Merged from trunk -r11713:11724
authorFabian Groffen <grobian@gentoo.org>
Tue, 28 Oct 2008 18:51:42 +0000 (18:51 -0000)
committerFabian Groffen <grobian@gentoo.org>
Tue, 28 Oct 2008 18:51:42 +0000 (18:51 -0000)
   | 11714   | Split dep validation out of doebuild() and skip it when      |
   | zmedico | called by emerge since there's no need to do this every time |
   |         | emerge executes a phase.                                     |

   | 11715   | Bug #233296 - Add minimal PROPERTIES=interactive support by  |
   | zmedico | simply forcing all package output to stdio whenever the      |
   |         | merge list contains one or more interactive packages.        |

   | 11716   | Document PROPERTIES=interactive.                             |
   | zmedico |                                                              |

   | 11717   | Add a PROPERTIES.syntax check.                               |
   | zmedico |                                                              |

   | 11718   | Fix grammar.                                                 |
   | zmedico |                                                              |

   | 11719   | Bug #243224 - Add an exemption to the inherit.autotools      |
   | zmedico | check for ebuilds that inherit git.eclass since the          |
   |         | GIT_BOOTSTRAP variable may be used to call one of autotools  |
   |         | functions.                                                   |

   | 11720   | Add "bzr" to the lists of live eclasses.                     |
   | zmedico |                                                              |

   | 11721   | Add "bzr" to the lists of live eclasses.                     |
   | zmedico |                                                              |

   | 11722   | Add "subversion" to InheritAutotools._exempt_eclasses.       |
   | zmedico | Thanks to Arfrever.                                          |

   | 11723   | When populating the fake $DISTDIR inside doebuild(), reuse   |
   | zmedico | existing symlinks when possible, instead of recreating the   |
   |         | whole directory from scratch.                                |

   | 11724   | Fix preserve-libs code inside dblink.unmerge() so that it    |
   | zmedico | will join paths correctly when ROOT != /.                    |

svn path=/main/branches/prefix/; revision=11735

bin/repoman
cnf/sets.conf
man/ebuild.5
man/repoman.1
pym/_emerge/__init__.py
pym/portage/__init__.py
pym/portage/dbapi/vartree.py
pym/repoman/checks.py

index 2ed9fc90fd2a890a266241ef26332f6ab2d28e1c..a6c4553ac8eab8f61f0180f2dcdd80461852c841 100755 (executable)
@@ -289,6 +289,7 @@ qahelp={
        "PDEPEND.syntax":"Syntax error in PDEPEND (usually an extra/missing space/parenthesis)",
        "LICENSE.syntax":"Syntax error in LICENSE (usually an extra/missing space/parenthesis)",
        "PROVIDE.syntax":"Syntax error in PROVIDE (usually an extra/missing space/parenthesis)",
+       "PROPERTIES.syntax":"Syntax error in PROPERTIES (usually an extra/missing space/parenthesis)",
        "RESTRICT.syntax":"Syntax error in RESTRICT (usually an extra/missing space/parenthesis)",
        "SRC_URI.syntax":"Syntax error in SRC_URI (usually an extra/missing space/parenthesis)",
        "SRC_URI.mirror":"A uri listed in profiles/thirdpartymirrors is found in SRC_URI",
@@ -375,6 +376,7 @@ valid_restrict = frozenset(["binchecks", "bindist",
        "primaryuri", "strip", "test", "userpriv"])
 
 live_eclasses = frozenset([
+       "bzr",
        "cvs",
        "darcs",
        "git",
@@ -1230,7 +1232,8 @@ for x in scanlist:
                        "java-pkg-opt-2" in inherited
                operator_tokens = set(["||", "(", ")"])
                type_list, badsyntax = [], []
-               for mytype in ("DEPEND", "RDEPEND", "PDEPEND", "LICENSE", "PROVIDE"):
+               for mytype in ("DEPEND", "RDEPEND", "PDEPEND",
+                       "LICENSE", "PROPERTIES", "PROVIDE"):
                        mydepstr = myaux[mytype]
                        
                        if mydepstr.find(" ?") != -1:
index f9f351be8e91b281e7231ec9ba67f2f1d4dc300e..dd2ccb410dfe5f77e66eb07f26bfc862815b5b1e 100644 (file)
@@ -51,7 +51,7 @@ world-candidate = False
 class = portage.sets.dbapi.VariableSet
 world-candidate = False
 variable = INHERITED
-includes = cvs darcs git mercurial subversion
+includes = bzr cvs darcs git mercurial subversion
 
 # Installed packages that own files inside /lib/modules.
 [module-rebuild]
index ef5f2136e072df31dfa62e16d8a3cc44de38d416..0235f7be24413b70f20c2338bcf03cb9ce5e3d9d 100644 (file)
@@ -401,6 +401,16 @@ Disables userpriv for specific packages.
 .RE
 .PD 1
 .TP
+\fBPROPERTIES\fR = \fI[interactive]\fR
+A space delimited list of properties, with conditional syntax support.
+.PD 0
+.RS
+.TP
+.I interactive
+One or more ebuild phases will produce a prompt that requires user interaction.
+.RE
+.PD 1
+.TP
 \fBPROVIDE\fR = \fI"virtual/TARGET"\fR
 This variable should only be used when a package provides a virtual target.
 For example, blackdown\-jdk and sun\-jdk provide \fIvirtual/jdk\fR.  This
index dc9cb30e2bca08eb8bbf900c242a6b3dae6f8788..a4a92a731ceb42dc4cd4de2d88065936756409bf 100644 (file)
@@ -177,6 +177,12 @@ RDEPEND contains a package that usually only belongs in DEPEND
 .B RDEPEND.syntax
 Syntax error in RDEPEND (usually an extra/missing space/parenthesis)
 .TP
+.B PROPERTIES.syntax
+Syntax error in PROPERTIES (usually an extra/missing space/parenthesis)
+.TP
+.B RESTRICT.syntax
+Syntax error in RESTRICT (usually an extra/missing space/parenthesis)
+.TP
 .B SLOT.missing
 Ebuilds that have a missing or empty SLOT variable
 .TP
index 6837cf0fa95d6c51b237636abdc3e14620ba0f8a..82e08cef48d0604caa03a529b0f06d22603959b2 100644 (file)
@@ -2702,6 +2702,7 @@ class EbuildExecuter(CompositeTask):
        _phases = ("prepare", "configure", "compile", "test", "install")
 
        _live_eclasses = frozenset([
+               "bzr",
                "cvs",
                "darcs",
                "git",
@@ -9237,6 +9238,28 @@ class Scheduler(PollScheduler):
                        self._max_jobs > 1 or "--quiet" in self.myopts) and \
                        not bool(self._opts_no_background.intersection(self.myopts))
 
+               if background:
+                       interactive_tasks = self._get_interactive_tasks()
+                       if interactive_tasks:
+                               background = False
+                               writemsg_level(">>> Sending package output to stdio due " + \
+                                       "to interactive package(s):\n",
+                                       level=logging.INFO, noiselevel=-1)
+                               msg = [""]
+                               for pkg in interactive_tasks:
+                                       pkg_str = "  " + colorize("INFORM", str(pkg.cpv))
+                                       if pkg.root != "/":
+                                               pkg_str += " for " + pkg.root
+                                       msg.append(pkg_str)
+                               msg.append("")
+                               writemsg_level("".join("%s\n" % (l,) for l in msg),
+                                       level=logging.INFO, noiselevel=-1)
+                               if self._max_jobs is True or self._max_jobs > 1:
+                                       self._set_max_jobs(1)
+                                       writemsg_level(">>> Setting --jobs=1 due " + \
+                                               "to the above interactive package(s)\n",
+                                               level=logging.INFO, noiselevel=-1)
+
                self._status_display.quiet = \
                        not background or \
                        ("--quiet" in self.myopts and \
@@ -9248,6 +9271,20 @@ class Scheduler(PollScheduler):
 
                return background
 
+       def _get_interactive_tasks(self):
+               from portage import flatten
+               from portage.dep import use_reduce, paren_reduce
+               interactive_tasks = []
+               for task in self._mergelist:
+                       if not (isinstance(task, Package) and \
+                               task.operation == "merge"):
+                               continue
+                       properties = flatten(use_reduce(paren_reduce(
+                               task.metadata["PROPERTIES"]), uselist=task.use.enabled))
+                       if "interactive" in properties:
+                               interactive_tasks.append(task)
+               return interactive_tasks
+
        def _set_digraph(self, digraph):
                if self._max_jobs is not True and \
                        self._max_jobs < 2:
index 2f6712d21de81640ee6e075dd0b505c77d8689ba..575a59511804e425c49418c8dc0b5483a51cbdfd 100644 (file)
@@ -5427,46 +5427,13 @@ def doebuild(myebuild, mydo, myroot, mysettings, debug=0, listonly=0,
                                droppriv=droppriv)
 
                # Validate dependency metadata here to ensure that ebuilds with invalid
-               # data are never installed (even via the ebuild command).
-               invalid_dep_exempt_phases = \
-                       set(["clean", "cleanrm", "help", "prerm", "postrm"])
-               mycpv = mysettings["CATEGORY"] + "/" + mysettings["PF"]
-               dep_keys = ["DEPEND", "RDEPEND", "PDEPEND"]
-               misc_keys = ["LICENSE", "PROPERTIES", "PROVIDE", "RESTRICT", "SRC_URI"]
-               other_keys = ["SLOT"]
-               all_keys = dep_keys + misc_keys + other_keys
-               metadata = dict(izip(all_keys, mydbapi.aux_get(mycpv, all_keys)))
-               class FakeTree(object):
-                       def __init__(self, mydb):
-                               self.dbapi = mydb
-               dep_check_trees = {myroot:{}}
-               dep_check_trees[myroot]["porttree"] = \
-                       FakeTree(fakedbapi(settings=mysettings))
-               for dep_type in dep_keys:
-                       mycheck = dep_check(metadata[dep_type], None, mysettings,
-                               myuse="all", myroot=myroot, trees=dep_check_trees)
-                       if not mycheck[0]:
-                               writemsg("%s: %s\n%s\n" % (
-                                       dep_type, metadata[dep_type], mycheck[1]), noiselevel=-1)
-                               if mydo not in invalid_dep_exempt_phases:
-                                       return 1
-                       del dep_type, mycheck
-               for k in misc_keys:
-                       try:
-                               portage.dep.use_reduce(
-                                       portage.dep.paren_reduce(metadata[k]), matchall=True)
-                       except portage.exception.InvalidDependString, e:
-                               writemsg("%s: %s\n%s\n" % (
-                                       k, metadata[k], str(e)), noiselevel=-1)
-                               del e
-                               if mydo not in invalid_dep_exempt_phases:
-                                       return 1
-                       del k
-               if not metadata["SLOT"]:
-                       writemsg("SLOT is undefined\n", noiselevel=-1)
-                       if mydo not in invalid_dep_exempt_phases:
-                               return 1
-               del mycpv, dep_keys, metadata, misc_keys, FakeTree, dep_check_trees
+               # data are never installed via the ebuild command. Don't bother when
+               # returnpid == True since there's no need to do this every time emerge
+               # executes a phase.
+               if not returnpid:
+                       rval = _validate_deps(mysettings, myroot, mydo, mydbapi)
+                       if rval != os.EX_OK:
+                               return rval
 
                if "PORTAGE_TMPDIR" not in mysettings or \
                        not os.path.isdir(mysettings["PORTAGE_TMPDIR"]):
@@ -5737,24 +5704,31 @@ def doebuild(myebuild, mydo, myroot, mysettings, debug=0, listonly=0,
                        mysettings["PORTAGE_ACTUAL_DISTDIR"] = orig_distdir
                        edpath = mysettings["DISTDIR"] = \
                                os.path.join(mysettings["PORTAGE_BUILDDIR"], "distdir")
-                       if os.path.exists(edpath):
+                       portage.util.ensure_dirs(edpath, uid=portage_uid, mode=0755)
+
+                       # Remove any unexpected files or directories.
+                       for x in os.listdir(edpath):
+                               symlink_path = os.path.join(edpath, x)
+                               st = os.lstat(symlink_path)
+                               if x in alist and stat.S_ISLNK(st.st_mode):
+                                       continue
+                               if stat.S_ISDIR(st.st_mode):
+                                       shutil.rmtree(symlink_path)
+                               else:
+                                       os.unlink(symlink_path)
+
+                       # Check for existing symlinks and recreate if necessary.
+                       for x in alist:
+                               symlink_path = os.path.join(edpath, x)
+                               target = os.path.join(orig_distdir, x)
                                try:
-                                       if os.path.isdir(edpath) and not os.path.islink(edpath):
-                                               shutil.rmtree(edpath)
-                                       else:
-                                               os.unlink(edpath)
+                                       link_target = os.readlink(symlink_path)
                                except OSError:
-                                       print "!!! Failed reseting ebuild distdir path, " + edpath
-                                       raise
-                       os.mkdir(edpath)
-                       apply_secpass_permissions(edpath, uid=portage_uid, mode=0755)
-                       try:
-                               for file in alist:
-                                       os.symlink(os.path.join(orig_distdir, file),
-                                               os.path.join(edpath, file))
-                       except OSError:
-                               print "!!! Failed symlinking in '%s' to ebuild distdir" % file
-                               raise
+                                       os.symlink(target, symlink_path)
+                               else:
+                                       if link_target != target:
+                                               os.unlink(symlink_path)
+                                               os.symlink(target, symlink_path)
 
                #initial dep checks complete; time to process main commands
 
@@ -5879,6 +5853,50 @@ def doebuild(myebuild, mydo, myroot, mysettings, debug=0, listonly=0,
                        # and the exemption is no longer needed.
                        _doebuild_manifest_exempt_depend -= 1
 
+def _validate_deps(mysettings, myroot, mydo, mydbapi):
+
+       invalid_dep_exempt_phases = \
+               set(["clean", "cleanrm", "help", "prerm", "postrm"])
+       dep_keys = ["DEPEND", "RDEPEND", "PDEPEND"]
+       misc_keys = ["LICENSE", "PROPERTIES", "PROVIDE", "RESTRICT", "SRC_URI"]
+       other_keys = ["SLOT"]
+       all_keys = dep_keys + misc_keys + other_keys
+       metadata = dict(izip(all_keys,
+               mydbapi.aux_get(mysettings.mycpv, all_keys)))
+
+       class FakeTree(object):
+               def __init__(self, mydb):
+                       self.dbapi = mydb
+       dep_check_trees = {myroot:{}}
+       dep_check_trees[myroot]["porttree"] = \
+               FakeTree(fakedbapi(settings=mysettings))
+
+       for dep_type in dep_keys:
+               mycheck = dep_check(metadata[dep_type], None, mysettings,
+                       myuse="all", myroot=myroot, trees=dep_check_trees)
+               if not mycheck[0]:
+                       writemsg("%s: %s\n%s\n" % (
+                               dep_type, metadata[dep_type], mycheck[1]), noiselevel=-1)
+                       if mydo not in invalid_dep_exempt_phases:
+                               return 1
+
+       for k in misc_keys:
+               try:
+                       portage.dep.use_reduce(
+                               portage.dep.paren_reduce(metadata[k]), matchall=True)
+               except portage.exception.InvalidDependString, e:
+                       writemsg("%s: %s\n%s\n" % (
+                               k, metadata[k], str(e)), noiselevel=-1)
+                       if mydo not in invalid_dep_exempt_phases:
+                               return 1
+
+       if not metadata["SLOT"]:
+               writemsg("SLOT is undefined\n", noiselevel=-1)
+               if mydo not in invalid_dep_exempt_phases:
+                       return 1
+
+       return os.EX_OK
+
 expandcache={}
 
 def _movefile(src, dest, **kwargs):
index 078503e7d3f526f13afb14157fa5958e1aea0714..996fa517b8bc1d112b41b6abe426d26dec0c9ca2 100644 (file)
@@ -2373,6 +2373,8 @@ class dblink(object):
                                # their real target before the object is found not to be
                                # in the reverse NEEDED map
                                def symlink_compare(x, y):
+                                       x = os.path.join(self.myroot, x.lstrip(os.path.sep))
+                                       y = os.path.join(self.myroot, y.lstrip(os.path.sep))
                                        if os.path.islink(x):
                                                if os.path.islink(y):
                                                        return 0
@@ -2385,20 +2387,23 @@ class dblink(object):
 
                                plib_dict[cpv].sort(symlink_compare)
                                for f in plib_dict[cpv]:
-                                       if not os.path.exists(f):
+                                       f_abs = os.path.join(self.myroot, f.lstrip(os.path.sep))
+                                       if not os.path.exists(f_abs):
                                                continue
                                        unlink_list = []
                                        consumers = self.vartree.dbapi.linkmap.findConsumers(f)
                                        if not consumers:
-                                               unlink_list.append(f)
+                                               unlink_list.append(f_abs)
                                        else:
                                                keep=False
                                                for c in consumers:
+                                                       c = os.path.join(self.myroot,
+                                                               c.lstrip(os.path.sep))
                                                        if c not in self.getcontents():
                                                                keep=True
                                                                break
                                                if not keep:
-                                                       unlink_list.append(f)
+                                                       unlink_list.append(f_abs)
                                        for obj in unlink_list:
                                                try:
                                                        if os.path.islink(obj):
index f4a7733a07ef9e1aaca4ab53ffde06f71155165c..dd81d87162641cdceb791d07283f08850e7e588d 100644 (file)
@@ -232,12 +232,21 @@ class InheritAutotools(LineCheck):
                "eautomake", "eautoreconf", "_elibtoolize")
        _autotools_func_re = re.compile(r'(^|\s)(' + \
                "|".join(_autotools_funcs) + ')(\s|$)')
+       # Exempt eclasses:
+       # git - An EGIT_BOOTSTRAP variable may be used to call one of
+       #       the autotools functions.
+       # subversion - An ESVN_BOOTSTRAP variable may be used to call one of
+       #       the autotools functions.
+       _exempt_eclasses = frozenset(["git", "subversion"])
 
        def new(self, pkg):
                self._inherit_autotools = None
                self._autotools_func_call = None
+               self._disabled = self._exempt_eclasses.intersection(pkg.inherited)
 
        def check(self, num, line):
+               if self._disabled:
+                       return
                if self._inherit_autotools is None:
                        self._inherit_autotools = self._inherit_autotools_re.match(line)
                if self._inherit_autotools is not None and \