Compare commits

...

3 Commits

Author SHA1 Message Date
329c31da7d Repair any mis-directed android-1.0 annotated tags
The initial open source release of the Android 1.0 platform had
some problems with its Perforce->Git imports.  Google was forced
to rewrite some history to redirect users onto more stable upstream
sources and correct errors in the imports.

Not everyone has the correct android-1.0 tags, as some users did
manage to fetch the platform early, before the mirror sites crashed
and the history was rewritten.

This change is a band-aid to ensure any stale android-1.0 tags are
get updated to the corrected version.  It should be backed out at
some point in the near future, when we can be fairly certain that
everyone has the correct android-1.0 tags.

Signed-off-by: Shawn O. Pearce <sop@google.com>
2008-10-24 09:17:25 -07:00
5cc6679fb8 Support user supplied custom .repo/local_manifest.xml files
By creating a .repo/local_manifest.xml the user can add extra
projects into their client space, without touching the main
manifest script.

For example:

  $ cat .repo/local_manifest.xml
  <?xml version="1.0" encoding="UTF-8"?>
  <manifest>
   <project path="android-build"
            name="platform/build"
            remote="korg"
            revision="android-1.0" />
  </manifest>

Signed-off-by: Shawn O. Pearce <sop@google.com>
2008-10-23 16:20:14 -07:00
632768bc65 Teach repo how to download changes to the local checkout
Now `repo download . 1402` would download the change numbered 1402
into the current project and check it out for the user, using a
detached HEAD.  `repo sync .` would back out of the change and
return to the upstream version.

Multiple projects can be fetched at once by listing them out on
the command line as different arguments.

Individual patch sets can be selected by adding a '/n' to indicate
the n-th patch set should be downloaded instead of the default of
patch set 1.

Signed-off-by: Shawn O. Pearce <sop@google.com>
2008-10-23 14:43:28 -07:00
3 changed files with 162 additions and 5 deletions

View File

@ -26,6 +26,7 @@ from remote import Remote
from error import ManifestParseError
MANIFEST_FILE_NAME = 'manifest.xml'
LOCAL_MANIFEST_NAME = 'local_manifest.xml'
class _Default(object):
"""Project defaults within the manifest."""
@ -108,10 +109,20 @@ class Manifest(object):
def _Load(self):
if not self._loaded:
self._ParseManifest()
self._ParseManifest(True)
local = os.path.join(self.repodir, LOCAL_MANIFEST_NAME)
if os.path.exists(local):
try:
real = self.manifestFile
self.manifestFile = local
self._ParseManifest(False)
finally:
self.manifestFile = real
self._loaded = True
def _ParseManifest(self):
def _ParseManifest(self, is_root_file):
root = xml.dom.minidom.parse(self.manifestFile)
if not root or not root.childNodes:
raise ManifestParseError, \
@ -124,9 +135,10 @@ class Manifest(object):
"no <manifest> in %s" % \
self.manifestFile
self.branch = config.getAttribute('branch')
if not self.branch:
self.branch = 'default'
if is_root_file:
self.branch = config.getAttribute('branch')
if not self.branch:
self.branch = 'default'
for node in config.childNodes:
if node.nodeName == 'remote':

View File

@ -45,6 +45,31 @@ def _info(fmt, *args):
def not_rev(r):
return '^' + r
class DownloadedChange(object):
_commit_cache = None
def __init__(self, project, base, change_id, ps_id, commit):
self.project = project
self.base = base
self.change_id = change_id
self.ps_id = ps_id
self.commit = commit
@property
def commits(self):
if self._commit_cache is None:
self._commit_cache = self.project.bare_git.rev_list(
'--abbrev=8',
'--abbrev-commit',
'--pretty=oneline',
'--reverse',
'--date-order',
not_rev(self.base),
self.commit,
'--')
return self._commit_cache
class ReviewableBranch(object):
_commit_cache = None
@ -445,6 +470,7 @@ class Project(object):
return False
if not self._RemoteFetch():
return False
self._RepairAndroidImportErrors()
self._InitMRef()
return True
@ -452,6 +478,30 @@ 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.
@ -612,6 +662,23 @@ class Project(object):
src = os.path.join(self.worktree, src)
self.copyfiles.append(_CopyFile(src, dest))
def DownloadPatchSet(self, change_id, patch_id):
"""Download a single patch set of a single change to FETCH_HEAD.
"""
remote = self.GetRemote(self.remote.name)
cmd = ['fetch', remote.name]
cmd.append('refs/changes/%2.2d/%d/%d' \
% (change_id % 100, change_id, patch_id))
cmd.extend(map(lambda x: str(x), remote.fetch))
if GitCommand(self, cmd, bare=True).Wait() != 0:
return None
return DownloadedChange(self,
remote.ToLocal(self.revision),
change_id,
patch_id,
self.bare_git.rev_parse('FETCH_HEAD'))
## Branch Management ##

78
subcmds/download.py Normal file
View File

@ -0,0 +1,78 @@
#
# Copyright (C) 2008 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 os
import re
import sys
from command import Command
CHANGE_RE = re.compile(r'^([1-9][0-9]*)(?:[/\.-]([1-9][0-9]*))?$')
class Download(Command):
common = True
helpSummary = "Download and checkout a change"
helpUsage = """
%prog {project change[/patchset]}...
"""
helpDescription = """
The '%prog' command downloads a change from the review system and
makes it available in your project's local working directory.
"""
def _Options(self, p):
pass
def _ParseChangeIds(self, args):
to_get = []
project = None
for a in args:
m = CHANGE_RE.match(a)
if m:
if not project:
self.Usage()
chg_id = int(m.group(1))
if m.group(2):
ps_id = int(m.group(2))
else:
ps_id = 1
to_get.append((project, chg_id, ps_id))
else:
project = self.GetProjects([a])[0]
return to_get
def Execute(self, opt, args):
for project, change_id, ps_id in self._ParseChangeIds(args):
dl = project.DownloadPatchSet(change_id, ps_id)
if not dl:
print >>sys.stderr, \
'[%s] change %d/%d not found' \
% (project.name, change_id, ps_id)
sys.exit(1)
if not dl.commits:
print >>sys.stderr, \
'[%s] change %d/%d has already been merged' \
% (project.name, change_id, ps_id)
continue
if len(dl.commits) > 1:
print >>sys.stderr, \
'[%s] %d/%d depends on %d unmerged changes:' \
% (project.name, change_id, ps_id, len(dl.commits))
for c in dl.commits:
print >>sys.stderr, ' %s' % (c)
project._Checkout(dl.commit)