summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShawn O. Pearce <sop@google.com>2008-10-23 11:58:52 -0700
committerShawn O. Pearce <sop@google.com>2008-10-23 14:43:28 -0700
commit632768bc65ae0f1dc9eb9260c9146c42d9965a18 (patch)
treef8fc564a40e5886c74062d6be751ca4c2769721c
parent0758d2f1d61288c83282749d2b36958d2c289e7f (diff)
downloadgit-repo-632768bc65ae0f1dc9eb9260c9146c42d9965a18.tar.gz
Teach repo how to download changes to the local checkoutv1.0.4
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>
-rw-r--r--project.py42
-rw-r--r--subcmds/download.py78
2 files changed, 120 insertions, 0 deletions
diff --git a/project.py b/project.py
index 2b4a4f95..e88afcca 100644
--- a/project.py
+++ b/project.py
@@ -45,6 +45,31 @@ def _info(fmt, *args):
45def not_rev(r): 45def not_rev(r):
46 return '^' + r 46 return '^' + r
47 47
48class DownloadedChange(object):
49 _commit_cache = None
50
51 def __init__(self, project, base, change_id, ps_id, commit):
52 self.project = project
53 self.base = base
54 self.change_id = change_id
55 self.ps_id = ps_id
56 self.commit = commit
57
58 @property
59 def commits(self):
60 if self._commit_cache is None:
61 self._commit_cache = self.project.bare_git.rev_list(
62 '--abbrev=8',
63 '--abbrev-commit',
64 '--pretty=oneline',
65 '--reverse',
66 '--date-order',
67 not_rev(self.base),
68 self.commit,
69 '--')
70 return self._commit_cache
71
72
48class ReviewableBranch(object): 73class ReviewableBranch(object):
49 _commit_cache = None 74 _commit_cache = None
50 75
@@ -612,6 +637,23 @@ class Project(object):
612 src = os.path.join(self.worktree, src) 637 src = os.path.join(self.worktree, src)
613 self.copyfiles.append(_CopyFile(src, dest)) 638 self.copyfiles.append(_CopyFile(src, dest))
614 639
640 def DownloadPatchSet(self, change_id, patch_id):
641 """Download a single patch set of a single change to FETCH_HEAD.
642 """
643 remote = self.GetRemote(self.remote.name)
644
645 cmd = ['fetch', remote.name]
646 cmd.append('refs/changes/%2.2d/%d/%d' \
647 % (change_id % 100, change_id, patch_id))
648 cmd.extend(map(lambda x: str(x), remote.fetch))
649 if GitCommand(self, cmd, bare=True).Wait() != 0:
650 return None
651 return DownloadedChange(self,
652 remote.ToLocal(self.revision),
653 change_id,
654 patch_id,
655 self.bare_git.rev_parse('FETCH_HEAD'))
656
615 657
616## Branch Management ## 658## Branch Management ##
617 659
diff --git a/subcmds/download.py b/subcmds/download.py
new file mode 100644
index 00000000..a6f3aa45
--- /dev/null
+++ b/subcmds/download.py
@@ -0,0 +1,78 @@
1#
2# Copyright (C) 2008 The Android Open Source Project
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16import os
17import re
18import sys
19
20from command import Command
21
22CHANGE_RE = re.compile(r'^([1-9][0-9]*)(?:[/\.-]([1-9][0-9]*))?$')
23
24class Download(Command):
25 common = True
26 helpSummary = "Download and checkout a change"
27 helpUsage = """
28%prog {project change[/patchset]}...
29"""
30 helpDescription = """
31The '%prog' command downloads a change from the review system and
32makes it available in your project's local working directory.
33"""
34
35 def _Options(self, p):
36 pass
37
38 def _ParseChangeIds(self, args):
39 to_get = []
40 project = None
41
42 for a in args:
43 m = CHANGE_RE.match(a)
44 if m:
45 if not project:
46 self.Usage()
47 chg_id = int(m.group(1))
48 if m.group(2):
49 ps_id = int(m.group(2))
50 else:
51 ps_id = 1
52 to_get.append((project, chg_id, ps_id))
53 else:
54 project = self.GetProjects([a])[0]
55 return to_get
56
57 def Execute(self, opt, args):
58 for project, change_id, ps_id in self._ParseChangeIds(args):
59 dl = project.DownloadPatchSet(change_id, ps_id)
60 if not dl:
61 print >>sys.stderr, \
62 '[%s] change %d/%d not found' \
63 % (project.name, change_id, ps_id)
64 sys.exit(1)
65
66 if not dl.commits:
67 print >>sys.stderr, \
68 '[%s] change %d/%d has already been merged' \
69 % (project.name, change_id, ps_id)
70 continue
71
72 if len(dl.commits) > 1:
73 print >>sys.stderr, \
74 '[%s] %d/%d depends on %d unmerged changes:' \
75 % (project.name, change_id, ps_id, len(dl.commits))
76 for c in dl.commits:
77 print >>sys.stderr, ' %s' % (c)
78 project._Checkout(dl.commit)