~ibmcharmers/charms/xenial/ibm-cinder-storwize-svc/trunk

« back to all changes in this revision

Viewing changes to .tox/py35/lib/python3.5/site-packages/pip/_vendor/distlib/scripts.py

  • Committer: Ankammarao
  • Date: 2017-03-06 05:11:42 UTC
  • Revision ID: achittet@in.ibm.com-20170306051142-dpg27z4es1k56hfn
Marked tests folder executable

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
#
 
7
from io import BytesIO
 
8
import logging
 
9
import os
 
10
import re
 
11
import struct
 
12
import sys
 
13
 
 
14
from .compat import sysconfig, detect_encoding, ZipFile
 
15
from .resources import finder
 
16
from .util import (FileOperator, get_export_entry, convert_path,
 
17
                   get_executable, in_venv)
 
18
 
 
19
logger = 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
 
40
FIRST_LINE_RE = re.compile(b'^#!.*pythonw?[0-9.]*([ \t].*)?$')
 
41
SCRIPT_TEMPLATE = '''# -*- coding: utf-8 -*-
 
42
if __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
 
 
66
def _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
 
 
82
class 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 _get_shebang(self, encoding, post_interp=b'', options=None):
 
140
        enquote = True
 
141
        if self.executable:
 
142
            executable = self.executable
 
143
            enquote = False     # assume this will be taken care of
 
144
        elif not sysconfig.is_python_build():
 
145
            executable = get_executable()
 
146
        elif in_venv():  # pragma: no cover
 
147
            executable = os.path.join(sysconfig.get_path('scripts'),
 
148
                            'python%s' % sysconfig.get_config_var('EXE'))
 
149
        else:  # pragma: no cover
 
150
            executable = os.path.join(
 
151
                sysconfig.get_config_var('BINDIR'),
 
152
               'python%s%s' % (sysconfig.get_config_var('VERSION'),
 
153
                               sysconfig.get_config_var('EXE')))
 
154
        if options:
 
155
            executable = self._get_alternate_executable(executable, options)
 
156
 
 
157
        if sys.platform.startswith('java'):  # pragma: no cover
 
158
            executable = self._fix_jython_executable(executable)
 
159
        # Normalise case for Windows
 
160
        executable = os.path.normcase(executable)
 
161
        # If the user didn't specify an executable, it may be necessary to
 
162
        # cater for executable paths with spaces (not uncommon on Windows)
 
163
        if enquote:
 
164
            executable = _enquote_executable(executable)
 
165
        # Issue #51: don't use fsencode, since we later try to
 
166
        # check that the shebang is decodable using utf-8.
 
167
        executable = executable.encode('utf-8')
 
168
        # in case of IronPython, play safe and enable frames support
 
169
        if (sys.platform == 'cli' and '-X:Frames' not in post_interp
 
170
            and '-X:FullFrames' not in post_interp):  # pragma: no cover
 
171
            post_interp += b' -X:Frames'
 
172
        shebang = b'#!' + executable + post_interp + b'\n'
 
173
        # Python parser starts to read a script using UTF-8 until
 
174
        # it gets a #coding:xxx cookie. The shebang has to be the
 
175
        # first line of a file, the #coding:xxx cookie cannot be
 
176
        # written before. So the shebang has to be decodable from
 
177
        # UTF-8.
 
178
        try:
 
179
            shebang.decode('utf-8')
 
180
        except UnicodeDecodeError:  # pragma: no cover
 
181
            raise ValueError(
 
182
                'The shebang (%r) is not decodable from utf-8' % shebang)
 
183
        # If the script is encoded to a custom encoding (use a
 
184
        # #coding:xxx cookie), the shebang has to be decodable from
 
185
        # the script encoding too.
 
186
        if encoding != 'utf-8':
 
187
            try:
 
188
                shebang.decode(encoding)
 
189
            except UnicodeDecodeError:  # pragma: no cover
 
190
                raise ValueError(
 
191
                    'The shebang (%r) is not decodable '
 
192
                    'from the script encoding (%r)' % (shebang, encoding))
 
193
        return shebang
 
194
 
 
195
    def _get_script_text(self, entry):
 
196
        return self.script_template % dict(module=entry.prefix,
 
197
                                           func=entry.suffix)
 
198
 
 
199
    manifest = _DEFAULT_MANIFEST
 
200
 
 
201
    def get_manifest(self, exename):
 
202
        base = os.path.basename(exename)
 
203
        return self.manifest % base
 
204
 
 
205
    def _write_script(self, names, shebang, script_bytes, filenames, ext):
 
206
        use_launcher = self.add_launchers and self._is_nt
 
207
        linesep = os.linesep.encode('utf-8')
 
208
        if not use_launcher:
 
209
            script_bytes = shebang + linesep + script_bytes
 
210
        else:  # pragma: no cover
 
211
            if ext == 'py':
 
212
                launcher = self._get_launcher('t')
 
213
            else:
 
214
                launcher = self._get_launcher('w')
 
215
            stream = BytesIO()
 
216
            with ZipFile(stream, 'w') as zf:
 
217
                zf.writestr('__main__.py', script_bytes)
 
218
            zip_data = stream.getvalue()
 
219
            script_bytes = launcher + shebang + linesep + zip_data
 
220
        for name in names:
 
221
            outname = os.path.join(self.target_dir, name)
 
222
            if use_launcher:  # pragma: no cover
 
223
                n, e = os.path.splitext(outname)
 
224
                if e.startswith('.py'):
 
225
                    outname = n
 
226
                outname = '%s.exe' % outname
 
227
                try:
 
228
                    self._fileop.write_binary_file(outname, script_bytes)
 
229
                except Exception:
 
230
                    # Failed writing an executable - it might be in use.
 
231
                    logger.warning('Failed to write executable - trying to '
 
232
                                   'use .deleteme logic')
 
233
                    dfname = '%s.deleteme' % outname
 
234
                    if os.path.exists(dfname):
 
235
                        os.remove(dfname)       # Not allowed to fail here
 
236
                    os.rename(outname, dfname)  # nor here
 
237
                    self._fileop.write_binary_file(outname, script_bytes)
 
238
                    logger.debug('Able to replace executable using '
 
239
                                 '.deleteme logic')
 
240
                    try:
 
241
                        os.remove(dfname)
 
242
                    except Exception:
 
243
                        pass    # still in use - ignore error
 
244
            else:
 
245
                if self._is_nt and not outname.endswith('.' + ext):  # pragma: no cover
 
246
                    outname = '%s.%s' % (outname, ext)
 
247
                if os.path.exists(outname) and not self.clobber:
 
248
                    logger.warning('Skipping existing file %s', outname)
 
249
                    continue
 
250
                self._fileop.write_binary_file(outname, script_bytes)
 
251
                if self.set_mode:
 
252
                    self._fileop.set_executable_mode([outname])
 
253
            filenames.append(outname)
 
254
 
 
255
    def _make_script(self, entry, filenames, options=None):
 
256
        post_interp = b''
 
257
        if options:
 
258
            args = options.get('interpreter_args', [])
 
259
            if args:
 
260
                args = ' %s' % ' '.join(args)
 
261
                post_interp = args.encode('utf-8')
 
262
        shebang = self._get_shebang('utf-8', post_interp, options=options)
 
263
        script = self._get_script_text(entry).encode('utf-8')
 
264
        name = entry.name
 
265
        scriptnames = set()
 
266
        if '' in self.variants:
 
267
            scriptnames.add(name)
 
268
        if 'X' in self.variants:
 
269
            scriptnames.add('%s%s' % (name, sys.version[0]))
 
270
        if 'X.Y' in self.variants:
 
271
            scriptnames.add('%s-%s' % (name, sys.version[:3]))
 
272
        if options and options.get('gui', False):
 
273
            ext = 'pyw'
 
274
        else:
 
275
            ext = 'py'
 
276
        self._write_script(scriptnames, shebang, script, filenames, ext)
 
277
 
 
278
    def _copy_script(self, script, filenames):
 
279
        adjust = False
 
280
        script = os.path.join(self.source_dir, convert_path(script))
 
281
        outname = os.path.join(self.target_dir, os.path.basename(script))
 
282
        if not self.force and not self._fileop.newer(script, outname):
 
283
            logger.debug('not copying %s (up-to-date)', script)
 
284
            return
 
285
 
 
286
        # Always open the file, but ignore failures in dry-run mode --
 
287
        # that way, we'll get accurate feedback if we can read the
 
288
        # script.
 
289
        try:
 
290
            f = open(script, 'rb')
 
291
        except IOError:  # pragma: no cover
 
292
            if not self.dry_run:
 
293
                raise
 
294
            f = None
 
295
        else:
 
296
            first_line = f.readline()
 
297
            if not first_line:  # pragma: no cover
 
298
                logger.warning('%s: %s is an empty file (skipping)',
 
299
                               self.get_command_name(),  script)
 
300
                return
 
301
 
 
302
            match = FIRST_LINE_RE.match(first_line.replace(b'\r\n', b'\n'))
 
303
            if match:
 
304
                adjust = True
 
305
                post_interp = match.group(1) or b''
 
306
 
 
307
        if not adjust:
 
308
            if f:
 
309
                f.close()
 
310
            self._fileop.copy_file(script, outname)
 
311
            if self.set_mode:
 
312
                self._fileop.set_executable_mode([outname])
 
313
            filenames.append(outname)
 
314
        else:
 
315
            logger.info('copying and adjusting %s -> %s', script,
 
316
                        self.target_dir)
 
317
            if not self._fileop.dry_run:
 
318
                encoding, lines = detect_encoding(f.readline)
 
319
                f.seek(0)
 
320
                shebang = self._get_shebang(encoding, post_interp)
 
321
                if b'pythonw' in first_line:  # pragma: no cover
 
322
                    ext = 'pyw'
 
323
                else:
 
324
                    ext = 'py'
 
325
                n = os.path.basename(outname)
 
326
                self._write_script([n], shebang, f.read(), filenames, ext)
 
327
            if f:
 
328
                f.close()
 
329
 
 
330
    @property
 
331
    def dry_run(self):
 
332
        return self._fileop.dry_run
 
333
 
 
334
    @dry_run.setter
 
335
    def dry_run(self, value):
 
336
        self._fileop.dry_run = value
 
337
 
 
338
    if os.name == 'nt' or (os.name == 'java' and os._name == 'nt'):  # pragma: no cover
 
339
        # Executable launcher support.
 
340
        # Launchers are from https://bitbucket.org/vinay.sajip/simple_launcher/
 
341
 
 
342
        def _get_launcher(self, kind):
 
343
            if struct.calcsize('P') == 8:   # 64-bit
 
344
                bits = '64'
 
345
            else:
 
346
                bits = '32'
 
347
            name = '%s%s.exe' % (kind, bits)
 
348
            # Issue 31: don't hardcode an absolute package name, but
 
349
            # determine it relative to the current package
 
350
            distlib_package = __name__.rsplit('.', 1)[0]
 
351
            result = finder(distlib_package).find(name).bytes
 
352
            return result
 
353
 
 
354
    # Public API follows
 
355
 
 
356
    def make(self, specification, options=None):
 
357
        """
 
358
        Make a script.
 
359
 
 
360
        :param specification: The specification, which is either a valid export
 
361
                              entry specification (to make a script from a
 
362
                              callable) or a filename (to make a script by
 
363
                              copying from a source location).
 
364
        :param options: A dictionary of options controlling script generation.
 
365
        :return: A list of all absolute pathnames written to.
 
366
        """
 
367
        filenames = []
 
368
        entry = get_export_entry(specification)
 
369
        if entry is None:
 
370
            self._copy_script(specification, filenames)
 
371
        else:
 
372
            self._make_script(entry, filenames, options=options)
 
373
        return filenames
 
374
 
 
375
    def make_multiple(self, specifications, options=None):
 
376
        """
 
377
        Take a list of specifications and make scripts from them,
 
378
        :param specifications: A list of specifications.
 
379
        :return: A list of all absolute pathnames written to,
 
380
        """
 
381
        filenames = []
 
382
        for specification in specifications:
 
383
            filenames.extend(self.make(specification, options))
 
384
        return filenames