blob: 3c5e0de657dd5292afcfc4b5ee09fa205c05fd50 [file] [log] [blame]
#!/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:]))