| // Copyright 2014 The Flutter Authors. 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' hide Platform; |
| |
| import 'package:args/args.dart'; |
| import 'package:path/path.dart' as path; |
| import 'package:platform/platform.dart'; |
| |
| import 'configuration.dart'; |
| import 'snippets.dart'; |
| |
| const String _kSerialOption = 'serial'; |
| const String _kElementOption = 'element'; |
| const String _kHelpOption = 'help'; |
| const String _kInputOption = 'input'; |
| const String _kLibraryOption = 'library'; |
| const String _kOutputOption = 'output'; |
| const String _kPackageOption = 'package'; |
| const String _kTemplateOption = 'template'; |
| const String _kTypeOption = 'type'; |
| const String _kShowDartPad = 'dartpad'; |
| |
| String getChannelName() { |
| final RegExp gitBranchRegexp = RegExp(r'^## (.*)'); |
| final ProcessResult gitResult = Process.runSync('git', <String>['status', '-b', '--porcelain']); |
| if (gitResult.exitCode != 0) |
| throw 'git status exit with non-zero exit code: ${gitResult.exitCode}'; |
| final Match gitBranchMatch = gitBranchRegexp.firstMatch( |
| (gitResult.stdout as String).trim().split('\n').first); |
| return gitBranchMatch == null ? '<unknown>' : gitBranchMatch.group(1).split('...').first; |
| } |
| |
| /// Generates snippet dartdoc output for a given input, and creates any sample |
| /// applications needed by the snippet. |
| void main(List<String> argList) { |
| const Platform platform = LocalPlatform(); |
| final Map<String, String> environment = platform.environment; |
| final ArgParser parser = ArgParser(); |
| final List<String> snippetTypes = |
| SnippetType.values.map<String>((SnippetType type) => getEnumName(type)).toList(); |
| parser.addOption( |
| _kTypeOption, |
| defaultsTo: getEnumName(SnippetType.sample), |
| allowed: snippetTypes, |
| allowedHelp: <String, String>{ |
| getEnumName(SnippetType.sample): |
| 'Produce a code sample application complete with embedding the sample in an ' |
| 'application template.', |
| getEnumName(SnippetType.snippet): |
| 'Produce a nicely formatted piece of sample code. Does not embed the ' |
| 'sample into an application template.', |
| }, |
| help: 'The type of snippet to produce.', |
| ); |
| parser.addOption( |
| _kTemplateOption, |
| defaultsTo: null, |
| help: 'The name of the template to inject the code into.', |
| ); |
| parser.addOption( |
| _kOutputOption, |
| defaultsTo: null, |
| help: 'The output path for the generated sample application. Overrides ' |
| 'the naming generated by the --package/--library/--element arguments. ' |
| 'Metadata will be written alongside in a .json file. ' |
| 'The basename of this argument is used as the ID', |
| ); |
| parser.addOption( |
| _kInputOption, |
| defaultsTo: environment['INPUT'], |
| help: 'The input file containing the sample code to inject.', |
| ); |
| parser.addOption( |
| _kPackageOption, |
| defaultsTo: environment['PACKAGE_NAME'], |
| help: 'The name of the package that this sample belongs to.', |
| ); |
| parser.addOption( |
| _kLibraryOption, |
| defaultsTo: environment['LIBRARY_NAME'], |
| help: 'The name of the library that this sample belongs to.', |
| ); |
| parser.addOption( |
| _kElementOption, |
| defaultsTo: environment['ELEMENT_NAME'], |
| help: 'The name of the element that this sample belongs to.', |
| ); |
| parser.addOption( |
| _kSerialOption, |
| defaultsTo: environment['INVOCATION_INDEX'], |
| help: 'A unique serial number for this snippet tool invocation.', |
| ); |
| parser.addFlag( |
| _kHelpOption, |
| defaultsTo: false, |
| negatable: false, |
| help: 'Prints help documentation for this command', |
| ); |
| parser.addFlag( |
| _kShowDartPad, |
| defaultsTo: false, |
| negatable: false, |
| help: "Indicates whether DartPad should be included in the sample's " |
| 'final HTML output. This flag only applies when the type parameter is ' |
| '"sample".', |
| ); |
| |
| final ArgResults args = parser.parse(argList); |
| |
| if (args[_kHelpOption] as bool) { |
| stderr.writeln(parser.usage); |
| exit(0); |
| } |
| |
| final SnippetType snippetType = SnippetType.values |
| .firstWhere((SnippetType type) => getEnumName(type) == args[_kTypeOption], orElse: () => null); |
| assert(snippetType != null, "Unable to find '${args[_kTypeOption]}' in SnippetType enum."); |
| |
| if (args[_kShowDartPad] == true && snippetType != SnippetType.sample) { |
| errorExit('${args[_kTypeOption]} was selected, but the --dartpad flag is only valid ' |
| 'for application sample code.'); |
| } |
| |
| if (args[_kInputOption] == null) { |
| stderr.writeln(parser.usage); |
| errorExit('The --$_kInputOption option must be specified, either on the command ' |
| 'line, or in the INPUT environment variable.'); |
| } |
| |
| final File input = File(args['input'] as String); |
| if (!input.existsSync()) { |
| errorExit('The input file ${input.path} does not exist.'); |
| } |
| |
| String template; |
| if (snippetType == SnippetType.sample) { |
| final String templateArg = args[_kTemplateOption] as String; |
| if (templateArg == null || templateArg.isEmpty) { |
| stderr.writeln(parser.usage); |
| errorExit('The --$_kTemplateOption option must be specified on the command ' |
| 'line for application samples.'); |
| } |
| template = templateArg.replaceAll(RegExp(r'.tmpl$'), ''); |
| } |
| |
| String emptyToNull(String value) => value?.isEmpty ?? true ? null : value; |
| final String packageName = emptyToNull(args[_kPackageOption] as String); |
| final String libraryName = emptyToNull(args[_kLibraryOption] as String); |
| final String elementName = emptyToNull(args[_kElementOption] as String); |
| final String serial = emptyToNull(args[_kSerialOption] as String); |
| final List<String> id = <String>[]; |
| if (args[_kOutputOption] != null) { |
| id.add(path.basename(path.basenameWithoutExtension(args[_kOutputOption] as String))); |
| } else { |
| if (packageName != null && packageName != 'flutter') { |
| id.add(packageName); |
| } |
| if (libraryName != null) { |
| id.add(libraryName); |
| } |
| if (elementName != null) { |
| id.add(elementName); |
| } |
| if (serial != null) { |
| id.add(serial); |
| } |
| if (id.isEmpty) { |
| errorExit('Unable to determine ID. At least one of --$_kPackageOption, ' |
| '--$_kLibraryOption, --$_kElementOption, -$_kSerialOption, or the environment variables ' |
| 'PACKAGE_NAME, LIBRARY_NAME, ELEMENT_NAME, or INVOCATION_INDEX must be non-empty.'); |
| } |
| } |
| |
| final SnippetGenerator generator = SnippetGenerator(); |
| stdout.write(generator.generate( |
| input, |
| snippetType, |
| showDartPad: args[_kShowDartPad] as bool, |
| template: template, |
| output: args[_kOutputOption] != null ? File(args[_kOutputOption] as String) : null, |
| metadata: <String, Object>{ |
| 'sourcePath': environment['SOURCE_PATH'], |
| 'sourceLine': environment['SOURCE_LINE'] != null |
| ? int.tryParse(environment['SOURCE_LINE']) |
| : null, |
| 'id': id.join('.'), |
| 'channel': getChannelName(), |
| 'serial': serial, |
| 'package': packageName, |
| 'library': libraryName, |
| 'element': elementName, |
| }, |
| )); |
| |
| exit(0); |
| } |