From af16463743d83cb91e54d67f6d921ab75f29080b Mon Sep 17 00:00:00 2001 From: Alec Warner Date: Sat, 26 Jan 2008 20:53:20 +0000 Subject: Move random functions out of repoman and into utilties.py svn path=/main/trunk/; revision=9221 --- pym/repoman/utilities.py | 188 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 pym/repoman/utilities.py (limited to 'pym/repoman') diff --git a/pym/repoman/utilities.py b/pym/repoman/utilities.py new file mode 100644 index 000000000..26863ecf1 --- /dev/null +++ b/pym/repoman/utilities.py @@ -0,0 +1,188 @@ +# 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)) -- cgit v1.2.3-1-g7c22