Compare commits

...

5 Commits

Author SHA1 Message Date
9888accb0c project: fix diff printing with embedded %
The recent commit 84230009ee ("project:
make diff tools synchronous") broke repo diff if it includes % formats.
Add an explicit format string to fix.

Bug: https://crbug.com/gerrit/14208
Change-Id: Ie255a43c5b767488616b2b3dd15abc18f93bfab2
Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/299402
Reviewed-by: Michael Mortensen <mmortensen@google.com>
Tested-by: Mike Frysinger <vapier@google.com>
2021-03-09 17:00:02 +00:00
5a4c8fde17 init: expose --worktree option
There's a few rough edges here still, but no known corruption ones,
so open it up a bit for people to experiment with.

Bug: https://crbug.com/gerrit/11486
Change-Id: I81e0122ab6d3e032c546c8239dd4f03740676e80
Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/299242
Reviewed-by: Michael Mortensen <mmortensen@google.com>
Tested-by: Mike Frysinger <vapier@google.com>
2021-03-09 16:59:59 +00:00
835a34bdb9 Log repo.* config variables in git trace2 logger.
Bug: [google internal] b/181758736
Testing:
- Unit tests
- Verified repo git trace2 logs had expected data

Change-Id: I9af8a574377bd91115f085808c1271e9dee16a36
Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/299182
Tested-by: Ian Kasprzak <iankaz@google.com>
Reviewed-by: Mike Frysinger <vapier@google.com>
Reviewed-by: Raman Tenneti <rtenneti@google.com>
2021-03-08 17:32:09 +00:00
ef99ec07b4 superproject: Display status messages during repo init/sync.
Superproject objects accept the optional argument “quiet”.
The following progress messages are displayed if quiet is false.

Displayed the following message whenever we find we have to make a new
folder (aka new remote), because if you started with repo init android
and later do googleplex-android that is when it will be slow.

"<location>: Performing initial setup for superproject; this might take
several minutes.".

After fetch completion, added the following notification:
"<location>: Initial setup for superproject completed."

Tested the code with the following commands.

$ ./run_tests -v

Tested the sync code by using repo_dev alias and pointing to this CL.

$ repo_dev init -u persistent-https://googleplex-android.git.corp.google.com/platform/manifest -b rvc-dev  --partial-clone --clone-filter=blob:limit=10M --repo-rev=main  --use-superproject

Bug: [google internal] b/181178282
Bug: https://crbug.com/gerrit/13707
Change-Id: Ia7fb85c6fb934faaa90c48fc0c55e7f41055f48a
Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/299122
Reviewed-by: Mike Frysinger <vapier@google.com>
Tested-by: Raman Tenneti <rtenneti@google.com>
2021-03-04 20:07:52 +00:00
934cb0a849 tests: fix duplicate method from copy & paste error
Change-Id: Ib748c61b1e65aee6dff8b97a9753d14c470a827f
Reported-by: Daniel Kutik <daniel.kutik@lavawerk.com>
Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/299002
Reviewed-by: Daniel Kutik <daniel.kutik@lavawerk.com>
Reviewed-by: Ian Kasprzak <iankaz@google.com>
Tested-by: Mike Frysinger <vapier@google.com>
2021-03-04 16:17:11 +00:00
10 changed files with 106 additions and 13 deletions

View File

@ -145,6 +145,21 @@ class GitConfig(object):
except ValueError: except ValueError:
return None return None
def DumpConfigDict(self):
"""Returns the current configuration dict.
Configuration data is information only (e.g. logging) and
should not be considered a stable data-source.
Returns:
dict of {<key>, <value>} for git configuration cache.
<value> are strings converted by GetString.
"""
config_dict = {}
for key in self._cache:
config_dict[key] = self.GetString(key)
return config_dict
def GetBoolean(self, name): def GetBoolean(self, name):
"""Returns a boolean from the configuration file. """Returns a boolean from the configuration file.
None : The value was not defined, or is not a boolean. None : The value was not defined, or is not a boolean.

View File

@ -41,7 +41,8 @@ class Superproject(object):
lookup of commit ids for all projects. It contains _project_commit_ids which lookup of commit ids for all projects. It contains _project_commit_ids which
is a dictionary with project/commit id entries. is a dictionary with project/commit id entries.
""" """
def __init__(self, manifest, repodir, superproject_dir='exp-superproject'): def __init__(self, manifest, repodir, superproject_dir='exp-superproject',
quiet=False):
"""Initializes superproject. """Initializes superproject.
Args: Args:
@ -49,9 +50,11 @@ class Superproject(object):
repodir: Path to the .repo/ dir for holding all internal checkout state. repodir: Path to the .repo/ dir for holding all internal checkout state.
It must be in the top directory of the repo client checkout. It must be in the top directory of the repo client checkout.
superproject_dir: Relative path under |repodir| to checkout superproject. superproject_dir: Relative path under |repodir| to checkout superproject.
quiet: If True then only print the progress messages.
""" """
self._project_commit_ids = None self._project_commit_ids = None
self._manifest = manifest self._manifest = manifest
self._quiet = quiet
self._branch = self._GetBranch() self._branch = self._GetBranch()
self._repodir = os.path.abspath(repodir) self._repodir = os.path.abspath(repodir)
self._superproject_dir = superproject_dir self._superproject_dir = superproject_dir
@ -89,6 +92,9 @@ class Superproject(object):
""" """
if not os.path.exists(self._superproject_path): if not os.path.exists(self._superproject_path):
os.mkdir(self._superproject_path) os.mkdir(self._superproject_path)
if not self._quiet and not os.path.exists(self._work_git):
print('%s: Performing initial setup for superproject; this might take '
'several minutes.' % self._work_git)
cmd = ['init', '--bare', self._work_git_name] cmd = ['init', '--bare', self._work_git_name]
p = GitCommand(None, p = GitCommand(None,
cmd, cmd,
@ -183,6 +189,8 @@ class Superproject(object):
return False return False
if not self._Fetch(url): if not self._Fetch(url):
return False return False
if not self._quiet:
print('%s: Initial setup for superproject completed.' % self._work_git)
return True return True
def _GetAllProjectsCommitIds(self): def _GetAllProjectsCommitIds(self):

View File

@ -132,6 +132,21 @@ class EventLog(object):
exit_event['code'] = result exit_event['code'] = result
self._log.append(exit_event) self._log.append(exit_event)
def DefParamRepoEvents(self, config):
"""Append a 'def_param' event for each repo.* config key to the current log.
Args:
config: Repo configuration dictionary
"""
# Only output the repo.* config parameters.
repo_config = {k: v for k, v in config.items() if k.startswith('repo.')}
for param, value in repo_config.items():
def_param_event = self._CreateEventDict('def_param')
def_param_event['param'] = param
def_param_event['value'] = value
self._log.append(def_param_event)
def _GetEventTargetPath(self): def _GetEventTargetPath(self):
"""Get the 'trace2.eventtarget' path from git configuration. """Get the 'trace2.eventtarget' path from git configuration.

View File

@ -297,6 +297,8 @@ class _Repo(object):
cmd.event_log.FinishEvent(cmd_event, finish, cmd.event_log.FinishEvent(cmd_event, finish,
result is None or result == 0) result is None or result == 0)
git_trace2_event_log.DefParamRepoEvents(
cmd.manifest.manifestProject.config.DumpConfigDict())
git_trace2_event_log.ExitEvent(result) git_trace2_event_log.ExitEvent(result)
if gopts.event_log: if gopts.event_log:

View File

@ -863,7 +863,7 @@ class Project(object):
out.nl() out.nl()
out.project('project %s/' % self.relpath) out.project('project %s/' % self.relpath)
out.nl() out.nl()
out.write(p.stdout) out.write('%s', p.stdout)
return p.Wait() == 0 return p.Wait() == 0
# Publish / Upload ## # Publish / Upload ##

2
repo
View File

@ -318,7 +318,7 @@ def GetParser(gitc_init=False):
help='filter for use with --partial-clone ' help='filter for use with --partial-clone '
'[default: %default]') '[default: %default]')
group.add_option('--worktree', action='store_true', group.add_option('--worktree', action='store_true',
help=optparse.SUPPRESS_HELP) help='use git-worktree to manage projects')
group.add_option('--archive', action='store_true', group.add_option('--archive', action='store_true',
help='checkout an archive instead of a git repository for ' help='checkout an archive instead of a git repository for '
'each project. See git archive.') 'each project. See git archive.')

View File

@ -127,10 +127,8 @@ to update the working directory files.
g.add_option('--clone-filter', action='store', default='blob:none', g.add_option('--clone-filter', action='store', default='blob:none',
dest='clone_filter', dest='clone_filter',
help='filter for use with --partial-clone [default: %default]') help='filter for use with --partial-clone [default: %default]')
# TODO(vapier): Expose option with real help text once this has been in the
# wild for a while w/out significant bug reports. Goal is by ~Sep 2020.
g.add_option('--worktree', action='store_true', g.add_option('--worktree', action='store_true',
help=optparse.SUPPRESS_HELP) help='use git-worktree to manage projects')
g.add_option('--archive', g.add_option('--archive',
dest='archive', action='store_true', dest='archive', action='store_true',
help='checkout an archive instead of a git repository for ' help='checkout an archive instead of a git repository for '
@ -185,10 +183,15 @@ to update the working directory files.
return {'REPO_MANIFEST_URL': 'manifest_url', return {'REPO_MANIFEST_URL': 'manifest_url',
'REPO_MIRROR_LOCATION': 'reference'} 'REPO_MIRROR_LOCATION': 'reference'}
def _CloneSuperproject(self): def _CloneSuperproject(self, opt):
"""Clone the superproject based on the superproject's url and branch.""" """Clone the superproject based on the superproject's url and branch.
Args:
opt: Program options returned from optparse. See _Options().
"""
superproject = git_superproject.Superproject(self.manifest, superproject = git_superproject.Superproject(self.manifest,
self.repodir) self.repodir,
quiet=opt.quiet)
if not superproject.Sync(): if not superproject.Sync():
print('error: git update of superproject failed', file=sys.stderr) print('error: git update of superproject failed', file=sys.stderr)
sys.exit(1) sys.exit(1)
@ -553,7 +556,7 @@ to update the working directory files.
self._LinkManifest(opt.manifest_name) self._LinkManifest(opt.manifest_name)
if self.manifest.manifestProject.config.GetBoolean('repo.superproject'): if self.manifest.manifestProject.config.GetBoolean('repo.superproject'):
self._CloneSuperproject() self._CloneSuperproject(opt)
if os.isatty(0) and os.isatty(1) and not self.manifest.IsMirror: if os.isatty(0) and os.isatty(1) and not self.manifest.IsMirror:
if opt.config_name or self._ShouldConfigureUser(opt): if opt.config_name or self._ShouldConfigureUser(opt):

View File

@ -292,7 +292,8 @@ later is required to fix a server side protocol bug.
Returns path to the overriding manifest file. Returns path to the overriding manifest file.
""" """
superproject = git_superproject.Superproject(self.manifest, superproject = git_superproject.Superproject(self.manifest,
self.repodir) self.repodir,
quiet=opt.quiet)
all_projects = self.GetProjects(args, all_projects = self.GetProjects(args,
missing_ok=True, missing_ok=True,
submodules_ok=opt.fetch_submodules) submodules_ok=opt.fetch_submodules)

View File

@ -161,6 +161,55 @@ class EventLogTestCase(unittest.TestCase):
self.assertIn('code', exit_event) self.assertIn('code', exit_event)
self.assertEqual(exit_event['code'], 2) self.assertEqual(exit_event['code'], 2)
def test_def_params_event_repo_config(self):
"""Test 'def_params' event data outputs only repo config keys.
Expected event log:
<version event>
<def_param event>
<def_param event>
"""
config = {
'git.foo': 'bar',
'repo.partialclone': 'true',
'repo.partialclonefilter': 'blob:none',
}
self._event_log_module.DefParamRepoEvents(config)
with tempfile.TemporaryDirectory(prefix='event_log_tests') as tempdir:
log_path = self._event_log_module.Write(path=tempdir)
self._log_data = self.readLog(log_path)
self.assertEqual(len(self._log_data), 3)
def_param_events = self._log_data[1:]
self.verifyCommonKeys(self._log_data[0], expected_event_name='version')
for event in def_param_events:
self.verifyCommonKeys(event, expected_event_name='def_param')
# Check for 'def_param' event specific fields.
self.assertIn('param', event)
self.assertIn('value', event)
self.assertTrue(event['param'].startswith('repo.'))
def test_def_params_event_no_repo_config(self):
"""Test 'def_params' event data won't output non-repo config keys.
Expected event log:
<version event>
"""
config = {
'git.foo': 'bar',
'git.core.foo2': 'baz',
}
self._event_log_module.DefParamRepoEvents(config)
with tempfile.TemporaryDirectory(prefix='event_log_tests') as tempdir:
log_path = self._event_log_module.Write(path=tempdir)
self._log_data = self.readLog(log_path)
self.assertEqual(len(self._log_data), 1)
self.verifyCommonKeys(self._log_data[0], expected_event_name='version')
def test_write_with_filename(self): def test_write_with_filename(self):
"""Test Write() with a path to a file exits with None.""" """Test Write() with a path to a file exits with None."""
self.assertIsNone(self._event_log_module.Write(path='path/to/file')) self.assertIsNone(self._event_log_module.Write(path='path/to/file'))

View File

@ -305,8 +305,8 @@ class Requirements(RepoWrapperTestCase):
reqs = self.wrapper.Requirements({'python': {'hard': sys.version_info}}) reqs = self.wrapper.Requirements({'python': {'hard': sys.version_info}})
reqs.assert_all() reqs.assert_all()
def test_assert_all_old_repo(self): def test_assert_all_old_python(self):
"""Check assert_all rejects old repo.""" """Check assert_all rejects old python."""
reqs = self.wrapper.Requirements({'python': {'hard': [99999, 0]}}) reqs = self.wrapper.Requirements({'python': {'hard': [99999, 0]}})
with self.assertRaises(SystemExit): with self.assertRaises(SystemExit):
reqs.assert_all() reqs.assert_all()