In-line the package:stagehand templates into 'dart create'.
Change-Id: I717f0970314700b123b750fcfe7ed066ba88d2e5 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/192944 Commit-Queue: Devon Carew <devoncarew@google.com> Reviewed-by: Ben Konyi <bkonyi@google.com>
This commit is contained in:
committed by
commit-bot@chromium.org
parent
e9d7ad78e4
commit
f6ce7a829f
@@ -11,7 +11,7 @@
|
||||
"constraint, update this by running tools/generate_package_config.dart."
|
||||
],
|
||||
"configVersion": 2,
|
||||
"generated": "2021-03-24T12:15:31.538873",
|
||||
"generated": "2021-03-24T13:42:28.071470",
|
||||
"generator": "tools/generate_package_config.dart",
|
||||
"packages": [
|
||||
{
|
||||
@@ -637,12 +637,6 @@
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "2.12"
|
||||
},
|
||||
{
|
||||
"name": "stagehand",
|
||||
"rootUri": "../third_party/pkg/stagehand",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "2.10"
|
||||
},
|
||||
{
|
||||
"name": "status_file",
|
||||
"rootUri": "../pkg/status_file",
|
||||
|
||||
@@ -95,7 +95,6 @@ source_maps:third_party/pkg/source_maps/lib
|
||||
source_span:third_party/pkg/source_span/lib
|
||||
sse:third_party/pkg/sse/lib
|
||||
stack_trace:third_party/pkg/stack_trace/lib
|
||||
stagehand:third_party/pkg/stagehand/lib
|
||||
status_file:pkg/status_file/lib
|
||||
stream_channel:third_party/pkg/stream_channel/lib
|
||||
string_scanner:third_party/pkg/string_scanner/lib
|
||||
|
||||
@@ -152,7 +152,6 @@ vars = {
|
||||
"source_span_rev": "1be3c44045a06dff840d2ed3a13e6082d7a03a23",
|
||||
"sse_tag": "5da8fedcdc56f306933d202e2d204753eecefd36",
|
||||
"stack_trace_tag": "6788afc61875079b71b3d1c3e65aeaa6a25cbc2f",
|
||||
"stagehand_rev": "e64ac90cac508981011299c4ceb819149e71f1bd",
|
||||
"stream_channel_tag": "d7251e61253ec389ee6e045ee1042311bced8f1d",
|
||||
"string_scanner_rev": "1b63e6e5db5933d7be0a45da6e1129fe00262734",
|
||||
"sync_http_rev": "b59c134f2e34d12acac110d4f17f83e5a7db4330",
|
||||
@@ -430,8 +429,6 @@ deps = {
|
||||
Var("dart_git") + "sse.git" + "@" + Var("sse_tag"),
|
||||
Var("dart_root") + "/third_party/pkg/stack_trace":
|
||||
Var("dart_git") + "stack_trace.git" + "@" + Var("stack_trace_tag"),
|
||||
Var("dart_root") + "/third_party/pkg/stagehand":
|
||||
Var("dart_git") + "stagehand.git" + "@" + Var("stagehand_rev"),
|
||||
Var("dart_root") + "/third_party/pkg/stream_channel":
|
||||
Var("dart_git") + "stream_channel.git" +
|
||||
"@" + Var("stream_channel_tag"),
|
||||
|
||||
@@ -8,10 +8,10 @@ import 'dart:io' as io;
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:stagehand/stagehand.dart' as stagehand;
|
||||
|
||||
import '../core.dart';
|
||||
import '../sdk.dart';
|
||||
import '../templates.dart';
|
||||
|
||||
/// A command to create a new project from a set of templates.
|
||||
class CreateCommand extends DartdevCommand {
|
||||
@@ -19,18 +19,8 @@ class CreateCommand extends DartdevCommand {
|
||||
|
||||
static String defaultTemplateId = 'console-simple';
|
||||
|
||||
static List<String> legalTemplateIds = [
|
||||
'console-simple',
|
||||
'console-full',
|
||||
'package-simple',
|
||||
'web-simple'
|
||||
];
|
||||
|
||||
static Iterable<stagehand.Generator> get generators =>
|
||||
legalTemplateIds.map(retrieveTemplateGenerator);
|
||||
|
||||
static stagehand.Generator retrieveTemplateGenerator(String templateId) =>
|
||||
stagehand.getGenerator(templateId);
|
||||
static final List<String> legalTemplateIds =
|
||||
generators.map((generator) => generator.id).toList();
|
||||
|
||||
CreateCommand({bool verbose = false})
|
||||
: super(cmdName, 'Create a new Dart project.') {
|
||||
@@ -91,8 +81,8 @@ class CreateCommand extends DartdevCommand {
|
||||
);
|
||||
log.stdout('');
|
||||
|
||||
var generator = retrieveTemplateGenerator(templateId);
|
||||
await generator.generate(
|
||||
var generator = getGenerator(templateId);
|
||||
generator.generate(
|
||||
p.basename(dir),
|
||||
DirectoryGeneratorTarget(generator, io.Directory(dir)),
|
||||
);
|
||||
@@ -151,7 +141,7 @@ class CreateCommand extends DartdevCommand {
|
||||
}
|
||||
|
||||
String _availableTemplatesJson() {
|
||||
var items = generators.map((stagehand.Generator generator) {
|
||||
var items = generators.map((Generator generator) {
|
||||
var m = {
|
||||
'name': generator.id,
|
||||
'label': generator.label,
|
||||
@@ -171,8 +161,8 @@ class CreateCommand extends DartdevCommand {
|
||||
}
|
||||
}
|
||||
|
||||
class DirectoryGeneratorTarget extends stagehand.GeneratorTarget {
|
||||
final stagehand.Generator generator;
|
||||
class DirectoryGeneratorTarget extends GeneratorTarget {
|
||||
final Generator generator;
|
||||
final io.Directory dir;
|
||||
|
||||
DirectoryGeneratorTarget(this.generator, this.dir) {
|
||||
@@ -180,13 +170,13 @@ class DirectoryGeneratorTarget extends stagehand.GeneratorTarget {
|
||||
}
|
||||
|
||||
@override
|
||||
Future createFile(String path, List<int> contents) async {
|
||||
void createFile(String path, List<int> contents) {
|
||||
io.File file = io.File(p.join(dir.path, path));
|
||||
|
||||
String name = p.relative(file.path, from: dir.path);
|
||||
log.stdout(' $name');
|
||||
|
||||
await file.create(recursive: true);
|
||||
await file.writeAsBytes(contents);
|
||||
file.createSync(recursive: true);
|
||||
file.writeAsBytesSync(contents);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
// Copyright (c) 2021, 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.
|
||||
|
||||
import 'dart:convert' show utf8;
|
||||
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
import 'templates/console_full.dart';
|
||||
import 'templates/console_simple.dart';
|
||||
import 'templates/package_simple.dart';
|
||||
import 'templates/server_simple.dart';
|
||||
import 'templates/web_simple.dart';
|
||||
|
||||
final _substituteRegExp = RegExp(r'__([a-zA-Z]+)__');
|
||||
final _nonValidSubstituteRegExp = RegExp('[^a-zA-Z]');
|
||||
|
||||
final List<Generator> generators = [
|
||||
ConsoleSimpleGenerator(),
|
||||
ConsoleFullGenerator(),
|
||||
PackageSimpleGenerator(),
|
||||
ServerSimpleGenerator(),
|
||||
WebSimpleGenerator(),
|
||||
];
|
||||
|
||||
Generator getGenerator(String id) =>
|
||||
generators.firstWhere((g) => g.id == id, orElse: () => null);
|
||||
|
||||
/// An abstract class which both defines a template generator and can generate a
|
||||
/// user project based on this template.
|
||||
abstract class Generator implements Comparable<Generator> {
|
||||
final String id;
|
||||
final String label;
|
||||
final String description;
|
||||
final List<String> categories;
|
||||
|
||||
final List<TemplateFile> files = [];
|
||||
TemplateFile _entrypoint;
|
||||
|
||||
Generator(
|
||||
this.id,
|
||||
this.label,
|
||||
this.description, {
|
||||
this.categories = const [],
|
||||
});
|
||||
|
||||
/// The entrypoint of the application; the main file for the project, which an
|
||||
/// IDE might open after creating the project.
|
||||
TemplateFile get entrypoint => _entrypoint;
|
||||
|
||||
TemplateFile addFile(String path, String contents) {
|
||||
return addTemplateFile(TemplateFile(path, contents));
|
||||
}
|
||||
|
||||
/// Add a new template file.
|
||||
TemplateFile addTemplateFile(TemplateFile file) {
|
||||
files.add(file);
|
||||
return file;
|
||||
}
|
||||
|
||||
/// Return the template file wih the given [path].
|
||||
TemplateFile getFile(String path) =>
|
||||
files.firstWhere((file) => file.path == path, orElse: () => null);
|
||||
|
||||
/// Set the main entrypoint of this template. This is the 'most important'
|
||||
/// file of this template. An IDE might use this information to open this file
|
||||
/// after the user's project is generated.
|
||||
void setEntrypoint(TemplateFile entrypoint) {
|
||||
if (_entrypoint != null) throw StateError('entrypoint already set');
|
||||
if (entrypoint == null) throw StateError('entrypoint is null');
|
||||
_entrypoint = entrypoint;
|
||||
}
|
||||
|
||||
void generate(
|
||||
String projectName,
|
||||
GeneratorTarget target, {
|
||||
Map<String, String> additionalVars,
|
||||
}) {
|
||||
final vars = {
|
||||
'projectName': projectName,
|
||||
'description': description,
|
||||
'year': DateTime.now().year.toString(),
|
||||
'author': '<your name>',
|
||||
if (additionalVars != null) ...additionalVars,
|
||||
};
|
||||
|
||||
for (TemplateFile file in files) {
|
||||
final resultFile = file.runSubstitution(vars);
|
||||
final filePath = resultFile.path;
|
||||
target.createFile(filePath, resultFile.content);
|
||||
}
|
||||
}
|
||||
|
||||
int numFiles() => files.length;
|
||||
|
||||
@override
|
||||
int compareTo(Generator other) =>
|
||||
id.toLowerCase().compareTo(other.id.toLowerCase());
|
||||
|
||||
/// Return some user facing instructions about how to finish installation of
|
||||
/// the template.
|
||||
String getInstallInstructions() => '';
|
||||
|
||||
@override
|
||||
String toString() => '[$id: $description]';
|
||||
}
|
||||
|
||||
/// An abstract implementation of a [Generator].
|
||||
abstract class DefaultGenerator extends Generator {
|
||||
DefaultGenerator(
|
||||
String id,
|
||||
String label,
|
||||
String description, {
|
||||
List<String> categories = const [],
|
||||
}) : super(id, label, description, categories: categories);
|
||||
}
|
||||
|
||||
/// A target for a [Generator]. This class knows how to create files given a
|
||||
/// path for the file (relative to the particular [GeneratorTarget] instance),
|
||||
/// and the binary content for the file.
|
||||
abstract class GeneratorTarget {
|
||||
/// Create a file at the given path with the given contents.
|
||||
void createFile(String path, List<int> contents);
|
||||
}
|
||||
|
||||
/// This class represents a file in a generator template. The contents could
|
||||
/// either be binary or text. If text, the contents may contain mustache
|
||||
/// variables that can be substituted (`__myVar__`).
|
||||
class TemplateFile {
|
||||
final String path;
|
||||
final String content;
|
||||
|
||||
TemplateFile(this.path, this.content);
|
||||
|
||||
FileContents runSubstitution(Map<String, String> parameters) {
|
||||
if (path == 'pubspec.yaml' && parameters['author'] == '<your name>') {
|
||||
parameters = Map.from(parameters);
|
||||
parameters['author'] = 'Your Name';
|
||||
}
|
||||
|
||||
final newPath = substituteVars(path, parameters);
|
||||
final newContents = _createContent(parameters);
|
||||
|
||||
return FileContents(newPath, newContents);
|
||||
}
|
||||
|
||||
List<int> _createContent(Map<String, String> vars) {
|
||||
return utf8.encode(substituteVars(content, vars));
|
||||
}
|
||||
}
|
||||
|
||||
class FileContents {
|
||||
final String path;
|
||||
final List<int> content;
|
||||
|
||||
FileContents(this.path, this.content);
|
||||
}
|
||||
|
||||
/// Given a `String` [str] with mustache templates, and a [Map] of String key /
|
||||
/// value pairs, substitute all instances of `__key__` for `value`. I.e.,
|
||||
///
|
||||
/// ```
|
||||
/// Foo __projectName__ baz.
|
||||
/// ```
|
||||
///
|
||||
/// and
|
||||
///
|
||||
/// ```
|
||||
/// {'projectName': 'bar'}
|
||||
/// ```
|
||||
///
|
||||
/// becomes:
|
||||
///
|
||||
/// ```
|
||||
/// Foo bar baz.
|
||||
/// ```
|
||||
///
|
||||
/// A key value can only be an ASCII string made up of letters: A-Z, a-z.
|
||||
/// No whitespace, numbers, or other characters are allowed.
|
||||
@visibleForTesting
|
||||
String substituteVars(String str, Map<String, String> vars) {
|
||||
if (vars.keys.any((element) => element.contains(_nonValidSubstituteRegExp))) {
|
||||
throw ArgumentError('vars.keys can only contain letters.');
|
||||
}
|
||||
|
||||
return str.replaceAllMapped(_substituteRegExp, (match) {
|
||||
final item = vars[match[1]];
|
||||
|
||||
if (item == null) {
|
||||
return match[0];
|
||||
} else {
|
||||
return item;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
// Copyright (c) 2021, 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.
|
||||
|
||||
final String gitignore = '''
|
||||
# Files and directories created by pub.
|
||||
.dart_tool/
|
||||
.packages
|
||||
|
||||
# Conventional directory for build output.
|
||||
build/
|
||||
''';
|
||||
|
||||
final String analysisOptions = '''
|
||||
# Defines a default set of lint rules enforced for projects at Google. For
|
||||
# details and rationale, see
|
||||
# https://github.com/dart-lang/pedantic#enabled-lints.
|
||||
|
||||
include: package:pedantic/analysis_options.yaml
|
||||
|
||||
# For lint rules and documentation, see http://dart-lang.github.io/linter/lints.
|
||||
|
||||
# Uncomment to specify additional rules.
|
||||
# linter:
|
||||
# rules:
|
||||
# - camel_case_types
|
||||
|
||||
# analyzer:
|
||||
# exclude:
|
||||
# - path/to/excluded/files/**
|
||||
''';
|
||||
|
||||
final String changelog = '''
|
||||
## 1.0.0
|
||||
|
||||
- Initial version.
|
||||
''';
|
||||
@@ -0,0 +1,76 @@
|
||||
// Copyright (c) 2021, 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.
|
||||
|
||||
import '../templates.dart';
|
||||
import 'common.dart' as common;
|
||||
|
||||
/// A generator for a hello world command-line application.
|
||||
class ConsoleFullGenerator extends DefaultGenerator {
|
||||
ConsoleFullGenerator()
|
||||
: super('console-full', 'Console Application',
|
||||
'A command-line application sample.',
|
||||
categories: const ['dart', 'console']) {
|
||||
addFile('.gitignore', common.gitignore);
|
||||
addFile('analysis_options.yaml', common.analysisOptions);
|
||||
addFile('CHANGELOG.md', common.changelog);
|
||||
addFile('pubspec.yaml', _pubspec);
|
||||
addFile('README.md', _readme);
|
||||
setEntrypoint(
|
||||
addFile('bin/__projectName__.dart', _mainDart),
|
||||
);
|
||||
addFile('lib/__projectName__.dart', _libDart);
|
||||
addFile('test/__projectName___test.dart', _testDart);
|
||||
}
|
||||
|
||||
@override
|
||||
String getInstallInstructions() => '${super.getInstallInstructions()}\n'
|
||||
'run your app using `dart ${entrypoint.path}`.';
|
||||
}
|
||||
|
||||
final String _pubspec = '''
|
||||
name: __projectName__
|
||||
description: A sample command-line application.
|
||||
version: 1.0.0
|
||||
# homepage: https://www.example.com
|
||||
|
||||
environment:
|
||||
sdk: '>=2.12.0 <3.0.0'
|
||||
|
||||
# dependencies:
|
||||
# path: ^1.8.0
|
||||
|
||||
dev_dependencies:
|
||||
pedantic: ^1.10.0
|
||||
test: ^1.16.0
|
||||
''';
|
||||
|
||||
final String _readme = '''
|
||||
A sample command-line application with an entrypoint in `bin/`, library code
|
||||
in `lib/`, and example unit test in `test/`.
|
||||
''';
|
||||
|
||||
final String _mainDart = r'''
|
||||
import 'package:__projectName__/__projectName__.dart' as __projectName__;
|
||||
|
||||
void main(List<String> arguments) {
|
||||
print('Hello world: ${__projectName__.calculate()}!');
|
||||
}
|
||||
''';
|
||||
|
||||
final String _libDart = '''
|
||||
int calculate() {
|
||||
return 6 * 7;
|
||||
}
|
||||
''';
|
||||
|
||||
final String _testDart = '''
|
||||
import 'package:__projectName__/__projectName__.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
test('calculate', () {
|
||||
expect(calculate(), 42);
|
||||
});
|
||||
}
|
||||
''';
|
||||
@@ -0,0 +1,53 @@
|
||||
// Copyright (c) 2021, 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.
|
||||
|
||||
import '../templates.dart';
|
||||
import 'common.dart' as common;
|
||||
|
||||
/// A generator for a simple command-line application.
|
||||
class ConsoleSimpleGenerator extends DefaultGenerator {
|
||||
ConsoleSimpleGenerator()
|
||||
: super('console-simple', 'Simple Console Application',
|
||||
'A simple command-line application.',
|
||||
categories: const ['dart', 'console']) {
|
||||
addFile('.gitignore', common.gitignore);
|
||||
addFile('analysis_options.yaml', common.analysisOptions);
|
||||
addFile('CHANGELOG.md', common.changelog);
|
||||
addFile('pubspec.yaml', _pubspec);
|
||||
addFile('README.md', _readme);
|
||||
setEntrypoint(
|
||||
addFile('bin/__projectName__.dart', main),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String getInstallInstructions() => '${super.getInstallInstructions()}\n'
|
||||
'run your app using `dart ${entrypoint.path}`.';
|
||||
}
|
||||
|
||||
final String _pubspec = '''
|
||||
name: __projectName__
|
||||
description: A simple command-line application.
|
||||
version: 1.0.0
|
||||
# homepage: https://www.example.com
|
||||
|
||||
environment:
|
||||
sdk: '>=2.12.0 <3.0.0'
|
||||
|
||||
# dependencies:
|
||||
# path: ^1.8.0
|
||||
|
||||
dev_dependencies:
|
||||
pedantic: ^1.10.0
|
||||
''';
|
||||
|
||||
final String _readme = '''
|
||||
A simple command-line application.
|
||||
''';
|
||||
|
||||
final String main = '''
|
||||
void main(List<String> arguments) {
|
||||
print('Hello world!');
|
||||
}
|
||||
''';
|
||||
@@ -0,0 +1,130 @@
|
||||
// Copyright (c) 2021, 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.
|
||||
|
||||
import '../templates.dart';
|
||||
import 'common.dart' as common;
|
||||
|
||||
/// A generator for a simple command-line application.
|
||||
class PackageSimpleGenerator extends DefaultGenerator {
|
||||
PackageSimpleGenerator()
|
||||
: super('package-simple', 'Dart Package',
|
||||
'A starting point for Dart libraries or applications.',
|
||||
categories: const ['dart']) {
|
||||
addFile('.gitignore', _gitignore);
|
||||
addFile('analysis_options.yaml', common.analysisOptions);
|
||||
addFile('CHANGELOG.md', common.changelog);
|
||||
addFile('pubspec.yaml', _pubspec);
|
||||
addFile('README.md', _readme);
|
||||
addFile('example/__projectName___example.dart', _exampleDart);
|
||||
setEntrypoint(
|
||||
addFile('lib/__projectName__.dart', _libDart),
|
||||
);
|
||||
addFile('lib/src/__projectName___base.dart', _libSrcDart);
|
||||
addFile('test/__projectName___test.dart', _testDart);
|
||||
}
|
||||
|
||||
@override
|
||||
String getInstallInstructions() => '${super.getInstallInstructions()}\n'
|
||||
'run your app using `dart ${entrypoint.path}`.';
|
||||
}
|
||||
|
||||
final String _gitignore = '''
|
||||
# Files and directories created by pub.
|
||||
.dart_tool/
|
||||
.packages
|
||||
|
||||
# Conventional directory for build outputs.
|
||||
build/
|
||||
|
||||
# Omit committing pubspec.lock for library packages; see
|
||||
# https://dart.dev/guides/libraries/private-files#pubspeclock.
|
||||
pubspec.lock
|
||||
''';
|
||||
|
||||
final String _pubspec = '''
|
||||
name: __projectName__
|
||||
description: A starting point for Dart libraries or applications.
|
||||
version: 1.0.0
|
||||
# homepage: https://www.example.com
|
||||
|
||||
environment:
|
||||
sdk: '>=2.12.0 <3.0.0'
|
||||
|
||||
# dependencies:
|
||||
# path: ^1.8.0
|
||||
|
||||
dev_dependencies:
|
||||
pedantic: ^1.10.0
|
||||
test: ^1.16.0
|
||||
''';
|
||||
|
||||
final String _readme = '''
|
||||
A library for Dart developers.
|
||||
|
||||
## Usage
|
||||
|
||||
A simple usage example:
|
||||
|
||||
```dart
|
||||
import 'package:__projectName__/__projectName__.dart';
|
||||
|
||||
main() {
|
||||
var awesome = new Awesome();
|
||||
}
|
||||
```
|
||||
|
||||
## Features and bugs
|
||||
|
||||
Please file feature requests and bugs at the [issue tracker][tracker].
|
||||
|
||||
[tracker]: http://example.com/issues/replaceme
|
||||
''';
|
||||
|
||||
final String _exampleDart = r'''
|
||||
import 'package:__projectName__/__projectName__.dart';
|
||||
|
||||
void main() {
|
||||
var awesome = Awesome();
|
||||
print('awesome: ${awesome.isAwesome}');
|
||||
}
|
||||
''';
|
||||
|
||||
final String _libDart = '''
|
||||
/// Support for doing something awesome.
|
||||
///
|
||||
/// More dartdocs go here.
|
||||
library __projectName__;
|
||||
|
||||
export 'src/__projectName___base.dart';
|
||||
|
||||
// TODO: Export any libraries intended for clients of this package.
|
||||
''';
|
||||
|
||||
final String _libSrcDart = '''
|
||||
// TODO: Put public facing types in this file.
|
||||
|
||||
/// Checks if you are awesome. Spoiler: you are.
|
||||
class Awesome {
|
||||
bool get isAwesome => true;
|
||||
}
|
||||
''';
|
||||
|
||||
final String _testDart = '''
|
||||
import 'package:__projectName__/__projectName__.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
group('A group of tests', () {
|
||||
final awesome = Awesome();
|
||||
|
||||
setUp(() {
|
||||
// Additional setup goes here.
|
||||
});
|
||||
|
||||
test('First Test', () {
|
||||
expect(awesome.isAwesome, isTrue);
|
||||
});
|
||||
});
|
||||
}
|
||||
''';
|
||||
@@ -0,0 +1,85 @@
|
||||
// Copyright (c) 2021, 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.
|
||||
|
||||
import '../templates.dart';
|
||||
import 'common.dart' as common;
|
||||
|
||||
/// A generator for a server app built on `package:shelf`.
|
||||
class ServerSimpleGenerator extends DefaultGenerator {
|
||||
ServerSimpleGenerator()
|
||||
: super('server-simple', 'Web Server',
|
||||
'A web server built using package:shelf.',
|
||||
categories: const ['dart', 'server']) {
|
||||
addFile('.gitignore', common.gitignore);
|
||||
addFile('analysis_options.yaml', common.analysisOptions);
|
||||
addFile('CHANGELOG.md', common.changelog);
|
||||
addFile('pubspec.yaml', _pubspec);
|
||||
addFile('README.md', _readme);
|
||||
setEntrypoint(
|
||||
addFile('bin/server.dart', _main),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String getInstallInstructions() => '${super.getInstallInstructions()}\n'
|
||||
'run your app using `dart ${entrypoint.path}`.';
|
||||
}
|
||||
|
||||
final String _pubspec = '''
|
||||
name: __projectName__
|
||||
description: A web server built using the shelf package.
|
||||
version: 1.0.0
|
||||
# homepage: https://www.example.com
|
||||
|
||||
environment:
|
||||
sdk: ">=2.12.0 <3.0.0"
|
||||
|
||||
dependencies:
|
||||
args: ^2.0.0
|
||||
shelf: ^1.1.0
|
||||
|
||||
dev_dependencies:
|
||||
pedantic: ^1.10.0
|
||||
''';
|
||||
|
||||
final String _readme = '''
|
||||
A web server built using [Shelf](https://pub.dev/packages/shelf).
|
||||
''';
|
||||
|
||||
final String _main = r'''
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:args/args.dart';
|
||||
import 'package:shelf/shelf.dart' as shelf;
|
||||
import 'package:shelf/shelf_io.dart' as io;
|
||||
|
||||
// For Google Cloud Run, set _hostname to '0.0.0.0'.
|
||||
const _hostname = 'localhost';
|
||||
|
||||
void main(List<String> args) async {
|
||||
var parser = ArgParser()..addOption('port', abbr: 'p');
|
||||
var result = parser.parse(args);
|
||||
|
||||
// For Google Cloud Run, we respect the PORT environment variable
|
||||
var portStr = result['port'] ?? Platform.environment['PORT'] ?? '8080';
|
||||
var port = int.tryParse(portStr);
|
||||
|
||||
if (port == null) {
|
||||
stdout.writeln('Could not parse port value "$portStr" into a number.');
|
||||
// 64: command line usage error
|
||||
exitCode = 64;
|
||||
return;
|
||||
}
|
||||
|
||||
var handler = const shelf.Pipeline()
|
||||
.addMiddleware(shelf.logRequests())
|
||||
.addHandler(_echoRequest);
|
||||
|
||||
var server = await io.serve(handler, _hostname, port);
|
||||
print('Serving at http://${server.address.host}:${server.port}');
|
||||
}
|
||||
|
||||
shelf.Response _echoRequest(shelf.Request request) =>
|
||||
shelf.Response.ok('Request for "${request.url}"');
|
||||
''';
|
||||
@@ -0,0 +1,94 @@
|
||||
// Copyright (c) 2021, 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.
|
||||
|
||||
import '../templates.dart';
|
||||
import 'common.dart' as common;
|
||||
|
||||
/// A generator for a uber-simple web application.
|
||||
class WebSimpleGenerator extends DefaultGenerator {
|
||||
WebSimpleGenerator()
|
||||
: super('web-simple', 'Bare-bones Web App',
|
||||
'A web app that uses only core Dart libraries.',
|
||||
categories: const ['dart', 'web']) {
|
||||
addFile('.gitignore', common.gitignore);
|
||||
addFile('analysis_options.yaml', common.analysisOptions);
|
||||
addFile('CHANGELOG.md', common.changelog);
|
||||
addFile('pubspec.yaml', _pubspec);
|
||||
addFile('README.md', _readme);
|
||||
addFile('web/index.html', _index);
|
||||
setEntrypoint(
|
||||
addFile('web/main.dart', _main),
|
||||
);
|
||||
addFile('web/styles.css', _styles);
|
||||
}
|
||||
}
|
||||
|
||||
final String _pubspec = '''
|
||||
name: __projectName__
|
||||
description: An absolute bare-bones web app.
|
||||
version: 1.0.0
|
||||
# homepage: https://www.example.com
|
||||
|
||||
environment:
|
||||
sdk: '>=2.10.0 <3.0.0'
|
||||
|
||||
# dependencies:
|
||||
# path: ^1.7.0
|
||||
|
||||
dev_dependencies:
|
||||
build_runner: ^1.10.0
|
||||
build_web_compilers: ^2.11.0
|
||||
pedantic: ^1.9.0
|
||||
''';
|
||||
|
||||
final String _readme = '''
|
||||
An absolute bare-bones web app.
|
||||
''';
|
||||
|
||||
final String _index = '''
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="scaffolded-by" content="https://github.com/dart-lang/sdk">
|
||||
<title>__projectName__</title>
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
<script defer src="main.dart.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="output"></div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
''';
|
||||
|
||||
final String _main = '''
|
||||
import 'dart:html';
|
||||
|
||||
void main() {
|
||||
querySelector('#output').text = 'Your Dart app is running.';
|
||||
}
|
||||
''';
|
||||
|
||||
final String _styles = '''
|
||||
@import url(https://fonts.googleapis.com/css?family=Roboto);
|
||||
|
||||
html, body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
}
|
||||
|
||||
#output {
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
''';
|
||||
@@ -27,7 +27,6 @@ dependencies:
|
||||
path: ^1.0.0
|
||||
pedantic: ^1.9.0
|
||||
pub: any
|
||||
stagehand: any
|
||||
telemetry:
|
||||
path: ../telemetry
|
||||
usage: ^3.4.0
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
// Copyright (c) 2021, 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.
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:dartdev/src/commands/create.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import '../utils.dart';
|
||||
|
||||
void main() {
|
||||
group('create integration', defineCreateTests, timeout: longTimeout);
|
||||
}
|
||||
|
||||
void defineCreateTests() {
|
||||
TestProject p;
|
||||
|
||||
setUp(() => p = null);
|
||||
|
||||
tearDown(() => p?.dispose());
|
||||
|
||||
// Create tests for each template.
|
||||
for (String templateId in CreateCommand.legalTemplateIds) {
|
||||
test(templateId, () {
|
||||
p = project();
|
||||
|
||||
ProcessResult createResult = p.runSync([
|
||||
'create',
|
||||
'--force',
|
||||
'--template',
|
||||
templateId,
|
||||
p.dir.path,
|
||||
]);
|
||||
expect(createResult.exitCode, 0, reason: createResult.stderr);
|
||||
|
||||
// Validate that the project analyzes cleanly.
|
||||
// TODO: Should we use --fatal-infos here?
|
||||
ProcessResult analyzeResult =
|
||||
p.runSync(['analyze'], workingDir: p.dir.path);
|
||||
expect(analyzeResult.exitCode, 0, reason: analyzeResult.stdout);
|
||||
|
||||
// Validate that the code is well formatted.
|
||||
ProcessResult formatResult = p.runSync([
|
||||
'format',
|
||||
'--output',
|
||||
'none',
|
||||
'--set-exit-if-changed',
|
||||
p.dir.path,
|
||||
]);
|
||||
expect(formatResult.exitCode, 0, reason: formatResult.stdout);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:dartdev/src/commands/create.dart';
|
||||
import 'package:dartdev/src/templates.dart' as templates;
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:test/test.dart';
|
||||
|
||||
@@ -77,14 +78,19 @@ void defineCreateTests() {
|
||||
test('create $templateId', () {
|
||||
p = project();
|
||||
|
||||
ProcessResult result = p
|
||||
.runSync(['create', '--force', '--template', templateId, p.dir.path]);
|
||||
ProcessResult result = p.runSync([
|
||||
'create',
|
||||
'--force',
|
||||
'--no-pub',
|
||||
'--template',
|
||||
templateId,
|
||||
p.dir.path,
|
||||
]);
|
||||
expect(result.exitCode, 0);
|
||||
|
||||
String projectName = path.basename(p.dir.path);
|
||||
|
||||
String entry =
|
||||
CreateCommand.retrieveTemplateGenerator(templateId).entrypoint.path;
|
||||
String entry = templates.getGenerator(templateId).entrypoint.path;
|
||||
entry = entry.replaceAll('__projectName__', projectName);
|
||||
File entryFile = File(path.join(p.dir.path, entry));
|
||||
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
// Copyright (c) 2021, 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.
|
||||
|
||||
import 'package:dartdev/src/templates.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
group('templates', () {
|
||||
group('substituteVars', () {
|
||||
test('simple', () {
|
||||
_expect('foo __bar__ baz', {'bar': 'baz'}, 'foo baz baz');
|
||||
});
|
||||
|
||||
test('nosub', () {
|
||||
_expect('foo __bar__ baz', {'aaa': 'bbb'}, 'foo __bar__ baz');
|
||||
});
|
||||
|
||||
test('matching input', () {
|
||||
_expect('foo __bar__ baz', {'bar': '__baz__', 'baz': 'foo'},
|
||||
'foo __baz__ baz');
|
||||
});
|
||||
|
||||
test('vars must be alpha + numeric', () {
|
||||
expect(() => substituteVars('str', {'with space': 'noop'}),
|
||||
throwsArgumentError);
|
||||
expect(() => substituteVars('str', {'with!symbols': 'noop'}),
|
||||
throwsArgumentError);
|
||||
expect(() => substituteVars('str', {'with1numbers': 'noop'}),
|
||||
throwsArgumentError);
|
||||
expect(() => substituteVars('str', {'with_under': 'noop'}),
|
||||
throwsArgumentError);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void _expect(String original, Map<String, String> vars, String result) {
|
||||
expect(substituteVars(original, vars), result);
|
||||
}
|
||||
@@ -7,7 +7,6 @@ import 'dart:io';
|
||||
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:pub_semver/pub_semver.dart';
|
||||
|
||||
import 'package:test/test.dart';
|
||||
|
||||
/// A long [Timeout] is provided for tests that start a process on
|
||||
@@ -54,7 +53,7 @@ class TestProject {
|
||||
this.name = _defaultProjectName,
|
||||
this.logAnalytics = false,
|
||||
this.sdkConstraint}) {
|
||||
dir = Directory.systemTemp.createTempSync(name);
|
||||
dir = Directory.systemTemp.createTempSync('a');
|
||||
file('pubspec.yaml', '''
|
||||
name: $name
|
||||
environment:
|
||||
|
||||
Reference in New Issue
Block a user