2 # Copyright 2013 Gentoo Foundation
3 # Distributed under the terms of the GNU General Public License v2
12 from portage.util._argparse import ArgumentParser
13 from portage.util.movefile import _copyxattr
14 from portage.exception import OperationNotSupported
16 # Change back to original cwd _after_ all imports (bug #469338).
17 os.chdir(os.environ["__PORTAGE_HELPER_CWD"])
21 Parse the command line arguments using optparse for python 2.6 compatibility
23 args: a list of the white space delimited command line
25 tuple of the Namespace of parsed options, and a list of order parameters
27 parser = ArgumentParser(add_help=False)
80 "--preserve-timestamps",
83 dest="preserve_timestamps"
103 "--target-directory",
106 dest="target_directory"
109 "--no-target-directory",
112 dest="no_target_directory"
137 # Use parse_known_args for maximum compatibility with
138 # getopt handling of non-option file arguments. Note
139 # that parser.add_argument("files", nargs='+') would
140 # be subtly incompatible because it requires that all
141 # of the file arguments be grouped sequentially. Also
142 # note that we have to explicitly call add_argument
143 # for known options in order for argparse to correctly
144 # separate option arguments from file arguments in all
145 # cases (it also allows for optparse compatibility).
146 parsed_args = parser.parse_known_args()
148 opts = parsed_args[0]
149 files = parsed_args[1]
150 files = [f for f in files if f != "--"] # filter out "--"
155 def copy_xattrs(opts, files):
157 Copy the extended attributes using portage.util.movefile._copyxattr
159 opts: Namespace of the parsed command line otions
160 files: list of ordered command line parameters which should be files/directories
164 if opts.directory or not files:
167 if opts.target_directory is None:
168 source, target = files[:-1], files[-1]
169 target_is_directory = os.path.isdir(target)
171 source, target = files, opts.target_directory
172 target_is_directory = True
174 exclude = os.environ.get("PORTAGE_XATTR_EXCLUDE", "security.* system.nfs4_acl")
177 if target_is_directory:
179 abs_path = os.path.join(target, os.path.basename(s))
180 _copyxattr(s, abs_path, exclude=exclude)
182 _copyxattr(source[0], target, exclude=exclude)
185 except OperationNotSupported:
186 traceback.print_exc()
190 def Which(filename, path=None, exclude=None):
192 Find the absolute path of 'filename' in a given search 'path'
194 filename: basename of the file
195 path: colon delimited search path
196 exclude: path of file to exclude
199 path = os.environ.get('PATH', '')
201 if exclude is not None:
202 st = os.stat(exclude)
203 exclude = (st.st_ino, st.st_dev)
205 for p in path.split(':'):
206 p = os.path.join(p, filename)
207 if os.access(p, os.X_OK):
214 if stat.S_ISREG(st.st_mode) and \
215 (exclude is None or exclude != (st.st_ino, st.st_dev)):
222 opts, files = parse_args(args)
223 install_binary = Which('install', exclude=os.environ["__PORTAGE_HELPER_PATH"])
224 if install_binary is None:
225 sys.stderr.write("install: command not found\n")
228 cmdline = [install_binary]
231 if sys.hexversion >= 0x3000000:
232 # We can't trust that the filesystem encoding (locale dependent)
233 # correctly matches the arguments, so use surrogateescape to
234 # pass through the original argv bytes for Python 3.
235 fs_encoding = sys.getfilesystemencoding()
236 cmdline = [x.encode(fs_encoding, 'surrogateescape') for x in cmdline]
237 files = [x.encode(fs_encoding, 'surrogateescape') for x in files]
238 if opts.target_directory is not None:
239 opts.target_directory = \
240 opts.target_directory.encode(fs_encoding, 'surrogateescape')
242 returncode = subprocess.call(cmdline)
243 if returncode == os.EX_OK:
244 returncode = copy_xattrs(opts, files)
245 if returncode != os.EX_OK:
246 portage.util.writemsg("!!! install: copy_xattrs failed with the "
247 "following arguments: %s\n" %
248 " ".join(portage._shell_quote(x) for x in args), noiselevel=-1)
252 if __name__ == "__main__":
253 sys.exit(main(sys.argv[1:]))