@@ -18,21 +18,27 @@ package org.grails.cli.profile.commands
1818
1919import grails.build.logging.GrailsConsole
2020import grails.io.IOUtils
21- import grails.util.BuildSettings
2221import grails.util.Environment
2322import grails.util.GrailsNameUtils
2423import groovy.transform.CompileDynamic
2524import groovy.transform.CompileStatic
2625import groovy.transform.TypeCheckingMode
27- import org.eclipse.aether.artifact.DefaultArtifact
2826import org.eclipse.aether.graph.Dependency
2927import org.grails.build.logging.GrailsConsoleAntBuilder
3028import org.grails.build.parsing.CommandLine
3129import org.grails.cli.GrailsCli
32- 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
3336import org.grails.io.support.FileSystemResource
3437import org.grails.io.support.Resource
3538
39+ import java.nio.file.Path
40+ import java.nio.file.Paths
41+
3642/**
3743 * Command for creating Grails applications
3844 *
@@ -52,6 +58,7 @@ class CreateAppCommand extends ArgumentCompletingCommand implements ProfileRepos
5258 Map<String , String > variables = [:]
5359 String appname
5460 String groupname
61+ String defaultpackagename
5562 File targetDirectory
5663 List<String > binaryFileExtensions = [' png' ,' gif' ,' jpg' ,' jpeg' ,' ico' ,' icns' ,' pdf' ,' zip' ,' jar' ,' class' ]
5764
@@ -128,25 +135,27 @@ class CreateAppCommand extends ArgumentCompletingCommand implements ProfileRepos
128135 return super . complete(commandLine, desc, candidates, cursor)
129136 }
130137
131- @Override
132- boolean handle (ExecutionContext executionContext ) {
133- if (profileRepository == null ) throw new IllegalStateException (" Property 'profileRepository' must be set" )
134-
135-
136- def mainCommandLine = executionContext. commandLine
137- def profileName = evaluateProfileName(mainCommandLine)
138+ boolean handle (CreateAppCommandObject cmd ) {
139+ if (profileRepository == null ) throw new IllegalStateException (" Property 'profileRepository' must be set" )
138140
141+ String profileName = cmd. profileName
139142 Profile profileInstance = profileRepository. getProfile(profileName)
140- if ( ! validateProfile(profileInstance, profileName, executionContext )) {
143+ if ( ! validateProfile(profileInstance, profileName)) {
141144 return false
142145 }
143- List<Feature > features = evaluateFeatures(profileInstance, mainCommandLine). toList()
144- if (profileInstance) {
145146
146- if ( ! initializeVariables(profileInstance, mainCommandLine) ) {
147+ List<Feature > features = evaluateFeatures(profileInstance, cmd. features). toList()
148+
149+ if (profileInstance) {
150+ if (! initializeGroupAndName(cmd. appName, cmd. inplace)) {
147151 return false
148152 }
149- targetDirectory = mainCommandLine. hasOption(' inplace' ) || GrailsCli . isInteractiveModeActive() ? new File (" ." ). canonicalFile : new File (appname)
153+
154+ initializeVariables(cmd. appName, defaultpackagename, profileName, cmd. grailsVersion)
155+
156+ Path appFullDirectory = Paths . get(cmd. baseDir. path, appname)
157+ targetDirectory = cmd. inplace ? new File (" ." ). canonicalFile : appFullDirectory. toFile()
158+
150159 File applicationYmlFile = new File (targetDirectory, " grails-app/conf/application.yml" )
151160
152161 def profiles = profileRepository. getProfileAndDependencies(profileInstance)
@@ -189,7 +198,7 @@ class CreateAppCommand extends ArgumentCompletingCommand implements ProfileRepos
189198 }
190199
191200 replaceBuildTokens(profileName, profileInstance, features, targetDirectory)
192- executionContext . console . addStatus(
201+ GrailsConsole . instance . addStatus(
193202 " ${ name == 'create-plugin' ? 'Plugin' : 'Application'} created at $targetDirectory . absolutePath "
194203 )
195204 GrailsCli . tiggerAppLoad()
@@ -201,15 +210,39 @@ class CreateAppCommand extends ArgumentCompletingCommand implements ProfileRepos
201210 }
202211 }
203212
204- protected boolean validateProfile (Profile profileInstance , String profileName , ExecutionContext executionContext ) {
213+ @Override
214+ boolean handle (ExecutionContext executionContext ) {
215+ CommandLine commandLine = executionContext. commandLine
216+
217+ String profileName = evaluateProfileName(commandLine)
218+
219+ boolean inPlace = commandLine. hasOption(' inplace' ) || GrailsCli . isInteractiveModeActive()
220+ String appName = commandLine. remainingArgs ? commandLine. remainingArgs[0 ] : " "
221+
222+ List<String > features = commandLine. optionValue(" features" )?. toString()?. split(' ,' )?. toList()
223+
224+ CreateAppCommandObject cmd = new CreateAppCommandObject (
225+ appName : appName,
226+ baseDir : executionContext. baseDir,
227+ profileName : profileName,
228+ grailsVersion : Environment . getPackage(). getImplementationVersion() ?: GRAILS_VERSION_FALLBACK_IN_IDE_ENVIRONMENTS_FOR_RUNNING_TESTS ,
229+ features : features,
230+ inplace : inPlace
231+ )
232+
233+ return this . handle(cmd)
234+ }
235+
236+ protected boolean validateProfile (Profile profileInstance , String profileName ) {
205237 if (profileInstance == null ) {
206- executionContext . console . error(" Profile not found for name [$profileName ]" )
238+ GrailsConsole . instance . error(" Profile not found for name [$profileName ]" )
207239 return false
208240 }
209241 return true
210242 }
211243
212244 private Map<URL , File > unzippedDirectories = new LinkedHashMap<URL , File > ()
245+
213246 @CompileDynamic
214247 protected File unzipProfile (AntBuilder ant , Resource location ) {
215248
@@ -313,15 +346,15 @@ class CreateAppCommand extends ArgumentCompletingCommand implements ProfileRepos
313346 mainCommandLine. optionValue(' profile' )?. toString() ?: getDefaultProfile()
314347 }
315348
316- protected Iterable<Feature > evaluateFeatures (Profile profile , CommandLine commandLine ) {
317- String [] requestedFeatures = commandLine. optionValue(" features" )?. toString()?. split(' ,' )
318- if (requestedFeatures) {
319- List<String > requestedFeaturesList = requestedFeatures. toList()
349+ protected Iterable<Feature > evaluateFeatures (Profile profile , List<String > requestedFeatures ) {
350+ if (requestedFeatures) {
320351 List<String > allFeatureNames = profile. features* . name
321- List<String > validFeatureNames = requestedFeaturesList. intersect(allFeatureNames)
322- requestedFeaturesList. removeAll(allFeatureNames)
323- requestedFeaturesList. each { String invalidFeature ->
324- List possibleSolutions = allFeatureNames. findAll { it. substring(0 , 2 ) == invalidFeature. substring(0 , 2 ) }
352+ List<String > validFeatureNames = requestedFeatures. intersect(allFeatureNames)
353+ requestedFeatures. removeAll(allFeatureNames)
354+ requestedFeatures. each { String invalidFeature ->
355+ List possibleSolutions = allFeatureNames. findAll {
356+ it. substring(0 , 2 ) == invalidFeature. substring(0 , 2 )
357+ }
325358 StringBuilder warning = new StringBuilder (" Feature ${ invalidFeature} does not exist in the profile ${ profile.name} !" )
326359 if (possibleSolutions) {
327360 warning. append(" Possible solutions: " )
@@ -340,7 +373,6 @@ class CreateAppCommand extends ArgumentCompletingCommand implements ProfileRepos
340373 ProfileRepository . DEFAULT_PROFILE_NAME
341374 }
342375
343-
344376 private void appendToYmlSubDocument (File applicationYmlFile , String previousApplicationYml ) {
345377 String newApplicationYml = applicationYmlFile. text
346378 if (previousApplicationYml && newApplicationYml != previousApplicationYml) {
@@ -353,49 +385,45 @@ class CreateAppCommand extends ArgumentCompletingCommand implements ProfileRepos
353385 applicationYmlFile. text = appended. toString()
354386 }
355387 }
356-
357- protected boolean initializeVariables (Profile profile , CommandLine commandLine ) {
358- String defaultPackage
359388
360- def args = commandLine. getRemainingArgs()
361- boolean inPlace = commandLine. hasOption(' inplace' ) || GrailsCli . isInteractiveModeActive()
362-
363- if (! args && ! inPlace) {
389+ protected boolean initializeGroupAndName (String appName , boolean inplace ) {
390+ if (! appName && ! inplace) {
364391 GrailsConsole . getInstance(). error(" Specify an application name or use --inplace to create an application in the current directory" )
365392 return false
366393 }
367- String groupAndAppName = args ? args[ 0 ] : null
368- if (inPlace ) {
394+ String groupAndAppName = appName
395+ if (inplace ) {
369396 appname = new File (" ." ). canonicalFile. name
370397 if (! groupAndAppName) {
371398 groupAndAppName = appname
372399 }
373400 }
374-
401+
375402 if (! groupAndAppName) {
376403 GrailsConsole . getInstance(). error(" Specify an application name or use --inplace to create an application in the current directory" )
377404 return false
378405 }
379406
380407 try {
381- defaultPackage = establishGroupAndAppName(groupAndAppName)
408+ defaultpackagename = establishGroupAndAppName(groupAndAppName)
382409 } catch (IllegalArgumentException e ) {
383410 GrailsConsole . instance. error(e. message)
384411 return false
385412 }
413+ }
386414
387-
415+ private void initializeVariables ( String appname , String defaultPackage , String profileName , String grailsVersion ) {
388416 variables. APPNAME = appname
389417
390418 variables[' grails.codegen.defaultPackage' ] = defaultPackage
391- variables[' grails.codegen.defaultPackage.path' ] = defaultPackage. replace(' .' , ' /' )
419+ variables[' grails.codegen.defaultPackage.path' ] = defaultPackage. replace(' .' , ' /' )
392420
393421 def projectClassName = GrailsNameUtils . getNameFromScript(appname)
394422 variables[' grails.codegen.projectClassName' ] = projectClassName
395423 variables[' grails.codegen.projectNaturalName' ] = GrailsNameUtils . getNaturalName(projectClassName)
396424 variables[' grails.codegen.projectName' ] = GrailsNameUtils . getScriptName(projectClassName)
397- variables[' grails.profile' ] = profile . name
398- variables[' grails.version' ] = Environment . getPackage() . getImplementationVersion() ?: GRAILS_VERSION_FALLBACK_IN_IDE_ENVIRONMENTS_FOR_RUNNING_TESTS
425+ variables[' grails.profile' ] = profileName
426+ variables[' grails.version' ] = grailsVersion
399427 variables[' grails.app.name' ] = appname
400428 variables[' grails.app.group' ] = groupname
401429 }
@@ -416,7 +444,7 @@ class CreateAppCommand extends ArgumentCompletingCommand implements ProfileRepos
416444 }
417445
418446 private String createValidPackageName () {
419- String defaultPackage = appname. split(/ [-]+/ ). collect { String token -> (token. toLowerCase(). toCharArray(). findAll { char ch -> Character . isJavaIdentifierPart(ch) } as char []) as String }. join(' .' )
447+ String defaultPackage = appname. split(/ [-]+/ ). collect { String token -> (token. toLowerCase(). toCharArray(). findAll { char ch -> Character . isJavaIdentifierPart(ch) } as char []) as String }. join(' .' )
420448 if (! GrailsNameUtils . isValidJavaPackage(defaultPackage)) {
421449 throw new IllegalArgumentException (" Cannot create a valid package name for [$appname ]. Please specify a name that is also a valid Java package." )
422450 }
@@ -522,4 +550,13 @@ class CreateAppCommand extends ArgumentCompletingCommand implements ProfileRepos
522550
523551 return v ? " ${ artifact.groupId} :${ artifact.artifactId} :${ v} " : " ${ artifact.groupId} :${ artifact.artifactId} "
524552 }
553+
554+ static class CreateAppCommandObject {
555+ String appName
556+ File baseDir
557+ String profileName
558+ String grailsVersion
559+ List<String > features
560+ boolean inplace = false
561+ }
525562}
0 commit comments