SettingsPlugin.groovy
001 /*
002  * SPDX-License-Identifier: Apache-2.0
003  *
004  * Copyright 2018-2019 Andres Almiray.
005  *
006  * Licensed under the Apache License, Version 2.0 (the "License");
007  * you may not use this file except in compliance with the License.
008  * You may obtain a copy of the License at
009  *
010  *     http://www.apache.org/licenses/LICENSE-2.0
011  *
012  * Unless required by applicable law or agreed to in writing, software
013  * distributed under the License is distributed on an "AS IS" BASIS,
014  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015  * See the License for the specific language governing permissions and
016  * limitations under the License.
017  */
018 package org.kordamp.gradle.plugin.settings
019 
020 import groovy.transform.CompileStatic
021 import org.gradle.BuildAdapter
022 import org.gradle.api.Plugin
023 import org.gradle.api.initialization.Settings
024 
025 /**
026  @author Andres Almiray
027  @since 0.15.0
028  */
029 @CompileStatic
030 class SettingsPlugin implements Plugin<Settings> {
031     private Settings settings
032 
033     @Override
034     void apply(Settings settings) {
035         this.settings = settings
036 
037         if (!settings.extensions.findByType(ProjectsExtension)) {
038             settings.extensions.create(ProjectsExtension.EXTENSION_NAME, ProjectsExtension)
039         }
040 
041         settings.gradle.addBuildListener(new BuildAdapter() {
042             @Override
043             void settingsEvaluated(Settings s) {
044                 ProjectsExtension projects = (ProjectsExtensionsettings.extensions.findByName(ProjectsExtension.EXTENSION_NAME)
045 
046                 if ('two-level' == projects.layout?.toLowerCase()) {
047                     processTwoLevelLayout()
048                 else if ('multi-level' == projects.layout?.toLowerCase()) {
049                     processMultiLevelLayout()
050                 else if ('standard' == projects.layout?.toLowerCase()) {
051                     processStandardLayout()
052                 else {
053                     println "Unknown project layout '${projects.layout}'. No subprojects will be added."
054                 }
055             }
056         })
057     }
058 
059     private void processTwoLevelLayout() {
060         ProjectsExtension projects = (ProjectsExtensionsettings.extensions.findByName(ProjectsExtension.EXTENSION_NAME)
061 
062         if (projects.directories) {
063             for (String parentDirName : projects.directories) {
064                 File parentDir = new File(settings.rootDir, parentDirName)
065                 if (!parentDir.exists()) {
066                     println "Skipping ${parentDir} as it does not exist"
067                     continue
068                 }
069 
070                 doProcessTwoLevelLayout(projects, parentDir)
071             }
072         else {
073             settings.settingsDir.eachDir File parentDir ->
074                 doProcessTwoLevelLayout(projects, parentDir)
075             }
076         }
077     }
078 
079     private void doProcessTwoLevelLayout(ProjectsExtension projects, File parentDir) {
080         parentDir.eachDir File projectDir ->
081             if (projects.excludes.contains(projectDir.name)) return
082 
083             File buildFile = resolveBuildFile(projects, projectDir, projectDir.name)
084             SettingsPlugin.doIncludeProject(settings, parentDir, projectDir.name, buildFile)
085         }
086     }
087 
088     private void processMultiLevelLayout() {
089         ProjectsExtension projects = (ProjectsExtensionsettings.extensions.findByName(ProjectsExtension.EXTENSION_NAME)
090 
091         for (String path : projects.directories) {
092             File projectDir = new File(settings.rootDir, path)
093             if (!projectDir.exists()) {
094                 println "Skipping ${projectDir} as it does not exist"
095                 continue
096             }
097             SettingsPlugin.includeProject(settings, path)
098         }
099     }
100 
101     private void processStandardLayout() {
102         ProjectsExtension projects = (ProjectsExtensionsettings.extensions.findByName(ProjectsExtension.EXTENSION_NAME)
103 
104         settings.rootDir.eachDir File projectDir ->
105             if (projects.excludes.contains(projectDir.name)) return
106 
107             File buildFile = resolveBuildFile(projects, projectDir, projectDir.name)
108             SettingsPlugin.doIncludeProject(settings, settings.rootDir, projectDir.name, buildFile)
109         }
110     }
111 
112     static void includeProject(Settings settings, File parentDir, String projectDirName) {
113         ProjectsExtension projects = (ProjectsExtensionsettings.extensions.findByName(ProjectsExtension.EXTENSION_NAME)
114 
115         File buildFile = resolveBuildFile(projects, parentDir, projectDirName)
116         doIncludeProject(settings, settings.rootDir, parentDir.name, buildFile)
117     }
118 
119     static void includeProject(Settings settings, File projectDir) {
120         includeProject(settings, projectDir.parentFile, projectDir.name)
121     }
122 
123     static void includeProject(Settings settings, String projectPath) {
124         ProjectsExtension projects = (ProjectsExtensionsettings.extensions.findByName(ProjectsExtension.EXTENSION_NAME)
125 
126         String[] parts = projectPath.split('/')
127         String projectDirName = projectPath
128         String projectName = parts[-1]
129 
130         if (projects.excludes.contains(projectName)) return
131 
132         File projectDir = new File(projectDirName)
133 
134         assert projectDir.isDirectory()
135 
136         File buildFile = resolveBuildFile(projects, projectDir, projectName)
137         if (buildFile.exists()) {
138             settings.include(projectName)
139             settings.project(":${projectName}").projectDir = projectDir
140             settings.project(":${projectName}").buildFileName = buildFile.name
141         }
142     }
143 
144     private static File resolveBuildFile(ProjectsExtension projects, File projectDir, String projectName) {
145         if (projects.enforceNamingConvention) {
146             if ('add'.equalsIgnoreCase(projects.fileNameTransformation)) {
147                 if (!isBlank(projects.prefix)) {
148                     projectName = projects.prefix + projectName
149                 }
150                 if (!isBlank(projects.suffix)) {
151                     projectName += projects.suffix
152                 }
153             else if ('remove'.equalsIgnoreCase(projects.fileNameTransformation)) {
154                 if (!isBlank(projects.prefix)) {
155                     projectName -= projects.prefix
156                 }
157                 if (!isBlank(projects.suffix)) {
158                     projectName -= projects.suffix
159                 }
160             }
161         }
162 
163         File buildFile = new File(projectDir, projects.enforceNamingConvention ? "${projectName}.gradle".toString() 'build.gradle')
164         if (!buildFile.exists()) {
165             buildFile = new File(projectDir, projects.enforceNamingConvention ? "${projectName}.gradle.kts".toString() 'build.gradle.kts')
166         }
167         buildFile
168     }
169 
170     private static void doIncludeProject(Settings settings, File parentDir, String projectDirName, File buildFile) {
171         if (buildFile.exists()) {
172             File projectDir = new File(parentDir, projectDirName)
173 
174             settings.include(projectDirName)
175             settings.project(":${projectDirName}").projectDir = projectDir
176             settings.project(":${projectDirName}").buildFileName = buildFile.name
177         }
178     }
179 
180     private static boolean isBlank(String str) {
181         if (str == null || str.length() == 0) {
182             return true
183         }
184         for (char c : str.toCharArray()) {
185             if (!Character.isWhitespace(c)) {
186                 return false
187             }
188         }
189 
190         return true
191     }
192 }