@@ -27,15 +27,20 @@ import org.eclipse.aether.graph.Dependency
2727import org.grails.build.logging.GrailsConsoleAntBuilder
2828import org.grails.build.parsing.CommandLine
2929import org.grails.cli.GrailsCli
30- import org.grails.cli.profile.*
30+ import org.grails.cli.profile.CommandDescription
31+ import org.grails.cli.profile.ExecutionContext
32+ import org.grails.cli.profile.Feature
33+ import org.grails.cli.profile.Profile
34+ import org.grails.cli.profile.ProfileRepository
35+ import org.grails.cli.profile.ProfileRepositoryAware
3136import org.grails.io.support.FileSystemResource
3237import org.grails.io.support.Resource
33-
3438import java.nio.file.FileVisitResult
3539import java.nio.file.Files
3640import java.nio.file.Path
3741import java.nio.file.SimpleFileVisitor
3842import java.nio.file.attribute.BasicFileAttributes
43+ import java.nio.file.Paths
3944
4045/**
4146 * Command for creating Grails applications
@@ -60,6 +65,7 @@ class CreateAppCommand extends ArgumentCompletingCommand implements ProfileRepos
6065 Map<String , String > variables = [:]
6166 String appname
6267 String groupname
68+ String defaultpackagename
6369 File targetDirectory
6470 List<String > binaryFileExtensions = [' png' ,' gif' ,' jpg' ,' jpeg' ,' ico' ,' icns' ,' pdf' ,' zip' ,' jar' ,' class' ]
6571
@@ -202,38 +208,28 @@ class CreateAppCommand extends ArgumentCompletingCommand implements ProfileRepos
202208 files
203209 }
204210
205- @Override
206- boolean handle (ExecutionContext executionContext ) {
207- if (profileRepository == null ) throw new IllegalStateException (" Property 'profileRepository' must be set" )
208-
211+ boolean handle (CreateAppCommandObject cmd ) {
212+ if (profileRepository == null ) throw new IllegalStateException (" Property 'profileRepository' must be set" )
209213
210- def mainCommandLine = executionContext. commandLine
211- def profileName = evaluateProfileName(mainCommandLine)
212-
213- List<String > validFlags = [INPLACE_FLAG , PROFILE_FLAG , FEATURES_FLAG ]
214- mainCommandLine. undeclaredOptions. each { String key , Object value ->
215- if (! validFlags. contains(key)) {
216- List possibleSolutions = validFlags. findAll { it. substring(0 , 2 ) == key. substring(0 , 2 ) }
217- StringBuilder warning = new StringBuilder (" Unrecognized flag: ${ key} ." )
218- if (possibleSolutions) {
219- warning. append(" Possible solutions: " )
220- warning. append(possibleSolutions. join(" , " ))
221- }
222- GrailsConsole . instance. warn(warning. toString())
223- }
224- }
214+ String profileName = cmd. profileName
225215
226216 Profile profileInstance = profileRepository. getProfile(profileName)
227- if ( ! validateProfile(profileInstance, profileName, executionContext )) {
217+ if ( ! validateProfile(profileInstance, profileName)) {
228218 return false
229219 }
230- List<Feature > features = evaluateFeatures(profileInstance, mainCommandLine). toList()
231- if (profileInstance) {
232220
233- if ( ! initializeVariables(profileInstance, mainCommandLine) ) {
221+ List<Feature > features = evaluateFeatures(profileInstance, cmd. features). toList()
222+
223+ if (profileInstance) {
224+ if (! initializeGroupAndName(cmd. appName, cmd. inplace)) {
234225 return false
235226 }
236- File projectTargetDirectory = mainCommandLine. hasOption(' inplace' ) || GrailsCli . isInteractiveModeActive() ? new File (" ." ). canonicalFile : new File (appname)
227+
228+ initializeVariables(cmd. appName, defaultpackagename, profileName, cmd. grailsVersion)
229+
230+ Path appFullDirectory = Paths . get(cmd. baseDir. path, appname)
231+
232+ File projectTargetDirectory = cmd. inplace ? new File (" ." ). canonicalFile : appFullDirectory. toAbsolutePath(). normalize(). toFile()
237233
238234 def profiles = profileRepository. getProfileAndDependencies(profileInstance)
239235
@@ -285,11 +281,11 @@ class CreateAppCommand extends ArgumentCompletingCommand implements ProfileRepos
285281 }
286282
287283 replaceBuildTokens(profileName, profileInstance, features, projectTargetDirectory)
288- executionContext . console. addStatus(
289- " ${ name == 'create-plugin' ? 'Plugin' : 'Application'} created at $projectTargetDirectory . absolutePath "
284+ cmd . console. addStatus(
285+ " ${ name == 'create-plugin' ? 'Plugin' : 'Application'} created at ${ projectTargetDirectory.absolutePath} "
290286 )
291287 if (profileInstance. instructions) {
292- executionContext . console. addStatus(profileInstance. instructions)
288+ cmd . console. addStatus(profileInstance. instructions)
293289 }
294290 GrailsCli . tiggerAppLoad()
295291 return true
@@ -300,15 +296,53 @@ class CreateAppCommand extends ArgumentCompletingCommand implements ProfileRepos
300296 }
301297 }
302298
303- protected boolean validateProfile (Profile profileInstance , String profileName , ExecutionContext executionContext ) {
299+ @Override
300+ boolean handle (ExecutionContext executionContext ) {
301+ CommandLine commandLine = executionContext. commandLine
302+
303+ String profileName = evaluateProfileName(commandLine)
304+
305+ List<String > validFlags = [INPLACE_FLAG , PROFILE_FLAG , FEATURES_FLAG ]
306+ commandLine. undeclaredOptions. each { String key , Object value ->
307+ if (! validFlags. contains(key)) {
308+ List possibleSolutions = validFlags. findAll { it. substring(0 , 2 ) == key. substring(0 , 2 ) }
309+ StringBuilder warning = new StringBuilder (" Unrecognized flag: ${ key} ." )
310+ if (possibleSolutions) {
311+ warning. append(" Possible solutions: " )
312+ warning. append(possibleSolutions. join(" , " ))
313+ }
314+ executionContext. console. warn(warning. toString())
315+ }
316+ }
317+
318+ boolean inPlace = commandLine. hasOption(' inplace' ) || GrailsCli . isInteractiveModeActive()
319+ String appName = commandLine. remainingArgs ? commandLine. remainingArgs[0 ] : " "
320+
321+ List<String > features = commandLine. optionValue(" features" )?. toString()?. split(' ,' )?. toList()
322+
323+ CreateAppCommandObject cmd = new CreateAppCommandObject (
324+ appName : appName,
325+ baseDir : executionContext. baseDir,
326+ profileName : profileName,
327+ grailsVersion : Environment . getPackage(). getImplementationVersion() ?: GRAILS_VERSION_FALLBACK_IN_IDE_ENVIRONMENTS_FOR_RUNNING_TESTS ,
328+ features : features,
329+ inplace : inPlace,
330+ console : executionContext. console
331+ )
332+
333+ return this . handle(cmd)
334+ }
335+
336+ protected boolean validateProfile (Profile profileInstance , String profileName ) {
304337 if (profileInstance == null ) {
305- executionContext . console . error(" Profile not found for name [$profileName ]" )
338+ GrailsConsole . instance . error(" Profile not found for name [$profileName ]" )
306339 return false
307340 }
308341 return true
309342 }
310343
311344 private Map<URL , File > unzippedDirectories = new LinkedHashMap<URL , File > ()
345+
312346 @CompileDynamic
313347 protected File unzipProfile (AntBuilder ant , Resource location ) {
314348
@@ -411,15 +445,15 @@ class CreateAppCommand extends ArgumentCompletingCommand implements ProfileRepos
411445 mainCommandLine. optionValue(' profile' )?. toString() ?: getDefaultProfile()
412446 }
413447
414- protected Iterable<Feature > evaluateFeatures (Profile profile , CommandLine commandLine ) {
415- String [] requestedFeatures = commandLine. optionValue(" features" )?. toString()?. split(' ,' )
416- if (requestedFeatures) {
417- List<String > requestedFeaturesList = requestedFeatures. toList()
448+ protected Iterable<Feature > evaluateFeatures (Profile profile , List<String > requestedFeatures ) {
449+ if (requestedFeatures) {
418450 List<String > allFeatureNames = profile. features* . name
419- List<String > validFeatureNames = requestedFeaturesList. intersect(allFeatureNames)
420- requestedFeaturesList. removeAll(allFeatureNames)
421- requestedFeaturesList. each { String invalidFeature ->
422- List possibleSolutions = allFeatureNames. findAll { it. substring(0 , 2 ) == invalidFeature. substring(0 , 2 ) }
451+ List<String > validFeatureNames = requestedFeatures. intersect(allFeatureNames)
452+ requestedFeatures. removeAll(allFeatureNames)
453+ requestedFeatures. each { String invalidFeature ->
454+ List possibleSolutions = allFeatureNames. findAll {
455+ it. substring(0 , 2 ) == invalidFeature. substring(0 , 2 )
456+ }
423457 StringBuilder warning = new StringBuilder (" Feature ${ invalidFeature} does not exist in the profile ${ profile.name} !" )
424458 if (possibleSolutions) {
425459 warning. append(" Possible solutions: " )
@@ -463,49 +497,45 @@ class CreateAppCommand extends ArgumentCompletingCommand implements ProfileRepos
463497 setTo. text = createNewApplicationYml(previousApplicationYml, newApplicationYml)
464498 }
465499 }
466-
467- protected boolean initializeVariables (Profile profile , CommandLine commandLine ) {
468- String defaultPackage
469-
470- def args = commandLine. getRemainingArgs()
471- boolean inPlace = commandLine. hasOption(' inplace' ) || GrailsCli . isInteractiveModeActive()
472500
473- if (! args && ! inPlace) {
501+ protected boolean initializeGroupAndName (String appName , boolean inplace ) {
502+ if (! appName && ! inplace) {
474503 GrailsConsole . getInstance(). error(" Specify an application name or use --inplace to create an application in the current directory" )
475504 return false
476505 }
477- String groupAndAppName = args ? args[ 0 ] : null
478- if (inPlace ) {
506+ String groupAndAppName = appName
507+ if (inplace ) {
479508 appname = new File (" ." ). canonicalFile. name
480509 if (! groupAndAppName) {
481510 groupAndAppName = appname
482511 }
483512 }
484-
513+
485514 if (! groupAndAppName) {
486515 GrailsConsole . getInstance(). error(" Specify an application name or use --inplace to create an application in the current directory" )
487516 return false
488517 }
489518
490519 try {
491- defaultPackage = establishGroupAndAppName(groupAndAppName)
520+ defaultpackagename = establishGroupAndAppName(groupAndAppName)
492521 } catch (IllegalArgumentException e ) {
493522 GrailsConsole . instance. error(e. message)
494523 return false
495524 }
525+ }
496526
497-
527+ private void initializeVariables ( String appname , String defaultPackage , String profileName , String grailsVersion ) {
498528 variables. APPNAME = appname
499529
500530 variables[' grails.codegen.defaultPackage' ] = defaultPackage
501- variables[' grails.codegen.defaultPackage.path' ] = defaultPackage. replace(' .' , ' /' )
531+ variables[' grails.codegen.defaultPackage.path' ] = defaultPackage. replace(' .' , ' /' )
502532
503533 def projectClassName = GrailsNameUtils . getNameFromScript(appname)
504534 variables[' grails.codegen.projectClassName' ] = projectClassName
505535 variables[' grails.codegen.projectNaturalName' ] = GrailsNameUtils . getNaturalName(projectClassName)
506536 variables[' grails.codegen.projectName' ] = GrailsNameUtils . getScriptName(projectClassName)
507- variables[' grails.profile' ] = profile . name
508- variables[' grails.version' ] = Environment . getPackage() . getImplementationVersion() ?: GRAILS_VERSION_FALLBACK_IN_IDE_ENVIRONMENTS_FOR_RUNNING_TESTS
537+ variables[' grails.profile' ] = profileName
538+ variables[' grails.version' ] = grailsVersion
509539 variables[' grails.app.name' ] = appname
510540 variables[' grails.app.group' ] = groupname
511541 }
@@ -526,7 +556,7 @@ class CreateAppCommand extends ArgumentCompletingCommand implements ProfileRepos
526556 }
527557
528558 private String createValidPackageName () {
529- String defaultPackage = appname. split(/ [-]+/ ). collect { String token -> (token. toLowerCase(). toCharArray(). findAll { char ch -> Character . isJavaIdentifierPart(ch) } as char []) as String }. join(' .' )
559+ String defaultPackage = appname. split(/ [-]+/ ). collect { String token -> (token. toLowerCase(). toCharArray(). findAll { char ch -> Character . isJavaIdentifierPart(ch) } as char []) as String }. join(' .' )
530560 if (! GrailsNameUtils . isValidJavaPackage(defaultPackage)) {
531561 throw new IllegalArgumentException (" Cannot create a valid package name for [$appname ]. Please specify a name that is also a valid Java package." )
532562 }
@@ -635,4 +665,14 @@ class CreateAppCommand extends ArgumentCompletingCommand implements ProfileRepos
635665
636666 return v ? " ${ artifact.groupId} :${ artifact.artifactId} :${ v} " : " ${ artifact.groupId} :${ artifact.artifactId} "
637667 }
668+
669+ static class CreateAppCommandObject {
670+ String appName
671+ File baseDir
672+ String profileName
673+ String grailsVersion
674+ List<String > features
675+ boolean inplace = false
676+ GrailsConsole console
677+ }
638678}
0 commit comments