summaryrefslogtreecommitdiff
path: root/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/distlib/scripts.py
diff options
context:
space:
mode:
authorShubham Saini <shubham6405@gmail.com>2018-12-11 10:01:23 +0000
committerShubham Saini <shubham6405@gmail.com>2018-12-11 10:01:23 +0000
commit68df54d6629ec019142eb149dd037774f2d11e7c (patch)
tree345bc22d46b4e01a4ba8303b94278952a4ed2b9e /venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/distlib/scripts.py
First commit
Diffstat (limited to 'venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/distlib/scripts.py')
-rw-r--r--venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/distlib/scripts.py415
1 files changed, 415 insertions, 0 deletions
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/distlib/scripts.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/distlib/scripts.py
new file mode 100644
index 0000000..440bd30
--- /dev/null
+++ b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/distlib/scripts.py
@@ -0,0 +1,415 @@
1# -*- coding: utf-8 -*-
2#
3# Copyright (C) 2013-2015 Vinay Sajip.
4# Licensed to the Python Software Foundation under a contributor agreement.
5# See LICENSE.txt and CONTRIBUTORS.txt.
6#
7from io import BytesIO
8import logging
9import os
10import re
11import struct
12import sys
13
14from .compat import sysconfig, detect_encoding, ZipFile
15from .resources import finder
16from .util import (FileOperator, get_export_entry, convert_path,
17 get_executable, in_venv)
18
19logger = logging.getLogger(__name__)
20
21_DEFAULT_MANIFEST = '''
22<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
23<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
24 <assemblyIdentity version="1.0.0.0"
25 processorArchitecture="X86"
26 name="%s"
27 type="win32"/>
28
29 <!-- Identify the application security requirements. -->
30 <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
31 <security>
32 <requestedPrivileges>
33 <requestedExecutionLevel level="asInvoker" uiAccess="false"/>
34 </requestedPrivileges>
35 </security>
36 </trustInfo>
37</assembly>'''.strip()
38
39# check if Python is called on the first line with this expression
40FIRST_LINE_RE = re.compile(b'^#!.*pythonw?[0-9.]*([ \t].*)?$')
41SCRIPT_TEMPLATE = r'''# -*- coding: utf-8 -*-
42if __name__ == '__main__':
43 import sys, re
44
45 def _resolve(module, func):
46 __import__(module)
47 mod = sys.modules[module]
48 parts = func.split('.')
49 result = getattr(mod, parts.pop(0))
50 for p in parts:
51 result = getattr(result, p)
52 return result
53
54 try:
55 sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
56
57 func = _resolve('%(module)s', '%(func)s')
58 rc = func() # None interpreted as 0
59 except Exception as e: # only supporting Python >= 2.6
60 sys.stderr.write('%%s\n' %% e)
61 rc = 1
62 sys.exit(rc)
63'''
64
65
66def _enquote_executable(executable):
67 if ' ' in executable:
68 # make sure we quote only the executable in case of env
69 # for example /usr/bin/env "/dir with spaces/bin/jython"
70 # instead of "/usr/bin/env /dir with spaces/bin/jython"
71 # otherwise whole
72 if executable.startswith('/usr/bin/env '):
73 env, _executable = executable.split(' ', 1)
74 if ' ' in _executable and not _executable.startswith('"'):
75 executable = '%s "%s"' % (env, _executable)
76 else:
77 if not executable.startswith('"'):
78 executable = '"%s"' % executable
79 return executable
80
81
82class ScriptMaker(object):
83 """
84 A class to copy or create scripts from source scripts or callable
85 specifications.
86 """
87 script_template = SCRIPT_TEMPLATE
88
89 executable = None # for shebangs
90
91 def __init__(self, source_dir, target_dir, add_launchers=True,
92 dry_run=False, fileop=None):
93 self.source_dir = source_dir
94 self.target_dir = target_dir
95 self.add_launchers = add_launchers
96 self.force = False
97 self.clobber = False
98 # It only makes sense to set mode bits on POSIX.
99 self.set_mode = (os.name == 'posix') or (os.name == 'java' and
100 os._name == 'posix')
101 self.variants = set(('', 'X.Y'))
102 self._fileop = fileop or FileOperator(dry_run)
103
104 self._is_nt = os.name == 'nt' or (
105 os.name == 'java' and os._name == 'nt')
106
107 def _get_alternate_executable(self, executable, options):
108 if options.get('gui', False) and self._is_nt: # pragma: no cover
109 dn, fn = os.path.split(executable)
110 fn = fn.replace('python', 'pythonw')
111 executable = os.path.join(dn, fn)
112 return executable
113
114 if sys.platform.startswith('java'): # pragma: no cover
115 def _is_shell(self, executable):
116 """
117 Determine if the specified executable is a script
118 (contains a #! line)
119 """
120 try:
121 with open(executable) as fp:
122 return fp.read(2) == '#!'
123 except (OSError, IOError):
124 logger.warning('Failed to open %s', executable)
125 return False
126
127 def _fix_jython_executable(self, executable):
128 if self._is_shell(executable):
129 # Workaround for Jython is not needed on Linux systems.
130 import java
131
132 if java.lang.System.getProperty('os.name') == 'Linux':
133 return executable
134 elif executable.lower().endswith('jython.exe'):
135 # Use wrapper exe for Jython on Windows
136 return executable
137 return '/usr/bin/env %s' % executable
138
139 def _build_shebang(self, executable, post_interp):
140 """
141 Build a shebang line. In the simple case (on Windows, or a shebang line
142 which is not too long or contains spaces) use a simple formulation for
143 the shebang. Otherwise, use /bin/sh as the executable, with a contrived
144 shebang which allows the script to run either under Python or sh, using
145 suitable quoting. Thanks to Harald Nordgren for his input.
146
147 See also: http://www.in-ulm.de/~mascheck/various/shebang/#length
148 https://hg.mozilla.org/mozilla-central/file/tip/mach
149 """
150 if os.name != 'posix':
151 simple_shebang = True
152 else:
153 # Add 3 for '#!' prefix and newline suffix.
154 shebang_length = len(executable) + len(post_interp) + 3
155 if sys.platform == 'darwin':
156 max_shebang_length = 512
157 else:
158 max_shebang_length = 127
159 simple_shebang = ((b' ' not in executable) and
160 (shebang_length <= max_shebang_length))
161
162 if simple_shebang:
163 result = b'#!' + executable + post_interp + b'\n'
164 else:
165 result = b'#!/bin/sh\n'
166 result += b"'''exec' " + executable + post_interp + b' "$0" "$@"\n'
167 result += b"' '''"
168 return result
169
170 def _get_shebang(self, encoding, post_interp=b'', options=None):
171 enquote = True
172 if self.executable:
173 executable = self.executable
174 enquote = False # assume this will be taken care of
175 elif not sysconfig.is_python_build():
176 executable = get_executable()
177 elif in_venv(): # pragma: no cover
178 executable = os.path.join(sysconfig.get_path('scripts'),
179 'python%s' % sysconfig.get_config_var('EXE'))
180 else: # pragma: no cover
181 executable = os.path.join(
182 sysconfig.get_config_var('BINDIR'),
183 'python%s%s' % (sysconfig.get_config_var('VERSION'),
184 sysconfig.get_config_var('EXE')))
185 if options:
186 executable = self._get_alternate_executable(executable, options)
187
188 if sys.platform.startswith('java'): # pragma: no cover
189 executable = self._fix_jython_executable(executable)
190 # Normalise case for Windows
191 executable = os.path.normcase(executable)
192 # If the user didn't specify an executable, it may be necessary to
193 # cater for executable paths with spaces (not uncommon on Windows)
194 if enquote:
195 executable = _enquote_executable(executable)
196 # Issue #51: don't use fsencode, since we later try to
197 # check that the shebang is decodable using utf-8.
198 executable = executable.encode('utf-8')
199 # in case of IronPython, play safe and enable frames support
200 if (sys.platform == 'cli' and '-X:Frames' not in post_interp
201 and '-X:FullFrames' not in post_interp): # pragma: no cover
202 post_interp += b' -X:Frames'
203 shebang = self._build_shebang(executable, post_interp)
204 # Python parser starts to read a script using UTF-8 until
205 # it gets a #coding:xxx cookie. The shebang has to be the
206 # first line of a file, the #coding:xxx cookie cannot be
207 # written before. So the shebang has to be decodable from
208 # UTF-8.
209 try:
210 shebang.decode('utf-8')
211 except UnicodeDecodeError: # pragma: no cover
212 raise ValueError(
213 'The shebang (%r) is not decodable from utf-8' % shebang)
214 # If the script is encoded to a custom encoding (use a
215 # #coding:xxx cookie), the shebang has to be decodable from
216 # the script encoding too.
217 if encoding != 'utf-8':
218 try:
219 shebang.decode(encoding)
220 except UnicodeDecodeError: # pragma: no cover
221 raise ValueError(
222 'The shebang (%r) is not decodable '
223 'from the script encoding (%r)' % (shebang, encoding))
224 return shebang
225
226 def _get_script_text(self, entry):
227 return self.script_template % dict(module=entry.prefix,
228 func=entry.suffix)
229
230 manifest = _DEFAULT_MANIFEST
231
232 def get_manifest(self, exename):
233 base = os.path.basename(exename)
234 return self.manifest % base
235
236 def _write_script(self, names, shebang, script_bytes, filenames, ext):
237 use_launcher = self.add_launchers and self._is_nt
238 linesep = os.linesep.encode('utf-8')
239 if not use_launcher:
240 script_bytes = shebang + linesep + script_bytes
241 else: # pragma: no cover
242 if ext == 'py':
243 launcher = self._get_launcher('t')
244 else:
245 launcher = self._get_launcher('w')
246 stream = BytesIO()
247 with ZipFile(stream, 'w') as zf:
248 zf.writestr('__main__.py', script_bytes)
249 zip_data = stream.getvalue()
250 script_bytes = launcher + shebang + linesep + zip_data
251 for name in names:
252 outname = os.path.join(self.target_dir, name)
253 if use_launcher: # pragma: no cover
254 n, e = os.path.splitext(outname)
255 if e.startswith('.py'):
256 outname = n
257 outname = '%s.exe' % outname
258 try:
259 self._fileop.write_binary_file(outname, script_bytes)
260 except Exception:
261 # Failed writing an executable - it might be in use.
262 logger.warning('Failed to write executable - trying to '
263 'use .deleteme logic')
264 dfname = '%s.deleteme' % outname
265 if os.path.exists(dfname):
266 os.remove(dfname) # Not allowed to fail here
267 os.rename(outname, dfname) # nor here
268 self._fileop.write_binary_file(outname, script_bytes)
269 logger.debug('Able to replace executable using '
270 '.deleteme logic')
271 try:
272 os.remove(dfname)
273 except Exception:
274 pass # still in use - ignore error
275 else:
276 if self._is_nt and not outname.endswith('.' + ext): # pragma: no cover
277 outname = '%s.%s' % (outname, ext)
278 if os.path.exists(outname) and not self.clobber:
279 logger.warning('Skipping existing file %s', outname)
280 continue
281 self._fileop.write_binary_file(outname, script_bytes)
282 if self.set_mode:
283 self._fileop.set_executable_mode([outname])
284 filenames.append(outname)
285
286 def _make_script(self, entry, filenames, options=None):
287 post_interp = b''
288 if options:
289 args = options.get('interpreter_args', [])
290 if args:
291 args = ' %s' % ' '.join(args)
292 post_interp = args.encode('utf-8')
293 shebang = self._get_shebang('utf-8', post_interp, options=options)
294 script = self._get_script_text(entry).encode('utf-8')
295 name = entry.name
296 scriptnames = set()
297 if '' in self.variants:
298 scriptnames.add(name)
299 if 'X' in self.variants:
300 scriptnames.add('%s%s' % (name, sys.version[0]))
301 if 'X.Y' in self.variants:
302 scriptnames.add('%s-%s' % (name, sys.version[:3]))
303 if options and options.get('gui', False):
304 ext = 'pyw'
305 else:
306 ext = 'py'
307 self._write_script(scriptnames, shebang, script, filenames, ext)
308
309 def _copy_script(self, script, filenames):
310 adjust = False
311 script = os.path.join(self.source_dir, convert_path(script))
312 outname = os.path.join(self.target_dir, os.path.basename(script))
313 if not self.force and not self._fileop.newer(script, outname):
314 logger.debug('not copying %s (up-to-date)', script)
315 return
316
317 # Always open the file, but ignore failures in dry-run mode --
318 # that way, we'll get accurate feedback if we can read the
319 # script.
320 try:
321 f = open(script, 'rb')
322 except IOError: # pragma: no cover
323 if not self.dry_run:
324 raise
325 f = None
326 else:
327 first_line = f.readline()
328 if not first_line: # pragma: no cover
329 logger.warning('%s: %s is an empty file (skipping)',
330 self.get_command_name(), script)
331 return
332
333 match = FIRST_LINE_RE.match(first_line.replace(b'\r\n', b'\n'))
334 if match:
335 adjust = True
336 post_interp = match.group(1) or b''
337
338 if not adjust:
339 if f:
340 f.close()
341 self._fileop.copy_file(script, outname)
342 if self.set_mode:
343 self._fileop.set_executable_mode([outname])
344 filenames.append(outname)
345 else:
346 logger.info('copying and adjusting %s -> %s', script,
347 self.target_dir)
348 if not self._fileop.dry_run:
349 encoding, lines = detect_encoding(f.readline)
350 f.seek(0)
351 shebang = self._get_shebang(encoding, post_interp)
352 if b'pythonw' in first_line: # pragma: no cover
353 ext = 'pyw'
354 else:
355 ext = 'py'
356 n = os.path.basename(outname)
357 self._write_script([n], shebang, f.read(), filenames, ext)
358 if f:
359 f.close()
360
361 @property
362 def dry_run(self):
363 return self._fileop.dry_run
364
365 @dry_run.setter
366 def dry_run(self, value):
367 self._fileop.dry_run = value
368
369 if os.name == 'nt' or (os.name == 'java' and os._name == 'nt'): # pragma: no cover
370 # Executable launcher support.
371 # Launchers are from https://bitbucket.org/vinay.sajip/simple_launcher/
372
373 def _get_launcher(self, kind):
374 if struct.calcsize('P') == 8: # 64-bit
375 bits = '64'
376 else:
377 bits = '32'
378 name = '%s%s.exe' % (kind, bits)
379 # Issue 31: don't hardcode an absolute package name, but
380 # determine it relative to the current package
381 distlib_package = __name__.rsplit('.', 1)[0]
382 result = finder(distlib_package).find(name).bytes
383 return result
384
385 # Public API follows
386
387 def make(self, specification, options=None):
388 """
389 Make a script.
390
391 :param specification: The specification, which is either a valid export
392 entry specification (to make a script from a
393 callable) or a filename (to make a script by
394 copying from a source location).
395 :param options: A dictionary of options controlling script generation.
396 :return: A list of all absolute pathnames written to.
397 """
398 filenames = []
399 entry = get_export_entry(specification)
400 if entry is None:
401 self._copy_script(specification, filenames)
402 else:
403 self._make_script(entry, filenames, options=options)
404 return filenames
405
406 def make_multiple(self, specifications, options=None):
407 """
408 Take a list of specifications and make scripts from them,
409 :param specifications: A list of specifications.
410 :return: A list of all absolute pathnames written to,
411 """
412 filenames = []
413 for specification in specifications:
414 filenames.extend(self.make(specification, options))
415 return filenames