From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from pigeon.gentoo.org ([208.92.234.80] helo=lists.gentoo.org) by finch.gentoo.org with esmtp (Exim 4.60) (envelope-from ) id 1RZDXL-0007ly-2S for garchives@archives.gentoo.org; Sat, 10 Dec 2011 03:23:43 +0000 Received: from pigeon.gentoo.org (localhost [127.0.0.1]) by pigeon.gentoo.org (Postfix) with SMTP id BBB6521C020; Sat, 10 Dec 2011 03:23:35 +0000 (UTC) Received: from smtp.gentoo.org (smtp.gentoo.org [140.211.166.183]) by pigeon.gentoo.org (Postfix) with ESMTP id E68B221C020 for ; Sat, 10 Dec 2011 03:23:34 +0000 (UTC) Received: from pelican.gentoo.org (unknown [66.219.59.40]) (using TLSv1 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id 4EADB1B4006 for ; Sat, 10 Dec 2011 03:23:34 +0000 (UTC) Received: from localhost.localdomain (localhost [127.0.0.1]) by pelican.gentoo.org (Postfix) with ESMTP id 9965780042 for ; Sat, 10 Dec 2011 03:23:33 +0000 (UTC) From: "Zac Medico" To: gentoo-commits@lists.gentoo.org Content-type: text/plain; charset=UTF-8 Reply-To: gentoo-dev@lists.gentoo.org, "Zac Medico" Message-ID: <0b32a054ea5e30f127addf7246e0f8dfafbab091.zmedico@gentoo> Subject: [gentoo-commits] proj/portage:master commit in: bin/, pym/_emerge/ X-VCS-Repository: proj/portage X-VCS-Files: bin/chpathtool.py pym/_emerge/Binpkg.py X-VCS-Directories: bin/ pym/_emerge/ X-VCS-Committer: zmedico X-VCS-Committer-Name: Zac Medico X-VCS-Revision: 0b32a054ea5e30f127addf7246e0f8dfafbab091 Date: Sat, 10 Dec 2011 03:23:33 +0000 (UTC) Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-Id: Gentoo Linux mail X-BeenThere: gentoo-commits@lists.gentoo.org Content-Transfer-Encoding: quoted-printable X-Archives-Salt: 8dbfc5f9-09f8-4ea4-b24e-367f25338a1a X-Archives-Hash: 3aca9ba72cb6f7a97c30f368f0f5e987 commit: 0b32a054ea5e30f127addf7246e0f8dfafbab091 Author: Zac Medico gentoo org> AuthorDate: Sat Dec 10 03:21:44 2011 +0000 Commit: Zac Medico gentoo org> CommitDate: Sat Dec 10 03:21:44 2011 +0000 URL: http://git.overlays.gentoo.org/gitweb/?p=3Dproj/portage.git;a= =3Dcommit;h=3D0b32a054 Binpkg: add chpathtool support for prefix This uses a python-based chpathtool implementation which is intended to be compatible with the C-based implemenation that the prefix branch uses. --- bin/chpathtool.py | 182 +++++++++++++++++++++++++++++++++++++++++++= ++++++ pym/_emerge/Binpkg.py | 64 ++++++++++++++++-- 2 files changed, 241 insertions(+), 5 deletions(-) diff --git a/bin/chpathtool.py b/bin/chpathtool.py new file mode 100755 index 0000000..d0d49cb --- /dev/null +++ b/bin/chpathtool.py @@ -0,0 +1,182 @@ +#!/usr/bin/python +# Copyright 2011 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 + +import io +import optparse +import os +import stat +import sys + +CONTENT_ENCODING =3D "utf_8" +FS_ENCODING =3D "utf_8" + +try: + import magic +except ImportError: + magic =3D None +else: + try: + magic.MIME_TYPE + except AttributeError: + # magic module seems to be broken + magic =3D None + +class IsTextFile(object): + + def __init__(self): + if magic is not None: + self._call =3D self._is_text_magic + self._m =3D magic.open(magic.MIME_TYPE) + self._m.load() + else: + self._call =3D self._is_text_encoding + self._encoding =3D CONTENT_ENCODING + + def __call__(self, filename): + """ + Returns True if the given file is a text file, and False otherwise. + """ + return self._call(filename) + + def _is_text_magic(self, filename): + mime_type =3D self._m.file(filename) + return mime_type.startswith("text/") + + def _is_text_encoding(self, filename): + try: + for line in io.open(filename, mode=3D'r', encoding=3Dself._encoding): + pass + except UnicodeDecodeError: + return False + return True + +def chpath_inplace(filename, is_text_file, old, new): + """ + Returns True if any modifications were made, and False otherwise. + """ + + modified =3D False + orig_stat =3D os.lstat(filename) + try: + f =3D io.open(filename, buffering=3D0, mode=3D'r+b') + except IOError: + try: + orig_mode =3D stat.S_IMODE(os.lstat(filename).st_mode) + except OSError as e: + sys.stderr.write("%s: %s\n" % (e, filename)) + return + temp_mode =3D 0o200 | orig_mode + os.chmod(filename, temp_mode) + try: + f =3D io.open(filename, buffering=3D0, mode=3D'r+b') + finally: + os.chmod(filename, orig_mode) + + len_old =3D len(old) + len_new =3D len(new) + matched_byte_count =3D 0 + while True: + in_byte =3D f.read(1) + + if not in_byte: + break + + if in_byte =3D=3D old[matched_byte_count]: + matched_byte_count +=3D 1 + if matched_byte_count =3D=3D len_old: + modified =3D True + matched_byte_count =3D 0 + end_position =3D f.tell() + start_position =3D end_position - len_old + if not is_text_file: + # search backwards for leading slashes written by + # a previous invocation of this tool + num_to_write =3D len_old + f.seek(start_position - 1) + while True: + if f.read(1) !=3D b'/': + break + num_to_write +=3D 1 + f.seek(f.tell() - 2) + + # pad with as many leading slashes as necessary + while num_to_write > len_new: + f.write(b'/') + num_to_write -=3D 1 + f.write(new) + else: + remainder =3D f.read() + f.seek(start_position) + f.write(new) + if remainder: + f.write(remainder) + f.truncate() + f.seek(start_position + len_new) + elif matched_byte_count > 0: + # back up an try to start a new match after + # the first byte of the previous partial match + f.seek(f.tell() - matched_byte_count) + matched_byte_count =3D 0 + + f.close() + if modified: + orig_mtime =3D orig_stat[stat.ST_MTIME] + os.utime(filename, (orig_mtime, orig_mtime)) + return modified + +def chpath_inplace_symlink(filename, st, old, new): + target =3D os.readlink(filename) + if target.startswith(old): + new_target =3D new + target[len(old):] + os.unlink(filename) + os.symlink(new_target, filename) + os.lchown(filename, st.st_uid, st.st_gid) + +def main(argv): + + usage =3D "%s [options] " % (os.path.basename(arg= v[0],)) + parser =3D optparse.OptionParser(usage=3Dusage) + options, args =3D parser.parse_args(argv[1:]) + + if len(args) !=3D 3: + parser.error("3 args required, got %s" % (len(args),)) + + location, old, new =3D args + + is_text_file =3D IsTextFile() + + if not isinstance(location, bytes): + location =3D location.encode(FS_ENCODING) + if not isinstance(old, bytes): + old =3D old.encode(FS_ENCODING) + if not isinstance(new, bytes): + new =3D new.encode(FS_ENCODING) + + st =3D os.lstat(location) + + if stat.S_ISDIR(st.st_mode): + for parent, dirs, files in os.walk(location): + for filename in files: + filename =3D os.path.join(parent, filename) + try: + st =3D os.lstat(filename) + except OSError: + pass + else: + if stat.S_ISREG(st.st_mode): + chpath_inplace(filename, + is_text_file(filename), old, new) + elif stat.S_ISLNK(st.st_mode): + chpath_inplace_symlink(filename, st, old, new) + + elif stat.S_ISREG(st.st_mode): + chpath_inplace(location, + is_text_file(location), old, new) + elif stat.S_ISLNK(st.st_mode): + chpath_inplace_symlink(location, st, old, new) + + return os.EX_OK + +if __name__ =3D=3D "__main__": + sys.exit(main(sys.argv)) diff --git a/pym/_emerge/Binpkg.py b/pym/_emerge/Binpkg.py index bc6511e..5a58ad2 100644 --- a/pym/_emerge/Binpkg.py +++ b/pym/_emerge/Binpkg.py @@ -9,8 +9,9 @@ from _emerge.CompositeTask import CompositeTask from _emerge.BinpkgVerifier import BinpkgVerifier from _emerge.EbuildMerge import EbuildMerge from _emerge.EbuildBuildDir import EbuildBuildDir +from _emerge.SpawnProcess import SpawnProcess from portage.eapi import eapi_exports_replace_vars -from portage.util import writemsg +from portage.util import ensure_dirs, writemsg import portage from portage import os from portage import _encodings @@ -18,6 +19,7 @@ from portage import _unicode_decode from portage import _unicode_encode import io import logging +import shutil from portage.output import colorize =20 class Binpkg(CompositeTask): @@ -25,7 +27,8 @@ class Binpkg(CompositeTask): __slots__ =3D ("find_blockers", "ldpath_mtimes", "logger", "opts", "pkg", "pkg_count", "prefetcher", "settings", "world_atom") + \ - ("_bintree", "_build_dir", "_ebuild_path", "_fetched_pkg", + ("_bintree", "_build_dir", "_build_prefix", + "_ebuild_path", "_fetched_pkg", "_image_dir", "_infloc", "_pkg_path", "_tree", "_verify") =20 def _writemsg_level(self, msg, level=3D0, noiselevel=3D0): @@ -83,9 +86,9 @@ class Binpkg(CompositeTask): =20 waiting_msg =3D ("Fetching '%s' " + \ "in the background. " + \ - "To view fetch progress, run `tail -f " + \ + "To view fetch progress, run `tail -f %s" + \ "/var/log/emerge-fetch.log` in another " + \ - "terminal.") % prefetcher.pkg_path + "terminal.") % (prefetcher.pkg_path, settings["EPREFIX"]) msg_prefix =3D colorize("GOOD", " * ") from textwrap import wrap waiting_msg =3D "".join("%s%s\n" % (msg_prefix, line) \ @@ -299,10 +302,61 @@ class Binpkg(CompositeTask): self._start_task(extractor, self._extractor_exit) =20 def _extractor_exit(self, extractor): - if self._final_exit(extractor) !=3D os.EX_OK: + if self._default_exit(extractor) !=3D os.EX_OK: self._unlock_builddir() self._writemsg_level("!!! Error Extracting '%s'\n" % \ self._pkg_path, noiselevel=3D-1, level=3Dlogging.ERROR) + self.wait() + return + + try: + with io.open(_unicode_encode(os.path.join(self._infloc, "EPREFIX"), + encoding=3D_encodings['fs'], errors=3D'strict'), mode=3D'r', + encoding=3D_encodings['repo.content'], errors=3D'replace') as f: + self._build_prefix =3D f.read().rstrip('\n') + except IOError: + self._build_prefix =3D "" + + if self._build_prefix =3D=3D self.settings["EPREFIX"]: + self._current_task =3D None + self.returncode =3D os.EX_OK + self.wait() + return + + chpathtool =3D SpawnProcess( + args=3D[portage._python_interpreter, + os.path.join(self.settings["PORTAGE_BIN_PATH"], "chpathtool.py"), + self.settings["D"], self._build_prefix, self.settings["EPREFIX"]], + background=3Dself.background, env=3Dself.settings.environ(),=20 + scheduler=3Dself.scheduler, + logfile=3Dself.settings.get('PORTAGE_LOG_FILE')) + self._writemsg_level(">>> Adjusting Prefix to %s\n" % self.settings["E= PREFIX"]) + self._start_task(chpathtool, self._chpathtool_exit) + + def _chpathtool_exit(self, chpathtool): + if self._final_exit(chpathtool) !=3D os.EX_OK: + self._unlock_builddir() + self._writemsg_level("!!! Error Adjusting Prefix to %s" % + (self.settings["EPREFIX"],), + noiselevel=3D-1, level=3Dlogging.ERROR) + self.wait() + return + + # We want to install in "our" prefix, not the binary one + with io.open(_unicode_encode(os.path.join(self._infloc, "EPREFIX"), + encoding=3D_encodings['fs'], errors=3D'strict'), mode=3D'w', + encoding=3D_encodings['repo.content'], errors=3D'strict') as f: + f.write(self.settings["EPREFIX"] + "\n") + + # Move the files to the correct location for merge. + image_tmp_dir =3D os.path.join( + self.settings["PORTAGE_BUILDDIR"], "image_tmp") + os.rename(os.path.join(self.settings["D"], + self._build_prefix.lstrip(os.sep)), image_tmp_dir) + shutil.rmtree(self._image_dir) + ensure_dirs(os.path.dirname(self.settings["ED"])) + os.rename(image_tmp_dir, self.settings["ED"]) + self.wait() =20 def _unlock_builddir(self):