Use the new chpathtool.
authorFabian Groffen <grobian@gentoo.org>
Sat, 13 Oct 2007 12:26:58 +0000 (12:26 -0000)
committerFabian Groffen <grobian@gentoo.org>
Sat, 13 Oct 2007 12:26:58 +0000 (12:26 -0000)
If we install on a system with a different prefix, unpack in the
workdir, instead of the image dir.  We "copy" from the workdir to the
image using chpathtool, which behaves as a cp -a.

chpathtool was changed to copy file by file, changing paths it finds in
files to overcome the following problem.  chpathtool was used in a piped
fashion, like this:

bzip2 -d file | chpathtool | tar -x

in this way, chpathtool operated on the raw tar-stream, changing paths
it saw over the stream.  This has the following advantages:
- not only rpaths, library locations, or hardcoded paths to conf files
  were changed, but also the location of the files in the filesystem
  themselves, as chpathtool also changed the tar envelope
- just one run over the stream, simple, easy and cheap from an fork/exec
  perspective
- no need to deal with file attributes, creation modes, etc, tar dealt
  with that, chpathtool only changed paths where appropriate

However, when doing the path changements, chpathtool inserts padding
bytes at the end of each string it sees, in order not to break offsets
stored in e.g. programs to point in the TEXT or DATA spaces.  Because
text files are in the tar stream, chpathtool sees the end of string at
the end of such text file, and inserts the padding null-bytes there.
However, tar still has an administration for each file of its size, so
as result, tar writes the padding null-bytes to the text files.  In most
cases this doesn't hurt, however, some applications, such as GHC get
confused by it, because EOF isn't found, but null-bytes don't make sense
for them.

The only way to fix this, without interpreting the tar envelope, is to
use chpathtool per file.  chpathtool doesn't write padding bytes if it
doesn't find an end of string, which in textfiles doesn't exist (instead
you get the EOF).  Running find -exec, or with xargs results in a
serious performance problem due to numerous fork/exec calls.  Instead,
chpathtool was changed to recursively walk directories, and process all
what is in there.

Because chpathtool operates on files in this case, it needs to properly
behave, such that it doesn't change the properties of each file it
replicates.  For this reason, chpathtool's implementation grew twice its
original size in order to retain the original file's permissions,
owners, and times.

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

pym/portage/__init__.py

index 9bda7bd6abc3daeac4581040d9e7bc16a943261e..d0593e47bcab989c6cc51461e12fe03946452811 100644 (file)
@@ -5347,7 +5347,11 @@ def pkgmerge(mytbz2, myroot, mysettings, mydbapi=None, vartree=None, prev_mtimes
                builddir = os.path.join(
                        mysettings["PORTAGE_TMPDIR"], "portage", mycat, mypkg)
                catdir = os.path.dirname(builddir)
-               pkgloc = os.path.join(builddir, "image")
+               # if the prefix differs, we copy it to the image after extraction
+               if (buildprefix != EPREFIX):
+                       pkgloc = os.path.join(builddir, "work")
+               else
+                       pkgloc = os.path.join(builddir, "image")
                infloc = os.path.join(builddir, "build-info")
                myebuild = os.path.join(
                        infloc, os.path.basename(mytbz2)[:-4] + "ebuild")
@@ -5392,7 +5396,7 @@ def pkgmerge(mytbz2, myroot, mysettings, mydbapi=None, vartree=None, prev_mtimes
 
                writemsg_stdout(">>> Extracting %s\n" % mypkg)
                retval = portage.process.spawn_bash(
-                       "bzip2 -dqc -- '%s' | chpathtool - - '%s' '%s' | tar -xp -C '%s' -f -" % (mytbz2, buildprefix, EPREFIX, pkgloc),
+                       "bzip2 -dqc -- '%s' | tar -xp -C '%s' -f -" % (mytbz2, pkgloc),
                        env=mysettings.environ())
                if retval != os.EX_OK:
                        writemsg("!!! Error Extracting '%s'\n" % mytbz2, noiselevel=-1)
@@ -5403,16 +5407,20 @@ def pkgmerge(mytbz2, myroot, mysettings, mydbapi=None, vartree=None, prev_mtimes
                # the extracted package put everything in buildprefix, so we
                # just have to move it to the right EPREFIX
                if buildprefix != EPREFIX:
-                       try:
-                               shutil.copytree(os.path.join(pkgloc,
-                                       buildprefix.lstrip(os.path.sep)), os.path.join(pkgloc,
-                                               EPREFIX_LSTRIP), symlinks=True)
-                       except OSError:
-                               if not os.path.exists(os.path.join(pkgloc, EPREFIX_LSTRIP)):
-                                       writemsg("!!! Package was was built in a wrong way, " +
-                                                       "please rebuild the package with a recent " +
-                                                       "Portage\n", noiselevel=-1)
-                                       return os.EX_OSERR
+                       writemsg_stdout(">>> Adjusting Prefix to %s\n" % EPREFIX)
+                       b = os.path.join(pkgloc, buildprefix.lstrip(os.path.sep))
+                       i = os.path.join(builddir, "image", EPREFIX_LSTRIP)
+                       # make sure the directory structure for EPREFIX is set up in
+                       # the image, but avoid the last directory being there,
+                       # otherwise chpathtool will complain
+                       portage.util.ensure_dirs(i)
+                       os.rmdir(i)
+                       retval = portage.process.spawn_bash(
+                               "chpathtool '%s' '%s' '%s' '%s'" % (b, i, buildprefix, EPREFIX),
+                               env=mysettings.environ())
+                       if retval != os.EX_OK:
+                               writemsg("!!! Adjusing to Prefix failed!\n", noiselevel=-1)
+                               return retval
 
                mylink = dblink(mycat, mypkg, myroot, mysettings, vartree=vartree,
                        treetype="bintree")