2016-05-24 03:11:09 +02:00
|
|
|
// Copyright 2016 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.
|
|
|
|
|
2020-01-24 22:05:04 +01:00
|
|
|
import 'dart:isolate';
|
|
|
|
|
|
|
|
import 'package:path/path.dart' as p;
|
|
|
|
import 'package:stack_trace/stack_trace.dart';
|
|
|
|
import 'package:term_glyph/term_glyph.dart' as term_glyph;
|
|
|
|
|
|
|
|
import 'package:sass/src/exception.dart';
|
|
|
|
import 'package:sass/src/executable/compile_stylesheet.dart';
|
|
|
|
import 'package:sass/src/executable/options.dart';
|
|
|
|
import 'package:sass/src/executable/repl.dart';
|
|
|
|
import 'package:sass/src/executable/watch.dart';
|
|
|
|
import 'package:sass/src/import_cache.dart';
|
|
|
|
import 'package:sass/src/io.dart';
|
|
|
|
import 'package:sass/src/stylesheet_graph.dart';
|
|
|
|
|
|
|
|
Future<void> main(List<String> args) async {
|
|
|
|
var printedError = false;
|
|
|
|
|
|
|
|
// Prints [error] to stderr, along with a preceding newline if anything else
|
|
|
|
// has been printed to stderr.
|
|
|
|
//
|
|
|
|
// If [trace] is passed, its terse representation is printed after the error.
|
2021-03-17 03:25:39 +01:00
|
|
|
void printError(String error, StackTrace? stackTrace) {
|
2020-01-24 22:05:04 +01:00
|
|
|
if (printedError) stderr.writeln();
|
|
|
|
printedError = true;
|
|
|
|
stderr.writeln(error);
|
|
|
|
|
|
|
|
if (stackTrace != null) {
|
|
|
|
stderr.writeln();
|
|
|
|
stderr.writeln(Trace.from(stackTrace).terse.toString().trimRight());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-17 04:51:32 +01:00
|
|
|
ExecutableOptions? options;
|
2020-01-24 22:05:04 +01:00
|
|
|
try {
|
|
|
|
options = ExecutableOptions.parse(args);
|
|
|
|
term_glyph.ascii = !options.unicode;
|
|
|
|
|
|
|
|
if (options.version) {
|
|
|
|
print(await _loadVersion());
|
|
|
|
exitCode = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (options.interactive) {
|
|
|
|
await repl(options);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
var graph = StylesheetGraph(
|
2021-03-16 23:22:00 +01:00
|
|
|
ImportCache(loadPaths: options.loadPaths, logger: options.logger));
|
2020-01-24 22:05:04 +01:00
|
|
|
if (options.watch) {
|
|
|
|
await watch(options, graph);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (var source in options.sourcesToDestinations.keys) {
|
|
|
|
var destination = options.sourcesToDestinations[source];
|
|
|
|
try {
|
|
|
|
await compileStylesheet(options, graph, source, destination,
|
|
|
|
ifModified: options.update);
|
|
|
|
} on SassException catch (error, stackTrace) {
|
|
|
|
// This is an immediately-invoked function expression to work around
|
|
|
|
// dart-lang/sdk#33400.
|
|
|
|
() {
|
|
|
|
try {
|
2021-03-17 04:51:32 +01:00
|
|
|
if (destination != null &&
|
|
|
|
// dart-lang/sdk#45348
|
|
|
|
!options!.emitErrorCss) {
|
2020-01-24 22:05:04 +01:00
|
|
|
deleteFile(destination);
|
|
|
|
}
|
|
|
|
} on FileSystemException {
|
|
|
|
// If the file doesn't exist, that's fine.
|
|
|
|
}
|
|
|
|
}();
|
|
|
|
|
|
|
|
printError(error.toString(color: options.color),
|
|
|
|
options.trace ? stackTrace : null);
|
|
|
|
|
|
|
|
// Exit code 65 indicates invalid data per
|
|
|
|
// http://www.freebsd.org/cgi/man.cgi?query=sysexits.
|
|
|
|
//
|
|
|
|
// We let exitCode 66 take precedence for deterministic behavior.
|
|
|
|
if (exitCode != 66) exitCode = 65;
|
|
|
|
if (options.stopOnError) return;
|
|
|
|
} on FileSystemException catch (error, stackTrace) {
|
2021-03-19 05:43:02 +01:00
|
|
|
var path = error.path;
|
|
|
|
printError(
|
|
|
|
path == null
|
|
|
|
? error.message
|
|
|
|
: "Error reading ${p.relative(path)}: ${error.message}.",
|
2020-01-24 22:05:04 +01:00
|
|
|
options.trace ? stackTrace : null);
|
|
|
|
|
|
|
|
// Error 66 indicates no input.
|
|
|
|
exitCode = 66;
|
|
|
|
if (options.stopOnError) return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} on UsageException catch (error) {
|
|
|
|
print("${error.message}\n");
|
|
|
|
print("Usage: sass <input.scss> [output.css]\n"
|
|
|
|
" sass <input.scss>:<output.css> <input/>:<output/> <dir/>\n");
|
|
|
|
print(ExecutableOptions.usage);
|
|
|
|
exitCode = 64;
|
|
|
|
} catch (error, stackTrace) {
|
|
|
|
var buffer = StringBuffer();
|
|
|
|
if (options != null && options.color) buffer.write('\u001b[31m\u001b[1m');
|
|
|
|
buffer.write('Unexpected exception:');
|
|
|
|
if (options != null && options.color) buffer.write('\u001b[0m');
|
|
|
|
buffer.writeln();
|
|
|
|
buffer.writeln(error);
|
|
|
|
|
|
|
|
printError(buffer.toString(), stackTrace);
|
|
|
|
exitCode = 255;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Loads and returns the current version of Sass.
|
|
|
|
Future<String> _loadVersion() async {
|
2021-03-10 02:04:09 +01:00
|
|
|
if (bool.hasEnvironment('version')) {
|
|
|
|
var version = const String.fromEnvironment('version');
|
|
|
|
if (const bool.fromEnvironment('node')) {
|
|
|
|
version += " compiled with dart2js "
|
|
|
|
"${const String.fromEnvironment('dart-version')}";
|
|
|
|
}
|
|
|
|
return version;
|
2020-01-24 22:05:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
var libDir =
|
|
|
|
p.fromUri(await Isolate.resolvePackageUri(Uri.parse('package:sass/')));
|
|
|
|
var pubspec = readFile(p.join(libDir, '..', 'pubspec.yaml'));
|
|
|
|
return pubspec
|
|
|
|
.split("\n")
|
|
|
|
.firstWhere((line) => line.startsWith('version: '))
|
|
|
|
.split(" ")
|
|
|
|
.last;
|
|
|
|
}
|