Skip to content

Commit 582175a

Browse files
author
Sebastien Fusilier
committed
Merge tag 'v2.32' into setuppy
repo v2.32
2 parents 437d787 + 7fa149b commit 582175a

29 files changed

+594
-268
lines changed
+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# GitHub actions workflow.
2+
# https://help.github.com/en/actions/automating-your-workflow-with-github-actions/workflow-syntax-for-github-actions
3+
# https://github.com/marketplace/actions/python-flake8
4+
5+
name: Flake8
6+
7+
on:
8+
push:
9+
branches: [main]
10+
11+
jobs:
12+
lint:
13+
name: Python Lint
14+
runs-on: ubuntu-latest
15+
steps:
16+
- uses: actions/checkout@v3
17+
- uses: actions/setup-python@v4
18+
with:
19+
python-version: "3.9"
20+
- name: Run flake8
21+
uses: julianwachholz/flake8-action@v2
22+
with:
23+
checkName: "Python Lint"

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ that you can put anywhere in your path.
5656

5757
* Homepage: <https://gerrit.googlesource.com/git-repo/>
5858
* Mailing list: [repo-discuss on Google Groups][repo-discuss]
59-
* Bug reports: <https://bugs.chromium.org/p/gerrit/issues/list?q=component:repo>
59+
* Bug reports: <https://bugs.chromium.org/p/gerrit/issues/list?q=component:Applications%3Erepo>
6060
* Source: <https://gerrit.googlesource.com/git-repo/>
6161
* Overview: <https://source.android.com/source/developing.html>
6262
* Docs: <https://source.android.com/source/using-repo.html>
@@ -98,5 +98,5 @@ $ chmod a+rx ~/.bin/repo
9898
```
9999

100100
[new-bug]: https://bugs.chromium.org/p/gerrit/issues/entry?template=Repo+tool+issue
101-
[issue tracker]: https://bugs.chromium.org/p/gerrit/issues/list?q=component:repo
101+
[issue tracker]: https://bugs.chromium.org/p/gerrit/issues/list?q=component:Applications%3Erepo
102102
[repo-discuss]: https://groups.google.com/forum/#!forum/repo-discuss

docs/internal-fs-layout.md

+21-18
Original file line numberDiff line numberDiff line change
@@ -222,27 +222,30 @@ The `[remote]` settings are automatically populated/updated from the manifest.
222222

223223
The `[branch]` settings are updated by `repo start` and `git branch`.
224224

225-
| Setting | Subcommands | Use/Meaning |
226-
|-------------------------------|---------------|-------------|
227-
| review.\<url\>.autocopy | upload | Automatically add to `--cc=<value>` |
228-
| review.\<url\>.autoreviewer | upload | Automatically add to `--reviewers=<value>` |
229-
| review.\<url\>.autoupload | upload | Automatically answer "yes" or "no" to all prompts |
230-
| review.\<url\>.uploadhashtags | upload | Automatically add to `--hashtag=<value>` |
231-
| review.\<url\>.uploadlabels | upload | Automatically add to `--label=<value>` |
232-
| review.\<url\>.uploadnotify | upload | [Notify setting][upload-notify] to use |
233-
| review.\<url\>.uploadtopic | upload | Default [topic] to use |
234-
| review.\<url\>.username | upload | Override username with `ssh://` review URIs |
235-
| remote.\<remote\>.fetch | sync | Set of refs to fetch |
236-
| remote.\<remote\>.projectname | \<network\> | The name of the project as it exists in Gerrit review |
237-
| remote.\<remote\>.pushurl | upload | The base URI for pushing CLs |
238-
| remote.\<remote\>.review | upload | The URI of the Gerrit review server |
239-
| remote.\<remote\>.url | sync & upload | The URI of the git project to fetch |
240-
| branch.\<branch\>.merge | sync & upload | The branch to merge & upload & track |
241-
| branch.\<branch\>.remote | sync & upload | The remote to track |
225+
| Setting | Subcommands | Use/Meaning |
226+
|---------------------------------------|---------------|-------------|
227+
| review.\<url\>.autocopy | upload | Automatically add to `--cc=<value>` |
228+
| review.\<url\>.autoreviewer | upload | Automatically add to `--reviewers=<value>` |
229+
| review.\<url\>.autoupload | upload | Automatically answer "yes" or "no" to all prompts |
230+
| review.\<url\>.uploadhashtags | upload | Automatically add to `--hashtag=<value>` |
231+
| review.\<url\>.uploadlabels | upload | Automatically add to `--label=<value>` |
232+
| review.\<url\>.uploadnotify | upload | [Notify setting][upload-notify] to use |
233+
| review.\<url\>.uploadtopic | upload | Default [topic] to use |
234+
| review.\<url\>.uploadwarningthreshold | upload | Warn when attempting to upload more than this many CLs |
235+
| review.\<url\>.username | upload | Override username with `ssh://` review URIs |
236+
| remote.\<remote\>.fetch | sync | Set of refs to fetch |
237+
| remote.\<remote\>.projectname | \<network\> | The name of the project as it exists in Gerrit review |
238+
| remote.\<remote\>.pushurl | upload | The base URI for pushing CLs |
239+
| remote.\<remote\>.review | upload | The URI of the Gerrit review server |
240+
| remote.\<remote\>.url | sync & upload | The URI of the git project to fetch |
241+
| branch.\<branch\>.merge | sync & upload | The branch to merge & upload & track |
242+
| branch.\<branch\>.remote | sync & upload | The remote to track |
242243

243244
## ~/ dotconfig layout
244245

245-
Repo will create & maintain a few files in the user's home directory.
246+
Repo will create & maintain a few files under the `.repoconfig/` directory.
247+
This is placed in the user's home directory by default but can be changed by
248+
setting `REPO_CONFIG_DIR`.
246249

247250
* `.repoconfig/`: Repo's per-user directory for all random config files/state.
248251
* `.repoconfig/config`: Per-user settings using [git-config] file format.

release/__init__.py

Whitespace-only changes.

release/update-manpages

+1-11
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,9 @@
1818
This is intended to be run before every official Repo release.
1919
"""
2020

21-
from pathlib import Path
22-
from functools import partial
23-
import argparse
24-
import multiprocessing
25-
import os
26-
import re
27-
import shutil
28-
import subprocess
2921
import sys
30-
import tempfile
3122

32-
TOPDIR = Path(__file__).resolve().parent.parent
33-
MANDIR = TOPDIR.joinpath('man')
23+
import update_manpages
3424

3525
# Load repo local modules.
3626
sys.path.insert(0, str(TOPDIR))

release/update_manpages.py

+119
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
# Copyright (C) 2021 The Android Open Source Project
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""Helper tool for generating manual page for all repo commands.
16+
17+
Most code lives in this module so it can be unittested.
18+
"""
19+
20+
from pathlib import Path
21+
from functools import partial
22+
import argparse
23+
import multiprocessing
24+
import os
25+
import re
26+
import shutil
27+
import subprocess
28+
import sys
29+
import tempfile
30+
31+
TOPDIR = Path(__file__).resolve().parent.parent
32+
MANDIR = TOPDIR.joinpath('man')
33+
34+
# Load repo local modules.
35+
sys.path.insert(0, str(TOPDIR))
36+
from repo.git_command import RepoSourceVersion
37+
import subcmds
38+
39+
def worker(cmd, **kwargs):
40+
subprocess.run(cmd, **kwargs)
41+
42+
def main(argv):
43+
parser = argparse.ArgumentParser(description=__doc__)
44+
opts = parser.parse_args(argv)
45+
46+
if not shutil.which('help2man'):
47+
sys.exit('Please install help2man to continue.')
48+
49+
# Let repo know we're generating man pages so it can avoid some dynamic
50+
# behavior (like probing active number of CPUs). We use a weird name &
51+
# value to make it less likely for users to set this var themselves.
52+
os.environ['_REPO_GENERATE_MANPAGES_'] = ' indeed! '
53+
54+
# "repo branch" is an alias for "repo branches".
55+
del subcmds.all_commands['branch']
56+
(MANDIR / 'repo-branch.1').write_text('.so man1/repo-branches.1')
57+
58+
version = RepoSourceVersion()
59+
cmdlist = [['help2man', '-N', '-n', f'repo {cmd} - manual page for repo {cmd}',
60+
'-S', f'repo {cmd}', '-m', 'Repo Manual', f'--version-string={version}',
61+
'-o', MANDIR.joinpath(f'repo-{cmd}.1.tmp'), './repo',
62+
'-h', f'help {cmd}'] for cmd in subcmds.all_commands]
63+
cmdlist.append(['help2man', '-N', '-n', 'repository management tool built on top of git',
64+
'-S', 'repo', '-m', 'Repo Manual', f'--version-string={version}',
65+
'-o', MANDIR.joinpath('repo.1.tmp'), './repo',
66+
'-h', '--help-all'])
67+
68+
with tempfile.TemporaryDirectory() as tempdir:
69+
tempdir = Path(tempdir)
70+
repo_dir = tempdir / '.repo'
71+
repo_dir.mkdir()
72+
(repo_dir / 'repo').symlink_to(TOPDIR)
73+
74+
# Create a repo wrapper using the active Python executable. We can't pass
75+
# this directly to help2man as it's too simple, so insert it via shebang.
76+
data = (TOPDIR / 'repo').read_text(encoding='utf-8')
77+
tempbin = tempdir / 'repo'
78+
tempbin.write_text(f'#!{sys.executable}\n' + data, encoding='utf-8')
79+
tempbin.chmod(0o755)
80+
81+
# Run all cmd in parallel, and wait for them to finish.
82+
with multiprocessing.Pool() as pool:
83+
pool.map(partial(worker, cwd=tempdir, check=True), cmdlist)
84+
85+
for tmp_path in MANDIR.glob('*.1.tmp'):
86+
path = tmp_path.parent / tmp_path.stem
87+
old_data = path.read_text() if path.exists() else ''
88+
89+
data = tmp_path.read_text()
90+
tmp_path.unlink()
91+
92+
data = replace_regex(data)
93+
94+
# If the only thing that changed was the date, don't refresh. This avoids
95+
# a lot of noise when only one file actually updates.
96+
old_data = re.sub(r'^(\.TH REPO "1" ")([^"]+)', r'\1', old_data, flags=re.M)
97+
new_data = re.sub(r'^(\.TH REPO "1" ")([^"]+)', r'\1', data, flags=re.M)
98+
if old_data != new_data:
99+
path.write_text(data)
100+
101+
102+
def replace_regex(data):
103+
"""Replace semantically null regexes in the data.
104+
105+
Args:
106+
data: manpage text.
107+
108+
Returns:
109+
Updated manpage text.
110+
"""
111+
regex = (
112+
(r'(It was generated by help2man) [0-9.]+', r'\g<1>.'),
113+
(r'^\033\[[0-9;]*m([^\033]*)\033\[m', r'\g<1>'),
114+
(r'^\.IP\n(.*:)\n', r'.SS \g<1>\n'),
115+
(r'^\.PP\nDescription', r'.SH DETAILS'),
116+
)
117+
for pattern, replacement in regex:
118+
data = re.sub(pattern, replacement, data, flags=re.M)
119+
return data

repo/command.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,8 @@ def GetProjects(self, args, manifest=None, groups='', missing_ok=False,
320320
for arg in args:
321321
# We have to filter by manifest groups in case the requested project is
322322
# checked out multiple times or differently based on them.
323-
projects = [project for project in manifest.GetProjectsWithName(
323+
projects = [project
324+
for project in manifest.GetProjectsWithName(
324325
arg, all_manifests=all_manifests)
325326
if project.MatchesGroups(groups)]
326327

repo/git_command.py

+21-21
Original file line numberDiff line numberDiff line change
@@ -159,12 +159,12 @@ def git_require(min_version, fail=False, msg=''):
159159

160160

161161
def _build_env(
162-
_kwargs_only=(),
163-
bare: Optional[bool] = False,
164-
disable_editor: Optional[bool] = False,
165-
ssh_proxy: Optional[Any] = None,
166-
gitdir: Optional[str] = None,
167-
objdir: Optional[str] = None
162+
_kwargs_only=(),
163+
bare: Optional[bool] = False,
164+
disable_editor: Optional[bool] = False,
165+
ssh_proxy: Optional[Any] = None,
166+
gitdir: Optional[str] = None,
167+
objdir: Optional[str] = None
168168
):
169169
"""Constucts an env dict for command execution."""
170170

@@ -194,8 +194,7 @@ def _build_env(
194194
env['GIT_OBJECT_DIRECTORY'] = objdir
195195

196196
alt_objects = os.path.join(gitdir, 'objects') if gitdir else None
197-
if (alt_objects and
198-
os.path.realpath(alt_objects) != os.path.realpath(objdir)):
197+
if alt_objects and os.path.realpath(alt_objects) != os.path.realpath(objdir):
199198
# Allow git to search the original place in case of local or unique refs
200199
# that git will attempt to resolve even if we aren't fetching them.
201200
env['GIT_ALTERNATE_OBJECT_DIRECTORIES'] = alt_objects
@@ -236,11 +235,11 @@ def __init__(self,
236235
gitdir = gitdir.replace('\\', '/')
237236

238237
env = _build_env(
239-
disable_editor=disable_editor,
240-
ssh_proxy=ssh_proxy,
241-
objdir=objdir,
242-
gitdir=gitdir,
243-
bare=bare,
238+
disable_editor=disable_editor,
239+
ssh_proxy=ssh_proxy,
240+
objdir=objdir,
241+
gitdir=gitdir,
242+
bare=bare,
244243
)
245244

246245
command = [GIT]
@@ -279,7 +278,8 @@ def __init__(self,
279278
if 'GIT_OBJECT_DIRECTORY' in env:
280279
dbg += ': export GIT_OBJECT_DIRECTORY=%s\n' % env['GIT_OBJECT_DIRECTORY']
281280
if 'GIT_ALTERNATE_OBJECT_DIRECTORIES' in env:
282-
dbg += ': export GIT_ALTERNATE_OBJECT_DIRECTORIES=%s\n' % env['GIT_ALTERNATE_OBJECT_DIRECTORIES']
281+
dbg += ': export GIT_ALTERNATE_OBJECT_DIRECTORIES=%s\n' % (
282+
env['GIT_ALTERNATE_OBJECT_DIRECTORIES'])
283283

284284
dbg += ': '
285285
dbg += ' '.join(command)
@@ -295,13 +295,13 @@ def __init__(self,
295295
with Trace('git command %s %s with debug: %s', LAST_GITDIR, command, dbg):
296296
try:
297297
p = subprocess.Popen(command,
298-
cwd=cwd,
299-
env=env,
300-
encoding='utf-8',
301-
errors='backslashreplace',
302-
stdin=stdin,
303-
stdout=stdout,
304-
stderr=stderr)
298+
cwd=cwd,
299+
env=env,
300+
encoding='utf-8',
301+
errors='backslashreplace',
302+
stdin=stdin,
303+
stdout=stdout,
304+
stderr=stderr)
305305
except Exception as e:
306306
raise GitError('%s: %s' % (command[1], e))
307307

repo/git_config.py

+11-6
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,6 @@ def _key(name):
7171
class GitConfig(object):
7272
_ForUser = None
7373

74-
_USER_CONFIG = '~/.gitconfig'
75-
7674
_ForSystem = None
7775
_SYSTEM_CONFIG = '/etc/gitconfig'
7876

@@ -85,9 +83,13 @@ def ForSystem(cls):
8583
@classmethod
8684
def ForUser(cls):
8785
if cls._ForUser is None:
88-
cls._ForUser = cls(configfile=os.path.expanduser(cls._USER_CONFIG))
86+
cls._ForUser = cls(configfile=cls._getUserConfig())
8987
return cls._ForUser
9088

89+
@staticmethod
90+
def _getUserConfig():
91+
return os.path.expanduser('~/.gitconfig')
92+
9193
@classmethod
9294
def ForRepository(cls, gitdir, defaults=None):
9395
return cls(configfile=os.path.join(gitdir, 'config'),
@@ -190,7 +192,7 @@ def GetBoolean(self, name: str) -> Union[str, None]:
190192
if v in ('false', 'no'):
191193
return False
192194
print(f"warning: expected {name} to represent a boolean, got {v} instead",
193-
file=sys.stderr)
195+
file=sys.stderr)
194196
return None
195197

196198
def SetBoolean(self, name, value):
@@ -199,7 +201,7 @@ def SetBoolean(self, name, value):
199201
value = 'true' if value else 'false'
200202
self.SetString(name, value)
201203

202-
def GetString(self, name: str, all_keys: bool = False) -> Union[str, None]:
204+
def GetString(self, name: str, all_keys: bool = False) -> Union[str, None]:
203205
"""Get the first value for a key, or None if it is not defined.
204206
205207
This configuration file is used first, if the key is not
@@ -417,7 +419,10 @@ def _do(self, *args):
417419
class RepoConfig(GitConfig):
418420
"""User settings for repo itself."""
419421

420-
_USER_CONFIG = '~/.repoconfig/config'
422+
@staticmethod
423+
def _getUserConfig():
424+
repo_config_dir = os.getenv('REPO_CONFIG_DIR', os.path.expanduser('~'))
425+
return os.path.join(repo_config_dir, '.repoconfig/config')
421426

422427

423428
class RefSpec(object):

0 commit comments

Comments
 (0)