#!/usr/bin/python -b # Copyright 2013-2014 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 import argparse import os import stat import sys import subprocess import traceback import portage from portage.util.movefile import _copyxattr from portage.exception import OperationNotSupported # Change back to original cwd _after_ all imports (bug #469338). os.chdir(os.environ["__PORTAGE_HELPER_CWD"]) def parse_args(args): """ Parse the command line arguments using optparse for python 2.6 compatibility Args: args: a list of the white space delimited command line Returns: tuple of the Namespace of parsed options, and a list of order parameters """ parser = argparse.ArgumentParser(add_help=False) parser.add_argument("-b", action="store_true", dest="shortopt_b") parser.add_argument("--backup", action="store", dest="backup") parser.add_argument("-c", action="store_true", dest="shortopt_c") parser.add_argument("--compare", "-C", action="store_true", dest="compare") parser.add_argument("--directory", "-d", action="store_true", dest="directory") parser.add_argument("-D", action="store_true", dest="shortopt_D") parser.add_argument("--owner", "-o", action="store", dest="owner") parser.add_argument("--group", "-g", action="store", dest="group") parser.add_argument("--mode", "-m", action="store", dest="mode") parser.add_argument( "--preserve-timestamps", "-p", action="store_true", dest="preserve_timestamps" ) parser.add_argument("--strip", "-s", action="store_true", dest="strip") parser.add_argument("--strip-program", action="store", dest="strip_program") parser.add_argument("--suffix", "-S", action="store", dest="suffix") parser.add_argument( "--target-directory", "-t", action="store", dest="target_directory" ) parser.add_argument( "--no-target-directory", "-T", action="store_true", dest="no_target_directory" ) parser.add_argument("--verbose", "-v", action="store_true", dest="verbose") parser.add_argument("--help", action="store_true", dest="help") parser.add_argument("--version", action="store_true", dest="version") # Use parse_known_args for maximum compatibility with # getopt handling of non-option file arguments. Note # that parser.add_argument("files", nargs='+') would # be subtly incompatible because it requires that all # of the file arguments be grouped sequentially. Also # note that we have to explicitly call add_argument # for known options in order for argparse to correctly # separate option arguments from file arguments in all # cases (it also allows for optparse compatibility). (opts, args) = parser.parse_known_args(args) files = [] i = 0 while i < len(args): if args[i] == "--": i += 1 break if not args[i].startswith("-"): files.append(args[i]) i += 1 while i < len(args): files.append(args[i]) i += 1 return (opts, files) def copy_xattrs(opts, files): """ Copy the extended attributes using portage.util.movefile._copyxattr Args: opts: Namespace of the parsed command line otions files: list of ordered command line parameters which should be files/directories Returns: system exit code """ if opts.directory or not files: return os.EX_OK if opts.target_directory is None: source, target = files[:-1], files[-1] target_is_directory = os.path.isdir(target) else: source, target = files, opts.target_directory target_is_directory = True exclude = os.environ.get("PORTAGE_XATTR_EXCLUDE", "") try: if target_is_directory: for s in source: abs_path = os.path.join(target, os.path.basename(s)) _copyxattr(s, abs_path, exclude=exclude) else: _copyxattr(source[0], target, exclude=exclude) return os.EX_OK except OperationNotSupported: traceback.print_exc() return os.EX_OSERR def Which(filename, path=None, exclude=None): """ Find the absolute path of 'filename' in a given search 'path' Args: filename: basename of the file path: colon delimited search path exclude: path of file to exclude """ if path is None: path = os.environ.get("PATH", "") if exclude is not None: st = os.stat(exclude) exclude = (st.st_ino, st.st_dev) for p in path.split(":"): p = os.path.join(p, filename) if os.access(p, os.X_OK): try: st = os.stat(p) except OSError: # file disappeared? pass else: if stat.S_ISREG(st.st_mode) and ( exclude is None or exclude != (st.st_ino, st.st_dev) ): return p return None def main(args): opts, files = parse_args(args) install_binary = Which("install", exclude=os.environ["__PORTAGE_HELPER_PATH"]) if install_binary is None: sys.stderr.write("install: command not found\n") return 127 cmdline = [install_binary] cmdline += args # We can't trust that the filesystem encoding (locale dependent) # correctly matches the arguments, so use surrogateescape to # pass through the original argv bytes for Python 3. fs_encoding = sys.getfilesystemencoding() cmdline = [x.encode(fs_encoding, "surrogateescape") for x in cmdline] files = [x.encode(fs_encoding, "surrogateescape") for x in files] if opts.target_directory is not None: opts.target_directory = opts.target_directory.encode( fs_encoding, "surrogateescape" ) returncode = subprocess.call(cmdline) if returncode == os.EX_OK: returncode = copy_xattrs(opts, files) if returncode != os.EX_OK: portage.util.writemsg( "!!! install: copy_xattrs failed with the " "following arguments: %s\n" % " ".join(portage._shell_quote(x) for x in args), noiselevel=-1, ) return returncode if __name__ == "__main__": sys.exit(main(sys.argv[1:]))