diff --git a/.travis.yml b/.travis.yml index 1a67397b7..d4255de8e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -61,6 +61,8 @@ install: - if-specs git -C sass-spec checkout FETCH_HEAD - if-specs bundle install --gemfile=sass-spec/Gemfile --jobs=3 --retry=3 +- if [ "$TASK" = tests ]; then pub run grinder app-snapshot; fi + script: tool/travis/test.sh ## Deployment diff --git a/appveyor.yml b/appveyor.yml index 00458976e..1c7dc8df2 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -19,6 +19,10 @@ install: Install-Product node '' pub run grinder npm-package } +- ps: >- + If ($env:NODE -eq "false") { + pub run grinder app-snapshot + } # Run this as CMD because npm's stderr will cause PowerShell to think it failed. - IF "%NODE%"=="true" npm install diff --git a/test/cli/dart/colon_args_test.dart b/test/cli/dart/colon_args_test.dart index f1c1956f8..6a8da9f78 100644 --- a/test/cli/dart/colon_args_test.dart +++ b/test/cli/dart/colon_args_test.dart @@ -10,5 +10,6 @@ import '../dart_test.dart'; import '../shared/colon_args.dart'; void main() { + setUpAll(ensureSnapshotUpToDate); sharedTests(runSass); } diff --git a/test/cli/dart/errors_test.dart b/test/cli/dart/errors_test.dart index 008389667..db672602e 100644 --- a/test/cli/dart/errors_test.dart +++ b/test/cli/dart/errors_test.dart @@ -10,5 +10,6 @@ import '../dart_test.dart'; import '../shared/errors.dart'; void main() { + setUpAll(ensureSnapshotUpToDate); sharedTests(runSass); } diff --git a/test/cli/dart/repl_test.dart b/test/cli/dart/repl_test.dart index f0485e334..d19641e14 100644 --- a/test/cli/dart/repl_test.dart +++ b/test/cli/dart/repl_test.dart @@ -10,5 +10,6 @@ import '../dart_test.dart'; import '../shared/repl.dart'; void main() { + setUpAll(ensureSnapshotUpToDate); sharedTests(runSass); } diff --git a/test/cli/dart/source_maps_test.dart b/test/cli/dart/source_maps_test.dart index d0c2dcd85..133bf719d 100644 --- a/test/cli/dart/source_maps_test.dart +++ b/test/cli/dart/source_maps_test.dart @@ -10,5 +10,6 @@ import '../dart_test.dart'; import '../shared/source_maps.dart'; void main() { + setUpAll(ensureSnapshotUpToDate); sharedTests(runSass); } diff --git a/test/cli/dart/update_test.dart b/test/cli/dart/update_test.dart index 78a2aa6d4..2c83e827c 100644 --- a/test/cli/dart/update_test.dart +++ b/test/cli/dart/update_test.dart @@ -10,5 +10,6 @@ import '../dart_test.dart'; import '../shared/update.dart'; void main() { + setUpAll(ensureSnapshotUpToDate); sharedTests(runSass); } diff --git a/test/cli/dart/watch_test.dart b/test/cli/dart/watch_test.dart index 418aea78a..aff5a4c6f 100644 --- a/test/cli/dart/watch_test.dart +++ b/test/cli/dart/watch_test.dart @@ -10,5 +10,6 @@ import '../dart_test.dart'; import '../shared/watch.dart'; void main() { + setUpAll(ensureSnapshotUpToDate); sharedTests(runSass); } diff --git a/test/cli/dart_test.dart b/test/cli/dart_test.dart index b673dc83e..e9d011836 100644 --- a/test/cli/dart_test.dart +++ b/test/cli/dart_test.dart @@ -12,9 +12,19 @@ import 'package:test/test.dart'; import 'package:test_descriptor/test_descriptor.dart' as d; import 'package:test_process/test_process.dart'; +import '../io.dart'; import 'shared.dart'; +/// Paths where snapshots of the Sass binary might exist, in order of +/// preference. +final _snapshotPaths = [ + p.absolute("build/sass.dart.app.snapshot"), + p.absolute("build/sass.dart.snapshot") +]; + void main() { + setUpAll(ensureSnapshotUpToDate); + sharedTests(runSass); test("--version prints the Sass version", () async { @@ -24,8 +34,32 @@ void main() { }); } -Future runSass(Iterable arguments) => TestProcess.start( - Platform.executable, - ["--checked", p.absolute("bin/sass.dart")]..addAll(arguments), - workingDirectory: d.sandbox, - description: "sass"); +/// Ensures that the snapshot of the Dart executable used by [runSass] is +/// up-to-date, if one has been generated. +void ensureSnapshotUpToDate() { + for (var path in _snapshotPaths) { + if (new File(path).existsSync()) { + ensureUpToDate(path, "pub run grinder app-snapshot"); + return; + } + } +} + +Future runSass(Iterable arguments) { + var executable = _snapshotPaths.firstWhere( + (path) => new File(path).existsSync(), + orElse: () => p.absolute("bin/sass.dart")); + + var args = ["--checked"]; + + // Work around dart-lang/sdk#33622. + if (Platform.isWindows) args.add("--packages=${p.absolute('.packages')}"); + + return TestProcess.start( + Platform.executable, + args + ..add(executable) + ..addAll(arguments), + workingDirectory: d.sandbox, + description: "sass"); +} diff --git a/test/ensure_npm_package.dart b/test/ensure_npm_package.dart index e8c5e8e01..3b2ae6d4d 100644 --- a/test/ensure_npm_package.dart +++ b/test/ensure_npm_package.dart @@ -3,42 +3,16 @@ // https://opensource.org/licenses/MIT. import 'dart:async'; -import 'dart:io'; import 'package:stream_channel/stream_channel.dart'; import 'package:test/test.dart'; import 'package:sass/src/io.dart'; -hybridMain(StreamChannel channel) async { - if (!new Directory("build/npm").existsSync()) { - throw "NPM package is not built. Run pub run grinder npm-package."; - } - - var lastModified = new File("build/npm/package.json").lastModifiedSync(); - var entriesToCheck = new Directory("lib").listSync(recursive: true).toList(); - - // If we have a dependency override, "pub run" will touch the lockfile to mark - // it as newer than the pubspec, which makes it unsuitable to use for - // freshness checking. - if (new File("pubspec.yaml") - .readAsStringSync() - .contains("dependency_overrides")) { - entriesToCheck.add(new File("pubspec.yaml")); - } else { - entriesToCheck.add(new File("pubspec.lock")); - } - - for (var entry in entriesToCheck) { - if (entry is File) { - var entryLastModified = entry.lastModifiedSync(); - if (lastModified.isBefore(entryLastModified)) { - throw "${entry.path} was modified after NPM package was generated.\n" - "Run pub run grinder before-test."; - } - } - } +import 'io.dart'; +hybridMain(StreamChannel channel) async { + ensureUpToDate("build/npm/sass.dart.js", "pub run grinder npm-package"); channel.sink.close(); } diff --git a/test/io.dart b/test/io.dart new file mode 100644 index 000000000..855cd2d62 --- /dev/null +++ b/test/io.dart @@ -0,0 +1,45 @@ +// Copyright 2018 Google Inc. Use of this source code is governed by an +// MIT-style license that can be found in the LICENSE file or at +// https://opensource.org/licenses/MIT. + +import 'dart:io'; + +import 'package:path/path.dart' as p; + +/// Ensures that [path] (usually a compilation artifact) has been modified more +/// recently than all this package's source files. +/// +/// If [path] isn't up-to-date, this throws an error encouraging the user to run +/// [commandToRun]. +void ensureUpToDate(String path, String commandToRun) { + // Ensure path is relative so the error messages are more readable. + path = p.relative(path); + if (!new File(path).existsSync()) { + throw "$path does not exist. Run $commandToRun."; + } + + var lastModified = new File(path).lastModifiedSync(); + var entriesToCheck = new Directory("lib").listSync(recursive: true).toList(); + + // If we have a dependency override, "pub run" will touch the lockfile to mark + // it as newer than the pubspec, which makes it unsuitable to use for + // freshness checking. + if (new File("pubspec.yaml") + .readAsStringSync() + .contains("dependency_overrides")) { + entriesToCheck.add(new File("pubspec.yaml")); + } else { + entriesToCheck.add(new File("pubspec.lock")); + } + + for (var entry in entriesToCheck) { + if (entry is File) { + var entryLastModified = entry.lastModifiedSync(); + if (lastModified.isBefore(entryLastModified)) { + throw "${entry.path} was modified after ${p.prettyUri(p.toUri(path))} " + "was generated.\n" + "Run pub run grinder before_test."; + } + } + } +} diff --git a/tool/grind/benchmark.dart b/tool/grind/benchmark.dart index a53a86423..bb4fee8c0 100644 --- a/tool/grind/benchmark.dart +++ b/tool/grind/benchmark.dart @@ -13,7 +13,7 @@ import 'standalone.dart'; import 'utils.dart'; @Task('Run benchmarks for Sass compilation speed.') -@Depends(snapshot, appSnapshot, npmPackage) +@Depends(snapshot, releaseAppSnapshot, npmPackage) benchmark() async { var libsass = await cloneOrPull('https://github.com/sass/libsass'); var sassc = await cloneOrPull('https://github.com/sass/sassc'); diff --git a/tool/grind/standalone.dart b/tool/grind/standalone.dart index 54a5ef326..e7d6409a7 100644 --- a/tool/grind/standalone.dart +++ b/tool/grind/standalone.dart @@ -7,6 +7,7 @@ import 'dart:io'; import 'package:archive/archive.dart'; import 'package:grinder/grinder.dart'; +import 'package:meta/meta.dart'; import 'package:path/path.dart' as p; import 'package:http/http.dart' as http; @@ -21,20 +22,32 @@ snapshot() { Dart.run('bin/sass.dart', vmArgs: ['--snapshot=build/sass.dart.snapshot']); } -@Task('Build Dart application snapshot.') -appSnapshot() { +@Task('Build a dev-mode Dart application snapshot.') +appSnapshot() => _appSnapshot(release: false); + +@Task('Build a release-mode Dart application snapshot.') +releaseAppSnapshot() => _appSnapshot(release: true); + +/// Compiles Sass to an application snapshot. +/// +/// If [release] is `true`, this compiles in checked mode. Otherwise, it +/// compiles in unchecked mode. +void _appSnapshot({@required bool release}) { + var args = [ + '--snapshot=build/sass.dart.app.snapshot', + '--snapshot-kind=app-jit' + ]; + // TODO(nweiz): Once we're building with Dart 2 runtime semantics, pass a flag + // to enable assertions rather than a flag to enable checked mode. + if (!release) args..add('--checked'); + ensureBuild(); Dart.run('bin/sass.dart', - arguments: ['tool/app-snapshot-input.scss'], - vmArgs: [ - '--snapshot=build/sass.dart.app.snapshot', - '--snapshot-kind=app-jit' - ], - quiet: true); + arguments: ['tool/app-snapshot-input.scss'], vmArgs: args, quiet: true); } @Task('Build standalone packages for all OSes.') -@Depends(snapshot, appSnapshot) +@Depends(snapshot, releaseAppSnapshot) package() async { var client = new http.Client(); await Future.wait(["linux", "macos", "windows"].expand((os) => [