747f79ce1f
BUG= Review URL: https://codereview.chromium.org//11884029 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@17031 260f80e4-7a28-3924-810f-c04153c831b5
226 lines
7.1 KiB
Dart
226 lines
7.1 KiB
Dart
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
/**
|
|
* This file contains functionality for getting dart version numbers using
|
|
* our standard version construction method. Systems that does not include this
|
|
* file should emulate the structure for revision numbers that we have here.
|
|
*
|
|
* The version number of a dart build is constructed as follows:
|
|
* 1. The major, minor, build and patch numbers are extracted from the VERSION
|
|
* file in the root directory. We call these MAJOR, MINOR, BUILD and PATCH.
|
|
* 2. The svn revision number for the current checkout is extracted from the
|
|
* source control system that is used in the current checkout. We call this
|
|
* REVISION.
|
|
* 3. If this is _not_ a official build, i.e., this is not build by our
|
|
* buildbot infrastructure, we extract the user-name of the logged in
|
|
* person from the operating system. We call this USERNAME.
|
|
* 4. The version number is constructed as follows:
|
|
* MAJOR.MINOR.BUILD.PATCH_rREVISION_USERNAME
|
|
*/
|
|
|
|
library version;
|
|
|
|
import "dart:async";
|
|
import "dart:io";
|
|
|
|
/**
|
|
* Generates version information for builds.
|
|
*/
|
|
class Version {
|
|
String _versionFileName;
|
|
String USERNAME;
|
|
int REVISION;
|
|
int MAJOR;
|
|
int MINOR;
|
|
int BUILD;
|
|
int PATCH;
|
|
|
|
Version(Path versionFile) {
|
|
_versionFileName = versionFile.toNativePath();
|
|
}
|
|
|
|
/**
|
|
* Get the version number for this specific build using the version info
|
|
* from the VERSION file in the root directory and the revision info
|
|
* from the source control system of the current checkout.
|
|
*/
|
|
Future<String> getVersion() {
|
|
File f = new File(_versionFileName);
|
|
Completer c = new Completer();
|
|
|
|
var wasCompletedWithError = false;
|
|
completeError(String msg) {
|
|
if (!wasCompletedWithError) {
|
|
c.completeError(msg);
|
|
wasCompletedWithError = true;
|
|
}
|
|
}
|
|
f.exists().then((existed) {
|
|
if (!existed) {
|
|
completeError("No VERSION file");
|
|
return;
|
|
}
|
|
StringInputStream input = new StringInputStream(f.openInputStream());
|
|
input.onLine = () {
|
|
var line = input.readLine().trim();
|
|
if (line == null) {
|
|
completeError(
|
|
"VERSION input file seems to be in the wrong format");
|
|
return;
|
|
}
|
|
var values = line.split(" ");
|
|
if (values.length != 2) {
|
|
completeError(
|
|
"VERSION input file seems to be in the wrong format");
|
|
return;
|
|
}
|
|
var number = 0;
|
|
try {
|
|
number = int.parse(values[1]);
|
|
} catch (e) {
|
|
completeError("Can't parse version numbers, not an int");
|
|
return;
|
|
}
|
|
switch (values[0]) {
|
|
case "MAJOR":
|
|
MAJOR = number;
|
|
break;
|
|
case "MINOR":
|
|
MINOR = number;
|
|
break;
|
|
case "BUILD":
|
|
BUILD = number;
|
|
break;
|
|
case "PATCH":
|
|
PATCH = number;
|
|
break;
|
|
default:
|
|
completeError("Wrong format in VERSION file, line does not "
|
|
"contain one of {MAJOR, MINOR, BUILD, PATCH}");
|
|
return;
|
|
}
|
|
};
|
|
input.onClosed = () {
|
|
// Only complete if we did not already complete with a failure.
|
|
if (!wasCompletedWithError) {
|
|
getRevision().then((revision) {
|
|
REVISION = revision;
|
|
USERNAME = getUserName();
|
|
var userNameString = "";
|
|
if (USERNAME != '') userNameString = "_$USERNAME";
|
|
var revisionString = "";
|
|
if (revision != 0) revisionString = "_r$revision";
|
|
c.complete(
|
|
"$MAJOR.$MINOR.$BUILD.$PATCH$revisionString$userNameString");
|
|
return;
|
|
});
|
|
}
|
|
};
|
|
});
|
|
return c.future;
|
|
}
|
|
|
|
String getExecutableSuffix() {
|
|
if (Platform.operatingSystem == 'windows') {
|
|
return '.bat';
|
|
}
|
|
return '';
|
|
}
|
|
|
|
int getRevisionFromSvnInfo(String info) {
|
|
if (info == null || info == '') return 0;
|
|
var lines = info.split("\n");
|
|
RegExp exp = new RegExp(r"Last Changed Rev: (\d*)");
|
|
for (var line in lines) {
|
|
if (exp.hasMatch(line)) {
|
|
String revisionString = (exp.firstMatch(line).group(1));
|
|
try {
|
|
return int.parse(revisionString);
|
|
} catch(e) {
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
Future<int> getRevision() {
|
|
if (repositoryType == RepositoryType.UNKNOWN) {
|
|
return new Future.immediate(0);
|
|
}
|
|
var isSvn = repositoryType == RepositoryType.SVN;
|
|
var command = isSvn ? "svn" : "git";
|
|
command = "$command${getExecutableSuffix()}";
|
|
var arguments = isSvn ? ["info"] : ["svn", "info"];
|
|
ProcessOptions options = new ProcessOptions();
|
|
// Run the command from the root to get the last changed revision for this
|
|
// "branch". Since we have both trunk and bleeding edge in the same
|
|
// repository and since we always build TOT we need this to get the
|
|
// right version number.
|
|
Path toolsDirectory = new Path(_versionFileName).directoryPath;
|
|
Path root = toolsDirectory.join(new Path(".."));
|
|
options.workingDirectory = root.toNativePath();
|
|
return Process.run(command, arguments, options).then((result) {
|
|
if (result.exitCode != 0) {
|
|
return 0;
|
|
}
|
|
return getRevisionFromSvnInfo(result.stdout);
|
|
});
|
|
}
|
|
|
|
bool isProductionBuild(String username) {
|
|
return username == "chrome-bot";
|
|
}
|
|
|
|
String getUserName() {
|
|
// TODO(ricow): Don't add this on the buildbot.
|
|
var key = "USER";
|
|
if (Platform.operatingSystem == 'windows') {
|
|
key = "USERNAME";
|
|
}
|
|
if (!Platform.environment.containsKey(key)) return "";
|
|
var username = Platform.environment[key];
|
|
// If this is a production build, i.e., this is something we are shipping,
|
|
// don't suffix the version with the username.
|
|
if (isProductionBuild(username)) return "";
|
|
return username;
|
|
}
|
|
|
|
bool isGitRepository() {
|
|
var currentPath = new Path(new Directory.current().path);
|
|
while (!new Directory.fromPath(currentPath.append(".git")).existsSync()) {
|
|
currentPath = currentPath.directoryPath;
|
|
if (currentPath.toString() == "/") {
|
|
break;
|
|
}
|
|
}
|
|
return new Directory.fromPath(currentPath.append(".git")).existsSync();
|
|
}
|
|
|
|
RepositoryType get repositoryType {
|
|
if (new Directory(".svn").existsSync()) return RepositoryType.SVN;
|
|
if (isGitRepository()) return RepositoryType.GIT;
|
|
return RepositoryType.UNKNOWN;
|
|
}
|
|
}
|
|
|
|
class RepositoryType {
|
|
static final RepositoryType SVN = const RepositoryType("SVN");
|
|
static final RepositoryType GIT = const RepositoryType("GIT");
|
|
static final RepositoryType UNKNOWN = const RepositoryType("UNKNOWN");
|
|
|
|
const RepositoryType(String this.name);
|
|
|
|
static RepositoryType guessType() {
|
|
if (new Directory(".svn").existsSync()) return RepositoryType.SVN;
|
|
if (new Directory(".git").existsSync()) return RepositoryType.GIT;
|
|
return RepositoryType.UNKNOWN;
|
|
}
|
|
|
|
String toString() => name;
|
|
|
|
final String name;
|
|
}
|