| #!/usr/bin/python -b |
| # Copyright 2013-2014 Gentoo Foundation |
| # Distributed under the terms of the GNU General Public License v2 |
| |
| import os |
| import stat |
| import sys |
| import subprocess |
| import traceback |
| |
| import portage |
| from portage.util._argparse import ArgumentParser |
| 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 = 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( |
| "--context", |
| "-Z", |
| action="store", |
| dest="context" |
| ) |
| 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). |
| parsed_args = parser.parse_known_args() |
| |
| opts = parsed_args[0] |
| files = parsed_args[1] |
| files = [f for f in files if f != "--"] # filter out "--" |
| |
| 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", "security.* system.nfs4_acl") |
| |
| 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 |
| |
| if sys.hexversion >= 0x3000000: |
| # 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:])) |