File: make_update.py

package info (click to toggle)
blender-doc 4.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 253,604 kB
  • sloc: python: 13,030; javascript: 322; makefile: 113; sh: 107
file content (201 lines) | stat: -rw-r--r-- 6,217 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
#!/usr/bin/env python3
# SPDX-License-Identifier: GPL-2.0-or-later

"""
"make update" for all platforms, git repository
"""

import argparse
import os
import sys

import make_utils
from pathlib import Path
from make_utils import call, check_output

from typing import (
    List,
)


class Submodule:
    path: str
    branch: str
    branch_fallback: str

    def __init__(self, path: str, branch: str, branch_fallback: str) -> None:
        self.path = path
        self.branch = branch
        self.branch_fallback = branch_fallback


def print_stage(text: str) -> None:
    print("")
    print(text)
    print("")


def parse_arguments() -> argparse.Namespace:
    parser = argparse.ArgumentParser()
    parser.add_argument("--no-manual", action="store_true")
    parser.add_argument("--no-locale", action="store_true")
    parser.add_argument("--git-command", default="git")
    return parser.parse_args()


def run_git(path: Path, commands: List, exit_on_error: bool = True) -> str:
    args = parse_arguments()

    return check_output([args.git_command, "-C", path] + commands, exit_on_error)


def get_manual_git_root() -> str:
    return check_output([args.git_command, "rev-parse", "--show-toplevel"])


def git_update_skip(args: argparse.Namespace, path: Path, check_remote_exists: bool = True) -> str:
    """Tests if git repo can be updated"""

    if make_utils.command_missing(args.git_command):
        sys.stderr.write("git not found, can't update manual\n")
        sys.exit(1)

    if make_utils.command_missing(args.git_command + "-lfs"):
        sys.stderr.write("git LFS not found, can't update manual\n")
        sys.exit(1)

    # Abort if a rebase is still progress.
    rebase_merge = run_git(
        path, ['rev-parse', '--git-path', 'rebase-merge'], exit_on_error=False)
    rebase_apply = run_git(
        path, ['rev-parse', '--git-path', 'rebase-apply'], exit_on_error=False)
    merge_head = run_git(
        path, ['rev-parse', '--git-path', 'MERGE_HEAD'], exit_on_error=False)
    if (
            os.path.exists(rebase_merge) or
            os.path.exists(rebase_apply) or
            os.path.exists(merge_head)
    ):
        return "rebase or merge in progress, complete it first"

    # Abort if uncommitted changes.
    changes = run_git(path, ['status', '--porcelain',
                      '--untracked-files=no', '--ignore-submodules'])
    if len(changes) != 0:
        return "you have unstaged changes"

    # Test if there is an upstream branch configured
    if check_remote_exists:
        branch = run_git(path, ["rev-parse", "--abbrev-ref", "HEAD"])
        remote = run_git(path, ["config", "branch." +
                         branch + ".remote"], exit_on_error=False)
        if len(remote) == 0:
            return "no remote branch to pull from"

    return ""


def use_upstream_workflow(args: argparse.Namespace, path: Path) -> bool:
    return make_utils.git_remote_exist([args.git_command, "-C", path], "upstream")


def work_tree_update_upstream_workflow(args: argparse.Namespace, path: Path, use_fetch: bool = True) -> str:
    """
    Update the repository using the Github style of fork organization

    Returns true if the current local branch has been updated to the upstream state.
    Otherwise false is returned.
    """

    branch_name = make_utils.git_branch([args.git_command, "-C"], path)

    if use_fetch:
        run_git(path, ["fetch", "upstream"])

    upstream_branch = f"upstream/{branch_name}"
    if not make_utils.git_branch_exists([args.git_command, "-C", path], upstream_branch):
        return "no_branch"

    retcode = call((args.git_command, "-C", path, "merge",
                   "--ff-only", upstream_branch), exit_on_error=False)
    if retcode != 0:
        return "Unable to fast forward\n"

    return ""


def work_tree_update(args: argparse.Namespace, path: Path, use_fetch: bool = True) -> str:
    """
    Update the Git working tree using the best strategy

    This function detects whether it is a github style of fork remote organization is used, or
    is it a repository which origin is an upstream.
    """

    if use_upstream_workflow(args, path):
        message = work_tree_update_upstream_workflow(args, path, use_fetch)
        if message != "no_branch":
            return message

        # If there is upstream configured but the local branch is not in the upstream, try to
        # update the branch from the fork.

    run_git(path, ["pull", "--rebase"])

    return ""


def manual_update(args: argparse.Namespace) -> str:
    """Update the root manual directory"""

    print_stage("Updating Manual Git Repository")

    return work_tree_update(args, Path(get_manual_git_root()))


def locale_exists() -> bool:
    locale_dir = os.path.join(get_manual_git_root(), "locale")
    if os.path.exists(locale_dir):
        return True

    return False


def locale_update(args: argparse.Namespace) -> str:
    """Update the translations directory"""

    if not locale_exists():
        return "locale directory not found skipping"

    print_stage("Updating manual translations Git Repository")

    locale_dir = os.path.join(get_manual_git_root(), "locale")

    return work_tree_update(args, locale_dir)


if __name__ == "__main__":
    args = parse_arguments()
    manual_skip_msg = ""
    locale_skip_msg = ""

    manual_dir = get_manual_git_root()
    locale_dir = os.path.join(get_manual_git_root(), "locale")

    if not args.no_manual:
        manual_skip_msg = git_update_skip(args, manual_dir)
        if not manual_skip_msg:
            manual_skip_msg = manual_update(args)
        if manual_skip_msg:
            manual_skip_msg = "Manual repository skipped: " + manual_skip_msg + "\n"
    if not args.no_locale and os.path.exists(locale_dir):
        locale_skip_msg = git_update_skip(args, locale_dir)
        if not locale_skip_msg:
            locale_skip_msg = locale_update(args)
        if locale_skip_msg:
            locale_skip_msg = "locale repository skipped: " + locale_skip_msg + "\n"

    # Report any skipped repositories at the end, so it's not as easy to miss.
    skip_msg = manual_skip_msg + locale_skip_msg
    if skip_msg:
        print_stage(skip_msg.strip())