2 # Copyright 2013 Gentoo Foundation
3 # Distributed under the terms of the GNU General Public License v2
11 from portage.util.movefile import _copyxattr
12 from portage.exception import OperationNotSupported
15 from argparse import ArgumentParser
17 # Compatibility with Python 2.6 and 3.1
18 from optparse import OptionParser
20 class ArgumentParser(object):
21 def __init__(self, **kwargs):
22 add_help = kwargs.pop("add_help", None)
23 if add_help is not None:
24 kwargs["add_help_option"] = add_help
25 parser = OptionParser(**kwargs)
26 self.add_argument = parser.add_option
27 self.parse_known_args = parser.parse_args
29 # Change back to original cwd _after_ all imports (bug #469338).
30 os.chdir(os.environ["__PORTAGE_HELPER_CWD"])
34 Parse the command line arguments using optparse for python 2.6 compatibility
36 args: a list of the white space delimited command line
38 tuple of the Namespace of parsed options, and a list of order parameters
40 parser = ArgumentParser(add_help=False)
93 "--preserve-timestamps",
96 dest="preserve_timestamps"
116 "--target-directory",
119 dest="target_directory"
122 "--no-target-directory",
125 dest="no_target_directory"
150 # Use parse_known_args for maximum compatibility with
151 # getopt handling of non-option file arguments. Note
152 # that parser.add_argument("files", nargs='+') would
153 # be subtly incompatible because it requires that all
154 # of the file arguments be grouped sequentially. Also
155 # note that we have to explicitly call add_argument
156 # for known options in order for argparse to correctly
157 # separate option arguments from file arguments in all
158 # cases (it also allows for optparse compatibility).
159 parsed_args = parser.parse_known_args()
161 opts = parsed_args[0]
162 files = parsed_args[1]
163 files = [f for f in files if f != "--"] # filter out "--"
168 def copy_xattrs(opts, files):
170 Copy the extended attributes using portage.util.movefile._copyxattr
172 opts: Namespace of the parsed command line otions
173 files: list of ordered command line parameters which should be files/directories
180 if opts.target_directory is None:
181 source, target = files[:-1], files[-1]
182 target_is_directory = os.path.isdir(target)
184 source, target = files, opts.target_directory
185 target_is_directory = True
187 exclude = os.environ.get("PORTAGE_XATTR_EXCLUDE", "security.* system.nfs4_acl")
190 if target_is_directory:
192 abs_path = os.path.join(target, os.path.basename(s))
193 _copyxattr(s, abs_path, exclude=exclude)
195 _copyxattr(source[0], target, exclude=exclude)
198 except OperationNotSupported:
199 traceback.print_exc()
203 def Which(filename, path=None, exclude=None):
205 Find the absolute path of 'filename' in a given search 'path'
207 filename: basename of the file
208 path: colon delimited search path
209 exclude: path of file to exclude
212 path = os.environ.get('PATH', '')
214 if exclude is not None:
215 st = os.stat(exclude)
216 exclude = (st.st_ino, st.st_dev)
218 for p in path.split(':'):
219 p = os.path.join(p, filename)
220 if os.access(p, os.X_OK):
227 if stat.S_ISREG(st.st_mode) and \
228 (exclude is None or exclude != (st.st_ino, st.st_dev)):
235 opts, files = parse_args(args)
236 install_binary = Which('install', exclude=os.environ["__PORTAGE_HELPER_PATH"])
237 if install_binary is None:
238 sys.stderr.write("install: command not found\n")
241 cmdline = [install_binary]
244 if sys.hexversion >= 0x3000000:
245 # We can't trust that the filesystem encoding (locale dependent)
246 # correctly matches the arguments, so use surrogateescape to
247 # pass through the original argv bytes for Python 3.
248 fs_encoding = sys.getfilesystemencoding()
249 cmdline = [x.encode(fs_encoding, 'surrogateescape') for x in cmdline]
250 files = [x.encode(fs_encoding, 'surrogateescape') for x in files]
251 if opts.target_directory is not None:
252 opts.target_directory = \
253 opts.target_directory.encode(fs_encoding, 'surrogateescape')
255 returncode = subprocess.call(cmdline)
256 if returncode == os.EX_OK:
257 returncode = copy_xattrs(opts, files)
261 if __name__ == "__main__":
262 sys.exit(main(sys.argv[1:]))