blob: b5cc604ea34c8b0d2ccdc3410980eaa666f67f76 [file] [log] [blame]
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001#
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
Shawn O. Pearce2a1ccb22009-04-10 16:51:53 -070016from optparse import SUPPRESS_HELP
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070017import os
18import re
19import subprocess
20import sys
Shawn O. Pearcef6906872009-04-18 10:49:00 -070021import time
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070022
23from git_command import GIT
Shawn O. Pearcee756c412009-04-13 11:51:15 -070024from project import HEAD
Shawn O. Pearcec95583b2009-03-03 17:47:06 -080025from command import Command, MirrorSafeCommand
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070026from error import RepoChangedException, GitError
27from project import R_HEADS
Shawn O. Pearce350cde42009-04-16 11:21:18 -070028from project import SyncBuffer
Shawn O. Pearce68194f42009-04-10 16:48:52 -070029from progress import Progress
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070030
Shawn O. Pearcec95583b2009-03-03 17:47:06 -080031class Sync(Command, MirrorSafeCommand):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070032 common = True
33 helpSummary = "Update working tree to the latest revision"
34 helpUsage = """
35%prog [<project>...]
36"""
37 helpDescription = """
38The '%prog' command synchronizes local project directories
39with the remote repositories specified in the manifest. If a local
40project does not yet exist, it will clone a new local directory from
41the remote repository and set up tracking branches as specified in
42the manifest. If the local project already exists, '%prog'
43will update the remote branches and rebase any new local changes
44on top of the new remote changes.
45
46'%prog' will synchronize all projects listed at the command
47line. Projects can be specified either by name, or by a relative
48or absolute path to the project's local directory. If no projects
49are specified, '%prog' will synchronize all projects listed in
50the manifest.
Shawn O. Pearce3e768c92009-04-10 16:59:36 -070051
52The -d/--detach option can be used to switch specified projects
53back to the manifest revision. This option is especially helpful
54if the project is currently on a topic branch, but the manifest
55revision is temporarily needed.
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070056"""
57
58 def _Options(self, p):
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -070059 p.add_option('-l','--local-only',
60 dest='local_only', action='store_true',
61 help="only update working tree, don't fetch")
Shawn O. Pearce96fdcef2009-04-10 16:29:20 -070062 p.add_option('-n','--network-only',
63 dest='network_only', action='store_true',
64 help="fetch only, don't update working tree")
Shawn O. Pearce3e768c92009-04-10 16:59:36 -070065 p.add_option('-d','--detach',
66 dest='detach_head', action='store_true',
67 help='detach projects back to manifest revision')
68
Shawn O. Pearcefd89b672009-04-18 11:28:57 -070069 g = p.add_option_group('repo Version options')
70 g.add_option('--no-repo-verify',
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070071 dest='no_repo_verify', action='store_true',
72 help='do not verify repo source code')
Shawn O. Pearcefd89b672009-04-18 11:28:57 -070073 g.add_option('--repo-upgraded',
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -080074 dest='repo_upgraded', action='store_true',
Shawn O. Pearce2a1ccb22009-04-10 16:51:53 -070075 help=SUPPRESS_HELP)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070076
Shawn O. Pearcef6906872009-04-18 10:49:00 -070077 def _Fetch(self, projects):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070078 fetched = set()
Shawn O. Pearce68194f42009-04-10 16:48:52 -070079 pm = Progress('Fetching projects', len(projects))
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070080 for project in projects:
Shawn O. Pearce68194f42009-04-10 16:48:52 -070081 pm.update()
82
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070083 if project.Sync_NetworkHalf():
84 fetched.add(project.gitdir)
85 else:
86 print >>sys.stderr, 'error: Cannot fetch %s' % project.name
87 sys.exit(1)
Shawn O. Pearce68194f42009-04-10 16:48:52 -070088 pm.end()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070089 return fetched
90
91 def Execute(self, opt, args):
Shawn O. Pearce3e768c92009-04-10 16:59:36 -070092 if opt.network_only and opt.detach_head:
93 print >>sys.stderr, 'error: cannot combine -n and -d'
94 sys.exit(1)
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -070095 if opt.network_only and opt.local_only:
96 print >>sys.stderr, 'error: cannot combine -n and -l'
97 sys.exit(1)
Shawn O. Pearce3e768c92009-04-10 16:59:36 -070098
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070099 rp = self.manifest.repoProject
100 rp.PreSync()
101
102 mp = self.manifest.manifestProject
103 mp.PreSync()
104
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800105 if opt.repo_upgraded:
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700106 _PostRepoUpgrade(self.manifest)
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -0800107
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700108 all = self.GetProjects(args, missing_ok=True)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700109
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700110 if not opt.local_only:
Shawn O. Pearcef6906872009-04-18 10:49:00 -0700111 to_fetch = []
112 now = time.time()
113 if (24 * 60 * 60) <= (now - rp.LastFetch):
114 to_fetch.append(rp)
115 to_fetch.append(mp)
116 to_fetch.extend(all)
117
118 fetched = self._Fetch(to_fetch)
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700119 _PostRepoFetch(rp, opt.no_repo_verify)
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700120 if opt.network_only:
121 # bail out now; the rest touches the working tree
122 return
123
124 if mp.HasChanges:
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700125 syncbuf = SyncBuffer(mp.config)
126 mp.Sync_LocalHalf(syncbuf)
127 if not syncbuf.Finish():
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700128 sys.exit(1)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700129
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700130 self.manifest._Unload()
131 all = self.GetProjects(args, missing_ok=True)
132 missing = []
133 for project in all:
134 if project.gitdir not in fetched:
135 missing.append(project)
Shawn O. Pearcef6906872009-04-18 10:49:00 -0700136 self._Fetch(missing)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700137
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700138 syncbuf = SyncBuffer(mp.config,
139 detach_head = opt.detach_head)
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700140 pm = Progress('Syncing work tree', len(all))
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700141 for project in all:
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700142 pm.update()
Shawn O. Pearcee284ad12008-11-04 07:37:10 -0800143 if project.worktree:
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700144 project.Sync_LocalHalf(syncbuf)
Shawn O. Pearce68194f42009-04-10 16:48:52 -0700145 pm.end()
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700146 print >>sys.stderr
147 if not syncbuf.Finish():
148 sys.exit(1)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700149
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700150
151def _PostRepoUpgrade(manifest):
152 for project in manifest.projects.values():
153 if project.Exists:
154 project.PostRepoUpgrade()
155
156def _PostRepoFetch(rp, no_repo_verify=False, verbose=False):
157 if rp.HasChanges:
158 print >>sys.stderr, 'info: A new version of repo is available'
159 print >>sys.stderr, ''
160 if no_repo_verify or _VerifyTag(rp):
Shawn O. Pearce350cde42009-04-16 11:21:18 -0700161 syncbuf = SyncBuffer(rp.config)
162 rp.Sync_LocalHalf(syncbuf)
163 if not syncbuf.Finish():
Shawn O. Pearcee756c412009-04-13 11:51:15 -0700164 sys.exit(1)
165 print >>sys.stderr, 'info: Restarting repo with latest version'
166 raise RepoChangedException(['--repo-upgraded'])
167 else:
168 print >>sys.stderr, 'warning: Skipped upgrade to unverified version'
169 else:
170 if verbose:
171 print >>sys.stderr, 'repo version %s is current' % rp.work_git.describe(HEAD)
172
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700173def _VerifyTag(project):
174 gpg_dir = os.path.expanduser('~/.repoconfig/gnupg')
175 if not os.path.exists(gpg_dir):
176 print >>sys.stderr,\
177"""warning: GnuPG was not available during last "repo init"
178warning: Cannot automatically authenticate repo."""
179 return True
180
181 remote = project.GetRemote(project.remote.name)
182 ref = remote.ToLocal(project.revision)
183
184 try:
185 cur = project.bare_git.describe(ref)
186 except GitError:
187 cur = None
188
189 if not cur \
190 or re.compile(r'^.*-[0-9]{1,}-g[0-9a-f]{1,}$').match(cur):
191 rev = project.revision
192 if rev.startswith(R_HEADS):
193 rev = rev[len(R_HEADS):]
194
195 print >>sys.stderr
196 print >>sys.stderr,\
197 "warning: project '%s' branch '%s' is not signed" \
198 % (project.name, rev)
199 return False
200
201 env = dict(os.environ)
202 env['GIT_DIR'] = project.gitdir
203 env['GNUPGHOME'] = gpg_dir
204
205 cmd = [GIT, 'tag', '-v', cur]
206 proc = subprocess.Popen(cmd,
207 stdout = subprocess.PIPE,
208 stderr = subprocess.PIPE,
209 env = env)
210 out = proc.stdout.read()
211 proc.stdout.close()
212
213 err = proc.stderr.read()
214 proc.stderr.close()
215
216 if proc.wait() != 0:
217 print >>sys.stderr
218 print >>sys.stderr, out
219 print >>sys.stderr, err
220 print >>sys.stderr
221 return False
222 return True