| 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 |