summaryrefslogtreecommitdiff
path: root/tasks
diff options
context:
space:
mode:
authorDonald Stufft <donald@stufft.io>2016-01-20 08:53:45 -0500
committerDonald Stufft <donald@stufft.io>2016-01-20 08:53:45 -0500
commit3c753c5a86303dd012a96e60013b216ebb85edbe (patch)
tree3131cce0c753b9cadae3aa77b79714fb90147c6a /tasks
parent06f13ff9772664aef9c0bbefe138aa5f235049a6 (diff)
downloadpip-3c753c5a86303dd012a96e60013b216ebb85edbe.tar.gz
Move get-pip.py to its own repository
Diffstat (limited to 'tasks')
-rw-r--r--tasks/generate.py266
-rw-r--r--tasks/paths.py5
2 files changed, 0 insertions, 271 deletions
diff --git a/tasks/generate.py b/tasks/generate.py
index 50f88c90e..7a68cd0c1 100644
--- a/tasks/generate.py
+++ b/tasks/generate.py
@@ -1,14 +1,7 @@
-import base64
-import hashlib
import io
-import json
-import os
-import urllib.request
import invoke
-from . import paths
-
@invoke.task
def authors():
@@ -33,262 +26,3 @@ def authors():
with io.open("AUTHORS.txt", "w", encoding="utf8") as fp:
fp.write(u"\n".join(authors))
fp.write(u"\n")
-
-
-@invoke.task
-def installer(installer_path=os.path.join(paths.CONTRIB, "get-pip.py")):
- print("[generate.installer] Generating installer")
-
- # Define our wrapper script
- WRAPPER_SCRIPT = """
-#!/usr/bin/env python
-#
-# Hi There!
-# You may be wondering what this giant blob of binary data here is, you might
-# even be worried that we're up to something nefarious (good for you for being
-# paranoid!). This is a base85 encoding of a zip file, this zip file contains
-# an entire copy of pip.
-#
-# Pip is a thing that installs packages, pip itself is a package that someone
-# might want to install, especially if they're looking to run this get-pip.py
-# script. Pip has a lot of code to deal with the security of installing
-# packages, various edge cases on various platforms, and other such sort of
-# "tribal knowledge" that has been encoded in its code base. Because of this
-# we basically include an entire copy of pip inside this blob. We do this
-# because the alternatives are attempt to implement a "minipip" that probably
-# doesn't do things correctly and has weird edge cases, or compress pip itself
-# down into a single file.
-#
-# If you're wondering how this is created, it is using an invoke task located
-# in tasks/generate.py called "installer". It can be invoked by using
-# ``invoke generate.installer``.
-
-import os.path
-import pkgutil
-import shutil
-import sys
-import struct
-import tempfile
-
-# Useful for very coarse version differentiation.
-PY2 = sys.version_info[0] == 2
-PY3 = sys.version_info[0] == 3
-
-if PY3:
- iterbytes = iter
-else:
- def iterbytes(buf):
- return (ord(byte) for byte in buf)
-
-try:
- from base64 import b85decode
-except ImportError:
- _b85alphabet = (b"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- b"abcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{{|}}~")
-
- def b85decode(b):
- _b85dec = [None] * 256
- for i, c in enumerate(iterbytes(_b85alphabet)):
- _b85dec[c] = i
-
- padding = (-len(b)) % 5
- b = b + b'~' * padding
- out = []
- packI = struct.Struct('!I').pack
- for i in range(0, len(b), 5):
- chunk = b[i:i + 5]
- acc = 0
- try:
- for c in iterbytes(chunk):
- acc = acc * 85 + _b85dec[c]
- except TypeError:
- for j, c in enumerate(iterbytes(chunk)):
- if _b85dec[c] is None:
- raise ValueError(
- 'bad base85 character at position %d' % (i + j)
- )
- raise
- try:
- out.append(packI(acc))
- except struct.error:
- raise ValueError('base85 overflow in hunk starting at byte %d'
- % i)
-
- result = b''.join(out)
- if padding:
- result = result[:-padding]
- return result
-
-
-def bootstrap(tmpdir=None):
- # Import pip so we can use it to install pip and maybe setuptools too
- import pip
- from pip.commands.install import InstallCommand
- from pip.req import InstallRequirement
-
- # Wrapper to provide default certificate with the lowest priority
- class CertInstallCommand(InstallCommand):
- def parse_args(self, args):
- # If cert isn't specified in config or environment, we provide our
- # own certificate through defaults.
- # This allows user to specify custom cert anywhere one likes:
- # config, environment variable or argv.
- if not self.parser.get_default_values().cert:
- self.parser.defaults["cert"] = cert_path # calculated below
- return super(CertInstallCommand, self).parse_args(args)
-
- pip.commands_dict["install"] = CertInstallCommand
-
- implicit_pip = True
- implicit_setuptools = True
- implicit_wheel = True
-
- # Check if the user has requested us not to install setuptools
- if "--no-setuptools" in sys.argv or os.environ.get("PIP_NO_SETUPTOOLS"):
- args = [x for x in sys.argv[1:] if x != "--no-setuptools"]
- implicit_setuptools = False
- else:
- args = sys.argv[1:]
-
- # Check if the user has requested us not to install wheel
- if "--no-wheel" in args or os.environ.get("PIP_NO_WHEEL"):
- args = [x for x in args if x != "--no-wheel"]
- implicit_wheel = False
-
- # We only want to implicitly install setuptools and wheel if they don't
- # already exist on the target platform.
- if implicit_setuptools:
- try:
- import setuptools # noqa
- implicit_setuptools = False
- except ImportError:
- pass
- if implicit_wheel:
- try:
- import wheel # noqa
- implicit_wheel = False
- except ImportError:
- pass
-
- # We want to support people passing things like 'pip<8' to get-pip.py which
- # will let them install a specific version. However because of the dreaded
- # DoubleRequirement error if any of the args look like they might be a
- # specific for one of our packages, then we'll turn off the implicit
- # install of them.
- for arg in args:
- try:
- req = InstallRequirement.from_line(arg)
- except:
- continue
-
- if implicit_pip and req.name == "pip":
- implicit_pip = False
- elif implicit_setuptools and req.name == "setuptools":
- implicit_setuptools = False
- elif implicit_wheel and req.name == "wheel":
- implicit_wheel = False
-
- # Add any implicit installations to the end of our args
- if implicit_pip:
- args += ["pip"]
- if implicit_setuptools:
- args += ["setuptools"]
- if implicit_wheel:
- args += ["wheel"]
-
- delete_tmpdir = False
- try:
- # Create a temporary directory to act as a working directory if we were
- # not given one.
- if tmpdir is None:
- tmpdir = tempfile.mkdtemp()
- delete_tmpdir = True
-
- # We need to extract the SSL certificates from requests so that they
- # can be passed to --cert
- cert_path = os.path.join(tmpdir, "cacert.pem")
- with open(cert_path, "wb") as cert:
- cert.write(pkgutil.get_data("pip._vendor.requests", "cacert.pem"))
-
- # Execute the included pip and use it to install the latest pip and
- # setuptools from PyPI
- sys.exit(pip.main(["install", "--upgrade"] + args))
- finally:
- # Remove our temporary directory
- if delete_tmpdir and tmpdir:
- shutil.rmtree(tmpdir, ignore_errors=True)
-
-
-def main():
- tmpdir = None
- try:
- # Create a temporary working directory
- tmpdir = tempfile.mkdtemp()
-
- # Unpack the zipfile into the temporary directory
- pip_zip = os.path.join(tmpdir, "pip.zip")
- with open(pip_zip, "wb") as fp:
- fp.write(b85decode(DATA.replace(b"\\n", b"")))
-
- # Add the zipfile to sys.path so that we can import it
- sys.path.insert(0, pip_zip)
-
- # Run the bootstrap
- bootstrap(tmpdir=tmpdir)
- finally:
- # Clean up our temporary working directory
- if tmpdir:
- shutil.rmtree(tmpdir, ignore_errors=True)
-
-
-DATA = b\"\"\"
-{zipfile}
-\"\"\"
-
-
-if __name__ == "__main__":
- main()
-""".lstrip()
-
- # Determine what the latest version of pip on PyPI is.
- resp = urllib.request.urlopen("https://pypi.python.org/pypi/pip/json")
- data = json.loads(resp.read().decode("utf8"))
- version = data["info"]["version"]
- file_urls = [
- (x["url"], x["md5_digest"])
- for x in data["releases"][version]
- if x["url"].endswith(".whl")
- ]
- assert len(file_urls) == 1
- url, expected_hash = file_urls[0]
-
- # Fetch the file itself.
- data = urllib.request.urlopen(url).read()
- assert hashlib.md5(data).hexdigest() == expected_hash
-
- # Write out the wrapper script that will take the place of the zip script
- # The reason we need to do this instead of just directly executing the
- # zip script is that while Python will happily execute a zip script if
- # passed it on the file system, it will not however allow this to work if
- # passed it via stdin. This means that this wrapper script is required to
- # make ``curl https://...../get-pip.py | python`` continue to work.
- print(
- "[generate.installer] Write the wrapper script with the bundled zip "
- "file"
- )
-
- zipdata = base64.b85encode(data).decode("utf8")
- chunked = []
-
- for i in range(0, len(zipdata), 79):
- chunked.append(zipdata[i:i + 79])
-
- with open(installer_path, "w") as fp:
- fp.write(WRAPPER_SCRIPT.format(zipfile="\n".join(chunked)))
-
- # Ensure the permissions on the newly created file
- oldmode = os.stat(installer_path).st_mode & 0o7777
- newmode = (oldmode | 0o555) & 0o7777
- os.chmod(installer_path, newmode)
-
- print("[generate.installer] Generated installer")
diff --git a/tasks/paths.py b/tasks/paths.py
deleted file mode 100644
index abb901153..000000000
--- a/tasks/paths.py
+++ /dev/null
@@ -1,5 +0,0 @@
-import os.path
-
-PROJECT_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
-
-CONTRIB = os.path.join(PROJECT_ROOT, "contrib")