1
1
import 'dart:io' ;
2
2
import 'package:resource/resource.dart' show Resource;
3
- import 'dart:convert' show UTF8;
3
+ import 'dart:convert' show UTF8, JsonEncoder, JsonDecoder ;
4
4
import 'dart:async' ;
5
+ import 'package:args/command_runner.dart' ;
6
+ import 'package:path/path.dart' as path;
5
7
6
-
7
- abstract class Command {
8
- String get name;
9
- String get help;
10
- Future <int > execute (List <String > arguments);
11
- const Command ();
8
+ String ask (String prompt,String defaultsTo) {
9
+ stdout.write ("${prompt } [${defaultsTo }]:" );
10
+ var result = stdin.readLineSync ();
11
+ if (result == "" ) return defaultsTo;
12
+ return result;
12
13
}
14
+ class Config {
15
+ String _homePath () {
16
+ String os = Platform .operatingSystem;
17
+ String home = "" ;
18
+ Map <String , String > envVars = Platform .environment;
19
+ if (Platform .isMacOS) {
20
+ home = envVars['HOME' ];
21
+ } else if (Platform .isLinux) {
22
+ home = envVars['HOME' ];
23
+ } else if (Platform .isWindows) {
24
+ home = envVars['UserProfile' ];
25
+ }
26
+ return home;
27
+ }
28
+ Map <
String ,
String > _data
= {
"ghaccount" : "github-name" ,
"author" : "Anonymous" ,
"email" : "[email protected] " };
29
+ bool _modified = false ;
30
+
31
+ String get configFileName => path.join (_homePath (),".dacsslide.json" );
32
+
33
+ Config ._() {
34
+
35
+ var file = new File (configFileName);
36
+ if (file.existsSync ()) {
37
+ _data = new JsonDecoder ().convert (file.readAsStringSync ());
38
+ }
39
+ }
40
+ static Config _instance;
41
+ operator [](String key) => _data[key];
42
+ operator []= (String key, String value) {
43
+ if (_data[key]!= value) {
44
+ _modified = true ;
45
+ _data[key] = value;
46
+ }
47
+ }
48
+ void save () {
49
+ if (_modified) {
50
+ new File (configFileName).writeAsStringSync (new JsonEncoder ().convert (_data));
51
+ _modified = false ;
52
+ }
53
+ }
54
+
55
+ factory Config () {
56
+ if (_instance== null ) _instance = new Config ._();
57
+ return _instance;
58
+ }
13
59
14
- class CreationParameter {
15
- final String name;
16
- final String defaultValue;
17
- final String description;
18
- const CreationParameter (this .name, this .defaultValue, this .description);
19
60
}
61
+
62
+
20
63
class CreateCommand extends Command {
21
- CreateCommand ();
22
-
23
- static const List <String > templatableExtensions = const ['.yaml' ,'.html' ];
24
- static const List <String > parameters = const [
25
- const CreationParameter ("name" , "new_presentation" , "Presentation name" ),
26
- const CreationParameter ("title" , "Great New Presentation" ,"Presentation title" ),
27
- const CreationParameter ("ghaccount" , "mygithubaccount" ,"GitHub account" ),
28
- const CreationParameter ("author" , "Anonymous" ,"Authour's name" ),
29
- const CreationParameter (
"email" ,
"[email protected] " ,
"Author's email" ),
30
- ];
31
-
32
- final Map <String ,String > parametersValues = {};
64
+ final name = "create" ;
65
+ final description = "Creates new project" ;
66
+ final config = new Config ();
67
+
68
+ CreateCommand () {
69
+ argParser
70
+ ..addOption ('title' ,defaultsTo: "Great New Presentation" ,help: "Presentation title" )
71
+ ..addOption ('ghaccount' ,help: 'GitHub account' , defaultsTo: config["ghaccount" ] )
72
+ ..addOption ('author' ,help: "Author's name" , defaultsTo: config["author" ])
73
+ ..addOption ('email' ,help: "Author's email" , defaultsTo: config["email" ]);
74
+ }
75
+
76
+ static const List <String > templatableExtensions = const ['.yaml' ,'.html' ,'.dart' ];
77
+
33
78
RegExp parameterRegExp;
79
+ String projectName;
34
80
35
81
Future <bool > createFile (String fileName) async {
36
82
37
- print ("Processing ${fileName }" );
38
- var file = await (new File (fileName).create (recursive: true ));
39
- if (fileName.endsWith (".template" )) fileName = fileName.substring (fileName.length- ".templat" .length);
40
83
var fileResource = new Resource ("package:dacsslide/template/${fileName }" );
84
+ if (fileName.endsWith (".template" )) fileName = fileName.substring (0 ,fileName.length- ".template" .length);
85
+ var file = await (new File (path.join (projectName,fileName)).create (recursive: true ));
41
86
if (templatableExtensions.any ( (ext) => fileName.endsWith (ext))) {
42
- print ("Processing template ${fileName }" );
43
87
var content = await fileResource.readAsString (encoding: UTF8 );
44
- var _content = content.replaceAllMapped (parameterRegExp, (m) => parametersValues [m.group (0 ).substring (1 )]);
88
+ var _content = content.replaceAllMapped (parameterRegExp, (m) => m. group ( 0 ) == " \$ name" ? projectName : argResults [m.group (0 ).substring (1 )]);
45
89
if (content != _content) {
46
- //print("Changed:\n ${_content}");
47
90
await file.writeAsString (_content);
48
91
return true ;
49
92
}
@@ -52,47 +95,45 @@ class CreateCommand extends Command {
52
95
return true ;
53
96
}
54
97
55
- @override
56
- int execute ( List < String > arguments) async {
57
- print ( "Generating project ${ arguments . join ( '-' )}" );
58
- for ( CreationParameter parameter in parameters) {
59
- parametersValues[parameter. name] = parameter.defaultValue ;
98
+ void _askArgument ( String name, String prompt) {
99
+ if ( ! argResults. wasParsed (name)) {
100
+ config[name] = ask ( "Enter ${ prompt }" ,config[name] );
101
+ } else {
102
+ config[ name] = argResults[name] ;
60
103
}
61
- parameterRegExp = new RegExp ("\\\$ (${parameters .map ( (p ) => p .name ).join ('|' )})" );
104
+ }
105
+
106
+ Future <int > run () async {
107
+ projectName = argResults.rest.length> 0 ? argResults.rest.first: ask ('Enter project name' ,'some-name' );
108
+ _askArgument ('ghaccount' ,'GitHub account' );
109
+ _askArgument ('author' ,"author's full name" );
110
+ _askArgument ('email' ,"author's email" );
111
+
112
+
113
+ print ("Generating project '${projectName }'" );
114
+ await new Directory (projectName).create ();
115
+
116
+ parameterRegExp = new RegExp ("\\\$ (${argResults .options .join ('|' )}|name)" );
62
117
63
118
var resource = new Resource ("package:dacsslide/template/.files.txt" );
64
119
var fileNames = (await resource.readAsString (encoding: UTF8 )).split ("\n " )
65
120
.where ( (f) => f.length> 0 ).map ( (f) => f.substring (2 ));
66
121
await Future .wait (fileNames.map (createFile));
67
- print ("Project generated" );
122
+ print ("Project ${projectName } generated." );
123
+
124
+ config.save ();
125
+
68
126
return 0 ;
69
127
}
70
128
71
- @override
72
- String get help => "Use 'create' command to initialize new presentation project." ;
73
-
74
- @override
75
- String get name => "create" ;
76
129
}
77
130
78
- //T commandCreator<T>() => new T();
79
-
80
- List <Command > commands = [new CreateCommand ()];
81
-
82
- void main (List <String > arguments) async {
83
- if (arguments.length< 1 ) {
84
- var commandList = commands.map ((Command c) => c.name).join ("," );
85
- stderr.write ("Usage: dacsslide [command]\n Where [command] is one of: ${commandList }" );
86
- exitCode = 2 ;
87
- return ;
88
- }
89
-
90
- var command = commands.firstWhere ((Command c) => c.name== arguments.first, orElse: () => null );
91
- if (command == null ) {
92
- var commandList = commands.map ((Command c) => c.name).join ("," );
93
- stderr.write ("Invalid command '${arguments .first }'\n Awailable commands are: ${commandList }" );
94
- exitCode = 2 ;
95
- return ;
96
- }
97
- exitCode = await command.execute (arguments.sublist (1 ));
131
+ void main (List <String > arguments) {
132
+ var runner = new CommandRunner ("dacsslide" ,"CLI for DaCSSlide presentation library" )
133
+ ..addCommand (new CreateCommand ());
134
+ runner.run (arguments).catchError ((error) {
135
+ if (error is ! UsageException ) throw error;
136
+ print (error);
137
+ exit (64 ); // Exit code 64 indicates a usage error.
138
+ });
98
139
}
0 commit comments