Compare commits

..

10 Commits
v1.6 ... v1.6.1

Author SHA1 Message Date
2816d4f387 Set core.bare to true on mirror repositories
When creating a mirror repository we will always be using a bare
repository.  Setting $GIT_DIR/config to have core.bare = true is
reasonable and helps Git to recognize the environment it is in.

Signed-off-by: Shawn O. Pearce <sop@google.com>
2009-03-03 17:53:18 -08:00
44469464d2 Allow repo forall -c on a mirror by using GIT_DIR as pwd
We can permit a forall on a mirror, but only if we put
the command into the git repository.

Signed-off-by: Shawn O. Pearce <sop@google.com>
2009-03-03 17:51:01 -08:00
c95583bf4f Don't permit users to run repo status in a mirror client
If a client was created with "repo init --mirror" then there are
no working directories present, and no files checked out.  Using
a command like "repo status" in this context makes no sense, and
actually throws back a Pytyon traceback at the console when the
underlying commands fail out.

We now tag commands with the MirrorSafeCommand type if they are
able to be executed within a mirror directory safely.  Using a
command in a mirror which lacks this base class results in a
useful error letting you know the command isn't supported.

Bug: REPO-14
Signed-off-by: Shawn O. Pearce <sop@google.com>
2009-03-03 17:47:06 -08:00
6a5644d392 Get rid of the horrible android import work around hack
Months ago when the Android Open Source Project launched we had some
import errors that had to be fixed and worked over.  These hacks
were here to help users update their clients to newer versions of
the imported code.

Its very likely all clients have either been deleted, or have been
updated and have the fixed imports.  So we don't need this hack in
repo anymore.

If a very ancient client still existed, it would need to be created
from scratch anyway, due to the Android cupcake branch merging
into master and the manifest changes not being able to be handled
correctly by repo.  A new client wouldn't have the incorrectly
imported code in it, and thus wouldn't need this hack.

Signed-off-by: Shawn O. Pearce <sop@google.com>
2009-03-03 13:52:20 -08:00
fe08675956 Fix repo status when there are renamed/copied files
I missed a parameter in the format string, but still provided the
value in the parameter list, so the format failed to produce an
output message.

Bug: REPO-15
Signed-off-by: Shawn O. Pearce <sop@google.com>
2009-03-03 13:49:48 -08:00
be0e8ac232 Export additional environment variables to repo forall:
REPO_PATH is the path relative the the root of the client.

REPO_REMOTE is the name of the remote system from the manifest.

REPO_LREV is the name of the revision from the manifest, but
translated to something the local repository knows.

REPO_RREV is the name of the revision from the manifest.

This allows us to do commands like:

  repo forall -c 'echo "(cd $REPO_PATH && git checkout `git rev-parse HEAD`)"'
2009-03-02 19:32:28 -08:00
47c1a63a07 Add 'repo version' to describe what code we are running
I meant to have this in here, so clients can more easily report
what version of repo they are running.

Signed-off-by: Shawn O. Pearce <sop@google.com>
2009-03-02 18:24:23 -08:00
559b846b17 Report better errors when a project revision is invalid
If a manifest specifies an invalid revision property, give the
user a better error message detaling the problem, instead of an
ugly Python traceback with a strange Git error message.

Bug: REPO-2
Signed-off-by: Shawn O. Pearce <sop@google.com>
2009-03-02 12:56:08 -08:00
7c6c64d463 Fix repo prune output to sort by branch name
We didn't always sort the output.  Now we do.

Signed-off-by: Shawn O. Pearce <sop@google.com>
2009-03-02 12:38:45 -08:00
3778f9d47e Fix repo prune to work on git 1.6.1-rc3~5 and later
Prior to git 1.6.1-rc3~5 the output of 'git branch -d' matched:

  Deleted branch (.*)\.

where the subgroup grabbed the branch name. In v1.6.1-rc3~5 (aka
a126ed0a01e265d7f3b2972a34e85636e12e6d34) Brandon Casey changed
the output to include the SHA-1 of the branch name, now matching
the pattern:

  Deleted branch (.*) \([0-9a-f]*\)\.

Instead of parsing the output of git branch we now re-obtain the
list of branches after the deletion attempt and perform a set
difference in memory to determine which branches we were able to
successfully delete.

Bug: REPO-9
Signed-off-by: Shawn O. Pearce <sop@google.com>
2009-03-02 12:38:36 -08:00
9 changed files with 124 additions and 50 deletions

View File

@ -114,3 +114,8 @@ class PagedCommand(Command):
"""Command which defaults to output in a pager, as its
display tends to be larger than one screen full.
"""
class MirrorSafeCommand(object):
"""Command permits itself to run within a mirror,
and does not require a working directory.
"""

View File

@ -17,6 +17,10 @@ class ManifestParseError(Exception):
"""Failed to parse the manifest file.
"""
class ManifestInvalidRevisionError(Exception):
"""The revision value in a project is incorrect.
"""
class EditorError(Exception):
"""Unspecified error from the user's text editor.
"""

24
main.py
View File

@ -27,8 +27,11 @@ import os
import re
import sys
from command import InteractiveCommand, PagedCommand
from command import InteractiveCommand
from command import MirrorSafeCommand
from command import PagedCommand
from editor import Editor
from error import ManifestInvalidRevisionError
from error import NoSuchProjectError
from error import RepoChangedException
from manifest import Manifest
@ -45,6 +48,9 @@ global_options.add_option('-p', '--paginate',
global_options.add_option('--no-pager',
dest='no_pager', action='store_true',
help='disable the pager')
global_options.add_option('--version',
dest='show_version', action='store_true',
help='display this version of repo')
class _Repo(object):
def __init__(self, repodir):
@ -68,6 +74,13 @@ class _Repo(object):
argv = []
gopts, gargs = global_options.parse_args(glob)
if gopts.show_version:
if name == 'help':
name = 'version'
else:
print >>sys.stderr, 'fatal: invalid usage of --version'
sys.exit(1)
try:
cmd = self.commands[name]
except KeyError:
@ -80,6 +93,12 @@ class _Repo(object):
cmd.manifest = Manifest(cmd.repodir)
Editor.globalConfig = cmd.manifest.globalConfig
if not isinstance(cmd, MirrorSafeCommand) and cmd.manifest.IsMirror:
print >>sys.stderr, \
"fatal: '%s' requires a working directory"\
% name
sys.exit(1)
if not gopts.no_pager and not isinstance(cmd, InteractiveCommand):
config = cmd.manifest.globalConfig
if gopts.pager:
@ -94,6 +113,9 @@ class _Repo(object):
copts, cargs = cmd.OptionParser.parse_args(argv)
try:
cmd.Execute(copts, cargs)
except ManifestInvalidRevisionError, e:
print >>sys.stderr, 'error: %s' % str(e)
sys.exit(1)
except NoSuchProjectError, e:
if e.name:
print >>sys.stderr, 'error: project %s not found' % e.name

View File

@ -25,6 +25,7 @@ from color import Coloring
from git_command import GitCommand
from git_config import GitConfig, IsId
from error import GitError, ImportError, UploadError
from error import ManifestInvalidRevisionError
from remote import Remote
HEAD = 'HEAD'
@ -357,7 +358,7 @@ class Project(object):
else: f_status = '-'
if i and i.src_path:
line = ' %s%s\t%s => (%s%%)' % (i_status, f_status,
line = ' %s%s\t%s => %s (%s%%)' % (i_status, f_status,
i.src_path, p, i.level)
else:
line = ' %s%s\t%s' % (i_status, f_status, p)
@ -528,7 +529,6 @@ class Project(object):
return False
if self.worktree:
self._RepairAndroidImportErrors()
self._InitMRef()
else:
self._InitMirrorHead()
@ -545,30 +545,6 @@ class Project(object):
for file in self.copyfiles:
file._Copy()
def _RepairAndroidImportErrors(self):
if self.name in ['platform/external/iptables',
'platform/external/libpcap',
'platform/external/tcpdump',
'platform/external/webkit',
'platform/system/wlan/ti']:
# I hate myself for doing this...
#
# In the initial Android 1.0 release these projects were
# shipped, some users got them, and then the history had
# to be rewritten to correct problems with their imports.
# The 'android-1.0' tag may still be pointing at the old
# history, so we need to drop the tag and fetch it again.
#
try:
remote = self.GetRemote(self.remote.name)
relname = remote.ToLocal(R_HEADS + 'release-1.0')
tagname = R_TAGS + 'android-1.0'
if self._revlist(not_rev(relname), tagname):
cmd = ['fetch', remote.name, '+%s:%s' % (tagname, tagname)]
GitCommand(self, cmd, bare = True).Wait()
except GitError:
pass
def Sync_LocalHalf(self):
"""Perform only the local IO portion of the sync process.
Network access is not required.
@ -582,6 +558,12 @@ class Project(object):
rem = self.GetRemote(self.remote.name)
rev = rem.ToLocal(self.revision)
try:
self.bare_git.rev_parse('--verify', '%s^0' % rev)
except GitError:
raise ManifestInvalidRevisionError(
'revision %s in %s not found' % (self.revision, self.name))
branch = self.CurrentBranch
if branch is None:
@ -770,7 +752,8 @@ class Project(object):
"""
cb = self.CurrentBranch
kill = []
for name in self._allrefs.keys():
left = self._allrefs
for name in left.keys():
if name.startswith(R_HEADS):
name = name[len(R_HEADS):]
if cb is None or name != cb:
@ -783,14 +766,12 @@ class Project(object):
self.work_git.DetachHead(HEAD)
kill.append(cb)
deleted = set()
if kill:
try:
old = self.bare_git.GetHead()
except GitError:
old = 'refs/heads/please_never_use_this_as_a_branch_name'
rm_re = re.compile(r"^Deleted branch (.*)\.$")
try:
self.bare_git.DetachHead(rev)
@ -802,14 +783,12 @@ class Project(object):
b.Wait()
finally:
self.bare_git.SetHead(old)
left = self._allrefs
for line in b.stdout.split("\n"):
m = rm_re.match(line)
if m:
deleted.add(m.group(1))
if deleted:
for branch in kill:
if (R_HEADS + branch) not in left:
self.CleanPublishedCache()
break
if cb and cb not in kill:
kill.append(cb)
@ -817,7 +796,7 @@ class Project(object):
kept = []
for branch in kill:
if branch not in deleted:
if (R_HEADS + branch) in left:
branch = self.GetBranch(branch)
base = branch.LocalMerge
if not base:
@ -872,6 +851,10 @@ class Project(object):
if not os.path.exists(self.gitdir):
os.makedirs(self.gitdir)
self.bare_git.init()
if self.manifest.IsMirror:
self.config.SetString('core.bare', 'true')
else:
self.config.SetString('core.bare', None)
hooks = self._gitdir_path('hooks')

View File

@ -17,9 +17,9 @@ import re
import os
import sys
import subprocess
from command import Command
from command import Command, MirrorSafeCommand
class Forall(Command):
class Forall(Command, MirrorSafeCommand):
common = False
helpSummary = "Run a shell command in each project"
helpUsage = """
@ -30,10 +30,22 @@ Executes the same shell command in each project.
Environment
-----------
pwd is the project's working directory.
pwd is the project's working directory. If the current client is
a mirror client, then pwd is the Git repository.
REPO_PROJECT is set to the unique name of the project.
REPO_PATH is the path relative the the root of the client.
REPO_REMOTE is the name of the remote system from the manifest.
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.
REPO_RREV is the name of the revision from the manifest, exactly
as written in the manifest.
shell positional arguments ($1, $2, .., $#) are set to any arguments
following <command>.
@ -66,13 +78,26 @@ not redirected.
cmd.append(cmd[0])
cmd.extend(opt.command[1:])
mirror = self.manifest.IsMirror
rc = 0
for project in self.GetProjects(args):
env = dict(os.environ.iteritems())
env['REPO_PROJECT'] = project.name
env['REPO_PATH'] = project.relpath
env['REPO_REMOTE'] = project.remote.name
env['REPO_LREV'] = project\
.GetRemote(project.remote.name)\
.ToLocal(project.revision)
env['REPO_RREV'] = project.revision
if mirror:
env['GIT_DIR'] = project.gitdir
cwd = project.gitdir
else:
cwd = project.worktree
p = subprocess.Popen(cmd,
cwd = project.worktree,
cwd = cwd,
shell = shell,
env = env)
r = p.wait()

View File

@ -17,9 +17,9 @@ import sys
from formatter import AbstractFormatter, DumbWriter
from color import Coloring
from command import PagedCommand
from command import PagedCommand, MirrorSafeCommand
class Help(PagedCommand):
class Help(PagedCommand, MirrorSafeCommand):
common = False
helpSummary = "Display detailed help on a command"
helpUsage = """

View File

@ -17,12 +17,12 @@ import os
import sys
from color import Coloring
from command import InteractiveCommand
from command import InteractiveCommand, MirrorSafeCommand
from error import ManifestParseError
from remote import Remote
from git_command import git, MIN_GIT_VERSION
class Init(InteractiveCommand):
class Init(InteractiveCommand, MirrorSafeCommand):
common = True
helpSummary = "Initialize repo in the current directory"
helpUsage = """

View File

@ -19,11 +19,11 @@ import subprocess
import sys
from git_command import GIT
from command import Command
from command import Command, MirrorSafeCommand
from error import RepoChangedException, GitError
from project import R_HEADS
class Sync(Command):
class Sync(Command, MirrorSafeCommand):
common = True
helpSummary = "Update working tree to the latest revision"
helpUsage = """

35
subcmds/version.py Normal file
View File

@ -0,0 +1,35 @@
#
# Copyright (C) 2009 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.
import sys
from command import Command, MirrorSafeCommand
from git_command import git
from project import HEAD
class Version(Command, MirrorSafeCommand):
common = False
helpSummary = "Display the version of repo"
helpUsage = """
%prog
"""
def Execute(self, opt, args):
rp = self.manifest.repoProject
rem = rp.GetRemote(rp.remote.name)
print 'repo version %s' % rp.work_git.describe(HEAD)
print ' (from %s)' % rem.url
print git.version().strip()
print 'Python %s' % sys.version