| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | |
| 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. | |
| 4 | |
| 5 /** | |
| 6 * This file contains functionality for getting dart version numbers using | |
| 7 * our standard version construction method. Systems that does not include this | |
| 8 * file should emulate the structure for revision numbers that we have here. | |
| 9 * | |
| 10 * The version number of a dart build is constructed as follows: | |
| 11 * 1. The major, minor, build and patch numbers are extracted from the VERSION | |
| 12 * file in the root directory. We call these MAJOR, MINOR, BUILD and PATCH. | |
| 13 * 2. The svn revision number for the current checkout is extracted from the | |
| 14 * source control system that is used in the current checkout. We call this | |
| 15 * REVISION. | |
| 16 * 3. If this is _not_ a official build, i.e., this is not build by our | |
| 17 * buildbot infrastructure, we extract the user-name of the logged in | |
| 18 * person from the operating system. We call this USERNAME. | |
| 19 * 4. The version number is constructed as follows: | |
| 20 * MAJOR.MINOR.BUILD.PATCH_rREVISION_USERNAME | |
| 21 */ | |
| 22 | |
| 23 library version; | |
| 24 | |
| 25 import "dart:async"; | |
| 26 import "dart:io"; | |
| 27 | |
| 28 /** | |
| 29 * Generates version information for builds. | |
| 30 */ | |
| 31 class Version { | |
| 32 String _versionFileName; | |
| 33 String USERNAME; | |
| 34 int REVISION; | |
| 35 int MAJOR; | |
| 36 int MINOR; | |
| 37 int BUILD; | |
| 38 int PATCH; | |
| 39 | |
| 40 Version(Path versionFile) { | |
| 41 _versionFileName = versionFile.toNativePath(); | |
| 42 } | |
| 43 | |
| 44 /** | |
| 45 * Get the version number for this specific build using the version info | |
| 46 * from the VERSION file in the root directory and the revision info | |
| 47 * from the source control system of the current checkout. | |
| 48 */ | |
| 49 Future<String> getVersion() { | |
| 50 File f = new File(_versionFileName); | |
| 51 Completer c = new Completer(); | |
| 52 | |
| 53 var wasCompletedWithError = false; | |
| 54 completeError(String msg) { | |
| 55 if (!wasCompletedWithError) { | |
| 56 c.completeError(msg); | |
| 57 wasCompletedWithError = true; | |
| 58 } | |
| 59 } | |
| 60 f.exists().then((existed) { | |
| 61 if (!existed) { | |
| 62 completeError("No VERSION file"); | |
| 63 return; | |
| 64 } | |
| 65 Stream<String> stream = | |
| 66 f.openRead().transform(new StringDecoder()) | |
| 67 .transform(new LineTransformer()); | |
| 68 stream.listen((String line) { | |
| 69 if (line == null) { | |
| 70 completeError( | |
| 71 "VERSION input file seems to be in the wrong format"); | |
| 72 return; | |
| 73 } | |
| 74 var values = line.split(" "); | |
| 75 if (values.length != 2) { | |
| 76 completeError( | |
| 77 "VERSION input file seems to be in the wrong format"); | |
| 78 return; | |
| 79 } | |
| 80 var number = 0; | |
| 81 try { | |
| 82 number = int.parse(values[1]); | |
| 83 } catch (e) { | |
| 84 completeError("Can't parse version numbers, not an int"); | |
| 85 return; | |
| 86 } | |
| 87 switch (values[0]) { | |
| 88 case "MAJOR": | |
| 89 MAJOR = number; | |
| 90 break; | |
| 91 case "MINOR": | |
| 92 MINOR = number; | |
| 93 break; | |
| 94 case "BUILD": | |
| 95 BUILD = number; | |
| 96 break; | |
| 97 case "PATCH": | |
| 98 PATCH = number; | |
| 99 break; | |
| 100 default: | |
| 101 completeError("Wrong format in VERSION file, line does not " | |
| 102 "contain one of {MAJOR, MINOR, BUILD, PATCH}"); | |
| 103 return; | |
| 104 } | |
| 105 }, | |
| 106 onDone: () { | |
| 107 // Only complete if we did not already complete with a failure. | |
| 108 if (!wasCompletedWithError) { | |
| 109 getRevision().then((revision) { | |
| 110 REVISION = revision; | |
| 111 USERNAME = getUserName(); | |
| 112 var userNameString = ""; | |
| 113 if (USERNAME != '') userNameString = "_$USERNAME"; | |
| 114 var revisionString = ""; | |
| 115 if (revision != 0) revisionString = "_r$revision"; | |
| 116 c.complete( | |
| 117 "$MAJOR.$MINOR.$BUILD.$PATCH$revisionString$userNameString"); | |
| 118 return; | |
| 119 }); | |
| 120 } | |
| 121 }); | |
| 122 }); | |
| 123 return c.future; | |
| 124 } | |
| 125 | |
| 126 String getExecutableSuffix() { | |
| 127 if (Platform.operatingSystem == 'windows') { | |
| 128 return '.bat'; | |
| 129 } | |
| 130 return ''; | |
| 131 } | |
| 132 | |
| 133 int getRevisionFromSvnInfo(String info) { | |
| 134 if (info == null || info == '') return 0; | |
| 135 var lines = info.split("\n"); | |
| 136 RegExp exp = new RegExp(r"Last Changed Rev: (\d*)"); | |
| 137 for (var line in lines) { | |
| 138 if (exp.hasMatch(line)) { | |
| 139 String revisionString = (exp.firstMatch(line).group(1)); | |
| 140 try { | |
| 141 return int.parse(revisionString); | |
| 142 } catch(e) { | |
| 143 return 0; | |
| 144 } | |
| 145 } | |
| 146 } | |
| 147 return 0; | |
| 148 } | |
| 149 | |
| 150 Future<int> getRevision() { | |
| 151 if (repositoryType == RepositoryType.UNKNOWN) { | |
| 152 return new Future.value(0); | |
| 153 } | |
| 154 var isSvn = repositoryType == RepositoryType.SVN; | |
| 155 var command = isSvn ? "svn" : "git"; | |
| 156 command = "$command${getExecutableSuffix()}"; | |
| 157 var arguments = isSvn ? ["info"] : ["svn", "info"]; | |
| 158 // Run the command from the root to get the last changed revision for this | |
| 159 // "branch". Since we have both trunk and bleeding edge in the same | |
| 160 // repository and since we always build TOT we need this to get the | |
| 161 // right version number. | |
| 162 Path toolsDirectory = new Path(_versionFileName).directoryPath; | |
| 163 Path root = toolsDirectory.join(new Path("..")); | |
| 164 var workingDirectory = root.toNativePath(); | |
| 165 return Process.run(command, | |
| 166 arguments, | |
| 167 workingDirectory: workingDirectory).then((result) { | |
| 168 if (result.exitCode != 0) { | |
| 169 return 0; | |
| 170 } | |
| 171 return getRevisionFromSvnInfo(result.stdout); | |
| 172 }); | |
| 173 } | |
| 174 | |
| 175 bool isProductionBuild(String username) { | |
| 176 return username == "chrome-bot"; | |
| 177 } | |
| 178 | |
| 179 String getUserName() { | |
| 180 // TODO(ricow): Don't add this on the buildbot. | |
| 181 var key = "USER"; | |
| 182 if (Platform.operatingSystem == 'windows') { | |
| 183 key = "USERNAME"; | |
| 184 } | |
| 185 if (!Platform.environment.containsKey(key)) return ""; | |
| 186 var username = Platform.environment[key]; | |
| 187 // If this is a production build, i.e., this is something we are shipping, | |
| 188 // don't suffix the version with the username. | |
| 189 if (isProductionBuild(username)) return ""; | |
| 190 return username; | |
| 191 } | |
| 192 | |
| 193 RepositoryType get repositoryType { | |
| 194 bool isWindows = Platform.operatingSystem == 'windows'; | |
| 195 bool hasDirectory(path, name) { | |
| 196 return new Directory.fromPath(path.append(name)).existsSync(); | |
| 197 } | |
| 198 bool isFileSystemRoot(absolutePath) { | |
| 199 if (isWindows) { | |
| 200 return "${absolutePath.directoryPath}" == '/'; | |
| 201 } | |
| 202 return "$absolutePath" == '/'; | |
| 203 } | |
| 204 | |
| 205 var currentPath = new Path(Directory.current.path); | |
| 206 while (true) { | |
| 207 if (hasDirectory(currentPath, '.svn')) { | |
| 208 return RepositoryType.SVN; | |
| 209 } else if (hasDirectory(currentPath, '.git')) { | |
| 210 return RepositoryType.GIT; | |
| 211 } | |
| 212 if (isFileSystemRoot(currentPath)) { | |
| 213 break; | |
| 214 } | |
| 215 currentPath = currentPath.directoryPath; | |
| 216 } | |
| 217 return RepositoryType.UNKNOWN; | |
| 218 } | |
| 219 } | |
| 220 | |
| 221 class RepositoryType { | |
| 222 static final RepositoryType SVN = const RepositoryType("SVN"); | |
| 223 static final RepositoryType GIT = const RepositoryType("GIT"); | |
| 224 static final RepositoryType UNKNOWN = const RepositoryType("UNKNOWN"); | |
| 225 | |
| 226 const RepositoryType(String this.name); | |
| 227 | |
| 228 static RepositoryType guessType() { | |
| 229 if (new Directory(".svn").existsSync()) return RepositoryType.SVN; | |
| 230 if (new Directory(".git").existsSync()) return RepositoryType.GIT; | |
| 231 return RepositoryType.UNKNOWN; | |
| 232 } | |
| 233 | |
| 234 String toString() => name; | |
| 235 | |
| 236 final String name; | |
| 237 } | |
| OLD | NEW |