mirror of
https://gerrit.googlesource.com/git-repo
synced 2025-06-28 20:17:26 +00:00
Compare commits
37 Commits
Author | SHA1 | Date | |
---|---|---|---|
9122bfc3a8 | |||
7954de13b7 | |||
ae86a46022 | |||
73c43b839f | |||
56345c345b | |||
a024bd33b8 | |||
968d646f04 | |||
cfa00d6e3d | |||
5467185db0 | |||
b380322174 | |||
13d6c94cfb | |||
6ea0caea86 | |||
8e983bbc0f | |||
c34b91c9d8 | |||
0a1f533e28 | |||
927d29a8af | |||
8db30d686a | |||
e39d8b36f6 | |||
06da9987f6 | |||
5892973212 | |||
0cb6e92ac5 | |||
0e776a5837 | |||
1da6f30579 | |||
784e16f3aa | |||
b8c84483a5 | |||
d58d0dd3bf | |||
d88b369a42 | |||
4f21054c28 | |||
5ba2120362 | |||
78f4dd3138 | |||
fc7aa90623 | |||
50c91ecf4f | |||
816d82c010 | |||
2b37fa3f26 | |||
a3b2edf1af | |||
e253b43e17 | |||
5d58c18146 |
2
.github/workflows/test-ci.yml
vendored
2
.github/workflows/test-ci.yml
vendored
@ -14,7 +14,7 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||||
python-version: [3.5, 3.6, 3.7, 3.8, 3.9]
|
python-version: [3.6, 3.7, 3.8, 3.9]
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
24
command.py
24
command.py
@ -15,7 +15,6 @@
|
|||||||
import multiprocessing
|
import multiprocessing
|
||||||
import os
|
import os
|
||||||
import optparse
|
import optparse
|
||||||
import platform
|
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
@ -43,15 +42,32 @@ class Command(object):
|
|||||||
"""Base class for any command line action in repo.
|
"""Base class for any command line action in repo.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
common = False
|
# Singleton for all commands to track overall repo command execution and
|
||||||
|
# provide event summary to callers. Only used by sync subcommand currently.
|
||||||
|
#
|
||||||
|
# NB: This is being replaced by git trace2 events. See git_trace2_event_log.
|
||||||
event_log = EventLog()
|
event_log = EventLog()
|
||||||
manifest = None
|
|
||||||
_optparse = None
|
# Whether this command is a "common" one, i.e. whether the user would commonly
|
||||||
|
# use it or it's a more uncommon command. This is used by the help command to
|
||||||
|
# show short-vs-full summaries.
|
||||||
|
COMMON = False
|
||||||
|
|
||||||
# Whether this command supports running in parallel. If greater than 0,
|
# Whether this command supports running in parallel. If greater than 0,
|
||||||
# it is the number of parallel jobs to default to.
|
# it is the number of parallel jobs to default to.
|
||||||
PARALLEL_JOBS = None
|
PARALLEL_JOBS = None
|
||||||
|
|
||||||
|
def __init__(self, repodir=None, client=None, manifest=None, gitc_manifest=None,
|
||||||
|
git_event_log=None):
|
||||||
|
self.repodir = repodir
|
||||||
|
self.client = client
|
||||||
|
self.manifest = manifest
|
||||||
|
self.gitc_manifest = gitc_manifest
|
||||||
|
self.git_event_log = git_event_log
|
||||||
|
|
||||||
|
# Cache for the OptionParser property.
|
||||||
|
self._optparse = None
|
||||||
|
|
||||||
def WantPager(self, _opt):
|
def WantPager(self, _opt):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -14,6 +14,9 @@
|
|||||||
|
|
||||||
# Programmable bash completion. https://github.com/scop/bash-completion
|
# Programmable bash completion. https://github.com/scop/bash-completion
|
||||||
|
|
||||||
|
# TODO: Handle interspersed options. We handle `repo h<tab>`, but not
|
||||||
|
# `repo --time h<tab>`.
|
||||||
|
|
||||||
# Complete the list of repo subcommands.
|
# Complete the list of repo subcommands.
|
||||||
__complete_repo_list_commands() {
|
__complete_repo_list_commands() {
|
||||||
local repo=${COMP_WORDS[0]}
|
local repo=${COMP_WORDS[0]}
|
||||||
@ -37,6 +40,7 @@ __complete_repo_list_branches() {
|
|||||||
__complete_repo_list_projects() {
|
__complete_repo_list_projects() {
|
||||||
local repo=${COMP_WORDS[0]}
|
local repo=${COMP_WORDS[0]}
|
||||||
"${repo}" list -n 2>/dev/null
|
"${repo}" list -n 2>/dev/null
|
||||||
|
"${repo}" list -p --relative-to=. 2>/dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
# Complete the repo <command> argument.
|
# Complete the repo <command> argument.
|
||||||
@ -66,6 +70,48 @@ __complete_repo_command_projects() {
|
|||||||
COMPREPLY=($(compgen -W "$(__complete_repo_list_projects)" -- "${current}"))
|
COMPREPLY=($(compgen -W "$(__complete_repo_list_projects)" -- "${current}"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Complete `repo help`.
|
||||||
|
__complete_repo_command_help() {
|
||||||
|
local current=$1
|
||||||
|
# CWORD=1 is "start".
|
||||||
|
# CWORD=2 is the <subcommand> which we complete here.
|
||||||
|
if [[ ${COMP_CWORD} -eq 2 ]]; then
|
||||||
|
COMPREPLY=(
|
||||||
|
$(compgen -W "$(__complete_repo_list_commands)" -- "${current}")
|
||||||
|
)
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Complete `repo forall`.
|
||||||
|
__complete_repo_command_forall() {
|
||||||
|
local current=$1
|
||||||
|
# CWORD=1 is "forall".
|
||||||
|
# CWORD=2+ are <projects> *until* we hit the -c option.
|
||||||
|
local i
|
||||||
|
for (( i = 0; i < COMP_CWORD; ++i )); do
|
||||||
|
if [[ "${COMP_WORDS[i]}" == "-c" ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
COMPREPLY=(
|
||||||
|
$(compgen -W "$(__complete_repo_list_projects)" -- "${current}")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Complete `repo start`.
|
||||||
|
__complete_repo_command_start() {
|
||||||
|
local current=$1
|
||||||
|
# CWORD=1 is "start".
|
||||||
|
# CWORD=2 is the <branch> which we don't complete.
|
||||||
|
# CWORD=3+ are <projects> which we complete here.
|
||||||
|
if [[ ${COMP_CWORD} -gt 2 ]]; then
|
||||||
|
COMPREPLY=(
|
||||||
|
$(compgen -W "$(__complete_repo_list_projects)" -- "${current}")
|
||||||
|
)
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# Complete the repo subcommand arguments.
|
# Complete the repo subcommand arguments.
|
||||||
__complete_repo_arg() {
|
__complete_repo_arg() {
|
||||||
if [[ ${COMP_CWORD} -le 1 ]]; then
|
if [[ ${COMP_CWORD} -le 1 ]]; then
|
||||||
@ -86,21 +132,8 @@ __complete_repo_arg() {
|
|||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
|
|
||||||
help)
|
help|start|forall)
|
||||||
if [[ ${COMP_CWORD} -eq 2 ]]; then
|
__complete_repo_command_${command} "${current}"
|
||||||
COMPREPLY=(
|
|
||||||
$(compgen -W "$(__complete_repo_list_commands)" -- "${current}")
|
|
||||||
)
|
|
||||||
fi
|
|
||||||
return 0
|
|
||||||
;;
|
|
||||||
|
|
||||||
start)
|
|
||||||
if [[ ${COMP_CWORD} -gt 2 ]]; then
|
|
||||||
COMPREPLY=(
|
|
||||||
$(compgen -W "$(__complete_repo_list_projects)" -- "${current}")
|
|
||||||
)
|
|
||||||
fi
|
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
|
|
||||||
@ -118,4 +151,6 @@ __complete_repo() {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
complete -F __complete_repo repo
|
# Fallback to the default complete methods if we aren't able to provide anything
|
||||||
|
# useful. This will allow e.g. local paths to be used when it makes sense.
|
||||||
|
complete -F __complete_repo -o bashdefault -o default repo
|
||||||
|
@ -146,7 +146,12 @@ Instead, you should use standard Git workflows like [git worktree] or
|
|||||||
|
|
||||||
The `.repo/manifests.git/config` file is used to track settings for the entire
|
The `.repo/manifests.git/config` file is used to track settings for the entire
|
||||||
repo client checkout.
|
repo client checkout.
|
||||||
|
|
||||||
Most settings use the `[repo]` section to avoid conflicts with git.
|
Most settings use the `[repo]` section to avoid conflicts with git.
|
||||||
|
|
||||||
|
Everything under `[repo.syncstate.*]` is used to keep track of sync details for logging
|
||||||
|
purposes.
|
||||||
|
|
||||||
User controlled settings are initialized when running `repo init`.
|
User controlled settings are initialized when running `repo init`.
|
||||||
|
|
||||||
| Setting | `repo init` Option | Use/Meaning |
|
| Setting | `repo init` Option | Use/Meaning |
|
||||||
|
@ -36,7 +36,7 @@ following DTD:
|
|||||||
|
|
||||||
<!ELEMENT notice (#PCDATA)>
|
<!ELEMENT notice (#PCDATA)>
|
||||||
|
|
||||||
<!ELEMENT remote EMPTY>
|
<!ELEMENT remote (annotation*)>
|
||||||
<!ATTLIST remote name ID #REQUIRED>
|
<!ATTLIST remote name ID #REQUIRED>
|
||||||
<!ATTLIST remote alias CDATA #IMPLIED>
|
<!ATTLIST remote alias CDATA #IMPLIED>
|
||||||
<!ATTLIST remote fetch CDATA #REQUIRED>
|
<!ATTLIST remote fetch CDATA #REQUIRED>
|
||||||
@ -96,6 +96,7 @@ following DTD:
|
|||||||
|
|
||||||
<!ELEMENT remove-project EMPTY>
|
<!ELEMENT remove-project EMPTY>
|
||||||
<!ATTLIST remove-project name CDATA #REQUIRED>
|
<!ATTLIST remove-project name CDATA #REQUIRED>
|
||||||
|
<!ATTLIST remove-project optional CDATA #IMPLIED>
|
||||||
|
|
||||||
<!ELEMENT repo-hooks EMPTY>
|
<!ELEMENT repo-hooks EMPTY>
|
||||||
<!ATTLIST repo-hooks in-project CDATA #REQUIRED>
|
<!ATTLIST repo-hooks in-project CDATA #REQUIRED>
|
||||||
@ -347,12 +348,12 @@ project. Same syntax as the corresponding element of `project`.
|
|||||||
### Element annotation
|
### Element annotation
|
||||||
|
|
||||||
Zero or more annotation elements may be specified as children of a
|
Zero or more annotation elements may be specified as children of a
|
||||||
project element. Each element describes a name-value pair that will be
|
project or remote element. Each element describes a name-value pair.
|
||||||
exported into each project's environment during a 'forall' command,
|
For projects, this name-value pair will be exported into each project's
|
||||||
prefixed with REPO__. In addition, there is an optional attribute
|
environment during a 'forall' command, prefixed with `REPO__`. In addition,
|
||||||
"keep" which accepts the case insensitive values "true" (default) or
|
there is an optional attribute "keep" which accepts the case insensitive values
|
||||||
"false". This attribute determines whether or not the annotation will
|
"true" (default) or "false". This attribute determines whether or not the
|
||||||
be kept when exported with the manifest subcommand.
|
annotation will be kept when exported with the manifest subcommand.
|
||||||
|
|
||||||
### Element copyfile
|
### Element copyfile
|
||||||
|
|
||||||
@ -393,6 +394,9 @@ This element is mostly useful in a local manifest file, where
|
|||||||
the user can remove a project, and possibly replace it with their
|
the user can remove a project, and possibly replace it with their
|
||||||
own definition.
|
own definition.
|
||||||
|
|
||||||
|
Attribute `optional`: Set to true to ignore remove-project elements with no
|
||||||
|
matching `project` element.
|
||||||
|
|
||||||
### Element repo-hooks
|
### Element repo-hooks
|
||||||
|
|
||||||
NB: See the [practical documentation](./repo-hooks.md) for using repo hooks.
|
NB: See the [practical documentation](./repo-hooks.md) for using repo hooks.
|
||||||
@ -485,6 +489,9 @@ these extra projects.
|
|||||||
Manifest files stored in `$TOP_DIR/.repo/local_manifests/*.xml` will
|
Manifest files stored in `$TOP_DIR/.repo/local_manifests/*.xml` will
|
||||||
be loaded in alphabetical order.
|
be loaded in alphabetical order.
|
||||||
|
|
||||||
|
Projects from local manifest files are added into
|
||||||
|
local::<local manifest filename> group.
|
||||||
|
|
||||||
The legacy `$TOP_DIR/.repo/local_manifest.xml` path is no longer supported.
|
The legacy `$TOP_DIR/.repo/local_manifest.xml` path is no longer supported.
|
||||||
|
|
||||||
|
|
||||||
|
@ -75,7 +75,8 @@ def RepoSourceVersion():
|
|||||||
proj = os.path.dirname(os.path.abspath(__file__))
|
proj = os.path.dirname(os.path.abspath(__file__))
|
||||||
env[GIT_DIR] = os.path.join(proj, '.git')
|
env[GIT_DIR] = os.path.join(proj, '.git')
|
||||||
result = subprocess.run([GIT, 'describe', HEAD], stdout=subprocess.PIPE,
|
result = subprocess.run([GIT, 'describe', HEAD], stdout=subprocess.PIPE,
|
||||||
encoding='utf-8', env=env, check=False)
|
stderr=subprocess.DEVNULL, encoding='utf-8',
|
||||||
|
env=env, check=False)
|
||||||
if result.returncode == 0:
|
if result.returncode == 0:
|
||||||
ver = result.stdout.strip()
|
ver = result.stdout.strip()
|
||||||
if ver.startswith('v'):
|
if ver.startswith('v'):
|
||||||
|
102
git_config.py
102
git_config.py
@ -13,6 +13,7 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
|
import datetime
|
||||||
import errno
|
import errno
|
||||||
from http.client import HTTPException
|
from http.client import HTTPException
|
||||||
import json
|
import json
|
||||||
@ -30,6 +31,10 @@ from repo_trace import Trace
|
|||||||
from git_command import GitCommand
|
from git_command import GitCommand
|
||||||
from git_refs import R_CHANGES, R_HEADS, R_TAGS
|
from git_refs import R_CHANGES, R_HEADS, R_TAGS
|
||||||
|
|
||||||
|
# Prefix that is prepended to all the keys of SyncAnalysisState's data
|
||||||
|
# that is saved in the config.
|
||||||
|
SYNC_STATE_PREFIX = 'repo.syncstate.'
|
||||||
|
|
||||||
ID_RE = re.compile(r'^[0-9a-f]{40}$')
|
ID_RE = re.compile(r'^[0-9a-f]{40}$')
|
||||||
|
|
||||||
REVIEW_CACHE = dict()
|
REVIEW_CACHE = dict()
|
||||||
@ -65,6 +70,15 @@ class GitConfig(object):
|
|||||||
|
|
||||||
_USER_CONFIG = '~/.gitconfig'
|
_USER_CONFIG = '~/.gitconfig'
|
||||||
|
|
||||||
|
_ForSystem = None
|
||||||
|
_SYSTEM_CONFIG = '/etc/gitconfig'
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def ForSystem(cls):
|
||||||
|
if cls._ForSystem is None:
|
||||||
|
cls._ForSystem = cls(configfile=cls._SYSTEM_CONFIG)
|
||||||
|
return cls._ForSystem
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def ForUser(cls):
|
def ForUser(cls):
|
||||||
if cls._ForUser is None:
|
if cls._ForUser is None:
|
||||||
@ -253,6 +267,22 @@ class GitConfig(object):
|
|||||||
self._branches[b.name] = b
|
self._branches[b.name] = b
|
||||||
return b
|
return b
|
||||||
|
|
||||||
|
def GetSyncAnalysisStateData(self):
|
||||||
|
"""Returns data to be logged for the analysis of sync performance."""
|
||||||
|
return {k: v for k, v in self.DumpConfigDict().items() if k.startswith(SYNC_STATE_PREFIX)}
|
||||||
|
|
||||||
|
def UpdateSyncAnalysisState(self, options, superproject_logging_data):
|
||||||
|
"""Update Config's SYNC_STATE_PREFIX* data with the latest sync data.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
options: Options passed to sync returned from optparse. See _Options().
|
||||||
|
superproject_logging_data: A dictionary of superproject data that is to be logged.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
SyncAnalysisState object.
|
||||||
|
"""
|
||||||
|
return SyncAnalysisState(self, options, superproject_logging_data)
|
||||||
|
|
||||||
def GetSubSections(self, section):
|
def GetSubSections(self, section):
|
||||||
"""List all subsection names matching $section.*.*
|
"""List all subsection names matching $section.*.*
|
||||||
"""
|
"""
|
||||||
@ -356,7 +386,10 @@ class GitConfig(object):
|
|||||||
return c
|
return c
|
||||||
|
|
||||||
def _do(self, *args):
|
def _do(self, *args):
|
||||||
command = ['config', '--file', self.file, '--includes']
|
if self.file == self._SYSTEM_CONFIG:
|
||||||
|
command = ['config', '--system', '--includes']
|
||||||
|
else:
|
||||||
|
command = ['config', '--file', self.file, '--includes']
|
||||||
command.extend(args)
|
command.extend(args)
|
||||||
|
|
||||||
p = GitCommand(None,
|
p = GitCommand(None,
|
||||||
@ -705,3 +738,70 @@ class Branch(object):
|
|||||||
def _Get(self, key, all_keys=False):
|
def _Get(self, key, all_keys=False):
|
||||||
key = 'branch.%s.%s' % (self.name, key)
|
key = 'branch.%s.%s' % (self.name, key)
|
||||||
return self._config.GetString(key, all_keys=all_keys)
|
return self._config.GetString(key, all_keys=all_keys)
|
||||||
|
|
||||||
|
|
||||||
|
class SyncAnalysisState:
|
||||||
|
"""Configuration options related to logging of sync state for analysis.
|
||||||
|
|
||||||
|
This object is versioned.
|
||||||
|
"""
|
||||||
|
def __init__(self, config, options, superproject_logging_data):
|
||||||
|
"""Initializes SyncAnalysisState.
|
||||||
|
|
||||||
|
Saves the following data into the |config| object.
|
||||||
|
- sys.argv, options, superproject's logging data.
|
||||||
|
- repo.*, branch.* and remote.* parameters from config object.
|
||||||
|
- Current time as synctime.
|
||||||
|
- Version number of the object.
|
||||||
|
|
||||||
|
All the keys saved by this object are prepended with SYNC_STATE_PREFIX.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
config: GitConfig object to store all options.
|
||||||
|
options: Options passed to sync returned from optparse. See _Options().
|
||||||
|
superproject_logging_data: A dictionary of superproject data that is to be logged.
|
||||||
|
"""
|
||||||
|
self._config = config
|
||||||
|
now = datetime.datetime.utcnow()
|
||||||
|
self._Set('main.synctime', now.isoformat() + 'Z')
|
||||||
|
self._Set('main.version', '1')
|
||||||
|
self._Set('sys.argv', sys.argv)
|
||||||
|
for key, value in superproject_logging_data.items():
|
||||||
|
self._Set(f'superproject.{key}', value)
|
||||||
|
for key, value in options.__dict__.items():
|
||||||
|
self._Set(f'options.{key}', value)
|
||||||
|
config_items = config.DumpConfigDict().items()
|
||||||
|
EXTRACT_NAMESPACES = {'repo', 'branch', 'remote'}
|
||||||
|
self._SetDictionary({k: v for k, v in config_items
|
||||||
|
if not k.startswith(SYNC_STATE_PREFIX) and
|
||||||
|
k.split('.', 1)[0] in EXTRACT_NAMESPACES})
|
||||||
|
|
||||||
|
def _SetDictionary(self, data):
|
||||||
|
"""Save all key/value pairs of |data| dictionary.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
data: A dictionary whose key/value are to be saved.
|
||||||
|
"""
|
||||||
|
for key, value in data.items():
|
||||||
|
self._Set(key, value)
|
||||||
|
|
||||||
|
def _Set(self, key, value):
|
||||||
|
"""Set the |value| for a |key| in the |_config| member.
|
||||||
|
|
||||||
|
|key| is prepended with the value of SYNC_STATE_PREFIX constant.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
key: Name of the key.
|
||||||
|
value: |value| could be of any type. If it is 'bool', it will be saved
|
||||||
|
as a Boolean and for all other types, it will be saved as a String.
|
||||||
|
"""
|
||||||
|
if value is None:
|
||||||
|
return
|
||||||
|
sync_key = f'{SYNC_STATE_PREFIX}{key}'
|
||||||
|
sync_key = sync_key.replace('_', '')
|
||||||
|
if isinstance(value, str):
|
||||||
|
self._config.SetString(sync_key, value)
|
||||||
|
elif isinstance(value, bool):
|
||||||
|
self._config.SetBoolean(sync_key, value)
|
||||||
|
else:
|
||||||
|
self._config.SetString(sync_key, str(value))
|
||||||
|
@ -19,20 +19,52 @@ https://en.wikibooks.org/wiki/Git/Submodules_and_Superprojects
|
|||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
superproject = Superproject()
|
superproject = Superproject()
|
||||||
project_commit_ids = superproject.UpdateProjectsRevisionId(projects)
|
UpdateProjectsResult = superproject.UpdateProjectsRevisionId(projects)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import hashlib
|
import hashlib
|
||||||
|
import functools
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import time
|
||||||
|
from typing import NamedTuple
|
||||||
|
|
||||||
from git_command import GitCommand
|
from git_command import git_require, GitCommand
|
||||||
|
from git_config import RepoConfig
|
||||||
from git_refs import R_HEADS
|
from git_refs import R_HEADS
|
||||||
|
from manifest_xml import LOCAL_MANIFEST_GROUP_PREFIX
|
||||||
|
|
||||||
_SUPERPROJECT_GIT_NAME = 'superproject.git'
|
_SUPERPROJECT_GIT_NAME = 'superproject.git'
|
||||||
_SUPERPROJECT_MANIFEST_NAME = 'superproject_override.xml'
|
_SUPERPROJECT_MANIFEST_NAME = 'superproject_override.xml'
|
||||||
|
|
||||||
|
|
||||||
|
class SyncResult(NamedTuple):
|
||||||
|
"""Return the status of sync and whether caller should exit."""
|
||||||
|
|
||||||
|
# Whether the superproject sync was successful.
|
||||||
|
success: bool
|
||||||
|
# Whether the caller should exit.
|
||||||
|
fatal: bool
|
||||||
|
|
||||||
|
|
||||||
|
class CommitIdsResult(NamedTuple):
|
||||||
|
"""Return the commit ids and whether caller should exit."""
|
||||||
|
|
||||||
|
# A dictionary with the projects/commit ids on success, otherwise None.
|
||||||
|
commit_ids: dict
|
||||||
|
# Whether the caller should exit.
|
||||||
|
fatal: bool
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateProjectsResult(NamedTuple):
|
||||||
|
"""Return the overriding manifest file and whether caller should exit."""
|
||||||
|
|
||||||
|
# Path name of the overriding manfiest file if successful, otherwise None.
|
||||||
|
manifest_path: str
|
||||||
|
# Whether the caller should exit.
|
||||||
|
fatal: bool
|
||||||
|
|
||||||
|
|
||||||
class Superproject(object):
|
class Superproject(object):
|
||||||
"""Get commit ids from superproject.
|
"""Get commit ids from superproject.
|
||||||
|
|
||||||
@ -40,19 +72,21 @@ 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, git_event_log,
|
||||||
quiet=False):
|
superproject_dir='exp-superproject', quiet=False):
|
||||||
"""Initializes superproject.
|
"""Initializes superproject.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
manifest: A Manifest object that is to be written to a file.
|
manifest: A Manifest object that is to be written to a file.
|
||||||
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.
|
||||||
|
git_event_log: A git trace2 event log to log events.
|
||||||
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.
|
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._git_event_log = git_event_log
|
||||||
self._quiet = quiet
|
self._quiet = quiet
|
||||||
self._branch = self._GetBranch()
|
self._branch = self._GetBranch()
|
||||||
self._repodir = os.path.abspath(repodir)
|
self._repodir = os.path.abspath(repodir)
|
||||||
@ -72,6 +106,11 @@ class Superproject(object):
|
|||||||
"""Returns a dictionary of projects and their commit ids."""
|
"""Returns a dictionary of projects and their commit ids."""
|
||||||
return self._project_commit_ids
|
return self._project_commit_ids
|
||||||
|
|
||||||
|
@property
|
||||||
|
def manifest_path(self):
|
||||||
|
"""Returns the manifest path if the path exists or None."""
|
||||||
|
return self._manifest_path if os.path.exists(self._manifest_path) else None
|
||||||
|
|
||||||
def _GetBranch(self):
|
def _GetBranch(self):
|
||||||
"""Returns the branch name for getting the approved manifest."""
|
"""Returns the branch name for getting the approved manifest."""
|
||||||
p = self._manifest.manifestProject
|
p = self._manifest.manifestProject
|
||||||
@ -83,6 +122,11 @@ class Superproject(object):
|
|||||||
branch = branch[len(R_HEADS):]
|
branch = branch[len(R_HEADS):]
|
||||||
return branch
|
return branch
|
||||||
|
|
||||||
|
def _LogError(self, message):
|
||||||
|
"""Logs message to stderr and _git_event_log."""
|
||||||
|
print(message, file=sys.stderr)
|
||||||
|
self._git_event_log.ErrorEvent(message, '')
|
||||||
|
|
||||||
def _Init(self):
|
def _Init(self):
|
||||||
"""Sets up a local Git repository to get a copy of a superproject.
|
"""Sets up a local Git repository to get a copy of a superproject.
|
||||||
|
|
||||||
@ -102,8 +146,8 @@ class Superproject(object):
|
|||||||
capture_stderr=True)
|
capture_stderr=True)
|
||||||
retval = p.Wait()
|
retval = p.Wait()
|
||||||
if retval:
|
if retval:
|
||||||
print('repo: error: git init call failed with return code: %r, stderr: %r' %
|
self._LogError(f'repo: error: git init call failed, command: git {cmd}, '
|
||||||
(retval, p.stderr), file=sys.stderr)
|
f'return code: {retval}, stderr: {p.stderr}')
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@ -117,8 +161,10 @@ class Superproject(object):
|
|||||||
True if fetch is successful, or False.
|
True if fetch is successful, or False.
|
||||||
"""
|
"""
|
||||||
if not os.path.exists(self._work_git):
|
if not os.path.exists(self._work_git):
|
||||||
print('git fetch missing drectory: %s' % self._work_git,
|
self._LogError(f'git fetch missing directory: {self._work_git}')
|
||||||
file=sys.stderr)
|
return False
|
||||||
|
if not git_require((2, 28, 0)):
|
||||||
|
print('superproject requires a git version 2.28 or later', file=sys.stderr)
|
||||||
return False
|
return False
|
||||||
cmd = ['fetch', url, '--depth', '1', '--force', '--no-tags', '--filter', 'blob:none']
|
cmd = ['fetch', url, '--depth', '1', '--force', '--no-tags', '--filter', 'blob:none']
|
||||||
if self._branch:
|
if self._branch:
|
||||||
@ -130,8 +176,8 @@ class Superproject(object):
|
|||||||
capture_stderr=True)
|
capture_stderr=True)
|
||||||
retval = p.Wait()
|
retval = p.Wait()
|
||||||
if retval:
|
if retval:
|
||||||
print('repo: error: git fetch call failed with return code: %r, stderr: %r' %
|
self._LogError(f'repo: error: git fetch call failed, command: git {cmd}, '
|
||||||
(retval, p.stderr), file=sys.stderr)
|
f'return code: {retval}, stderr: {p.stderr}')
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@ -144,8 +190,7 @@ class Superproject(object):
|
|||||||
data: data returned from 'git ls-tree ...' instead of None.
|
data: data returned from 'git ls-tree ...' instead of None.
|
||||||
"""
|
"""
|
||||||
if not os.path.exists(self._work_git):
|
if not os.path.exists(self._work_git):
|
||||||
print('git ls-tree missing drectory: %s' % self._work_git,
|
self._LogError(f'git ls-tree missing directory: {self._work_git}')
|
||||||
file=sys.stderr)
|
|
||||||
return None
|
return None
|
||||||
data = None
|
data = None
|
||||||
branch = 'HEAD' if not self._branch else self._branch
|
branch = 'HEAD' if not self._branch else self._branch
|
||||||
@ -160,52 +205,54 @@ class Superproject(object):
|
|||||||
if retval == 0:
|
if retval == 0:
|
||||||
data = p.stdout
|
data = p.stdout
|
||||||
else:
|
else:
|
||||||
print('repo: error: git ls-tree call failed with return code: %r, stderr: %r' % (
|
self._LogError(f'repo: error: git ls-tree call failed, command: git {cmd}, '
|
||||||
retval, p.stderr), file=sys.stderr)
|
f'return code: {retval}, stderr: {p.stderr}')
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def Sync(self):
|
def Sync(self):
|
||||||
"""Gets a local copy of a superproject for the manifest.
|
"""Gets a local copy of a superproject for the manifest.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
True if sync of superproject is successful, or False.
|
SyncResult
|
||||||
"""
|
"""
|
||||||
print('WARNING: --use-superproject is experimental and not '
|
print('NOTICE: --use-superproject is in beta; report any issues to the '
|
||||||
'for general use', file=sys.stderr)
|
'address described in `repo version`', file=sys.stderr)
|
||||||
|
|
||||||
if not self._manifest.superproject:
|
if not self._manifest.superproject:
|
||||||
print('error: superproject tag is not defined in manifest',
|
self._LogError(f'repo error: superproject tag is not defined in manifest: '
|
||||||
file=sys.stderr)
|
f'{self._manifest.manifestFile}')
|
||||||
return False
|
return SyncResult(False, False)
|
||||||
|
|
||||||
|
should_exit = True
|
||||||
url = self._manifest.superproject['remote'].url
|
url = self._manifest.superproject['remote'].url
|
||||||
if not url:
|
if not url:
|
||||||
print('error: superproject URL is not defined in manifest',
|
self._LogError(f'repo error: superproject URL is not defined in manifest: '
|
||||||
file=sys.stderr)
|
f'{self._manifest.manifestFile}')
|
||||||
return False
|
return SyncResult(False, should_exit)
|
||||||
|
|
||||||
if not self._Init():
|
if not self._Init():
|
||||||
return False
|
return SyncResult(False, should_exit)
|
||||||
if not self._Fetch(url):
|
if not self._Fetch(url):
|
||||||
return False
|
return SyncResult(False, should_exit)
|
||||||
if not self._quiet:
|
if not self._quiet:
|
||||||
print('%s: Initial setup for superproject completed.' % self._work_git)
|
print('%s: Initial setup for superproject completed.' % self._work_git)
|
||||||
return True
|
return SyncResult(True, False)
|
||||||
|
|
||||||
def _GetAllProjectsCommitIds(self):
|
def _GetAllProjectsCommitIds(self):
|
||||||
"""Get commit ids for all projects from superproject and save them in _project_commit_ids.
|
"""Get commit ids for all projects from superproject and save them in _project_commit_ids.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
A dictionary with the projects/commit ids on success, otherwise None.
|
CommitIdsResult
|
||||||
"""
|
"""
|
||||||
if not self.Sync():
|
sync_result = self.Sync()
|
||||||
return None
|
if not sync_result.success:
|
||||||
|
return CommitIdsResult(None, sync_result.fatal)
|
||||||
|
|
||||||
data = self._LsTree()
|
data = self._LsTree()
|
||||||
if not data:
|
if not data:
|
||||||
print('error: git ls-tree failed to return data for superproject',
|
print('warning: git ls-tree failed to return data for superproject',
|
||||||
file=sys.stderr)
|
file=sys.stderr)
|
||||||
return None
|
return CommitIdsResult(None, True)
|
||||||
|
|
||||||
# Parse lines like the following to select lines starting with '160000' and
|
# Parse lines like the following to select lines starting with '160000' and
|
||||||
# build a dictionary with project path (last element) and its commit id (3rd element).
|
# build a dictionary with project path (last element) and its commit id (3rd element).
|
||||||
@ -221,7 +268,7 @@ class Superproject(object):
|
|||||||
commit_ids[ls_data[3]] = ls_data[2]
|
commit_ids[ls_data[3]] = ls_data[2]
|
||||||
|
|
||||||
self._project_commit_ids = commit_ids
|
self._project_commit_ids = commit_ids
|
||||||
return commit_ids
|
return CommitIdsResult(commit_ids, False)
|
||||||
|
|
||||||
def _WriteManfiestFile(self):
|
def _WriteManfiestFile(self):
|
||||||
"""Writes manifest to a file.
|
"""Writes manifest to a file.
|
||||||
@ -230,9 +277,7 @@ class Superproject(object):
|
|||||||
manifest_path: Path name of the file into which manifest is written instead of None.
|
manifest_path: Path name of the file into which manifest is written instead of None.
|
||||||
"""
|
"""
|
||||||
if not os.path.exists(self._superproject_path):
|
if not os.path.exists(self._superproject_path):
|
||||||
print('error: missing superproject directory %s' %
|
self._LogError(f'error: missing superproject directory: {self._superproject_path}')
|
||||||
self._superproject_path,
|
|
||||||
file=sys.stderr)
|
|
||||||
return None
|
return None
|
||||||
manifest_str = self._manifest.ToXml(groups=self._manifest.GetGroupsStr()).toxml()
|
manifest_str = self._manifest.ToXml(groups=self._manifest.GetGroupsStr()).toxml()
|
||||||
manifest_path = self._manifest_path
|
manifest_path = self._manifest_path
|
||||||
@ -240,12 +285,30 @@ class Superproject(object):
|
|||||||
with open(manifest_path, 'w', encoding='utf-8') as fp:
|
with open(manifest_path, 'w', encoding='utf-8') as fp:
|
||||||
fp.write(manifest_str)
|
fp.write(manifest_str)
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
print('error: cannot write manifest to %s:\n%s'
|
self._LogError(f'error: cannot write manifest to : {manifest_path} {e}')
|
||||||
% (manifest_path, e),
|
|
||||||
file=sys.stderr)
|
|
||||||
return None
|
return None
|
||||||
return manifest_path
|
return manifest_path
|
||||||
|
|
||||||
|
def _SkipUpdatingProjectRevisionId(self, project):
|
||||||
|
"""Checks if a project's revision id needs to be updated or not.
|
||||||
|
|
||||||
|
Revision id for projects from local manifest will not be updated.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
project: project whose revision id is being updated.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True if a project's revision id should not be updated, or False,
|
||||||
|
"""
|
||||||
|
path = project.relpath
|
||||||
|
if not path:
|
||||||
|
return True
|
||||||
|
# Skip the project with revisionId.
|
||||||
|
if project.revisionId:
|
||||||
|
return True
|
||||||
|
# Skip the project if it comes from the local manifest.
|
||||||
|
return any(s.startswith(LOCAL_MANIFEST_GROUP_PREFIX) for s in project.groups)
|
||||||
|
|
||||||
def UpdateProjectsRevisionId(self, projects):
|
def UpdateProjectsRevisionId(self, projects):
|
||||||
"""Update revisionId of every project in projects with the commit id.
|
"""Update revisionId of every project in projects with the commit id.
|
||||||
|
|
||||||
@ -253,37 +316,111 @@ class Superproject(object):
|
|||||||
projects: List of projects whose revisionId needs to be updated.
|
projects: List of projects whose revisionId needs to be updated.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
manifest_path: Path name of the overriding manfiest file instead of None.
|
UpdateProjectsResult
|
||||||
"""
|
"""
|
||||||
commit_ids = self._GetAllProjectsCommitIds()
|
commit_ids_result = self._GetAllProjectsCommitIds()
|
||||||
|
commit_ids = commit_ids_result.commit_ids
|
||||||
if not commit_ids:
|
if not commit_ids:
|
||||||
print('error: Cannot get project commit ids from manifest', file=sys.stderr)
|
print('warning: Cannot get project commit ids from manifest', file=sys.stderr)
|
||||||
return None
|
return UpdateProjectsResult(None, commit_ids_result.fatal)
|
||||||
|
|
||||||
projects_missing_commit_ids = []
|
projects_missing_commit_ids = []
|
||||||
superproject_fetchUrl = self._manifest.superproject['remote'].fetchUrl
|
|
||||||
for project in projects:
|
for project in projects:
|
||||||
|
if self._SkipUpdatingProjectRevisionId(project):
|
||||||
|
continue
|
||||||
path = project.relpath
|
path = project.relpath
|
||||||
if not path:
|
|
||||||
continue
|
|
||||||
# Some manifests that pull projects from the "chromium" GoB
|
|
||||||
# (remote="chromium"), and have a private manifest that pulls projects
|
|
||||||
# from both the chromium GoB and "chrome-internal" GoB (remote="chrome").
|
|
||||||
# For such projects, one of the remotes will be different from
|
|
||||||
# superproject's remote. Until superproject, supports multiple remotes,
|
|
||||||
# don't update the commit ids of remotes that don't match superproject's
|
|
||||||
# remote.
|
|
||||||
if project.remote.fetchUrl != superproject_fetchUrl:
|
|
||||||
continue
|
|
||||||
commit_id = commit_ids.get(path)
|
commit_id = commit_ids.get(path)
|
||||||
if commit_id:
|
if not commit_id:
|
||||||
project.SetRevisionId(commit_id)
|
|
||||||
else:
|
|
||||||
projects_missing_commit_ids.append(path)
|
projects_missing_commit_ids.append(path)
|
||||||
|
|
||||||
|
# If superproject doesn't have a commit id for a project, then report an
|
||||||
|
# error event and continue as if do not use superproject is specified.
|
||||||
if projects_missing_commit_ids:
|
if projects_missing_commit_ids:
|
||||||
print('error: please file a bug using %s to report missing commit_ids for: %s' %
|
self._LogError(f'error: please file a bug using {self._manifest.contactinfo.bugurl} '
|
||||||
(self._manifest.contactinfo.bugurl, projects_missing_commit_ids), file=sys.stderr)
|
f'to report missing commit_ids for: {projects_missing_commit_ids}')
|
||||||
return None
|
return UpdateProjectsResult(None, False)
|
||||||
|
|
||||||
|
for project in projects:
|
||||||
|
if not self._SkipUpdatingProjectRevisionId(project):
|
||||||
|
project.SetRevisionId(commit_ids.get(project.relpath))
|
||||||
|
|
||||||
manifest_path = self._WriteManfiestFile()
|
manifest_path = self._WriteManfiestFile()
|
||||||
return manifest_path
|
return UpdateProjectsResult(manifest_path, False)
|
||||||
|
|
||||||
|
|
||||||
|
@functools.lru_cache(maxsize=None)
|
||||||
|
def _UseSuperprojectFromConfiguration():
|
||||||
|
"""Returns the user choice of whether to use superproject."""
|
||||||
|
user_cfg = RepoConfig.ForUser()
|
||||||
|
system_cfg = RepoConfig.ForSystem()
|
||||||
|
time_now = int(time.time())
|
||||||
|
|
||||||
|
user_value = user_cfg.GetBoolean('repo.superprojectChoice')
|
||||||
|
if user_value is not None:
|
||||||
|
user_expiration = user_cfg.GetInt('repo.superprojectChoiceExpire')
|
||||||
|
if user_expiration is not None and (user_expiration <= 0 or user_expiration >= time_now):
|
||||||
|
# TODO(b/190688390) - Remove prompt when we are comfortable with the new
|
||||||
|
# default value.
|
||||||
|
print(('You are currently enrolled in Git submodules experiment '
|
||||||
|
'(go/android-submodules-quickstart). Use --no-use-superproject '
|
||||||
|
'to override.\n'), file=sys.stderr)
|
||||||
|
return user_value
|
||||||
|
|
||||||
|
# We don't have an unexpired choice, ask for one.
|
||||||
|
system_value = system_cfg.GetBoolean('repo.superprojectChoice')
|
||||||
|
if system_value:
|
||||||
|
# The system configuration is proposing that we should enable the
|
||||||
|
# use of superproject. Present this to user for confirmation if we
|
||||||
|
# are on a TTY, or, when we are not on a TTY, accept the system
|
||||||
|
# default for this time only.
|
||||||
|
#
|
||||||
|
# TODO(b/190688390) - Remove prompt when we are comfortable with the new
|
||||||
|
# default value.
|
||||||
|
prompt = ('Repo can now use Git submodules (go/android-submodules-quickstart) '
|
||||||
|
'instead of manifests to represent the state of the Android '
|
||||||
|
'superproject, which results in faster syncs and better atomicity.\n\n')
|
||||||
|
if sys.stdout.isatty():
|
||||||
|
prompt += 'Would you like to opt in for two weeks (y/N)? '
|
||||||
|
response = input(prompt).lower()
|
||||||
|
time_choiceexpire = time_now + (86400 * 14)
|
||||||
|
if response in ('y', 'yes'):
|
||||||
|
userchoice = True
|
||||||
|
elif response in ('a', 'always'):
|
||||||
|
userchoice = True
|
||||||
|
time_choiceexpire = 0
|
||||||
|
elif response == 'never':
|
||||||
|
userchoice = False
|
||||||
|
time_choiceexpire = 0
|
||||||
|
elif response in ('n', 'no'):
|
||||||
|
userchoice = False
|
||||||
|
else:
|
||||||
|
# Unrecognized user response, assume the intention was no, but
|
||||||
|
# only for 2 hours instead of 2 weeks to balance between not
|
||||||
|
# being overly pushy while still retain the opportunity to
|
||||||
|
# enroll.
|
||||||
|
userchoice = False
|
||||||
|
time_choiceexpire = time_now + 7200
|
||||||
|
|
||||||
|
user_cfg.SetString('repo.superprojectChoiceExpire', str(time_choiceexpire))
|
||||||
|
user_cfg.SetBoolean('repo.superprojectChoice', userchoice)
|
||||||
|
|
||||||
|
return userchoice
|
||||||
|
else:
|
||||||
|
print('Accepting once since we are not on a TTY', file=sys.stderr)
|
||||||
|
return True
|
||||||
|
|
||||||
|
# For all other cases, we would not use superproject by default.
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def UseSuperproject(opt, manifest):
|
||||||
|
"""Returns a boolean if use-superproject option is enabled."""
|
||||||
|
|
||||||
|
if opt.use_superproject is not None:
|
||||||
|
return opt.use_superproject
|
||||||
|
else:
|
||||||
|
client_value = manifest.manifestProject.config.GetBoolean('repo.superproject')
|
||||||
|
if client_value is not None:
|
||||||
|
return client_value
|
||||||
|
else:
|
||||||
|
return _UseSuperprojectFromConfiguration()
|
||||||
|
@ -144,6 +144,19 @@ class EventLog(object):
|
|||||||
command_event['subcommands'] = subcommands
|
command_event['subcommands'] = subcommands
|
||||||
self._log.append(command_event)
|
self._log.append(command_event)
|
||||||
|
|
||||||
|
def LogConfigEvents(self, config, event_dict_name):
|
||||||
|
"""Append a |event_dict_name| event for each config key in |config|.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
config: Configuration dictionary.
|
||||||
|
event_dict_name: Name of the event dictionary for items to be logged under.
|
||||||
|
"""
|
||||||
|
for param, value in config.items():
|
||||||
|
event = self._CreateEventDict(event_dict_name)
|
||||||
|
event['param'] = param
|
||||||
|
event['value'] = value
|
||||||
|
self._log.append(event)
|
||||||
|
|
||||||
def DefParamRepoEvents(self, config):
|
def DefParamRepoEvents(self, config):
|
||||||
"""Append a 'def_param' event for each repo.* config key to the current log.
|
"""Append a 'def_param' event for each repo.* config key to the current log.
|
||||||
|
|
||||||
@ -152,12 +165,14 @@ class EventLog(object):
|
|||||||
"""
|
"""
|
||||||
# Only output the repo.* config parameters.
|
# Only output the repo.* config parameters.
|
||||||
repo_config = {k: v for k, v in config.items() if k.startswith('repo.')}
|
repo_config = {k: v for k, v in config.items() if k.startswith('repo.')}
|
||||||
|
self.LogConfigEvents(repo_config, 'def_param')
|
||||||
|
|
||||||
for param, value in repo_config.items():
|
def ErrorEvent(self, msg, fmt):
|
||||||
def_param_event = self._CreateEventDict('def_param')
|
"""Append a 'error' event to the current log."""
|
||||||
def_param_event['param'] = param
|
error_event = self._CreateEventDict('error')
|
||||||
def_param_event['value'] = value
|
error_event['msg'] = msg
|
||||||
self._log.append(def_param_event)
|
error_event['fmt'] = fmt
|
||||||
|
self._log.append(error_event)
|
||||||
|
|
||||||
def _GetEventTargetPath(self):
|
def _GetEventTargetPath(self):
|
||||||
"""Get the 'trace2.eventtarget' path from git configuration.
|
"""Get the 'trace2.eventtarget' path from git configuration.
|
||||||
|
100
main.py
100
main.py
@ -71,7 +71,7 @@ from subcmds import all_commands
|
|||||||
#
|
#
|
||||||
# python-3.6 is in Ubuntu Bionic.
|
# python-3.6 is in Ubuntu Bionic.
|
||||||
MIN_PYTHON_VERSION_SOFT = (3, 6)
|
MIN_PYTHON_VERSION_SOFT = (3, 6)
|
||||||
MIN_PYTHON_VERSION_HARD = (3, 5)
|
MIN_PYTHON_VERSION_HARD = (3, 6)
|
||||||
|
|
||||||
if sys.version_info.major < 3:
|
if sys.version_info.major < 3:
|
||||||
print('repo: error: Python 2 is no longer supported; '
|
print('repo: error: Python 2 is no longer supported; '
|
||||||
@ -95,6 +95,8 @@ global_options = optparse.OptionParser(
|
|||||||
add_help_option=False)
|
add_help_option=False)
|
||||||
global_options.add_option('-h', '--help', action='store_true',
|
global_options.add_option('-h', '--help', action='store_true',
|
||||||
help='show this help message and exit')
|
help='show this help message and exit')
|
||||||
|
global_options.add_option('--help-all', action='store_true',
|
||||||
|
help='show this help message with all subcommands and exit')
|
||||||
global_options.add_option('-p', '--paginate',
|
global_options.add_option('-p', '--paginate',
|
||||||
dest='pager', action='store_true',
|
dest='pager', action='store_true',
|
||||||
help='display command output in the pager')
|
help='display command output in the pager')
|
||||||
@ -116,6 +118,10 @@ global_options.add_option('--time',
|
|||||||
global_options.add_option('--version',
|
global_options.add_option('--version',
|
||||||
dest='show_version', action='store_true',
|
dest='show_version', action='store_true',
|
||||||
help='display this version of repo')
|
help='display this version of repo')
|
||||||
|
global_options.add_option('--show-toplevel',
|
||||||
|
action='store_true',
|
||||||
|
help='display the path of the top-level directory of '
|
||||||
|
'the repo client checkout')
|
||||||
global_options.add_option('--event-log',
|
global_options.add_option('--event-log',
|
||||||
dest='event_log', action='store',
|
dest='event_log', action='store',
|
||||||
help='filename of event log to append timeline to')
|
help='filename of event log to append timeline to')
|
||||||
@ -128,34 +134,40 @@ class _Repo(object):
|
|||||||
self.repodir = repodir
|
self.repodir = repodir
|
||||||
self.commands = all_commands
|
self.commands = all_commands
|
||||||
|
|
||||||
|
def _PrintHelp(self, short: bool = False, all_commands: bool = False):
|
||||||
|
"""Show --help screen."""
|
||||||
|
global_options.print_help()
|
||||||
|
print()
|
||||||
|
if short:
|
||||||
|
commands = ' '.join(sorted(self.commands))
|
||||||
|
wrapped_commands = textwrap.wrap(commands, width=77)
|
||||||
|
print('Available commands:\n %s' % ('\n '.join(wrapped_commands),))
|
||||||
|
print('\nRun `repo help <command>` for command-specific details.')
|
||||||
|
print('Bug reports:', Wrapper().BUG_URL)
|
||||||
|
else:
|
||||||
|
cmd = self.commands['help']()
|
||||||
|
if all_commands:
|
||||||
|
cmd.PrintAllCommandsBody()
|
||||||
|
else:
|
||||||
|
cmd.PrintCommonCommandsBody()
|
||||||
|
|
||||||
def _ParseArgs(self, argv):
|
def _ParseArgs(self, argv):
|
||||||
"""Parse the main `repo` command line options."""
|
"""Parse the main `repo` command line options."""
|
||||||
name = None
|
for i, arg in enumerate(argv):
|
||||||
glob = []
|
if not arg.startswith('-'):
|
||||||
|
name = arg
|
||||||
for i in range(len(argv)):
|
glob = argv[:i]
|
||||||
if not argv[i].startswith('-'):
|
|
||||||
name = argv[i]
|
|
||||||
if i > 0:
|
|
||||||
glob = argv[:i]
|
|
||||||
argv = argv[i + 1:]
|
argv = argv[i + 1:]
|
||||||
break
|
break
|
||||||
if not name:
|
else:
|
||||||
|
name = None
|
||||||
glob = argv
|
glob = argv
|
||||||
name = 'help'
|
|
||||||
argv = []
|
argv = []
|
||||||
gopts, _gargs = global_options.parse_args(glob)
|
gopts, _gargs = global_options.parse_args(glob)
|
||||||
|
|
||||||
name, alias_args = self._ExpandAlias(name)
|
if name:
|
||||||
argv = alias_args + argv
|
name, alias_args = self._ExpandAlias(name)
|
||||||
|
argv = alias_args + argv
|
||||||
if gopts.help:
|
|
||||||
global_options.print_help()
|
|
||||||
commands = ' '.join(sorted(self.commands))
|
|
||||||
wrapped_commands = textwrap.wrap(commands, width=77)
|
|
||||||
print('\nAvailable commands:\n %s' % ('\n '.join(wrapped_commands),))
|
|
||||||
print('\nRun `repo help <command>` for command-specific details.')
|
|
||||||
global_options.exit()
|
|
||||||
|
|
||||||
return (name, gopts, argv)
|
return (name, gopts, argv)
|
||||||
|
|
||||||
@ -186,32 +198,44 @@ class _Repo(object):
|
|||||||
|
|
||||||
if gopts.trace:
|
if gopts.trace:
|
||||||
SetTrace()
|
SetTrace()
|
||||||
if gopts.show_version:
|
|
||||||
if name == 'help':
|
# Handle options that terminate quickly first.
|
||||||
name = 'version'
|
if gopts.help or gopts.help_all:
|
||||||
else:
|
self._PrintHelp(short=False, all_commands=gopts.help_all)
|
||||||
print('fatal: invalid usage of --version', file=sys.stderr)
|
return 0
|
||||||
return 1
|
elif gopts.show_version:
|
||||||
|
# Always allow global --version regardless of subcommand validity.
|
||||||
|
name = 'version'
|
||||||
|
elif gopts.show_toplevel:
|
||||||
|
print(os.path.dirname(self.repodir))
|
||||||
|
return 0
|
||||||
|
elif not name:
|
||||||
|
# No subcommand specified, so show the help/subcommand.
|
||||||
|
self._PrintHelp(short=True)
|
||||||
|
return 1
|
||||||
|
|
||||||
SetDefaultColoring(gopts.color)
|
SetDefaultColoring(gopts.color)
|
||||||
|
|
||||||
|
git_trace2_event_log = EventLog()
|
||||||
|
repo_client = RepoClient(self.repodir)
|
||||||
|
gitc_manifest = None
|
||||||
|
gitc_client_name = gitc_utils.parse_clientdir(os.getcwd())
|
||||||
|
if gitc_client_name:
|
||||||
|
gitc_manifest = GitcClient(self.repodir, gitc_client_name)
|
||||||
|
repo_client.isGitcClient = True
|
||||||
|
|
||||||
try:
|
try:
|
||||||
cmd = self.commands[name]()
|
cmd = self.commands[name](
|
||||||
|
repodir=self.repodir,
|
||||||
|
client=repo_client,
|
||||||
|
manifest=repo_client.manifest,
|
||||||
|
gitc_manifest=gitc_manifest,
|
||||||
|
git_event_log=git_trace2_event_log)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
print("repo: '%s' is not a repo command. See 'repo help'." % name,
|
print("repo: '%s' is not a repo command. See 'repo help'." % name,
|
||||||
file=sys.stderr)
|
file=sys.stderr)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
git_trace2_event_log = EventLog()
|
|
||||||
cmd.repodir = self.repodir
|
|
||||||
cmd.client = RepoClient(cmd.repodir)
|
|
||||||
cmd.manifest = cmd.client.manifest
|
|
||||||
cmd.gitc_manifest = None
|
|
||||||
gitc_client_name = gitc_utils.parse_clientdir(os.getcwd())
|
|
||||||
if gitc_client_name:
|
|
||||||
cmd.gitc_manifest = GitcClient(cmd.repodir, gitc_client_name)
|
|
||||||
cmd.client.isGitcClient = True
|
|
||||||
|
|
||||||
Editor.globalConfig = cmd.client.globalConfig
|
Editor.globalConfig = cmd.client.globalConfig
|
||||||
|
|
||||||
if not isinstance(cmd, MirrorSafeCommand) and cmd.manifest.IsMirror:
|
if not isinstance(cmd, MirrorSafeCommand) and cmd.manifest.IsMirror:
|
||||||
|
35
man/repo-abandon.1
Normal file
35
man/repo-abandon.1
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man.
|
||||||
|
.TH REPO "1" "July 2021" "repo abandon" "Repo Manual"
|
||||||
|
.SH NAME
|
||||||
|
repo \- repo abandon - manual page for repo abandon
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B repo
|
||||||
|
\fI\,abandon \/\fR[\fI\,--all | <branchname>\/\fR] [\fI\,<project>\/\fR...]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
Summary
|
||||||
|
.PP
|
||||||
|
Permanently abandon a development branch
|
||||||
|
.PP
|
||||||
|
This subcommand permanently abandons a development branch by
|
||||||
|
deleting it (and all its history) from your local repository.
|
||||||
|
.PP
|
||||||
|
It is equivalent to "git branch \fB\-D\fR <branchname>".
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
\fB\-h\fR, \fB\-\-help\fR
|
||||||
|
show this help message and exit
|
||||||
|
.TP
|
||||||
|
\fB\-j\fR JOBS, \fB\-\-jobs\fR=\fI\,JOBS\/\fR
|
||||||
|
number of jobs to run in parallel (default: 4)
|
||||||
|
.TP
|
||||||
|
\fB\-\-all\fR
|
||||||
|
delete all branches in all projects
|
||||||
|
.SS Logging options:
|
||||||
|
.TP
|
||||||
|
\fB\-v\fR, \fB\-\-verbose\fR
|
||||||
|
show all output
|
||||||
|
.TP
|
||||||
|
\fB\-q\fR, \fB\-\-quiet\fR
|
||||||
|
only show errors
|
||||||
|
.PP
|
||||||
|
Run `repo help abandon` to view the detailed manual.
|
1
man/repo-branch.1
Normal file
1
man/repo-branch.1
Normal file
@ -0,0 +1 @@
|
|||||||
|
.so man1/repo-branches.1
|
58
man/repo-branches.1
Normal file
58
man/repo-branches.1
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man.
|
||||||
|
.TH REPO "1" "July 2021" "repo branches" "Repo Manual"
|
||||||
|
.SH NAME
|
||||||
|
repo \- repo branches - manual page for repo branches
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B repo
|
||||||
|
\fI\,branches \/\fR[\fI\,<project>\/\fR...]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
Summary
|
||||||
|
.PP
|
||||||
|
View current topic branches
|
||||||
|
.PP
|
||||||
|
Summarizes the currently available topic branches.
|
||||||
|
.PP
|
||||||
|
# Branch Display
|
||||||
|
.PP
|
||||||
|
The branch display output by this command is organized into four
|
||||||
|
columns of information; for example:
|
||||||
|
.TP
|
||||||
|
*P nocolor
|
||||||
|
| in repo
|
||||||
|
.TP
|
||||||
|
repo2
|
||||||
|
|
|
||||||
|
.PP
|
||||||
|
The first column contains a * if the branch is the currently
|
||||||
|
checked out branch in any of the specified projects, or a blank
|
||||||
|
if no project has the branch checked out.
|
||||||
|
.PP
|
||||||
|
The second column contains either blank, p or P, depending upon
|
||||||
|
the upload status of the branch.
|
||||||
|
.IP
|
||||||
|
(blank): branch not yet published by repo upload
|
||||||
|
.IP
|
||||||
|
P: all commits were published by repo upload
|
||||||
|
p: only some commits were published by repo upload
|
||||||
|
.PP
|
||||||
|
The third column contains the branch name.
|
||||||
|
.PP
|
||||||
|
The fourth column (after the | separator) lists the projects that
|
||||||
|
the branch appears in, or does not appear in. If no project list
|
||||||
|
is shown, then the branch appears in all projects.
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
\fB\-h\fR, \fB\-\-help\fR
|
||||||
|
show this help message and exit
|
||||||
|
.TP
|
||||||
|
\fB\-j\fR JOBS, \fB\-\-jobs\fR=\fI\,JOBS\/\fR
|
||||||
|
number of jobs to run in parallel (default: 4)
|
||||||
|
.SS Logging options:
|
||||||
|
.TP
|
||||||
|
\fB\-v\fR, \fB\-\-verbose\fR
|
||||||
|
show all output
|
||||||
|
.TP
|
||||||
|
\fB\-q\fR, \fB\-\-quiet\fR
|
||||||
|
only show errors
|
||||||
|
.PP
|
||||||
|
Run `repo help branches` to view the detailed manual.
|
35
man/repo-checkout.1
Normal file
35
man/repo-checkout.1
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man.
|
||||||
|
.TH REPO "1" "July 2021" "repo checkout" "Repo Manual"
|
||||||
|
.SH NAME
|
||||||
|
repo \- repo checkout - manual page for repo checkout
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B repo
|
||||||
|
\fI\,checkout <branchname> \/\fR[\fI\,<project>\/\fR...]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
Summary
|
||||||
|
.PP
|
||||||
|
Checkout a branch for development
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
\fB\-h\fR, \fB\-\-help\fR
|
||||||
|
show this help message and exit
|
||||||
|
.TP
|
||||||
|
\fB\-j\fR JOBS, \fB\-\-jobs\fR=\fI\,JOBS\/\fR
|
||||||
|
number of jobs to run in parallel (default: 4)
|
||||||
|
.SS Logging options:
|
||||||
|
.TP
|
||||||
|
\fB\-v\fR, \fB\-\-verbose\fR
|
||||||
|
show all output
|
||||||
|
.TP
|
||||||
|
\fB\-q\fR, \fB\-\-quiet\fR
|
||||||
|
only show errors
|
||||||
|
.PP
|
||||||
|
Run `repo help checkout` to view the detailed manual.
|
||||||
|
.SH DETAILS
|
||||||
|
.PP
|
||||||
|
The 'repo checkout' command checks out an existing branch that was previously
|
||||||
|
created by 'repo start'.
|
||||||
|
.PP
|
||||||
|
The command is equivalent to:
|
||||||
|
.IP
|
||||||
|
repo forall [<project>...] \fB\-c\fR git checkout <branchname>
|
28
man/repo-cherry-pick.1
Normal file
28
man/repo-cherry-pick.1
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man.
|
||||||
|
.TH REPO "1" "July 2021" "repo cherry-pick" "Repo Manual"
|
||||||
|
.SH NAME
|
||||||
|
repo \- repo cherry-pick - manual page for repo cherry-pick
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B repo
|
||||||
|
\fI\,cherry-pick <sha1>\/\fR
|
||||||
|
.SH DESCRIPTION
|
||||||
|
Summary
|
||||||
|
.PP
|
||||||
|
Cherry\-pick a change.
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
\fB\-h\fR, \fB\-\-help\fR
|
||||||
|
show this help message and exit
|
||||||
|
.SS Logging options:
|
||||||
|
.TP
|
||||||
|
\fB\-v\fR, \fB\-\-verbose\fR
|
||||||
|
show all output
|
||||||
|
.TP
|
||||||
|
\fB\-q\fR, \fB\-\-quiet\fR
|
||||||
|
only show errors
|
||||||
|
.PP
|
||||||
|
Run `repo help cherry\-pick` to view the detailed manual.
|
||||||
|
.SH DETAILS
|
||||||
|
.PP
|
||||||
|
\&'repo cherry\-pick' cherry\-picks a change from one branch to another. The change
|
||||||
|
id will be updated, and a reference to the old change id will be added.
|
34
man/repo-diff.1
Normal file
34
man/repo-diff.1
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man.
|
||||||
|
.TH REPO "1" "July 2021" "repo diff" "Repo Manual"
|
||||||
|
.SH NAME
|
||||||
|
repo \- repo diff - manual page for repo diff
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B repo
|
||||||
|
\fI\,diff \/\fR[\fI\,<project>\/\fR...]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
Summary
|
||||||
|
.PP
|
||||||
|
Show changes between commit and working tree
|
||||||
|
.PP
|
||||||
|
The \fB\-u\fR option causes 'repo diff' to generate diff output with file paths
|
||||||
|
relative to the repository root, so the output can be applied
|
||||||
|
to the Unix 'patch' command.
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
\fB\-h\fR, \fB\-\-help\fR
|
||||||
|
show this help message and exit
|
||||||
|
.TP
|
||||||
|
\fB\-j\fR JOBS, \fB\-\-jobs\fR=\fI\,JOBS\/\fR
|
||||||
|
number of jobs to run in parallel (default: 4)
|
||||||
|
.TP
|
||||||
|
\fB\-u\fR, \fB\-\-absolute\fR
|
||||||
|
paths are relative to the repository root
|
||||||
|
.SS Logging options:
|
||||||
|
.TP
|
||||||
|
\fB\-v\fR, \fB\-\-verbose\fR
|
||||||
|
show all output
|
||||||
|
.TP
|
||||||
|
\fB\-q\fR, \fB\-\-quiet\fR
|
||||||
|
only show errors
|
||||||
|
.PP
|
||||||
|
Run `repo help diff` to view the detailed manual.
|
61
man/repo-diffmanifests.1
Normal file
61
man/repo-diffmanifests.1
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man.
|
||||||
|
.TH REPO "1" "July 2021" "repo diffmanifests" "Repo Manual"
|
||||||
|
.SH NAME
|
||||||
|
repo \- repo diffmanifests - manual page for repo diffmanifests
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B repo
|
||||||
|
\fI\,diffmanifests manifest1.xml \/\fR[\fI\,manifest2.xml\/\fR] [\fI\,options\/\fR]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
Summary
|
||||||
|
.PP
|
||||||
|
Manifest diff utility
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
\fB\-h\fR, \fB\-\-help\fR
|
||||||
|
show this help message and exit
|
||||||
|
.TP
|
||||||
|
\fB\-\-raw\fR
|
||||||
|
display raw diff
|
||||||
|
.TP
|
||||||
|
\fB\-\-no\-color\fR
|
||||||
|
does not display the diff in color
|
||||||
|
.TP
|
||||||
|
\fB\-\-pretty\-format=\fR<FORMAT>
|
||||||
|
print the log using a custom git pretty format string
|
||||||
|
.SS Logging options:
|
||||||
|
.TP
|
||||||
|
\fB\-v\fR, \fB\-\-verbose\fR
|
||||||
|
show all output
|
||||||
|
.TP
|
||||||
|
\fB\-q\fR, \fB\-\-quiet\fR
|
||||||
|
only show errors
|
||||||
|
.PP
|
||||||
|
Run `repo help diffmanifests` to view the detailed manual.
|
||||||
|
.SH DETAILS
|
||||||
|
.PP
|
||||||
|
The repo diffmanifests command shows differences between project revisions of
|
||||||
|
manifest1 and manifest2. if manifest2 is not specified, current manifest.xml
|
||||||
|
will be used instead. Both absolute and relative paths may be used for
|
||||||
|
manifests. Relative paths start from project's ".repo/manifests" folder.
|
||||||
|
.PP
|
||||||
|
The \fB\-\-raw\fR option Displays the diff in a way that facilitates parsing, the
|
||||||
|
project pattern will be <status> <path> <revision from> [<revision to>] and the
|
||||||
|
commit pattern will be <status> <onelined log> with status values respectively :
|
||||||
|
.IP
|
||||||
|
A = Added project
|
||||||
|
R = Removed project
|
||||||
|
C = Changed project
|
||||||
|
U = Project with unreachable revision(s) (revision(s) not found)
|
||||||
|
.PP
|
||||||
|
for project, and
|
||||||
|
.IP
|
||||||
|
A = Added commit
|
||||||
|
R = Removed commit
|
||||||
|
.PP
|
||||||
|
for a commit.
|
||||||
|
.PP
|
||||||
|
Only changed projects may contain commits, and commit status always starts with
|
||||||
|
a space, and are part of last printed project. Unreachable revisions may occur
|
||||||
|
if project is not up to date or if repo has not been initialized with all the
|
||||||
|
groups, in which case some projects won't be synced and their revisions won't be
|
||||||
|
found.
|
44
man/repo-download.1
Normal file
44
man/repo-download.1
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man.
|
||||||
|
.TH REPO "1" "July 2021" "repo download" "Repo Manual"
|
||||||
|
.SH NAME
|
||||||
|
repo \- repo download - manual page for repo download
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B repo
|
||||||
|
\fI\,download {\/\fR[\fI\,project\/\fR] \fI\,change\/\fR[\fI\,/patchset\/\fR]\fI\,}\/\fR...
|
||||||
|
.SH DESCRIPTION
|
||||||
|
Summary
|
||||||
|
.PP
|
||||||
|
Download and checkout a change
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
\fB\-h\fR, \fB\-\-help\fR
|
||||||
|
show this help message and exit
|
||||||
|
.TP
|
||||||
|
\fB\-b\fR BRANCH, \fB\-\-branch\fR=\fI\,BRANCH\/\fR
|
||||||
|
create a new branch first
|
||||||
|
.TP
|
||||||
|
\fB\-c\fR, \fB\-\-cherry\-pick\fR
|
||||||
|
cherry\-pick instead of checkout
|
||||||
|
.TP
|
||||||
|
\fB\-x\fR, \fB\-\-record\-origin\fR
|
||||||
|
pass \fB\-x\fR when cherry\-picking
|
||||||
|
.TP
|
||||||
|
\fB\-r\fR, \fB\-\-revert\fR
|
||||||
|
revert instead of checkout
|
||||||
|
.TP
|
||||||
|
\fB\-f\fR, \fB\-\-ff\-only\fR
|
||||||
|
force fast\-forward merge
|
||||||
|
.SS Logging options:
|
||||||
|
.TP
|
||||||
|
\fB\-v\fR, \fB\-\-verbose\fR
|
||||||
|
show all output
|
||||||
|
.TP
|
||||||
|
\fB\-q\fR, \fB\-\-quiet\fR
|
||||||
|
only show errors
|
||||||
|
.PP
|
||||||
|
Run `repo help download` to view the detailed manual.
|
||||||
|
.SH DETAILS
|
||||||
|
.PP
|
||||||
|
The 'repo download' command downloads a change from the review system and makes
|
||||||
|
it available in your project's local working directory. If no project is
|
||||||
|
specified try to use current directory as a project.
|
127
man/repo-forall.1
Normal file
127
man/repo-forall.1
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man.
|
||||||
|
.TH REPO "1" "July 2021" "repo forall" "Repo Manual"
|
||||||
|
.SH NAME
|
||||||
|
repo \- repo forall - manual page for repo forall
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B repo
|
||||||
|
\fI\,forall \/\fR[\fI\,<project>\/\fR...] \fI\,-c <command> \/\fR[\fI\,<arg>\/\fR...]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
Summary
|
||||||
|
.PP
|
||||||
|
Run a shell command in each project
|
||||||
|
.PP
|
||||||
|
repo forall \fB\-r\fR str1 [str2] ... \fB\-c\fR <command> [<arg>...]
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
\fB\-h\fR, \fB\-\-help\fR
|
||||||
|
show this help message and exit
|
||||||
|
.TP
|
||||||
|
\fB\-j\fR JOBS, \fB\-\-jobs\fR=\fI\,JOBS\/\fR
|
||||||
|
number of jobs to run in parallel (default: 4)
|
||||||
|
.TP
|
||||||
|
\fB\-r\fR, \fB\-\-regex\fR
|
||||||
|
execute the command only on projects matching regex or
|
||||||
|
wildcard expression
|
||||||
|
.TP
|
||||||
|
\fB\-i\fR, \fB\-\-inverse\-regex\fR
|
||||||
|
execute the command only on projects not matching
|
||||||
|
regex or wildcard expression
|
||||||
|
.TP
|
||||||
|
\fB\-g\fR GROUPS, \fB\-\-groups\fR=\fI\,GROUPS\/\fR
|
||||||
|
execute the command only on projects matching the
|
||||||
|
specified groups
|
||||||
|
.TP
|
||||||
|
\fB\-c\fR, \fB\-\-command\fR
|
||||||
|
command (and arguments) to execute
|
||||||
|
.TP
|
||||||
|
\fB\-e\fR, \fB\-\-abort\-on\-errors\fR
|
||||||
|
abort if a command exits unsuccessfully
|
||||||
|
.TP
|
||||||
|
\fB\-\-ignore\-missing\fR
|
||||||
|
silently skip & do not exit non\-zero due missing
|
||||||
|
checkouts
|
||||||
|
.TP
|
||||||
|
\fB\-\-interactive\fR
|
||||||
|
force interactive usage
|
||||||
|
.SS Logging options:
|
||||||
|
.TP
|
||||||
|
\fB\-v\fR, \fB\-\-verbose\fR
|
||||||
|
show all output
|
||||||
|
.TP
|
||||||
|
\fB\-q\fR, \fB\-\-quiet\fR
|
||||||
|
only show errors
|
||||||
|
.TP
|
||||||
|
\fB\-p\fR
|
||||||
|
show project headers before output
|
||||||
|
.PP
|
||||||
|
Run `repo help forall` to view the detailed manual.
|
||||||
|
.SH DETAILS
|
||||||
|
.PP
|
||||||
|
Executes the same shell command in each project.
|
||||||
|
.PP
|
||||||
|
The \fB\-r\fR option allows running the command only on projects matching regex or
|
||||||
|
wildcard expression.
|
||||||
|
.PP
|
||||||
|
By default, projects are processed non\-interactively in parallel. If you want to
|
||||||
|
run interactive commands, make sure to pass \fB\-\-interactive\fR to force \fB\-\-jobs\fR 1.
|
||||||
|
While the processing order of projects is not guaranteed, the order of project
|
||||||
|
output is stable.
|
||||||
|
.PP
|
||||||
|
Output Formatting
|
||||||
|
.PP
|
||||||
|
The \fB\-p\fR option causes 'repo forall' to bind pipes to the command's stdin, stdout
|
||||||
|
and stderr streams, and pipe all output into a continuous stream that is
|
||||||
|
displayed in a single pager session. Project headings are inserted before the
|
||||||
|
output of each command is displayed. If the command produces no output in a
|
||||||
|
project, no heading is displayed.
|
||||||
|
.PP
|
||||||
|
The formatting convention used by \fB\-p\fR is very suitable for some types of
|
||||||
|
searching, e.g. `repo forall \fB\-p\fR \fB\-c\fR git log \fB\-SFoo\fR` will print all commits that
|
||||||
|
add or remove references to Foo.
|
||||||
|
.PP
|
||||||
|
The \fB\-v\fR option causes 'repo forall' to display stderr messages if a command
|
||||||
|
produces output only on stderr. Normally the \fB\-p\fR option causes command output to
|
||||||
|
be suppressed until the command produces at least one byte of output on stdout.
|
||||||
|
.PP
|
||||||
|
Environment
|
||||||
|
.PP
|
||||||
|
pwd is the project's working directory. If the current client is a mirror
|
||||||
|
client, then pwd is the Git repository.
|
||||||
|
.PP
|
||||||
|
REPO_PROJECT is set to the unique name of the project.
|
||||||
|
.PP
|
||||||
|
REPO_PATH is the path relative the the root of the client.
|
||||||
|
.PP
|
||||||
|
REPO_REMOTE is the name of the remote system from the manifest.
|
||||||
|
.PP
|
||||||
|
REPO_LREV is the name of the revision from the manifest, translated to a local
|
||||||
|
tracking branch. If you need to pass the manifest revision to a locally executed
|
||||||
|
git command, use REPO_LREV.
|
||||||
|
.PP
|
||||||
|
REPO_RREV is the name of the revision from the manifest, exactly as written in
|
||||||
|
the manifest.
|
||||||
|
.PP
|
||||||
|
REPO_COUNT is the total number of projects being iterated.
|
||||||
|
.PP
|
||||||
|
REPO_I is the current (1\-based) iteration count. Can be used in conjunction with
|
||||||
|
REPO_COUNT to add a simple progress indicator to your command.
|
||||||
|
.PP
|
||||||
|
REPO__* are any extra environment variables, specified by the "annotation"
|
||||||
|
element under any project element. This can be useful for differentiating trees
|
||||||
|
based on user\-specific criteria, or simply annotating tree details.
|
||||||
|
.PP
|
||||||
|
shell positional arguments ($1, $2, .., $#) are set to any arguments following
|
||||||
|
<command>.
|
||||||
|
.PP
|
||||||
|
Example: to list projects:
|
||||||
|
.IP
|
||||||
|
repo forall \fB\-c\fR 'echo $REPO_PROJECT'
|
||||||
|
.PP
|
||||||
|
Notice that $REPO_PROJECT is quoted to ensure it is expanded in the context of
|
||||||
|
running <command> instead of in the calling shell.
|
||||||
|
.PP
|
||||||
|
Unless \fB\-p\fR is used, stdin, stdout, stderr are inherited from the terminal and are
|
||||||
|
not redirected.
|
||||||
|
.PP
|
||||||
|
If \fB\-e\fR is used, when a command exits unsuccessfully, 'repo forall' will abort
|
||||||
|
without iterating through the remaining projects.
|
31
man/repo-gitc-delete.1
Normal file
31
man/repo-gitc-delete.1
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man.
|
||||||
|
.TH REPO "1" "July 2021" "repo gitc-delete" "Repo Manual"
|
||||||
|
.SH NAME
|
||||||
|
repo \- repo gitc-delete - manual page for repo gitc-delete
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B repo
|
||||||
|
\fI\,gitc-delete\/\fR
|
||||||
|
.SH DESCRIPTION
|
||||||
|
Summary
|
||||||
|
.PP
|
||||||
|
Delete a GITC Client.
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
\fB\-h\fR, \fB\-\-help\fR
|
||||||
|
show this help message and exit
|
||||||
|
.TP
|
||||||
|
\fB\-f\fR, \fB\-\-force\fR
|
||||||
|
force the deletion (no prompt)
|
||||||
|
.SS Logging options:
|
||||||
|
.TP
|
||||||
|
\fB\-v\fR, \fB\-\-verbose\fR
|
||||||
|
show all output
|
||||||
|
.TP
|
||||||
|
\fB\-q\fR, \fB\-\-quiet\fR
|
||||||
|
only show errors
|
||||||
|
.PP
|
||||||
|
Run `repo help gitc\-delete` to view the detailed manual.
|
||||||
|
.SH DETAILS
|
||||||
|
.PP
|
||||||
|
This subcommand deletes the current GITC client, deleting the GITC manifest and
|
||||||
|
all locally downloaded sources.
|
146
man/repo-gitc-init.1
Normal file
146
man/repo-gitc-init.1
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man.
|
||||||
|
.TH REPO "1" "July 2021" "repo gitc-init" "Repo Manual"
|
||||||
|
.SH NAME
|
||||||
|
repo \- repo gitc-init - manual page for repo gitc-init
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B repo
|
||||||
|
\fI\,gitc-init \/\fR[\fI\,options\/\fR] [\fI\,client name\/\fR]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
Summary
|
||||||
|
.PP
|
||||||
|
Initialize a GITC Client.
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
\fB\-h\fR, \fB\-\-help\fR
|
||||||
|
show this help message and exit
|
||||||
|
.SS Logging options:
|
||||||
|
.TP
|
||||||
|
\fB\-v\fR, \fB\-\-verbose\fR
|
||||||
|
show all output
|
||||||
|
.TP
|
||||||
|
\fB\-q\fR, \fB\-\-quiet\fR
|
||||||
|
only show errors
|
||||||
|
.SS Manifest options:
|
||||||
|
.TP
|
||||||
|
\fB\-u\fR URL, \fB\-\-manifest\-url\fR=\fI\,URL\/\fR
|
||||||
|
manifest repository location
|
||||||
|
.TP
|
||||||
|
\fB\-b\fR REVISION, \fB\-\-manifest\-branch\fR=\fI\,REVISION\/\fR
|
||||||
|
manifest branch or revision (use HEAD for default)
|
||||||
|
.TP
|
||||||
|
\fB\-m\fR NAME.xml, \fB\-\-manifest\-name\fR=\fI\,NAME\/\fR.xml
|
||||||
|
initial manifest file
|
||||||
|
.TP
|
||||||
|
\fB\-g\fR GROUP, \fB\-\-groups\fR=\fI\,GROUP\/\fR
|
||||||
|
restrict manifest projects to ones with specified
|
||||||
|
group(s) [default|all|G1,G2,G3|G4,\-G5,\-G6]
|
||||||
|
.TP
|
||||||
|
\fB\-p\fR PLATFORM, \fB\-\-platform\fR=\fI\,PLATFORM\/\fR
|
||||||
|
restrict manifest projects to ones with a specified
|
||||||
|
platform group [auto|all|none|linux|darwin|...]
|
||||||
|
.TP
|
||||||
|
\fB\-\-submodules\fR
|
||||||
|
sync any submodules associated with the manifest repo
|
||||||
|
.SS Manifest (only) checkout options:
|
||||||
|
.TP
|
||||||
|
\fB\-\-current\-branch\fR
|
||||||
|
fetch only current manifest branch from server
|
||||||
|
.TP
|
||||||
|
\fB\-\-no\-current\-branch\fR
|
||||||
|
fetch all manifest branches from server
|
||||||
|
.TP
|
||||||
|
\fB\-\-tags\fR
|
||||||
|
fetch tags in the manifest
|
||||||
|
.TP
|
||||||
|
\fB\-\-no\-tags\fR
|
||||||
|
don't fetch tags in the manifest
|
||||||
|
.SS Checkout modes:
|
||||||
|
.TP
|
||||||
|
\fB\-\-mirror\fR
|
||||||
|
create a replica of the remote repositories rather
|
||||||
|
than a client working directory
|
||||||
|
.TP
|
||||||
|
\fB\-\-archive\fR
|
||||||
|
checkout an archive instead of a git repository for
|
||||||
|
each project. See git archive.
|
||||||
|
.TP
|
||||||
|
\fB\-\-worktree\fR
|
||||||
|
use git\-worktree to manage projects
|
||||||
|
.SS Project checkout optimizations:
|
||||||
|
.TP
|
||||||
|
\fB\-\-reference\fR=\fI\,DIR\/\fR
|
||||||
|
location of mirror directory
|
||||||
|
.TP
|
||||||
|
\fB\-\-dissociate\fR
|
||||||
|
dissociate from reference mirrors after clone
|
||||||
|
.TP
|
||||||
|
\fB\-\-depth\fR=\fI\,DEPTH\/\fR
|
||||||
|
create a shallow clone with given depth; see git clone
|
||||||
|
.TP
|
||||||
|
\fB\-\-partial\-clone\fR
|
||||||
|
perform partial clone (https://gitscm.com/docs/gitrepositorylayout#_code_partialclone_code)
|
||||||
|
.TP
|
||||||
|
\fB\-\-no\-partial\-clone\fR
|
||||||
|
disable use of partial clone (https://gitscm.com/docs/gitrepositorylayout#_code_partialclone_code)
|
||||||
|
.TP
|
||||||
|
\fB\-\-partial\-clone\-exclude\fR=\fI\,PARTIAL_CLONE_EXCLUDE\/\fR
|
||||||
|
exclude the specified projects (a comma\-delimited
|
||||||
|
project names) from partial clone (https://gitscm.com/docs/gitrepositorylayout#_code_partialclone_code)
|
||||||
|
.TP
|
||||||
|
\fB\-\-clone\-filter\fR=\fI\,CLONE_FILTER\/\fR
|
||||||
|
filter for use with \fB\-\-partial\-clone\fR [default:
|
||||||
|
blob:none]
|
||||||
|
.TP
|
||||||
|
\fB\-\-use\-superproject\fR
|
||||||
|
use the manifest superproject to sync projects
|
||||||
|
.TP
|
||||||
|
\fB\-\-no\-use\-superproject\fR
|
||||||
|
disable use of manifest superprojects
|
||||||
|
.TP
|
||||||
|
\fB\-\-clone\-bundle\fR
|
||||||
|
enable use of \fI\,/clone.bundle\/\fP on HTTP/HTTPS (default if
|
||||||
|
not \fB\-\-partial\-clone\fR)
|
||||||
|
.TP
|
||||||
|
\fB\-\-no\-clone\-bundle\fR
|
||||||
|
disable use of \fI\,/clone.bundle\/\fP on HTTP/HTTPS (default if
|
||||||
|
\fB\-\-partial\-clone\fR)
|
||||||
|
.SS repo Version options:
|
||||||
|
.TP
|
||||||
|
\fB\-\-repo\-url\fR=\fI\,URL\/\fR
|
||||||
|
repo repository location ($REPO_URL)
|
||||||
|
.TP
|
||||||
|
\fB\-\-repo\-rev\fR=\fI\,REV\/\fR
|
||||||
|
repo branch or revision ($REPO_REV)
|
||||||
|
.TP
|
||||||
|
\fB\-\-no\-repo\-verify\fR
|
||||||
|
do not verify repo source code
|
||||||
|
.SS Other options:
|
||||||
|
.TP
|
||||||
|
\fB\-\-config\-name\fR
|
||||||
|
Always prompt for name/e\-mail
|
||||||
|
.SS GITC options:
|
||||||
|
.TP
|
||||||
|
\fB\-f\fR MANIFEST_FILE, \fB\-\-manifest\-file\fR=\fI\,MANIFEST_FILE\/\fR
|
||||||
|
Optional manifest file to use for this GITC client.
|
||||||
|
.TP
|
||||||
|
\fB\-c\fR GITC_CLIENT, \fB\-\-gitc\-client\fR=\fI\,GITC_CLIENT\/\fR
|
||||||
|
Name of the gitc_client instance to create or modify.
|
||||||
|
.PP
|
||||||
|
Run `repo help gitc\-init` to view the detailed manual.
|
||||||
|
.SH DETAILS
|
||||||
|
.PP
|
||||||
|
The 'repo gitc\-init' command is ran to initialize a new GITC client for use with
|
||||||
|
the GITC file system.
|
||||||
|
.PP
|
||||||
|
This command will setup the client directory, initialize repo, just like repo
|
||||||
|
init does, and then downloads the manifest collection and installs it in the
|
||||||
|
\&.repo/directory of the GITC client.
|
||||||
|
.PP
|
||||||
|
Once this is done, a GITC manifest is generated by pulling the HEAD SHA for each
|
||||||
|
project and generates the properly formatted XML file and installs it as
|
||||||
|
\&.manifest in the GITC client directory.
|
||||||
|
.PP
|
||||||
|
The \fB\-c\fR argument is required to specify the GITC client name.
|
||||||
|
.PP
|
||||||
|
The optional \fB\-f\fR argument can be used to specify the manifest file to use for
|
||||||
|
this GITC client.
|
118
man/repo-grep.1
Normal file
118
man/repo-grep.1
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man.
|
||||||
|
.TH REPO "1" "July 2021" "repo grep" "Repo Manual"
|
||||||
|
.SH NAME
|
||||||
|
repo \- repo grep - manual page for repo grep
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B repo
|
||||||
|
\fI\,grep {pattern | -e pattern} \/\fR[\fI\,<project>\/\fR...]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
Summary
|
||||||
|
.PP
|
||||||
|
Print lines matching a pattern
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
\fB\-h\fR, \fB\-\-help\fR
|
||||||
|
show this help message and exit
|
||||||
|
.TP
|
||||||
|
\fB\-j\fR JOBS, \fB\-\-jobs\fR=\fI\,JOBS\/\fR
|
||||||
|
number of jobs to run in parallel (default: 4)
|
||||||
|
.SS Logging options:
|
||||||
|
.TP
|
||||||
|
\fB\-\-verbose\fR
|
||||||
|
show all output
|
||||||
|
.TP
|
||||||
|
\fB\-q\fR, \fB\-\-quiet\fR
|
||||||
|
only show errors
|
||||||
|
.SS Sources:
|
||||||
|
.TP
|
||||||
|
\fB\-\-cached\fR
|
||||||
|
Search the index, instead of the work tree
|
||||||
|
.TP
|
||||||
|
\fB\-r\fR TREEish, \fB\-\-revision\fR=\fI\,TREEish\/\fR
|
||||||
|
Search TREEish, instead of the work tree
|
||||||
|
.SS Pattern:
|
||||||
|
.TP
|
||||||
|
\fB\-e\fR PATTERN
|
||||||
|
Pattern to search for
|
||||||
|
.TP
|
||||||
|
\fB\-i\fR, \fB\-\-ignore\-case\fR
|
||||||
|
Ignore case differences
|
||||||
|
.TP
|
||||||
|
\fB\-a\fR, \fB\-\-text\fR
|
||||||
|
Process binary files as if they were text
|
||||||
|
.TP
|
||||||
|
\fB\-I\fR
|
||||||
|
Don't match the pattern in binary files
|
||||||
|
.TP
|
||||||
|
\fB\-w\fR, \fB\-\-word\-regexp\fR
|
||||||
|
Match the pattern only at word boundaries
|
||||||
|
.TP
|
||||||
|
\fB\-v\fR, \fB\-\-invert\-match\fR
|
||||||
|
Select non\-matching lines
|
||||||
|
.TP
|
||||||
|
\fB\-G\fR, \fB\-\-basic\-regexp\fR
|
||||||
|
Use POSIX basic regexp for patterns (default)
|
||||||
|
.TP
|
||||||
|
\fB\-E\fR, \fB\-\-extended\-regexp\fR
|
||||||
|
Use POSIX extended regexp for patterns
|
||||||
|
.TP
|
||||||
|
\fB\-F\fR, \fB\-\-fixed\-strings\fR
|
||||||
|
Use fixed strings (not regexp) for pattern
|
||||||
|
.SS Pattern Grouping:
|
||||||
|
.TP
|
||||||
|
\fB\-\-all\-match\fR
|
||||||
|
Limit match to lines that have all patterns
|
||||||
|
.TP
|
||||||
|
\fB\-\-and\fR, \fB\-\-or\fR, \fB\-\-not\fR
|
||||||
|
Boolean operators to combine patterns
|
||||||
|
.TP
|
||||||
|
\-(, \-)
|
||||||
|
Boolean operator grouping
|
||||||
|
.SS Output:
|
||||||
|
.TP
|
||||||
|
\fB\-n\fR
|
||||||
|
Prefix the line number to matching lines
|
||||||
|
.TP
|
||||||
|
\fB\-C\fR CONTEXT
|
||||||
|
Show CONTEXT lines around match
|
||||||
|
.TP
|
||||||
|
\fB\-B\fR CONTEXT
|
||||||
|
Show CONTEXT lines before match
|
||||||
|
.TP
|
||||||
|
\fB\-A\fR CONTEXT
|
||||||
|
Show CONTEXT lines after match
|
||||||
|
.TP
|
||||||
|
\fB\-l\fR, \fB\-\-name\-only\fR, \fB\-\-files\-with\-matches\fR
|
||||||
|
Show only file names containing matching lines
|
||||||
|
.TP
|
||||||
|
\fB\-L\fR, \fB\-\-files\-without\-match\fR
|
||||||
|
Show only file names not containing matching lines
|
||||||
|
.PP
|
||||||
|
Run `repo help grep` to view the detailed manual.
|
||||||
|
.SH DETAILS
|
||||||
|
.PP
|
||||||
|
Search for the specified patterns in all project files.
|
||||||
|
.PP
|
||||||
|
Boolean Options
|
||||||
|
.PP
|
||||||
|
The following options can appear as often as necessary to express the pattern to
|
||||||
|
locate:
|
||||||
|
.HP
|
||||||
|
\fB\-e\fR PATTERN
|
||||||
|
.HP
|
||||||
|
\fB\-\-and\fR, \fB\-\-or\fR, \fB\-\-not\fR, \-(, \-)
|
||||||
|
.PP
|
||||||
|
Further, the \fB\-r\fR/\-\-revision option may be specified multiple times in order to
|
||||||
|
scan multiple trees. If the same file matches in more than one tree, only the
|
||||||
|
first result is reported, prefixed by the revision name it was found under.
|
||||||
|
.PP
|
||||||
|
Examples
|
||||||
|
.PP
|
||||||
|
Look for a line that has '#define' and either 'MAX_PATH or 'PATH_MAX':
|
||||||
|
.IP
|
||||||
|
repo grep \fB\-e\fR '#define' \fB\-\-and\fR \-\e( \fB\-e\fR MAX_PATH \fB\-e\fR PATH_MAX \e)
|
||||||
|
.PP
|
||||||
|
Look for a line that has 'NODE' or 'Unexpected' in files that contain a line
|
||||||
|
that matches both expressions:
|
||||||
|
.IP
|
||||||
|
repo grep \fB\-\-all\-match\fR \fB\-e\fR NODE \fB\-e\fR Unexpected
|
33
man/repo-help.1
Normal file
33
man/repo-help.1
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man.
|
||||||
|
.TH REPO "1" "July 2021" "repo help" "Repo Manual"
|
||||||
|
.SH NAME
|
||||||
|
repo \- repo help - manual page for repo help
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B repo
|
||||||
|
\fI\,help \/\fR[\fI\,--all|command\/\fR]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
Summary
|
||||||
|
.PP
|
||||||
|
Display detailed help on a command
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
\fB\-h\fR, \fB\-\-help\fR
|
||||||
|
show this help message and exit
|
||||||
|
.TP
|
||||||
|
\fB\-a\fR, \fB\-\-all\fR
|
||||||
|
show the complete list of commands
|
||||||
|
.TP
|
||||||
|
\fB\-\-help\-all\fR
|
||||||
|
show the \fB\-\-help\fR of all commands
|
||||||
|
.SS Logging options:
|
||||||
|
.TP
|
||||||
|
\fB\-v\fR, \fB\-\-verbose\fR
|
||||||
|
show all output
|
||||||
|
.TP
|
||||||
|
\fB\-q\fR, \fB\-\-quiet\fR
|
||||||
|
only show errors
|
||||||
|
.PP
|
||||||
|
Run `repo help help` to view the detailed manual.
|
||||||
|
.SH DETAILS
|
||||||
|
.PP
|
||||||
|
Displays detailed usage information about a command.
|
40
man/repo-info.1
Normal file
40
man/repo-info.1
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man.
|
||||||
|
.TH REPO "1" "July 2021" "repo info" "Repo Manual"
|
||||||
|
.SH NAME
|
||||||
|
repo \- repo info - manual page for repo info
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B repo
|
||||||
|
\fI\,info \/\fR[\fI\,-dl\/\fR] [\fI\,-o \/\fR[\fI\,-c\/\fR]] [\fI\,<project>\/\fR...]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
Summary
|
||||||
|
.PP
|
||||||
|
Get info on the manifest branch, current branch or unmerged branches
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
\fB\-h\fR, \fB\-\-help\fR
|
||||||
|
show this help message and exit
|
||||||
|
.TP
|
||||||
|
\fB\-d\fR, \fB\-\-diff\fR
|
||||||
|
show full info and commit diff including remote
|
||||||
|
branches
|
||||||
|
.TP
|
||||||
|
\fB\-o\fR, \fB\-\-overview\fR
|
||||||
|
show overview of all local commits
|
||||||
|
.TP
|
||||||
|
\fB\-c\fR, \fB\-\-current\-branch\fR
|
||||||
|
consider only checked out branches
|
||||||
|
.TP
|
||||||
|
\fB\-\-no\-current\-branch\fR
|
||||||
|
consider all local branches
|
||||||
|
.TP
|
||||||
|
\fB\-l\fR, \fB\-\-local\-only\fR
|
||||||
|
disable all remote operations
|
||||||
|
.SS Logging options:
|
||||||
|
.TP
|
||||||
|
\fB\-v\fR, \fB\-\-verbose\fR
|
||||||
|
show all output
|
||||||
|
.TP
|
||||||
|
\fB\-q\fR, \fB\-\-quiet\fR
|
||||||
|
only show errors
|
||||||
|
.PP
|
||||||
|
Run `repo help info` to view the detailed manual.
|
160
man/repo-init.1
Normal file
160
man/repo-init.1
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man.
|
||||||
|
.TH REPO "1" "July 2021" "repo init" "Repo Manual"
|
||||||
|
.SH NAME
|
||||||
|
repo \- repo init - manual page for repo init
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B repo
|
||||||
|
\fI\,init \/\fR[\fI\,options\/\fR] [\fI\,manifest url\/\fR]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
Summary
|
||||||
|
.PP
|
||||||
|
Initialize a repo client checkout in the current directory
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
\fB\-h\fR, \fB\-\-help\fR
|
||||||
|
show this help message and exit
|
||||||
|
.SS Logging options:
|
||||||
|
.TP
|
||||||
|
\fB\-v\fR, \fB\-\-verbose\fR
|
||||||
|
show all output
|
||||||
|
.TP
|
||||||
|
\fB\-q\fR, \fB\-\-quiet\fR
|
||||||
|
only show errors
|
||||||
|
.SS Manifest options:
|
||||||
|
.TP
|
||||||
|
\fB\-u\fR URL, \fB\-\-manifest\-url\fR=\fI\,URL\/\fR
|
||||||
|
manifest repository location
|
||||||
|
.TP
|
||||||
|
\fB\-b\fR REVISION, \fB\-\-manifest\-branch\fR=\fI\,REVISION\/\fR
|
||||||
|
manifest branch or revision (use HEAD for default)
|
||||||
|
.TP
|
||||||
|
\fB\-m\fR NAME.xml, \fB\-\-manifest\-name\fR=\fI\,NAME\/\fR.xml
|
||||||
|
initial manifest file
|
||||||
|
.TP
|
||||||
|
\fB\-g\fR GROUP, \fB\-\-groups\fR=\fI\,GROUP\/\fR
|
||||||
|
restrict manifest projects to ones with specified
|
||||||
|
group(s) [default|all|G1,G2,G3|G4,\-G5,\-G6]
|
||||||
|
.TP
|
||||||
|
\fB\-p\fR PLATFORM, \fB\-\-platform\fR=\fI\,PLATFORM\/\fR
|
||||||
|
restrict manifest projects to ones with a specified
|
||||||
|
platform group [auto|all|none|linux|darwin|...]
|
||||||
|
.TP
|
||||||
|
\fB\-\-submodules\fR
|
||||||
|
sync any submodules associated with the manifest repo
|
||||||
|
.SS Manifest (only) checkout options:
|
||||||
|
.TP
|
||||||
|
\fB\-c\fR, \fB\-\-current\-branch\fR
|
||||||
|
fetch only current manifest branch from server
|
||||||
|
.TP
|
||||||
|
\fB\-\-no\-current\-branch\fR
|
||||||
|
fetch all manifest branches from server
|
||||||
|
.TP
|
||||||
|
\fB\-\-tags\fR
|
||||||
|
fetch tags in the manifest
|
||||||
|
.TP
|
||||||
|
\fB\-\-no\-tags\fR
|
||||||
|
don't fetch tags in the manifest
|
||||||
|
.SS Checkout modes:
|
||||||
|
.TP
|
||||||
|
\fB\-\-mirror\fR
|
||||||
|
create a replica of the remote repositories rather
|
||||||
|
than a client working directory
|
||||||
|
.TP
|
||||||
|
\fB\-\-archive\fR
|
||||||
|
checkout an archive instead of a git repository for
|
||||||
|
each project. See git archive.
|
||||||
|
.TP
|
||||||
|
\fB\-\-worktree\fR
|
||||||
|
use git\-worktree to manage projects
|
||||||
|
.SS Project checkout optimizations:
|
||||||
|
.TP
|
||||||
|
\fB\-\-reference\fR=\fI\,DIR\/\fR
|
||||||
|
location of mirror directory
|
||||||
|
.TP
|
||||||
|
\fB\-\-dissociate\fR
|
||||||
|
dissociate from reference mirrors after clone
|
||||||
|
.TP
|
||||||
|
\fB\-\-depth\fR=\fI\,DEPTH\/\fR
|
||||||
|
create a shallow clone with given depth; see git clone
|
||||||
|
.TP
|
||||||
|
\fB\-\-partial\-clone\fR
|
||||||
|
perform partial clone (https://gitscm.com/docs/gitrepositorylayout#_code_partialclone_code)
|
||||||
|
.TP
|
||||||
|
\fB\-\-no\-partial\-clone\fR
|
||||||
|
disable use of partial clone (https://gitscm.com/docs/gitrepositorylayout#_code_partialclone_code)
|
||||||
|
.TP
|
||||||
|
\fB\-\-partial\-clone\-exclude\fR=\fI\,PARTIAL_CLONE_EXCLUDE\/\fR
|
||||||
|
exclude the specified projects (a comma\-delimited
|
||||||
|
project names) from partial clone (https://gitscm.com/docs/gitrepositorylayout#_code_partialclone_code)
|
||||||
|
.TP
|
||||||
|
\fB\-\-clone\-filter\fR=\fI\,CLONE_FILTER\/\fR
|
||||||
|
filter for use with \fB\-\-partial\-clone\fR [default:
|
||||||
|
blob:none]
|
||||||
|
.TP
|
||||||
|
\fB\-\-use\-superproject\fR
|
||||||
|
use the manifest superproject to sync projects
|
||||||
|
.TP
|
||||||
|
\fB\-\-no\-use\-superproject\fR
|
||||||
|
disable use of manifest superprojects
|
||||||
|
.TP
|
||||||
|
\fB\-\-clone\-bundle\fR
|
||||||
|
enable use of \fI\,/clone.bundle\/\fP on HTTP/HTTPS (default if
|
||||||
|
not \fB\-\-partial\-clone\fR)
|
||||||
|
.TP
|
||||||
|
\fB\-\-no\-clone\-bundle\fR
|
||||||
|
disable use of \fI\,/clone.bundle\/\fP on HTTP/HTTPS (default if
|
||||||
|
\fB\-\-partial\-clone\fR)
|
||||||
|
.SS repo Version options:
|
||||||
|
.TP
|
||||||
|
\fB\-\-repo\-url\fR=\fI\,URL\/\fR
|
||||||
|
repo repository location ($REPO_URL)
|
||||||
|
.TP
|
||||||
|
\fB\-\-repo\-rev\fR=\fI\,REV\/\fR
|
||||||
|
repo branch or revision ($REPO_REV)
|
||||||
|
.TP
|
||||||
|
\fB\-\-no\-repo\-verify\fR
|
||||||
|
do not verify repo source code
|
||||||
|
.SS Other options:
|
||||||
|
.TP
|
||||||
|
\fB\-\-config\-name\fR
|
||||||
|
Always prompt for name/e\-mail
|
||||||
|
.PP
|
||||||
|
Run `repo help init` to view the detailed manual.
|
||||||
|
.SH DETAILS
|
||||||
|
.PP
|
||||||
|
The 'repo init' command is run once to install and initialize repo. The latest
|
||||||
|
repo source code and manifest collection is downloaded from the server and is
|
||||||
|
installed in the .repo/ directory in the current working directory.
|
||||||
|
.PP
|
||||||
|
When creating a new checkout, the manifest URL is the only required setting. It
|
||||||
|
may be specified using the \fB\-\-manifest\-url\fR option, or as the first optional
|
||||||
|
argument.
|
||||||
|
.PP
|
||||||
|
The optional \fB\-b\fR argument can be used to select the manifest branch to checkout
|
||||||
|
and use. If no branch is specified, the remote's default branch is used. This is
|
||||||
|
equivalent to using \fB\-b\fR HEAD.
|
||||||
|
.PP
|
||||||
|
The optional \fB\-m\fR argument can be used to specify an alternate manifest to be
|
||||||
|
used. If no manifest is specified, the manifest default.xml will be used.
|
||||||
|
.PP
|
||||||
|
The \fB\-\-reference\fR option can be used to point to a directory that has the content
|
||||||
|
of a \fB\-\-mirror\fR sync. This will make the working directory use as much data as
|
||||||
|
possible from the local reference directory when fetching from the server. This
|
||||||
|
will make the sync go a lot faster by reducing data traffic on the network.
|
||||||
|
.PP
|
||||||
|
The \fB\-\-dissociate\fR option can be used to borrow the objects from the directory
|
||||||
|
specified with the \fB\-\-reference\fR option only to reduce network transfer, and stop
|
||||||
|
borrowing from them after a first clone is made by making necessary local copies
|
||||||
|
of borrowed objects.
|
||||||
|
.PP
|
||||||
|
The \fB\-\-no\-clone\-bundle\fR option disables any attempt to use \fI\,$URL/clone.bundle\/\fP to
|
||||||
|
bootstrap a new Git repository from a resumeable bundle file on a content
|
||||||
|
delivery network. This may be necessary if there are problems with the local
|
||||||
|
Python HTTP client or proxy configuration, but the Git binary works.
|
||||||
|
.PP
|
||||||
|
Switching Manifest Branches
|
||||||
|
.PP
|
||||||
|
To switch to another manifest branch, `repo init \fB\-b\fR otherbranch` may be used in
|
||||||
|
an existing client. However, as this only updates the manifest, a subsequent
|
||||||
|
`repo sync` (or `repo sync \fB\-d\fR`) is necessary to update the working directory
|
||||||
|
files.
|
61
man/repo-list.1
Normal file
61
man/repo-list.1
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man.
|
||||||
|
.TH REPO "1" "July 2021" "repo list" "Repo Manual"
|
||||||
|
.SH NAME
|
||||||
|
repo \- repo list - manual page for repo list
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B repo
|
||||||
|
\fI\,list \/\fR[\fI\,-f\/\fR] [\fI\,<project>\/\fR...]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
Summary
|
||||||
|
.PP
|
||||||
|
List projects and their associated directories
|
||||||
|
.PP
|
||||||
|
repo list [\-f] \fB\-r\fR str1 [str2]...
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
\fB\-h\fR, \fB\-\-help\fR
|
||||||
|
show this help message and exit
|
||||||
|
.TP
|
||||||
|
\fB\-r\fR, \fB\-\-regex\fR
|
||||||
|
filter the project list based on regex or wildcard
|
||||||
|
matching of strings
|
||||||
|
.TP
|
||||||
|
\fB\-g\fR GROUPS, \fB\-\-groups\fR=\fI\,GROUPS\/\fR
|
||||||
|
filter the project list based on the groups the
|
||||||
|
project is in
|
||||||
|
.TP
|
||||||
|
\fB\-a\fR, \fB\-\-all\fR
|
||||||
|
show projects regardless of checkout state
|
||||||
|
.TP
|
||||||
|
\fB\-n\fR, \fB\-\-name\-only\fR
|
||||||
|
display only the name of the repository
|
||||||
|
.TP
|
||||||
|
\fB\-p\fR, \fB\-\-path\-only\fR
|
||||||
|
display only the path of the repository
|
||||||
|
.TP
|
||||||
|
\fB\-f\fR, \fB\-\-fullpath\fR
|
||||||
|
display the full work tree path instead of the
|
||||||
|
relative path
|
||||||
|
.TP
|
||||||
|
\fB\-\-relative\-to\fR=\fI\,PATH\/\fR
|
||||||
|
display paths relative to this one (default: top of
|
||||||
|
repo client checkout)
|
||||||
|
.SS Logging options:
|
||||||
|
.TP
|
||||||
|
\fB\-v\fR, \fB\-\-verbose\fR
|
||||||
|
show all output
|
||||||
|
.TP
|
||||||
|
\fB\-q\fR, \fB\-\-quiet\fR
|
||||||
|
only show errors
|
||||||
|
.PP
|
||||||
|
Run `repo help list` to view the detailed manual.
|
||||||
|
.SH DETAILS
|
||||||
|
.PP
|
||||||
|
List all projects; pass '.' to list the project for the cwd.
|
||||||
|
.PP
|
||||||
|
By default, only projects that currently exist in the checkout are shown. If you
|
||||||
|
want to list all projects (using the specified filter settings), use the \fB\-\-all\fR
|
||||||
|
option. If you want to show all projects regardless of the manifest groups, then
|
||||||
|
also pass \fB\-\-groups\fR all.
|
||||||
|
.PP
|
||||||
|
This is similar to running: repo forall \fB\-c\fR 'echo "$REPO_PATH : $REPO_PROJECT"'.
|
548
man/repo-manifest.1
Normal file
548
man/repo-manifest.1
Normal file
@ -0,0 +1,548 @@
|
|||||||
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man.
|
||||||
|
.TH REPO "1" "July 2021" "repo manifest" "Repo Manual"
|
||||||
|
.SH NAME
|
||||||
|
repo \- repo manifest - manual page for repo manifest
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B repo
|
||||||
|
\fI\,manifest \/\fR[\fI\,-o {-|NAME.xml}\/\fR] [\fI\,-m MANIFEST.xml\/\fR] [\fI\,-r\/\fR]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
Summary
|
||||||
|
.PP
|
||||||
|
Manifest inspection utility
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
\fB\-h\fR, \fB\-\-help\fR
|
||||||
|
show this help message and exit
|
||||||
|
.TP
|
||||||
|
\fB\-r\fR, \fB\-\-revision\-as\-HEAD\fR
|
||||||
|
save revisions as current HEAD
|
||||||
|
.TP
|
||||||
|
\fB\-m\fR NAME.xml, \fB\-\-manifest\-name\fR=\fI\,NAME\/\fR.xml
|
||||||
|
temporary manifest to use for this sync
|
||||||
|
.TP
|
||||||
|
\fB\-\-suppress\-upstream\-revision\fR
|
||||||
|
if in \fB\-r\fR mode, do not write the upstream field (only
|
||||||
|
of use if the branch names for a sha1 manifest are
|
||||||
|
sensitive)
|
||||||
|
.TP
|
||||||
|
\fB\-\-suppress\-dest\-branch\fR
|
||||||
|
if in \fB\-r\fR mode, do not write the dest\-branch field
|
||||||
|
(only of use if the branch names for a sha1 manifest
|
||||||
|
are sensitive)
|
||||||
|
.TP
|
||||||
|
\fB\-\-json\fR
|
||||||
|
output manifest in JSON format (experimental)
|
||||||
|
.TP
|
||||||
|
\fB\-\-pretty\fR
|
||||||
|
format output for humans to read
|
||||||
|
.TP
|
||||||
|
\fB\-\-no\-local\-manifests\fR
|
||||||
|
ignore local manifests
|
||||||
|
.TP
|
||||||
|
\fB\-o\fR \-|NAME.xml, \fB\-\-output\-file\fR=\fI\,\-\/\fR|NAME.xml
|
||||||
|
file to save the manifest to
|
||||||
|
.SS Logging options:
|
||||||
|
.TP
|
||||||
|
\fB\-v\fR, \fB\-\-verbose\fR
|
||||||
|
show all output
|
||||||
|
.TP
|
||||||
|
\fB\-q\fR, \fB\-\-quiet\fR
|
||||||
|
only show errors
|
||||||
|
.PP
|
||||||
|
Run `repo help manifest` to view the detailed manual.
|
||||||
|
.SH DETAILS
|
||||||
|
.PP
|
||||||
|
With the \fB\-o\fR option, exports the current manifest for inspection. The manifest
|
||||||
|
and (if present) local_manifests/ are combined together to produce a single
|
||||||
|
manifest file. This file can be stored in a Git repository for use during future
|
||||||
|
\&'repo init' invocations.
|
||||||
|
.PP
|
||||||
|
The \fB\-r\fR option can be used to generate a manifest file with project revisions set
|
||||||
|
to the current commit hash. These are known as "revision locked manifests", as
|
||||||
|
they don't follow a particular branch. In this case, the 'upstream' attribute is
|
||||||
|
set to the ref we were on when the manifest was generated. The 'dest\-branch'
|
||||||
|
attribute is set to indicate the remote ref to push changes to via 'repo
|
||||||
|
upload'.
|
||||||
|
.PP
|
||||||
|
repo Manifest Format
|
||||||
|
.PP
|
||||||
|
A repo manifest describes the structure of a repo client; that is the
|
||||||
|
directories that are visible and where they should be obtained from with git.
|
||||||
|
.PP
|
||||||
|
The basic structure of a manifest is a bare Git repository holding a single
|
||||||
|
`default.xml` XML file in the top level directory.
|
||||||
|
.PP
|
||||||
|
Manifests are inherently version controlled, since they are kept within a Git
|
||||||
|
repository. Updates to manifests are automatically obtained by clients during
|
||||||
|
`repo sync`.
|
||||||
|
.PP
|
||||||
|
[TOC]
|
||||||
|
.PP
|
||||||
|
XML File Format
|
||||||
|
.PP
|
||||||
|
A manifest XML file (e.g. `default.xml`) roughly conforms to the following DTD:
|
||||||
|
.PP
|
||||||
|
```xml <!DOCTYPE manifest [
|
||||||
|
.TP
|
||||||
|
<!ELEMENT manifest (notice?,
|
||||||
|
remote*,
|
||||||
|
default?,
|
||||||
|
manifest\-server?,
|
||||||
|
remove\-project*,
|
||||||
|
project*,
|
||||||
|
extend\-project*,
|
||||||
|
repo\-hooks?,
|
||||||
|
superproject?,
|
||||||
|
contactinfo?,
|
||||||
|
include*)>
|
||||||
|
.IP
|
||||||
|
<!ELEMENT notice (#PCDATA)>
|
||||||
|
.IP
|
||||||
|
<!ELEMENT remote (annotation*)>
|
||||||
|
<!ATTLIST remote name ID #REQUIRED>
|
||||||
|
<!ATTLIST remote alias CDATA #IMPLIED>
|
||||||
|
<!ATTLIST remote fetch CDATA #REQUIRED>
|
||||||
|
<!ATTLIST remote pushurl CDATA #IMPLIED>
|
||||||
|
<!ATTLIST remote review CDATA #IMPLIED>
|
||||||
|
<!ATTLIST remote revision CDATA #IMPLIED>
|
||||||
|
.IP
|
||||||
|
<!ELEMENT default EMPTY>
|
||||||
|
<!ATTLIST default remote IDREF #IMPLIED>
|
||||||
|
<!ATTLIST default revision CDATA #IMPLIED>
|
||||||
|
<!ATTLIST default dest\-branch CDATA #IMPLIED>
|
||||||
|
<!ATTLIST default upstream CDATA #IMPLIED>
|
||||||
|
<!ATTLIST default sync\-j CDATA #IMPLIED>
|
||||||
|
<!ATTLIST default sync\-c CDATA #IMPLIED>
|
||||||
|
<!ATTLIST default sync\-s CDATA #IMPLIED>
|
||||||
|
<!ATTLIST default sync\-tags CDATA #IMPLIED>
|
||||||
|
.IP
|
||||||
|
<!ELEMENT manifest\-server EMPTY>
|
||||||
|
<!ATTLIST manifest\-server url CDATA #REQUIRED>
|
||||||
|
.TP
|
||||||
|
<!ELEMENT project (annotation*,
|
||||||
|
project*,
|
||||||
|
copyfile*,
|
||||||
|
linkfile*)>
|
||||||
|
.TP
|
||||||
|
<!ATTLIST project name
|
||||||
|
CDATA #REQUIRED>
|
||||||
|
.TP
|
||||||
|
<!ATTLIST project path
|
||||||
|
CDATA #IMPLIED>
|
||||||
|
.TP
|
||||||
|
<!ATTLIST project remote
|
||||||
|
IDREF #IMPLIED>
|
||||||
|
.TP
|
||||||
|
<!ATTLIST project revision
|
||||||
|
CDATA #IMPLIED>
|
||||||
|
.IP
|
||||||
|
<!ATTLIST project dest\-branch CDATA #IMPLIED>
|
||||||
|
<!ATTLIST project groups CDATA #IMPLIED>
|
||||||
|
<!ATTLIST project sync\-c CDATA #IMPLIED>
|
||||||
|
<!ATTLIST project sync\-s CDATA #IMPLIED>
|
||||||
|
<!ATTLIST project sync\-tags CDATA #IMPLIED>
|
||||||
|
<!ATTLIST project upstream CDATA #IMPLIED>
|
||||||
|
<!ATTLIST project clone\-depth CDATA #IMPLIED>
|
||||||
|
<!ATTLIST project force\-path CDATA #IMPLIED>
|
||||||
|
.IP
|
||||||
|
<!ELEMENT annotation EMPTY>
|
||||||
|
<!ATTLIST annotation name CDATA #REQUIRED>
|
||||||
|
<!ATTLIST annotation value CDATA #REQUIRED>
|
||||||
|
<!ATTLIST annotation keep CDATA "true">
|
||||||
|
.IP
|
||||||
|
<!ELEMENT copyfile EMPTY>
|
||||||
|
<!ATTLIST copyfile src CDATA #REQUIRED>
|
||||||
|
<!ATTLIST copyfile dest CDATA #REQUIRED>
|
||||||
|
.IP
|
||||||
|
<!ELEMENT linkfile EMPTY>
|
||||||
|
<!ATTLIST linkfile src CDATA #REQUIRED>
|
||||||
|
<!ATTLIST linkfile dest CDATA #REQUIRED>
|
||||||
|
.IP
|
||||||
|
<!ELEMENT extend\-project EMPTY>
|
||||||
|
<!ATTLIST extend\-project name CDATA #REQUIRED>
|
||||||
|
<!ATTLIST extend\-project path CDATA #IMPLIED>
|
||||||
|
<!ATTLIST extend\-project groups CDATA #IMPLIED>
|
||||||
|
<!ATTLIST extend\-project revision CDATA #IMPLIED>
|
||||||
|
<!ATTLIST extend\-project remote CDATA #IMPLIED>
|
||||||
|
.IP
|
||||||
|
<!ELEMENT remove\-project EMPTY>
|
||||||
|
<!ATTLIST remove\-project name CDATA #REQUIRED>
|
||||||
|
<!ATTLIST remove\-project optional CDATA #IMPLIED>
|
||||||
|
.IP
|
||||||
|
<!ELEMENT repo\-hooks EMPTY>
|
||||||
|
<!ATTLIST repo\-hooks in\-project CDATA #REQUIRED>
|
||||||
|
<!ATTLIST repo\-hooks enabled\-list CDATA #REQUIRED>
|
||||||
|
.IP
|
||||||
|
<!ELEMENT superproject EMPTY>
|
||||||
|
<!ATTLIST superproject name CDATA #REQUIRED>
|
||||||
|
<!ATTLIST superproject remote IDREF #IMPLIED>
|
||||||
|
.IP
|
||||||
|
<!ELEMENT contactinfo EMPTY>
|
||||||
|
<!ATTLIST contactinfo bugurl CDATA #REQUIRED>
|
||||||
|
.IP
|
||||||
|
<!ELEMENT include EMPTY>
|
||||||
|
<!ATTLIST include name CDATA #REQUIRED>
|
||||||
|
<!ATTLIST include groups CDATA #IMPLIED>
|
||||||
|
.PP
|
||||||
|
]>
|
||||||
|
```
|
||||||
|
.PP
|
||||||
|
For compatibility purposes across repo releases, all unknown elements are
|
||||||
|
silently ignored. However, repo reserves all possible names for itself for
|
||||||
|
future use. If you want to use custom elements, the `x\-*` namespace is reserved
|
||||||
|
for that purpose, and repo guarantees to never allocate any corresponding names.
|
||||||
|
.PP
|
||||||
|
A description of the elements and their attributes follows.
|
||||||
|
.PP
|
||||||
|
Element manifest
|
||||||
|
.PP
|
||||||
|
The root element of the file.
|
||||||
|
.PP
|
||||||
|
Element notice
|
||||||
|
.PP
|
||||||
|
Arbitrary text that is displayed to users whenever `repo sync` finishes. The
|
||||||
|
content is simply passed through as it exists in the manifest.
|
||||||
|
.PP
|
||||||
|
Element remote
|
||||||
|
.PP
|
||||||
|
One or more remote elements may be specified. Each remote element specifies a
|
||||||
|
Git URL shared by one or more projects and (optionally) the Gerrit review server
|
||||||
|
those projects upload changes through.
|
||||||
|
.PP
|
||||||
|
Attribute `name`: A short name unique to this manifest file. The name specified
|
||||||
|
here is used as the remote name in each project's .git/config, and is therefore
|
||||||
|
automatically available to commands like `git fetch`, `git remote`, `git pull`
|
||||||
|
and `git push`.
|
||||||
|
.PP
|
||||||
|
Attribute `alias`: The alias, if specified, is used to override `name` to be set
|
||||||
|
as the remote name in each project's .git/config. Its value can be duplicated
|
||||||
|
while attribute `name` has to be unique in the manifest file. This helps each
|
||||||
|
project to be able to have same remote name which actually points to different
|
||||||
|
remote url.
|
||||||
|
.PP
|
||||||
|
Attribute `fetch`: The Git URL prefix for all projects which use this remote.
|
||||||
|
Each project's name is appended to this prefix to form the actual URL used to
|
||||||
|
clone the project.
|
||||||
|
.PP
|
||||||
|
Attribute `pushurl`: The Git "push" URL prefix for all projects which use this
|
||||||
|
remote. Each project's name is appended to this prefix to form the actual URL
|
||||||
|
used to "git push" the project. This attribute is optional; if not specified
|
||||||
|
then "git push" will use the same URL as the `fetch` attribute.
|
||||||
|
.PP
|
||||||
|
Attribute `review`: Hostname of the Gerrit server where reviews are uploaded to
|
||||||
|
by `repo upload`. This attribute is optional; if not specified then `repo
|
||||||
|
upload` will not function.
|
||||||
|
.PP
|
||||||
|
Attribute `revision`: Name of a Git branch (e.g. `main` or `refs/heads/main`).
|
||||||
|
Remotes with their own revision will override the default revision.
|
||||||
|
.PP
|
||||||
|
Element default
|
||||||
|
.PP
|
||||||
|
At most one default element may be specified. Its remote and revision attributes
|
||||||
|
are used when a project element does not specify its own remote or revision
|
||||||
|
attribute.
|
||||||
|
.PP
|
||||||
|
Attribute `remote`: Name of a previously defined remote element. Project
|
||||||
|
elements lacking a remote attribute of their own will use this remote.
|
||||||
|
.PP
|
||||||
|
Attribute `revision`: Name of a Git branch (e.g. `main` or `refs/heads/main`).
|
||||||
|
Project elements lacking their own revision attribute will use this revision.
|
||||||
|
.PP
|
||||||
|
Attribute `dest\-branch`: Name of a Git branch (e.g. `main`). Project elements
|
||||||
|
not setting their own `dest\-branch` will inherit this value. If this value is
|
||||||
|
not set, projects will use `revision` by default instead.
|
||||||
|
.PP
|
||||||
|
Attribute `upstream`: Name of the Git ref in which a sha1 can be found. Used
|
||||||
|
when syncing a revision locked manifest in \fB\-c\fR mode to avoid having to sync the
|
||||||
|
entire ref space. Project elements not setting their own `upstream` will inherit
|
||||||
|
this value.
|
||||||
|
.PP
|
||||||
|
Attribute `sync\-j`: Number of parallel jobs to use when synching.
|
||||||
|
.PP
|
||||||
|
Attribute `sync\-c`: Set to true to only sync the given Git branch (specified in
|
||||||
|
the `revision` attribute) rather than the whole ref space. Project elements
|
||||||
|
lacking a sync\-c element of their own will use this value.
|
||||||
|
.PP
|
||||||
|
Attribute `sync\-s`: Set to true to also sync sub\-projects.
|
||||||
|
.PP
|
||||||
|
Attribute `sync\-tags`: Set to false to only sync the given Git branch (specified
|
||||||
|
in the `revision` attribute) rather than the other ref tags.
|
||||||
|
.PP
|
||||||
|
Element manifest\-server
|
||||||
|
.PP
|
||||||
|
At most one manifest\-server may be specified. The url attribute is used to
|
||||||
|
specify the URL of a manifest server, which is an XML RPC service.
|
||||||
|
.PP
|
||||||
|
The manifest server should implement the following RPC methods:
|
||||||
|
.IP
|
||||||
|
GetApprovedManifest(branch, target)
|
||||||
|
.PP
|
||||||
|
Return a manifest in which each project is pegged to a known good revision for
|
||||||
|
the current branch and target. This is used by repo sync when the \fB\-\-smart\-sync\fR
|
||||||
|
option is given.
|
||||||
|
.PP
|
||||||
|
The target to use is defined by environment variables TARGET_PRODUCT and
|
||||||
|
TARGET_BUILD_VARIANT. These variables are used to create a string of the form
|
||||||
|
$TARGET_PRODUCT\-$TARGET_BUILD_VARIANT, e.g. passion\-userdebug. If one of those
|
||||||
|
variables or both are not present, the program will call GetApprovedManifest
|
||||||
|
without the target parameter and the manifest server should choose a reasonable
|
||||||
|
default target.
|
||||||
|
.IP
|
||||||
|
GetManifest(tag)
|
||||||
|
.PP
|
||||||
|
Return a manifest in which each project is pegged to the revision at the
|
||||||
|
specified tag. This is used by repo sync when the \fB\-\-smart\-tag\fR option is given.
|
||||||
|
.PP
|
||||||
|
Element project
|
||||||
|
.PP
|
||||||
|
One or more project elements may be specified. Each element describes a single
|
||||||
|
Git repository to be cloned into the repo client workspace. You may specify
|
||||||
|
Git\-submodules by creating a nested project. Git\-submodules will be
|
||||||
|
automatically recognized and inherit their parent's attributes, but those may be
|
||||||
|
overridden by an explicitly specified project element.
|
||||||
|
.PP
|
||||||
|
Attribute `name`: A unique name for this project. The project's name is appended
|
||||||
|
onto its remote's fetch URL to generate the actual URL to configure the Git
|
||||||
|
remote with. The URL gets formed as:
|
||||||
|
.IP
|
||||||
|
${remote_fetch}/${project_name}.git
|
||||||
|
.PP
|
||||||
|
where ${remote_fetch} is the remote's fetch attribute and ${project_name} is the
|
||||||
|
project's name attribute. The suffix ".git" is always appended as repo assumes
|
||||||
|
the upstream is a forest of bare Git repositories. If the project has a parent
|
||||||
|
element, its name will be prefixed by the parent's.
|
||||||
|
.PP
|
||||||
|
The project name must match the name Gerrit knows, if Gerrit is being used for
|
||||||
|
code reviews.
|
||||||
|
.PP
|
||||||
|
"name" must not be empty, and may not be an absolute path or use "." or ".."
|
||||||
|
path components. It is always interpreted relative to the remote's fetch
|
||||||
|
settings, so if a different base path is needed, declare a different remote with
|
||||||
|
the new settings needed. These restrictions are not enforced for [Local
|
||||||
|
Manifests].
|
||||||
|
.PP
|
||||||
|
Attribute `path`: An optional path relative to the top directory of the repo
|
||||||
|
client where the Git working directory for this project should be placed. If not
|
||||||
|
supplied the project "name" is used. If the project has a parent element, its
|
||||||
|
path will be prefixed by the parent's.
|
||||||
|
.PP
|
||||||
|
"path" may not be an absolute path or use "." or ".." path components. These
|
||||||
|
restrictions are not enforced for [Local Manifests].
|
||||||
|
.PP
|
||||||
|
If you want to place files into the root of the checkout (e.g. a README or
|
||||||
|
Makefile or another build script), use the [copyfile] or [linkfile] elements
|
||||||
|
instead.
|
||||||
|
.PP
|
||||||
|
Attribute `remote`: Name of a previously defined remote element. If not supplied
|
||||||
|
the remote given by the default element is used.
|
||||||
|
.PP
|
||||||
|
Attribute `revision`: Name of the Git branch the manifest wants to track for
|
||||||
|
this project. Names can be relative to refs/heads (e.g. just "main") or absolute
|
||||||
|
(e.g. "refs/heads/main"). Tags and/or explicit SHA\-1s should work in theory, but
|
||||||
|
have not been extensively tested. If not supplied the revision given by the
|
||||||
|
remote element is used if applicable, else the default element is used.
|
||||||
|
.PP
|
||||||
|
Attribute `dest\-branch`: Name of a Git branch (e.g. `main`). When using `repo
|
||||||
|
upload`, changes will be submitted for code review on this branch. If
|
||||||
|
unspecified both here and in the default element, `revision` is used instead.
|
||||||
|
.PP
|
||||||
|
Attribute `groups`: List of groups to which this project belongs, whitespace or
|
||||||
|
comma separated. All projects belong to the group "all", and each project
|
||||||
|
automatically belongs to a group of its name:`name` and path:`path`. E.g. for
|
||||||
|
`<project name="monkeys" path="barrel\-of"/>`, that project definition is
|
||||||
|
implicitly in the following manifest groups: default, name:monkeys, and
|
||||||
|
path:barrel\-of. If you place a project in the group "notdefault", it will not be
|
||||||
|
automatically downloaded by repo. If the project has a parent element, the
|
||||||
|
`name` and `path` here are the prefixed ones.
|
||||||
|
.PP
|
||||||
|
Attribute `sync\-c`: Set to true to only sync the given Git branch (specified in
|
||||||
|
the `revision` attribute) rather than the whole ref space.
|
||||||
|
.PP
|
||||||
|
Attribute `sync\-s`: Set to true to also sync sub\-projects.
|
||||||
|
.PP
|
||||||
|
Attribute `upstream`: Name of the Git ref in which a sha1 can be found. Used
|
||||||
|
when syncing a revision locked manifest in \fB\-c\fR mode to avoid having to sync the
|
||||||
|
entire ref space.
|
||||||
|
.PP
|
||||||
|
Attribute `clone\-depth`: Set the depth to use when fetching this project. If
|
||||||
|
specified, this value will override any value given to repo init with the
|
||||||
|
\fB\-\-depth\fR option on the command line.
|
||||||
|
.PP
|
||||||
|
Attribute `force\-path`: Set to true to force this project to create the local
|
||||||
|
mirror repository according to its `path` attribute (if supplied) rather than
|
||||||
|
the `name` attribute. This attribute only applies to the local mirrors syncing,
|
||||||
|
it will be ignored when syncing the projects in a client working directory.
|
||||||
|
.PP
|
||||||
|
Element extend\-project
|
||||||
|
.PP
|
||||||
|
Modify the attributes of the named project.
|
||||||
|
.PP
|
||||||
|
This element is mostly useful in a local manifest file, to modify the attributes
|
||||||
|
of an existing project without completely replacing the existing project
|
||||||
|
definition. This makes the local manifest more robust against changes to the
|
||||||
|
original manifest.
|
||||||
|
.PP
|
||||||
|
Attribute `path`: If specified, limit the change to projects checked out at the
|
||||||
|
specified path, rather than all projects with the given name.
|
||||||
|
.PP
|
||||||
|
Attribute `groups`: List of additional groups to which this project belongs.
|
||||||
|
Same syntax as the corresponding element of `project`.
|
||||||
|
.PP
|
||||||
|
Attribute `revision`: If specified, overrides the revision of the original
|
||||||
|
project. Same syntax as the corresponding element of `project`.
|
||||||
|
.PP
|
||||||
|
Attribute `remote`: If specified, overrides the remote of the original project.
|
||||||
|
Same syntax as the corresponding element of `project`.
|
||||||
|
.PP
|
||||||
|
Element annotation
|
||||||
|
.PP
|
||||||
|
Zero or more annotation elements may be specified as children of a project or
|
||||||
|
remote element. Each element describes a name\-value pair. For projects, this
|
||||||
|
name\-value pair will be exported into each project's environment during a
|
||||||
|
\&'forall' command, prefixed with `REPO__`. In addition, there is an optional
|
||||||
|
attribute "keep" which accepts the case insensitive values "true" (default) or
|
||||||
|
"false". This attribute determines whether or not the annotation will be kept
|
||||||
|
when exported with the manifest subcommand.
|
||||||
|
.PP
|
||||||
|
Element copyfile
|
||||||
|
.PP
|
||||||
|
Zero or more copyfile elements may be specified as children of a project
|
||||||
|
element. Each element describes a src\-dest pair of files; the "src" file will be
|
||||||
|
copied to the "dest" place during `repo sync` command.
|
||||||
|
.PP
|
||||||
|
"src" is project relative, "dest" is relative to the top of the tree. Copying
|
||||||
|
from paths outside of the project or to paths outside of the repo client is not
|
||||||
|
allowed.
|
||||||
|
.PP
|
||||||
|
"src" and "dest" must be files. Directories or symlinks are not allowed.
|
||||||
|
Intermediate paths must not be symlinks either.
|
||||||
|
.PP
|
||||||
|
Parent directories of "dest" will be automatically created if missing.
|
||||||
|
.PP
|
||||||
|
Element linkfile
|
||||||
|
.PP
|
||||||
|
It's just like copyfile and runs at the same time as copyfile but instead of
|
||||||
|
copying it creates a symlink.
|
||||||
|
.PP
|
||||||
|
The symlink is created at "dest" (relative to the top of the tree) and points to
|
||||||
|
the path specified by "src" which is a path in the project.
|
||||||
|
.PP
|
||||||
|
Parent directories of "dest" will be automatically created if missing.
|
||||||
|
.PP
|
||||||
|
The symlink target may be a file or directory, but it may not point outside of
|
||||||
|
the repo client.
|
||||||
|
.PP
|
||||||
|
Element remove\-project
|
||||||
|
.PP
|
||||||
|
Deletes the named project from the internal manifest table, possibly allowing a
|
||||||
|
subsequent project element in the same manifest file to replace the project with
|
||||||
|
a different source.
|
||||||
|
.PP
|
||||||
|
This element is mostly useful in a local manifest file, where the user can
|
||||||
|
remove a project, and possibly replace it with their own definition.
|
||||||
|
.PP
|
||||||
|
Attribute `optional`: Set to true to ignore remove\-project elements with no
|
||||||
|
matching `project` element.
|
||||||
|
.PP
|
||||||
|
Element repo\-hooks
|
||||||
|
.PP
|
||||||
|
NB: See the [practical documentation](./repo\-hooks.md) for using repo hooks.
|
||||||
|
.PP
|
||||||
|
Only one repo\-hooks element may be specified at a time. Attempting to redefine
|
||||||
|
it will fail to parse.
|
||||||
|
.PP
|
||||||
|
Attribute `in\-project`: The project where the hooks are defined. The value must
|
||||||
|
match the `name` attribute (**not** the `path` attribute) of a previously
|
||||||
|
defined `project` element.
|
||||||
|
.PP
|
||||||
|
Attribute `enabled\-list`: List of hooks to use, whitespace or comma separated.
|
||||||
|
.PP
|
||||||
|
Element superproject
|
||||||
|
.PP
|
||||||
|
*** *Note*: This is currently a WIP. ***
|
||||||
|
.PP
|
||||||
|
NB: See the [git superprojects documentation](
|
||||||
|
https://en.wikibooks.org/wiki/Git/Submodules_and_Superprojects) for background
|
||||||
|
information.
|
||||||
|
.PP
|
||||||
|
This element is used to specify the URL of the superproject. It has "name" and
|
||||||
|
"remote" as atrributes. Only "name" is required while the others have reasonable
|
||||||
|
defaults. At most one superproject may be specified. Attempting to redefine it
|
||||||
|
will fail to parse.
|
||||||
|
.PP
|
||||||
|
Attribute `name`: A unique name for the superproject. This attribute has the
|
||||||
|
same meaning as project's name attribute. See the [element
|
||||||
|
project](#element\-project) for more information.
|
||||||
|
.PP
|
||||||
|
Attribute `remote`: Name of a previously defined remote element. If not supplied
|
||||||
|
the remote given by the default element is used.
|
||||||
|
.PP
|
||||||
|
Element contactinfo
|
||||||
|
.PP
|
||||||
|
*** *Note*: This is currently a WIP. ***
|
||||||
|
.PP
|
||||||
|
This element is used to let manifest authors self\-register contact info. It has
|
||||||
|
"bugurl" as a required atrribute. This element can be repeated, and any later
|
||||||
|
entries will clobber earlier ones. This would allow manifest authors who extend
|
||||||
|
manifests to specify their own contact info.
|
||||||
|
.PP
|
||||||
|
Attribute `bugurl`: The URL to file a bug against the manifest owner.
|
||||||
|
.PP
|
||||||
|
Element include
|
||||||
|
.PP
|
||||||
|
This element provides the capability of including another manifest file into the
|
||||||
|
originating manifest. Normal rules apply for the target manifest to include \- it
|
||||||
|
must be a usable manifest on its own.
|
||||||
|
.PP
|
||||||
|
Attribute `name`: the manifest to include, specified relative to the manifest
|
||||||
|
repository's root.
|
||||||
|
.PP
|
||||||
|
"name" may not be an absolute path or use "." or ".." path components. These
|
||||||
|
restrictions are not enforced for [Local Manifests].
|
||||||
|
.PP
|
||||||
|
Attribute `groups`: List of additional groups to which all projects in the
|
||||||
|
included manifest belong. This appends and recurses, meaning all projects in
|
||||||
|
sub\-manifests carry all parent include groups. Same syntax as the corresponding
|
||||||
|
element of `project`.
|
||||||
|
.PP
|
||||||
|
Local Manifests
|
||||||
|
.PP
|
||||||
|
Additional remotes and projects may be added through local manifest files stored
|
||||||
|
in `$TOP_DIR/.repo/local_manifests/*.xml`.
|
||||||
|
.PP
|
||||||
|
For example:
|
||||||
|
.IP
|
||||||
|
\f(CW$ ls .repo/local_manifests\fR
|
||||||
|
.IP
|
||||||
|
local_manifest.xml
|
||||||
|
another_local_manifest.xml
|
||||||
|
.IP
|
||||||
|
\f(CW$ cat .repo/local_manifests/local_manifest.xml\fR
|
||||||
|
.IP
|
||||||
|
<?xml version="1.0" encoding="UTF\-8"?>
|
||||||
|
<manifest>
|
||||||
|
.IP
|
||||||
|
<project path="manifest"
|
||||||
|
.IP
|
||||||
|
name="tools/manifest" />
|
||||||
|
.IP
|
||||||
|
<project path="platform\-manifest"
|
||||||
|
.IP
|
||||||
|
name="platform/manifest" />
|
||||||
|
.IP
|
||||||
|
</manifest>
|
||||||
|
.PP
|
||||||
|
Users may add projects to the local manifest(s) prior to a `repo sync`
|
||||||
|
invocation, instructing repo to automatically download and manage these extra
|
||||||
|
projects.
|
||||||
|
.PP
|
||||||
|
Manifest files stored in `$TOP_DIR/.repo/local_manifests/*.xml` will be loaded
|
||||||
|
in alphabetical order.
|
||||||
|
.PP
|
||||||
|
Projects from local manifest files are added into local::<local manifest
|
||||||
|
filename> group.
|
||||||
|
.PP
|
||||||
|
The legacy `$TOP_DIR/.repo/local_manifest.xml` path is no longer supported.
|
||||||
|
.SS [copyfile]: #Element\-copyfile [linkfile]: #Element\-linkfile [Local Manifests]:
|
||||||
|
.PP
|
||||||
|
#local\-manifests
|
39
man/repo-overview.1
Normal file
39
man/repo-overview.1
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man.
|
||||||
|
.TH REPO "1" "July 2021" "repo overview" "Repo Manual"
|
||||||
|
.SH NAME
|
||||||
|
repo \- repo overview - manual page for repo overview
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B repo
|
||||||
|
\fI\,overview \/\fR[\fI\,--current-branch\/\fR] [\fI\,<project>\/\fR...]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
Summary
|
||||||
|
.PP
|
||||||
|
Display overview of unmerged project branches
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
\fB\-h\fR, \fB\-\-help\fR
|
||||||
|
show this help message and exit
|
||||||
|
.TP
|
||||||
|
\fB\-c\fR, \fB\-\-current\-branch\fR
|
||||||
|
consider only checked out branches
|
||||||
|
.TP
|
||||||
|
\fB\-\-no\-current\-branch\fR
|
||||||
|
consider all local branches
|
||||||
|
.SS Logging options:
|
||||||
|
.TP
|
||||||
|
\fB\-v\fR, \fB\-\-verbose\fR
|
||||||
|
show all output
|
||||||
|
.TP
|
||||||
|
\fB\-q\fR, \fB\-\-quiet\fR
|
||||||
|
only show errors
|
||||||
|
.PP
|
||||||
|
Run `repo help overview` to view the detailed manual.
|
||||||
|
.SH DETAILS
|
||||||
|
.PP
|
||||||
|
The 'repo overview' command is used to display an overview of the projects
|
||||||
|
branches, and list any local commits that have not yet been merged into the
|
||||||
|
project.
|
||||||
|
.PP
|
||||||
|
The \fB\-c\fR/\-\-current\-branch option can be used to restrict the output to only
|
||||||
|
branches currently checked out in each project. By default, all branches are
|
||||||
|
displayed.
|
27
man/repo-prune.1
Normal file
27
man/repo-prune.1
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man.
|
||||||
|
.TH REPO "1" "July 2021" "repo prune" "Repo Manual"
|
||||||
|
.SH NAME
|
||||||
|
repo \- repo prune - manual page for repo prune
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B repo
|
||||||
|
\fI\,prune \/\fR[\fI\,<project>\/\fR...]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
Summary
|
||||||
|
.PP
|
||||||
|
Prune (delete) already merged topics
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
\fB\-h\fR, \fB\-\-help\fR
|
||||||
|
show this help message and exit
|
||||||
|
.TP
|
||||||
|
\fB\-j\fR JOBS, \fB\-\-jobs\fR=\fI\,JOBS\/\fR
|
||||||
|
number of jobs to run in parallel (default: 4)
|
||||||
|
.SS Logging options:
|
||||||
|
.TP
|
||||||
|
\fB\-v\fR, \fB\-\-verbose\fR
|
||||||
|
show all output
|
||||||
|
.TP
|
||||||
|
\fB\-q\fR, \fB\-\-quiet\fR
|
||||||
|
only show errors
|
||||||
|
.PP
|
||||||
|
Run `repo help prune` to view the detailed manual.
|
55
man/repo-rebase.1
Normal file
55
man/repo-rebase.1
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man.
|
||||||
|
.TH REPO "1" "July 2021" "repo rebase" "Repo Manual"
|
||||||
|
.SH NAME
|
||||||
|
repo \- repo rebase - manual page for repo rebase
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B repo
|
||||||
|
\fI\,rebase {\/\fR[\fI\,<project>\/\fR...] \fI\,| -i <project>\/\fR...\fI\,}\/\fR
|
||||||
|
.SH DESCRIPTION
|
||||||
|
Summary
|
||||||
|
.PP
|
||||||
|
Rebase local branches on upstream branch
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
\fB\-h\fR, \fB\-\-help\fR
|
||||||
|
show this help message and exit
|
||||||
|
.TP
|
||||||
|
\fB\-\-fail\-fast\fR
|
||||||
|
stop rebasing after first error is hit
|
||||||
|
.TP
|
||||||
|
\fB\-f\fR, \fB\-\-force\-rebase\fR
|
||||||
|
pass \fB\-\-force\-rebase\fR to git rebase
|
||||||
|
.TP
|
||||||
|
\fB\-\-no\-ff\fR
|
||||||
|
pass \fB\-\-no\-ff\fR to git rebase
|
||||||
|
.TP
|
||||||
|
\fB\-\-autosquash\fR
|
||||||
|
pass \fB\-\-autosquash\fR to git rebase
|
||||||
|
.TP
|
||||||
|
\fB\-\-whitespace\fR=\fI\,WS\/\fR
|
||||||
|
pass \fB\-\-whitespace\fR to git rebase
|
||||||
|
.TP
|
||||||
|
\fB\-\-auto\-stash\fR
|
||||||
|
stash local modifications before starting
|
||||||
|
.TP
|
||||||
|
\fB\-m\fR, \fB\-\-onto\-manifest\fR
|
||||||
|
rebase onto the manifest version instead of upstream
|
||||||
|
HEAD (this helps to make sure the local tree stays
|
||||||
|
consistent if you previously synced to a manifest)
|
||||||
|
.SS Logging options:
|
||||||
|
.TP
|
||||||
|
\fB\-v\fR, \fB\-\-verbose\fR
|
||||||
|
show all output
|
||||||
|
.TP
|
||||||
|
\fB\-q\fR, \fB\-\-quiet\fR
|
||||||
|
only show errors
|
||||||
|
.TP
|
||||||
|
\fB\-i\fR, \fB\-\-interactive\fR
|
||||||
|
interactive rebase (single project only)
|
||||||
|
.PP
|
||||||
|
Run `repo help rebase` to view the detailed manual.
|
||||||
|
.SH DETAILS
|
||||||
|
.PP
|
||||||
|
\&'repo rebase' uses git rebase to move local changes in the current topic branch
|
||||||
|
to the HEAD of the upstream history, useful when you have made commits in a
|
||||||
|
topic branch but need to incorporate new upstream changes "underneath" them.
|
35
man/repo-selfupdate.1
Normal file
35
man/repo-selfupdate.1
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man.
|
||||||
|
.TH REPO "1" "July 2021" "repo selfupdate" "Repo Manual"
|
||||||
|
.SH NAME
|
||||||
|
repo \- repo selfupdate - manual page for repo selfupdate
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B repo
|
||||||
|
\fI\,selfupdate\/\fR
|
||||||
|
.SH DESCRIPTION
|
||||||
|
Summary
|
||||||
|
.PP
|
||||||
|
Update repo to the latest version
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
\fB\-h\fR, \fB\-\-help\fR
|
||||||
|
show this help message and exit
|
||||||
|
.SS Logging options:
|
||||||
|
.TP
|
||||||
|
\fB\-v\fR, \fB\-\-verbose\fR
|
||||||
|
show all output
|
||||||
|
.TP
|
||||||
|
\fB\-q\fR, \fB\-\-quiet\fR
|
||||||
|
only show errors
|
||||||
|
.SS repo Version options:
|
||||||
|
.TP
|
||||||
|
\fB\-\-no\-repo\-verify\fR
|
||||||
|
do not verify repo source code
|
||||||
|
.PP
|
||||||
|
Run `repo help selfupdate` to view the detailed manual.
|
||||||
|
.SH DETAILS
|
||||||
|
.PP
|
||||||
|
The 'repo selfupdate' command upgrades repo to the latest version, if a newer
|
||||||
|
version is available.
|
||||||
|
.PP
|
||||||
|
Normally this is done automatically by 'repo sync' and does not need to be
|
||||||
|
performed by an end\-user.
|
117
man/repo-smartsync.1
Normal file
117
man/repo-smartsync.1
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man.
|
||||||
|
.TH REPO "1" "July 2021" "repo smartsync" "Repo Manual"
|
||||||
|
.SH NAME
|
||||||
|
repo \- repo smartsync - manual page for repo smartsync
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B repo
|
||||||
|
\fI\,smartsync \/\fR[\fI\,<project>\/\fR...]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
Summary
|
||||||
|
.PP
|
||||||
|
Update working tree to the latest known good revision
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
\fB\-h\fR, \fB\-\-help\fR
|
||||||
|
show this help message and exit
|
||||||
|
.TP
|
||||||
|
\fB\-j\fR JOBS, \fB\-\-jobs\fR=\fI\,JOBS\/\fR
|
||||||
|
number of jobs to run in parallel (default: 1)
|
||||||
|
.TP
|
||||||
|
\fB\-\-jobs\-network\fR=\fI\,JOBS\/\fR
|
||||||
|
number of network jobs to run in parallel (defaults to
|
||||||
|
\fB\-\-jobs\fR)
|
||||||
|
.TP
|
||||||
|
\fB\-\-jobs\-checkout\fR=\fI\,JOBS\/\fR
|
||||||
|
number of local checkout jobs to run in parallel
|
||||||
|
(defaults to \fB\-\-jobs\fR)
|
||||||
|
.TP
|
||||||
|
\fB\-f\fR, \fB\-\-force\-broken\fR
|
||||||
|
obsolete option (to be deleted in the future)
|
||||||
|
.TP
|
||||||
|
\fB\-\-fail\-fast\fR
|
||||||
|
stop syncing after first error is hit
|
||||||
|
.TP
|
||||||
|
\fB\-\-force\-sync\fR
|
||||||
|
overwrite an existing git directory if it needs to
|
||||||
|
point to a different object directory. WARNING: this
|
||||||
|
may cause loss of data
|
||||||
|
.TP
|
||||||
|
\fB\-\-force\-remove\-dirty\fR
|
||||||
|
force remove projects with uncommitted modifications
|
||||||
|
if projects no longer exist in the manifest. WARNING:
|
||||||
|
this may cause loss of data
|
||||||
|
.TP
|
||||||
|
\fB\-l\fR, \fB\-\-local\-only\fR
|
||||||
|
only update working tree, don't fetch
|
||||||
|
.TP
|
||||||
|
\fB\-\-no\-manifest\-update\fR, \fB\-\-nmu\fR
|
||||||
|
use the existing manifest checkout as\-is. (do not
|
||||||
|
update to the latest revision)
|
||||||
|
.TP
|
||||||
|
\fB\-n\fR, \fB\-\-network\-only\fR
|
||||||
|
fetch only, don't update working tree
|
||||||
|
.TP
|
||||||
|
\fB\-d\fR, \fB\-\-detach\fR
|
||||||
|
detach projects back to manifest revision
|
||||||
|
.TP
|
||||||
|
\fB\-c\fR, \fB\-\-current\-branch\fR
|
||||||
|
fetch only current branch from server
|
||||||
|
.TP
|
||||||
|
\fB\-\-no\-current\-branch\fR
|
||||||
|
fetch all branches from server
|
||||||
|
.TP
|
||||||
|
\fB\-m\fR NAME.xml, \fB\-\-manifest\-name\fR=\fI\,NAME\/\fR.xml
|
||||||
|
temporary manifest to use for this sync
|
||||||
|
.TP
|
||||||
|
\fB\-\-clone\-bundle\fR
|
||||||
|
enable use of \fI\,/clone.bundle\/\fP on HTTP/HTTPS
|
||||||
|
.TP
|
||||||
|
\fB\-\-no\-clone\-bundle\fR
|
||||||
|
disable use of \fI\,/clone.bundle\/\fP on HTTP/HTTPS
|
||||||
|
.TP
|
||||||
|
\fB\-u\fR MANIFEST_SERVER_USERNAME, \fB\-\-manifest\-server\-username\fR=\fI\,MANIFEST_SERVER_USERNAME\/\fR
|
||||||
|
username to authenticate with the manifest server
|
||||||
|
.TP
|
||||||
|
\fB\-p\fR MANIFEST_SERVER_PASSWORD, \fB\-\-manifest\-server\-password\fR=\fI\,MANIFEST_SERVER_PASSWORD\/\fR
|
||||||
|
password to authenticate with the manifest server
|
||||||
|
.TP
|
||||||
|
\fB\-\-fetch\-submodules\fR
|
||||||
|
fetch submodules from server
|
||||||
|
.TP
|
||||||
|
\fB\-\-use\-superproject\fR
|
||||||
|
use the manifest superproject to sync projects
|
||||||
|
.TP
|
||||||
|
\fB\-\-no\-use\-superproject\fR
|
||||||
|
disable use of manifest superprojects
|
||||||
|
.TP
|
||||||
|
\fB\-\-tags\fR
|
||||||
|
fetch tags
|
||||||
|
.TP
|
||||||
|
\fB\-\-no\-tags\fR
|
||||||
|
don't fetch tags
|
||||||
|
.TP
|
||||||
|
\fB\-\-optimized\-fetch\fR
|
||||||
|
only fetch projects fixed to sha1 if revision does not
|
||||||
|
exist locally
|
||||||
|
.TP
|
||||||
|
\fB\-\-retry\-fetches\fR=\fI\,RETRY_FETCHES\/\fR
|
||||||
|
number of times to retry fetches on transient errors
|
||||||
|
.TP
|
||||||
|
\fB\-\-prune\fR
|
||||||
|
delete refs that no longer exist on the remote
|
||||||
|
.SS Logging options:
|
||||||
|
.TP
|
||||||
|
\fB\-v\fR, \fB\-\-verbose\fR
|
||||||
|
show all output
|
||||||
|
.TP
|
||||||
|
\fB\-q\fR, \fB\-\-quiet\fR
|
||||||
|
only show errors
|
||||||
|
.SS repo Version options:
|
||||||
|
.TP
|
||||||
|
\fB\-\-no\-repo\-verify\fR
|
||||||
|
do not verify repo source code
|
||||||
|
.PP
|
||||||
|
Run `repo help smartsync` to view the detailed manual.
|
||||||
|
.SH DETAILS
|
||||||
|
.PP
|
||||||
|
The 'repo smartsync' command is a shortcut for sync \fB\-s\fR.
|
30
man/repo-stage.1
Normal file
30
man/repo-stage.1
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man.
|
||||||
|
.TH REPO "1" "July 2021" "repo stage" "Repo Manual"
|
||||||
|
.SH NAME
|
||||||
|
repo \- repo stage - manual page for repo stage
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B repo
|
||||||
|
\fI\,stage -i \/\fR[\fI\,<project>\/\fR...]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
Summary
|
||||||
|
.PP
|
||||||
|
Stage file(s) for commit
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
\fB\-h\fR, \fB\-\-help\fR
|
||||||
|
show this help message and exit
|
||||||
|
.SS Logging options:
|
||||||
|
.TP
|
||||||
|
\fB\-v\fR, \fB\-\-verbose\fR
|
||||||
|
show all output
|
||||||
|
.TP
|
||||||
|
\fB\-q\fR, \fB\-\-quiet\fR
|
||||||
|
only show errors
|
||||||
|
.TP
|
||||||
|
\fB\-i\fR, \fB\-\-interactive\fR
|
||||||
|
use interactive staging
|
||||||
|
.PP
|
||||||
|
Run `repo help stage` to view the detailed manual.
|
||||||
|
.SH DETAILS
|
||||||
|
.PP
|
||||||
|
The 'repo stage' command stages files to prepare the next commit.
|
40
man/repo-start.1
Normal file
40
man/repo-start.1
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man.
|
||||||
|
.TH REPO "1" "July 2021" "repo start" "Repo Manual"
|
||||||
|
.SH NAME
|
||||||
|
repo \- repo start - manual page for repo start
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B repo
|
||||||
|
\fI\,start <newbranchname> \/\fR[\fI\,--all | <project>\/\fR...]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
Summary
|
||||||
|
.PP
|
||||||
|
Start a new branch for development
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
\fB\-h\fR, \fB\-\-help\fR
|
||||||
|
show this help message and exit
|
||||||
|
.TP
|
||||||
|
\fB\-j\fR JOBS, \fB\-\-jobs\fR=\fI\,JOBS\/\fR
|
||||||
|
number of jobs to run in parallel (default: 4)
|
||||||
|
.TP
|
||||||
|
\fB\-\-all\fR
|
||||||
|
begin branch in all projects
|
||||||
|
.TP
|
||||||
|
\fB\-r\fR REVISION, \fB\-\-rev\fR=\fI\,REVISION\/\fR, \fB\-\-revision\fR=\fI\,REVISION\/\fR
|
||||||
|
point branch at this revision instead of upstream
|
||||||
|
.TP
|
||||||
|
\fB\-\-head\fR, \fB\-\-HEAD\fR
|
||||||
|
abbreviation for \fB\-\-rev\fR HEAD
|
||||||
|
.SS Logging options:
|
||||||
|
.TP
|
||||||
|
\fB\-v\fR, \fB\-\-verbose\fR
|
||||||
|
show all output
|
||||||
|
.TP
|
||||||
|
\fB\-q\fR, \fB\-\-quiet\fR
|
||||||
|
only show errors
|
||||||
|
.PP
|
||||||
|
Run `repo help start` to view the detailed manual.
|
||||||
|
.SH DETAILS
|
||||||
|
.PP
|
||||||
|
\&'repo start' begins a new branch of development, starting from the revision
|
||||||
|
specified in the manifest.
|
97
man/repo-status.1
Normal file
97
man/repo-status.1
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man.
|
||||||
|
.TH REPO "1" "July 2021" "repo status" "Repo Manual"
|
||||||
|
.SH NAME
|
||||||
|
repo \- repo status - manual page for repo status
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B repo
|
||||||
|
\fI\,status \/\fR[\fI\,<project>\/\fR...]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
Summary
|
||||||
|
.PP
|
||||||
|
Show the working tree status
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
\fB\-h\fR, \fB\-\-help\fR
|
||||||
|
show this help message and exit
|
||||||
|
.TP
|
||||||
|
\fB\-j\fR JOBS, \fB\-\-jobs\fR=\fI\,JOBS\/\fR
|
||||||
|
number of jobs to run in parallel (default: 4)
|
||||||
|
.TP
|
||||||
|
\fB\-o\fR, \fB\-\-orphans\fR
|
||||||
|
include objects in working directory outside of repo
|
||||||
|
projects
|
||||||
|
.SS Logging options:
|
||||||
|
.TP
|
||||||
|
\fB\-v\fR, \fB\-\-verbose\fR
|
||||||
|
show all output
|
||||||
|
.TP
|
||||||
|
\fB\-q\fR, \fB\-\-quiet\fR
|
||||||
|
only show errors
|
||||||
|
.PP
|
||||||
|
Run `repo help status` to view the detailed manual.
|
||||||
|
.SH DETAILS
|
||||||
|
.PP
|
||||||
|
\&'repo status' compares the working tree to the staging area (aka index), and the
|
||||||
|
most recent commit on this branch (HEAD), in each project specified. A summary
|
||||||
|
is displayed, one line per file where there is a difference between these three
|
||||||
|
states.
|
||||||
|
.PP
|
||||||
|
The \fB\-j\fR/\-\-jobs option can be used to run multiple status queries in parallel.
|
||||||
|
.PP
|
||||||
|
The \fB\-o\fR/\-\-orphans option can be used to show objects that are in the working
|
||||||
|
directory, but not associated with a repo project. This includes unmanaged
|
||||||
|
top\-level files and directories, but also includes deeper items. For example, if
|
||||||
|
dir/subdir/proj1 and dir/subdir/proj2 are repo projects, dir/subdir/proj3 will
|
||||||
|
be shown if it is not known to repo.
|
||||||
|
.PP
|
||||||
|
Status Display
|
||||||
|
.PP
|
||||||
|
The status display is organized into three columns of information, for example
|
||||||
|
if the file 'subcmds/status.py' is modified in the project 'repo' on branch
|
||||||
|
\&'devwork':
|
||||||
|
.TP
|
||||||
|
project repo/
|
||||||
|
branch devwork
|
||||||
|
.TP
|
||||||
|
\fB\-m\fR
|
||||||
|
subcmds/status.py
|
||||||
|
.PP
|
||||||
|
The first column explains how the staging area (index) differs from the last
|
||||||
|
commit (HEAD). Its values are always displayed in upper case and have the
|
||||||
|
following meanings:
|
||||||
|
.TP
|
||||||
|
\-:
|
||||||
|
no difference
|
||||||
|
.TP
|
||||||
|
A:
|
||||||
|
added (not in HEAD, in index )
|
||||||
|
.TP
|
||||||
|
M:
|
||||||
|
modified ( in HEAD, in index, different content )
|
||||||
|
.TP
|
||||||
|
D:
|
||||||
|
deleted ( in HEAD, not in index )
|
||||||
|
.TP
|
||||||
|
R:
|
||||||
|
renamed (not in HEAD, in index, path changed )
|
||||||
|
.TP
|
||||||
|
C:
|
||||||
|
copied (not in HEAD, in index, copied from another)
|
||||||
|
.TP
|
||||||
|
T:
|
||||||
|
mode changed ( in HEAD, in index, same content )
|
||||||
|
.TP
|
||||||
|
U:
|
||||||
|
unmerged; conflict resolution required
|
||||||
|
.PP
|
||||||
|
The second column explains how the working directory differs from the index. Its
|
||||||
|
values are always displayed in lower case and have the following meanings:
|
||||||
|
.TP
|
||||||
|
\-:
|
||||||
|
new / unknown (not in index, in work tree )
|
||||||
|
.TP
|
||||||
|
m:
|
||||||
|
modified ( in index, in work tree, modified )
|
||||||
|
.TP
|
||||||
|
d:
|
||||||
|
deleted ( in index, not in work tree )
|
208
man/repo-sync.1
Normal file
208
man/repo-sync.1
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man.
|
||||||
|
.TH REPO "1" "July 2021" "repo sync" "Repo Manual"
|
||||||
|
.SH NAME
|
||||||
|
repo \- repo sync - manual page for repo sync
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B repo
|
||||||
|
\fI\,sync \/\fR[\fI\,<project>\/\fR...]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
Summary
|
||||||
|
.PP
|
||||||
|
Update working tree to the latest revision
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
\fB\-h\fR, \fB\-\-help\fR
|
||||||
|
show this help message and exit
|
||||||
|
.TP
|
||||||
|
\fB\-j\fR JOBS, \fB\-\-jobs\fR=\fI\,JOBS\/\fR
|
||||||
|
number of jobs to run in parallel (default: 1)
|
||||||
|
.TP
|
||||||
|
\fB\-\-jobs\-network\fR=\fI\,JOBS\/\fR
|
||||||
|
number of network jobs to run in parallel (defaults to
|
||||||
|
\fB\-\-jobs\fR)
|
||||||
|
.TP
|
||||||
|
\fB\-\-jobs\-checkout\fR=\fI\,JOBS\/\fR
|
||||||
|
number of local checkout jobs to run in parallel
|
||||||
|
(defaults to \fB\-\-jobs\fR)
|
||||||
|
.TP
|
||||||
|
\fB\-f\fR, \fB\-\-force\-broken\fR
|
||||||
|
obsolete option (to be deleted in the future)
|
||||||
|
.TP
|
||||||
|
\fB\-\-fail\-fast\fR
|
||||||
|
stop syncing after first error is hit
|
||||||
|
.TP
|
||||||
|
\fB\-\-force\-sync\fR
|
||||||
|
overwrite an existing git directory if it needs to
|
||||||
|
point to a different object directory. WARNING: this
|
||||||
|
may cause loss of data
|
||||||
|
.TP
|
||||||
|
\fB\-\-force\-remove\-dirty\fR
|
||||||
|
force remove projects with uncommitted modifications
|
||||||
|
if projects no longer exist in the manifest. WARNING:
|
||||||
|
this may cause loss of data
|
||||||
|
.TP
|
||||||
|
\fB\-l\fR, \fB\-\-local\-only\fR
|
||||||
|
only update working tree, don't fetch
|
||||||
|
.TP
|
||||||
|
\fB\-\-no\-manifest\-update\fR, \fB\-\-nmu\fR
|
||||||
|
use the existing manifest checkout as\-is. (do not
|
||||||
|
update to the latest revision)
|
||||||
|
.TP
|
||||||
|
\fB\-n\fR, \fB\-\-network\-only\fR
|
||||||
|
fetch only, don't update working tree
|
||||||
|
.TP
|
||||||
|
\fB\-d\fR, \fB\-\-detach\fR
|
||||||
|
detach projects back to manifest revision
|
||||||
|
.TP
|
||||||
|
\fB\-c\fR, \fB\-\-current\-branch\fR
|
||||||
|
fetch only current branch from server
|
||||||
|
.TP
|
||||||
|
\fB\-\-no\-current\-branch\fR
|
||||||
|
fetch all branches from server
|
||||||
|
.TP
|
||||||
|
\fB\-m\fR NAME.xml, \fB\-\-manifest\-name\fR=\fI\,NAME\/\fR.xml
|
||||||
|
temporary manifest to use for this sync
|
||||||
|
.TP
|
||||||
|
\fB\-\-clone\-bundle\fR
|
||||||
|
enable use of \fI\,/clone.bundle\/\fP on HTTP/HTTPS
|
||||||
|
.TP
|
||||||
|
\fB\-\-no\-clone\-bundle\fR
|
||||||
|
disable use of \fI\,/clone.bundle\/\fP on HTTP/HTTPS
|
||||||
|
.TP
|
||||||
|
\fB\-u\fR MANIFEST_SERVER_USERNAME, \fB\-\-manifest\-server\-username\fR=\fI\,MANIFEST_SERVER_USERNAME\/\fR
|
||||||
|
username to authenticate with the manifest server
|
||||||
|
.TP
|
||||||
|
\fB\-p\fR MANIFEST_SERVER_PASSWORD, \fB\-\-manifest\-server\-password\fR=\fI\,MANIFEST_SERVER_PASSWORD\/\fR
|
||||||
|
password to authenticate with the manifest server
|
||||||
|
.TP
|
||||||
|
\fB\-\-fetch\-submodules\fR
|
||||||
|
fetch submodules from server
|
||||||
|
.TP
|
||||||
|
\fB\-\-use\-superproject\fR
|
||||||
|
use the manifest superproject to sync projects
|
||||||
|
.TP
|
||||||
|
\fB\-\-no\-use\-superproject\fR
|
||||||
|
disable use of manifest superprojects
|
||||||
|
.TP
|
||||||
|
\fB\-\-tags\fR
|
||||||
|
fetch tags
|
||||||
|
.TP
|
||||||
|
\fB\-\-no\-tags\fR
|
||||||
|
don't fetch tags
|
||||||
|
.TP
|
||||||
|
\fB\-\-optimized\-fetch\fR
|
||||||
|
only fetch projects fixed to sha1 if revision does not
|
||||||
|
exist locally
|
||||||
|
.TP
|
||||||
|
\fB\-\-retry\-fetches\fR=\fI\,RETRY_FETCHES\/\fR
|
||||||
|
number of times to retry fetches on transient errors
|
||||||
|
.TP
|
||||||
|
\fB\-\-prune\fR
|
||||||
|
delete refs that no longer exist on the remote
|
||||||
|
.TP
|
||||||
|
\fB\-s\fR, \fB\-\-smart\-sync\fR
|
||||||
|
smart sync using manifest from the latest known good
|
||||||
|
build
|
||||||
|
.TP
|
||||||
|
\fB\-t\fR SMART_TAG, \fB\-\-smart\-tag\fR=\fI\,SMART_TAG\/\fR
|
||||||
|
smart sync using manifest from a known tag
|
||||||
|
.SS Logging options:
|
||||||
|
.TP
|
||||||
|
\fB\-v\fR, \fB\-\-verbose\fR
|
||||||
|
show all output
|
||||||
|
.TP
|
||||||
|
\fB\-q\fR, \fB\-\-quiet\fR
|
||||||
|
only show errors
|
||||||
|
.SS repo Version options:
|
||||||
|
.TP
|
||||||
|
\fB\-\-no\-repo\-verify\fR
|
||||||
|
do not verify repo source code
|
||||||
|
.PP
|
||||||
|
Run `repo help sync` to view the detailed manual.
|
||||||
|
.SH DETAILS
|
||||||
|
.PP
|
||||||
|
The 'repo sync' command synchronizes local project directories with the remote
|
||||||
|
repositories specified in the manifest. If a local project does not yet exist,
|
||||||
|
it will clone a new local directory from the remote repository and set up
|
||||||
|
tracking branches as specified in the manifest. If the local project already
|
||||||
|
exists, 'repo sync' will update the remote branches and rebase any new local
|
||||||
|
changes on top of the new remote changes.
|
||||||
|
.PP
|
||||||
|
\&'repo sync' will synchronize all projects listed at the command line. Projects
|
||||||
|
can be specified either by name, or by a relative or absolute path to the
|
||||||
|
project's local directory. If no projects are specified, 'repo sync' will
|
||||||
|
synchronize all projects listed in the manifest.
|
||||||
|
.PP
|
||||||
|
The \fB\-d\fR/\-\-detach option can be used to switch specified projects back to the
|
||||||
|
manifest revision. This option is especially helpful if the project is currently
|
||||||
|
on a topic branch, but the manifest revision is temporarily needed.
|
||||||
|
.PP
|
||||||
|
The \fB\-s\fR/\-\-smart\-sync option can be used to sync to a known good build as
|
||||||
|
specified by the manifest\-server element in the current manifest. The
|
||||||
|
\fB\-t\fR/\-\-smart\-tag option is similar and allows you to specify a custom tag/label.
|
||||||
|
.PP
|
||||||
|
The \fB\-u\fR/\-\-manifest\-server\-username and \fB\-p\fR/\-\-manifest\-server\-password options can
|
||||||
|
be used to specify a username and password to authenticate with the manifest
|
||||||
|
server when using the \fB\-s\fR or \fB\-t\fR option.
|
||||||
|
.PP
|
||||||
|
If \fB\-u\fR and \fB\-p\fR are not specified when using the \fB\-s\fR or \fB\-t\fR option, 'repo sync' will
|
||||||
|
attempt to read authentication credentials for the manifest server from the
|
||||||
|
user's .netrc file.
|
||||||
|
.PP
|
||||||
|
\&'repo sync' will not use authentication credentials from \fB\-u\fR/\-p or .netrc if the
|
||||||
|
manifest server specified in the manifest file already includes credentials.
|
||||||
|
.PP
|
||||||
|
By default, all projects will be synced. The \fB\-\-fail\-fast\fR option can be used to
|
||||||
|
halt syncing as soon as possible when the first project fails to sync.
|
||||||
|
.PP
|
||||||
|
The \fB\-\-force\-sync\fR option can be used to overwrite existing git directories if
|
||||||
|
they have previously been linked to a different object directory. WARNING: This
|
||||||
|
may cause data to be lost since refs may be removed when overwriting.
|
||||||
|
.PP
|
||||||
|
The \fB\-\-force\-remove\-dirty\fR option can be used to remove previously used projects
|
||||||
|
with uncommitted changes. WARNING: This may cause data to be lost since
|
||||||
|
uncommitted changes may be removed with projects that no longer exist in the
|
||||||
|
manifest.
|
||||||
|
.PP
|
||||||
|
The \fB\-\-no\-clone\-bundle\fR option disables any attempt to use \fI\,$URL/clone.bundle\/\fP to
|
||||||
|
bootstrap a new Git repository from a resumeable bundle file on a content
|
||||||
|
delivery network. This may be necessary if there are problems with the local
|
||||||
|
Python HTTP client or proxy configuration, but the Git binary works.
|
||||||
|
.PP
|
||||||
|
The \fB\-\-fetch\-submodules\fR option enables fetching Git submodules of a project from
|
||||||
|
server.
|
||||||
|
.PP
|
||||||
|
The \fB\-c\fR/\-\-current\-branch option can be used to only fetch objects that are on the
|
||||||
|
branch specified by a project's revision.
|
||||||
|
.PP
|
||||||
|
The \fB\-\-optimized\-fetch\fR option can be used to only fetch projects that are fixed
|
||||||
|
to a sha1 revision if the sha1 revision does not already exist locally.
|
||||||
|
.PP
|
||||||
|
The \fB\-\-prune\fR option can be used to remove any refs that no longer exist on the
|
||||||
|
remote.
|
||||||
|
.PP
|
||||||
|
SSH Connections
|
||||||
|
.PP
|
||||||
|
If at least one project remote URL uses an SSH connection (ssh://, git+ssh://,
|
||||||
|
or user@host:path syntax) repo will automatically enable the SSH ControlMaster
|
||||||
|
option when connecting to that host. This feature permits other projects in the
|
||||||
|
same 'repo sync' session to reuse the same SSH tunnel, saving connection setup
|
||||||
|
overheads.
|
||||||
|
.PP
|
||||||
|
To disable this behavior on UNIX platforms, set the GIT_SSH environment variable
|
||||||
|
to 'ssh'. For example:
|
||||||
|
.IP
|
||||||
|
export GIT_SSH=ssh
|
||||||
|
repo sync
|
||||||
|
.PP
|
||||||
|
Compatibility
|
||||||
|
.PP
|
||||||
|
This feature is automatically disabled on Windows, due to the lack of UNIX
|
||||||
|
domain socket support.
|
||||||
|
.PP
|
||||||
|
This feature is not compatible with url.insteadof rewrites in the user's
|
||||||
|
~/.gitconfig. 'repo sync' is currently not able to perform the rewrite early
|
||||||
|
enough to establish the ControlMaster tunnel.
|
||||||
|
.PP
|
||||||
|
If the remote SSH daemon is Gerrit Code Review, version 2.0.10 or later is
|
||||||
|
required to fix a server side protocol bug.
|
174
man/repo-upload.1
Normal file
174
man/repo-upload.1
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man.
|
||||||
|
.TH REPO "1" "July 2021" "repo upload" "Repo Manual"
|
||||||
|
.SH NAME
|
||||||
|
repo \- repo upload - manual page for repo upload
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B repo
|
||||||
|
\fI\,upload \/\fR[\fI\,--re --cc\/\fR] [\fI\,<project>\/\fR]...
|
||||||
|
.SH DESCRIPTION
|
||||||
|
Summary
|
||||||
|
.PP
|
||||||
|
Upload changes for code review
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
\fB\-h\fR, \fB\-\-help\fR
|
||||||
|
show this help message and exit
|
||||||
|
.TP
|
||||||
|
\fB\-j\fR JOBS, \fB\-\-jobs\fR=\fI\,JOBS\/\fR
|
||||||
|
number of jobs to run in parallel (default: 4)
|
||||||
|
.TP
|
||||||
|
\fB\-t\fR
|
||||||
|
send local branch name to Gerrit Code Review
|
||||||
|
.TP
|
||||||
|
\fB\-\-hashtag\fR=\fI\,HASHTAGS\/\fR, \fB\-\-ht\fR=\fI\,HASHTAGS\/\fR
|
||||||
|
add hashtags (comma delimited) to the review
|
||||||
|
.TP
|
||||||
|
\fB\-\-hashtag\-branch\fR, \fB\-\-htb\fR
|
||||||
|
add local branch name as a hashtag
|
||||||
|
.TP
|
||||||
|
\fB\-l\fR LABELS, \fB\-\-label\fR=\fI\,LABELS\/\fR
|
||||||
|
add a label when uploading
|
||||||
|
.TP
|
||||||
|
\fB\-\-re\fR=\fI\,REVIEWERS\/\fR, \fB\-\-reviewers\fR=\fI\,REVIEWERS\/\fR
|
||||||
|
request reviews from these people
|
||||||
|
.TP
|
||||||
|
\fB\-\-cc\fR=\fI\,CC\/\fR
|
||||||
|
also send email to these email addresses
|
||||||
|
.TP
|
||||||
|
\fB\-\-br\fR=\fI\,BRANCH\/\fR, \fB\-\-branch\fR=\fI\,BRANCH\/\fR
|
||||||
|
(local) branch to upload
|
||||||
|
.TP
|
||||||
|
\fB\-c\fR, \fB\-\-current\-branch\fR
|
||||||
|
upload current git branch
|
||||||
|
.TP
|
||||||
|
\fB\-\-no\-current\-branch\fR
|
||||||
|
upload all git branches
|
||||||
|
.TP
|
||||||
|
\fB\-\-ne\fR, \fB\-\-no\-emails\fR
|
||||||
|
do not send e\-mails on upload
|
||||||
|
.TP
|
||||||
|
\fB\-p\fR, \fB\-\-private\fR
|
||||||
|
upload as a private change (deprecated; use \fB\-\-wip\fR)
|
||||||
|
.TP
|
||||||
|
\fB\-w\fR, \fB\-\-wip\fR
|
||||||
|
upload as a work\-in\-progress change
|
||||||
|
.TP
|
||||||
|
\fB\-o\fR PUSH_OPTIONS, \fB\-\-push\-option\fR=\fI\,PUSH_OPTIONS\/\fR
|
||||||
|
additional push options to transmit
|
||||||
|
.TP
|
||||||
|
\fB\-D\fR BRANCH, \fB\-\-destination\fR=\fI\,BRANCH\/\fR, \fB\-\-dest\fR=\fI\,BRANCH\/\fR
|
||||||
|
submit for review on this target branch
|
||||||
|
.TP
|
||||||
|
\fB\-n\fR, \fB\-\-dry\-run\fR
|
||||||
|
do everything except actually upload the CL
|
||||||
|
.TP
|
||||||
|
\fB\-y\fR, \fB\-\-yes\fR
|
||||||
|
answer yes to all safe prompts
|
||||||
|
.TP
|
||||||
|
\fB\-\-no\-cert\-checks\fR
|
||||||
|
disable verifying ssl certs (unsafe)
|
||||||
|
.SS Logging options:
|
||||||
|
.TP
|
||||||
|
\fB\-v\fR, \fB\-\-verbose\fR
|
||||||
|
show all output
|
||||||
|
.TP
|
||||||
|
\fB\-q\fR, \fB\-\-quiet\fR
|
||||||
|
only show errors
|
||||||
|
.SS pre\-upload hooks:
|
||||||
|
.TP
|
||||||
|
\fB\-\-no\-verify\fR
|
||||||
|
Do not run the pre\-upload hook.
|
||||||
|
.TP
|
||||||
|
\fB\-\-verify\fR
|
||||||
|
Run the pre\-upload hook without prompting.
|
||||||
|
.TP
|
||||||
|
\fB\-\-ignore\-hooks\fR
|
||||||
|
Do not abort if pre\-upload hooks fail.
|
||||||
|
.PP
|
||||||
|
Run `repo help upload` to view the detailed manual.
|
||||||
|
.SH DETAILS
|
||||||
|
.PP
|
||||||
|
The 'repo upload' command is used to send changes to the Gerrit Code Review
|
||||||
|
system. It searches for topic branches in local projects that have not yet been
|
||||||
|
published for review. If multiple topic branches are found, 'repo upload' opens
|
||||||
|
an editor to allow the user to select which branches to upload.
|
||||||
|
.PP
|
||||||
|
\&'repo upload' searches for uploadable changes in all projects listed at the
|
||||||
|
command line. Projects can be specified either by name, or by a relative or
|
||||||
|
absolute path to the project's local directory. If no projects are specified,
|
||||||
|
\&'repo upload' will search for uploadable changes in all projects listed in the
|
||||||
|
manifest.
|
||||||
|
.PP
|
||||||
|
If the \fB\-\-reviewers\fR or \fB\-\-cc\fR options are passed, those emails are added to the
|
||||||
|
respective list of users, and emails are sent to any new users. Users passed as
|
||||||
|
\fB\-\-reviewers\fR must already be registered with the code review system, or the
|
||||||
|
upload will fail.
|
||||||
|
.PP
|
||||||
|
Configuration
|
||||||
|
.PP
|
||||||
|
review.URL.autoupload:
|
||||||
|
.PP
|
||||||
|
To disable the "Upload ... (y/N)?" prompt, you can set a per\-project or global
|
||||||
|
Git configuration option. If review.URL.autoupload is set to "true" then repo
|
||||||
|
will assume you always answer "y" at the prompt, and will not prompt you
|
||||||
|
further. If it is set to "false" then repo will assume you always answer "n",
|
||||||
|
and will abort.
|
||||||
|
.PP
|
||||||
|
review.URL.autoreviewer:
|
||||||
|
.PP
|
||||||
|
To automatically append a user or mailing list to reviews, you can set a
|
||||||
|
per\-project or global Git option to do so.
|
||||||
|
.PP
|
||||||
|
review.URL.autocopy:
|
||||||
|
.PP
|
||||||
|
To automatically copy a user or mailing list to all uploaded reviews, you can
|
||||||
|
set a per\-project or global Git option to do so. Specifically,
|
||||||
|
review.URL.autocopy can be set to a comma separated list of reviewers who you
|
||||||
|
always want copied on all uploads with a non\-empty \fB\-\-re\fR argument.
|
||||||
|
.PP
|
||||||
|
review.URL.username:
|
||||||
|
.PP
|
||||||
|
Override the username used to connect to Gerrit Code Review. By default the
|
||||||
|
local part of the email address is used.
|
||||||
|
.PP
|
||||||
|
The URL must match the review URL listed in the manifest XML file, or in the
|
||||||
|
\&.git/config within the project. For example:
|
||||||
|
.IP
|
||||||
|
[remote "origin"]
|
||||||
|
.IP
|
||||||
|
url = git://git.example.com/project.git
|
||||||
|
review = http://review.example.com/
|
||||||
|
.IP
|
||||||
|
[review "http://review.example.com/"]
|
||||||
|
.IP
|
||||||
|
autoupload = true
|
||||||
|
autocopy = johndoe@company.com,my\-team\-alias@company.com
|
||||||
|
.PP
|
||||||
|
review.URL.uploadtopic:
|
||||||
|
.PP
|
||||||
|
To add a topic branch whenever uploading a commit, you can set a per\-project or
|
||||||
|
global Git option to do so. If review.URL.uploadtopic is set to "true" then repo
|
||||||
|
will assume you always want the equivalent of the \fB\-t\fR option to the repo command.
|
||||||
|
If unset or set to "false" then repo will make use of only the command line
|
||||||
|
option.
|
||||||
|
.PP
|
||||||
|
review.URL.uploadhashtags:
|
||||||
|
.PP
|
||||||
|
To add hashtags whenever uploading a commit, you can set a per\-project or global
|
||||||
|
Git option to do so. The value of review.URL.uploadhashtags will be used as
|
||||||
|
comma delimited hashtags like the \fB\-\-hashtag\fR option.
|
||||||
|
.PP
|
||||||
|
review.URL.uploadlabels:
|
||||||
|
.PP
|
||||||
|
To add labels whenever uploading a commit, you can set a per\-project or global
|
||||||
|
Git option to do so. The value of review.URL.uploadlabels will be used as comma
|
||||||
|
delimited labels like the \fB\-\-label\fR option.
|
||||||
|
.PP
|
||||||
|
review.URL.uploadnotify:
|
||||||
|
.PP
|
||||||
|
Control e\-mail notifications when uploading.
|
||||||
|
https://gerrit\-review.googlesource.com/Documentation/user\-upload.html#notify
|
||||||
|
.PP
|
||||||
|
References
|
||||||
|
.PP
|
||||||
|
Gerrit Code Review: https://www.gerritcodereview.com/
|
24
man/repo-version.1
Normal file
24
man/repo-version.1
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man.
|
||||||
|
.TH REPO "1" "July 2021" "repo version" "Repo Manual"
|
||||||
|
.SH NAME
|
||||||
|
repo \- repo version - manual page for repo version
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B repo
|
||||||
|
\fI\,version\/\fR
|
||||||
|
.SH DESCRIPTION
|
||||||
|
Summary
|
||||||
|
.PP
|
||||||
|
Display the version of repo
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
\fB\-h\fR, \fB\-\-help\fR
|
||||||
|
show this help message and exit
|
||||||
|
.SS Logging options:
|
||||||
|
.TP
|
||||||
|
\fB\-v\fR, \fB\-\-verbose\fR
|
||||||
|
show all output
|
||||||
|
.TP
|
||||||
|
\fB\-q\fR, \fB\-\-quiet\fR
|
||||||
|
only show errors
|
||||||
|
.PP
|
||||||
|
Run `repo help version` to view the detailed manual.
|
133
man/repo.1
Normal file
133
man/repo.1
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
.\" DO NOT MODIFY THIS FILE! It was generated by help2man.
|
||||||
|
.TH REPO "1" "July 2021" "repo" "Repo Manual"
|
||||||
|
.SH NAME
|
||||||
|
repo \- repository management tool built on top of git
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B repo
|
||||||
|
[\fI\,-p|--paginate|--no-pager\/\fR] \fI\,COMMAND \/\fR[\fI\,ARGS\/\fR]
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
\fB\-h\fR, \fB\-\-help\fR
|
||||||
|
show this help message and exit
|
||||||
|
.TP
|
||||||
|
\fB\-\-help\-all\fR
|
||||||
|
show this help message with all subcommands and exit
|
||||||
|
.TP
|
||||||
|
\fB\-p\fR, \fB\-\-paginate\fR
|
||||||
|
display command output in the pager
|
||||||
|
.TP
|
||||||
|
\fB\-\-no\-pager\fR
|
||||||
|
disable the pager
|
||||||
|
.TP
|
||||||
|
\fB\-\-color\fR=\fI\,COLOR\/\fR
|
||||||
|
control color usage: auto, always, never
|
||||||
|
.TP
|
||||||
|
\fB\-\-trace\fR
|
||||||
|
trace git command execution (REPO_TRACE=1)
|
||||||
|
.TP
|
||||||
|
\fB\-\-trace\-python\fR
|
||||||
|
trace python command execution
|
||||||
|
.TP
|
||||||
|
\fB\-\-time\fR
|
||||||
|
time repo command execution
|
||||||
|
.TP
|
||||||
|
\fB\-\-version\fR
|
||||||
|
display this version of repo
|
||||||
|
.TP
|
||||||
|
\fB\-\-show\-toplevel\fR
|
||||||
|
display the path of the top\-level directory of the
|
||||||
|
repo client checkout
|
||||||
|
.TP
|
||||||
|
\fB\-\-event\-log\fR=\fI\,EVENT_LOG\/\fR
|
||||||
|
filename of event log to append timeline to
|
||||||
|
.TP
|
||||||
|
\fB\-\-git\-trace2\-event\-log\fR=\fI\,GIT_TRACE2_EVENT_LOG\/\fR
|
||||||
|
directory to write git trace2 event log to
|
||||||
|
.SS "The complete list of recognized repo commands are:"
|
||||||
|
.TP
|
||||||
|
abandon
|
||||||
|
Permanently abandon a development branch
|
||||||
|
.TP
|
||||||
|
branch
|
||||||
|
View current topic branches
|
||||||
|
.TP
|
||||||
|
branches
|
||||||
|
View current topic branches
|
||||||
|
.TP
|
||||||
|
checkout
|
||||||
|
Checkout a branch for development
|
||||||
|
.TP
|
||||||
|
cherry\-pick
|
||||||
|
Cherry\-pick a change.
|
||||||
|
.TP
|
||||||
|
diff
|
||||||
|
Show changes between commit and working tree
|
||||||
|
.TP
|
||||||
|
diffmanifests
|
||||||
|
Manifest diff utility
|
||||||
|
.TP
|
||||||
|
download
|
||||||
|
Download and checkout a change
|
||||||
|
.TP
|
||||||
|
forall
|
||||||
|
Run a shell command in each project
|
||||||
|
.TP
|
||||||
|
gitc\-delete
|
||||||
|
Delete a GITC Client.
|
||||||
|
.TP
|
||||||
|
gitc\-init
|
||||||
|
Initialize a GITC Client.
|
||||||
|
.TP
|
||||||
|
grep
|
||||||
|
Print lines matching a pattern
|
||||||
|
.TP
|
||||||
|
help
|
||||||
|
Display detailed help on a command
|
||||||
|
.TP
|
||||||
|
info
|
||||||
|
Get info on the manifest branch, current branch or unmerged branches
|
||||||
|
.TP
|
||||||
|
init
|
||||||
|
Initialize a repo client checkout in the current directory
|
||||||
|
.TP
|
||||||
|
list
|
||||||
|
List projects and their associated directories
|
||||||
|
.TP
|
||||||
|
manifest
|
||||||
|
Manifest inspection utility
|
||||||
|
.TP
|
||||||
|
overview
|
||||||
|
Display overview of unmerged project branches
|
||||||
|
.TP
|
||||||
|
prune
|
||||||
|
Prune (delete) already merged topics
|
||||||
|
.TP
|
||||||
|
rebase
|
||||||
|
Rebase local branches on upstream branch
|
||||||
|
.TP
|
||||||
|
selfupdate
|
||||||
|
Update repo to the latest version
|
||||||
|
.TP
|
||||||
|
smartsync
|
||||||
|
Update working tree to the latest known good revision
|
||||||
|
.TP
|
||||||
|
stage
|
||||||
|
Stage file(s) for commit
|
||||||
|
.TP
|
||||||
|
start
|
||||||
|
Start a new branch for development
|
||||||
|
.TP
|
||||||
|
status
|
||||||
|
Show the working tree status
|
||||||
|
.TP
|
||||||
|
sync
|
||||||
|
Update working tree to the latest revision
|
||||||
|
.TP
|
||||||
|
upload
|
||||||
|
Upload changes for code review
|
||||||
|
.TP
|
||||||
|
version
|
||||||
|
Display the version of repo
|
||||||
|
.PP
|
||||||
|
See 'repo help <command>' for more information on a specific command.
|
||||||
|
Bug reports: https://bugs.chromium.org/p/gerrit/issues/entry?template=Repo+tool+issue
|
@ -25,7 +25,7 @@ import gitc_utils
|
|||||||
from git_config import GitConfig, IsId
|
from git_config import GitConfig, IsId
|
||||||
from git_refs import R_HEADS, HEAD
|
from git_refs import R_HEADS, HEAD
|
||||||
import platform_utils
|
import platform_utils
|
||||||
from project import RemoteSpec, Project, MetaProject
|
from project import Annotation, RemoteSpec, Project, MetaProject
|
||||||
from error import (ManifestParseError, ManifestInvalidPathError,
|
from error import (ManifestParseError, ManifestInvalidPathError,
|
||||||
ManifestInvalidRevisionError)
|
ManifestInvalidRevisionError)
|
||||||
from wrapper import Wrapper
|
from wrapper import Wrapper
|
||||||
@ -34,6 +34,9 @@ MANIFEST_FILE_NAME = 'manifest.xml'
|
|||||||
LOCAL_MANIFEST_NAME = 'local_manifest.xml'
|
LOCAL_MANIFEST_NAME = 'local_manifest.xml'
|
||||||
LOCAL_MANIFESTS_DIR_NAME = 'local_manifests'
|
LOCAL_MANIFESTS_DIR_NAME = 'local_manifests'
|
||||||
|
|
||||||
|
# Add all projects from local manifest into a group.
|
||||||
|
LOCAL_MANIFEST_GROUP_PREFIX = 'local:'
|
||||||
|
|
||||||
# ContactInfo has the self-registered bug url, supplied by the manifest authors.
|
# ContactInfo has the self-registered bug url, supplied by the manifest authors.
|
||||||
ContactInfo = collections.namedtuple('ContactInfo', 'bugurl')
|
ContactInfo = collections.namedtuple('ContactInfo', 'bugurl')
|
||||||
|
|
||||||
@ -119,9 +122,13 @@ class _Default(object):
|
|||||||
sync_tags = True
|
sync_tags = True
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
|
if not isinstance(other, _Default):
|
||||||
|
return False
|
||||||
return self.__dict__ == other.__dict__
|
return self.__dict__ == other.__dict__
|
||||||
|
|
||||||
def __ne__(self, other):
|
def __ne__(self, other):
|
||||||
|
if not isinstance(other, _Default):
|
||||||
|
return True
|
||||||
return self.__dict__ != other.__dict__
|
return self.__dict__ != other.__dict__
|
||||||
|
|
||||||
|
|
||||||
@ -142,14 +149,22 @@ class _XmlRemote(object):
|
|||||||
self.reviewUrl = review
|
self.reviewUrl = review
|
||||||
self.revision = revision
|
self.revision = revision
|
||||||
self.resolvedFetchUrl = self._resolveFetchUrl()
|
self.resolvedFetchUrl = self._resolveFetchUrl()
|
||||||
|
self.annotations = []
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
return self.__dict__ == other.__dict__
|
if not isinstance(other, _XmlRemote):
|
||||||
|
return False
|
||||||
|
return (sorted(self.annotations) == sorted(other.annotations) and
|
||||||
|
self.name == other.name and self.fetchUrl == other.fetchUrl and
|
||||||
|
self.pushUrl == other.pushUrl and self.remoteAlias == other.remoteAlias
|
||||||
|
and self.reviewUrl == other.reviewUrl and self.revision == other.revision)
|
||||||
|
|
||||||
def __ne__(self, other):
|
def __ne__(self, other):
|
||||||
return self.__dict__ != other.__dict__
|
return not self.__eq__(other)
|
||||||
|
|
||||||
def _resolveFetchUrl(self):
|
def _resolveFetchUrl(self):
|
||||||
|
if self.fetchUrl is None:
|
||||||
|
return ''
|
||||||
url = self.fetchUrl.rstrip('/')
|
url = self.fetchUrl.rstrip('/')
|
||||||
manifestUrl = self.manifestUrl.rstrip('/')
|
manifestUrl = self.manifestUrl.rstrip('/')
|
||||||
# urljoin will gets confused over quite a few things. The ones we care
|
# urljoin will gets confused over quite a few things. The ones we care
|
||||||
@ -178,6 +193,9 @@ class _XmlRemote(object):
|
|||||||
orig_name=self.name,
|
orig_name=self.name,
|
||||||
fetchUrl=self.fetchUrl)
|
fetchUrl=self.fetchUrl)
|
||||||
|
|
||||||
|
def AddAnnotation(self, name, value, keep):
|
||||||
|
self.annotations.append(Annotation(name, value, keep))
|
||||||
|
|
||||||
|
|
||||||
class XmlManifest(object):
|
class XmlManifest(object):
|
||||||
"""manages the repo configuration file"""
|
"""manages the repo configuration file"""
|
||||||
@ -287,6 +305,13 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
|
|||||||
if r.revision is not None:
|
if r.revision is not None:
|
||||||
e.setAttribute('revision', r.revision)
|
e.setAttribute('revision', r.revision)
|
||||||
|
|
||||||
|
for a in r.annotations:
|
||||||
|
if a.keep == 'true':
|
||||||
|
ae = doc.createElement('annotation')
|
||||||
|
ae.setAttribute('name', a.name)
|
||||||
|
ae.setAttribute('value', a.value)
|
||||||
|
e.appendChild(ae)
|
||||||
|
|
||||||
def _ParseList(self, field):
|
def _ParseList(self, field):
|
||||||
"""Parse fields that contain flattened lists.
|
"""Parse fields that contain flattened lists.
|
||||||
|
|
||||||
@ -612,6 +637,13 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
|
|||||||
'repo.partialcloneexclude') or ''
|
'repo.partialcloneexclude') or ''
|
||||||
return set(x.strip() for x in exclude.split(','))
|
return set(x.strip() for x in exclude.split(','))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def UseLocalManifests(self):
|
||||||
|
return self._load_local_manifests
|
||||||
|
|
||||||
|
def SetUseLocalManifests(self, value):
|
||||||
|
self._load_local_manifests = value
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def HasLocalManifests(self):
|
def HasLocalManifests(self):
|
||||||
return self._load_local_manifests and self.local_manifests
|
return self._load_local_manifests and self.local_manifests
|
||||||
@ -679,7 +711,9 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
|
|||||||
# Since local manifests are entirely managed by the user, allow
|
# Since local manifests are entirely managed by the user, allow
|
||||||
# them to point anywhere the user wants.
|
# them to point anywhere the user wants.
|
||||||
nodes.append(self._ParseManifestXml(
|
nodes.append(self._ParseManifestXml(
|
||||||
local, self.repodir, restrict_includes=False))
|
local, self.repodir,
|
||||||
|
parent_groups=f'{LOCAL_MANIFEST_GROUP_PREFIX}:{local_file[:-4]}',
|
||||||
|
restrict_includes=False))
|
||||||
except OSError:
|
except OSError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -776,9 +810,10 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
|
|||||||
for node in itertools.chain(*node_list):
|
for node in itertools.chain(*node_list):
|
||||||
if node.nodeName == 'default':
|
if node.nodeName == 'default':
|
||||||
new_default = self._ParseDefault(node)
|
new_default = self._ParseDefault(node)
|
||||||
|
emptyDefault = not node.hasAttributes() and not node.hasChildNodes()
|
||||||
if self._default is None:
|
if self._default is None:
|
||||||
self._default = new_default
|
self._default = new_default
|
||||||
elif new_default != self._default:
|
elif not emptyDefault and new_default != self._default:
|
||||||
raise ManifestParseError('duplicate default in %s' %
|
raise ManifestParseError('duplicate default in %s' %
|
||||||
(self.manifestFile))
|
(self.manifestFile))
|
||||||
|
|
||||||
@ -902,19 +937,19 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
|
|||||||
if node.nodeName == 'remove-project':
|
if node.nodeName == 'remove-project':
|
||||||
name = self._reqatt(node, 'name')
|
name = self._reqatt(node, 'name')
|
||||||
|
|
||||||
if name not in self._projects:
|
if name in self._projects:
|
||||||
|
for p in self._projects[name]:
|
||||||
|
del self._paths[p.relpath]
|
||||||
|
del self._projects[name]
|
||||||
|
|
||||||
|
# If the manifest removes the hooks project, treat it as if it deleted
|
||||||
|
# the repo-hooks element too.
|
||||||
|
if self._repo_hooks_project and (self._repo_hooks_project.name == name):
|
||||||
|
self._repo_hooks_project = None
|
||||||
|
elif not XmlBool(node, 'optional', False):
|
||||||
raise ManifestParseError('remove-project element specifies non-existent '
|
raise ManifestParseError('remove-project element specifies non-existent '
|
||||||
'project: %s' % name)
|
'project: %s' % name)
|
||||||
|
|
||||||
for p in self._projects[name]:
|
|
||||||
del self._paths[p.relpath]
|
|
||||||
del self._projects[name]
|
|
||||||
|
|
||||||
# If the manifest removes the hooks project, treat it as if it deleted
|
|
||||||
# the repo-hooks element too.
|
|
||||||
if self._repo_hooks_project and (self._repo_hooks_project.name == name):
|
|
||||||
self._repo_hooks_project = None
|
|
||||||
|
|
||||||
def _AddMetaProjectMirror(self, m):
|
def _AddMetaProjectMirror(self, m):
|
||||||
name = None
|
name = None
|
||||||
m_url = m.GetRemote(m.remote.name).url
|
m_url = m.GetRemote(m.remote.name).url
|
||||||
@ -972,7 +1007,14 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
|
|||||||
if revision == '':
|
if revision == '':
|
||||||
revision = None
|
revision = None
|
||||||
manifestUrl = self.manifestProject.config.GetString('remote.origin.url')
|
manifestUrl = self.manifestProject.config.GetString('remote.origin.url')
|
||||||
return _XmlRemote(name, alias, fetch, pushUrl, manifestUrl, review, revision)
|
|
||||||
|
remote = _XmlRemote(name, alias, fetch, pushUrl, manifestUrl, review, revision)
|
||||||
|
|
||||||
|
for n in node.childNodes:
|
||||||
|
if n.nodeName == 'annotation':
|
||||||
|
self._ParseAnnotation(remote, n)
|
||||||
|
|
||||||
|
return remote
|
||||||
|
|
||||||
def _ParseDefault(self, node):
|
def _ParseDefault(self, node):
|
||||||
"""
|
"""
|
||||||
@ -1339,7 +1381,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
|
|||||||
self._ValidateFilePaths('linkfile', src, dest)
|
self._ValidateFilePaths('linkfile', src, dest)
|
||||||
project.AddLinkFile(src, dest, self.topdir)
|
project.AddLinkFile(src, dest, self.topdir)
|
||||||
|
|
||||||
def _ParseAnnotation(self, project, node):
|
def _ParseAnnotation(self, element, node):
|
||||||
name = self._reqatt(node, 'name')
|
name = self._reqatt(node, 'name')
|
||||||
value = self._reqatt(node, 'value')
|
value = self._reqatt(node, 'value')
|
||||||
try:
|
try:
|
||||||
@ -1349,7 +1391,7 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
|
|||||||
if keep != "true" and keep != "false":
|
if keep != "true" and keep != "false":
|
||||||
raise ManifestParseError('optional "keep" attribute must be '
|
raise ManifestParseError('optional "keep" attribute must be '
|
||||||
'"true" or "false"')
|
'"true" or "false"')
|
||||||
project.AddAnnotation(name, value, keep)
|
element.AddAnnotation(name, value, keep)
|
||||||
|
|
||||||
def _get_remote(self, node):
|
def _get_remote(self, node):
|
||||||
name = node.getAttribute('remote')
|
name = node.getAttribute('remote')
|
||||||
|
27
project.py
27
project.py
@ -251,13 +251,29 @@ class DiffColoring(Coloring):
|
|||||||
self.fail = self.printer('fail', fg='red')
|
self.fail = self.printer('fail', fg='red')
|
||||||
|
|
||||||
|
|
||||||
class _Annotation(object):
|
class Annotation(object):
|
||||||
|
|
||||||
def __init__(self, name, value, keep):
|
def __init__(self, name, value, keep):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.value = value
|
self.value = value
|
||||||
self.keep = keep
|
self.keep = keep
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
if not isinstance(other, Annotation):
|
||||||
|
return False
|
||||||
|
return self.__dict__ == other.__dict__
|
||||||
|
|
||||||
|
def __lt__(self, other):
|
||||||
|
# This exists just so that lists of Annotation objects can be sorted, for
|
||||||
|
# use in comparisons.
|
||||||
|
if not isinstance(other, Annotation):
|
||||||
|
raise ValueError('comparison is not between two Annotation objects')
|
||||||
|
if self.name == other.name:
|
||||||
|
if self.value == other.value:
|
||||||
|
return self.keep < other.keep
|
||||||
|
return self.value < other.value
|
||||||
|
return self.name < other.name
|
||||||
|
|
||||||
|
|
||||||
def _SafeExpandPath(base, subpath, skipfinal=False):
|
def _SafeExpandPath(base, subpath, skipfinal=False):
|
||||||
"""Make sure |subpath| is completely safe under |base|.
|
"""Make sure |subpath| is completely safe under |base|.
|
||||||
@ -1216,7 +1232,7 @@ class Project(object):
|
|||||||
(self.revisionExpr, self.name))
|
(self.revisionExpr, self.name))
|
||||||
|
|
||||||
def SetRevisionId(self, revisionId):
|
def SetRevisionId(self, revisionId):
|
||||||
if self.clone_depth or self.manifest.manifestProject.config.GetString('repo.depth'):
|
if self.revisionExpr:
|
||||||
self.upstream = self.revisionExpr
|
self.upstream = self.revisionExpr
|
||||||
|
|
||||||
self.revisionId = revisionId
|
self.revisionId = revisionId
|
||||||
@ -1448,7 +1464,7 @@ class Project(object):
|
|||||||
self.linkfiles.append(_LinkFile(self.worktree, src, topdir, dest))
|
self.linkfiles.append(_LinkFile(self.worktree, src, topdir, dest))
|
||||||
|
|
||||||
def AddAnnotation(self, name, value, keep):
|
def AddAnnotation(self, name, value, keep):
|
||||||
self.annotations.append(_Annotation(name, value, keep))
|
self.annotations.append(Annotation(name, value, keep))
|
||||||
|
|
||||||
def DownloadPatchSet(self, change_id, patch_id):
|
def DownloadPatchSet(self, change_id, patch_id):
|
||||||
"""Download a single patch set of a single change to FETCH_HEAD.
|
"""Download a single patch set of a single change to FETCH_HEAD.
|
||||||
@ -1967,6 +1983,11 @@ class Project(object):
|
|||||||
# throws an error.
|
# throws an error.
|
||||||
self.bare_git.rev_list('-1', '--missing=allow-any',
|
self.bare_git.rev_list('-1', '--missing=allow-any',
|
||||||
'%s^0' % self.revisionExpr, '--')
|
'%s^0' % self.revisionExpr, '--')
|
||||||
|
if self.upstream:
|
||||||
|
rev = self.GetRemote(self.remote.name).ToLocal(self.upstream)
|
||||||
|
self.bare_git.rev_list('-1', '--missing=allow-any',
|
||||||
|
'%s^0' % rev, '--')
|
||||||
|
self.bare_git.merge_base('--is-ancestor', self.revisionExpr, rev)
|
||||||
return True
|
return True
|
||||||
except GitError:
|
except GitError:
|
||||||
# There is no such persistent revision. We have to fetch it.
|
# There is no such persistent revision. We have to fetch it.
|
||||||
|
85
release/update-manpages
Executable file
85
release/update-manpages
Executable file
@ -0,0 +1,85 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# Copyright (C) 2021 The Android Open Source Project
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
"""Helper tool for generating manual page for all repo commands.
|
||||||
|
|
||||||
|
This is intended to be run before every official Repo release.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
from functools import partial
|
||||||
|
import argparse
|
||||||
|
import multiprocessing
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
TOPDIR = Path(__file__).resolve().parent.parent
|
||||||
|
MANDIR = TOPDIR.joinpath('man')
|
||||||
|
|
||||||
|
# Load repo local modules.
|
||||||
|
sys.path.insert(0, str(TOPDIR))
|
||||||
|
from git_command import RepoSourceVersion
|
||||||
|
import subcmds
|
||||||
|
|
||||||
|
def worker(cmd, **kwargs):
|
||||||
|
subprocess.run(cmd, **kwargs)
|
||||||
|
|
||||||
|
def main(argv):
|
||||||
|
parser = argparse.ArgumentParser(description=__doc__)
|
||||||
|
opts = parser.parse_args(argv)
|
||||||
|
|
||||||
|
if not shutil.which('help2man'):
|
||||||
|
sys.exit('Please install help2man to continue.')
|
||||||
|
|
||||||
|
# "repo branch" is an alias for "repo branches".
|
||||||
|
del subcmds.all_commands['branch']
|
||||||
|
(MANDIR / 'repo-branch.1').write_text('.so man1/repo-branches.1')
|
||||||
|
|
||||||
|
version = RepoSourceVersion()
|
||||||
|
cmdlist = [['help2man', '-N', '-n', f'repo {cmd} - manual page for repo {cmd}',
|
||||||
|
'-S', f'repo {cmd}', '-m', 'Repo Manual', f'--version-string={version}',
|
||||||
|
'-o', MANDIR.joinpath(f'repo-{cmd}.1'), TOPDIR.joinpath('repo'),
|
||||||
|
'-h', f'help {cmd}'] for cmd in subcmds.all_commands]
|
||||||
|
cmdlist.append(['help2man', '-N', '-n', 'repository management tool built on top of git',
|
||||||
|
'-S', 'repo', '-m', 'Repo Manual', f'--version-string={version}',
|
||||||
|
'-o', MANDIR.joinpath('repo.1'), TOPDIR.joinpath('repo'),
|
||||||
|
'-h', '--help-all'])
|
||||||
|
|
||||||
|
with tempfile.TemporaryDirectory() as tempdir:
|
||||||
|
repo_dir = Path(tempdir) / '.repo'
|
||||||
|
repo_dir.mkdir()
|
||||||
|
(repo_dir / 'repo').symlink_to(TOPDIR)
|
||||||
|
|
||||||
|
# Run all cmd in parallel, and wait for them to finish.
|
||||||
|
with multiprocessing.Pool() as pool:
|
||||||
|
pool.map(partial(worker, cwd=tempdir, check=True), cmdlist)
|
||||||
|
|
||||||
|
regex = (
|
||||||
|
(r'(It was generated by help2man) [0-9.]+', '\g<1>.'),
|
||||||
|
(r'^\.IP\n(.*:)\n', '.SS \g<1>\n'),
|
||||||
|
(r'^\.PP\nDescription', '.SH DETAILS'),
|
||||||
|
)
|
||||||
|
for path in MANDIR.glob('*.1'):
|
||||||
|
data = path.read_text()
|
||||||
|
for pattern, replacement in regex:
|
||||||
|
data = re.sub(pattern, replacement, data, flags=re.M)
|
||||||
|
path.write_text(data)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sys.exit(main(sys.argv[1:]))
|
@ -38,9 +38,9 @@
|
|||||||
# Supported Python versions.
|
# Supported Python versions.
|
||||||
#
|
#
|
||||||
# python-3.6 is in Ubuntu Bionic.
|
# python-3.6 is in Ubuntu Bionic.
|
||||||
# python-3.5 is in Debian Stretch.
|
# python-3.7 is in Debian Buster.
|
||||||
"python": {
|
"python": {
|
||||||
"hard": [3, 5],
|
"hard": [3, 6],
|
||||||
"soft": [3, 6]
|
"soft": [3, 6]
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -24,6 +24,10 @@ import sys
|
|||||||
|
|
||||||
def find_pytest():
|
def find_pytest():
|
||||||
"""Try to locate a good version of pytest."""
|
"""Try to locate a good version of pytest."""
|
||||||
|
# If we're in a virtualenv, assume that it's provided the right pytest.
|
||||||
|
if 'VIRTUAL_ENV' in os.environ:
|
||||||
|
return 'pytest'
|
||||||
|
|
||||||
# Use the Python 3 version if available.
|
# Use the Python 3 version if available.
|
||||||
ret = shutil.which('pytest-3')
|
ret = shutil.which('pytest-3')
|
||||||
if ret:
|
if ret:
|
||||||
|
2
setup.py
2
setup.py
@ -56,6 +56,6 @@ setuptools.setup(
|
|||||||
'Programming Language :: Python :: 3 :: Only',
|
'Programming Language :: Python :: 3 :: Only',
|
||||||
'Topic :: Software Development :: Version Control :: Git',
|
'Topic :: Software Development :: Version Control :: Git',
|
||||||
],
|
],
|
||||||
python_requires='>=3.5',
|
python_requires='>=3.6',
|
||||||
packages=['subcmds'],
|
packages=['subcmds'],
|
||||||
)
|
)
|
||||||
|
@ -23,7 +23,7 @@ from progress import Progress
|
|||||||
|
|
||||||
|
|
||||||
class Abandon(Command):
|
class Abandon(Command):
|
||||||
common = True
|
COMMON = True
|
||||||
helpSummary = "Permanently abandon a development branch"
|
helpSummary = "Permanently abandon a development branch"
|
||||||
helpUsage = """
|
helpUsage = """
|
||||||
%prog [--all | <branchname>] [<project>...]
|
%prog [--all | <branchname>] [<project>...]
|
||||||
|
@ -62,7 +62,7 @@ class BranchInfo(object):
|
|||||||
|
|
||||||
|
|
||||||
class Branches(Command):
|
class Branches(Command):
|
||||||
common = True
|
COMMON = True
|
||||||
helpSummary = "View current topic branches"
|
helpSummary = "View current topic branches"
|
||||||
helpUsage = """
|
helpUsage = """
|
||||||
%prog [<project>...]
|
%prog [<project>...]
|
||||||
|
@ -20,7 +20,7 @@ from progress import Progress
|
|||||||
|
|
||||||
|
|
||||||
class Checkout(Command):
|
class Checkout(Command):
|
||||||
common = True
|
COMMON = True
|
||||||
helpSummary = "Checkout a branch for development"
|
helpSummary = "Checkout a branch for development"
|
||||||
helpUsage = """
|
helpUsage = """
|
||||||
%prog <branchname> [<project>...]
|
%prog <branchname> [<project>...]
|
||||||
|
@ -21,7 +21,7 @@ CHANGE_ID_RE = re.compile(r'^\s*Change-Id: I([0-9a-f]{40})\s*$')
|
|||||||
|
|
||||||
|
|
||||||
class CherryPick(Command):
|
class CherryPick(Command):
|
||||||
common = True
|
COMMON = True
|
||||||
helpSummary = "Cherry-pick a change."
|
helpSummary = "Cherry-pick a change."
|
||||||
helpUsage = """
|
helpUsage = """
|
||||||
%prog <sha1>
|
%prog <sha1>
|
||||||
|
@ -19,7 +19,7 @@ from command import DEFAULT_LOCAL_JOBS, PagedCommand
|
|||||||
|
|
||||||
|
|
||||||
class Diff(PagedCommand):
|
class Diff(PagedCommand):
|
||||||
common = True
|
COMMON = True
|
||||||
helpSummary = "Show changes between commit and working tree"
|
helpSummary = "Show changes between commit and working tree"
|
||||||
helpUsage = """
|
helpUsage = """
|
||||||
%prog [<project>...]
|
%prog [<project>...]
|
||||||
|
@ -31,7 +31,7 @@ class Diffmanifests(PagedCommand):
|
|||||||
deeper level.
|
deeper level.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
common = True
|
COMMON = True
|
||||||
helpSummary = "Manifest diff utility"
|
helpSummary = "Manifest diff utility"
|
||||||
helpUsage = """%prog manifest1.xml [manifest2.xml] [options]"""
|
helpUsage = """%prog manifest1.xml [manifest2.xml] [options]"""
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ CHANGE_RE = re.compile(r'^([1-9][0-9]*)(?:[/\.-]([1-9][0-9]*))?$')
|
|||||||
|
|
||||||
|
|
||||||
class Download(Command):
|
class Download(Command):
|
||||||
common = True
|
COMMON = True
|
||||||
helpSummary = "Download and checkout a change"
|
helpSummary = "Download and checkout a change"
|
||||||
helpUsage = """
|
helpUsage = """
|
||||||
%prog {[project] change[/patchset]}...
|
%prog {[project] change[/patchset]}...
|
||||||
|
@ -41,7 +41,7 @@ class ForallColoring(Coloring):
|
|||||||
|
|
||||||
|
|
||||||
class Forall(Command, MirrorSafeCommand):
|
class Forall(Command, MirrorSafeCommand):
|
||||||
common = False
|
COMMON = False
|
||||||
helpSummary = "Run a shell command in each project"
|
helpSummary = "Run a shell command in each project"
|
||||||
helpUsage = """
|
helpUsage = """
|
||||||
%prog [<project>...] -c <command> [<arg>...]
|
%prog [<project>...] -c <command> [<arg>...]
|
||||||
|
@ -19,7 +19,7 @@ import platform_utils
|
|||||||
|
|
||||||
|
|
||||||
class GitcDelete(Command, GitcClientCommand):
|
class GitcDelete(Command, GitcClientCommand):
|
||||||
common = True
|
COMMON = True
|
||||||
visible_everywhere = False
|
visible_everywhere = False
|
||||||
helpSummary = "Delete a GITC Client."
|
helpSummary = "Delete a GITC Client."
|
||||||
helpUsage = """
|
helpUsage = """
|
||||||
|
@ -23,7 +23,7 @@ import wrapper
|
|||||||
|
|
||||||
|
|
||||||
class GitcInit(init.Init, GitcAvailableCommand):
|
class GitcInit(init.Init, GitcAvailableCommand):
|
||||||
common = True
|
COMMON = True
|
||||||
helpSummary = "Initialize a GITC Client."
|
helpSummary = "Initialize a GITC Client."
|
||||||
helpUsage = """
|
helpUsage = """
|
||||||
%prog [options] [client name]
|
%prog [options] [client name]
|
||||||
|
@ -29,7 +29,7 @@ class GrepColoring(Coloring):
|
|||||||
|
|
||||||
|
|
||||||
class Grep(PagedCommand):
|
class Grep(PagedCommand):
|
||||||
common = True
|
COMMON = True
|
||||||
helpSummary = "Print lines matching a pattern"
|
helpSummary = "Print lines matching a pattern"
|
||||||
helpUsage = """
|
helpUsage = """
|
||||||
%prog {pattern | -e pattern} [<project>...]
|
%prog {pattern | -e pattern} [<project>...]
|
||||||
|
@ -24,7 +24,7 @@ from wrapper import Wrapper
|
|||||||
|
|
||||||
|
|
||||||
class Help(PagedCommand, MirrorSafeCommand):
|
class Help(PagedCommand, MirrorSafeCommand):
|
||||||
common = False
|
COMMON = False
|
||||||
helpSummary = "Display detailed help on a command"
|
helpSummary = "Display detailed help on a command"
|
||||||
helpUsage = """
|
helpUsage = """
|
||||||
%prog [--all|command]
|
%prog [--all|command]
|
||||||
@ -50,14 +50,21 @@ Displays detailed usage information about a command.
|
|||||||
|
|
||||||
def _PrintAllCommands(self):
|
def _PrintAllCommands(self):
|
||||||
print('usage: repo COMMAND [ARGS]')
|
print('usage: repo COMMAND [ARGS]')
|
||||||
|
self.PrintAllCommandsBody()
|
||||||
|
|
||||||
|
def PrintAllCommandsBody(self):
|
||||||
print('The complete list of recognized repo commands are:')
|
print('The complete list of recognized repo commands are:')
|
||||||
commandNames = list(sorted(all_commands))
|
commandNames = list(sorted(all_commands))
|
||||||
self._PrintCommands(commandNames)
|
self._PrintCommands(commandNames)
|
||||||
print("See 'repo help <command>' for more information on a "
|
print("See 'repo help <command>' for more information on a "
|
||||||
'specific command.')
|
'specific command.')
|
||||||
|
print('Bug reports:', Wrapper().BUG_URL)
|
||||||
|
|
||||||
def _PrintCommonCommands(self):
|
def _PrintCommonCommands(self):
|
||||||
print('usage: repo COMMAND [ARGS]')
|
print('usage: repo COMMAND [ARGS]')
|
||||||
|
self.PrintCommonCommandsBody()
|
||||||
|
|
||||||
|
def PrintCommonCommandsBody(self):
|
||||||
print('The most commonly used repo commands are:')
|
print('The most commonly used repo commands are:')
|
||||||
|
|
||||||
def gitc_supported(cmd):
|
def gitc_supported(cmd):
|
||||||
@ -73,7 +80,7 @@ Displays detailed usage information about a command.
|
|||||||
|
|
||||||
commandNames = list(sorted([name
|
commandNames = list(sorted([name
|
||||||
for name, command in all_commands.items()
|
for name, command in all_commands.items()
|
||||||
if command.common and gitc_supported(command)]))
|
if command.COMMON and gitc_supported(command)]))
|
||||||
self._PrintCommands(commandNames)
|
self._PrintCommands(commandNames)
|
||||||
|
|
||||||
print(
|
print(
|
||||||
@ -138,8 +145,7 @@ Displays detailed usage information about a command.
|
|||||||
|
|
||||||
def _PrintAllCommandHelp(self):
|
def _PrintAllCommandHelp(self):
|
||||||
for name in sorted(all_commands):
|
for name in sorted(all_commands):
|
||||||
cmd = all_commands[name]()
|
cmd = all_commands[name](manifest=self.manifest)
|
||||||
cmd.manifest = self.manifest
|
|
||||||
self._PrintCommandHelp(cmd, header_prefix='[%s] ' % (name,))
|
self._PrintCommandHelp(cmd, header_prefix='[%s] ' % (name,))
|
||||||
|
|
||||||
def _Options(self, p):
|
def _Options(self, p):
|
||||||
@ -163,12 +169,11 @@ Displays detailed usage information about a command.
|
|||||||
name = args[0]
|
name = args[0]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
cmd = all_commands[name]()
|
cmd = all_commands[name](manifest=self.manifest)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
print("repo: '%s' is not a repo command." % name, file=sys.stderr)
|
print("repo: '%s' is not a repo command." % name, file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
cmd.manifest = self.manifest
|
|
||||||
self._PrintCommandHelp(cmd)
|
self._PrintCommandHelp(cmd)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
@ -25,7 +25,7 @@ class _Coloring(Coloring):
|
|||||||
|
|
||||||
|
|
||||||
class Info(PagedCommand):
|
class Info(PagedCommand):
|
||||||
common = True
|
COMMON = True
|
||||||
helpSummary = "Get info on the manifest branch, current branch or unmerged branches"
|
helpSummary = "Get info on the manifest branch, current branch or unmerged branches"
|
||||||
helpUsage = "%prog [-dl] [-o [-c]] [<project>...]"
|
helpUsage = "%prog [-dl] [-o [-c]] [<project>...]"
|
||||||
|
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
import optparse
|
|
||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
import re
|
import re
|
||||||
@ -31,7 +30,7 @@ from wrapper import Wrapper
|
|||||||
|
|
||||||
|
|
||||||
class Init(InteractiveCommand, MirrorSafeCommand):
|
class Init(InteractiveCommand, MirrorSafeCommand):
|
||||||
common = True
|
COMMON = True
|
||||||
helpSummary = "Initialize a repo client checkout in the current directory"
|
helpSummary = "Initialize a repo client checkout in the current directory"
|
||||||
helpUsage = """
|
helpUsage = """
|
||||||
%prog [options] [manifest url]
|
%prog [options] [manifest url]
|
||||||
@ -97,10 +96,17 @@ to update the working directory files.
|
|||||||
"""
|
"""
|
||||||
superproject = git_superproject.Superproject(self.manifest,
|
superproject = git_superproject.Superproject(self.manifest,
|
||||||
self.repodir,
|
self.repodir,
|
||||||
|
self.git_event_log,
|
||||||
quiet=opt.quiet)
|
quiet=opt.quiet)
|
||||||
if not superproject.Sync():
|
sync_result = superproject.Sync()
|
||||||
print('error: git update of superproject failed', file=sys.stderr)
|
if not sync_result.success:
|
||||||
sys.exit(1)
|
print('warning: git update of superproject failed, repo sync will not '
|
||||||
|
'use superproject to fetch source; while this error is not fatal, '
|
||||||
|
'and you can continue to run repo sync, please run repo init with '
|
||||||
|
'the --no-use-superproject option to stop seeing this warning',
|
||||||
|
file=sys.stderr)
|
||||||
|
if sync_result.fatal and opt.use_superproject is not None:
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
def _SyncManifest(self, opt):
|
def _SyncManifest(self, opt):
|
||||||
m = self.manifest.manifestProject
|
m = self.manifest.manifestProject
|
||||||
|
@ -12,11 +12,13 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
from command import Command, MirrorSafeCommand
|
from command import Command, MirrorSafeCommand
|
||||||
|
|
||||||
|
|
||||||
class List(Command, MirrorSafeCommand):
|
class List(Command, MirrorSafeCommand):
|
||||||
common = True
|
COMMON = True
|
||||||
helpSummary = "List projects and their associated directories"
|
helpSummary = "List projects and their associated directories"
|
||||||
helpUsage = """
|
helpUsage = """
|
||||||
%prog [-f] [<project>...]
|
%prog [-f] [<project>...]
|
||||||
@ -43,20 +45,26 @@ This is similar to running: repo forall -c 'echo "$REPO_PATH : $REPO_PROJECT"'.
|
|||||||
p.add_option('-a', '--all',
|
p.add_option('-a', '--all',
|
||||||
action='store_true',
|
action='store_true',
|
||||||
help='show projects regardless of checkout state')
|
help='show projects regardless of checkout state')
|
||||||
p.add_option('-f', '--fullpath',
|
|
||||||
dest='fullpath', action='store_true',
|
|
||||||
help='display the full work tree path instead of the relative path')
|
|
||||||
p.add_option('-n', '--name-only',
|
p.add_option('-n', '--name-only',
|
||||||
dest='name_only', action='store_true',
|
dest='name_only', action='store_true',
|
||||||
help='display only the name of the repository')
|
help='display only the name of the repository')
|
||||||
p.add_option('-p', '--path-only',
|
p.add_option('-p', '--path-only',
|
||||||
dest='path_only', action='store_true',
|
dest='path_only', action='store_true',
|
||||||
help='display only the path of the repository')
|
help='display only the path of the repository')
|
||||||
|
p.add_option('-f', '--fullpath',
|
||||||
|
dest='fullpath', action='store_true',
|
||||||
|
help='display the full work tree path instead of the relative path')
|
||||||
|
p.add_option('--relative-to', metavar='PATH',
|
||||||
|
help='display paths relative to this one (default: top of repo client checkout)')
|
||||||
|
|
||||||
def ValidateOptions(self, opt, args):
|
def ValidateOptions(self, opt, args):
|
||||||
if opt.fullpath and opt.name_only:
|
if opt.fullpath and opt.name_only:
|
||||||
self.OptionParser.error('cannot combine -f and -n')
|
self.OptionParser.error('cannot combine -f and -n')
|
||||||
|
|
||||||
|
# Resolve any symlinks so the output is stable.
|
||||||
|
if opt.relative_to:
|
||||||
|
opt.relative_to = os.path.realpath(opt.relative_to)
|
||||||
|
|
||||||
def Execute(self, opt, args):
|
def Execute(self, opt, args):
|
||||||
"""List all projects and the associated directories.
|
"""List all projects and the associated directories.
|
||||||
|
|
||||||
@ -76,6 +84,8 @@ This is similar to running: repo forall -c 'echo "$REPO_PATH : $REPO_PROJECT"'.
|
|||||||
def _getpath(x):
|
def _getpath(x):
|
||||||
if opt.fullpath:
|
if opt.fullpath:
|
||||||
return x.worktree
|
return x.worktree
|
||||||
|
if opt.relative_to:
|
||||||
|
return os.path.relpath(x.worktree, opt.relative_to)
|
||||||
return x.relpath
|
return x.relpath
|
||||||
|
|
||||||
lines = []
|
lines = []
|
||||||
|
@ -20,7 +20,7 @@ from command import PagedCommand
|
|||||||
|
|
||||||
|
|
||||||
class Manifest(PagedCommand):
|
class Manifest(PagedCommand):
|
||||||
common = False
|
COMMON = False
|
||||||
helpSummary = "Manifest inspection utility"
|
helpSummary = "Manifest inspection utility"
|
||||||
helpUsage = """
|
helpUsage = """
|
||||||
%prog [-o {-|NAME.xml}] [-m MANIFEST.xml] [-r]
|
%prog [-o {-|NAME.xml}] [-m MANIFEST.xml] [-r]
|
||||||
@ -70,6 +70,8 @@ to indicate the remote ref to push changes to via 'repo upload'.
|
|||||||
help='output manifest in JSON format (experimental)')
|
help='output manifest in JSON format (experimental)')
|
||||||
p.add_option('--pretty', default=False, action='store_true',
|
p.add_option('--pretty', default=False, action='store_true',
|
||||||
help='format output for humans to read')
|
help='format output for humans to read')
|
||||||
|
p.add_option('--no-local-manifests', default=False, action='store_true',
|
||||||
|
dest='ignore_local_manifests', help='ignore local manifests')
|
||||||
p.add_option('-o', '--output-file',
|
p.add_option('-o', '--output-file',
|
||||||
dest='output_file',
|
dest='output_file',
|
||||||
default='-',
|
default='-',
|
||||||
@ -85,6 +87,9 @@ to indicate the remote ref to push changes to via 'repo upload'.
|
|||||||
fd = sys.stdout
|
fd = sys.stdout
|
||||||
else:
|
else:
|
||||||
fd = open(opt.output_file, 'w')
|
fd = open(opt.output_file, 'w')
|
||||||
|
|
||||||
|
self.manifest.SetUseLocalManifests(not opt.ignore_local_manifests)
|
||||||
|
|
||||||
if opt.json:
|
if opt.json:
|
||||||
print('warning: --json is experimental!', file=sys.stderr)
|
print('warning: --json is experimental!', file=sys.stderr)
|
||||||
doc = self.manifest.ToDict(peg_rev=opt.peg_rev,
|
doc = self.manifest.ToDict(peg_rev=opt.peg_rev,
|
||||||
|
@ -19,7 +19,7 @@ from command import PagedCommand
|
|||||||
|
|
||||||
|
|
||||||
class Overview(PagedCommand):
|
class Overview(PagedCommand):
|
||||||
common = True
|
COMMON = True
|
||||||
helpSummary = "Display overview of unmerged project branches"
|
helpSummary = "Display overview of unmerged project branches"
|
||||||
helpUsage = """
|
helpUsage = """
|
||||||
%prog [--current-branch] [<project>...]
|
%prog [--current-branch] [<project>...]
|
||||||
|
@ -19,7 +19,7 @@ from command import DEFAULT_LOCAL_JOBS, PagedCommand
|
|||||||
|
|
||||||
|
|
||||||
class Prune(PagedCommand):
|
class Prune(PagedCommand):
|
||||||
common = True
|
COMMON = True
|
||||||
helpSummary = "Prune (delete) already merged topics"
|
helpSummary = "Prune (delete) already merged topics"
|
||||||
helpUsage = """
|
helpUsage = """
|
||||||
%prog [<project>...]
|
%prog [<project>...]
|
||||||
|
@ -27,7 +27,7 @@ class RebaseColoring(Coloring):
|
|||||||
|
|
||||||
|
|
||||||
class Rebase(Command):
|
class Rebase(Command):
|
||||||
common = True
|
COMMON = True
|
||||||
helpSummary = "Rebase local branches on upstream branch"
|
helpSummary = "Rebase local branches on upstream branch"
|
||||||
helpUsage = """
|
helpUsage = """
|
||||||
%prog {[<project>...] | -i <project>...}
|
%prog {[<project>...] | -i <project>...}
|
||||||
|
@ -21,7 +21,7 @@ from subcmds.sync import _PostRepoFetch
|
|||||||
|
|
||||||
|
|
||||||
class Selfupdate(Command, MirrorSafeCommand):
|
class Selfupdate(Command, MirrorSafeCommand):
|
||||||
common = False
|
COMMON = False
|
||||||
helpSummary = "Update repo to the latest version"
|
helpSummary = "Update repo to the latest version"
|
||||||
helpUsage = """
|
helpUsage = """
|
||||||
%prog
|
%prog
|
||||||
|
@ -16,7 +16,7 @@ from subcmds.sync import Sync
|
|||||||
|
|
||||||
|
|
||||||
class Smartsync(Sync):
|
class Smartsync(Sync):
|
||||||
common = True
|
COMMON = True
|
||||||
helpSummary = "Update working tree to the latest known good revision"
|
helpSummary = "Update working tree to the latest known good revision"
|
||||||
helpUsage = """
|
helpUsage = """
|
||||||
%prog [<project>...]
|
%prog [<project>...]
|
||||||
|
@ -28,7 +28,7 @@ class _ProjectList(Coloring):
|
|||||||
|
|
||||||
|
|
||||||
class Stage(InteractiveCommand):
|
class Stage(InteractiveCommand):
|
||||||
common = True
|
COMMON = True
|
||||||
helpSummary = "Stage file(s) for commit"
|
helpSummary = "Stage file(s) for commit"
|
||||||
helpUsage = """
|
helpUsage = """
|
||||||
%prog -i [<project>...]
|
%prog -i [<project>...]
|
||||||
|
@ -25,7 +25,7 @@ from project import SyncBuffer
|
|||||||
|
|
||||||
|
|
||||||
class Start(Command):
|
class Start(Command):
|
||||||
common = True
|
COMMON = True
|
||||||
helpSummary = "Start a new branch for development"
|
helpSummary = "Start a new branch for development"
|
||||||
helpUsage = """
|
helpUsage = """
|
||||||
%prog <newbranchname> [--all | <project>...]
|
%prog <newbranchname> [--all | <project>...]
|
||||||
|
@ -24,7 +24,7 @@ import platform_utils
|
|||||||
|
|
||||||
|
|
||||||
class Status(PagedCommand):
|
class Status(PagedCommand):
|
||||||
common = True
|
COMMON = True
|
||||||
helpSummary = "Show the working tree status"
|
helpSummary = "Show the working tree status"
|
||||||
helpUsage = """
|
helpUsage = """
|
||||||
%prog [<project>...]
|
%prog [<project>...]
|
||||||
|
@ -66,7 +66,7 @@ _ONE_DAY_S = 24 * 60 * 60
|
|||||||
|
|
||||||
class Sync(Command, MirrorSafeCommand):
|
class Sync(Command, MirrorSafeCommand):
|
||||||
jobs = 1
|
jobs = 1
|
||||||
common = True
|
COMMON = True
|
||||||
helpSummary = "Update working tree to the latest revision"
|
helpSummary = "Update working tree to the latest revision"
|
||||||
helpUsage = """
|
helpUsage = """
|
||||||
%prog [<project>...]
|
%prog [<project>...]
|
||||||
@ -278,18 +278,11 @@ later is required to fix a server side protocol bug.
|
|||||||
branch = branch[len(R_HEADS):]
|
branch = branch[len(R_HEADS):]
|
||||||
return branch
|
return branch
|
||||||
|
|
||||||
def _UseSuperproject(self, opt):
|
|
||||||
"""Returns True if use-superproject option is enabled"""
|
|
||||||
if opt.use_superproject is not None:
|
|
||||||
return opt.use_superproject
|
|
||||||
else:
|
|
||||||
return self.manifest.manifestProject.config.GetBoolean('repo.superproject')
|
|
||||||
|
|
||||||
def _GetCurrentBranchOnly(self, opt):
|
def _GetCurrentBranchOnly(self, opt):
|
||||||
"""Returns True if current-branch or use-superproject options are enabled."""
|
"""Returns True if current-branch or use-superproject options are enabled."""
|
||||||
return opt.current_branch_only or self._UseSuperproject(opt)
|
return opt.current_branch_only or git_superproject.UseSuperproject(opt, self.manifest)
|
||||||
|
|
||||||
def _UpdateProjectsRevisionId(self, opt, args, load_local_manifests):
|
def _UpdateProjectsRevisionId(self, opt, args, load_local_manifests, superproject_logging_data):
|
||||||
"""Update revisionId of every project with the SHA from superproject.
|
"""Update revisionId of every project with the SHA from superproject.
|
||||||
|
|
||||||
This function updates each project's revisionId with SHA from superproject.
|
This function updates each project's revisionId with SHA from superproject.
|
||||||
@ -300,23 +293,36 @@ later is required to fix a server side protocol bug.
|
|||||||
args: Arguments to pass to GetProjects. See the GetProjects
|
args: Arguments to pass to GetProjects. See the GetProjects
|
||||||
docstring for details.
|
docstring for details.
|
||||||
load_local_manifests: Whether to load local manifests.
|
load_local_manifests: Whether to load local manifests.
|
||||||
|
superproject_logging_data: A dictionary of superproject data that is to be logged.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Returns path to the overriding manifest file.
|
Returns path to the overriding manifest file instead of None.
|
||||||
"""
|
"""
|
||||||
superproject = git_superproject.Superproject(self.manifest,
|
superproject = git_superproject.Superproject(self.manifest,
|
||||||
self.repodir,
|
self.repodir,
|
||||||
|
self.git_event_log,
|
||||||
quiet=opt.quiet)
|
quiet=opt.quiet)
|
||||||
|
if opt.local_only:
|
||||||
|
manifest_path = superproject.manifest_path
|
||||||
|
if manifest_path:
|
||||||
|
self._ReloadManifest(manifest_path, load_local_manifests)
|
||||||
|
return manifest_path
|
||||||
|
|
||||||
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)
|
||||||
manifest_path = superproject.UpdateProjectsRevisionId(all_projects)
|
update_result = superproject.UpdateProjectsRevisionId(all_projects)
|
||||||
if not manifest_path:
|
manifest_path = update_result.manifest_path
|
||||||
print('error: Update of revsionId from superproject has failed. '
|
superproject_logging_data['updatedrevisionid'] = bool(manifest_path)
|
||||||
'Please resync with --no-use-superproject option',
|
if manifest_path:
|
||||||
|
self._ReloadManifest(manifest_path, load_local_manifests)
|
||||||
|
else:
|
||||||
|
print('warning: Update of revisionId from superproject has failed, '
|
||||||
|
'repo sync will not use superproject to fetch the source. ',
|
||||||
|
'Please resync with the --no-use-superproject option to avoid this repo warning.',
|
||||||
file=sys.stderr)
|
file=sys.stderr)
|
||||||
sys.exit(1)
|
if update_result.fatal and opt.use_superproject is not None:
|
||||||
self._ReloadManifest(manifest_path, load_local_manifests)
|
sys.exit(1)
|
||||||
return manifest_path
|
return manifest_path
|
||||||
|
|
||||||
def _FetchProjectList(self, opt, projects):
|
def _FetchProjectList(self, opt, projects):
|
||||||
@ -363,7 +369,7 @@ later is required to fix a server side protocol bug.
|
|||||||
partial_clone_exclude=self.manifest.PartialCloneExclude)
|
partial_clone_exclude=self.manifest.PartialCloneExclude)
|
||||||
|
|
||||||
output = buf.getvalue()
|
output = buf.getvalue()
|
||||||
if opt.verbose and output:
|
if (opt.verbose or not success) and output:
|
||||||
print('\n' + output.rstrip())
|
print('\n' + output.rstrip())
|
||||||
|
|
||||||
if not success:
|
if not success:
|
||||||
@ -960,8 +966,14 @@ later is required to fix a server side protocol bug.
|
|||||||
self._UpdateManifestProject(opt, mp, manifest_name)
|
self._UpdateManifestProject(opt, mp, manifest_name)
|
||||||
|
|
||||||
load_local_manifests = not self.manifest.HasLocalManifests
|
load_local_manifests = not self.manifest.HasLocalManifests
|
||||||
if self._UseSuperproject(opt):
|
use_superproject = git_superproject.UseSuperproject(opt, self.manifest)
|
||||||
manifest_name = self._UpdateProjectsRevisionId(opt, args, load_local_manifests)
|
superproject_logging_data = {
|
||||||
|
'superproject': use_superproject,
|
||||||
|
'haslocalmanifests': bool(self.manifest.HasLocalManifests),
|
||||||
|
}
|
||||||
|
if use_superproject:
|
||||||
|
manifest_name = self._UpdateProjectsRevisionId(
|
||||||
|
opt, args, load_local_manifests, superproject_logging_data) or opt.manifest_name
|
||||||
|
|
||||||
if self.gitc_manifest:
|
if self.gitc_manifest:
|
||||||
gitc_manifest_projects = self.GetProjects(args,
|
gitc_manifest_projects = self.GetProjects(args,
|
||||||
@ -1075,6 +1087,15 @@ later is required to fix a server side protocol bug.
|
|||||||
file=sys.stderr)
|
file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Log the previous sync analysis state from the config.
|
||||||
|
self.git_event_log.LogConfigEvents(mp.config.GetSyncAnalysisStateData(),
|
||||||
|
'previous_sync_state')
|
||||||
|
|
||||||
|
# Update and log with the new sync analysis state.
|
||||||
|
mp.config.UpdateSyncAnalysisState(opt, superproject_logging_data)
|
||||||
|
self.git_event_log.LogConfigEvents(mp.config.GetSyncAnalysisStateData(),
|
||||||
|
'current_sync_state')
|
||||||
|
|
||||||
if not opt.quiet:
|
if not opt.quiet:
|
||||||
print('repo sync has finished successfully.')
|
print('repo sync has finished successfully.')
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ def _SplitEmails(values):
|
|||||||
|
|
||||||
|
|
||||||
class Upload(InteractiveCommand):
|
class Upload(InteractiveCommand):
|
||||||
common = True
|
COMMON = True
|
||||||
helpSummary = "Upload changes for code review"
|
helpSummary = "Upload changes for code review"
|
||||||
helpUsage = """
|
helpUsage = """
|
||||||
%prog [--re --cc] [<project>]...
|
%prog [--re --cc] [<project>]...
|
||||||
|
@ -25,7 +25,7 @@ class Version(Command, MirrorSafeCommand):
|
|||||||
wrapper_version = None
|
wrapper_version = None
|
||||||
wrapper_path = None
|
wrapper_path = None
|
||||||
|
|
||||||
common = False
|
COMMON = False
|
||||||
helpSummary = "Display the version of repo"
|
helpSummary = "Display the version of repo"
|
||||||
helpUsage = """
|
helpUsage = """
|
||||||
%prog
|
%prog
|
||||||
|
10
tests/fixtures/test.gitconfig
vendored
10
tests/fixtures/test.gitconfig
vendored
@ -11,3 +11,13 @@
|
|||||||
intk = 10k
|
intk = 10k
|
||||||
intm = 10m
|
intm = 10m
|
||||||
intg = 10g
|
intg = 10g
|
||||||
|
[repo "syncstate.main"]
|
||||||
|
synctime = 2021-07-29T22:07:43.463365Z
|
||||||
|
version = 1
|
||||||
|
[repo "syncstate.sys"]
|
||||||
|
argv = ['/usr/bin/pytest-3']
|
||||||
|
[repo "syncstate.superproject"]
|
||||||
|
test = false
|
||||||
|
[repo "syncstate.options"]
|
||||||
|
verbose = true
|
||||||
|
mpupdate = false
|
||||||
|
@ -104,6 +104,25 @@ class GitConfigReadOnlyTests(unittest.TestCase):
|
|||||||
for key, value in TESTS:
|
for key, value in TESTS:
|
||||||
self.assertEqual(value, self.config.GetInt('section.%s' % (key,)))
|
self.assertEqual(value, self.config.GetInt('section.%s' % (key,)))
|
||||||
|
|
||||||
|
def test_GetSyncAnalysisStateData(self):
|
||||||
|
"""Test config entries with a sync state analysis data."""
|
||||||
|
superproject_logging_data = {}
|
||||||
|
superproject_logging_data['test'] = False
|
||||||
|
options = type('options', (object,), {})()
|
||||||
|
options.verbose = 'true'
|
||||||
|
options.mp_update = 'false'
|
||||||
|
TESTS = (
|
||||||
|
('superproject.test', 'false'),
|
||||||
|
('options.verbose', 'true'),
|
||||||
|
('options.mpupdate', 'false'),
|
||||||
|
('main.version', '1'),
|
||||||
|
)
|
||||||
|
self.config.UpdateSyncAnalysisState(options, superproject_logging_data)
|
||||||
|
sync_data = self.config.GetSyncAnalysisStateData()
|
||||||
|
for key, value in TESTS:
|
||||||
|
self.assertEqual(sync_data[f'{git_config.SYNC_STATE_PREFIX}{key}'], value)
|
||||||
|
self.assertTrue(sync_data[f'{git_config.SYNC_STATE_PREFIX}main.synctime'])
|
||||||
|
|
||||||
|
|
||||||
class GitConfigReadWriteTests(unittest.TestCase):
|
class GitConfigReadWriteTests(unittest.TestCase):
|
||||||
"""Read/write tests of the GitConfig class."""
|
"""Read/write tests of the GitConfig class."""
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
"""Unittests for the git_superproject.py module."""
|
"""Unittests for the git_superproject.py module."""
|
||||||
|
|
||||||
|
import json
|
||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
import tempfile
|
import tempfile
|
||||||
@ -21,13 +22,20 @@ import unittest
|
|||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
import git_superproject
|
import git_superproject
|
||||||
|
import git_trace2_event_log
|
||||||
import manifest_xml
|
import manifest_xml
|
||||||
import platform_utils
|
import platform_utils
|
||||||
|
from test_manifest_xml import sort_attributes
|
||||||
|
|
||||||
|
|
||||||
class SuperprojectTestCase(unittest.TestCase):
|
class SuperprojectTestCase(unittest.TestCase):
|
||||||
"""TestCase for the Superproject module."""
|
"""TestCase for the Superproject module."""
|
||||||
|
|
||||||
|
PARENT_SID_KEY = 'GIT_TRACE2_PARENT_SID'
|
||||||
|
PARENT_SID_VALUE = 'parent_sid'
|
||||||
|
SELF_SID_REGEX = r'repo-\d+T\d+Z-.*'
|
||||||
|
FULL_SID_REGEX = r'^%s/%s' % (PARENT_SID_VALUE, SELF_SID_REGEX)
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
"""Set up superproject every time."""
|
"""Set up superproject every time."""
|
||||||
self.tempdir = tempfile.mkdtemp(prefix='repo_tests')
|
self.tempdir = tempfile.mkdtemp(prefix='repo_tests')
|
||||||
@ -37,6 +45,13 @@ class SuperprojectTestCase(unittest.TestCase):
|
|||||||
os.mkdir(self.repodir)
|
os.mkdir(self.repodir)
|
||||||
self.platform = platform.system().lower()
|
self.platform = platform.system().lower()
|
||||||
|
|
||||||
|
# By default we initialize with the expected case where
|
||||||
|
# repo launches us (so GIT_TRACE2_PARENT_SID is set).
|
||||||
|
env = {
|
||||||
|
self.PARENT_SID_KEY: self.PARENT_SID_VALUE,
|
||||||
|
}
|
||||||
|
self.git_event_log = git_trace2_event_log.EventLog(env=env)
|
||||||
|
|
||||||
# The manifest parsing really wants a git repo currently.
|
# The manifest parsing really wants a git repo currently.
|
||||||
gitdir = os.path.join(self.repodir, 'manifests.git')
|
gitdir = os.path.join(self.repodir, 'manifests.git')
|
||||||
os.mkdir(gitdir)
|
os.mkdir(gitdir)
|
||||||
@ -53,7 +68,8 @@ class SuperprojectTestCase(unittest.TestCase):
|
|||||||
<project path="art" name="platform/art" groups="notdefault,platform-""" + self.platform + """
|
<project path="art" name="platform/art" groups="notdefault,platform-""" + self.platform + """
|
||||||
" /></manifest>
|
" /></manifest>
|
||||||
""")
|
""")
|
||||||
self._superproject = git_superproject.Superproject(manifest, self.repodir)
|
self._superproject = git_superproject.Superproject(manifest, self.repodir,
|
||||||
|
self.git_event_log)
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
"""Tear down superproject every time."""
|
"""Tear down superproject every time."""
|
||||||
@ -65,14 +81,56 @@ class SuperprojectTestCase(unittest.TestCase):
|
|||||||
fp.write(data)
|
fp.write(data)
|
||||||
return manifest_xml.XmlManifest(self.repodir, self.manifest_file)
|
return manifest_xml.XmlManifest(self.repodir, self.manifest_file)
|
||||||
|
|
||||||
|
def verifyCommonKeys(self, log_entry, expected_event_name, full_sid=True):
|
||||||
|
"""Helper function to verify common event log keys."""
|
||||||
|
self.assertIn('event', log_entry)
|
||||||
|
self.assertIn('sid', log_entry)
|
||||||
|
self.assertIn('thread', log_entry)
|
||||||
|
self.assertIn('time', log_entry)
|
||||||
|
|
||||||
|
# Do basic data format validation.
|
||||||
|
self.assertEqual(expected_event_name, log_entry['event'])
|
||||||
|
if full_sid:
|
||||||
|
self.assertRegex(log_entry['sid'], self.FULL_SID_REGEX)
|
||||||
|
else:
|
||||||
|
self.assertRegex(log_entry['sid'], self.SELF_SID_REGEX)
|
||||||
|
self.assertRegex(log_entry['time'], r'^\d+-\d+-\d+T\d+:\d+:\d+\.\d+Z$')
|
||||||
|
|
||||||
|
def readLog(self, log_path):
|
||||||
|
"""Helper function to read log data into a list."""
|
||||||
|
log_data = []
|
||||||
|
with open(log_path, mode='rb') as f:
|
||||||
|
for line in f:
|
||||||
|
log_data.append(json.loads(line))
|
||||||
|
return log_data
|
||||||
|
|
||||||
|
def verifyErrorEvent(self):
|
||||||
|
"""Helper to verify that error event is written."""
|
||||||
|
|
||||||
|
with tempfile.TemporaryDirectory(prefix='event_log_tests') as tempdir:
|
||||||
|
log_path = self.git_event_log.Write(path=tempdir)
|
||||||
|
self.log_data = self.readLog(log_path)
|
||||||
|
|
||||||
|
self.assertEqual(len(self.log_data), 2)
|
||||||
|
error_event = self.log_data[1]
|
||||||
|
self.verifyCommonKeys(self.log_data[0], expected_event_name='version')
|
||||||
|
self.verifyCommonKeys(error_event, expected_event_name='error')
|
||||||
|
# Check for 'error' event specific fields.
|
||||||
|
self.assertIn('msg', error_event)
|
||||||
|
self.assertIn('fmt', error_event)
|
||||||
|
|
||||||
def test_superproject_get_superproject_no_superproject(self):
|
def test_superproject_get_superproject_no_superproject(self):
|
||||||
"""Test with no url."""
|
"""Test with no url."""
|
||||||
manifest = self.getXmlManifest("""
|
manifest = self.getXmlManifest("""
|
||||||
<manifest>
|
<manifest>
|
||||||
</manifest>
|
</manifest>
|
||||||
""")
|
""")
|
||||||
superproject = git_superproject.Superproject(manifest, self.repodir)
|
superproject = git_superproject.Superproject(manifest, self.repodir, self.git_event_log)
|
||||||
self.assertFalse(superproject.Sync())
|
# Test that exit condition is false when there is no superproject tag.
|
||||||
|
sync_result = superproject.Sync()
|
||||||
|
self.assertFalse(sync_result.success)
|
||||||
|
self.assertFalse(sync_result.fatal)
|
||||||
|
self.verifyErrorEvent()
|
||||||
|
|
||||||
def test_superproject_get_superproject_invalid_url(self):
|
def test_superproject_get_superproject_invalid_url(self):
|
||||||
"""Test with an invalid url."""
|
"""Test with an invalid url."""
|
||||||
@ -83,8 +141,10 @@ class SuperprojectTestCase(unittest.TestCase):
|
|||||||
<superproject name="superproject"/>
|
<superproject name="superproject"/>
|
||||||
</manifest>
|
</manifest>
|
||||||
""")
|
""")
|
||||||
superproject = git_superproject.Superproject(manifest, self.repodir)
|
superproject = git_superproject.Superproject(manifest, self.repodir, self.git_event_log)
|
||||||
self.assertFalse(superproject.Sync())
|
sync_result = superproject.Sync()
|
||||||
|
self.assertFalse(sync_result.success)
|
||||||
|
self.assertTrue(sync_result.fatal)
|
||||||
|
|
||||||
def test_superproject_get_superproject_invalid_branch(self):
|
def test_superproject_get_superproject_invalid_branch(self):
|
||||||
"""Test with an invalid branch."""
|
"""Test with an invalid branch."""
|
||||||
@ -95,21 +155,28 @@ class SuperprojectTestCase(unittest.TestCase):
|
|||||||
<superproject name="superproject"/>
|
<superproject name="superproject"/>
|
||||||
</manifest>
|
</manifest>
|
||||||
""")
|
""")
|
||||||
superproject = git_superproject.Superproject(manifest, self.repodir)
|
self._superproject = git_superproject.Superproject(manifest, self.repodir,
|
||||||
|
self.git_event_log)
|
||||||
with mock.patch.object(self._superproject, '_GetBranch', return_value='junk'):
|
with mock.patch.object(self._superproject, '_GetBranch', return_value='junk'):
|
||||||
self.assertFalse(superproject.Sync())
|
sync_result = self._superproject.Sync()
|
||||||
|
self.assertFalse(sync_result.success)
|
||||||
|
self.assertTrue(sync_result.fatal)
|
||||||
|
|
||||||
def test_superproject_get_superproject_mock_init(self):
|
def test_superproject_get_superproject_mock_init(self):
|
||||||
"""Test with _Init failing."""
|
"""Test with _Init failing."""
|
||||||
with mock.patch.object(self._superproject, '_Init', return_value=False):
|
with mock.patch.object(self._superproject, '_Init', return_value=False):
|
||||||
self.assertFalse(self._superproject.Sync())
|
sync_result = self._superproject.Sync()
|
||||||
|
self.assertFalse(sync_result.success)
|
||||||
|
self.assertTrue(sync_result.fatal)
|
||||||
|
|
||||||
def test_superproject_get_superproject_mock_fetch(self):
|
def test_superproject_get_superproject_mock_fetch(self):
|
||||||
"""Test with _Fetch failing."""
|
"""Test with _Fetch failing."""
|
||||||
with mock.patch.object(self._superproject, '_Init', return_value=True):
|
with mock.patch.object(self._superproject, '_Init', return_value=True):
|
||||||
os.mkdir(self._superproject._superproject_path)
|
os.mkdir(self._superproject._superproject_path)
|
||||||
with mock.patch.object(self._superproject, '_Fetch', return_value=False):
|
with mock.patch.object(self._superproject, '_Fetch', return_value=False):
|
||||||
self.assertFalse(self._superproject.Sync())
|
sync_result = self._superproject.Sync()
|
||||||
|
self.assertFalse(sync_result.success)
|
||||||
|
self.assertTrue(sync_result.fatal)
|
||||||
|
|
||||||
def test_superproject_get_all_project_commit_ids_mock_ls_tree(self):
|
def test_superproject_get_all_project_commit_ids_mock_ls_tree(self):
|
||||||
"""Test with LsTree being a mock."""
|
"""Test with LsTree being a mock."""
|
||||||
@ -121,12 +188,13 @@ class SuperprojectTestCase(unittest.TestCase):
|
|||||||
with mock.patch.object(self._superproject, '_Init', return_value=True):
|
with mock.patch.object(self._superproject, '_Init', return_value=True):
|
||||||
with mock.patch.object(self._superproject, '_Fetch', return_value=True):
|
with mock.patch.object(self._superproject, '_Fetch', return_value=True):
|
||||||
with mock.patch.object(self._superproject, '_LsTree', return_value=data):
|
with mock.patch.object(self._superproject, '_LsTree', return_value=data):
|
||||||
commit_ids = self._superproject._GetAllProjectsCommitIds()
|
commit_ids_result = self._superproject._GetAllProjectsCommitIds()
|
||||||
self.assertEqual(commit_ids, {
|
self.assertEqual(commit_ids_result.commit_ids, {
|
||||||
'art': '2c2724cb36cd5a9cec6c852c681efc3b7c6b86ea',
|
'art': '2c2724cb36cd5a9cec6c852c681efc3b7c6b86ea',
|
||||||
'bootable/recovery': 'e9d25da64d8d365dbba7c8ee00fe8c4473fe9a06',
|
'bootable/recovery': 'e9d25da64d8d365dbba7c8ee00fe8c4473fe9a06',
|
||||||
'build/bazel': 'ade9b7a0d874e25fff4bf2552488825c6f111928'
|
'build/bazel': 'ade9b7a0d874e25fff4bf2552488825c6f111928'
|
||||||
})
|
})
|
||||||
|
self.assertFalse(commit_ids_result.fatal)
|
||||||
|
|
||||||
def test_superproject_write_manifest_file(self):
|
def test_superproject_write_manifest_file(self):
|
||||||
"""Test with writing manifest to a file after setting revisionId."""
|
"""Test with writing manifest to a file after setting revisionId."""
|
||||||
@ -138,14 +206,14 @@ class SuperprojectTestCase(unittest.TestCase):
|
|||||||
manifest_path = self._superproject._WriteManfiestFile()
|
manifest_path = self._superproject._WriteManfiestFile()
|
||||||
self.assertIsNotNone(manifest_path)
|
self.assertIsNotNone(manifest_path)
|
||||||
with open(manifest_path, 'r') as fp:
|
with open(manifest_path, 'r') as fp:
|
||||||
manifest_xml = fp.read()
|
manifest_xml_data = fp.read()
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
manifest_xml,
|
sort_attributes(manifest_xml_data),
|
||||||
'<?xml version="1.0" ?><manifest>'
|
'<?xml version="1.0" ?><manifest>'
|
||||||
'<remote name="default-remote" fetch="http://localhost"/>'
|
'<remote fetch="http://localhost" name="default-remote"/>'
|
||||||
'<default remote="default-remote" revision="refs/heads/main"/>'
|
'<default remote="default-remote" revision="refs/heads/main"/>'
|
||||||
'<project name="platform/art" path="art" revision="ABCDEF" '
|
'<project groups="notdefault,platform-' + self.platform + '" '
|
||||||
'groups="notdefault,platform-' + self.platform + '"/>'
|
'name="platform/art" path="art" revision="ABCDEF" upstream="refs/heads/main"/>'
|
||||||
'<superproject name="superproject"/>'
|
'<superproject name="superproject"/>'
|
||||||
'</manifest>')
|
'</manifest>')
|
||||||
|
|
||||||
@ -162,40 +230,71 @@ class SuperprojectTestCase(unittest.TestCase):
|
|||||||
return_value=data):
|
return_value=data):
|
||||||
# Create temporary directory so that it can write the file.
|
# Create temporary directory so that it can write the file.
|
||||||
os.mkdir(self._superproject._superproject_path)
|
os.mkdir(self._superproject._superproject_path)
|
||||||
manifest_path = self._superproject.UpdateProjectsRevisionId(projects)
|
update_result = self._superproject.UpdateProjectsRevisionId(projects)
|
||||||
self.assertIsNotNone(manifest_path)
|
self.assertIsNotNone(update_result.manifest_path)
|
||||||
with open(manifest_path, 'r') as fp:
|
self.assertFalse(update_result.fatal)
|
||||||
manifest_xml = fp.read()
|
with open(update_result.manifest_path, 'r') as fp:
|
||||||
|
manifest_xml_data = fp.read()
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
manifest_xml,
|
sort_attributes(manifest_xml_data),
|
||||||
'<?xml version="1.0" ?><manifest>'
|
'<?xml version="1.0" ?><manifest>'
|
||||||
'<remote name="default-remote" fetch="http://localhost"/>'
|
'<remote fetch="http://localhost" name="default-remote"/>'
|
||||||
'<default remote="default-remote" revision="refs/heads/main"/>'
|
'<default remote="default-remote" revision="refs/heads/main"/>'
|
||||||
'<project name="platform/art" path="art" '
|
'<project groups="notdefault,platform-' + self.platform + '" '
|
||||||
'revision="2c2724cb36cd5a9cec6c852c681efc3b7c6b86ea" '
|
'name="platform/art" path="art" '
|
||||||
'groups="notdefault,platform-' + self.platform + '"/>'
|
'revision="2c2724cb36cd5a9cec6c852c681efc3b7c6b86ea" upstream="refs/heads/main"/>'
|
||||||
'<superproject name="superproject"/>'
|
'<superproject name="superproject"/>'
|
||||||
'</manifest>')
|
'</manifest>')
|
||||||
|
|
||||||
def test_superproject_update_project_revision_id_with_different_remotes(self):
|
def test_superproject_update_project_revision_id_no_superproject_tag(self):
|
||||||
"""Test update of commit ids of a manifest with mutiple remotes."""
|
"""Test update of commit ids of a manifest without superproject tag."""
|
||||||
|
manifest = self.getXmlManifest("""
|
||||||
|
<manifest>
|
||||||
|
<remote name="default-remote" fetch="http://localhost" />
|
||||||
|
<default remote="default-remote" revision="refs/heads/main" />
|
||||||
|
<project name="test-name"/>
|
||||||
|
</manifest>
|
||||||
|
""")
|
||||||
|
self.maxDiff = None
|
||||||
|
self._superproject = git_superproject.Superproject(manifest, self.repodir,
|
||||||
|
self.git_event_log)
|
||||||
|
self.assertEqual(len(self._superproject._manifest.projects), 1)
|
||||||
|
projects = self._superproject._manifest.projects
|
||||||
|
project = projects[0]
|
||||||
|
project.SetRevisionId('ABCDEF')
|
||||||
|
update_result = self._superproject.UpdateProjectsRevisionId(projects)
|
||||||
|
self.assertIsNone(update_result.manifest_path)
|
||||||
|
self.assertFalse(update_result.fatal)
|
||||||
|
self.verifyErrorEvent()
|
||||||
|
self.assertEqual(
|
||||||
|
sort_attributes(manifest.ToXml().toxml()),
|
||||||
|
'<?xml version="1.0" ?><manifest>'
|
||||||
|
'<remote fetch="http://localhost" name="default-remote"/>'
|
||||||
|
'<default remote="default-remote" revision="refs/heads/main"/>'
|
||||||
|
'<project name="test-name" revision="ABCDEF" upstream="refs/heads/main"/>'
|
||||||
|
'</manifest>')
|
||||||
|
|
||||||
|
def test_superproject_update_project_revision_id_from_local_manifest_group(self):
|
||||||
|
"""Test update of commit ids of a manifest that have local manifest no superproject group."""
|
||||||
|
local_group = manifest_xml.LOCAL_MANIFEST_GROUP_PREFIX + ':local'
|
||||||
manifest = self.getXmlManifest("""
|
manifest = self.getXmlManifest("""
|
||||||
<manifest>
|
<manifest>
|
||||||
<remote name="default-remote" fetch="http://localhost" />
|
<remote name="default-remote" fetch="http://localhost" />
|
||||||
<remote name="goog" fetch="http://localhost2" />
|
<remote name="goog" fetch="http://localhost2" />
|
||||||
<default remote="default-remote" revision="refs/heads/main" />
|
<default remote="default-remote" revision="refs/heads/main" />
|
||||||
<superproject name="superproject"/>
|
<superproject name="superproject"/>
|
||||||
<project path="vendor/x" name="platform/vendor/x" remote="goog" groups="vendor"
|
<project path="vendor/x" name="platform/vendor/x" remote="goog"
|
||||||
revision="master-with-vendor" clone-depth="1" />
|
groups=\"""" + local_group + """
|
||||||
|
" revision="master-with-vendor" clone-depth="1" />
|
||||||
<project path="art" name="platform/art" groups="notdefault,platform-""" + self.platform + """
|
<project path="art" name="platform/art" groups="notdefault,platform-""" + self.platform + """
|
||||||
" /></manifest>
|
" /></manifest>
|
||||||
""")
|
""")
|
||||||
self.maxDiff = None
|
self.maxDiff = None
|
||||||
self._superproject = git_superproject.Superproject(manifest, self.repodir)
|
self._superproject = git_superproject.Superproject(manifest, self.repodir,
|
||||||
|
self.git_event_log)
|
||||||
self.assertEqual(len(self._superproject._manifest.projects), 2)
|
self.assertEqual(len(self._superproject._manifest.projects), 2)
|
||||||
projects = self._superproject._manifest.projects
|
projects = self._superproject._manifest.projects
|
||||||
data = ('160000 commit 2c2724cb36cd5a9cec6c852c681efc3b7c6b86ea\tart\x00'
|
data = ('160000 commit 2c2724cb36cd5a9cec6c852c681efc3b7c6b86ea\tart\x00')
|
||||||
'160000 commit e9d25da64d8d365dbba7c8ee00fe8c4473fe9a06\tbootable/recovery\x00')
|
|
||||||
with mock.patch.object(self._superproject, '_Init', return_value=True):
|
with mock.patch.object(self._superproject, '_Init', return_value=True):
|
||||||
with mock.patch.object(self._superproject, '_Fetch', return_value=True):
|
with mock.patch.object(self._superproject, '_Fetch', return_value=True):
|
||||||
with mock.patch.object(self._superproject,
|
with mock.patch.object(self._superproject,
|
||||||
@ -203,21 +302,72 @@ class SuperprojectTestCase(unittest.TestCase):
|
|||||||
return_value=data):
|
return_value=data):
|
||||||
# Create temporary directory so that it can write the file.
|
# Create temporary directory so that it can write the file.
|
||||||
os.mkdir(self._superproject._superproject_path)
|
os.mkdir(self._superproject._superproject_path)
|
||||||
manifest_path = self._superproject.UpdateProjectsRevisionId(projects)
|
update_result = self._superproject.UpdateProjectsRevisionId(projects)
|
||||||
self.assertIsNotNone(manifest_path)
|
self.assertIsNotNone(update_result.manifest_path)
|
||||||
with open(manifest_path, 'r') as fp:
|
self.assertFalse(update_result.fatal)
|
||||||
manifest_xml = fp.read()
|
with open(update_result.manifest_path, 'r') as fp:
|
||||||
|
manifest_xml_data = fp.read()
|
||||||
|
# Verify platform/vendor/x's project revision hasn't changed.
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
manifest_xml,
|
sort_attributes(manifest_xml_data),
|
||||||
'<?xml version="1.0" ?><manifest>'
|
'<?xml version="1.0" ?><manifest>'
|
||||||
'<remote name="default-remote" fetch="http://localhost"/>'
|
'<remote fetch="http://localhost" name="default-remote"/>'
|
||||||
'<remote name="goog" fetch="http://localhost2"/>'
|
'<remote fetch="http://localhost2" name="goog"/>'
|
||||||
'<default remote="default-remote" revision="refs/heads/main"/>'
|
'<default remote="default-remote" revision="refs/heads/main"/>'
|
||||||
'<project name="platform/art" path="art" '
|
'<project groups="notdefault,platform-' + self.platform + '" '
|
||||||
'revision="2c2724cb36cd5a9cec6c852c681efc3b7c6b86ea" '
|
'name="platform/art" path="art" '
|
||||||
'groups="notdefault,platform-' + self.platform + '"/>'
|
'revision="2c2724cb36cd5a9cec6c852c681efc3b7c6b86ea" upstream="refs/heads/main"/>'
|
||||||
'<project name="platform/vendor/x" path="vendor/x" remote="goog" '
|
'<project clone-depth="1" groups="' + local_group + '" '
|
||||||
'revision="master-with-vendor" groups="vendor" clone-depth="1"/>'
|
'name="platform/vendor/x" path="vendor/x" remote="goog" '
|
||||||
|
'revision="master-with-vendor"/>'
|
||||||
|
'<superproject name="superproject"/>'
|
||||||
|
'</manifest>')
|
||||||
|
|
||||||
|
def test_superproject_update_project_revision_id_with_pinned_manifest(self):
|
||||||
|
"""Test update of commit ids of a pinned manifest."""
|
||||||
|
manifest = self.getXmlManifest("""
|
||||||
|
<manifest>
|
||||||
|
<remote name="default-remote" fetch="http://localhost" />
|
||||||
|
<default remote="default-remote" revision="refs/heads/main" />
|
||||||
|
<superproject name="superproject"/>
|
||||||
|
<project path="vendor/x" name="platform/vendor/x" revision="" />
|
||||||
|
<project path="vendor/y" name="platform/vendor/y"
|
||||||
|
revision="52d3c9f7c107839ece2319d077de0cd922aa9d8f" />
|
||||||
|
<project path="art" name="platform/art" groups="notdefault,platform-""" + self.platform + """
|
||||||
|
" /></manifest>
|
||||||
|
""")
|
||||||
|
self.maxDiff = None
|
||||||
|
self._superproject = git_superproject.Superproject(manifest, self.repodir,
|
||||||
|
self.git_event_log)
|
||||||
|
self.assertEqual(len(self._superproject._manifest.projects), 3)
|
||||||
|
projects = self._superproject._manifest.projects
|
||||||
|
data = ('160000 commit 2c2724cb36cd5a9cec6c852c681efc3b7c6b86ea\tart\x00'
|
||||||
|
'160000 commit e9d25da64d8d365dbba7c8ee00fe8c4473fe9a06\tvendor/x\x00')
|
||||||
|
with mock.patch.object(self._superproject, '_Init', return_value=True):
|
||||||
|
with mock.patch.object(self._superproject, '_Fetch', return_value=True):
|
||||||
|
with mock.patch.object(self._superproject,
|
||||||
|
'_LsTree',
|
||||||
|
return_value=data):
|
||||||
|
# Create temporary directory so that it can write the file.
|
||||||
|
os.mkdir(self._superproject._superproject_path)
|
||||||
|
update_result = self._superproject.UpdateProjectsRevisionId(projects)
|
||||||
|
self.assertIsNotNone(update_result.manifest_path)
|
||||||
|
self.assertFalse(update_result.fatal)
|
||||||
|
with open(update_result.manifest_path, 'r') as fp:
|
||||||
|
manifest_xml_data = fp.read()
|
||||||
|
# Verify platform/vendor/x's project revision hasn't changed.
|
||||||
|
self.assertEqual(
|
||||||
|
sort_attributes(manifest_xml_data),
|
||||||
|
'<?xml version="1.0" ?><manifest>'
|
||||||
|
'<remote fetch="http://localhost" name="default-remote"/>'
|
||||||
|
'<default remote="default-remote" revision="refs/heads/main"/>'
|
||||||
|
'<project groups="notdefault,platform-' + self.platform + '" '
|
||||||
|
'name="platform/art" path="art" '
|
||||||
|
'revision="2c2724cb36cd5a9cec6c852c681efc3b7c6b86ea" upstream="refs/heads/main"/>'
|
||||||
|
'<project name="platform/vendor/x" path="vendor/x" '
|
||||||
|
'revision="e9d25da64d8d365dbba7c8ee00fe8c4473fe9a06" upstream="refs/heads/main"/>'
|
||||||
|
'<project name="platform/vendor/y" path="vendor/y" '
|
||||||
|
'revision="52d3c9f7c107839ece2319d077de0cd922aa9d8f"/>'
|
||||||
'<superproject name="superproject"/>'
|
'<superproject name="superproject"/>'
|
||||||
'</manifest>')
|
'</manifest>')
|
||||||
|
|
||||||
|
@ -234,6 +234,30 @@ class EventLogTestCase(unittest.TestCase):
|
|||||||
self.assertEqual(len(self._log_data), 1)
|
self.assertEqual(len(self._log_data), 1)
|
||||||
self.verifyCommonKeys(self._log_data[0], expected_event_name='version')
|
self.verifyCommonKeys(self._log_data[0], expected_event_name='version')
|
||||||
|
|
||||||
|
def test_error_event(self):
|
||||||
|
"""Test and validate 'error' event data is valid.
|
||||||
|
|
||||||
|
Expected event log:
|
||||||
|
<version event>
|
||||||
|
<error event>
|
||||||
|
"""
|
||||||
|
msg = 'invalid option: --cahced'
|
||||||
|
fmt = 'invalid option: %s'
|
||||||
|
self._event_log_module.ErrorEvent(msg, fmt)
|
||||||
|
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), 2)
|
||||||
|
error_event = self._log_data[1]
|
||||||
|
self.verifyCommonKeys(self._log_data[0], expected_event_name='version')
|
||||||
|
self.verifyCommonKeys(error_event, expected_event_name='error')
|
||||||
|
# Check for 'error' event specific fields.
|
||||||
|
self.assertIn('msg', error_event)
|
||||||
|
self.assertIn('fmt', error_event)
|
||||||
|
self.assertEqual(error_event['msg'], msg)
|
||||||
|
self.assertEqual(error_event['fmt'], fmt)
|
||||||
|
|
||||||
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'))
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
import tempfile
|
import tempfile
|
||||||
import unittest
|
import unittest
|
||||||
@ -63,6 +64,30 @@ if os.path.sep != '/':
|
|||||||
INVALID_FS_PATHS += tuple(x.replace('/', os.path.sep) for x in INVALID_FS_PATHS)
|
INVALID_FS_PATHS += tuple(x.replace('/', os.path.sep) for x in INVALID_FS_PATHS)
|
||||||
|
|
||||||
|
|
||||||
|
def sort_attributes(manifest):
|
||||||
|
"""Sort the attributes of all elements alphabetically.
|
||||||
|
|
||||||
|
This is needed because different versions of the toxml() function from
|
||||||
|
xml.dom.minidom outputs the attributes of elements in different orders.
|
||||||
|
Before Python 3.8 they were output alphabetically, later versions preserve
|
||||||
|
the order specified by the user.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
manifest: String containing an XML manifest.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The XML manifest with the attributes of all elements sorted alphabetically.
|
||||||
|
"""
|
||||||
|
new_manifest = ''
|
||||||
|
# This will find every element in the XML manifest, whether they have
|
||||||
|
# attributes or not. This simplifies recreating the manifest below.
|
||||||
|
matches = re.findall(r'(<[/?]?[a-z-]+\s*)((?:\S+?="[^"]+"\s*?)*)(\s*[/?]?>)', manifest)
|
||||||
|
for head, attrs, tail in matches:
|
||||||
|
m = re.findall(r'\S+?="[^"]+"', attrs)
|
||||||
|
new_manifest += head + ' '.join(sorted(m)) + tail
|
||||||
|
return new_manifest
|
||||||
|
|
||||||
|
|
||||||
class ManifestParseTestCase(unittest.TestCase):
|
class ManifestParseTestCase(unittest.TestCase):
|
||||||
"""TestCase for parsing manifests."""
|
"""TestCase for parsing manifests."""
|
||||||
|
|
||||||
@ -254,13 +279,32 @@ class XmlManifestTests(ManifestParseTestCase):
|
|||||||
self.assertEqual(manifest.superproject['name'], 'superproject')
|
self.assertEqual(manifest.superproject['name'], 'superproject')
|
||||||
self.assertEqual(manifest.superproject['remote'].name, 'test-remote')
|
self.assertEqual(manifest.superproject['remote'].name, 'test-remote')
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
manifest.ToXml().toxml(),
|
sort_attributes(manifest.ToXml().toxml()),
|
||||||
'<?xml version="1.0" ?><manifest>'
|
'<?xml version="1.0" ?><manifest>'
|
||||||
'<remote name="test-remote" fetch="http://localhost"/>'
|
'<remote fetch="http://localhost" name="test-remote"/>'
|
||||||
'<default remote="test-remote" revision="refs/heads/main"/>'
|
'<default remote="test-remote" revision="refs/heads/main"/>'
|
||||||
'<superproject name="superproject"/>'
|
'<superproject name="superproject"/>'
|
||||||
'</manifest>')
|
'</manifest>')
|
||||||
|
|
||||||
|
def test_remote_annotations(self):
|
||||||
|
"""Check remote settings."""
|
||||||
|
manifest = self.getXmlManifest("""
|
||||||
|
<manifest>
|
||||||
|
<remote name="test-remote" fetch="http://localhost">
|
||||||
|
<annotation name="foo" value="bar"/>
|
||||||
|
</remote>
|
||||||
|
</manifest>
|
||||||
|
""")
|
||||||
|
self.assertEqual(manifest.remotes['test-remote'].annotations[0].name, 'foo')
|
||||||
|
self.assertEqual(manifest.remotes['test-remote'].annotations[0].value, 'bar')
|
||||||
|
self.assertEqual(
|
||||||
|
sort_attributes(manifest.ToXml().toxml()),
|
||||||
|
'<?xml version="1.0" ?><manifest>'
|
||||||
|
'<remote fetch="http://localhost" name="test-remote">'
|
||||||
|
'<annotation name="foo" value="bar"/>'
|
||||||
|
'</remote>'
|
||||||
|
'</manifest>')
|
||||||
|
|
||||||
|
|
||||||
class IncludeElementTests(ManifestParseTestCase):
|
class IncludeElementTests(ManifestParseTestCase):
|
||||||
"""Tests for <include>."""
|
"""Tests for <include>."""
|
||||||
@ -408,11 +452,11 @@ class ProjectElementTests(ManifestParseTestCase):
|
|||||||
project = manifest.projects[0]
|
project = manifest.projects[0]
|
||||||
project.SetRevisionId('ABCDEF')
|
project.SetRevisionId('ABCDEF')
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
manifest.ToXml().toxml(),
|
sort_attributes(manifest.ToXml().toxml()),
|
||||||
'<?xml version="1.0" ?><manifest>'
|
'<?xml version="1.0" ?><manifest>'
|
||||||
'<remote name="default-remote" fetch="http://localhost"/>'
|
'<remote fetch="http://localhost" name="default-remote"/>'
|
||||||
'<default remote="default-remote" revision="refs/heads/main"/>'
|
'<default remote="default-remote" revision="refs/heads/main"/>'
|
||||||
'<project name="test-name" revision="ABCDEF"/>'
|
'<project name="test-name" revision="ABCDEF" upstream="refs/heads/main"/>'
|
||||||
'</manifest>')
|
'</manifest>')
|
||||||
|
|
||||||
def test_trailing_slash(self):
|
def test_trailing_slash(self):
|
||||||
@ -516,9 +560,9 @@ class SuperProjectElementTests(ManifestParseTestCase):
|
|||||||
self.assertEqual(manifest.superproject['remote'].name, 'test-remote')
|
self.assertEqual(manifest.superproject['remote'].name, 'test-remote')
|
||||||
self.assertEqual(manifest.superproject['remote'].url, 'http://localhost/superproject')
|
self.assertEqual(manifest.superproject['remote'].url, 'http://localhost/superproject')
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
manifest.ToXml().toxml(),
|
sort_attributes(manifest.ToXml().toxml()),
|
||||||
'<?xml version="1.0" ?><manifest>'
|
'<?xml version="1.0" ?><manifest>'
|
||||||
'<remote name="test-remote" fetch="http://localhost"/>'
|
'<remote fetch="http://localhost" name="test-remote"/>'
|
||||||
'<default remote="test-remote" revision="refs/heads/main"/>'
|
'<default remote="test-remote" revision="refs/heads/main"/>'
|
||||||
'<superproject name="superproject"/>'
|
'<superproject name="superproject"/>'
|
||||||
'</manifest>')
|
'</manifest>')
|
||||||
@ -537,10 +581,10 @@ class SuperProjectElementTests(ManifestParseTestCase):
|
|||||||
self.assertEqual(manifest.superproject['remote'].name, 'superproject-remote')
|
self.assertEqual(manifest.superproject['remote'].name, 'superproject-remote')
|
||||||
self.assertEqual(manifest.superproject['remote'].url, 'http://localhost/platform/superproject')
|
self.assertEqual(manifest.superproject['remote'].url, 'http://localhost/platform/superproject')
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
manifest.ToXml().toxml(),
|
sort_attributes(manifest.ToXml().toxml()),
|
||||||
'<?xml version="1.0" ?><manifest>'
|
'<?xml version="1.0" ?><manifest>'
|
||||||
'<remote name="default-remote" fetch="http://localhost"/>'
|
'<remote fetch="http://localhost" name="default-remote"/>'
|
||||||
'<remote name="superproject-remote" fetch="http://localhost"/>'
|
'<remote fetch="http://localhost" name="superproject-remote"/>'
|
||||||
'<default remote="default-remote" revision="refs/heads/main"/>'
|
'<default remote="default-remote" revision="refs/heads/main"/>'
|
||||||
'<superproject name="platform/superproject" remote="superproject-remote"/>'
|
'<superproject name="platform/superproject" remote="superproject-remote"/>'
|
||||||
'</manifest>')
|
'</manifest>')
|
||||||
@ -557,9 +601,9 @@ class SuperProjectElementTests(ManifestParseTestCase):
|
|||||||
self.assertEqual(manifest.superproject['name'], 'superproject')
|
self.assertEqual(manifest.superproject['name'], 'superproject')
|
||||||
self.assertEqual(manifest.superproject['remote'].name, 'default-remote')
|
self.assertEqual(manifest.superproject['remote'].name, 'default-remote')
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
manifest.ToXml().toxml(),
|
sort_attributes(manifest.ToXml().toxml()),
|
||||||
'<?xml version="1.0" ?><manifest>'
|
'<?xml version="1.0" ?><manifest>'
|
||||||
'<remote name="default-remote" fetch="http://localhost"/>'
|
'<remote fetch="http://localhost" name="default-remote"/>'
|
||||||
'<default remote="default-remote" revision="refs/heads/main"/>'
|
'<default remote="default-remote" revision="refs/heads/main"/>'
|
||||||
'<superproject name="superproject"/>'
|
'<superproject name="superproject"/>'
|
||||||
'</manifest>')
|
'</manifest>')
|
||||||
@ -582,3 +626,92 @@ class ContactinfoElementTests(ManifestParseTestCase):
|
|||||||
'<?xml version="1.0" ?><manifest>'
|
'<?xml version="1.0" ?><manifest>'
|
||||||
f'<contactinfo bugurl="{bugurl}"/>'
|
f'<contactinfo bugurl="{bugurl}"/>'
|
||||||
'</manifest>')
|
'</manifest>')
|
||||||
|
|
||||||
|
|
||||||
|
class DefaultElementTests(ManifestParseTestCase):
|
||||||
|
"""Tests for <default>."""
|
||||||
|
|
||||||
|
def test_default(self):
|
||||||
|
"""Check default settings."""
|
||||||
|
a = manifest_xml._Default()
|
||||||
|
a.revisionExpr = 'foo'
|
||||||
|
a.remote = manifest_xml._XmlRemote(name='remote')
|
||||||
|
b = manifest_xml._Default()
|
||||||
|
b.revisionExpr = 'bar'
|
||||||
|
self.assertEqual(a, a)
|
||||||
|
self.assertNotEqual(a, b)
|
||||||
|
self.assertNotEqual(b, a.remote)
|
||||||
|
self.assertNotEqual(a, 123)
|
||||||
|
self.assertNotEqual(a, None)
|
||||||
|
|
||||||
|
|
||||||
|
class RemoteElementTests(ManifestParseTestCase):
|
||||||
|
"""Tests for <remote>."""
|
||||||
|
|
||||||
|
def test_remote(self):
|
||||||
|
"""Check remote settings."""
|
||||||
|
a = manifest_xml._XmlRemote(name='foo')
|
||||||
|
a.AddAnnotation('key1', 'value1', 'true')
|
||||||
|
b = manifest_xml._XmlRemote(name='foo')
|
||||||
|
b.AddAnnotation('key2', 'value1', 'true')
|
||||||
|
c = manifest_xml._XmlRemote(name='foo')
|
||||||
|
c.AddAnnotation('key1', 'value2', 'true')
|
||||||
|
d = manifest_xml._XmlRemote(name='foo')
|
||||||
|
d.AddAnnotation('key1', 'value1', 'false')
|
||||||
|
self.assertEqual(a, a)
|
||||||
|
self.assertNotEqual(a, b)
|
||||||
|
self.assertNotEqual(a, c)
|
||||||
|
self.assertNotEqual(a, d)
|
||||||
|
self.assertNotEqual(a, manifest_xml._Default())
|
||||||
|
self.assertNotEqual(a, 123)
|
||||||
|
self.assertNotEqual(a, None)
|
||||||
|
|
||||||
|
|
||||||
|
class RemoveProjectElementTests(ManifestParseTestCase):
|
||||||
|
"""Tests for <remove-project>."""
|
||||||
|
|
||||||
|
def test_remove_one_project(self):
|
||||||
|
manifest = self.getXmlManifest("""
|
||||||
|
<manifest>
|
||||||
|
<remote name="default-remote" fetch="http://localhost" />
|
||||||
|
<default remote="default-remote" revision="refs/heads/main" />
|
||||||
|
<project name="myproject" />
|
||||||
|
<remove-project name="myproject" />
|
||||||
|
</manifest>
|
||||||
|
""")
|
||||||
|
self.assertEqual(manifest.projects, [])
|
||||||
|
|
||||||
|
def test_remove_one_project_one_remains(self):
|
||||||
|
manifest = self.getXmlManifest("""
|
||||||
|
<manifest>
|
||||||
|
<remote name="default-remote" fetch="http://localhost" />
|
||||||
|
<default remote="default-remote" revision="refs/heads/main" />
|
||||||
|
<project name="myproject" />
|
||||||
|
<project name="yourproject" />
|
||||||
|
<remove-project name="myproject" />
|
||||||
|
</manifest>
|
||||||
|
""")
|
||||||
|
|
||||||
|
self.assertEqual(len(manifest.projects), 1)
|
||||||
|
self.assertEqual(manifest.projects[0].name, 'yourproject')
|
||||||
|
|
||||||
|
def test_remove_one_project_doesnt_exist(self):
|
||||||
|
with self.assertRaises(manifest_xml.ManifestParseError):
|
||||||
|
manifest = self.getXmlManifest("""
|
||||||
|
<manifest>
|
||||||
|
<remote name="default-remote" fetch="http://localhost" />
|
||||||
|
<default remote="default-remote" revision="refs/heads/main" />
|
||||||
|
<remove-project name="myproject" />
|
||||||
|
</manifest>
|
||||||
|
""")
|
||||||
|
manifest.projects
|
||||||
|
|
||||||
|
def test_remove_one_optional_project_doesnt_exist(self):
|
||||||
|
manifest = self.getXmlManifest("""
|
||||||
|
<manifest>
|
||||||
|
<remote name="default-remote" fetch="http://localhost" />
|
||||||
|
<default remote="default-remote" revision="refs/heads/main" />
|
||||||
|
<remove-project name="myproject" optional="true" />
|
||||||
|
</manifest>
|
||||||
|
""")
|
||||||
|
self.assertEqual(manifest.projects, [])
|
||||||
|
Reference in New Issue
Block a user