All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
io.micronaut.cli.profile.AbstractProfile.groovy Maven / Gradle / Ivy
/*
* Copyright 2017-2019 original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.micronaut.cli.profile
import groovy.transform.CompileStatic
import groovy.transform.ToString
import groovy.transform.TypeCheckingMode
import io.micronaut.cli.config.NavigableMap
import io.micronaut.cli.console.parsing.ScriptNameResolver
import io.micronaut.cli.interactive.completers.StringsCompleter
import io.micronaut.cli.io.IOUtils
import io.micronaut.cli.io.support.Resource
import io.micronaut.cli.profile.commands.CommandRegistry
import io.micronaut.cli.profile.commands.PicocliCompleter
import io.micronaut.cli.profile.commands.script.GroovyScriptCommand
import io.micronaut.cli.util.CliSettings
import io.micronaut.cli.util.CosineSimilarity
import io.micronaut.cli.util.VersionInfo
import jline.console.completer.Completer
import org.eclipse.aether.artifact.DefaultArtifact
import org.eclipse.aether.graph.Dependency
import org.eclipse.aether.graph.Exclusion
import org.eclipse.aether.util.graph.selector.ExclusionDependencySelector
import org.yaml.snakeyaml.Yaml
import picocli.CommandLine
/**
* Abstract implementation of the profile class
*
* @author Graeme Rocher
* @since 1.0
*/
@CompileStatic
@ToString(includes = ['name'])
abstract class AbstractProfile implements Profile {
protected final Resource profileDir
protected String name
protected List parentProfiles
protected Map commandsByName
protected NavigableMap navigableConfig
protected ProfileRepository profileRepository
protected List dependencies = []
protected List repositories = []
protected List jvmArgs = []
protected List parentNames = []
protected List buildRepositories = []
protected List buildPlugins = []
protected List buildExcludes = []
protected List skeletonExcludes = []
protected List binaryExtensions = []
protected List executablePatterns = []
protected final List internalCommands = []
protected List buildMerge = null
protected List features = []
protected Set defaultFeaturesNames = []
protected Set requiredFeatureNames = []
protected List oneOfFeatureGroups = []
protected String parentTargetFolder
protected final ClassLoader classLoader
protected ExclusionDependencySelector exclusionDependencySelector = new ExclusionDependencySelector()
protected String description = ""
protected String instructions = ""
protected String version = VersionInfo.getVersion(CliSettings)
protected Boolean abstractProfile = false
AbstractProfile(Resource profileDir) {
this(profileDir, AbstractProfile.getClassLoader())
}
AbstractProfile(Resource profileDir, ClassLoader classLoader) {
this.classLoader = classLoader
this.profileDir = profileDir
def url = profileDir.getURL()
def jarFile = IOUtils.findJarFile(url)
def pattern = ~/.+-(\d.+)\.jar/
def path
if (jarFile != null) {
path = jarFile.name
} else if (url != null) {
def p = url.path
path = p.substring(0, p.indexOf('.jar') + 4)
}
if (path) {
def matcher = pattern.matcher(path)
if (matcher.matches()) {
this.version = matcher.group(1)
}
}
}
String getVersion() {
return version
}
protected void initialize() {
def profileYml = profileDir.createRelative("profile.yml")
def profileConfig = (Map) new Yaml().loadAs(profileYml.getInputStream(), Map)
name = profileConfig.get("name")?.toString()
description = profileConfig.get("description")?.toString() ?: ''
instructions = profileConfig.get("instructions")?.toString() ?: ''
abstractProfile = Boolean.valueOf(profileConfig.get("abstract")?.toString() ?: '')
def parents = profileConfig.get("extends")
if (parents) {
parentNames = parents.toString().split(',').collect() { String name -> name.trim() }
}
if (this.name == null) {
throw new IllegalStateException("Profile name not set. Profile for path ${profileDir.URL} is invalid")
}
def map = new NavigableMap()
map.merge(profileConfig)
navigableConfig = map
def commandsByName = profileConfig.get("commands")
if (commandsByName instanceof Map) {
def commandsMap = (Map) commandsByName
for (clsName in commandsMap.keySet()) {
def fileName = commandsMap[clsName].toString()
if (fileName.endsWith(".groovy")) {
GroovyScriptCommand cmd = (GroovyScriptCommand) classLoader.loadClass(clsName.toString()).newInstance()
cmd.profile = this
cmd.profileRepository = profileRepository
internalCommands.add cmd
}
}
}
def featuresConfig = profileConfig.get("features")
if (featuresConfig instanceof Map) {
Map featureMap = (Map) featuresConfig
def featureList = (List) featureMap.get("provided") ?: Collections.emptyList()
def defaultFeatures = (List) featureMap.get("defaults") ?: Collections.emptyList()
def requiredFeatures = (List) featureMap.get("required") ?: Collections.emptyList()
def oneOfFeaturesMap = (Map) featureMap.get("oneOf") ?: Collections.emptyMap()
for (fn in featureList) {
def featureData = profileDir.createRelative("features/${fn}/feature.yml")
if (featureData.exists()) {
def f = new DefaultFeature(this, fn.toString(), profileDir.createRelative("features/$fn/"))
features.add f
}
}
for (Map.Entry entry: oneOfFeaturesMap.entrySet()) {
List oneOfFeatures = []
def group = new OneOfFeatureGroup(name: entry.getKey().toString(), oneOfFeaturesData: oneOfFeatures)
if (entry.getValue() instanceof List) {
for (feature in (List) entry.getValue()) {
if (feature instanceof Map) {
String name = (String) feature.feature
Integer priority = (Integer) feature.priority
oneOfFeatures.add([name: name, priority: priority])
}
}
}
oneOfFeatureGroups.add(group)
}
defaultFeaturesNames.addAll(defaultFeatures)
requiredFeatureNames.addAll(requiredFeatures)
}
def dependencyMap = profileConfig.get("dependencies")
if (dependencyMap instanceof List) {
List exclusions = []
for (entry in ((List) dependencyMap)) {
if (entry instanceof Map) {
def scope = (String) entry.scope
String coords = (String) entry.coords
if ("excludes".equals(scope)) {
def artifact = new DefaultArtifact(coords)
exclusions.add new Exclusion(artifact.groupId ?: null, artifact.artifactId ?: null, artifact.classifier ?: null, artifact.extension ?: null)
} else {
if (coords.count(':') == 1) {
coords = "$coords:BOM"
}
Dependency dependency = new Dependency(new DefaultArtifact(coords), scope.toString())
if (entry.containsKey('excludes')) {
List dependencyExclusions = new ArrayList<>()
List excludes = (List) entry.excludes
for (ex in excludes) {
if (ex instanceof Map) {
dependencyExclusions.add(new Exclusion((String) ex.group, (String) ex.module, (String) ex.classifier, (String) ex.extension))
}
}
dependency = dependency.setExclusions(dependencyExclusions)
}
dependencies.add(dependency)
}
}
exclusionDependencySelector = new ExclusionDependencySelector(exclusions)
}
}
this.repositories = (List) navigableConfig.get("repositories", [])
this.jvmArgs = (List) navigableConfig.get("jvmArgs", [])
this.buildRepositories = (List) navigableConfig.get("build.repositories", [])
this.buildPlugins = (List) navigableConfig.get("build.plugins", [])
this.buildExcludes = (List) navigableConfig.get("build.excludes", [])
this.buildMerge = (List) navigableConfig.get("build.merge", null)
this.parentTargetFolder = (String) navigableConfig.get("skeleton.parent.target", null)
this.skeletonExcludes = (List) navigableConfig.get("skeleton.excludes", [])
this.binaryExtensions = (List) navigableConfig.get("skeleton.binaryExtensions", [])
this.executablePatterns = (List) navigableConfig.get("skeleton.executable", [])
}
boolean isAbstract() {
abstractProfile
}
String getDescription() {
description
}
String getInstructions() {
instructions
}
Set getBinaryExtensions() {
Set calculatedBinaryExtensions = []
def parents = getExtends()
for (profile in parents) {
calculatedBinaryExtensions.addAll(profile.binaryExtensions)
}
calculatedBinaryExtensions.addAll(binaryExtensions)
return calculatedBinaryExtensions
}
Set getExecutablePatterns() {
Set calculatedExecutablePatterns = []
def parents = getExtends()
for (profile in parents) {
calculatedExecutablePatterns.addAll(profile.executablePatterns)
}
calculatedExecutablePatterns.addAll(executablePatterns)
return calculatedExecutablePatterns
}
@Override
Iterable getDefaultFeatures() {
getFeatures().findAll() { Feature f -> defaultFeaturesNames.contains(f.name) }
}
@Override
@CompileStatic(TypeCheckingMode.SKIP)
Iterable getOneOfFeatures() {
List features = getFeatures().toList()
oneOfFeatureGroups.each {
it.initialize(features)
}
oneOfFeatureGroups
}
@Override
Iterable getRequiredFeatures() {
def requiredFeatureInstances = getFeatures().findAll() { Feature f -> requiredFeatureNames.contains(f.name) }
if (requiredFeatureInstances.size() != requiredFeatureNames.size()) {
throw new IllegalStateException("One or more required features were not found on the classpath. Required features: $requiredFeatureNames")
}
return requiredFeatureInstances
}
@Override
Iterable getFeatures() {
Set calculatedFeatures = new LinkedHashSet()
calculatedFeatures.addAll(features)
def parents = getExtends()
for (profile in parents) {
calculatedFeatures.addAll profile.features
}
return calculatedFeatures
}
@Override
List getBuildMergeProfileNames() {
if (buildMerge != null) {
return this.buildMerge
} else {
List mergeNames = []
for (parent in getExtends()) {
mergeNames.add(parent.name)
}
mergeNames.add(name)
return mergeNames
}
}
@Override
List getBuildRepositories() {
List calculatedRepositories = []
if (buildRepositories.empty) {
def parents = getExtends()
for (profile in parents) {
calculatedRepositories.addAll(profile.buildRepositories)
}
} else {
calculatedRepositories.addAll(buildRepositories)
}
return calculatedRepositories
}
@Override
List getBuildPlugins() {
List calculatedPlugins = []
def parents = getExtends()
for (profile in parents) {
def dependencies = profile.buildPlugins
for (dep in dependencies) {
if (!buildExcludes.contains(dep))
calculatedPlugins.add(dep)
}
}
calculatedPlugins.addAll(buildPlugins)
return calculatedPlugins
}
@Override
List getRepositories() {
List calculatedRepositories = []
if (repositories.empty) {
def parents = getExtends()
for (profile in parents) {
calculatedRepositories.addAll(profile.repositories)
}
} else {
calculatedRepositories.addAll(repositories)
}
return calculatedRepositories
}
@Override
List getJvmArgs() {
jvmArgs
}
List getDependencies() {
List calculatedDependencies = []
def parents = getExtends()
for (profile in parents) {
def dependencies = profile.dependencies
for (dep in dependencies) {
if (exclusionDependencySelector.selectDependency(dep)) {
calculatedDependencies.add(dep)
}
}
}
calculatedDependencies.addAll(dependencies)
return calculatedDependencies
}
ProfileRepository getProfileRepository() {
return profileRepository
}
void setProfileRepository(ProfileRepository profileRepository) {
this.profileRepository = profileRepository
}
Resource getProfileDir() {
return profileDir
}
@Override
NavigableMap getConfiguration() {
navigableConfig
}
@Override
Resource getTemplate(String path) {
return profileDir.createRelative("templates/$path")
}
@Override
Iterable getExtends() {
return parentNames.collect() { String name ->
def parent = profileRepository.getProfile(name, true)
if (parent == null) {
throw new IllegalStateException("Profile [$name] declares an invalid dependency on parent profile [$name]")
}
return parent
}
}
@Override
Iterable getCompleters(io.micronaut.cli.profile.ProjectContext context) {
def commands = getCommands(context)
Collection completers = []
for (Command cmd in commands) {
completers << new StringsCompleter(cmd.name) // commandNameCompleter
completers << new PicocliCompleter(cmd.commandSpec)
}
return completers
}
@Override
Command getCommand(io.micronaut.cli.profile.ProjectContext context, String name) {
getCommands(context)
return commandsByName[name]
}
@Override
Iterable getCommands(io.micronaut.cli.profile.ProjectContext context) {
if (commandsByName == null) {
commandsByName = new LinkedHashMap()
List excludes = []
def registerCommand = { Command command ->
new CommandLine(command) // initialize @Spec
def name = command.name
if (!commandsByName.containsKey(name) && !excludes.contains(name)) {
if (command instanceof ProfileRepositoryAware) {
((ProfileRepositoryAware) command).setProfileRepository(profileRepository)
}
commandsByName.put(name, command)
def desc = command.commandSpec
def synonyms = desc?.aliases()
if (synonyms) {
for(String syn in synonyms) {
commandsByName.put(syn, command)
}
}
if (command instanceof ProjectContextAware) {
((ProjectContextAware) command).projectContext = context
}
if (command instanceof ProfileCommand) {
((ProfileCommand) command).profile = this
}
}
}
CommandRegistry.findCommands(this).each(registerCommand)
def parents = getExtends()
if (parents) {
excludes = (List) configuration.navigate("command", "excludes") ?: []
registerParentCommands(context, parents, registerCommand)
}
}
return commandsByName.values()
}
protected void registerParentCommands(ProjectContext context, Iterable parents, Closure registerCommand) {
for (parent in parents) {
parent.getCommands(context).each registerCommand
def extended = parent.extends
if (extended) {
registerParentCommands context, extended, registerCommand
}
}
}
@Override
boolean hasCommand(io.micronaut.cli.profile.ProjectContext context, String name) {
getCommands(context) // ensure initialization
return commandsByName.containsKey(name)
}
@Override
boolean handleCommand(io.micronaut.cli.profile.ExecutionContext context) {
def parseResult = context.parseResult
while (parseResult.hasSubcommand()) { parseResult = parseResult.subcommand() }
Command cmd = parseResult.commandSpec().userObject() as Command
boolean result = cmd.handle(context)
if (cmd instanceof ResetableCommand) {
cmd.reset()
}
return result
}
@Override
String getParentSkeletonDir() {
this.parentTargetFolder
}
@Override
File getParentSkeletonDir(File parent) {
if (parentSkeletonDir) {
new File(parent, parentSkeletonDir)
} else {
parent
}
}
List getSkeletonExcludes() {
this.skeletonExcludes
}
}