blob: 21e0899af03197c8e88c1c3d7d24184edad67121 [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
21
22from git_command import GIT
Shawn O. Pearcec95583b2009-03-03 17:47:06 -080023from command import Command, MirrorSafeCommand
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070024from error import RepoChangedException, GitError
25from project import R_HEADS
26
Shawn O. Pearcec95583b2009-03-03 17:47:06 -080027class Sync(Command, MirrorSafeCommand):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070028 common = True
29 helpSummary = "Update working tree to the latest revision"
30 helpUsage = """
31%prog [<project>...]
32"""
33 helpDescription = """
34The '%prog' command synchronizes local project directories
35with the remote repositories specified in the manifest. If a local
36project does not yet exist, it will clone a new local directory from
37the remote repository and set up tracking branches as specified in
38the manifest. If the local project already exists, '%prog'
39will update the remote branches and rebase any new local changes
40on top of the new remote changes.
41
42'%prog' will synchronize all projects listed at the command
43line. Projects can be specified either by name, or by a relative
44or absolute path to the project's local directory. If no projects
45are specified, '%prog' will synchronize all projects listed in
46the manifest.
Shawn O. Pearce3e768c92009-04-10 16:59:36 -070047
48The -d/--detach option can be used to switch specified projects
49back to the manifest revision. This option is especially helpful
50if the project is currently on a topic branch, but the manifest
51revision is temporarily needed.
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070052"""
53
54 def _Options(self, p):
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -070055 p.add_option('-l','--local-only',
56 dest='local_only', action='store_true',
57 help="only update working tree, don't fetch")
Shawn O. Pearce96fdcef2009-04-10 16:29:20 -070058 p.add_option('-n','--network-only',
59 dest='network_only', action='store_true',
60 help="fetch only, don't update working tree")
Shawn O. Pearce3e768c92009-04-10 16:59:36 -070061 p.add_option('-d','--detach',
62 dest='detach_head', action='store_true',
63 help='detach projects back to manifest revision')
64
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070065 p.add_option('--no-repo-verify',
66 dest='no_repo_verify', action='store_true',
67 help='do not verify repo source code')
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -080068 p.add_option('--repo-upgraded',
69 dest='repo_upgraded', action='store_true',
Shawn O. Pearce2a1ccb22009-04-10 16:51:53 -070070 help=SUPPRESS_HELP)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070071
72 def _Fetch(self, *projects):
73 fetched = set()
74 for project in projects:
75 if project.Sync_NetworkHalf():
76 fetched.add(project.gitdir)
77 else:
78 print >>sys.stderr, 'error: Cannot fetch %s' % project.name
79 sys.exit(1)
80 return fetched
81
82 def Execute(self, opt, args):
Shawn O. Pearce3e768c92009-04-10 16:59:36 -070083 if opt.network_only and opt.detach_head:
84 print >>sys.stderr, 'error: cannot combine -n and -d'
85 sys.exit(1)
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -070086 if opt.network_only and opt.local_only:
87 print >>sys.stderr, 'error: cannot combine -n and -l'
88 sys.exit(1)
Shawn O. Pearce3e768c92009-04-10 16:59:36 -070089
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070090 rp = self.manifest.repoProject
91 rp.PreSync()
92
93 mp = self.manifest.manifestProject
94 mp.PreSync()
95
Shawn O. Pearcec9ef7442008-11-03 10:32:09 -080096 if opt.repo_upgraded:
97 for project in self.manifest.projects.values():
98 if project.Exists:
99 project.PostRepoUpgrade()
100
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700101 all = self.GetProjects(args, missing_ok=True)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700102
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700103 if not opt.local_only:
104 fetched = self._Fetch(rp, mp, *all)
105
106 if rp.HasChanges:
107 print >>sys.stderr, 'info: A new version of repo is available'
108 print >>sys.stderr, ''
109 if opt.no_repo_verify or _VerifyTag(rp):
110 if not rp.Sync_LocalHalf():
111 sys.exit(1)
112 print >>sys.stderr, 'info: Restarting repo with latest version'
113 raise RepoChangedException(['--repo-upgraded'])
114 else:
115 print >>sys.stderr, 'warning: Skipped upgrade to unverified version'
116
117 if opt.network_only:
118 # bail out now; the rest touches the working tree
119 return
120
121 if mp.HasChanges:
122 if not mp.Sync_LocalHalf():
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700123 sys.exit(1)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700124
Shawn O. Pearceb1562fa2009-04-10 17:04:08 -0700125 self.manifest._Unload()
126 all = self.GetProjects(args, missing_ok=True)
127 missing = []
128 for project in all:
129 if project.gitdir not in fetched:
130 missing.append(project)
131 self._Fetch(*missing)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700132
133 for project in all:
Shawn O. Pearcee284ad12008-11-04 07:37:10 -0800134 if project.worktree:
Shawn O. Pearce3e768c92009-04-10 16:59:36 -0700135 if not project.Sync_LocalHalf(
136 detach_head=opt.detach_head):
Shawn O. Pearcee284ad12008-11-04 07:37:10 -0800137 sys.exit(1)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700138
139
140def _VerifyTag(project):
141 gpg_dir = os.path.expanduser('~/.repoconfig/gnupg')
142 if not os.path.exists(gpg_dir):
143 print >>sys.stderr,\
144"""warning: GnuPG was not available during last "repo init"
145warning: Cannot automatically authenticate repo."""
146 return True
147
148 remote = project.GetRemote(project.remote.name)
149 ref = remote.ToLocal(project.revision)
150
151 try:
152 cur = project.bare_git.describe(ref)
153 except GitError:
154 cur = None
155
156 if not cur \
157 or re.compile(r'^.*-[0-9]{1,}-g[0-9a-f]{1,}$').match(cur):
158 rev = project.revision
159 if rev.startswith(R_HEADS):
160 rev = rev[len(R_HEADS):]
161
162 print >>sys.stderr
163 print >>sys.stderr,\
164 "warning: project '%s' branch '%s' is not signed" \
165 % (project.name, rev)
166 return False
167
168 env = dict(os.environ)
169 env['GIT_DIR'] = project.gitdir
170 env['GNUPGHOME'] = gpg_dir
171
172 cmd = [GIT, 'tag', '-v', cur]
173 proc = subprocess.Popen(cmd,
174 stdout = subprocess.PIPE,
175 stderr = subprocess.PIPE,
176 env = env)
177 out = proc.stdout.read()
178 proc.stdout.close()
179
180 err = proc.stderr.read()
181 proc.stderr.close()
182
183 if proc.wait() != 0:
184 print >>sys.stderr
185 print >>sys.stderr, out
186 print >>sys.stderr, err
187 print >>sys.stderr
188 return False
189 return True