Esempio n. 1
0
 def check(self) -> bool:
     """Check if is SVN."""
     try:
         run_on_cmdline(logger, f"svn info {self.remote}")
         return True
     except (SubprocessCommandError, RuntimeError):
         return False
Esempio n. 2
0
    def _fetch_impl(self, version: Version) -> Version:
        """Get the revision of the remote and place it at the local path."""
        if version.tag:
            branch_path = f"tags/{version.tag}/"
            branch = ""
        elif version.branch and version.branch != self.DEFAULT_BRANCH:
            branch_path = f"branches/{version.branch}"
            branch = version.branch
        else:
            branch = branch_path = self.DEFAULT_BRANCH

        revision = version.revision or self._get_revision(branch_path)

        if not revision.isdigit():
            raise RuntimeError(f"{revision} must be a number for SVN")

        rev_arg = f"--revision {revision}" if revision else ""

        complete_path = "/".join([self.remote, branch_path,
                                  self.source]).strip("/")

        # When exporting a file, the destination directory must already exist
        pathlib.Path(os.path.dirname(self.local_path)).mkdir(parents=True,
                                                             exist_ok=True)

        run_on_cmdline(
            logger,
            f"svn export --force {rev_arg} {complete_path} {self.local_path}")

        return Version(tag=version.tag, branch=branch, revision=revision)
Esempio n. 3
0
 def check_path(path: str = ".") -> bool:
     """Check if is SVN."""
     try:
         with in_directory(path):
             run_on_cmdline(logger, "svn info")
         return True
     except (SubprocessCommandError, RuntimeError):
         return False
Esempio n. 4
0
 def is_git(self) -> bool:
     """Check if is git."""
     try:
         with in_directory(self._path):
             run_on_cmdline(logger, "git status")
         return True
     except (SubprocessCommandError, RuntimeError):
         return False
Esempio n. 5
0
    def is_git(self) -> bool:
        """Check if the set url is git."""
        if self._remote.endswith(".git"):
            return True

        try:
            run_on_cmdline(logger, f"git ls-remote --heads {self._remote}")
            return True
        except (SubprocessCommandError, RuntimeError):
            return False
Esempio n. 6
0
def test_run_on_cmdline(name, cmd, cmd_result, expectation):

    with patch("dfetch.util.cmdline.subprocess.run") as subprocess_mock:

        subprocess_mock.side_effect = cmd_result
        logger_mock = MagicMock()

        if isinstance(expectation, CompletedProcess):
            assert expectation == run_on_cmdline(logger_mock, cmd)
        else:
            with pytest.raises(expectation):
                run_on_cmdline(logger_mock, cmd)
Esempio n. 7
0
 def _files_in_path(url_path: str) -> List[str]:
     return [
         str(line)
         for line in run_on_cmdline(logger, f"svn list {url_path}")
         .stdout.decode()
         .splitlines()
     ]
Esempio n. 8
0
    def list_tool_info() -> None:
        """Print out version information."""
        result = run_on_cmdline(logger, "svn --version")

        first_line = result.stdout.decode().split("\n")[0]
        tool, version = first_line.replace(",", "").split("version", maxsplit=1)
        VCS._log_tool(tool, version)
Esempio n. 9
0
    def get_diff(self, old_revision: str, new_revision: Optional[str]) -> str:
        """Get the diff between two revisions."""
        cmd = f"svn diff {self.local_path} -r {old_revision}"
        if new_revision:
            cmd += f":{new_revision}"

        return "\n".join(run_on_cmdline(logger, cmd).stdout.decode().splitlines())
Esempio n. 10
0
    def list_tool_info() -> None:
        """Print out version information."""
        result = run_on_cmdline(logger, "git --version")

        tool, version = result.stdout.decode().strip().split("version",
                                                             maxsplit=1)

        VCS._log_tool(tool, version)
Esempio n. 11
0
    def _get_info_from_target(target: str = "") -> Dict[str, str]:
        result = run_on_cmdline(logger, f"svn info {target.strip()}").stdout.decode()

        return {
            key.strip(): value.strip()
            for key, value in (
                line.split(":", maxsplit=1) for line in result.split(os.linesep) if line
            )
        }
Esempio n. 12
0
    def _get_info_from_target(target: str = "") -> Dict[str, str]:
        result = run_on_cmdline(logger, f"svn info {target}")

        info = {}
        for line in result.stdout.decode().split(os.linesep):
            if line:
                key, value = f"{line} ".split(":", 1)
                info[key.strip()] = value.strip()
        return info
Esempio n. 13
0
    def get_last_file_hash(self, path: str) -> str:
        """Get the hash of a specific file."""
        with in_directory(self._path):
            result = run_on_cmdline(
                logger,
                ["git", "log", "-n", "1", "--pretty=format:%H", "--", path],
            )

        return str(result.stdout.decode())
Esempio n. 14
0
    def get_current_hash(self) -> str:
        """Get the last revision."""
        with in_directory(self._path):
            result = run_on_cmdline(
                logger,
                ["git", "log", "-n", "1", "--pretty=format:%H"],
            )

        return str(result.stdout.decode())
Esempio n. 15
0
    def _get_last_changed_revision(target: str) -> str:

        if os.path.isdir(target):
            last_digits = re.compile(r"(?P<digits>\d+)(?!.*\d)")
            version = run_on_cmdline(
                logger, f"svnversion {target.strip()}"
            ).stdout.decode()

            parsed_version = last_digits.search(version)
            if parsed_version:
                return parsed_version.group("digits")
            raise RuntimeError(f"svnversion output was unexpected: {version}")

        return str(
            run_on_cmdline(
                logger, f"svn info --show-item last-changed-revision {target.strip()}"
            )
            .stdout.decode()
            .strip()
        )
Esempio n. 16
0
    def externals() -> List[External]:
        """Get list of externals."""
        result = run_on_cmdline(
            logger,
            [
                "svn",
                "propget",
                "svn:externals",
                "-R",
            ],
        )

        repo_root = SvnRepo._get_info_from_target()["Repository Root"]

        externals = []
        path_pattern = r"([^\s^-]+)\s+-"
        for entry in result.stdout.decode().split(os.linesep * 2):

            match = None
            for match in re.finditer(path_pattern, entry):
                pass
            if match:
                local_path = match.group(1)
                entry = re.sub(path_pattern, "", entry)

            for match in re.finditer(
                r"([^-\s\d][^\s]+)(?:@)(\d+)\s+([^\s]+)|([^-\s\d][^\s]+)\s+([^\s]+)",
                entry,
            ):

                url = match.group(1) or match.group(4)
                name = match.group(3) or match.group(5)
                rev = "" if not match.group(2) else match.group(2).strip()

                url, branch, tag, src = SvnRepo._split_url(url, repo_root)

                externals += [
                    External(
                        name=name,
                        toplevel=os.getcwd(),
                        path="/".join(os.path.join(local_path, name).split(os.sep)),
                        revision=rev,
                        url=url,
                        branch=branch,
                        tag=tag,
                        src=src,
                    )
                ]

        return externals
Esempio n. 17
0
    def _ls_remote(remote: str) -> Dict[str, str]:

        result = run_on_cmdline(
            logger, f"git ls-remote --heads --tags {remote}"
        ).stdout.decode()

        info = {}
        for line in filter(lambda x: x, result.split("\n")):
            sha, ref = [part.strip() for part in f"{line} ".split("\t", maxsplit=1)]

            # Annotated tag commit (more important)
            if ref.endswith("^{}"):
                info[ref.strip("^{}")] = sha
            elif ref not in info:
                info[ref] = sha
        return info
Esempio n. 18
0
    def externals() -> List[External]:
        """Get list of externals."""
        result = run_on_cmdline(
            logger,
            [
                "svn",
                "propget",
                "svn:externals",
                "-R",
            ],
        )

        repo_root = SvnRepo._get_info_from_target()["Repository Root"]

        externals = []
        for entry in result.stdout.decode().split(os.linesep * 2):

            match = None
            for match in re.finditer(r"([^\s^-]+)\s+-", entry):
                pass
            if match:
                local_path = match.group(1)

            for match in itertools.chain(
                    re.finditer(r"([^\s]*)@(\d+)\s+([^\s]*)", entry),
                    re.finditer(r"\.\s-\s+([^\s]+)(\s+)([^\s]+)", entry),
            ):

                url, branch, tag, src = SvnRepo._split_url(
                    match.group(1), repo_root)

                externals += [
                    External(
                        name=match.group(3),
                        toplevel=os.getcwd(),
                        path="/".join(
                            os.path.join(local_path,
                                         match.group(3)).split(os.sep)),
                        revision=match.group(2).strip(),
                        url=url,
                        branch=branch,
                        tag=tag,
                        src=src,
                    )
                ]

        return externals
Esempio n. 19
0
    def _ls_remote(remote: str) -> Dict[str, str]:

        result = run_on_cmdline(logger, f"git ls-remote {remote}")

        info = {}
        for line in result.stdout.decode().split("\n"):
            if line:
                key, value = f"{line} ".split("\t", 1)
                if not value.startswith("refs/pull"):

                    # Annotated tag commit (more important)
                    if value.strip().endswith("^{}"):
                        info[value.strip().strip("^{}")] = key.strip()
                    else:
                        if value.strip() not in info:
                            info[value.strip()] = key.strip()
        return info
Esempio n. 20
0
    def create_diff(self, old_hash: str, new_hash: Optional[str]) -> str:
        """Generate a relative diff patch."""
        with in_directory(self._path):
            cmd = [
                "git",
                "diff",
                "--relative",
                "--binary",  # Add binary content
                "--no-ext-diff",  # Don't allow external diff tools
                "--no-color",
                old_hash,
            ]
            if new_hash:
                cmd.append(new_hash)
            result = run_on_cmdline(logger, cmd)

        return str(result.stdout.decode())
Esempio n. 21
0
    def submodules() -> List[Submodule]:
        """Get a list of submodules in the current directory."""
        result = run_on_cmdline(
            logger,
            [
                "git",
                "submodule",
                "foreach",
                "--quiet",
                "echo $name $sm_path $sha1 $toplevel",
            ],
        )

        submodules = []
        for line in result.stdout.decode().split("\n"):
            if line:
                name, sm_path, sha, toplevel = line.split(" ")
                url = GitLocalRepo._get_submodule_urls(toplevel)[name]
                branch, tag = GitRemote(url).find_branch_tip_or_tag_from_sha(sha)

                if not (branch or tag):
                    branch = GitLocalRepo(
                        os.path.join(os.getcwd(), sm_path)
                    ).find_branch_containing_sha(sha)

                submodules += [
                    Submodule(
                        name=name,
                        toplevel=toplevel,
                        path=sm_path,
                        sha=sha,
                        url=url,
                        branch=branch,
                        tag=tag,
                    )
                ]

        if not submodules and os.path.isfile(".gitmodules"):
            logger.warning(
                "This repository probably has submodules, "
                "but they might not have been initialized yet. "
                "Try updating them with 'git submodule update --init' and rerun the command."
            )

        return submodules
Esempio n. 22
0
    def find_branch_containing_sha(self, sha: str) -> str:
        """Try to find the branch that contains the given sha."""
        if not os.path.isdir(os.path.join(self._path, GitLocalRepo.METADATA_DIR)):
            return ""

        with in_directory(self._path):
            result = run_on_cmdline(
                logger,
                ["git", "branch", "--contains", sha],
            )

        branches: List[str] = [
            branch.strip()
            for branch in result.stdout.decode().split("*")
            if branch.strip() and "HEAD detached at" not in branch.strip()
        ]

        return "" if not branches else branches[0]
Esempio n. 23
0
    def _get_submodule_urls(toplevel: str) -> Dict[str, str]:

        result = run_on_cmdline(
            logger,
            [
                "git",
                "config",
                "--file",
                toplevel + "/.gitmodules",
                "--get-regexp",
                "url",
            ],
        )

        return {
            str(match.group(1)): str(match.group(2))
            for match in re.finditer(r"submodule\.(.*)\.url\s+(.*)",
                                     result.stdout.decode())
        }
Esempio n. 24
0
    def _find_branch_in_local_repo_containing_sha(repo_path: str,
                                                  sha: str) -> str:
        if not os.path.isdir(repo_path):
            return ""

        with in_directory(repo_path):
            if not os.path.isdir(GitRepo.METADATA_DIR):
                return ""
            result = run_on_cmdline(
                logger,
                ["git", "branch", "--contains", sha],
            )

        branches: List[str] = []
        for branch in result.stdout.decode().split("*"):
            branch = branch.strip()

            if branch and "HEAD detached at" not in branch:
                branches.append(branch)

        return branches[0] if len(branches) == 1 else ""
Esempio n. 25
0
def get_git_version() -> Tuple[str, str]:
    """Get the name and version of git."""
    result = run_on_cmdline(logger, "git --version")
    tool, version = result.stdout.decode().strip().split("version", maxsplit=1)
    return (str(tool), str(version))
Esempio n. 26
0
    def _checkout_version(remote: str, version: str,
                          src: Optional[str]) -> None:
        """Checkout a specific version from a given remote.

        Args:
            remote (str): Url or path to a remote git repository
            version (str): A target to checkout, can be branch, tag or sha
            src (Optional[str]): Optional path to subdirectory or file in repo
        """
        run_on_cmdline(logger, "git init")
        run_on_cmdline(logger, f"git remote add origin {remote}")
        run_on_cmdline(logger, "git checkout -b dfetch-local-branch")

        if src:
            run_on_cmdline(logger, "git config core.sparsecheckout true")
            with open(".git/info/sparse-checkout",
                      "a") as sparse_checkout_file:
                sparse_checkout_file.write("/" + src)

        run_on_cmdline(logger, f"git fetch --depth 1 origin {version}")
        run_on_cmdline(logger, "git reset --hard FETCH_HEAD")

        if src:
            for file_to_copy in os.listdir(src):
                shutil.move(src + "/" + file_to_copy, ".")
            safe_rmtree(src)
Esempio n. 27
0
    def checkout_version(
        self,
        remote: str,
        version: str,
        src: Optional[str],
        must_keeps: Optional[List[str]],
    ) -> None:
        """Checkout a specific version from a given remote.

        Args:
            remote (str): Url or path to a remote git repository
            version (str): A target to checkout, can be branch, tag or sha
            src (Optional[str]): Optional path to subdirectory or file in repo
            must_keeps (Optional[List[str]]): Optional list of glob patterns to keep
        """
        with in_directory(self._path):
            run_on_cmdline(logger, "git init")
            run_on_cmdline(logger, f"git remote add origin {remote}")
            run_on_cmdline(logger, "git checkout -b dfetch-local-branch")

            if src:
                run_on_cmdline(logger, "git config core.sparsecheckout true")
                with open(
                    ".git/info/sparse-checkout", "a", encoding="utf-8"
                ) as sparse_checkout_file:
                    sparse_checkout_file.write(
                        "\n".join(list([f"/{src}"] + (must_keeps or [])))
                    )

            run_on_cmdline(logger, f"git fetch --depth 1 origin {version}")
            run_on_cmdline(logger, "git reset --hard FETCH_HEAD")

            if src:
                full_src = src
                if not os.path.isdir(src):
                    src = os.path.dirname(src)

                if not src:
                    return

                try:
                    for file_to_copy in os.listdir(src):
                        shutil.move(src + "/" + file_to_copy, ".")
                    safe_rmtree(PurePath(src).parts[0])
                except FileNotFoundError:
                    logger.warning(
                        f"The 'src:' filter '{full_src}' didn't match any files from '{remote}'"
                    )
Esempio n. 28
0
 def _list_of_tags(self) -> List[str]:
     """Get list of all available tags."""
     result = run_on_cmdline(logger, f"svn ls {self.remote}/tags")
     return [
         str(tag).strip("/\r") for tag in result.stdout.decode().split("\n") if tag
     ]
Esempio n. 29
0
 def _export(url: str, rev: str = "", dst: str = ".") -> None:
     run_on_cmdline(
         logger,
         ["svn", "export", "--force"] + rev.split(" ") + [url, dst],
     )