Ejemplo n.º 1
0
def make_wheel(capsys, mocker, scratch_dir="/tmp/jdtest", python_tag=None, callback=None, **extra):
    kwargs = default_setup_kwargs.copy()
    kwargs.update(extra)
    name = kwargs["name"]
    version = kwargs["version"]
    fname_prefix = "-".join([name, version])
    script_args = ["--no-user-cfg", "bdist_wheel"]
    if python_tag is None:
        script_args.append("--universal")
        python_tag = "py2.py3"
    else:
        script_args.extend(["--python-tag", python_tag])
    mocker.patch("sys.dont_write_bytecode", False)
    with working_directory(scratch_dir):
        for fname in kwargs["py_modules"]:
            if os.path.exists(fname):
                raise Exception("already exists: {}".format(fname))
            with open(fname + ".py", "w"):
                pass
        dist = setup(script_args=script_args, **kwargs)
    out, err = capsys.readouterr()
    lines = out.splitlines() + err.splitlines()
    for line in lines:
        if "warning" in line.lower():
            raise Exception("setup warning: {}".format(line))
    dist_dir = os.path.join(scratch_dir, "dist")
    dist_files = [f for f in os.listdir(dist_dir) if fname_prefix in f]
    [dist_fname] = [f for f in dist_files if "-" + python_tag + "-" in f]
    dist_path = os.path.join(dist_dir, dist_fname)
    with open(dist_path, mode="rb") as f:
        md5 = hashlib.md5(f.read()).hexdigest()
    if callback is not None:
        # contribute to test index
        callback(name=name, path=dist_path, urlfragment="#md5=" + md5)
    return dist, dist_path, md5
Ejemplo n.º 2
0
def get(dist_name,
        index_url=None,
        env=None,
        extra_index_url=None,
        tmpdir=None):
    args = _get_wheel_args(index_url, env, extra_index_url) + [dist_name]
    scratch_dir = tempfile.mkdtemp(dir=tmpdir)
    log.debug("wheeling and dealing",
              scratch_dir=scratch_dir,
              args=" ".join(args))
    try:
        out = subprocess.check_output(args,
                                      stderr=subprocess.STDOUT,
                                      cwd=scratch_dir)
    except subprocess.CalledProcessError as err:
        output = getattr(err, "output", b"").decode("utf-8")
        log.warning(output)
        raise
    log.debug("wheel command completed ok")
    out = out.decode("utf-8")
    links = []
    for line in out.splitlines():
        line = line.strip()
        if line.startswith("Downloading from URL"):
            link = line.split()[3]
            links.append(link)
        elif line.startswith(
                "Source in ") and "which satisfies requirement" in line:
            link = line.split()[-1]
            links.append(link)
    links = list(OrderedDict.fromkeys(links))  # order-preserving dedupe
    if not links:
        log.warning("could not find download link", out=out)
        raise Exception("failed to collect dist")
    if len(links) > 1:
        log.debug("more than 1 link collected", out=out, links=links)
        # Since PEP 517, maybe an sdist will also need to collect other distributions
        # for the build system, even with --no-deps specified. pendulum==1.4.4 is one
        # example, which uses poetry and doesn't publish any python37 wheel to PyPI.
        # However, the dist itself should still be the first one downloaded.
    link = links[0]
    with working_directory(scratch_dir):
        [whl] = [
            os.path.abspath(x) for x in os.listdir(".") if x.endswith(".whl")
        ]
    url, _sep, checksum = link.partition("#")
    if not checksum.startswith("md5=") and not checksum.startswith("sha256="):
        # PyPI gives you the checksum in url fragment, as a convenience. But not all indices are so kind.
        algorithm = "md5"
        if os.path.basename(whl) == url.rsplit("/")[-1]:
            target = whl
        else:
            scratch_file = os.path.join(scratch_dir, os.path.basename(url))
            target, _headers = urlretrieve(url, scratch_file)
        checksum = compute_checksum(target=target, algorithm=algorithm)
        checksum = "=".join([algorithm, checksum])
    result = {"path": whl, "url": url, "checksum": checksum}
    return result
Ejemplo n.º 3
0
def test_pipper_main(mocker, capsys, make_dist, tmpdir):
    make_dist(name="fakedist", version="1.2.3")
    mocker.patch("sys.argv", "pipper.py fakedist".split())
    with working_directory(tmpdir):
        johnnydep.pipper.main()
    out, err = capsys.readouterr()
    output = json.loads(out)
    path = output.pop("path")
    checksum = output.pop("checksum")
    assert output == {"url": "http://fakeindex/fakedist-1.2.3-py2.py3-none-any.whl"}
    assert os.path.isfile(path)
    assert os.path.basename(path) == "fakedist-1.2.3-py2.py3-none-any.whl"
    assert len(checksum) == 4 + 32
    assert checksum.startswith("md5=")
    assert err == ""
Ejemplo n.º 4
0
def get(dist_name, index_url=None, env=None):
    args = _get_wheel_args(index_url, env) + [dist_name]
    scratch_dir = tempfile.mkdtemp()
    log.debug("wheeling and dealing",
              scratch_dir=scratch_dir,
              args=" ".join(args))
    try:
        out = subprocess.check_output(args,
                                      stderr=subprocess.STDOUT,
                                      cwd=scratch_dir)
    except subprocess.CalledProcessError as err:
        output = getattr(err, "output", b"").decode("utf-8")
        log.warning(output)
        raise
    log.debug("wheel command completed ok")
    out = out.decode("utf-8")
    links = set()
    for line in out.splitlines():
        line = line.strip()
        if line.startswith("Downloading from URL"):
            link = line.split()[3]
            links.add(link)
        elif line.startswith(
                "Source in ") and "which satisfies requirement" in line:
            link = line.split()[-1]
            links.add(link)
    if len(links) != 1:
        log.warning(out, links=links)
        raise Exception("Expected exactly 1 link downloaded")
    with working_directory(scratch_dir):
        [whl] = [
            os.path.abspath(x) for x in os.listdir(".") if x.endswith(".whl")
        ]
    url, _sep, checksum = link.partition("#")
    if not checksum.startswith("md5=") and not checksum.startswith("sha256="):
        # PyPI gives you the checksum in url fragment, as a convenience. But not all indices are so kind.
        algorithm = "md5"
        if os.path.basename(whl) == url.rsplit("/")[-1]:
            target = whl
        else:
            scratch_file = os.path.join(scratch_dir, os.path.basename(url))
            target, _headers = urlretrieve(url, scratch_file)
        checksum = compute_checksum(target=target, algorithm=algorithm)
        checksum = "=".join([algorithm, checksum])
    result = {"path": whl, "url": url, "checksum": checksum}
    return result
Ejemplo n.º 5
0
    def __init__(self, req_string, parent=None, index_url=None, env=None, extra_index_url=None):
        self.dist_path = None
        if req_string.endswith(".whl") and os.path.isfile(req_string):
            self.dist_path = req_string
            whl = WheelFile(req_string)
            whl_name_info = whl.parsed_filename.groupdict()
            self.name = canonicalize_name(whl_name_info["name"])
            self.specifier = "==" + canonicalize_version(whl_name_info["ver"])
            self.req = pkg_resources.Requirement.parse(self.name + self.specifier)
        else:
            self.req = pkg_resources.Requirement.parse(req_string)
            self.name = canonicalize_name(self.req.name)
            self.specifier = str(self.req.specifier)

        self.extras_requested = sorted(self.req.extras)
        log = self.log = logger.bind(dist=str(self.req))
        log.info("init johnnydist", parent=parent and str(parent.req))
        if parent is not None:
            self.index_url = parent.index_url
            self.extra_index_url = parent.extra_index_url
            self.required_by = [str(parent.req)]
            self.env = parent.env
            self.env_data = parent.env_data
        else:
            self.index_url = index_url
            self.extra_index_url = extra_index_url
            self.required_by = []
            self.env = env
            if self.env is None:
                self.env_data = default_environment()
            else:
                self.env_data = dict(self.env)
            log.debug("target env", **self.env_data)
        if self.dist_path is None:
            log.debug("fetching best wheel")
            with wimpy.working_directory(self.tmp()):
                data = pipper.get(
                    req_string,
                    index_url=self.index_url,
                    env=self.env,
                    extra_index_url=self.extra_index_url,
                )
                self.dist_path = data["path"]
        self.parent = parent
        self._recursed = False
Ejemplo n.º 6
0
def _get_info(dist_name, index_url=None, env=None, extra_index_url=None):
    log = logger.bind(dist_name=dist_name)
    tmpdir = tempfile.mkdtemp()
    log.debug("created scratch", tmpdir=tmpdir)
    try:
        with wimpy.working_directory(tmpdir):
            data = pipper.get(
                dist_name,
                index_url=index_url,
                env=env,
                extra_index_url=extra_index_url,
                tmpdir=".",
            )
        dist_path = data["path"]
        # extract any info we may need from downloaded dist right now, so the
        # downloaded file can be cleaned up immediately
        import_names = _discover_import_names(dist_path)
        metadata = _extract_metadata(dist_path)
    finally:
        log.debug("removing scratch", tmpdir=tmpdir)
        shutil.rmtree(tmpdir)
    return import_names, metadata
Ejemplo n.º 7
0
    def __init__(self, req_string, parent=None, index_url=DEFAULT_INDEX):
        self.req = pkg_resources.Requirement.parse(req_string)

        self.name = canonicalize_name(str(self.req.name))
        self.specifier = str(self.req.specifier)
        self.extras_requested = sorted(self.req.extras)

        log = self.log = logger.bind(dist=str(self.req))
        log.info('init johnnydist', parent=parent and str(parent.req))
        if parent is not None:
            self.index_url = parent.index_url
            self.required_by = [str(parent.req)]
        else:
            self.index_url = index_url
            self.required_by = []
        try:
            log.debug('checking if installed already')
            dist = pkg_resources.get_distribution(req_string)
            log.debug('existing installation found', version=dist.version)
            self.version_installed = dist.version
            dist = pkg_resources.get_distribution(self.pinned)
        except (pkg_resources.DistributionNotFound, pkg_resources.VersionConflict) as err:
            log.debug('fetching best wheel')
            with wimpy.working_directory(self.tmp()):
                local_whl_data = get_wheel(req_string, index_url=self.index_url)
            self.zip = ZipFile(file=local_whl_data['path'])
            self.namelist = self.zip.namelist()
            if isinstance(err, pkg_resources.VersionConflict):
                self.version_installed = pkg_resources.get_distribution(self.name).version
            else:
                self.version_installed = None
        else:
            log.debug('existing installation is best!', version=dist.version)
            self.namelist = [os.path.join(dist.egg_info, x) for x in os.listdir(dist.egg_info)]
            self.zip = None
        self.parent = parent
        self._recursed = False
Ejemplo n.º 8
0
    def __init__(self,
                 req_string,
                 parent=None,
                 index_url=None,
                 env=None,
                 extra_index_url=None):
        self.dist_path = None
        if req_string.endswith(".whl") and os.path.isfile(req_string):
            self.dist_path = req_string
            whl = WheelFile(req_string)
            whl_name_info = whl.parsed_filename.groupdict()
            self.name = canonicalize_name(whl_name_info["name"])
            self.specifier = "==" + canonicalize_version(whl_name_info["ver"])
            self.req = pkg_resources.Requirement.parse(self.name +
                                                       self.specifier)
        else:
            self.req = pkg_resources.Requirement.parse(req_string)
            self.name = canonicalize_name(self.req.name)
            self.specifier = str(self.req.specifier)

        self.extras_requested = sorted(self.req.extras)
        log = self.log = logger.bind(dist=str(self.req))
        log.info("init johnnydist", parent=parent and str(parent.req))
        if parent is not None:
            self.index_url = parent.index_url
            self.extra_index_url = parent.extra_index_url
            self.required_by = [str(parent.req)]
            self.env = parent.env
            self.env_data = parent.env_data
        else:
            self.index_url = index_url
            self.extra_index_url = extra_index_url
            self.required_by = []
            self.env = env
            if self.env is None:
                self.env_data = default_environment()
            else:
                self.env_data = dict(self.env)
            log.debug("target env", **self.env_data)
        if self.dist_path is None:
            log.debug("fetching best wheel")
            tmpdir = tempfile.mkdtemp()
            log.debug("created scratch", tmpdir=tmpdir)
            try:
                with wimpy.working_directory(tmpdir):
                    data = pipper.get(
                        req_string,
                        index_url=self.index_url,
                        env=self.env,
                        extra_index_url=self.extra_index_url,
                        tmpdir=tmpdir,
                    )
                self.dist_path = data["path"]
                # triggers retrieval of any info we need from downloaded dist
                self.import_names
                self.metadata
            finally:
                log.debug("removing scratch", tmpdir=tmpdir)
                shutil.rmtree(tmpdir)
        self.parent = parent
        self._recursed = False