# that last one is tricky because multiple profiles need to be checked.
import codecs
-import commands
import errno
import formatter
import logging
try:
from repoman.checks import run_checks
+ from repoman import utilities
except ImportError:
from os import path as osp
sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), 'pym'))
from repoman.checks import run_checks
+ from repoman import utilities
import portage.checksum
import portage.const
portage.dep._dep_check_strict = True
import portage.exception
from portage import cvstree, normalize_path
-from portage.manifest import Manifest
from portage.exception import ParseError
+from portage.manifest import Manifest
from portage.process import find_binary, spawn
from portage.util import initialize_logger
from portage.output import bold, create_color_func, darkgreen, \
"ebuild.allmasked",
"ebuild.autotools",
"ebuild.nesteddie",
-"desktop.invalid",
"digest.assumed",
"digest.missing",
"digestentry.unused",
qawarnings.append(x)
valid_restrict = frozenset(["binchecks", "bindist",
- "fetch", "installsources", "mirror",
+ "fetch", "installsources", "mirror",
"primaryuri", "strip", "test", "userpriv"])
# file.executable
logging.info("Not in a CVS repository; enabling pretend mode.")
options.pretend = True
-def have_profile_dir(path, maxdepth=3):
- while path != "/" and maxdepth:
- if os.path.exists(path + "/profiles/package.mask"):
- return normalize_path(path)
- path = normalize_path(path + "/..")
- maxdepth -= 1
-
-portdir=None
-portdir_overlay=None
-mydir=os.getcwd()
-if "PWD" in os.environ and os.environ["PWD"] != mydir and \
- os.path.realpath(os.environ["PWD"]) == mydir:
- # getcwd() returns the canonical path but that makes it hard for repoman to
- # orient itself if the user has symlinks in their portage tree structure.
- # We use os.environ["PWD"], if available, to get the non-canonical path of
- # the current working directory (from the shell).
- mydir = os.environ["PWD"]
-mydir = normalize_path(mydir)
-path_ids = set()
-p = mydir
-s = None
-while True:
- s = os.stat(p)
- path_ids.add((s.st_dev, s.st_ino))
- if p == "/":
- break
- p = os.path.dirname(p)
-if mydir[-1] != "/":
- mydir += "/"
-
-for overlay in repoman_settings["PORTDIR_OVERLAY"].split():
- overlay = os.path.realpath(overlay)
- try:
- s = os.stat(overlay)
- except OSError:
- continue
- overlay_id = (s.st_dev, s.st_ino)
- if overlay[-1] != "/":
- overlay += "/"
- if overlay_id in path_ids:
- portdir_overlay = overlay
- subdir = mydir[len(overlay):]
- if subdir and subdir[-1] != "/":
- subdir += "/"
- if have_profile_dir(mydir, subdir.count("/")):
- portdir = portdir_overlay
- break
-
-del p, s, path_ids
-
-if not portdir_overlay:
- if (repoman_settings["PORTDIR"] + os.path.sep).startswith(mydir):
- portdir_overlay = repoman_settings["PORTDIR"]
- else:
- portdir_overlay = have_profile_dir(mydir)
- portdir = portdir_overlay
-
-if not portdir_overlay:
- sys.stderr.write("Repoman is unable to determine PORTDIR or PORTDIR_OVERLAY from" + \
- " the current\nworking directory.\n")
+try:
+ portdir, portdir_overlay, mydir = utilities.FindPortdir(repoman_settings)
+except ValueError:
sys.exit(1)
-if not portdir:
- portdir = repoman_settings["PORTDIR"]
-
-portdir = normalize_path(portdir)
-portdir_overlay = normalize_path(portdir_overlay)
-
os.environ["PORTDIR"] = portdir
if portdir_overlay != portdir:
os.environ["PORTDIR_OVERLAY"] = portdir_overlay
# dep_zapdeps looks at the vardbapi, but it shouldn't for repoman.
del trees["/"]["vartree"]
-if not myreporoot:
- myreporoot = os.path.basename(portdir_overlay)
- myreporoot += mydir[len(portdir_overlay):-1]
+myreporoot = os.path.basename(portdir_overlay)
+myreporoot += mydir[len(portdir_overlay):]
-reposplit=myreporoot.split("/")
-repolevel=len(reposplit)
+reposplit = myreporoot.split(os.path.sep)
+repolevel = len(reposplit)
# check if it's in $PORTDIR/$CATEGORY/$PN , otherwise bail if commiting.
# Reason for this is if they're trying to commit in just $FILESDIR/*, the Manifest needs updating.
-# this check ensure that repoman knows where it is, and the manifest recommit is at least possible.
+# this check ensures that repoman knows where it is, and the manifest recommit is at least possible.
if options.mode == 'commit' and repolevel not in [1,2,3]:
print red("***")+" Commit attempts *must* be from within a cvs co, category, or package directory."
print red("***")+" Attempting to commit from a packages files directory will be blocked for instance."
startdir = normalize_path(mydir)
repodir = startdir
-for x in range(0,repolevel-1):
+for x in range(0, repolevel - 1):
repodir = os.path.dirname(repodir)
-def caterror(mycat):
- warn(mycat + " is not an official category. " + \
- "Skipping QA checks in this directory.\n" + \
- "Please ensure that you add " + catdir + \
- " to " + repodir + "/profiles/categories\nif it is a new category.")
-
-def parse_use_local_desc(mylines, usedict=None):
- """returns a dict of the form {cpv:set(flags)}"""
- if usedict is None:
- usedict = {}
- lineno = 0
- for l in mylines:
- lineno += 1
- if not l or l.startswith("#"):
- continue
- mysplit = l.split(None, 1)
- if not mysplit:
- continue
- mysplit = mysplit[0].split(":")
- if len(mysplit) != 2:
- raise ParseError("line %d: Malformed input: '%s'" % \
- (lineno, l.rstrip("\n")))
- usedict.setdefault(mysplit[0], set())
- usedict[mysplit[0]].add(mysplit[1])
- return usedict
-
# retreive local USE list
luselist={}
try:
f = open(os.path.join(portdir, "profiles", "use.local.desc"))
- parse_use_local_desc(f, luselist)
+ utilities.parse_use_local_desc(f, luselist)
f.close()
except (IOError, OSError, ParseError), e:
logging.exception("Couldn't read from use.local.desc", e)
manifest1_compat = not os.path.exists(
os.path.join(portdir_overlay, "manifest1_obsolete"))
-scanlist=[]
-if repolevel==2:
- #we are inside a category directory
- catdir=reposplit[-1]
- if catdir not in repoman_settings.categories:
- caterror(catdir)
- mydirlist=os.listdir(startdir)
- for x in mydirlist:
- if x == "CVS" or x.startswith("."):
- continue
- if os.path.isdir(startdir+"/"+x):
- scanlist.append(catdir+"/"+x)
-elif repolevel==1:
- for x in repoman_settings.categories:
- if not os.path.isdir(startdir+"/"+x):
- continue
- for y in os.listdir(startdir+"/"+x):
- if y == "CVS" or y.startswith("."):
- continue
- if os.path.isdir(startdir+"/"+x+"/"+y):
- scanlist.append(x+"/"+y)
-elif repolevel==3:
- catdir = reposplit[-2]
- if catdir not in repoman_settings.categories:
- caterror(catdir)
- scanlist.append(catdir+"/"+reposplit[-1])
+scanlist = utilities.FindPackagesToScan(repoman_settings, startdir, reposplit)
scanlist.sort()
+logging.debug("Found the following packages to scan:\n%s" % '\n'.join(scanlist))
profiles={}
descfile=portdir+"/profiles/profiles.desc"
full_path = os.path.join(repodir, relative_path)
if stat.S_IMODE(os.stat(full_path).st_mode) & 0111:
stats["file.executable"] += 1
- fails["file.executable"].append(relative_path)
+ fails["file.executable"].append(x+"/files/"+y)
mykey = catdir + "/" + y[7:]
if y[7:] not in ebuildlist:
full_path = os.path.join(repodir, relative_path)
if stat.S_IMODE(os.stat(full_path).st_mode) & 0111:
stats["file.executable"] += 1
- fails["file.executable"].append(relative_path)
+ fails["file.executable"].append(x+"/"+y+".ebuild")
if isCvs and y not in eadded:
#ebuild not added to cvs
stats["ebuild.notadded"]=stats["ebuild.notadded"]+1
for mybad in mybadrestrict:
fails["RESTRICT.invalid"].append(x+"/"+y+".ebuild: %s" % mybad)
# Syntax Checks
+ relative_path = os.path.join(x, y + ".ebuild")
+ full_path = os.path.join(repodir, relative_path)
f = open(full_path, 'rb')
try:
for check_name, e in run_checks(f, os.stat(full_path).st_mtime):
--- /dev/null
+# repoman: Utilities
+# Copyright 2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Id$
+
+import logging
+import os
+
+from portage import util
+from portage import exception
+
+normalize_path = util.normalize_path
+util.initialize_logger()
+
+def have_profile_dir(path, maxdepth=3):
+ """ Try to figure out if 'path' has a /profiles dir in it by checking for a package.mask file
+ """
+ while path != "/" and maxdepth:
+ if os.path.exists(path + "/profiles/package.mask"):
+ return normalize_path(path)
+ path = normalize_path(path + "/..")
+ maxdepth -= 1
+
+def parse_use_local_desc(mylines, usedict=None):
+ """
+ Records are of the form PACKAGE:FLAG - DESC
+ returns a dict of the form {cpv:set(flags)}"""
+ if usedict is None:
+ usedict = {}
+ for line_num, l in enumerate(mylines):
+ if not l or l.startswith('#'):
+ continue
+ pkg_flag = l.split(None, 1) # None implies splitting on whitespace
+ if not pkg_flag:
+ continue
+ try:
+ pkg, flag = pkg_flag[0].split(":")
+ except ValueError:
+ raise exception,ParseError("line %d: Malformed input: '%s'" % \
+ (linenum + 1, l.rstrip("\n")))
+ usedict.setdefault(pkg, set())
+ usedict[pkg].add(flag)
+ return usedict
+
+def FindPackagesToScan(settings, startdir, reposplit):
+ """ Try to find packages that need to be scanned
+
+ Args:
+ settings - portage.config instance, preferably repoman_settings
+ startdir - directory that repoman was run in
+ reposplit - root of the repository
+ Returns:
+ A list of directories to scan
+ """
+
+ def AddPackagesInDir(path):
+ """ Given a list of dirs, add any packages in it """
+ ret = []
+ pkgdirs = os.listdir(path)
+ for d in pkgdirs:
+ if d == 'CVS' or d.startswith('.'):
+ continue
+ p = os.path.join(path, d)
+
+ if os.path.isdir(p):
+ cat_pkg_dir = os.path.join(p.split(os.path.sep)[-2:])
+ logging.debug('adding %s to scanlist' % cat_pkg_dir)
+ ret.append(cat_pkg_dir)
+ return ret
+
+ scanlist = []
+ repolevel = len(reposplit)
+ if repolevel == 1: # root of the tree, startdir = repodir
+ for cat in settings.categories:
+ path = os.path.join(startdir, cat)
+ if not os.path.isdir(path):
+ continue
+ pkgdirs = os.listdir(path)
+ scanlist.extend(AddPackagesInDir(path))
+ elif repolevel == 2: # category level, startdir = catdir
+ # we only want 1 segment of the directory, is why we use catdir instead of startdir
+ catdir = reposplit[-2]
+ if catdir not in settings.categories:
+ logging.warn('%s is not a valid category according to profiles/categories, ' \
+ 'skipping checks in %s' % (catdir, catdir))
+ else:
+ scanlist = AddPackagesInDir(catdir)
+ elif repolevel == 3: # pkgdir level, startdir = pkgdir
+ catdir = reposplit[-2]
+ pkgdir = reposplit[-1]
+ if catdir not in settings.categories:
+ logging.warn('%s is not a valid category according to profiles/categories, ' \
+ 'skipping checks in %s' % (catdir, catdir))
+ else:
+ scanlist.append(os.path.join(catdir, pkgdir))
+ return scanlist
+
+def FindPortdir(settings):
+ """ Try to figure out what repo we are in and whether we are in a regular
+ tree or an overlay.
+
+ Basic logic is:
+
+ 1. Determine what directory we are in (supports symlinks).
+ 2. Build a list of directories from / to our current location
+ 3. Iterate over PORTDIR_OVERLAY, if we find a match, search for a profiles directory
+ in the overlay. If it has one, make it portdir, otherwise make it portdir_overlay.
+ 4. If we didn't find an overlay in PORTDIR_OVERLAY, see if we are in PORTDIR; if so, set
+ portdir_overlay to PORTDIR. If we aren't in PORTDIR, see if PWD has a profiles dir, if
+ so, set portdir_overlay and portdir to PWD, else make them False.
+ 5. If we haven't found portdir_overlay yet, it means the user is doing something odd, report
+ an error.
+ 6. If we haven't found a portdir yet, set portdir to PORTDIR.
+
+ Args:
+ settings - portage.config instance, preferably repoman_settings
+ Returns:
+ tuple(portdir, portdir_overlay, location)
+ """
+
+ portdir = None
+ portdir_overlay = None
+ location = os.getcwd()
+ pwd = os.environ.get('PWD', '')
+ if pwd != location and os.path.realpath(pwd) == location:
+ # getcwd() returns the canonical path but that makes it hard for repoman to
+ # orient itself if the user has symlinks in their portage tree structure.
+ # We use os.environ["PWD"], if available, to get the non-canonical path of
+ # the current working directory (from the shell).
+ location = pwd
+
+ location = normalize_path(location)
+
+ path_ids = set()
+ p = location
+ s = None
+ while True:
+ s = os.stat(p)
+ path_ids.add((s.st_dev, s.st_ino))
+ if p == "/":
+ break
+ p = os.path.dirname(p)
+ if location[-1] != "/":
+ location += "/"
+
+ for overlay in settings["PORTDIR_OVERLAY"].split():
+ overlay = os.path.realpath(overlay)
+ try:
+ s = os.stat(overlay)
+ except OSError:
+ continue
+ overlay_id = (s.st_dev, s.st_ino)
+ if overlay[-1] != "/":
+ overlay += "/"
+ if overlay_id in path_ids:
+ portdir_overlay = overlay
+ subdir = location[len(overlay):]
+ if subdir and subdir[-1] != "/":
+ subdir += "/"
+ if have_profile_dir(location, subdir.count("/")):
+ portdir = portdir_overlay
+ break
+
+ del p, s, path_ids
+
+ if not portdir_overlay:
+ if (settings["PORTDIR"] + os.path.sep).startswith(location):
+ portdir_overlay = settings["PORTDIR"]
+ else:
+ portdir_overlay = have_profile_dir(location)
+ portdir = portdir_overlay
+
+ if not portdir_overlay:
+ msg = 'Repoman is unable to determine PORTDIR or PORTDIR_OVERLAY' + \
+ ' from the current working directory'
+ logging.critical(msg)
+ raise ValueError(msg)
+
+ if not portdir:
+ portdir = settings["PORTDIR"]
+
+ if not portdir_overlay.endswith('/'):
+ portdir_overlay += '/'
+
+ if not portdir.endswith('/'):
+ portdir += '/'
+
+ return map(normalize_path, (portdir, portdir_overlay, location))