summaryrefslogtreecommitdiffstats
path: root/subcmds
diff options
context:
space:
mode:
Diffstat (limited to 'subcmds')
-rw-r--r--subcmds/__init__.py4
-rw-r--r--subcmds/branches.py5
-rw-r--r--subcmds/cherry_pick.py2
-rw-r--r--subcmds/forall.py21
-rw-r--r--subcmds/help.py12
-rw-r--r--subcmds/info.py12
-rw-r--r--subcmds/init.py30
-rw-r--r--subcmds/list.py33
-rw-r--r--subcmds/overview.py2
-rw-r--r--subcmds/rebase.py2
-rw-r--r--subcmds/stage.py8
-rw-r--r--subcmds/status.py12
-rw-r--r--subcmds/sync.py55
-rw-r--r--subcmds/upload.py56
14 files changed, 189 insertions, 65 deletions
diff --git a/subcmds/__init__.py b/subcmds/__init__.py
index 1fac802e..84efb4de 100644
--- a/subcmds/__init__.py
+++ b/subcmds/__init__.py
@@ -38,8 +38,8 @@ for py in os.listdir(my_dir):
38 try: 38 try:
39 cmd = getattr(mod, clsn)() 39 cmd = getattr(mod, clsn)()
40 except AttributeError: 40 except AttributeError:
41 raise SyntaxError, '%s/%s does not define class %s' % ( 41 raise SyntaxError('%s/%s does not define class %s' % (
42 __name__, py, clsn) 42 __name__, py, clsn))
43 43
44 name = name.replace('_', '-') 44 name = name.replace('_', '-')
45 cmd.NAME = name 45 cmd.NAME = name
diff --git a/subcmds/branches.py b/subcmds/branches.py
index 06d45abe..c2e7c4b9 100644
--- a/subcmds/branches.py
+++ b/subcmds/branches.py
@@ -98,14 +98,13 @@ is shown, then the branch appears in all projects.
98 project_cnt = len(projects) 98 project_cnt = len(projects)
99 99
100 for project in projects: 100 for project in projects:
101 for name, b in project.GetBranches().iteritems(): 101 for name, b in project.GetBranches().items():
102 b.project = project 102 b.project = project
103 if name not in all_branches: 103 if name not in all_branches:
104 all_branches[name] = BranchInfo(name) 104 all_branches[name] = BranchInfo(name)
105 all_branches[name].add(b) 105 all_branches[name].add(b)
106 106
107 names = all_branches.keys() 107 names = list(sorted(all_branches))
108 names.sort()
109 108
110 if not names: 109 if not names:
111 print(' (no branches)', file=sys.stderr) 110 print(' (no branches)', file=sys.stderr)
diff --git a/subcmds/cherry_pick.py b/subcmds/cherry_pick.py
index 01b97e07..520e4c32 100644
--- a/subcmds/cherry_pick.py
+++ b/subcmds/cherry_pick.py
@@ -81,7 +81,7 @@ change id will be added.
81 sys.exit(1) 81 sys.exit(1)
82 82
83 else: 83 else:
84 print('NOTE: When committing (please see above) and editing the commit' 84 print('NOTE: When committing (please see above) and editing the commit '
85 'message, please remove the old Change-Id-line and add:') 85 'message, please remove the old Change-Id-line and add:')
86 print(self._GetReference(sha1), file=sys.stderr) 86 print(self._GetReference(sha1), file=sys.stderr)
87 print(file=sys.stderr) 87 print(file=sys.stderr)
diff --git a/subcmds/forall.py b/subcmds/forall.py
index 4c1c9ff8..e2a420a9 100644
--- a/subcmds/forall.py
+++ b/subcmds/forall.py
@@ -42,10 +42,14 @@ class Forall(Command, MirrorSafeCommand):
42 helpSummary = "Run a shell command in each project" 42 helpSummary = "Run a shell command in each project"
43 helpUsage = """ 43 helpUsage = """
44%prog [<project>...] -c <command> [<arg>...] 44%prog [<project>...] -c <command> [<arg>...]
45%prog -r str1 [str2] ... -c <command> [<arg>...]"
45""" 46"""
46 helpDescription = """ 47 helpDescription = """
47Executes the same shell command in each project. 48Executes the same shell command in each project.
48 49
50The -r option allows running the command only on projects matching
51regex or wildcard expression.
52
49Output Formatting 53Output Formatting
50----------------- 54-----------------
51 55
@@ -103,6 +107,9 @@ without iterating through the remaining projects.
103 setattr(parser.values, option.dest, list(parser.rargs)) 107 setattr(parser.values, option.dest, list(parser.rargs))
104 while parser.rargs: 108 while parser.rargs:
105 del parser.rargs[0] 109 del parser.rargs[0]
110 p.add_option('-r', '--regex',
111 dest='regex', action='store_true',
112 help="Execute the command only on projects matching regex or wildcard expression")
106 p.add_option('-c', '--command', 113 p.add_option('-c', '--command',
107 help='Command (and arguments) to execute', 114 help='Command (and arguments) to execute',
108 dest='command', 115 dest='command',
@@ -166,7 +173,12 @@ without iterating through the remaining projects.
166 rc = 0 173 rc = 0
167 first = True 174 first = True
168 175
169 for project in self.GetProjects(args): 176 if not opt.regex:
177 projects = self.GetProjects(args)
178 else:
179 projects = self.FindProjects(args)
180
181 for project in projects:
170 env = os.environ.copy() 182 env = os.environ.copy()
171 def setenv(name, val): 183 def setenv(name, val):
172 if val is None: 184 if val is None:
@@ -248,7 +260,12 @@ without iterating through the remaining projects.
248 first = False 260 first = False
249 else: 261 else:
250 out.nl() 262 out.nl()
251 out.project('project %s/', project.relpath) 263
264 if mirror:
265 project_header_path = project.name
266 else:
267 project_header_path = project.relpath
268 out.project('project %s/', project_header_path)
252 out.nl() 269 out.nl()
253 out.flush() 270 out.flush()
254 if errbuf: 271 if errbuf:
diff --git a/subcmds/help.py b/subcmds/help.py
index 15aab7f9..4aa3f863 100644
--- a/subcmds/help.py
+++ b/subcmds/help.py
@@ -34,8 +34,7 @@ Displays detailed usage information about a command.
34 def _PrintAllCommands(self): 34 def _PrintAllCommands(self):
35 print('usage: repo COMMAND [ARGS]') 35 print('usage: repo COMMAND [ARGS]')
36 print('The complete list of recognized repo commands are:') 36 print('The complete list of recognized repo commands are:')
37 commandNames = self.commands.keys() 37 commandNames = list(sorted(self.commands))
38 commandNames.sort()
39 38
40 maxlen = 0 39 maxlen = 0
41 for name in commandNames: 40 for name in commandNames:
@@ -49,16 +48,15 @@ Displays detailed usage information about a command.
49 except AttributeError: 48 except AttributeError:
50 summary = '' 49 summary = ''
51 print(fmt % (name, summary)) 50 print(fmt % (name, summary))
52 print("See 'repo help <command>' for more information on a" 51 print("See 'repo help <command>' for more information on a "
53 'specific command.') 52 'specific command.')
54 53
55 def _PrintCommonCommands(self): 54 def _PrintCommonCommands(self):
56 print('usage: repo COMMAND [ARGS]') 55 print('usage: repo COMMAND [ARGS]')
57 print('The most commonly used repo commands are:') 56 print('The most commonly used repo commands are:')
58 commandNames = [name 57 commandNames = list(sorted([name
59 for name in self.commands.keys() 58 for name, command in self.commands.items()
60 if self.commands[name].common] 59 if command.common]))
61 commandNames.sort()
62 60
63 maxlen = 0 61 maxlen = 0
64 for name in commandNames: 62 for name in commandNames:
diff --git a/subcmds/info.py b/subcmds/info.py
index 8fb363f3..d42860ae 100644
--- a/subcmds/info.py
+++ b/subcmds/info.py
@@ -27,7 +27,7 @@ class Info(PagedCommand):
27 helpSummary = "Get info on the manifest branch, current branch or unmerged branches" 27 helpSummary = "Get info on the manifest branch, current branch or unmerged branches"
28 helpUsage = "%prog [-dl] [-o [-b]] [<project>...]" 28 helpUsage = "%prog [-dl] [-o [-b]] [<project>...]"
29 29
30 def _Options(self, p, show_smart=True): 30 def _Options(self, p):
31 p.add_option('-d', '--diff', 31 p.add_option('-d', '--diff',
32 dest='all', action='store_true', 32 dest='all', action='store_true',
33 help="show full info and commit diff including remote branches") 33 help="show full info and commit diff including remote branches")
@@ -53,7 +53,10 @@ class Info(PagedCommand):
53 53
54 self.opt = opt 54 self.opt = opt
55 55
56 mergeBranch = self.manifest.manifestProject.config.GetBranch("default").merge 56 manifestConfig = self.manifest.manifestProject.config
57 mergeBranch = manifestConfig.GetBranch("default").merge
58 manifestGroups = (manifestConfig.GetString('manifest.groups')
59 or 'all,-notdefault')
57 60
58 self.heading("Manifest branch: ") 61 self.heading("Manifest branch: ")
59 self.headtext(self.manifest.default.revisionExpr) 62 self.headtext(self.manifest.default.revisionExpr)
@@ -61,6 +64,9 @@ class Info(PagedCommand):
61 self.heading("Manifest merge branch: ") 64 self.heading("Manifest merge branch: ")
62 self.headtext(mergeBranch) 65 self.headtext(mergeBranch)
63 self.out.nl() 66 self.out.nl()
67 self.heading("Manifest groups: ")
68 self.headtext(manifestGroups)
69 self.out.nl()
64 70
65 self.printSeparator() 71 self.printSeparator()
66 72
@@ -157,7 +163,7 @@ class Info(PagedCommand):
157 all_branches = [] 163 all_branches = []
158 for project in self.GetProjects(args): 164 for project in self.GetProjects(args):
159 br = [project.GetUploadableBranch(x) 165 br = [project.GetUploadableBranch(x)
160 for x in project.GetBranches().keys()] 166 for x in project.GetBranches()]
161 br = [x for x in br if x] 167 br = [x for x in br if x]
162 if self.opt.current_branch: 168 if self.opt.current_branch:
163 br = [x for x in br if x.name == project.CurrentBranch] 169 br = [x for x in br if x.name == project.CurrentBranch]
diff --git a/subcmds/init.py b/subcmds/init.py
index 11312601..a44fb7a9 100644
--- a/subcmds/init.py
+++ b/subcmds/init.py
@@ -20,6 +20,15 @@ import re
20import shutil 20import shutil
21import sys 21import sys
22 22
23from pyversion import is_python3
24if is_python3():
25 import urllib.parse
26else:
27 import imp
28 import urlparse
29 urllib = imp.new_module('urllib')
30 urllib.parse = urlparse.urlparse
31
23from color import Coloring 32from color import Coloring
24from command import InteractiveCommand, MirrorSafeCommand 33from command import InteractiveCommand, MirrorSafeCommand
25from error import ManifestParseError 34from error import ManifestParseError
@@ -91,8 +100,9 @@ to update the working directory files.
91 dest='depth', 100 dest='depth',
92 help='create a shallow clone with given depth; see git clone') 101 help='create a shallow clone with given depth; see git clone')
93 g.add_option('-g', '--groups', 102 g.add_option('-g', '--groups',
94 dest='groups', default='all,-notdefault', 103 dest='groups', default='default',
95 help='restrict manifest projects to ones with a specified group', 104 help='restrict manifest projects to ones with specified '
105 'group(s) [default|all|G1,G2,G3|G4,-G5,-G6]',
96 metavar='GROUP') 106 metavar='GROUP')
97 g.add_option('-p', '--platform', 107 g.add_option('-p', '--platform',
98 dest='platform', default='auto', 108 dest='platform', default='auto',
@@ -134,7 +144,19 @@ to update the working directory files.
134 if not opt.quiet: 144 if not opt.quiet:
135 print('Get %s' % GitConfig.ForUser().UrlInsteadOf(opt.manifest_url), 145 print('Get %s' % GitConfig.ForUser().UrlInsteadOf(opt.manifest_url),
136 file=sys.stderr) 146 file=sys.stderr)
137 m._InitGitDir() 147
148 # The manifest project object doesn't keep track of the path on the
149 # server where this git is located, so let's save that here.
150 mirrored_manifest_git = None
151 if opt.reference:
152 manifest_git_path = urllib.parse(opt.manifest_url).path[1:]
153 mirrored_manifest_git = os.path.join(opt.reference, manifest_git_path)
154 if not mirrored_manifest_git.endswith(".git"):
155 mirrored_manifest_git += ".git"
156 if not os.path.exists(mirrored_manifest_git):
157 mirrored_manifest_git = os.path.join(opt.reference + '/.repo/manifests.git')
158
159 m._InitGitDir(mirror_git=mirrored_manifest_git)
138 160
139 if opt.manifest_branch: 161 if opt.manifest_branch:
140 m.revisionExpr = opt.manifest_branch 162 m.revisionExpr = opt.manifest_branch
@@ -169,7 +191,7 @@ to update the working directory files.
169 191
170 groups = [x for x in groups if x] 192 groups = [x for x in groups if x]
171 groupstr = ','.join(groups) 193 groupstr = ','.join(groups)
172 if opt.platform == 'auto' and groupstr == 'all,-notdefault,platform-' + platform.system().lower(): 194 if opt.platform == 'auto' and groupstr == 'default,platform-' + platform.system().lower():
173 groupstr = None 195 groupstr = None
174 m.config.SetString('manifest.groups', groupstr) 196 m.config.SetString('manifest.groups', groupstr)
175 197
diff --git a/subcmds/list.py b/subcmds/list.py
index 0d5c27f7..945c28d8 100644
--- a/subcmds/list.py
+++ b/subcmds/list.py
@@ -14,7 +14,7 @@
14# limitations under the License. 14# limitations under the License.
15 15
16from __future__ import print_function 16from __future__ import print_function
17import re 17import sys
18 18
19from command import Command, MirrorSafeCommand 19from command import Command, MirrorSafeCommand
20 20
@@ -31,13 +31,19 @@ List all projects; pass '.' to list the project for the cwd.
31This is similar to running: repo forall -c 'echo "$REPO_PATH : $REPO_PROJECT"'. 31This is similar to running: repo forall -c 'echo "$REPO_PATH : $REPO_PROJECT"'.
32""" 32"""
33 33
34 def _Options(self, p, show_smart=True): 34 def _Options(self, p):
35 p.add_option('-r', '--regex', 35 p.add_option('-r', '--regex',
36 dest='regex', action='store_true', 36 dest='regex', action='store_true',
37 help="Filter the project list based on regex or wildcard matching of strings") 37 help="Filter the project list based on regex or wildcard matching of strings")
38 p.add_option('-f', '--fullpath', 38 p.add_option('-f', '--fullpath',
39 dest='fullpath', action='store_true', 39 dest='fullpath', action='store_true',
40 help="Display the full work tree path instead of the relative path") 40 help="Display the full work tree path instead of the relative path")
41 p.add_option('-n', '--name-only',
42 dest='name_only', action='store_true',
43 help="Display only the name of the repository")
44 p.add_option('-p', '--path-only',
45 dest='path_only', action='store_true',
46 help="Display only the path of the repository")
41 47
42 def Execute(self, opt, args): 48 def Execute(self, opt, args):
43 """List all projects and the associated directories. 49 """List all projects and the associated directories.
@@ -50,6 +56,11 @@ This is similar to running: repo forall -c 'echo "$REPO_PATH : $REPO_PROJECT"'.
50 opt: The options. 56 opt: The options.
51 args: Positional args. Can be a list of projects to list, or empty. 57 args: Positional args. Can be a list of projects to list, or empty.
52 """ 58 """
59
60 if opt.fullpath and opt.name_only:
61 print('error: cannot combine -f and -n', file=sys.stderr)
62 sys.exit(1)
63
53 if not opt.regex: 64 if not opt.regex:
54 projects = self.GetProjects(args) 65 projects = self.GetProjects(args)
55 else: 66 else:
@@ -62,18 +73,12 @@ This is similar to running: repo forall -c 'echo "$REPO_PATH : $REPO_PROJECT"'.
62 73
63 lines = [] 74 lines = []
64 for project in projects: 75 for project in projects:
65 lines.append("%s : %s" % (_getpath(project), project.name)) 76 if opt.name_only and not opt.path_only:
77 lines.append("%s" % ( project.name))
78 elif opt.path_only and not opt.name_only:
79 lines.append("%s" % (_getpath(project)))
80 else:
81 lines.append("%s : %s" % (_getpath(project), project.name))
66 82
67 lines.sort() 83 lines.sort()
68 print('\n'.join(lines)) 84 print('\n'.join(lines))
69
70 def FindProjects(self, args):
71 result = []
72 for project in self.GetProjects(''):
73 for arg in args:
74 pattern = re.compile(r'%s' % arg, re.IGNORECASE)
75 if pattern.search(project.name) or pattern.search(project.relpath):
76 result.append(project)
77 break
78 result.sort(key=lambda project: project.relpath)
79 return result
diff --git a/subcmds/overview.py b/subcmds/overview.py
index 418459ae..eed8cf20 100644
--- a/subcmds/overview.py
+++ b/subcmds/overview.py
@@ -42,7 +42,7 @@ are displayed.
42 all_branches = [] 42 all_branches = []
43 for project in self.GetProjects(args): 43 for project in self.GetProjects(args):
44 br = [project.GetUploadableBranch(x) 44 br = [project.GetUploadableBranch(x)
45 for x in project.GetBranches().keys()] 45 for x in project.GetBranches()]
46 br = [x for x in br if x] 46 br = [x for x in br if x]
47 if opt.current_branch: 47 if opt.current_branch:
48 br = [x for x in br if x.name == project.CurrentBranch] 48 br = [x for x in br if x.name == project.CurrentBranch]
diff --git a/subcmds/rebase.py b/subcmds/rebase.py
index 06cda22c..b9a7774d 100644
--- a/subcmds/rebase.py
+++ b/subcmds/rebase.py
@@ -68,7 +68,7 @@ branch but need to incorporate new upstream changes "underneath" them.
68 cb = project.CurrentBranch 68 cb = project.CurrentBranch
69 if not cb: 69 if not cb:
70 if one_project: 70 if one_project:
71 print("error: project %s has a detatched HEAD" % project.relpath, 71 print("error: project %s has a detached HEAD" % project.relpath,
72 file=sys.stderr) 72 file=sys.stderr)
73 return -1 73 return -1
74 # ignore branches with detatched HEADs 74 # ignore branches with detatched HEADs
diff --git a/subcmds/stage.py b/subcmds/stage.py
index ff15ee0c..28849764 100644
--- a/subcmds/stage.py
+++ b/subcmds/stage.py
@@ -49,7 +49,7 @@ The '%prog' command stages files to prepare the next commit.
49 self.Usage() 49 self.Usage()
50 50
51 def _Interactive(self, opt, args): 51 def _Interactive(self, opt, args):
52 all_projects = filter(lambda x: x.IsDirty(), self.GetProjects(args)) 52 all_projects = [p for p in self.GetProjects(args) if p.IsDirty()]
53 if not all_projects: 53 if not all_projects:
54 print('no projects have uncommitted modifications', file=sys.stderr) 54 print('no projects have uncommitted modifications', file=sys.stderr)
55 return 55 return
@@ -98,9 +98,9 @@ The '%prog' command stages files to prepare the next commit.
98 _AddI(all_projects[a_index - 1]) 98 _AddI(all_projects[a_index - 1])
99 continue 99 continue
100 100
101 p = filter(lambda x: x.name == a or x.relpath == a, all_projects) 101 projects = [p for p in all_projects if a in [p.name, p.relpath]]
102 if len(p) == 1: 102 if len(projects) == 1:
103 _AddI(p[0]) 103 _AddI(projects[0])
104 continue 104 continue
105 print('Bye.') 105 print('Bye.')
106 106
diff --git a/subcmds/status.py b/subcmds/status.py
index cce00c81..41c4429a 100644
--- a/subcmds/status.py
+++ b/subcmds/status.py
@@ -21,10 +21,16 @@ except ImportError:
21 import dummy_threading as _threading 21 import dummy_threading as _threading
22 22
23import glob 23import glob
24
25from pyversion import is_python3
26if is_python3():
27 import io
28else:
29 import StringIO as io
30
24import itertools 31import itertools
25import os 32import os
26import sys 33import sys
27import StringIO
28 34
29from color import Coloring 35from color import Coloring
30 36
@@ -142,7 +148,7 @@ the following meanings:
142 for project in all_projects: 148 for project in all_projects:
143 sem.acquire() 149 sem.acquire()
144 150
145 class BufList(StringIO.StringIO): 151 class BufList(io.StringIO):
146 def dump(self, ostream): 152 def dump(self, ostream):
147 for entry in self.buflist: 153 for entry in self.buflist:
148 ostream.write(entry) 154 ostream.write(entry)
@@ -182,7 +188,7 @@ the following meanings:
182 try: 188 try:
183 os.chdir(self.manifest.topdir) 189 os.chdir(self.manifest.topdir)
184 190
185 outstring = StringIO.StringIO() 191 outstring = io.StringIO()
186 self._FindOrphans(glob.glob('.*') + \ 192 self._FindOrphans(glob.glob('.*') + \
187 glob.glob('*'), \ 193 glob.glob('*'), \
188 proj_dirs, proj_dirs_parents, outstring) 194 proj_dirs, proj_dirs_parents, outstring)
diff --git a/subcmds/sync.py b/subcmds/sync.py
index 5c369a74..e9d52b7b 100644
--- a/subcmds/sync.py
+++ b/subcmds/sync.py
@@ -24,8 +24,19 @@ import socket
24import subprocess 24import subprocess
25import sys 25import sys
26import time 26import time
27import urlparse 27
28import xmlrpclib 28from pyversion import is_python3
29if is_python3():
30 import urllib.parse
31 import xmlrpc.client
32else:
33 import imp
34 import urlparse
35 import xmlrpclib
36 urllib = imp.new_module('urllib')
37 urllib.parse = urlparse
38 xmlrpc = imp.new_module('xmlrpc')
39 xmlrpc.client = xmlrpclib
29 40
30try: 41try:
31 import threading as _threading 42 import threading as _threading
@@ -228,6 +239,9 @@ later is required to fix a server side protocol bug.
228 # We'll set to true once we've locked the lock. 239 # We'll set to true once we've locked the lock.
229 did_lock = False 240 did_lock = False
230 241
242 if not opt.quiet:
243 print('Fetching project %s' % project.name)
244
231 # Encapsulate everything in a try/except/finally so that: 245 # Encapsulate everything in a try/except/finally so that:
232 # - We always set err_event in the case of an exception. 246 # - We always set err_event in the case of an exception.
233 # - We always make sure we call sem.release(). 247 # - We always make sure we call sem.release().
@@ -274,6 +288,8 @@ later is required to fix a server side protocol bug.
274 if self.jobs == 1: 288 if self.jobs == 1:
275 for project in projects: 289 for project in projects:
276 pm.update() 290 pm.update()
291 if not opt.quiet:
292 print('Fetching project %s' % project.name)
277 if project.Sync_NetworkHalf( 293 if project.Sync_NetworkHalf(
278 quiet=opt.quiet, 294 quiet=opt.quiet,
279 current_branch_only=opt.current_branch_only, 295 current_branch_only=opt.current_branch_only,
@@ -372,6 +388,13 @@ later is required to fix a server side protocol bug.
372 print('\nerror: Exited sync due to gc errors', file=sys.stderr) 388 print('\nerror: Exited sync due to gc errors', file=sys.stderr)
373 sys.exit(1) 389 sys.exit(1)
374 390
391 def _ReloadManifest(self, manifest_name=None):
392 if manifest_name:
393 # Override calls _Unload already
394 self.manifest.Override(manifest_name)
395 else:
396 self.manifest._Unload()
397
375 def UpdateProjectList(self): 398 def UpdateProjectList(self):
376 new_project_paths = [] 399 new_project_paths = []
377 for project in self.GetProjects(None, missing_ok=True): 400 for project in self.GetProjects(None, missing_ok=True):
@@ -406,7 +429,7 @@ later is required to fix a server side protocol bug.
406 groups = None) 429 groups = None)
407 430
408 if project.IsDirty(): 431 if project.IsDirty():
409 print('error: Cannot remove project "%s": uncommitted changes' 432 print('error: Cannot remove project "%s": uncommitted changes '
410 'are present' % project.relpath, file=sys.stderr) 433 'are present' % project.relpath, file=sys.stderr)
411 print(' commit changes, then run sync again', 434 print(' commit changes, then run sync again',
412 file=sys.stderr) 435 file=sys.stderr)
@@ -464,13 +487,17 @@ later is required to fix a server side protocol bug.
464 if opt.manifest_name: 487 if opt.manifest_name:
465 self.manifest.Override(opt.manifest_name) 488 self.manifest.Override(opt.manifest_name)
466 489
490 manifest_name = opt.manifest_name
491
467 if opt.smart_sync or opt.smart_tag: 492 if opt.smart_sync or opt.smart_tag:
468 if not self.manifest.manifest_server: 493 if not self.manifest.manifest_server:
469 print('error: cannot smart sync: no manifest server defined in' 494 print('error: cannot smart sync: no manifest server defined in '
470 'manifest', file=sys.stderr) 495 'manifest', file=sys.stderr)
471 sys.exit(1) 496 sys.exit(1)
472 497
473 manifest_server = self.manifest.manifest_server 498 manifest_server = self.manifest.manifest_server
499 if not opt.quiet:
500 print('Using manifest server %s' % manifest_server)
474 501
475 if not '@' in manifest_server: 502 if not '@' in manifest_server:
476 username = None 503 username = None
@@ -486,7 +513,7 @@ later is required to fix a server side protocol bug.
486 file=sys.stderr) 513 file=sys.stderr)
487 else: 514 else:
488 try: 515 try:
489 parse_result = urlparse.urlparse(manifest_server) 516 parse_result = urllib.parse.urlparse(manifest_server)
490 if parse_result.hostname: 517 if parse_result.hostname:
491 username, _account, password = \ 518 username, _account, password = \
492 info.authenticators(parse_result.hostname) 519 info.authenticators(parse_result.hostname)
@@ -504,7 +531,7 @@ later is required to fix a server side protocol bug.
504 1) 531 1)
505 532
506 try: 533 try:
507 server = xmlrpclib.Server(manifest_server) 534 server = xmlrpc.client.Server(manifest_server)
508 if opt.smart_sync: 535 if opt.smart_sync:
509 p = self.manifest.manifestProject 536 p = self.manifest.manifestProject
510 b = p.GetBranch(p.CurrentBranch) 537 b = p.GetBranch(p.CurrentBranch)
@@ -513,8 +540,7 @@ later is required to fix a server side protocol bug.
513 branch = branch[len(R_HEADS):] 540 branch = branch[len(R_HEADS):]
514 541
515 env = os.environ.copy() 542 env = os.environ.copy()
516 if (env.has_key('TARGET_PRODUCT') and 543 if 'TARGET_PRODUCT' in env and 'TARGET_BUILD_VARIANT' in env:
517 env.has_key('TARGET_BUILD_VARIANT')):
518 target = '%s-%s' % (env['TARGET_PRODUCT'], 544 target = '%s-%s' % (env['TARGET_PRODUCT'],
519 env['TARGET_BUILD_VARIANT']) 545 env['TARGET_BUILD_VARIANT'])
520 [success, manifest_str] = server.GetApprovedManifest(branch, target) 546 [success, manifest_str] = server.GetApprovedManifest(branch, target)
@@ -538,15 +564,16 @@ later is required to fix a server side protocol bug.
538 print('error: cannot write manifest to %s' % manifest_path, 564 print('error: cannot write manifest to %s' % manifest_path,
539 file=sys.stderr) 565 file=sys.stderr)
540 sys.exit(1) 566 sys.exit(1)
541 self.manifest.Override(manifest_name) 567 self._ReloadManifest(manifest_name)
542 else: 568 else:
543 print('error: %s' % manifest_str, file=sys.stderr) 569 print('error: manifest server RPC call failed: %s' %
570 manifest_str, file=sys.stderr)
544 sys.exit(1) 571 sys.exit(1)
545 except (socket.error, IOError, xmlrpclib.Fault) as e: 572 except (socket.error, IOError, xmlrpc.client.Fault) as e:
546 print('error: cannot connect to manifest server %s:\n%s' 573 print('error: cannot connect to manifest server %s:\n%s'
547 % (self.manifest.manifest_server, e), file=sys.stderr) 574 % (self.manifest.manifest_server, e), file=sys.stderr)
548 sys.exit(1) 575 sys.exit(1)
549 except xmlrpclib.ProtocolError as e: 576 except xmlrpc.client.ProtocolError as e:
550 print('error: cannot connect to manifest server %s:\n%d %s' 577 print('error: cannot connect to manifest server %s:\n%d %s'
551 % (self.manifest.manifest_server, e.errcode, e.errmsg), 578 % (self.manifest.manifest_server, e.errcode, e.errmsg),
552 file=sys.stderr) 579 file=sys.stderr)
@@ -571,7 +598,7 @@ later is required to fix a server side protocol bug.
571 mp.Sync_LocalHalf(syncbuf) 598 mp.Sync_LocalHalf(syncbuf)
572 if not syncbuf.Finish(): 599 if not syncbuf.Finish():
573 sys.exit(1) 600 sys.exit(1)
574 self.manifest._Unload() 601 self._ReloadManifest(manifest_name)
575 if opt.jobs is None: 602 if opt.jobs is None:
576 self.jobs = self.manifest.default.sync_j 603 self.jobs = self.manifest.default.sync_j
577 all_projects = self.GetProjects(args, 604 all_projects = self.GetProjects(args,
@@ -596,7 +623,7 @@ later is required to fix a server side protocol bug.
596 # Iteratively fetch missing and/or nested unregistered submodules 623 # Iteratively fetch missing and/or nested unregistered submodules
597 previously_missing_set = set() 624 previously_missing_set = set()
598 while True: 625 while True:
599 self.manifest._Unload() 626 self._ReloadManifest(manifest_name)
600 all_projects = self.GetProjects(args, 627 all_projects = self.GetProjects(args,
601 missing_ok=True, 628 missing_ok=True,
602 submodules_ok=opt.fetch_submodules) 629 submodules_ok=opt.fetch_submodules)
diff --git a/subcmds/upload.py b/subcmds/upload.py
index e314032a..8d801e08 100644
--- a/subcmds/upload.py
+++ b/subcmds/upload.py
@@ -21,19 +21,26 @@ import sys
21from command import InteractiveCommand 21from command import InteractiveCommand
22from editor import Editor 22from editor import Editor
23from error import HookError, UploadError 23from error import HookError, UploadError
24from git_command import GitCommand
24from project import RepoHook 25from project import RepoHook
25 26
27from pyversion import is_python3
28if not is_python3():
29 # pylint:disable=W0622
30 input = raw_input
31 # pylint:enable=W0622
32
26UNUSUAL_COMMIT_THRESHOLD = 5 33UNUSUAL_COMMIT_THRESHOLD = 5
27 34
28def _ConfirmManyUploads(multiple_branches=False): 35def _ConfirmManyUploads(multiple_branches=False):
29 if multiple_branches: 36 if multiple_branches:
30 print('ATTENTION: One or more branches has an unusually high number' 37 print('ATTENTION: One or more branches has an unusually high number '
31 'of commits.') 38 'of commits.')
32 else: 39 else:
33 print('ATTENTION: You are uploading an unusually high number of commits.') 40 print('ATTENTION: You are uploading an unusually high number of commits.')
34 print('YOU PROBABLY DO NOT MEAN TO DO THIS. (Did you rebase across' 41 print('YOU PROBABLY DO NOT MEAN TO DO THIS. (Did you rebase across '
35 'branches?)') 42 'branches?)')
36 answer = raw_input("If you are sure you intend to do this, type 'yes': ").strip() 43 answer = input("If you are sure you intend to do this, type 'yes': ").strip()
37 return answer == "yes" 44 return answer == "yes"
38 45
39def _die(fmt, *args): 46def _die(fmt, *args):
@@ -140,6 +147,10 @@ Gerrit Code Review: http://code.google.com/p/gerrit/
140 p.add_option('-d', '--draft', 147 p.add_option('-d', '--draft',
141 action='store_true', dest='draft', default=False, 148 action='store_true', dest='draft', default=False,
142 help='If specified, upload as a draft.') 149 help='If specified, upload as a draft.')
150 p.add_option('-D', '--destination', '--dest',
151 type='string', action='store', dest='dest_branch',
152 metavar='BRANCH',
153 help='Submit for review on this target branch.')
143 154
144 # Options relating to upload hook. Note that verify and no-verify are NOT 155 # Options relating to upload hook. Note that verify and no-verify are NOT
145 # opposites of each other, which is why they store to different locations. 156 # opposites of each other, which is why they store to different locations.
@@ -179,7 +190,8 @@ Gerrit Code Review: http://code.google.com/p/gerrit/
179 date = branch.date 190 date = branch.date
180 commit_list = branch.commits 191 commit_list = branch.commits
181 192
182 print('Upload project %s/ to remote branch %s:' % (project.relpath, project.revisionExpr)) 193 destination = opt.dest_branch or project.dest_branch or project.revisionExpr
194 print('Upload project %s/ to remote branch %s:' % (project.relpath, destination))
183 print(' branch %s (%2d commit%s, %s):' % ( 195 print(' branch %s (%2d commit%s, %s):' % (
184 name, 196 name,
185 len(commit_list), 197 len(commit_list),
@@ -213,18 +225,21 @@ Gerrit Code Review: http://code.google.com/p/gerrit/
213 225
214 b = {} 226 b = {}
215 for branch in avail: 227 for branch in avail:
228 if branch is None:
229 continue
216 name = branch.name 230 name = branch.name
217 date = branch.date 231 date = branch.date
218 commit_list = branch.commits 232 commit_list = branch.commits
219 233
220 if b: 234 if b:
221 script.append('#') 235 script.append('#')
236 destination = opt.dest_branch or project.dest_branch or project.revisionExpr
222 script.append('# branch %s (%2d commit%s, %s) to remote branch %s:' % ( 237 script.append('# branch %s (%2d commit%s, %s) to remote branch %s:' % (
223 name, 238 name,
224 len(commit_list), 239 len(commit_list),
225 len(commit_list) != 1 and 's' or '', 240 len(commit_list) != 1 and 's' or '',
226 date, 241 date,
227 project.revisionExpr)) 242 destination))
228 for commit in commit_list: 243 for commit in commit_list:
229 script.append('# %s' % commit) 244 script.append('# %s' % commit)
230 b[name] = branch 245 b[name] = branch
@@ -330,7 +345,21 @@ Gerrit Code Review: http://code.google.com/p/gerrit/
330 key = 'review.%s.uploadtopic' % branch.project.remote.review 345 key = 'review.%s.uploadtopic' % branch.project.remote.review
331 opt.auto_topic = branch.project.config.GetBoolean(key) 346 opt.auto_topic = branch.project.config.GetBoolean(key)
332 347
333 branch.UploadForReview(people, auto_topic=opt.auto_topic, draft=opt.draft) 348 destination = opt.dest_branch or branch.project.dest_branch
349
350 # Make sure our local branch is not setup to track a different remote branch
351 merge_branch = self._GetMergeBranch(branch.project)
352 full_dest = 'refs/heads/%s' % destination
353 if not opt.dest_branch and merge_branch and merge_branch != full_dest:
354 print('merge branch %s does not match destination branch %s'
355 % (merge_branch, full_dest))
356 print('skipping upload.')
357 print('Please use `--destination %s` if this is intentional'
358 % destination)
359 branch.uploaded = False
360 continue
361
362 branch.UploadForReview(people, auto_topic=opt.auto_topic, draft=opt.draft, dest_branch=destination)
334 branch.uploaded = True 363 branch.uploaded = True
335 except UploadError as e: 364 except UploadError as e:
336 branch.error = e 365 branch.error = e
@@ -364,6 +393,21 @@ Gerrit Code Review: http://code.google.com/p/gerrit/
364 if have_errors: 393 if have_errors:
365 sys.exit(1) 394 sys.exit(1)
366 395
396 def _GetMergeBranch(self, project):
397 p = GitCommand(project,
398 ['rev-parse', '--abbrev-ref', 'HEAD'],
399 capture_stdout = True,
400 capture_stderr = True)
401 p.Wait()
402 local_branch = p.stdout.strip()
403 p = GitCommand(project,
404 ['config', '--get', 'branch.%s.merge' % local_branch],
405 capture_stdout = True,
406 capture_stderr = True)
407 p.Wait()
408 merge_branch = p.stdout.strip()
409 return merge_branch
410
367 def Execute(self, opt, args): 411 def Execute(self, opt, args):
368 project_list = self.GetProjects(args) 412 project_list = self.GetProjects(args)
369 pending = [] 413 pending = []