예제 #1
0
    def load(cls, path, create=True):
        """Create a new lockfile instance.

        :param project_path: Path to  project root or lockfile
        :type project_path: str or :class:`pathlib.Path`
        :param str lockfile_name: Name of the lockfile in the project root directory
        :param pipfile_path: Path to the project pipfile
        :type pipfile_path: :class:`pathlib.Path`
        :returns: A new lockfile representing the supplied project paths
        :rtype: :class:`~requirementslib.models.lockfile.Lockfile`
        """

        try:
            projectfile = cls.load_projectfile(path, create=create)
        except JSONDecodeError:
            path = os.path.abspath(path)
            path = Path(
                os.path.join(path, "Pipfile.lock") if os.path.isdir(path) else path
            )
            formatted_path = path.as_posix()
            backup_path = "%s.bak" % formatted_path
            LockfileCorruptException.show(formatted_path, backup_path=backup_path)
            path.rename(backup_path)
            cls.load(formatted_path, create=True)
        lockfile_path = Path(projectfile.location)
        creation_args = {
            "projectfile": projectfile,
            "lockfile": projectfile.model,
            "newlines": projectfile.line_ending,
            "path": lockfile_path
        }
        return cls(**creation_args)
예제 #2
0
 def formatted_path(self):
     if self.path:
         path = self.path
         if not isinstance(path, Path):
             path = Path(path)
         return path.as_posix()
     return
예제 #3
0
    def get_name(self):
        loc = self.path or self.uri
        if loc:
            self._uri_scheme = "path" if self.path else "uri"
        name = None
        if self.link and self.link.egg_fragment:
            return self.link.egg_fragment
        elif self.link and self.link.is_wheel:
            from pip_shims import Wheel

            return Wheel(self.link.filename).name
        if (self._uri_scheme != "uri" and self.path and self.setup_path
                and self.setup_path.exists()):
            from setuptools.dist import distutils

            old_curdir = os.path.abspath(os.getcwd())
            try:
                os.chdir(str(self.setup_path.parent))
                dist = distutils.core.run_setup(self.setup_path.as_posix())
                name = dist.get_name()
            except (FileNotFoundError, IOError) as e:
                dist = None
            except Exception as e:
                from pip_shims.shims import make_abstract_dist

                try:
                    if not isinstance(Path, self.path):
                        _path = Path(self.path)
                    else:
                        _path = self.path
                    if self.editable:
                        _ireq = pip_shims.shims.install_req_from_editable(
                            _path.as_uri())
                    else:
                        _ireq = pip_shims.shims.install_req_from_line(
                            _path.as_posix())
                    dist = make_abstract_dist(_ireq).get_dist()
                    name = dist.project_name
                except (TypeError, ValueError, AttributeError) as e:
                    dist = None
            finally:
                os.chdir(old_curdir)
        hashed_loc = hashlib.sha256(loc.encode("utf-8")).hexdigest()
        hashed_name = hashed_loc[-7:]
        if not name or name == "UNKNOWN":
            self._has_hashed_name = True
            name = hashed_name
        if self.link and not self._has_hashed_name:
            self.link = create_link("{0}#egg={1}".format(self.link.url, name))
        return name
예제 #4
0
    def create(cls, base_dir, subdirectory=None, ireq=None, kwargs=None):
        if not base_dir or base_dir is None:
            return

        creation_kwargs = {"extra_kwargs": kwargs}
        if not isinstance(base_dir, Path):
            base_dir = Path(base_dir)
        creation_kwargs["base_dir"] = base_dir.as_posix()
        pyproject = base_dir.joinpath("pyproject.toml")

        if subdirectory is not None:
            base_dir = base_dir.joinpath(subdirectory)
        setup_py = base_dir.joinpath("setup.py")
        setup_cfg = base_dir.joinpath("setup.cfg")
        creation_kwargs["pyproject"] = pyproject
        creation_kwargs["setup_py"] = setup_py
        creation_kwargs["setup_cfg"] = setup_cfg
        if ireq:
            creation_kwargs["ireq"] = ireq
        return cls(**creation_kwargs)
예제 #5
0
    def create(cls, base_dir, subdirectory=None, ireq=None, kwargs=None):
        # type: (AnyStr, Optional[AnyStr], Optional[InstallRequirement], Optional[Dict[AnyStr, AnyStr]]) -> Optional[SetupInfo]
        if not base_dir or base_dir is None:
            return

        creation_kwargs = {"extra_kwargs": kwargs}
        if not isinstance(base_dir, Path):
            base_dir = Path(base_dir)
        creation_kwargs["base_dir"] = base_dir.as_posix()
        pyproject = base_dir.joinpath("pyproject.toml")

        if subdirectory is not None:
            base_dir = base_dir.joinpath(subdirectory)
        setup_py = base_dir.joinpath("setup.py")
        setup_cfg = base_dir.joinpath("setup.cfg")
        creation_kwargs["pyproject"] = pyproject
        creation_kwargs["setup_py"] = setup_py
        creation_kwargs["setup_cfg"] = setup_cfg
        if ireq:
            creation_kwargs["ireq"] = ireq
        created = cls(**creation_kwargs)
        created.get_info()
        return created
예제 #6
0
    def get_link_from_line(cls, line):
        """Parse link information from given requirement line.

        Return a 6-tuple:

        - `vcs_type` indicates the VCS to use (e.g. "git"), or None.
        - `prefer` is either "file", "path" or "uri", indicating how the
            information should be used in later stages.
        - `relpath` is the relative path to use when recording the dependency,
            instead of the absolute path/URI used to perform installation.
            This can be None (to prefer the absolute path or URI).
        - `path` is the absolute file path to the package. This will always use
            forward slashes. Can be None if the line is a remote URI.
        - `uri` is the absolute URI to the package. Can be None if the line is
            not a URI.
        - `link` is an instance of :class:`pip._internal.index.Link`,
            representing a URI parse result based on the value of `uri`.

        This function is provided to deal with edge cases concerning URIs
        without a valid netloc. Those URIs are problematic to a straight
        ``urlsplit` call because they cannot be reliably reconstructed with
        ``urlunsplit`` due to a bug in the standard library:

        >>> from urllib.parse import urlsplit, urlunsplit
        >>> urlunsplit(urlsplit('git+file:///this/breaks'))
        'git+file:/this/breaks'
        >>> urlunsplit(urlsplit('file:///this/works'))
        'file:///this/works'

        See `https://bugs.python.org/issue23505#msg277350`.
        """

        # Git allows `[email protected]...` lines that are not really URIs.
        # Add "ssh://" so we can parse correctly, and restore afterwards.
        fixed_line = add_ssh_scheme_to_git_uri(line)
        added_ssh_scheme = fixed_line != line

        # We can assume a lot of things if this is a local filesystem path.
        if "://" not in fixed_line:
            p = Path(fixed_line).absolute()
            path = p.as_posix()
            uri = p.as_uri()
            link = create_link(uri)
            try:
                relpath = get_converted_relative_path(path)
            except ValueError:
                relpath = None
            return LinkInfo(None, "path", relpath, path, uri, link)

        # This is an URI. We'll need to perform some elaborated parsing.

        parsed_url = urllib_parse.urlsplit(fixed_line)
        original_url = parsed_url._replace()
        if added_ssh_scheme and ':' in parsed_url.netloc:
            original_netloc, original_path_start = parsed_url.netloc.rsplit(
                ':', 1)
            uri_path = '/{0}{1}'.format(original_path_start, parsed_url.path)
            parsed_url = original_url._replace(netloc=original_netloc,
                                               path=uri_path)

        # Split the VCS part out if needed.
        original_scheme = parsed_url.scheme
        if "+" in original_scheme:
            vcs_type, scheme = original_scheme.split("+", 1)
            parsed_url = parsed_url._replace(scheme=scheme)
            prefer = "uri"
        else:
            vcs_type = None
            prefer = "file"

        if parsed_url.scheme == "file" and parsed_url.path:
            # This is a "file://" URI. Use url_to_path and path_to_url to
            # ensure the path is absolute. Also we need to build relpath.
            path = Path(url_to_path(
                urllib_parse.urlunsplit(parsed_url))).as_posix()
            try:
                relpath = get_converted_relative_path(path)
            except ValueError:
                relpath = None
            uri = path_to_url(path)
        else:
            # This is a remote URI. Simply use it.
            path = None
            relpath = None
            # Cut the fragment, but otherwise this is fixed_line.
            uri = urllib_parse.urlunsplit(
                parsed_url._replace(scheme=original_scheme, fragment=""))

        if added_ssh_scheme:
            original_uri = urllib_parse.urlunsplit(
                original_url._replace(scheme=original_scheme, fragment=""))
            uri = strip_ssh_from_git_uri(original_uri)

        # Re-attach VCS prefix to build a Link.
        link = create_link(
            urllib_parse.urlunsplit(
                parsed_url._replace(scheme=original_scheme)))

        return LinkInfo(vcs_type, prefer, relpath, path, uri, link)
예제 #7
0
class Lockfile(plette.lockfiles.Lockfile):
    def __init__(self, *args, **kwargs):
        path = kwargs.pop("path", None)
        self._requirements = kwargs.pop("requirements", [])
        self._dev_requirements = kwargs.pop("dev_requirements", [])
        self.path = Path(path) if path else None
        self.newlines = u"\n"
        super(Lockfile, self).__init__(*args, **kwargs)

    @classmethod
    def load(cls, path):
        if not path:
            path = os.curdir
        path = Path(path).absolute()
        if path.is_dir():
            path = path / "Pipfile.lock"
        elif path.name == "Pipfile":
            path = path.parent / "Pipfile.lock"
        if not path.exists():
            raise OSError("Path does not exist: %s" % path)
        return cls.create(path.parent, lockfile_name=path.name)

    @classmethod
    def create(cls, project_path, lockfile_name="Pipfile.lock"):
        """Create a new lockfile instance

        :param project_path: Path to  project root
        :type project_path: str or :class:`~pathlib.Path`
        :returns: List[:class:`~requirementslib.Requirement`] objects
        """

        if not isinstance(project_path, Path):
            project_path = Path(project_path)
        lockfile_path = project_path / lockfile_name
        with lockfile_path.open(encoding="utf-8") as f:
            lockfile = super(Lockfile, cls).load(f)
            lockfile.newlines = preferred_newlines(f)
        lockfile.path = lockfile_path
        return lockfile

    def get_requirements(self, dev=False):
        section = self.develop if dev else self.default
        for k in section.keys():
            yield Requirement.from_pipfile(k, section[k]._data)

    @property
    def dev_requirements(self):
        if not self._dev_requirements:
            self._dev_requirements = list(self.get_requirements(dev=True))
        return self._dev_requirements

    @property
    def requirements(self):
        if not self._requirements:
            self._requirements = list(self.get_requirements(dev=False))
        return self._requirements

    @property
    def dev_requirements_list(self):
        return [{name: entry._data} for name, entry in self.develop.items()]

    @property
    def requirements_list(self):
        return [{name: entry._data} for name, entry in self.develop.items()]

    def write(self):
        open_kwargs = {"newline": self.newlines}
        with atomic_open_for_write(self.path.as_posix(), **open_kwargs) as f:
            super(Lockfile, self).dump(f, encoding="utf-8")

    def as_requirements(self, include_hashes=False, dev=False):
        """Returns a list of requirements in pip-style format"""
        lines = []
        section = self.dev_requirements if dev else self.requirements
        for req in section:
            r = req.as_line()
            if not include_hashes:
                r = r.split("--hash", 1)[0]
            lines.append(r.strip())
        return lines