OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library update_homebrew; | 5 library update_homebrew; |
6 | 6 |
| 7 import 'dart:async'; |
| 8 import 'dart:convert'; |
7 import 'dart:io'; | 9 import 'dart:io'; |
8 import 'dart:convert'; | 10 |
9 import 'dart:async'; | 11 import 'package:args/args.dart'; |
| 12 import 'package:googleapis/common/common.dart' show DownloadOptions, Media; |
| 13 import 'package:googleapis/storage/v1.dart' as storage; |
10 import 'package:http/http.dart' as http; | 14 import 'package:http/http.dart' as http; |
11 import 'package:args/args.dart'; | 15 import 'package:stack_trace/stack_trace.dart'; |
12 import 'package:googleapis/storage/v1.dart' as storage; | |
13 import 'package:googleapis/common/common.dart' show DownloadOptions, Media; | |
14 | 16 |
15 String repository; // The path to the temporary git checkout of dart-homebrew. | 17 String repository; // The path to the temporary git checkout of dart-homebrew. |
16 Map gitEnvironment; // Pass a wrapper script for SSH to git in the environment. | 18 Map gitEnvironment; // Pass a wrapper script for SSH to git in the environment. |
17 | 19 |
18 final CHANNELS = ['dev', 'stable']; | 20 const GITHUB_REPO = 'dart-lang/homebrew-dart'; |
19 | 21 |
20 final SDK_FILES = ['sdk/dartsdk-macos-x64-release.zip', | 22 const CHANNELS = const ['dev', 'stable']; |
21 'sdk/dartsdk-macos-ia32-release.zip' ]; | 23 |
22 final DARTIUM_FILES = ['dartium/dartium-macos-ia32-release.zip', | 24 const SDK_FILES = const [ |
23 'dartium/content_shell-macos-ia32-release.zip']; | 25 'sdk/dartsdk-macos-x64-release.zip', |
| 26 'sdk/dartsdk-macos-ia32-release.zip' |
| 27 ]; |
| 28 |
| 29 const DARTIUM_FILES = const [ |
| 30 'dartium/dartium-macos-ia32-release.zip', |
| 31 'dartium/content_shell-macos-ia32-release.zip' |
| 32 ]; |
| 33 |
24 final FILES = []..addAll(SDK_FILES)..addAll(DARTIUM_FILES); | 34 final FILES = []..addAll(SDK_FILES)..addAll(DARTIUM_FILES); |
25 | 35 |
| 36 Future<String> getHash256(String channel, int revision, String download) async { |
| 37 var client = new http.Client(); |
| 38 try { |
| 39 var api = new storage.StorageApi(client); |
| 40 var media = await api.objects.get('dart-archive', |
| 41 'channels/$channel/release/$revision/$download.sha256sum', |
| 42 downloadOptions: DownloadOptions.FullMedia); |
26 | 43 |
27 Future<String> getHash256(String channel, int revision, String download) { | 44 var hashLine = await ASCII.decodeStream(media.stream); |
28 var client = new http.Client(); | 45 return new RegExp('[0-9a-fA-F]*').stringMatch(hashLine); |
29 var api = new storage.StorageApi(client); | 46 } finally { |
30 return | 47 client.close(); |
31 api.objects.get('dart-archive', | 48 } |
32 'channels/$channel/release/$revision/$download.sha256sum', | |
33 downloadOptions: DownloadOptions.FullMedia) | |
34 .then((Media media) => ASCII.decodeStream(media.stream)) | |
35 .then((hashLine) => new RegExp('[0-9a-fA-F]*').stringMatch(hashLine)) | |
36 .whenComplete(client.close); | |
37 } | 49 } |
38 | 50 |
39 Future<String> getVersion(String channel, int revision) { | 51 Future<String> getVersion(String channel, int revision) async { |
40 var client = new http.Client(); | 52 var client = new http.Client(); |
41 var api = new storage.StorageApi(client); | 53 try { |
42 return api.objects.get('dart-archive', | 54 var api = new storage.StorageApi(client); |
43 'channels/$channel/release/$revision/VERSION', | 55 |
44 downloadOptions: DownloadOptions.FullMedia) | 56 var media = await api.objects.get( |
45 .then((Media media) => JSON.fuse(ASCII).decoder.bind(media.stream).first) | 57 'dart-archive', 'channels/$channel/release/$revision/VERSION', |
46 .then((versionObject) => versionObject['version']) | 58 downloadOptions: DownloadOptions.FullMedia); |
47 .whenComplete(client.close); | 59 |
| 60 var versionObject = await JSON.fuse(ASCII).decoder.bind(media.stream).first; |
| 61 return versionObject['version']; |
| 62 } finally { |
| 63 client.close(); |
| 64 } |
48 } | 65 } |
49 | 66 |
50 Future setCurrentRevisions(Map revisions) { | 67 Future setCurrentRevisions(Map revisions) async { |
51 return new File('$repository/dart.rb') | 68 var lines = await (new File('$repository/dart.rb')).readAsLines(); |
52 .readAsLines() | 69 |
53 .then((lines) { | 70 for (var channel in CHANNELS) { |
54 for (var channel in CHANNELS) { | 71 final regExp = new RegExp('channels/$channel/release/(\\d*)/sdk'); |
55 final regExp = new RegExp('channels/$channel/release/(\\d*)/sdk'); | 72 revisions[channel] = |
56 revisions[channel] = | 73 regExp.firstMatch(lines.firstWhere(regExp.hasMatch)).group(1); |
57 » regExp.firstMatch(lines.firstWhere(regExp.hasMatch)).group(1); | 74 } |
58 } | |
59 }); | |
60 } | 75 } |
61 | 76 |
62 Future setHashes(Map revisions, Map hashes) { | 77 Future setHashes(Map revisions, Map hashes) { |
63 List waitOn = []; | 78 List waitOn = []; |
64 for (var channel in CHANNELS) { | 79 for (var channel in CHANNELS) { |
65 hashes[channel] = {}; | 80 hashes[channel] = {}; |
66 for (var file in FILES) { | 81 for (var file in FILES) { |
67 waitOn.add(getHash256(channel, revisions[channel], file).then((hash) { | 82 waitOn.add(getHash256(channel, revisions[channel], file).then((hash) { |
68 hashes[channel][file] = hash; | 83 hashes[channel][file] = hash; |
69 })); | 84 })); |
70 } | 85 } |
71 } | 86 } |
72 return Future.wait(waitOn); | 87 return Future.wait(waitOn); |
73 } | 88 } |
74 | 89 |
75 Future writeHomebrewInfo(String channel, int revision) { | 90 Future writeHomebrewInfo(String channel, int revision) async { |
76 var revisions = {}; | 91 var revisions = {}; |
77 var hashes = {}; | 92 var hashes = {}; |
78 var devVersion; | 93 |
79 var stableVersion; | 94 await setCurrentRevisions(revisions); |
80 return setCurrentRevisions(revisions).then((_) { | 95 |
81 if (revisions[channel] == revision) { | 96 if (revisions[channel] == revision) { |
82 print("Channel $channel is already at revision $revision in homebrew."); | 97 print("Channel $channel is already at revision $revision in homebrew."); |
83 exit(0); | 98 exit(0); |
84 } | 99 } |
85 revisions[channel] = revision; | 100 revisions[channel] = revision; |
86 return setHashes(revisions, hashes); | 101 await setHashes(revisions, hashes); |
87 }).then((_) { | 102 var devVersion = await getVersion('dev', revisions['dev']); |
88 return getVersion('dev', revisions['dev']); | 103 |
89 }).then((version) { | 104 var stableVersion = await getVersion('stable', revisions['stable']); |
90 devVersion = version; | 105 |
91 return getVersion('stable', revisions['stable']); | 106 await (new File('$repository/dartium.rb').openWrite() |
92 }).then((version) { | 107 ..write(DartiumFile(revisions, hashes, devVersion, stableVersion))).close(); |
93 stableVersion = version; | 108 await (new File('$repository/dart.rb').openWrite() |
94 return (new File('$repository/dartium.rb').openWrite() | 109 ..write(DartFile(revisions, hashes, devVersion, stableVersion))).close(); |
95 ..write(DartiumFile(revisions, hashes, devVersion, stableVersion))) | |
96 .close(); | |
97 }).then((_) { | |
98 return (new File('$repository/dart.rb').openWrite() | |
99 ..write(DartFile(revisions, hashes, devVersion, stableVersion))) | |
100 .close(); | |
101 }); | |
102 } | 110 } |
103 | 111 |
104 String DartiumFile(Map revisions, | 112 String DartiumFile( |
105 Map hashes, | 113 Map revisions, Map hashes, String devVersion, String stableVersion) { |
106 String devVersion, | |
107 String stableVersion) { | |
108 final urlBase = 'https://storage.googleapis.com/dart-archive/channels'; | 114 final urlBase = 'https://storage.googleapis.com/dart-archive/channels'; |
109 final dartiumFile = 'dartium/dartium-macos-ia32-release.zip'; | 115 final dartiumFile = 'dartium/dartium-macos-ia32-release.zip'; |
110 final contentShellFile = 'dartium/content_shell-macos-ia32-release.zip'; | 116 final contentShellFile = 'dartium/content_shell-macos-ia32-release.zip'; |
111 | 117 |
112 return ''' | 118 return ''' |
113 require 'formula' | 119 require 'formula' |
114 | 120 |
115 class Dartium < Formula | 121 class Dartium < Formula |
116 homepage "https://www.dartlang.org" | 122 homepage "https://www.dartlang.org" |
117 | 123 |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
160 EOS | 166 EOS |
161 end | 167 end |
162 | 168 |
163 test do | 169 test do |
164 system "#{bin}/dartium" | 170 system "#{bin}/dartium" |
165 end | 171 end |
166 end | 172 end |
167 '''; | 173 '''; |
168 } | 174 } |
169 | 175 |
170 String DartFile(Map revisions, | 176 String DartFile( |
171 Map hashes, | 177 Map revisions, Map hashes, String devVersion, String stableVersion) { |
172 String devVersion, | |
173 String stableVersion) { | |
174 final urlBase = 'https://storage.googleapis.com/dart-archive/channels'; | 178 final urlBase = 'https://storage.googleapis.com/dart-archive/channels'; |
175 final x64File = 'sdk/dartsdk-macos-x64-release.zip'; | 179 final x64File = 'sdk/dartsdk-macos-x64-release.zip'; |
176 final ia32File = 'sdk/dartsdk-macos-ia32-release.zip'; | 180 final ia32File = 'sdk/dartsdk-macos-ia32-release.zip'; |
177 | 181 |
178 return ''' | 182 return ''' |
179 require 'formula' | 183 require 'formula' |
180 | 184 |
181 class Dart < Formula | 185 class Dart < Formula |
182 homepage 'https://www.dartlang.org/' | 186 homepage 'https://www.dartlang.org/' |
183 | 187 |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
219 print(r"test message"); | 223 print(r"test message"); |
220 } | 224 } |
221 EOS | 225 EOS |
222 | 226 |
223 assert_equal "test message\\n", shell_output("#{bin}/dart sample.dart") | 227 assert_equal "test message\\n", shell_output("#{bin}/dart sample.dart") |
224 end | 228 end |
225 end | 229 end |
226 '''; | 230 '''; |
227 } | 231 } |
228 | 232 |
229 Future runGit(List<String> args) { | 233 Future runGit(List<String> args) async { |
230 print("git ${args.join(' ')}"); | 234 print("git ${args.join(' ')}"); |
231 return Process.run('git', args, workingDirectory: repository, | 235 |
232 environment: gitEnvironment) | 236 var result = await Process.run('git', args, |
233 .then((result) { | 237 workingDirectory: repository, environment: gitEnvironment); |
234 print(result.stdout); | 238 |
235 print(result.stderr); | 239 print(result.stdout); |
236 }); | 240 print(result.stderr); |
237 } | 241 } |
238 | 242 |
239 main(args) { | 243 main(args) async { |
240 final parser = new ArgParser() | 244 final parser = new ArgParser() |
241 ..addOption('revision', abbr: 'r') | 245 ..addOption('revision', abbr: 'r') |
242 ..addOption('channel', abbr: 'c', allowed: ['dev', 'stable']) | 246 ..addOption('channel', abbr: 'c', allowed: ['dev', 'stable']) |
243 ..addOption('key', abbr: 'k'); | 247 ..addOption('key', abbr: 'k'); |
244 final options = parser.parse(args); | 248 final options = parser.parse(args); |
245 final revision = options['revision']; | 249 final revision = options['revision']; |
246 final channel = options['channel']; | 250 final channel = options['channel']; |
247 if ([revision, channel, options['key']].contains(null)) { | 251 final key = options['key']; |
| 252 if ([revision, channel, key].contains(null)) { |
248 print("Usage: update_homebrew.dart -r revision -c channel -k ssh_key\n" | 253 print("Usage: update_homebrew.dart -r revision -c channel -k ssh_key\n" |
249 " ssh_key should allow pushes to dart-lang/homebrew-dart on github"); | 254 " ssh_key should allow pushes to ${GITHUB_REPO} on github"); |
250 return; | 255 return; |
251 } | 256 } |
252 final sshWrapper = Platform.script.resolve('ssh_with_key').toFilePath(); | 257 final sshWrapper = Platform.script.resolve('ssh_with_key').toFilePath(); |
253 gitEnvironment = {'GIT_SSH': sshWrapper, | 258 gitEnvironment = {'GIT_SSH': sshWrapper, 'SSH_KEY_PATH': key}; |
254 'SSH_KEY_PATH': options['key']}; | |
255 | 259 |
256 Directory.systemTemp.createTemp('update_homebrew') | 260 Chain.capture(() async { |
257 .then((tempDir) { | 261 var tempDir = await Directory.systemTemp.createTemp('update_homebrew'); |
258 repository = tempDir.path; | 262 |
259 }) | 263 try { |
260 .then((_) => runGit( | 264 repository = tempDir.path; |
261 ['clone', 'git@github.com:dart-lang/homebrew-dart.git', '.'])) | 265 |
262 .then((_) => writeHomebrewInfo(channel, revision)) | 266 await runGit(['clone', 'git@github.com:${GITHUB_REPO}.git', '.']); |
263 .then((_) => runGit(['commit', '-a', '-m', | 267 await writeHomebrewInfo(channel, revision); |
264 'Updated $channel branch to revision $revision'])) | 268 await runGit([ |
265 .then((_) => runGit(['push'])) | 269 'commit', |
266 .whenComplete(() => new Directory(repository).delete(recursive: true)); | 270 '-a', |
| 271 '-m', |
| 272 'Updated $channel branch to revision $revision' |
| 273 ]); |
| 274 |
| 275 await runGit(['push']); |
| 276 } finally { |
| 277 await tempDir.delete(recursive: true); |
| 278 } |
| 279 }, onError: (error, chain) { |
| 280 print(error); |
| 281 print(chain.terse); |
| 282 }); |
267 } | 283 } |
OLD | NEW |