xref: /aosp_15_r20/external/antlr/runtime/Python3/ez_setup.py (revision 16467b971bd3e2009fad32dd79016f2c7e421deb)
1*16467b97STreehugger Robot#!/usr/bin/env python
2*16467b97STreehugger Robot
3*16467b97STreehugger Robot"""
4*16467b97STreehugger RobotSetuptools bootstrapping installer.
5*16467b97STreehugger Robot
6*16467b97STreehugger RobotRun this script to install or upgrade setuptools.
7*16467b97STreehugger Robot"""
8*16467b97STreehugger Robot
9*16467b97STreehugger Robotimport os
10*16467b97STreehugger Robotimport shutil
11*16467b97STreehugger Robotimport sys
12*16467b97STreehugger Robotimport tempfile
13*16467b97STreehugger Robotimport zipfile
14*16467b97STreehugger Robotimport optparse
15*16467b97STreehugger Robotimport subprocess
16*16467b97STreehugger Robotimport platform
17*16467b97STreehugger Robotimport textwrap
18*16467b97STreehugger Robotimport contextlib
19*16467b97STreehugger Robotimport warnings
20*16467b97STreehugger Robot
21*16467b97STreehugger Robotfrom distutils import log
22*16467b97STreehugger Robot
23*16467b97STreehugger Robottry:
24*16467b97STreehugger Robot    from urllib.request import urlopen
25*16467b97STreehugger Robotexcept ImportError:
26*16467b97STreehugger Robot    from urllib2 import urlopen
27*16467b97STreehugger Robot
28*16467b97STreehugger Robottry:
29*16467b97STreehugger Robot    from site import USER_SITE
30*16467b97STreehugger Robotexcept ImportError:
31*16467b97STreehugger Robot    USER_SITE = None
32*16467b97STreehugger Robot
33*16467b97STreehugger RobotDEFAULT_VERSION = "15.0"
34*16467b97STreehugger RobotDEFAULT_URL = "https://pypi.python.org/packages/source/s/setuptools/"
35*16467b97STreehugger RobotDEFAULT_SAVE_DIR = os.curdir
36*16467b97STreehugger Robot
37*16467b97STreehugger Robot
38*16467b97STreehugger Robotdef _python_cmd(*args):
39*16467b97STreehugger Robot    """
40*16467b97STreehugger Robot    Execute a command.
41*16467b97STreehugger Robot
42*16467b97STreehugger Robot    Return True if the command succeeded.
43*16467b97STreehugger Robot    """
44*16467b97STreehugger Robot    args = (sys.executable,) + args
45*16467b97STreehugger Robot    return subprocess.call(args) == 0
46*16467b97STreehugger Robot
47*16467b97STreehugger Robot
48*16467b97STreehugger Robotdef _install(archive_filename, install_args=()):
49*16467b97STreehugger Robot    """Install Setuptools."""
50*16467b97STreehugger Robot    with archive_context(archive_filename):
51*16467b97STreehugger Robot        # installing
52*16467b97STreehugger Robot        log.warn('Installing Setuptools')
53*16467b97STreehugger Robot        if not _python_cmd('setup.py', 'install', *install_args):
54*16467b97STreehugger Robot            log.warn('Something went wrong during the installation.')
55*16467b97STreehugger Robot            log.warn('See the error message above.')
56*16467b97STreehugger Robot            # exitcode will be 2
57*16467b97STreehugger Robot            return 2
58*16467b97STreehugger Robot
59*16467b97STreehugger Robot
60*16467b97STreehugger Robotdef _build_egg(egg, archive_filename, to_dir):
61*16467b97STreehugger Robot    """Build Setuptools egg."""
62*16467b97STreehugger Robot    with archive_context(archive_filename):
63*16467b97STreehugger Robot        # building an egg
64*16467b97STreehugger Robot        log.warn('Building a Setuptools egg in %s', to_dir)
65*16467b97STreehugger Robot        _python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir)
66*16467b97STreehugger Robot    # returning the result
67*16467b97STreehugger Robot    log.warn(egg)
68*16467b97STreehugger Robot    if not os.path.exists(egg):
69*16467b97STreehugger Robot        raise IOError('Could not build the egg.')
70*16467b97STreehugger Robot
71*16467b97STreehugger Robot
72*16467b97STreehugger Robotclass ContextualZipFile(zipfile.ZipFile):
73*16467b97STreehugger Robot
74*16467b97STreehugger Robot    """Supplement ZipFile class to support context manager for Python 2.6."""
75*16467b97STreehugger Robot
76*16467b97STreehugger Robot    def __enter__(self):
77*16467b97STreehugger Robot        return self
78*16467b97STreehugger Robot
79*16467b97STreehugger Robot    def __exit__(self, type, value, traceback):
80*16467b97STreehugger Robot        self.close()
81*16467b97STreehugger Robot
82*16467b97STreehugger Robot    def __new__(cls, *args, **kwargs):
83*16467b97STreehugger Robot        """Construct a ZipFile or ContextualZipFile as appropriate."""
84*16467b97STreehugger Robot        if hasattr(zipfile.ZipFile, '__exit__'):
85*16467b97STreehugger Robot            return zipfile.ZipFile(*args, **kwargs)
86*16467b97STreehugger Robot        return super(ContextualZipFile, cls).__new__(cls)
87*16467b97STreehugger Robot
88*16467b97STreehugger Robot
89*16467b97STreehugger Robot@contextlib.contextmanager
90*16467b97STreehugger Robotdef archive_context(filename):
91*16467b97STreehugger Robot    """
92*16467b97STreehugger Robot    Unzip filename to a temporary directory, set to the cwd.
93*16467b97STreehugger Robot
94*16467b97STreehugger Robot    The unzipped target is cleaned up after.
95*16467b97STreehugger Robot    """
96*16467b97STreehugger Robot    tmpdir = tempfile.mkdtemp()
97*16467b97STreehugger Robot    log.warn('Extracting in %s', tmpdir)
98*16467b97STreehugger Robot    old_wd = os.getcwd()
99*16467b97STreehugger Robot    try:
100*16467b97STreehugger Robot        os.chdir(tmpdir)
101*16467b97STreehugger Robot        with ContextualZipFile(filename) as archive:
102*16467b97STreehugger Robot            archive.extractall()
103*16467b97STreehugger Robot
104*16467b97STreehugger Robot        # going in the directory
105*16467b97STreehugger Robot        subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0])
106*16467b97STreehugger Robot        os.chdir(subdir)
107*16467b97STreehugger Robot        log.warn('Now working in %s', subdir)
108*16467b97STreehugger Robot        yield
109*16467b97STreehugger Robot
110*16467b97STreehugger Robot    finally:
111*16467b97STreehugger Robot        os.chdir(old_wd)
112*16467b97STreehugger Robot        shutil.rmtree(tmpdir)
113*16467b97STreehugger Robot
114*16467b97STreehugger Robot
115*16467b97STreehugger Robotdef _do_download(version, download_base, to_dir, download_delay):
116*16467b97STreehugger Robot    """Download Setuptools."""
117*16467b97STreehugger Robot    egg = os.path.join(to_dir, 'setuptools-%s-py%d.%d.egg'
118*16467b97STreehugger Robot                       % (version, sys.version_info[0], sys.version_info[1]))
119*16467b97STreehugger Robot    if not os.path.exists(egg):
120*16467b97STreehugger Robot        archive = download_setuptools(version, download_base,
121*16467b97STreehugger Robot                                      to_dir, download_delay)
122*16467b97STreehugger Robot        _build_egg(egg, archive, to_dir)
123*16467b97STreehugger Robot    sys.path.insert(0, egg)
124*16467b97STreehugger Robot
125*16467b97STreehugger Robot    # Remove previously-imported pkg_resources if present (see
126*16467b97STreehugger Robot    # https://bitbucket.org/pypa/setuptools/pull-request/7/ for details).
127*16467b97STreehugger Robot    if 'pkg_resources' in sys.modules:
128*16467b97STreehugger Robot        del sys.modules['pkg_resources']
129*16467b97STreehugger Robot
130*16467b97STreehugger Robot    import setuptools
131*16467b97STreehugger Robot    setuptools.bootstrap_install_from = egg
132*16467b97STreehugger Robot
133*16467b97STreehugger Robot
134*16467b97STreehugger Robotdef use_setuptools(
135*16467b97STreehugger Robot        version=DEFAULT_VERSION, download_base=DEFAULT_URL,
136*16467b97STreehugger Robot        to_dir=DEFAULT_SAVE_DIR, download_delay=15):
137*16467b97STreehugger Robot    """
138*16467b97STreehugger Robot    Ensure that a setuptools version is installed.
139*16467b97STreehugger Robot
140*16467b97STreehugger Robot    Return None. Raise SystemExit if the requested version
141*16467b97STreehugger Robot    or later cannot be installed.
142*16467b97STreehugger Robot    """
143*16467b97STreehugger Robot    to_dir = os.path.abspath(to_dir)
144*16467b97STreehugger Robot
145*16467b97STreehugger Robot    # prior to importing, capture the module state for
146*16467b97STreehugger Robot    # representative modules.
147*16467b97STreehugger Robot    rep_modules = 'pkg_resources', 'setuptools'
148*16467b97STreehugger Robot    imported = set(sys.modules).intersection(rep_modules)
149*16467b97STreehugger Robot
150*16467b97STreehugger Robot    try:
151*16467b97STreehugger Robot        import pkg_resources
152*16467b97STreehugger Robot        pkg_resources.require("setuptools>=" + version)
153*16467b97STreehugger Robot        # a suitable version is already installed
154*16467b97STreehugger Robot        return
155*16467b97STreehugger Robot    except ImportError:
156*16467b97STreehugger Robot        # pkg_resources not available; setuptools is not installed; download
157*16467b97STreehugger Robot        pass
158*16467b97STreehugger Robot    except pkg_resources.DistributionNotFound:
159*16467b97STreehugger Robot        # no version of setuptools was found; allow download
160*16467b97STreehugger Robot        pass
161*16467b97STreehugger Robot    except pkg_resources.VersionConflict as VC_err:
162*16467b97STreehugger Robot        if imported:
163*16467b97STreehugger Robot            _conflict_bail(VC_err, version)
164*16467b97STreehugger Robot
165*16467b97STreehugger Robot        # otherwise, unload pkg_resources to allow the downloaded version to
166*16467b97STreehugger Robot        #  take precedence.
167*16467b97STreehugger Robot        del pkg_resources
168*16467b97STreehugger Robot        _unload_pkg_resources()
169*16467b97STreehugger Robot
170*16467b97STreehugger Robot    return _do_download(version, download_base, to_dir, download_delay)
171*16467b97STreehugger Robot
172*16467b97STreehugger Robot
173*16467b97STreehugger Robotdef _conflict_bail(VC_err, version):
174*16467b97STreehugger Robot    """
175*16467b97STreehugger Robot    Setuptools was imported prior to invocation, so it is
176*16467b97STreehugger Robot    unsafe to unload it. Bail out.
177*16467b97STreehugger Robot    """
178*16467b97STreehugger Robot    conflict_tmpl = textwrap.dedent("""
179*16467b97STreehugger Robot        The required version of setuptools (>={version}) is not available,
180*16467b97STreehugger Robot        and can't be installed while this script is running. Please
181*16467b97STreehugger Robot        install a more recent version first, using
182*16467b97STreehugger Robot        'easy_install -U setuptools'.
183*16467b97STreehugger Robot
184*16467b97STreehugger Robot        (Currently using {VC_err.args[0]!r})
185*16467b97STreehugger Robot        """)
186*16467b97STreehugger Robot    msg = conflict_tmpl.format(**locals())
187*16467b97STreehugger Robot    sys.stderr.write(msg)
188*16467b97STreehugger Robot    sys.exit(2)
189*16467b97STreehugger Robot
190*16467b97STreehugger Robot
191*16467b97STreehugger Robotdef _unload_pkg_resources():
192*16467b97STreehugger Robot    del_modules = [
193*16467b97STreehugger Robot        name for name in sys.modules
194*16467b97STreehugger Robot        if name.startswith('pkg_resources')
195*16467b97STreehugger Robot    ]
196*16467b97STreehugger Robot    for mod_name in del_modules:
197*16467b97STreehugger Robot        del sys.modules[mod_name]
198*16467b97STreehugger Robot
199*16467b97STreehugger Robot
200*16467b97STreehugger Robotdef _clean_check(cmd, target):
201*16467b97STreehugger Robot    """
202*16467b97STreehugger Robot    Run the command to download target.
203*16467b97STreehugger Robot
204*16467b97STreehugger Robot    If the command fails, clean up before re-raising the error.
205*16467b97STreehugger Robot    """
206*16467b97STreehugger Robot    try:
207*16467b97STreehugger Robot        subprocess.check_call(cmd)
208*16467b97STreehugger Robot    except subprocess.CalledProcessError:
209*16467b97STreehugger Robot        if os.access(target, os.F_OK):
210*16467b97STreehugger Robot            os.unlink(target)
211*16467b97STreehugger Robot        raise
212*16467b97STreehugger Robot
213*16467b97STreehugger Robot
214*16467b97STreehugger Robotdef download_file_powershell(url, target):
215*16467b97STreehugger Robot    """
216*16467b97STreehugger Robot    Download the file at url to target using Powershell.
217*16467b97STreehugger Robot
218*16467b97STreehugger Robot    Powershell will validate trust.
219*16467b97STreehugger Robot    Raise an exception if the command cannot complete.
220*16467b97STreehugger Robot    """
221*16467b97STreehugger Robot    target = os.path.abspath(target)
222*16467b97STreehugger Robot    ps_cmd = (
223*16467b97STreehugger Robot        "[System.Net.WebRequest]::DefaultWebProxy.Credentials = "
224*16467b97STreehugger Robot        "[System.Net.CredentialCache]::DefaultCredentials; "
225*16467b97STreehugger Robot        "(new-object System.Net.WebClient).DownloadFile(%(url)r, %(target)r)"
226*16467b97STreehugger Robot        % vars()
227*16467b97STreehugger Robot    )
228*16467b97STreehugger Robot    cmd = [
229*16467b97STreehugger Robot        'powershell',
230*16467b97STreehugger Robot        '-Command',
231*16467b97STreehugger Robot        ps_cmd,
232*16467b97STreehugger Robot    ]
233*16467b97STreehugger Robot    _clean_check(cmd, target)
234*16467b97STreehugger Robot
235*16467b97STreehugger Robot
236*16467b97STreehugger Robotdef has_powershell():
237*16467b97STreehugger Robot    """Determine if Powershell is available."""
238*16467b97STreehugger Robot    if platform.system() != 'Windows':
239*16467b97STreehugger Robot        return False
240*16467b97STreehugger Robot    cmd = ['powershell', '-Command', 'echo test']
241*16467b97STreehugger Robot    with open(os.path.devnull, 'wb') as devnull:
242*16467b97STreehugger Robot        try:
243*16467b97STreehugger Robot            subprocess.check_call(cmd, stdout=devnull, stderr=devnull)
244*16467b97STreehugger Robot        except Exception:
245*16467b97STreehugger Robot            return False
246*16467b97STreehugger Robot    return True
247*16467b97STreehugger Robotdownload_file_powershell.viable = has_powershell
248*16467b97STreehugger Robot
249*16467b97STreehugger Robot
250*16467b97STreehugger Robotdef download_file_curl(url, target):
251*16467b97STreehugger Robot    cmd = ['curl', url, '--silent', '--output', target]
252*16467b97STreehugger Robot    _clean_check(cmd, target)
253*16467b97STreehugger Robot
254*16467b97STreehugger Robot
255*16467b97STreehugger Robotdef has_curl():
256*16467b97STreehugger Robot    cmd = ['curl', '--version']
257*16467b97STreehugger Robot    with open(os.path.devnull, 'wb') as devnull:
258*16467b97STreehugger Robot        try:
259*16467b97STreehugger Robot            subprocess.check_call(cmd, stdout=devnull, stderr=devnull)
260*16467b97STreehugger Robot        except Exception:
261*16467b97STreehugger Robot            return False
262*16467b97STreehugger Robot    return True
263*16467b97STreehugger Robotdownload_file_curl.viable = has_curl
264*16467b97STreehugger Robot
265*16467b97STreehugger Robot
266*16467b97STreehugger Robotdef download_file_wget(url, target):
267*16467b97STreehugger Robot    cmd = ['wget', url, '--quiet', '--output-document', target]
268*16467b97STreehugger Robot    _clean_check(cmd, target)
269*16467b97STreehugger Robot
270*16467b97STreehugger Robot
271*16467b97STreehugger Robotdef has_wget():
272*16467b97STreehugger Robot    cmd = ['wget', '--version']
273*16467b97STreehugger Robot    with open(os.path.devnull, 'wb') as devnull:
274*16467b97STreehugger Robot        try:
275*16467b97STreehugger Robot            subprocess.check_call(cmd, stdout=devnull, stderr=devnull)
276*16467b97STreehugger Robot        except Exception:
277*16467b97STreehugger Robot            return False
278*16467b97STreehugger Robot    return True
279*16467b97STreehugger Robotdownload_file_wget.viable = has_wget
280*16467b97STreehugger Robot
281*16467b97STreehugger Robot
282*16467b97STreehugger Robotdef download_file_insecure(url, target):
283*16467b97STreehugger Robot    """Use Python to download the file, without connection authentication."""
284*16467b97STreehugger Robot    src = urlopen(url)
285*16467b97STreehugger Robot    try:
286*16467b97STreehugger Robot        # Read all the data in one block.
287*16467b97STreehugger Robot        data = src.read()
288*16467b97STreehugger Robot    finally:
289*16467b97STreehugger Robot        src.close()
290*16467b97STreehugger Robot
291*16467b97STreehugger Robot    # Write all the data in one block to avoid creating a partial file.
292*16467b97STreehugger Robot    with open(target, "wb") as dst:
293*16467b97STreehugger Robot        dst.write(data)
294*16467b97STreehugger Robotdownload_file_insecure.viable = lambda: True
295*16467b97STreehugger Robot
296*16467b97STreehugger Robot
297*16467b97STreehugger Robotdef get_best_downloader():
298*16467b97STreehugger Robot    downloaders = (
299*16467b97STreehugger Robot        download_file_powershell,
300*16467b97STreehugger Robot        download_file_curl,
301*16467b97STreehugger Robot        download_file_wget,
302*16467b97STreehugger Robot        download_file_insecure,
303*16467b97STreehugger Robot    )
304*16467b97STreehugger Robot    viable_downloaders = (dl for dl in downloaders if dl.viable())
305*16467b97STreehugger Robot    return next(viable_downloaders, None)
306*16467b97STreehugger Robot
307*16467b97STreehugger Robot
308*16467b97STreehugger Robotdef download_setuptools(
309*16467b97STreehugger Robot        version=DEFAULT_VERSION, download_base=DEFAULT_URL,
310*16467b97STreehugger Robot        to_dir=DEFAULT_SAVE_DIR, delay=15,
311*16467b97STreehugger Robot        downloader_factory=get_best_downloader):
312*16467b97STreehugger Robot    """
313*16467b97STreehugger Robot    Download setuptools from a specified location and return its filename.
314*16467b97STreehugger Robot
315*16467b97STreehugger Robot    `version` should be a valid setuptools version number that is available
316*16467b97STreehugger Robot    as an sdist for download under the `download_base` URL (which should end
317*16467b97STreehugger Robot    with a '/'). `to_dir` is the directory where the egg will be downloaded.
318*16467b97STreehugger Robot    `delay` is the number of seconds to pause before an actual download
319*16467b97STreehugger Robot    attempt.
320*16467b97STreehugger Robot
321*16467b97STreehugger Robot    ``downloader_factory`` should be a function taking no arguments and
322*16467b97STreehugger Robot    returning a function for downloading a URL to a target.
323*16467b97STreehugger Robot    """
324*16467b97STreehugger Robot    # making sure we use the absolute path
325*16467b97STreehugger Robot    to_dir = os.path.abspath(to_dir)
326*16467b97STreehugger Robot    zip_name = "setuptools-%s.zip" % version
327*16467b97STreehugger Robot    url = download_base + zip_name
328*16467b97STreehugger Robot    saveto = os.path.join(to_dir, zip_name)
329*16467b97STreehugger Robot    if not os.path.exists(saveto):  # Avoid repeated downloads
330*16467b97STreehugger Robot        log.warn("Downloading %s", url)
331*16467b97STreehugger Robot        downloader = downloader_factory()
332*16467b97STreehugger Robot        downloader(url, saveto)
333*16467b97STreehugger Robot    return os.path.realpath(saveto)
334*16467b97STreehugger Robot
335*16467b97STreehugger Robot
336*16467b97STreehugger Robotdef _build_install_args(options):
337*16467b97STreehugger Robot    """
338*16467b97STreehugger Robot    Build the arguments to 'python setup.py install' on the setuptools package.
339*16467b97STreehugger Robot
340*16467b97STreehugger Robot    Returns list of command line arguments.
341*16467b97STreehugger Robot    """
342*16467b97STreehugger Robot    return ['--user'] if options.user_install else []
343*16467b97STreehugger Robot
344*16467b97STreehugger Robot
345*16467b97STreehugger Robotdef _parse_args():
346*16467b97STreehugger Robot    """Parse the command line for options."""
347*16467b97STreehugger Robot    parser = optparse.OptionParser()
348*16467b97STreehugger Robot    parser.add_option(
349*16467b97STreehugger Robot        '--user', dest='user_install', action='store_true', default=False,
350*16467b97STreehugger Robot        help='install in user site package (requires Python 2.6 or later)')
351*16467b97STreehugger Robot    parser.add_option(
352*16467b97STreehugger Robot        '--download-base', dest='download_base', metavar="URL",
353*16467b97STreehugger Robot        default=DEFAULT_URL,
354*16467b97STreehugger Robot        help='alternative URL from where to download the setuptools package')
355*16467b97STreehugger Robot    parser.add_option(
356*16467b97STreehugger Robot        '--insecure', dest='downloader_factory', action='store_const',
357*16467b97STreehugger Robot        const=lambda: download_file_insecure, default=get_best_downloader,
358*16467b97STreehugger Robot        help='Use internal, non-validating downloader'
359*16467b97STreehugger Robot    )
360*16467b97STreehugger Robot    parser.add_option(
361*16467b97STreehugger Robot        '--version', help="Specify which version to download",
362*16467b97STreehugger Robot        default=DEFAULT_VERSION,
363*16467b97STreehugger Robot    )
364*16467b97STreehugger Robot    parser.add_option(
365*16467b97STreehugger Robot    	'--to-dir',
366*16467b97STreehugger Robot    	help="Directory to save (and re-use) package",
367*16467b97STreehugger Robot    	default=DEFAULT_SAVE_DIR,
368*16467b97STreehugger Robot    )
369*16467b97STreehugger Robot    options, args = parser.parse_args()
370*16467b97STreehugger Robot    # positional arguments are ignored
371*16467b97STreehugger Robot    return options
372*16467b97STreehugger Robot
373*16467b97STreehugger Robot
374*16467b97STreehugger Robotdef _download_args(options):
375*16467b97STreehugger Robot	"""Return args for download_setuptools function from cmdline args."""
376*16467b97STreehugger Robot	return dict(
377*16467b97STreehugger Robot		version=options.version,
378*16467b97STreehugger Robot		download_base=options.download_base,
379*16467b97STreehugger Robot		downloader_factory=options.downloader_factory,
380*16467b97STreehugger Robot		to_dir=options.to_dir,
381*16467b97STreehugger Robot	)
382*16467b97STreehugger Robot
383*16467b97STreehugger Robot
384*16467b97STreehugger Robotdef main():
385*16467b97STreehugger Robot    """Install or upgrade setuptools and EasyInstall."""
386*16467b97STreehugger Robot    options = _parse_args()
387*16467b97STreehugger Robot    archive = download_setuptools(**_download_args(options))
388*16467b97STreehugger Robot    return _install(archive, _build_install_args(options))
389*16467b97STreehugger Robot
390*16467b97STreehugger Robotif __name__ == '__main__':
391*16467b97STreehugger Robot    sys.exit(main())
392