doebuild: avoid redundant distfiles checks
authorZac Medico <zmedico@gentoo.org>
Sun, 28 Aug 2011 23:29:49 +0000 (16:29 -0700)
committerZac Medico <zmedico@gentoo.org>
Sun, 28 Aug 2011 23:29:49 +0000 (16:29 -0700)
When the unpack phase is already marked as complete, it's wasteful to
check distfiles digests. In order to avoid this, we have to migrate the
distfiles/workdir timestamp comparisons from ebuild.sh to doebuild.py,
so that doebuild always knows when unpack will be triggered. This also
allows us to eliminate code in dyn_unpack that duplicated dyn_clean,
actually call dyn_clean instead.

bin/ebuild.sh
pym/portage/package/ebuild/doebuild.py

index d68e54b7b293164a9d9d77776b0944b267dfdc74..23a12401d3f318d831dd4143f9bc7dce1b9afab5 100755 (executable)
@@ -726,41 +726,10 @@ dyn_setup() {
 }
 
 dyn_unpack() {
-       local newstuff="no"
-       if [ -e "${WORKDIR}" ]; then
-               local x
-               local checkme
-               for x in $A ; do
-                       vecho ">>> Checking ${x}'s mtime..."
-                       if [ "${PORTAGE_ACTUAL_DISTDIR:-${DISTDIR}}/${x}" -nt "${WORKDIR}" ]; then
-                               vecho ">>> ${x} has been updated; recreating WORKDIR..."
-                               newstuff="yes"
-                               break
-                       fi
-               done
-               if [ ! -f "${PORTAGE_BUILDDIR}/.unpacked" ] ; then
-                       vecho ">>> Not marked as unpacked; recreating WORKDIR..."
-                       newstuff="yes"
-               fi
-       fi
-       if [ "${newstuff}" == "yes" ]; then
-               # We don't necessarily have privileges to do a full dyn_clean here.
-               rm -rf "${PORTAGE_BUILDDIR}"/{.setuped,.unpacked,.prepared,.configured,.compiled,.tested,.installed,.packaged,build-info}
-               if ! has keepwork $FEATURES ; then
-                       rm -rf "${WORKDIR}"
-               fi
-               if [ -d "${T}" ] && \
-                       ! has keeptemp $FEATURES ; then
-                       rm -rf "${T}" && mkdir "${T}"
-               fi
-       fi
-       if [ -e "${WORKDIR}" ]; then
-               if [ "$newstuff" == "no" ]; then
-                       vecho ">>> WORKDIR is up-to-date, keeping..."
-                       return 0
-               fi
+       if [[ -f ${PORTAGE_BUILDDIR}/.unpacked ]] ; then
+               vecho ">>> WORKDIR is up-to-date, keeping..."
+               return 0
        fi
-
        if [ ! -d "${WORKDIR}" ]; then
                install -m${PORTAGE_WORKDIR_MODE:-0700} -d "${WORKDIR}" || die "Failed to create dir '${WORKDIR}'"
        fi
index c252e86a3df9e7e3f05846ca4a84072274308419..a95a418b2236e43beb87048c56da25dadf1ae53a 100644 (file)
@@ -432,6 +432,7 @@ def doebuild(myebuild, mydo, myroot, mysettings, debug=0, listonly=0,
        "install":["test"],
        "rpm":    ["install"],
        "package":["install"],
+       "merge"  :["install"],
        }
        
        if mydbapi is None:
@@ -666,6 +667,68 @@ def doebuild(myebuild, mydo, myroot, mysettings, debug=0, listonly=0,
                        return unmerge(mysettings["CATEGORY"],
                                mysettings["PF"], myroot, mysettings, vartree=vartree)
 
+               phases_to_run = set()
+               if "noauto" in mysettings.features or \
+                       mydo not in actionmap_deps:
+                       phases_to_run.add(mydo)
+               else:
+                       phase_stack = [mydo]
+                       while phase_stack:
+                               x = phase_stack.pop()
+                               if x in phases_to_run:
+                                       continue
+                               phases_to_run.add(x)
+                               phase_stack.extend(actionmap_deps.get(x, []))
+                       del phase_stack
+
+               alist = set(mysettings.configdict["pkg"].get("A", "").split())
+
+               unpacked = False
+               if "unpack" in phases_to_run:
+                       try:
+                               workdir_st = os.stat(mysettings["WORKDIR"])
+                       except OSError:
+                               pass
+                       else:
+                               newstuff = False
+                               if not os.path.exists(os.path.join(
+                                       mysettings["PORTAGE_BUILDDIR"], ".unpacked")):
+                                       writemsg_stdout(
+                                               ">>> Not marked as unpacked; recreating WORKDIR...\n")
+                                       newstuff = True
+                               else:
+                                       for x in alist:
+                                               writemsg_stdout(">>> Checking %s's mtime...\n" % x)
+                                               try:
+                                                       x_st = os.stat(os.path.join(
+                                                               mysettings["DISTDIR"], x))
+                                               except OSError:
+                                                       # file not fetched yet
+                                                       x_st = None
+
+                                               if x_st is None or x_st.st_mtime > workdir_st.st_mtime:
+                                                       writemsg_stdout(">>> Timestamp of "
+                                                               "%s has changed; recreating WORKDIR...\n" % x)
+                                                       newstuff = True
+                                                       break
+
+                               if newstuff:
+                                       if builddir_lock is None and \
+                                               'PORTAGE_BUILDIR_LOCKED' not in mysettings:
+                                               builddir_lock = EbuildBuildDir(
+                                                       scheduler=PollScheduler().sched_iface,
+                                                       settings=mysettings)
+                                               builddir_lock.lock()
+                                       try:
+                                               _spawn_phase("clean", mysettings)
+                                       finally:
+                                               if builddir_lock is not None:
+                                                       builddir_lock.unlock()
+                                                       builddir_lock = None
+                               else:
+                                       writemsg_stdout(">>> WORKDIR is up-to-date, keeping...\n")
+                                       unpacked = True
+
                # Build directory creation isn't required for any of these.
                # In the fetch phase, the directory is needed only for RESTRICT=fetch
                # in order to satisfy the sane $PWD requirement (from bug #239560)
@@ -739,10 +802,9 @@ def doebuild(myebuild, mydo, myroot, mysettings, debug=0, listonly=0,
                # Only try and fetch the files if we are going to need them ...
                # otherwise, if user has FEATURES=noauto and they run `ebuild clean
                # unpack compile install`, we will try and fetch 4 times :/
-               need_distfiles = tree == "porttree" and \
+               need_distfiles = tree == "porttree" and not unpacked and \
                        (mydo in ("fetch", "unpack") or \
                        mydo not in ("digest", "manifest") and "noauto" not in features)
-               alist = set(mysettings.configdict["pkg"].get("A", "").split())
                if need_distfiles:
 
                        src_uri, = mydbapi.aux_get(mysettings.mycpv,
@@ -787,6 +849,10 @@ def doebuild(myebuild, mydo, myroot, mysettings, debug=0, listonly=0,
                        # Files are already checked inside fetch(),
                        # so do not check them again.
                        checkme = []
+               elif unpacked:
+                       # The unpack phase is marked as complete, so it
+                       # would be wasteful to check distfiles again.
+                       checkme = []
                else:
                        checkme = alist