| OLD | NEW |
| (Empty) | |
| 1 #!/usr/bin/python |
| 2 |
| 3 # Update Dartium DEPS automatically. |
| 4 |
| 5 from datetime import datetime, timedelta |
| 6 import optparse |
| 7 import os |
| 8 import re |
| 9 from subprocess import Popen, PIPE |
| 10 import sys |
| 11 from time import strptime |
| 12 |
| 13 # Instructions: |
| 14 # |
| 15 # To run locally: |
| 16 # (a) Create and change to a directory to run the updater in: |
| 17 # > mkdir /usr/local/google/home/$USER/dartium_deps_updater |
| 18 # > cd /usr/local/google/home/$USER/dartium_deps_updater |
| 19 # |
| 20 # (b) Make a 'deps' directory to store temporary files: |
| 21 # > mkdir deps |
| 22 # |
| 23 # (c) Checkout dart/tools/dartium (with this script): |
| 24 # > svn co https://dart.googlecode.com/svn/branches/bleeding_edge/dart/tool
s/dartium dartium_tools |
| 25 # |
| 26 # (d) If your home directory is remote, consider redefining it for this shell/s
cript: |
| 27 # > cp -R $HOME/.subversion /usr/local/google/home/$USER |
| 28 # > export HOME=/usr/local/google/home/$USER |
| 29 # |
| 30 # (e) Test by running (Ctrl-C to quit): |
| 31 # > ./dartium_tools/update_deps.py |
| 32 # > ./dartium_tools/update_deps.py --target=multivm |
| 33 # > ./dartium_tools/update_deps.py --target=clank |
| 34 # > ./dartium_tools/update_deps.py --target=integration |
| 35 # |
| 36 # (f) Run periodical update: |
| 37 # > while true; do ./dartium_tools/update_deps.py --force ; sleep 300 ; don
e |
| 38 |
| 39 ######################################################################## |
| 40 # Repositories to auto-update |
| 41 ######################################################################## |
| 42 |
| 43 BRANCH_CURRENT="dart/1847" |
| 44 BRANCH_NEXT="dart/1916" |
| 45 BRANCH_MULTIVM="dart/multivm" |
| 46 |
| 47 TARGETS = { |
| 48 'dartium': ( |
| 49 'https://dart.googlecode.com/svn/branches/bleeding_edge/deps/dartium.deps', |
| 50 'dartium', |
| 51 ['webkit', 'chromium'], |
| 52 BRANCH_CURRENT, |
| 53 ), |
| 54 'integration': ( |
| 55 'https://dart.googlecode.com/svn/branches/dartium_integration/deps/dartium.d
eps', |
| 56 'dartium', |
| 57 ['webkit', 'chromium'], |
| 58 BRANCH_NEXT, |
| 59 ), |
| 60 'clank': ( |
| 61 'https://dart.googlecode.com/svn/branches/bleeding_edge/deps/clank.deps', |
| 62 'dartium', |
| 63 ['webkit', 'chromium'], |
| 64 BRANCH_CURRENT, |
| 65 ), |
| 66 'multivm': ( |
| 67 'https://dart.googlecode.com/svn/branches/bleeding_edge/deps/multivm.deps', |
| 68 'multivm', |
| 69 ['blink'], |
| 70 BRANCH_MULTIVM, |
| 71 ), |
| 72 } |
| 73 |
| 74 # Each element in this map represents a repository to update. Entries |
| 75 # take the form: |
| 76 # (repo_tag: (svn_url, view_url)) |
| 77 # |
| 78 # The repo_tag must match the DEPS revision entry. I.e, there must be |
| 79 # an entry of the form: |
| 80 # 'dartium_%s_revision' % repo_tag |
| 81 # to roll forward. |
| 82 # |
| 83 # The view_url should be parameterized by revision number. This is |
| 84 # used to generated the commit message. |
| 85 REPOSITORY_INFO = { |
| 86 'webkit': ( |
| 87 'http://src.chromium.org/blink/branches/%s', |
| 88 'http://src.chromium.org/viewvc/blink?view=rev&revision=%s'), |
| 89 'blink': ( |
| 90 'http://src.chromium.org/blink/branches/%s', |
| 91 'http://src.chromium.org/viewvc/blink?view=rev&revision=%s'), |
| 92 'chromium': ( |
| 93 'http://src.chromium.org/chrome/branches/%s', |
| 94 'http://src.chromium.org/viewvc/chrome?view=rev&revision=%s'), |
| 95 } |
| 96 |
| 97 REPOSITORIES = REPOSITORY_INFO.keys() |
| 98 |
| 99 ######################################################################## |
| 100 # Actions |
| 101 ######################################################################## |
| 102 |
| 103 def write_file(filename, content): |
| 104 f = open(filename, "w") |
| 105 f.write(content) |
| 106 f.close() |
| 107 |
| 108 def run_cmd(cmd): |
| 109 print "\n[%s]\n$ %s" % (os.getcwd(), " ".join(cmd)) |
| 110 pipe = Popen(cmd, stdout=PIPE, stderr=PIPE) |
| 111 output = pipe.communicate() |
| 112 if pipe.returncode == 0: |
| 113 return output[0] |
| 114 else: |
| 115 print output[1] |
| 116 print "FAILED. RET_CODE=%d" % pipe.returncode |
| 117 sys.exit(pipe.returncode) |
| 118 |
| 119 def parse_iso_time(s): |
| 120 pair = s.rsplit(' ', 1) |
| 121 d = datetime.strptime(pair[0], '%Y-%m-%d %H:%M:%S') |
| 122 offset = timedelta(hours=int(pair[1][0:3])) |
| 123 return d - offset |
| 124 |
| 125 def parse_git_log(output, repo): |
| 126 if len(output) < 4: |
| 127 return [] |
| 128 lst = output.split(os.linesep) |
| 129 lst = [s.strip('\'') for s in lst] |
| 130 lst = [s.split(',', 3) for s in lst] |
| 131 lst = [{'repo': repo, |
| 132 'rev': s[0], |
| 133 'isotime':s[1], |
| 134 'author': s[2], |
| 135 'utctime': parse_iso_time(s[1]), |
| 136 'info': s[3]} for s in lst] |
| 137 return lst |
| 138 |
| 139 def parse_svn_log(output, repo): |
| 140 lst = output.split(os.linesep) |
| 141 lst = [s.strip('\'') for s in lst] |
| 142 output = '_LINESEP_'.join(lst) |
| 143 lst = output.split('----------------------------------------------------------
--------------') |
| 144 lst = [s.replace('_LINESEP_', '\n') for s in lst] |
| 145 lst = [s.strip('\n') for s in lst] |
| 146 lst = [s.strip(' ') for s in lst] |
| 147 lst = [s for s in lst if len(s) > 0] |
| 148 pattern = re.compile(' \| (\d+) line(s|)') |
| 149 lst = [pattern.sub(' | ', s) for s in lst] |
| 150 lst = [s.split(' | ', 3) for s in lst] |
| 151 lst = [{'repo': repo, |
| 152 'rev': s[0].replace('r', ''), |
| 153 'author': s[1], |
| 154 'isotime':s[2][0:25], |
| 155 'utctime': parse_iso_time(s[2][0:25]), |
| 156 'info': s[3].split('\n')[2]} for s in lst] |
| 157 return lst |
| 158 |
| 159 def commit_url(repo, rev): |
| 160 numrev = rev.replace('r', '') |
| 161 if repo in REPOSITORIES: |
| 162 (_, view_url) = REPOSITORY_INFO[repo] |
| 163 return view_url % numrev |
| 164 else: |
| 165 raise Exception('Unknown repo'); |
| 166 |
| 167 def find_max(revs): |
| 168 max_time = None |
| 169 max_position = None |
| 170 for i, rev in enumerate(revs): |
| 171 if rev == []: |
| 172 continue |
| 173 if max_time is None or rev[0]['utctime'] > max_time: |
| 174 max_time = rev[0]['utctime'] |
| 175 max_position = i |
| 176 return max_position |
| 177 |
| 178 def merge_revs(revs): |
| 179 position = find_max(revs) |
| 180 if position is None: |
| 181 return [] |
| 182 item = revs[position][0] |
| 183 revs[position] = revs[position][1:] |
| 184 return [item] + merge_revs(revs) |
| 185 |
| 186 def main(): |
| 187 option_parser = optparse.OptionParser() |
| 188 option_parser.add_option('', '--target', help="Update one of [dartium|integrat
ion|multivm|clank]", action="store", dest="target", default="dartium") |
| 189 option_parser.add_option('', '--force', help="Push DEPS update to server witho
ut prompting", action="store_true", dest="force") |
| 190 options, args = option_parser.parse_args() |
| 191 |
| 192 target = options.target |
| 193 if not target in TARGETS.keys(): |
| 194 print "Error: invalid target" |
| 195 print "Choose one of " + str(TARGETS) |
| 196 (deps_dir, prefix, repos, branch) = TARGETS[target] |
| 197 deps_file = deps_dir + '/DEPS' |
| 198 |
| 199 src_dir = "/usr/local/google/home/%s/dartium_deps_updater/deps/%s" % (os.envir
on["USER"], target) |
| 200 os.putenv("GIT_PAGER", "") |
| 201 |
| 202 if not os.path.exists(src_dir): |
| 203 print run_cmd(['svn', 'co', deps_dir, src_dir]) |
| 204 |
| 205 os.chdir(src_dir) |
| 206 |
| 207 # parse DEPS |
| 208 deps = run_cmd(['svn', 'cat', deps_file]) |
| 209 rev_num = {} |
| 210 for repo in repos: |
| 211 revision = '%s_%s_revision":\s*"(.+)"' % (prefix, repo) |
| 212 rev_num[repo] = re.search(revision, deps).group(1) |
| 213 |
| 214 # update repos |
| 215 all_revs = [] |
| 216 for repo in repos: |
| 217 (svn_url, _) = REPOSITORY_INFO[repo] |
| 218 output = run_cmd(["svn", "log", "-r", "HEAD:%s" % rev_num[repo], svn_url %
branch]) |
| 219 revs = parse_svn_log(output, repo) |
| 220 if revs and revs[-1]['rev'] == rev_num[repo]: |
| 221 revs.pop() |
| 222 all_revs.append(revs) |
| 223 |
| 224 pending_updates = merge_revs(all_revs) |
| 225 pending_updates.reverse() |
| 226 |
| 227 print |
| 228 print "Current DEPS revisions:" |
| 229 for repo in repos: |
| 230 print ' %s_%s_revision=%s' % (prefix, repo, rev_num[repo]) |
| 231 |
| 232 if len(pending_updates) == 0: |
| 233 print "DEPS is up-to-date." |
| 234 sys.exit(0) |
| 235 else: |
| 236 print "Pending DEPS updates:" |
| 237 for s in pending_updates: |
| 238 print " %s to %s (%s) %s" % (s['repo'], s['rev'], s['isotime'], s['info']
) |
| 239 |
| 240 # make the next DEPS update |
| 241 os.chdir(src_dir) |
| 242 run_cmd(['rm', 'DEPS']) |
| 243 print run_cmd(['svn', 'update']) |
| 244 s = pending_updates[0] |
| 245 |
| 246 pattern = re.compile(prefix + '_' + s['repo'] + '_revision":\s*"(.+)"') |
| 247 new_deps = pattern.sub(prefix + '_' + s['repo'] + '_revision": "' + s['rev'] +
'"', deps) |
| 248 write_file('DEPS', new_deps) |
| 249 |
| 250 commit_log = 'DEPS AutoUpdate: %s to %s (%s) %s\n' % (s['repo'], s['rev'], s['
isotime'], s['author']) |
| 251 commit_log += s['info'] + '\n' + commit_url(s['repo'], s['rev']) |
| 252 |
| 253 write_file('commit_log.txt', commit_log) |
| 254 print run_cmd(['svn', 'diff']) |
| 255 print |
| 256 print "Commit log:" |
| 257 print "---------------------------------------------" |
| 258 print commit_log |
| 259 print "---------------------------------------------" |
| 260 |
| 261 if not options.force: |
| 262 print "Ready to push; press Enter to continue or Control-C to abort..." |
| 263 sys.stdin.readline() |
| 264 print run_cmd(['svn', 'commit', '--file', 'commit_log.txt']) |
| 265 print "Done." |
| 266 |
| 267 |
| 268 if '__main__' == __name__: |
| 269 main() |
| OLD | NEW |