mirror of
https://gerrit.googlesource.com/git-repo
synced 2025-07-04 20:17:16 +00:00
Compare commits
17 Commits
Author | SHA1 | Date | |
---|---|---|---|
91d9587e45 | |||
0bcc2d28d4 | |||
ec0ba2777f | |||
9da67feecf | |||
b0b164a87f | |||
b71d61d34e | |||
8f997b38cb | |||
0eb2d3c8a0 | |||
e4d20372b2 | |||
1e01a74445 | |||
7c321f1bf6 | |||
7ac12a9b22 | |||
0b304c06ff | |||
4997d1c838 | |||
5b3a57c3ff | |||
6f8c85ce2a | |||
6856f98467 |
8
.gitignore
vendored
8
.gitignore
vendored
@ -1,3 +1,11 @@
|
|||||||
|
*.egg-info/
|
||||||
|
*.log
|
||||||
*.pyc
|
*.pyc
|
||||||
|
__pycache__
|
||||||
|
/dist
|
||||||
.repopickle_*
|
.repopickle_*
|
||||||
/repoc
|
/repoc
|
||||||
|
/.tox
|
||||||
|
|
||||||
|
# PyCharm related
|
||||||
|
/.idea/
|
||||||
|
6
MANIFEST.in
Normal file
6
MANIFEST.in
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
graft docs hooks tests
|
||||||
|
include *.py
|
||||||
|
include LICENSE
|
||||||
|
include git_ssh
|
||||||
|
include repo
|
||||||
|
include run_tests
|
@ -14,6 +14,7 @@ that you can put anywhere in your path.
|
|||||||
* [repo Manifest Format](./docs/manifest-format.md)
|
* [repo Manifest Format](./docs/manifest-format.md)
|
||||||
* [repo Hooks](./docs/repo-hooks.md)
|
* [repo Hooks](./docs/repo-hooks.md)
|
||||||
* [Submitting patches](./SUBMITTING_PATCHES.md)
|
* [Submitting patches](./SUBMITTING_PATCHES.md)
|
||||||
|
* Running Repo in [Microsoft Windows](./docs/windows.md)
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
|
@ -69,10 +69,38 @@ suppressed in the included `.flake8` file.
|
|||||||
|
|
||||||
## Running tests
|
## Running tests
|
||||||
|
|
||||||
There is a [`./run_tests`](./run_tests) helper script for quickly invoking all
|
We use [pytest](https://pytest.org/) and [tox](https://tox.readthedocs.io/) for
|
||||||
of our unittests. The coverage isn't great currently, but it should still be
|
running tests. You should make sure to install those first.
|
||||||
run for all commits.
|
|
||||||
|
|
||||||
|
To run the full suite against all supported Python versions, simply execute:
|
||||||
|
```sh
|
||||||
|
$ tox -p auto
|
||||||
|
```
|
||||||
|
|
||||||
|
We have [`./run_tests`](./run_tests) which is a simple wrapper around `pytest`:
|
||||||
|
```sh
|
||||||
|
# Run the full suite against the default Python version.
|
||||||
|
$ ./run_tests
|
||||||
|
# List each test as it runs.
|
||||||
|
$ ./run_tests -v
|
||||||
|
|
||||||
|
# Run a specific unittest module (and all tests in it).
|
||||||
|
$ ./run_tests tests/test_git_command.py
|
||||||
|
|
||||||
|
# Run a specific testsuite in a specific unittest module.
|
||||||
|
$ ./run_tests tests/test_editor.py::EditString
|
||||||
|
|
||||||
|
# Run a single test.
|
||||||
|
$ ./run_tests tests/test_editor.py::EditString::test_cat_editor
|
||||||
|
|
||||||
|
# List all available tests.
|
||||||
|
$ ./run_tests --collect-only
|
||||||
|
|
||||||
|
# Run a single test using substring match.
|
||||||
|
$ ./run_tests -k test_cat_editor
|
||||||
|
```
|
||||||
|
|
||||||
|
The coverage isn't great currently, but it should still be run for all commits.
|
||||||
Adding more unittests for changes you make would be greatly appreciated :).
|
Adding more unittests for changes you make would be greatly appreciated :).
|
||||||
Check out the [tests/](./tests/) subdirectory for more details.
|
Check out the [tests/](./tests/) subdirectory for more details.
|
||||||
|
|
||||||
|
144
docs/windows.md
Normal file
144
docs/windows.md
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
# Microsoft Windows Details
|
||||||
|
|
||||||
|
Repo is primarily developed on Linux with a lot of users on macOS.
|
||||||
|
Windows is, unfortunately, not a common platform.
|
||||||
|
There is support in repo for Windows, but there might be some rough edges.
|
||||||
|
|
||||||
|
Keep in mind that Windows in general is "best effort" and "community supported".
|
||||||
|
That means we don't actively test or verify behavior, but rely heavily on users
|
||||||
|
to report problems back to us, and to contribute fixes as needed.
|
||||||
|
|
||||||
|
[TOC]
|
||||||
|
|
||||||
|
## Windows
|
||||||
|
|
||||||
|
We only support Windows 10 or newer.
|
||||||
|
This is largely due to symlinks not being available in older versions, but it's
|
||||||
|
also due to most developers not using Windows.
|
||||||
|
|
||||||
|
We will never add code specific to older versions of Windows.
|
||||||
|
It might work, but it most likely won't, so please don't bother asking.
|
||||||
|
|
||||||
|
## Symlinks
|
||||||
|
|
||||||
|
Repo will use symlinks heavily internally.
|
||||||
|
On *NIX platforms, this isn't an issue, but Windows makes it a bit difficult.
|
||||||
|
|
||||||
|
There are some documents out there for how to do this, but usually the easiest
|
||||||
|
answer is to run your shell as an Administrator and invoke repo/git in that.
|
||||||
|
|
||||||
|
This isn't a great solution, but Windows doesn't make this easy, so here we are.
|
||||||
|
|
||||||
|
### Launch Git Bash
|
||||||
|
|
||||||
|
If you install Git Bash (see below), you can launch that with appropriate
|
||||||
|
permissions so that all programs "just work".
|
||||||
|
|
||||||
|
* Open the Start Menu (i.e. press the ⊞ key).
|
||||||
|
* Find/search for "Git Bash".
|
||||||
|
* Right click it and select "Run as administrator".
|
||||||
|
|
||||||
|
*** note
|
||||||
|
**NB**: This environment is only needed when running `repo`, or any specific `git`
|
||||||
|
command that might involve symlinks (e.g. `pull` or `checkout`).
|
||||||
|
You do not need to run all your commands in here such as your editor.
|
||||||
|
***
|
||||||
|
|
||||||
|
### Symlinks with GNU tools
|
||||||
|
|
||||||
|
If you want to use `ln -s` inside of the default Git/bash shell, you might need
|
||||||
|
to export this environment variable:
|
||||||
|
```sh
|
||||||
|
$ export MSYS="winsymlinks:nativestrict"
|
||||||
|
```
|
||||||
|
|
||||||
|
Otherwise `ln -s` will copy files and not actually create a symlink.
|
||||||
|
This also helps `tar` unpack symlinks, so that's nice.
|
||||||
|
|
||||||
|
### References
|
||||||
|
|
||||||
|
* https://github.com/git-for-windows/git/wiki/Symbolic-Links
|
||||||
|
* https://blogs.windows.com/windowsdeveloper/2016/12/02/symlinks-windows-10/
|
||||||
|
|
||||||
|
## Python
|
||||||
|
|
||||||
|
You should make sure to be running Python 3.6 or newer under Windows.
|
||||||
|
Python 2 might work, but due to already limited platform testing, you should
|
||||||
|
only run newer Python versions.
|
||||||
|
See our [Python Support](./python-support.md) document for more details.
|
||||||
|
|
||||||
|
You can grab the latest Windows installer here:<br>
|
||||||
|
https://www.python.org/downloads/release/python-3
|
||||||
|
|
||||||
|
## Git
|
||||||
|
|
||||||
|
You should install the most recent version of Git for Windows:<br>
|
||||||
|
https://git-scm.com/download/win
|
||||||
|
|
||||||
|
When installing, make sure to turn on "Enable symbolic links" when prompted.
|
||||||
|
|
||||||
|
If you've already installed Git for Windows, you can simply download the latest
|
||||||
|
installer from above and run it again.
|
||||||
|
It should safely upgrade things in situ for you.
|
||||||
|
This is useful if you want to switch the symbolic link option after the fact.
|
||||||
|
|
||||||
|
## Shell
|
||||||
|
|
||||||
|
We don't have a specific requirement for shell environments when running repo.
|
||||||
|
Most developers use MinTTY/bash that's included with the Git for Windows install
|
||||||
|
(so see above for installing Git).
|
||||||
|
|
||||||
|
Command & Powershell & the Windows Terminal probably work.
|
||||||
|
Who knows!
|
||||||
|
|
||||||
|
## FAQ
|
||||||
|
|
||||||
|
### repo upload always complains about allowing hooks or using --no-verify!
|
||||||
|
|
||||||
|
When using `repo upload` in projects that have custom repohooks, you might get
|
||||||
|
an error like the following:
|
||||||
|
```sh
|
||||||
|
$ repo upload
|
||||||
|
ERROR: You must allow the pre-upload hook or use --no-verify.
|
||||||
|
```
|
||||||
|
|
||||||
|
This can be confusing as you never get prompted.
|
||||||
|
[MinTTY has a bug][mintty] that breaks isatty checking inside of repo which
|
||||||
|
causes repo to never interactively prompt the user which means the upload check
|
||||||
|
always fails.
|
||||||
|
|
||||||
|
You can workaround this by manually granting consent when uploading.
|
||||||
|
Simply add the `--verify` option whenever uploading:
|
||||||
|
```sh
|
||||||
|
$ repo upload --verify
|
||||||
|
```
|
||||||
|
|
||||||
|
You will have to specify this flag every time you upload.
|
||||||
|
|
||||||
|
[mintty]: https://github.com/mintty/mintty/issues/56
|
||||||
|
|
||||||
|
### repohooks always fail with an close_fds error.
|
||||||
|
|
||||||
|
When using the [reference repohooks project][repohooks] included in AOSP,
|
||||||
|
you might see errors like this when running `repo upload`:
|
||||||
|
```sh
|
||||||
|
$ repo upload
|
||||||
|
ERROR: Traceback (most recent call last):
|
||||||
|
...
|
||||||
|
File "C:\...\lib\subprocess.py", line 351, in __init__
|
||||||
|
raise ValueError("close_fds is not supported on Windows "
|
||||||
|
ValueError: close_fds is not supported on Windows platforms if you redirect stdin/stderr/stdout
|
||||||
|
|
||||||
|
Failed to run main() for pre-upload hook; see traceback above.
|
||||||
|
```
|
||||||
|
|
||||||
|
This error shows up when using Python 2.
|
||||||
|
You should upgrade to Python 3 instead (see above).
|
||||||
|
|
||||||
|
If you already have Python 3 installed, make sure it's the default version.
|
||||||
|
Running `python --version` should say `Python 3`, not `Python 2`.
|
||||||
|
If you didn't install the Python versions, or don't have permission to change
|
||||||
|
the default version, you can probably workaround this by changing `$PATH` in
|
||||||
|
your shell so the Python 3 version is found first.
|
||||||
|
|
||||||
|
[repohooks]: https://android.googlesource.com/platform/tools/repohooks
|
15
main.py
15
main.py
@ -27,6 +27,7 @@ import netrc
|
|||||||
import optparse
|
import optparse
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import textwrap
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from pyversion import is_python3
|
from pyversion import is_python3
|
||||||
@ -71,8 +72,10 @@ if not is_python3():
|
|||||||
input = raw_input
|
input = raw_input
|
||||||
|
|
||||||
global_options = optparse.OptionParser(
|
global_options = optparse.OptionParser(
|
||||||
usage="repo [-p|--paginate|--no-pager] COMMAND [ARGS]"
|
usage='repo [-p|--paginate|--no-pager] COMMAND [ARGS]',
|
||||||
)
|
add_help_option=False)
|
||||||
|
global_options.add_option('-h', '--help', action='store_true',
|
||||||
|
help='show this help message 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')
|
||||||
@ -123,6 +126,14 @@ class _Repo(object):
|
|||||||
argv = []
|
argv = []
|
||||||
gopts, _gargs = global_options.parse_args(glob)
|
gopts, _gargs = global_options.parse_args(glob)
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
def _Run(self, name, gopts, argv):
|
def _Run(self, name, gopts, argv):
|
||||||
|
@ -80,7 +80,7 @@ class FileDescriptorStreams(object):
|
|||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def _create_stream(fd, dest, std_name):
|
def _create_stream(self, fd, dest, std_name):
|
||||||
""" Creates a new stream wrapping an existing file descriptor.
|
""" Creates a new stream wrapping an existing file descriptor.
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
import errno
|
import errno
|
||||||
|
|
||||||
|
from pyversion import is_python3
|
||||||
from ctypes import WinDLL, get_last_error, FormatError, WinError, addressof
|
from ctypes import WinDLL, get_last_error, FormatError, WinError, addressof
|
||||||
from ctypes import c_buffer
|
from ctypes import c_buffer
|
||||||
from ctypes.wintypes import BOOL, BOOLEAN, LPCWSTR, DWORD, HANDLE, POINTER, c_ubyte
|
from ctypes.wintypes import BOOL, BOOLEAN, LPCWSTR, DWORD, HANDLE, POINTER, c_ubyte
|
||||||
@ -179,7 +180,7 @@ def readlink(path):
|
|||||||
if reparse_point_handle == INVALID_HANDLE_VALUE:
|
if reparse_point_handle == INVALID_HANDLE_VALUE:
|
||||||
_raise_winerror(
|
_raise_winerror(
|
||||||
get_last_error(),
|
get_last_error(),
|
||||||
'Error opening symblic link \"%s\"'.format(path))
|
'Error opening symbolic link \"%s\"'.format(path))
|
||||||
target_buffer = c_buffer(MAXIMUM_REPARSE_DATA_BUFFER_SIZE)
|
target_buffer = c_buffer(MAXIMUM_REPARSE_DATA_BUFFER_SIZE)
|
||||||
n_bytes_returned = DWORD()
|
n_bytes_returned = DWORD()
|
||||||
io_result = DeviceIoControl(reparse_point_handle,
|
io_result = DeviceIoControl(reparse_point_handle,
|
||||||
@ -194,7 +195,7 @@ def readlink(path):
|
|||||||
if not io_result:
|
if not io_result:
|
||||||
_raise_winerror(
|
_raise_winerror(
|
||||||
get_last_error(),
|
get_last_error(),
|
||||||
'Error reading symblic link \"%s\"'.format(path))
|
'Error reading symbolic link \"%s\"'.format(path))
|
||||||
rdb = REPARSE_DATA_BUFFER.from_buffer(target_buffer)
|
rdb = REPARSE_DATA_BUFFER.from_buffer(target_buffer)
|
||||||
if rdb.ReparseTag == IO_REPARSE_TAG_SYMLINK:
|
if rdb.ReparseTag == IO_REPARSE_TAG_SYMLINK:
|
||||||
return _preserve_encoding(path, rdb.SymbolicLinkReparseBuffer.PrintName)
|
return _preserve_encoding(path, rdb.SymbolicLinkReparseBuffer.PrintName)
|
||||||
@ -203,11 +204,15 @@ def readlink(path):
|
|||||||
# Unsupported reparse point type
|
# Unsupported reparse point type
|
||||||
_raise_winerror(
|
_raise_winerror(
|
||||||
ERROR_NOT_SUPPORTED,
|
ERROR_NOT_SUPPORTED,
|
||||||
'Error reading symblic link \"%s\"'.format(path))
|
'Error reading symbolic link \"%s\"'.format(path))
|
||||||
|
|
||||||
|
|
||||||
def _preserve_encoding(source, target):
|
def _preserve_encoding(source, target):
|
||||||
"""Ensures target is the same string type (i.e. unicode or str) as source."""
|
"""Ensures target is the same string type (i.e. unicode or str) as source."""
|
||||||
|
|
||||||
|
if is_python3():
|
||||||
|
return target
|
||||||
|
|
||||||
if isinstance(source, unicode):
|
if isinstance(source, unicode):
|
||||||
return unicode(target)
|
return unicode(target)
|
||||||
return str(target)
|
return str(target)
|
||||||
|
53
project.py
53
project.py
@ -1065,7 +1065,7 @@ class Project(object):
|
|||||||
"""Prints the status of the repository to stdout.
|
"""Prints the status of the repository to stdout.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
output: If specified, redirect the output to this object.
|
output_redir: If specified, redirect the output to this object.
|
||||||
quiet: If True then only print the project name. Do not print
|
quiet: If True then only print the project name. Do not print
|
||||||
the modified files, branch name, etc.
|
the modified files, branch name, etc.
|
||||||
"""
|
"""
|
||||||
@ -2235,16 +2235,6 @@ class Project(object):
|
|||||||
cmd.append('--update-head-ok')
|
cmd.append('--update-head-ok')
|
||||||
cmd.append(name)
|
cmd.append(name)
|
||||||
|
|
||||||
spec = []
|
|
||||||
|
|
||||||
# If using depth then we should not get all the tags since they may
|
|
||||||
# be outside of the depth.
|
|
||||||
if no_tags or depth:
|
|
||||||
cmd.append('--no-tags')
|
|
||||||
else:
|
|
||||||
cmd.append('--tags')
|
|
||||||
spec.append(str((u'+refs/tags/*:') + remote.ToLocal('refs/tags/*')))
|
|
||||||
|
|
||||||
if force_sync:
|
if force_sync:
|
||||||
cmd.append('--force')
|
cmd.append('--force')
|
||||||
|
|
||||||
@ -2254,6 +2244,7 @@ class Project(object):
|
|||||||
if submodules:
|
if submodules:
|
||||||
cmd.append('--recurse-submodules=on-demand')
|
cmd.append('--recurse-submodules=on-demand')
|
||||||
|
|
||||||
|
spec = []
|
||||||
if not current_branch_only:
|
if not current_branch_only:
|
||||||
# Fetch whole repo
|
# Fetch whole repo
|
||||||
spec.append(str((u'+refs/heads/*:') + remote.ToLocal('refs/heads/*')))
|
spec.append(str((u'+refs/heads/*:') + remote.ToLocal('refs/heads/*')))
|
||||||
@ -2261,19 +2252,33 @@ class Project(object):
|
|||||||
spec.append('tag')
|
spec.append('tag')
|
||||||
spec.append(tag_name)
|
spec.append(tag_name)
|
||||||
|
|
||||||
if not self.manifest.IsMirror:
|
branch = self.revisionExpr
|
||||||
branch = self.revisionExpr
|
if (not self.manifest.IsMirror and is_sha1 and depth
|
||||||
if is_sha1 and depth and git_require((1, 8, 3)):
|
and git_require((1, 8, 3))):
|
||||||
# Shallow checkout of a specific commit, fetch from that commit and not
|
# Shallow checkout of a specific commit, fetch from that commit and not
|
||||||
# the heads only as the commit might be deeper in the history.
|
# the heads only as the commit might be deeper in the history.
|
||||||
spec.append(branch)
|
spec.append(branch)
|
||||||
else:
|
else:
|
||||||
if is_sha1:
|
if is_sha1:
|
||||||
branch = self.upstream
|
branch = self.upstream
|
||||||
if branch is not None and branch.strip():
|
if branch is not None and branch.strip():
|
||||||
if not branch.startswith('refs/'):
|
if not branch.startswith('refs/'):
|
||||||
branch = R_HEADS + branch
|
branch = R_HEADS + branch
|
||||||
spec.append(str((u'+%s:' % branch) + remote.ToLocal(branch)))
|
spec.append(str((u'+%s:' % branch) + remote.ToLocal(branch)))
|
||||||
|
|
||||||
|
# If mirroring repo and we cannot deduce the tag or branch to fetch, fetch
|
||||||
|
# whole repo.
|
||||||
|
if self.manifest.IsMirror and not spec:
|
||||||
|
spec.append(str((u'+refs/heads/*:') + remote.ToLocal('refs/heads/*')))
|
||||||
|
|
||||||
|
# If using depth then we should not get all the tags since they may
|
||||||
|
# be outside of the depth.
|
||||||
|
if no_tags or depth:
|
||||||
|
cmd.append('--no-tags')
|
||||||
|
else:
|
||||||
|
cmd.append('--tags')
|
||||||
|
spec.append(str((u'+refs/tags/*:') + remote.ToLocal('refs/tags/*')))
|
||||||
|
|
||||||
cmd.extend(spec)
|
cmd.extend(spec)
|
||||||
|
|
||||||
ok = False
|
ok = False
|
||||||
|
11
repo
11
repo
@ -366,15 +366,18 @@ def _Init(args, gitc_init=False):
|
|||||||
|
|
||||||
_CheckGitVersion()
|
_CheckGitVersion()
|
||||||
try:
|
try:
|
||||||
if NeedSetupGnuPG():
|
if opt.no_repo_verify:
|
||||||
can_verify = SetupGnuPG(opt.quiet)
|
do_verify = False
|
||||||
else:
|
else:
|
||||||
can_verify = True
|
if NeedSetupGnuPG():
|
||||||
|
do_verify = SetupGnuPG(opt.quiet)
|
||||||
|
else:
|
||||||
|
do_verify = True
|
||||||
|
|
||||||
dst = os.path.abspath(os.path.join(repodir, S_repo))
|
dst = os.path.abspath(os.path.join(repodir, S_repo))
|
||||||
_Clone(url, dst, opt.quiet, not opt.no_clone_bundle)
|
_Clone(url, dst, opt.quiet, not opt.no_clone_bundle)
|
||||||
|
|
||||||
if can_verify and not opt.no_repo_verify:
|
if do_verify:
|
||||||
rev = _Verify(dst, branch, opt.quiet)
|
rev = _Verify(dst, branch, opt.quiet)
|
||||||
else:
|
else:
|
||||||
rev = 'refs/remotes/origin/%s^0' % branch
|
rev = 'refs/remotes/origin/%s^0' % branch
|
||||||
|
@ -27,14 +27,13 @@ import sys
|
|||||||
def run_pytest(cmd, argv):
|
def run_pytest(cmd, argv):
|
||||||
"""Run the unittests via |cmd|."""
|
"""Run the unittests via |cmd|."""
|
||||||
try:
|
try:
|
||||||
subprocess.check_call([cmd] + argv)
|
return subprocess.call([cmd] + argv)
|
||||||
return 0
|
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
if e.errno == errno.ENOENT:
|
if e.errno == errno.ENOENT:
|
||||||
print('%s: unable to run `%s`: %s' % (__file__, cmd, e), file=sys.stderr)
|
print('%s: unable to run `%s`: %s' % (__file__, cmd, e), file=sys.stderr)
|
||||||
print('%s: Try installing pytest: sudo apt-get install python-pytest' %
|
print('%s: Try installing pytest: sudo apt-get install python-pytest' %
|
||||||
(__file__,), file=sys.stderr)
|
(__file__,), file=sys.stderr)
|
||||||
return 1
|
return 127
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
63
setup.py
Executable file
63
setup.py
Executable file
@ -0,0 +1,63 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
# Copyright 2019 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.
|
||||||
|
|
||||||
|
"""Python packaging for repo."""
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
|
import os
|
||||||
|
import setuptools
|
||||||
|
|
||||||
|
|
||||||
|
TOPDIR = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
|
||||||
|
|
||||||
|
# Rip out the first intro paragraph.
|
||||||
|
with open(os.path.join(TOPDIR, 'README.md')) as fp:
|
||||||
|
lines = fp.read().splitlines()[2:]
|
||||||
|
end = lines.index('')
|
||||||
|
long_description = ' '.join(lines[0:end])
|
||||||
|
|
||||||
|
|
||||||
|
# https://packaging.python.org/tutorials/packaging-projects/
|
||||||
|
setuptools.setup(
|
||||||
|
name='repo',
|
||||||
|
version='1.13.8',
|
||||||
|
maintainer='Various',
|
||||||
|
maintainer_email='repo-discuss@googlegroups.com',
|
||||||
|
description='Repo helps manage many Git repositories',
|
||||||
|
long_description=long_description,
|
||||||
|
long_description_content_type='text/plain',
|
||||||
|
url='https://gerrit.googlesource.com/git-repo/',
|
||||||
|
project_urls={
|
||||||
|
'Bug Tracker': 'https://bugs.chromium.org/p/gerrit/issues/list?q=component:repo',
|
||||||
|
},
|
||||||
|
# https://pypi.org/classifiers/
|
||||||
|
classifiers=[
|
||||||
|
'Development Status :: 6 - Mature',
|
||||||
|
'Environment :: Console',
|
||||||
|
'Intended Audience :: Developers',
|
||||||
|
'License :: OSI Approved :: Apache Software License',
|
||||||
|
'Natural Language :: English',
|
||||||
|
'Operating System :: MacOS :: MacOS X',
|
||||||
|
'Operating System :: Microsoft :: Windows :: Windows 10',
|
||||||
|
'Operating System :: POSIX :: Linux',
|
||||||
|
'Topic :: Software Development :: Version Control :: Git',
|
||||||
|
],
|
||||||
|
# We support Python 2.7 and Python 3.6+.
|
||||||
|
python_requires='>=2.7, ' + ', '.join('!=3.%i.*' % x for x in range(0, 6)),
|
||||||
|
packages=['subcmds'],
|
||||||
|
)
|
@ -33,11 +33,8 @@ class Help(PagedCommand, MirrorSafeCommand):
|
|||||||
Displays detailed usage information about a command.
|
Displays detailed usage information about a command.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def _PrintAllCommands(self):
|
def _PrintCommands(self, commandNames):
|
||||||
print('usage: repo COMMAND [ARGS]')
|
"""Helper to display |commandNames| summaries."""
|
||||||
print('The complete list of recognized repo commands are:')
|
|
||||||
commandNames = list(sorted(self.commands))
|
|
||||||
|
|
||||||
maxlen = 0
|
maxlen = 0
|
||||||
for name in commandNames:
|
for name in commandNames:
|
||||||
maxlen = max(maxlen, len(name))
|
maxlen = max(maxlen, len(name))
|
||||||
@ -50,6 +47,12 @@ Displays detailed usage information about a command.
|
|||||||
except AttributeError:
|
except AttributeError:
|
||||||
summary = ''
|
summary = ''
|
||||||
print(fmt % (name, summary))
|
print(fmt % (name, summary))
|
||||||
|
|
||||||
|
def _PrintAllCommands(self):
|
||||||
|
print('usage: repo COMMAND [ARGS]')
|
||||||
|
print('The complete list of recognized repo commands are:')
|
||||||
|
commandNames = list(sorted(self.commands))
|
||||||
|
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.')
|
||||||
|
|
||||||
@ -71,19 +74,8 @@ Displays detailed usage information about a command.
|
|||||||
commandNames = list(sorted([name
|
commandNames = list(sorted([name
|
||||||
for name, command in self.commands.items()
|
for name, command in self.commands.items()
|
||||||
if command.common and gitc_supported(command)]))
|
if command.common and gitc_supported(command)]))
|
||||||
|
self._PrintCommands(commandNames)
|
||||||
|
|
||||||
maxlen = 0
|
|
||||||
for name in commandNames:
|
|
||||||
maxlen = max(maxlen, len(name))
|
|
||||||
fmt = ' %%-%ds %%s' % maxlen
|
|
||||||
|
|
||||||
for name in commandNames:
|
|
||||||
command = self.commands[name]
|
|
||||||
try:
|
|
||||||
summary = command.helpSummary.strip()
|
|
||||||
except AttributeError:
|
|
||||||
summary = ''
|
|
||||||
print(fmt % (name, summary))
|
|
||||||
print(
|
print(
|
||||||
"See 'repo help <command>' for more information on a specific command.\n"
|
"See 'repo help <command>' for more information on a specific command.\n"
|
||||||
"See 'repo help --all' for a complete list of recognized commands.")
|
"See 'repo help --all' for a complete list of recognized commands.")
|
||||||
|
@ -103,6 +103,10 @@ class Info(PagedCommand):
|
|||||||
self.headtext(currentBranch)
|
self.headtext(currentBranch)
|
||||||
self.out.nl()
|
self.out.nl()
|
||||||
|
|
||||||
|
self.heading("Manifest revision: ")
|
||||||
|
self.headtext(p.revisionExpr)
|
||||||
|
self.out.nl()
|
||||||
|
|
||||||
localBranches = list(p.GetBranches().keys())
|
localBranches = list(p.GetBranches().keys())
|
||||||
self.heading("Local Branches: ")
|
self.heading("Local Branches: ")
|
||||||
self.redtext(str(len(localBranches)))
|
self.redtext(str(len(localBranches)))
|
||||||
|
@ -96,7 +96,7 @@ to update the working directory files.
|
|||||||
g.add_option('-b', '--manifest-branch',
|
g.add_option('-b', '--manifest-branch',
|
||||||
dest='manifest_branch',
|
dest='manifest_branch',
|
||||||
help='manifest branch or revision', metavar='REVISION')
|
help='manifest branch or revision', metavar='REVISION')
|
||||||
g.add_option('--current-branch',
|
g.add_option('-c', '--current-branch',
|
||||||
dest='current_branch_only', action='store_true',
|
dest='current_branch_only', action='store_true',
|
||||||
help='fetch only current manifest branch from server')
|
help='fetch only current manifest branch from server')
|
||||||
g.add_option('-m', '--manifest-name',
|
g.add_option('-m', '--manifest-name',
|
||||||
|
22
tox.ini
Normal file
22
tox.ini
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# Copyright 2019 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.
|
||||||
|
|
||||||
|
# https://tox.readthedocs.io/
|
||||||
|
|
||||||
|
[tox]
|
||||||
|
envlist = py27, py36, py37, py38
|
||||||
|
|
||||||
|
[testenv]
|
||||||
|
deps = pytest
|
||||||
|
commands = {toxinidir}/run_tests
|
Reference in New Issue
Block a user