Exemple #1
0
def main(args: argparse.Namespace) -> None:
    workspace = tsrc.cli.get_workspace(args)
    cmd_runner = CmdRunner(workspace.root_path,
                           args.cmd,
                           args.cmd_as_str,
                           shell=args.shell)
    manifest = workspace.local_manifest.get_manifest()
    workspace_config = workspace.config
    groups_from_config = workspace_config.repo_groups

    all_remote_repos = manifest.get_repos(all_=True)
    cloned_repos = [
        x for x in all_remote_repos if (workspace.root_path / x.src).exists()
    ]

    if args.groups_from_config:
        requested_repos = manifest.get_repos(groups=groups_from_config)
    elif args.groups:
        requested_repos = manifest.get_repos(groups=args.groups)
    else:
        requested_repos = cloned_repos

    found = [x for x in requested_repos if x in cloned_repos]
    missing = [x for x in requested_repos if x not in cloned_repos]

    tsrc.run_sequence(found, cmd_runner)
    if missing:
        ui.warning(
            "The following repos were requested but missing from the workspace:"
        )
        for repo in missing:
            ui.info("*", repo.src, fileobj=sys.stderr)
        raise MissingRepos(missing)
    else:
        ui.info("OK", ui.check)
Exemple #2
0
    def info(self, *args: Any, **kwargs: Any) -> None:
        """Same as cli_ui.info(), except this is a no-op if the
        task is run in parallel with other tasks.

        """
        if not self.parallel:
            ui.info(*args, **kwargs)
Exemple #3
0
def repos_from_config(
    manifest: Manifest, workspace_config: WorkspaceConfig
) -> List[tsrc.Repo]:
    """
    Given a workspace config, returns a list of repos.

    """
    clone_all_repos = workspace_config.clone_all_repos
    repo_groups = workspace_config.repo_groups

    if clone_all_repos:
        # workspace config contains clone_all_repos: true,
        # return everything
        return manifest.get_repos(all_=True)
    if repo_groups:
        # workspace config contains some groups, use that,
        # fmt: off
        ui.info(
            ui.green, "*", ui.reset, "Using groups from workspace config:",
            ", ".join(repo_groups),
        )
        # fmt: on
        return manifest.get_repos(groups=repo_groups)
    else:
        # workspace config does not specify clone_all_repos nor
        # a list of groups, ask the manifest for the list of default
        # repos
        return manifest.get_repos(groups=None)
Exemple #4
0
def run_git(
    working_path: Path,
    *cmd: str,
    check: bool = True,
    show_output: bool = True,
    show_cmd: bool = True,
) -> None:
    """Run git `cmd` in given `working_path`.

    Raise GitCommandError if return code is non-zero and `check` is True.
    """
    assert_working_path(working_path)
    git_cmd = list(cmd)
    git_cmd.insert(0, "git")

    if show_cmd:
        ui.info(ui.blue, "$", ui.reset, *git_cmd)
    if show_output:
        process = subprocess.run(git_cmd,
                                 cwd=working_path,
                                 universal_newlines=True)
    else:
        process = subprocess.run(
            git_cmd,
            cwd=working_path,
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT,
            universal_newlines=True,
        )
    if process.returncode != 0 and check:
        raise GitCommandError(working_path, cmd, output=process.stdout)
Exemple #5
0
def run(args: argparse.Namespace) -> None:
    # Note:
    # we want to support both:
    #  $ tsrc foreach -c 'shell command'
    #  and
    #  $ tsrc foreach -- some-cmd --some-opts
    #
    # Due to argparse limitations, `cmd` will always be a list,
    # but we need a *string* when using 'shell=True'.
    #
    # So transform use the value from `cmd` and `shell` so that:
    # * action.command is suitable as argument to pass to subprocess.run()
    # * action.description is suitable for display purposes
    command: Command = []
    if args.shell:
        if len(args.cmd) != 1:
            die("foreach -c must be followed by exactly one argument")
        command = args.cmd[0]
        description = args.cmd[0]
    else:
        if not args.cmd:
            die("needs a command to run")
        command = args.cmd
        description = " ".join(args.cmd)
    shell = args.shell
    command = command
    description = description

    workspace = get_workspace_with_repos(args)

    cmd_runner = CmdRunner(workspace.root_path, command, description, shell=shell)
    tsrc.run_sequence(workspace.repos, cmd_runner)
    ui.info("OK", ui.check)
Exemple #6
0
    def process_item(self, index: int, count: int, item: T) -> Outcome:
        # We want to keep all output when processing items it parallel on just
        # one line (like ninja-build)
        #
        # To do that, we need a lock on stdout. We also need task.process() to
        # be silent, which should be the case if it is implemented correctly
        tokens = self.task.describe_process_start(item)
        if tokens:
            with self.lock:
                erase_last_line()
                ui.info_count(index, count, *tokens, end="\r")

        result = self.task.process(index, count, item)

        # Note: we don't know if tasks will be finished in the same order
        # they were started, so to keep the output relevant, we need a
        # done_count here.
        self.done_count += 1

        tokens = self.task.describe_process_end(item)
        if tokens:
            with self.lock:
                erase_last_line()
                ui.info_count(self.done_count - 1, count, *tokens, end="\r")
                if self.done_count == count:
                    ui.info()

        return result
Exemple #7
0
def test_parallel_happy() -> None:
    task = FakeTask()
    ui.info("Frobnicating 4 items with two workers")
    actual = process_items_parallel(["foo", "bar", "baz", "quux"], task, num_jobs=2)
    ui.info("Done")
    for outcome in actual.values():
        assert outcome.success()
    def status(self):
        if not (os.path.exists(self.restore_log_path) and os.path.isfile(self.restore_log_path)):
            cli_ui.warning('No restore log found!')
            sys.exit(0)  # FIXME: Don't exit, rather throw an exception

        restore_log = self._get_restore_log()

        if not self.rubrik:
            creds = self._read_credentials(ignore_stored=True, presets={'address': restore_log['cluster']['ip']})
            self._connect(creds)

        statuses = []

        for job in restore_log['jobs']:
            klass = config_class(job['configType'])
            status = klass(self.path, self.rubrik, logging.getLogger()).status(job)
            if status:
                statuses.append(status)

        status_rows = list(map(
            lambda s: [
                (status_color(s[0]), s[0]),
                (cli_ui.lightgray, s[1]),
                (cli_ui.lightgray, s[2]),
                (cli_ui.lightgray, s[3]),
                (cli_ui.bold, s[4])],
            statuses
        ))

        cli_ui.info('\nBackup Id:', cli_ui.turquoise, restore_log['backupId'], end='\n\n')
        cli_ui.info_table(status_rows, headers=['Status', 'Start time', 'End time', 'Type', 'Name'])
Exemple #9
0
    def test(self) -> None:
        self.build()

        if not self._is_host_target:
            ui.info(self.profile, "is a cross-compiled target, skipping tests")
            return

        tankerci.run("cargo", "fmt", "--", "--check", cwd=self.src_path)
        tankerci.run(
            "cargo",
            "clippy",
            "--all-targets",
            "--",
            "--deny",
            "warnings",
            "--allow",
            "unknown-lints",
            cwd=self.src_path,
        )
        if self._is_windows_target:
            shutil.copy(
                Path("native") / self.target_triplet / "ctanker.dll",
                Path("target") / "debug/deps",
            )
        self._cargo("test")
Exemple #10
0
    def post_push(self) -> None:
        self.pull_request = self.ensure_pull_request()
        assert self.pull_request
        if self.args.close:
            ui.info_2("Closing merge request #%s" % self.pull_request.number)
            self.pull_request.close()
            return
        params = dict()
        if self.requested_target_branch:
            params["base"] = self.requested_target_branch

        if self.requested_title:
            params["title"] = self.requested_title

        self.pull_request.update(**params)

        if self.requested_reviewers:
            message = [
                "Requesting review from", ", ".join(self.requested_reviewers)
            ]
            ui.info_2(*message)
            tsrc.github.request_reviewers(self.repository,
                                          self.pull_request.number,
                                          self.requested_reviewers)

        if self.requested_assignee:
            ui.info_2("Assigning to", self.requested_assignee)
            self.assign_pull_request()

        if self.args.merge:
            self.merge_pull_request()

        ui.info(ui.green, "::", ui.reset, "See pull request at",
                self.pull_request.html_url)
Exemple #11
0
def download():
    cli_ui.info_2("Downloading the newest version of PortCMS")
    if (not checker.checkGitStatus()):
        cli_ui.error(
            "Please download and install git to continue: https://git-scm.com/downloads"
        )
        os._exit(1)
    isUpdate = False
    try:
        os.mkdir("PortCMS")
    except:
        what = cli_ui.ask_choice(
            "PortCMS is already downloaded. What do You want to do?",
            choices=["Update", "Check database config"])
        isUpdate = what == "Update"
        if (not isUpdate):
            os.chdir("PortCMS")
            dbconf()
            os._exit(0)
    if (isUpdate):
        os.chdir("PortCMS")
        os.system("git pull")
    else:
        os.system(
            "git clone https://github.com/PetrusTryb/portfolio.git PortCMS")
        os.chdir("PortCMS")
    cli_ui.info(cli_ui.check, "Download complete")
Exemple #12
0
 def print_self(self) -> None:
     # fmt: off
     ui.info(
         ui.red,
         "- ",
         ui.reset,
         ui.bold,
         self.src,
         ":",
         ui.reset,
         ui.darkgray,
         self.lineno + 1,
         ui.reset,
         " ",
         ui.red,
         self.old_line.strip(),
         sep="",
     )
     ui.info(
         ui.green,
         "+ ",
         ui.reset,
         ui.bold,
         self.src,
         ":",
         ui.reset,
         ui.darkgray,
         self.lineno + 1,
         ui.reset,
         " ",
         ui.green,
         self.new_line.strip(),
         sep="",
     )
Exemple #13
0
def dump_logcat_for_failed_tests() -> None:
    try:
        dump_path = "tanker-bindings/build/reports/androidTests/connected/flavors/releaseAndroidTest/logcat.txt"  # noqa: E501
        tankerci.android.dump_logcat(dump_path)
        ui.info("Tests have failed, logcat dumped to", dump_path)
    except Exception as e:
        ui.error("Failed to dump logcat:", e)
Exemple #14
0
    def post_push(self) -> None:
        merge_request = self.ensure_merge_request()
        assert self.gitlab_api
        if self.args.close:
            ui.info_2("Closing merge request #%s" % merge_request.iid)
            merge_request.state_event = "close"
            merge_request.save()
            return

        assignee = None
        if self.requested_assignee:
            assignee = self.handle_assignee()
            if assignee:
                ui.info_2("Assigning to", assignee.username)

        title = self.handle_title(merge_request)
        merge_request.title = title
        merge_request.remove_source_branch = True
        if self.requested_target_branch:
            merge_request.target_branch = self.requested_target_branch
        if assignee:
            merge_request.assignee_id = assignee.id

        approvers = self.handle_approvers()
        merge_request.approvals.set_approvers([x.id for x in approvers])

        merge_request.save()

        if self.args.accept:
            merge_request.merge(merge_when_pipeline_succeeds=True)

        ui.info(ui.green, "::",
                ui.reset, "See merge request at", merge_request.web_url)
Exemple #15
0
def foreach(workspace: tsrc.Workspace, *args: Any, **kwargs: Any) -> None:
    cmd: List[str] = args  # type: ignore
    shell: bool = kwargs["shell"]
    # Note:
    # we want to support both:
    #  $ tsrc foreach -c 'shell command'
    #  and
    #  $ tsrc foreach -- some-cmd --some-opts
    #
    # Due to argparse limitations, `cmd` will always be a list,
    # but we need a *string* when using 'shell=True'.
    #
    # So transform use the value from `cmd` and `shell` to build:
    # * `subprocess_cmd`, suitable as argument to pass to subprocess.run()
    # * `cmd_as_str`, suitable for display purposes
    command: Command = []
    if shell:
        if len(cmd) != 1:
            die("foreach -c must be followed by exactly one argument")
        command = cmd[0]
        description = cmd[0]
    else:
        if not cmd:
            die("needs a command to run")
        command = cmd
        description = " ".join(cmd)
    cmd_runner = CmdRunner(workspace.root_path,
                           command,
                           description,
                           shell=shell)
    tsrc.run_sequence(workspace.repos, cmd_runner)
    ui.info("OK", ui.check)
Exemple #16
0
def main(args: argparse.Namespace) -> None:
    tsrc_distribution = pkg_resources.get_distribution("tsrc")
    version = tsrc_distribution.version
    message = "tsrc version %s" % version
    location = Path(tsrc_distribution.location)
    message += get_details(location)
    ui.info(message)
Exemple #17
0
def display_statuses(statuses: List[Tuple[str, tsrc.git.Status]]) -> None:
    if not statuses:
        return
    max_src = max((len(x[0]) for x in statuses))
    for src, status in statuses:
        message = [ui.green, "*", ui.reset, src.ljust(max_src)]
        message += describe(status)
        ui.info(*message)
Exemple #18
0
 def handle_errors(self) -> None:
     self.task.on_failure(num_errors=len(self.errors))
     for item, error in self.errors:
         item_desc = self.task.display_item(item)
         message = [ui.green, "*", " ", ui.reset, ui.bold, item_desc]
         if error.message:
             message.extend([ui.reset, ": ", error.message])
         ui.info(*message, sep="", fileobj=sys.stderr)
     raise ExecutorFailed()
Exemple #19
0
def generate_test_config(src_path: Path, *, config_name: str) -> None:
    filepath = ci.tanker_configs.get_path()
    to_write = textwrap.dedent(f"""\
        #define TANKER_CONFIG_FILEPATH @"{filepath}"
        #define TANKER_CONFIG_NAME @"{config_name}"
        """)
    config_header = src_path / "TKRTestConfig.h"
    config_header.write_text(to_write)
    ui.info("Config written to", config_header)
Exemple #20
0
def test_info_characters(smart_tty: SmartTTY) -> None:
    cli_ui.info("Doing stuff",
                cli_ui.ellipsis,
                "sucess",
                cli_ui.check,
                fileobj=smart_tty)
    actual = smart_tty.getvalue()
    expected = f"Doing stuff {RESET_ALL}{RESET_ALL}… {RESET_ALL}sucess {RESET_ALL}{GREEN}✓ {RESET_ALL}\n{RESET_ALL}"
    assert actual == expected
Exemple #21
0
def get_branch_name() -> Optional[str]:
    branch = os.environ.get("CI_COMMIT_BRANCH", None)
    if not branch:
        branch = os.environ.get("CI_COMMIT_REF_NAME", None)
    if not branch:
        branch = tankerci.git.get_current_branch(Path.cwd())
    if not branch:
        return None
    ui.info(f"Running on branch {branch}")
    return branch
def test_info_characters(smart_tty: SmartTTY) -> None:
    cli_ui.info("Doing stuff",
                cli_ui.ellipsis,
                "sucess",
                cli_ui.check,
                fileobj=smart_tty)
    actual = smart_tty.getvalue()
    expected = ("Doing stuff " + colorama.Style.RESET_ALL + "…" + " sucess " +
                colorama.Fore.GREEN + "✓")
    assert_equal_strings(actual, expected)
Exemple #23
0
def find_files(working_path: Path, current_version: str) -> List[str]:
    ui.info_2("Looking for files matching", ui.bold, current_version)
    cmd = ["grep", "--fixed-strings", "--files-with-matches", current_version]
    _, out = tbump.git.run_git_captured(working_path, *cmd, check=True)
    res = []  # type: List[str]
    ui.info("Found following matching files")
    for file in out.splitlines():
        ui.info(" * ", file)
        res.append(file)
    return res
Exemple #24
0
def main(args: argparse.Namespace) -> None:
    workspace_path = args.workspace_path or os.getcwd()
    workspace = tsrc.Workspace(Path(workspace_path))
    ui.info_1("Configuring workspace in", ui.bold, workspace_path)
    manifest_config = tsrc.workspace.ManifestConfig.from_args(args)
    workspace.configure_manifest(manifest_config)
    workspace.load_manifest()
    workspace.clone_missing()
    workspace.set_remotes()
    workspace.copy_files()
    ui.info("Done", ui.check)
Exemple #25
0
 def on_success(self) -> None:
     erase_last_line()
     if not self.statuses:
         ui.info_2("Workspace is empty")
         return
     ui.info_2("Workspace status:")
     max_dest = max(len(x) for x in self.statuses.keys())
     for dest, status in self.statuses.items():
         message = [ui.green, "*", ui.reset, dest.ljust(max_dest)]
         message += describe_status(status)
         ui.info(*message)
Exemple #26
0
 def process(self, repo: tsrc.Repo) -> None:
     # fmt: off
     ui.info(repo.src, "\n",
             ui.lightgray, "$ ",
             ui.reset, ui.bold, self.cmd_as_str,
             sep="")
     # fmt: on
     full_path = self.workspace_path / repo.src
     rc = subprocess.call(self.cmd, cwd=full_path, shell=self.shell)
     if rc != 0:
         raise CommandFailed()
def test_update_title(always_color: None, smart_tty: SmartTTY) -> None:
    # fmt: off
    cli_ui.info("Something",
                cli_ui.bold,
                "bold",
                fileobj=smart_tty,
                update_title=True)
    expected = ("\x1b]0;Something bold\n\x07"
                f"Something {BRIGHT}bold\n{RESET_ALL}")
    # fmt: on
    actual = smart_tty.getvalue()
    assert actual == expected
def test_info_stdout_is_not_a_tty(dumb_tty: DumbTTY) -> None:
    # fmt: off
    cli_ui.info(cli_ui.red,
                "this is red",
                cli_ui.reset,
                cli_ui.green,
                "this is green",
                fileobj=dumb_tty)
    # fmt: on
    expected = "this is red this is green\n"
    actual = dumb_tty.getvalue()
    assert_equal_strings(actual, expected)
def test_info_stdout_no_colors(dumb_tty: DumbTTY) -> None:
    # fmt: off
    cli_ui.info(cli_ui.red,
                "this is red",
                cli_ui.reset,
                cli_ui.green,
                "this is green",
                fileobj=dumb_tty)
    # fmt: on
    expected = "this is red this is green\n"
    actual = dumb_tty.getvalue()
    assert actual == expected
Exemple #30
0
def run(args: argparse.Namespace) -> None:
    # Note:
    # we want to support both:
    #  $ tsrc foreach -c 'shell command'
    #  and
    #  $ tsrc foreach -- some-cmd --some-opts
    #
    # Due to argparse limitations, `cmd` will always be a list,
    # but we need a *string* when using 'shell=True'.
    #
    # So transform use the value from `cmd` and `shell` so that:
    # * action.command is suitable as argument to pass to subprocess.run()
    # * action.description is suitable for display purposes
    command: Command = []
    if args.shell:
        if len(args.cmd) != 1:
            die("foreach -c must be followed by exactly one argument")
        command = args.cmd[0]
        description = args.cmd[0]
    else:
        if not args.cmd:
            die("needs a command to run")
        command = args.cmd
        description = " ".join(args.cmd)
    shell = args.shell
    command = command
    description = description
    num_jobs = get_num_jobs(args)

    workspace = get_workspace_with_repos(args)
    cmd_runner = CmdRunner(workspace.root_path,
                           command,
                           description,
                           shell=shell)
    repos = workspace.repos
    ui.info_1(f"Running `{description}` on {len(repos)} repos")
    collection = process_items(repos, cmd_runner, num_jobs=num_jobs)
    errors = collection.errors
    if errors:
        ui.error(f"Command failed for {len(errors)} repo(s)")
        if cmd_runner.parallel:
            # Print output of failed commands that were hidden
            for (item, error) in errors.items():
                ui.info(item)
                ui.info("-" * len(item))
                ui.info(error)
        else:
            # Just print the repos
            for item in errors:
                ui.info(ui.green, "*", ui.reset, item)
        raise ForeachError()
    else:
        ui.info("OK", ui.check)