Skip to content

Commit

Permalink
Merge pull request #12401 from gradle/bamboo/release/ie/composite-gra…
Browse files Browse the repository at this point in the history
…dle-properties

Make Gradle properties available to settings scripts
  • Loading branch information
bamboo committed Mar 4, 2020
2 parents 50234ac + d4eff18 commit 7d0bf6d
Show file tree
Hide file tree
Showing 17 changed files with 470 additions and 29 deletions.
@@ -0,0 +1,65 @@
/*
* Copyright 2020 the original author or 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 org.gradle.integtests.composite

import org.gradle.integtests.fixtures.AbstractIntegrationSpec
import org.gradle.integtests.fixtures.executer.GradleContextualExecuter
import spock.lang.IgnoreIf

@IgnoreIf({ GradleContextualExecuter.isInstant() })
class CompositeBuildPropertiesIntegrationTest extends AbstractIntegrationSpec {

def "included build properties take precedence over root build properties"() {
given:
def createBuild = { String buildName, String dir ->
createDir(dir) {
file("gradle.properties") << """
theProperty=$buildName
"""
file("settings.gradle") << """
println("$buildName settings script: " + theProperty)
"""
file("build.gradle") << """
println("$buildName build script: " + theProperty)
"""
}
}

createBuild "root", "."
settingsFile << """
includeBuild 'included'
"""

createBuild "included", "included"
file("included/settings.gradle") << """
includeBuild '../nested'
"""

createBuild "nested", "nested"

when:
run('help')

then:
outputContains("root settings script: root")
outputContains("root build script: root")
outputContains("included settings script: included")
outputContains("included build script: included")
outputContains("nested settings script: nested")
outputContains("nested build script: nested")
}
}
Expand Up @@ -29,6 +29,11 @@ class DistributionPropertiesLoaderIntegrationTest extends AbstractIntegrationSpe
settingsFile << '''
includeBuild 'includedBuild'
println("system_property_available in settings.gradle: ${System.getProperty('system_property_available', 'false')} ")
try {
println("project_property_available in settings.gradle: ${project_property_available} ")
} catch (MissingPropertyException e) {
println("project_property_available in settings.gradle: false ")
}
'''
buildFile << '''
println("system_property_available in root: ${System.getProperty('system_property_available', 'false')} ")
Expand All @@ -45,6 +50,11 @@ class DistributionPropertiesLoaderIntegrationTest extends AbstractIntegrationSpe
'''
file('includedBuild/settings.gradle') << '''
println("system_property_available in included settings.gradle: ${System.getProperty('system_property_available', 'false')} ")
try {
println("project_property_available in included settings.gradle:${project_property_available} ")
} catch (MissingPropertyException e) {
println("project_property_available in included settings.gradle:false ")
}
'''
file('includedBuild/buildSrc/build.gradle') << '''
println("system_property_available in included buildSrc: ${System.getProperty('system_property_available', 'false')} ")
Expand All @@ -61,15 +71,17 @@ class DistributionPropertiesLoaderIntegrationTest extends AbstractIntegrationSpe
then:
outputContains('system_property_available in buildSrc: true')
outputContains('system_property_available in buildSrc: true')
outputContains('project_property_available in buildSrc: true')
outputContains('project_property_available in buildSrc: false')
outputContains('system_property_available in included buildSrc: true')
outputContains('project_property_available in included buildSrc: true')
outputContains('project_property_available in included buildSrc: false')
outputContains('system_property_available in included root: true')
outputContains('project_property_available in included root: true')
outputContains('project_property_available in included root: false')
outputContains('system_property_available in root: true')
outputContains('project_property_available in root: true')
outputContains('system_property_available in settings.gradle: true')
outputContains('project_property_available in settings.gradle: true')
outputContains('system_property_available in included settings.gradle: true')
outputContains('project_property_available in included settings.gradle:false')

cleanup:
executer.withArguments("--stop", "--info").run()
Expand Down
@@ -0,0 +1,114 @@
/*
* Copyright 2020 the original author or 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 org.gradle.initialization;

import org.gradle.api.internal.properties.GradleProperties;

import javax.annotation.Nullable;
import java.io.File;
import java.util.Map;

public class DefaultGradlePropertiesController implements GradlePropertiesController {

private State state = new NotLoaded();
private final GradleProperties sharedGradleProperties = new SharedGradleProperties();
private final IGradlePropertiesLoader propertiesLoader;

public DefaultGradlePropertiesController(IGradlePropertiesLoader propertiesLoader) {
this.propertiesLoader = propertiesLoader;
}

@Override
public GradleProperties getGradleProperties() {
return sharedGradleProperties;
}

@Override
public void loadGradlePropertiesFrom(File settingsDir) {
state = state.loadGradlePropertiesFrom(settingsDir);
}

private class SharedGradleProperties implements GradleProperties {

@Nullable
@Override
public String find(String propertyName) {
return gradleProperties().find(propertyName);
}

@Override
public Map<String, String> mergeProperties(Map<String, String> properties) {
return gradleProperties().mergeProperties(properties);
}

private GradleProperties gradleProperties() {
return state.gradleProperties();
}
}

private interface State {

GradleProperties gradleProperties();

State loadGradlePropertiesFrom(File settingsDir);
}

private class NotLoaded implements State {

@Override
public GradleProperties gradleProperties() {
throw new IllegalStateException("GradleProperties has not been loaded yet.");
}

@Override
public State loadGradlePropertiesFrom(File settingsDir) {
return new Loaded(
propertiesLoader.loadGradleProperties(settingsDir),
settingsDir
);
}
}

private static class Loaded implements State {

private final GradleProperties gradleProperties;
private final File propertiesDir;

public Loaded(GradleProperties gradleProperties, File propertiesDir) {
this.gradleProperties = gradleProperties;
this.propertiesDir = propertiesDir;
}

@Override
public GradleProperties gradleProperties() {
return gradleProperties;
}

@Override
public State loadGradlePropertiesFrom(File settingsDir) {
if (!propertiesDir.equals(settingsDir)) {
throw new IllegalStateException(
String.format(
"GradleProperties has already been loaded from '%s' and cannot be loaded from '%s'.",
propertiesDir, settingsDir
)
);
}
return this;
}
}
}
Expand Up @@ -36,16 +36,25 @@ public class DefaultSettingsLoader implements SettingsLoader {
public static final String BUILD_SRC_PROJECT_PATH = ":" + SettingsInternal.BUILD_SRC;
private SettingsProcessor settingsProcessor;
private final BuildLayoutFactory buildLayoutFactory;
private final GradlePropertiesController gradlePropertiesController;

public DefaultSettingsLoader(SettingsProcessor settingsProcessor, BuildLayoutFactory buildLayoutFactory) {
public DefaultSettingsLoader(
SettingsProcessor settingsProcessor,
BuildLayoutFactory buildLayoutFactory,
GradlePropertiesController gradlePropertiesController
) {
this.settingsProcessor = settingsProcessor;
this.buildLayoutFactory = buildLayoutFactory;
this.gradlePropertiesController = gradlePropertiesController;
}

@Override
public SettingsInternal findAndLoadSettings(GradleInternal gradle) {
StartParameter startParameter = gradle.getStartParameter();

SettingsLocation settingsLocation = buildLayoutFactory.getLayoutFor(new BuildLayoutConfiguration(startParameter));
loadGradlePropertiesFrom(settingsLocation);

SettingsInternal settings = findSettingsAndLoadIfAppropriate(gradle, startParameter, settingsLocation, gradle.getClassLoaderScope());
ProjectSpec spec = ProjectSpecs.forStartParameter(startParameter, settings);
if (useEmptySettings(spec, settings, startParameter)) {
Expand All @@ -56,6 +65,12 @@ public SettingsInternal findAndLoadSettings(GradleInternal gradle) {
return settings;
}

private void loadGradlePropertiesFrom(SettingsLocation settingsLocation) {
gradlePropertiesController.loadGradlePropertiesFrom(
settingsLocation.getSettingsDir()
);
}

private boolean useEmptySettings(ProjectSpec spec, SettingsInternal loadedSettings, StartParameter startParameter) {
// Never use empty settings when the settings were explicitly set
if (startParameter.getSettingsFile() != null) {
Expand Down
Expand Up @@ -32,14 +32,24 @@ public class DefaultSettingsLoaderFactory implements SettingsLoaderFactory {
private final PublicBuildPath publicBuildPath;
private final Instantiator instantiator;
private final BuildLayoutFactory buildLayoutFactory;
private final GradlePropertiesController gradlePropertiesController;

public DefaultSettingsLoaderFactory(SettingsProcessor settingsProcessor, BuildStateRegistry buildRegistry, ProjectStateRegistry projectRegistry, PublicBuildPath publicBuildPath, Instantiator instantiator, BuildLayoutFactory buildLayoutFactory) {
public DefaultSettingsLoaderFactory(
SettingsProcessor settingsProcessor,
BuildStateRegistry buildRegistry,
ProjectStateRegistry projectRegistry,
PublicBuildPath publicBuildPath,
Instantiator instantiator,
BuildLayoutFactory buildLayoutFactory,
GradlePropertiesController gradlePropertiesController
) {
this.settingsProcessor = settingsProcessor;
this.buildRegistry = buildRegistry;
this.projectRegistry = projectRegistry;
this.publicBuildPath = publicBuildPath;
this.instantiator = instantiator;
this.buildLayoutFactory = buildLayoutFactory;
this.gradlePropertiesController = gradlePropertiesController;
}

@Override
Expand Down Expand Up @@ -68,7 +78,12 @@ public SettingsLoader forNestedBuild() {

private SettingsLoader defaultSettingsLoader() {
return new SettingsAttachingSettingsLoader(
new DefaultSettingsLoader(settingsProcessor, buildLayoutFactory),
projectRegistry);
new DefaultSettingsLoader(
settingsProcessor,
buildLayoutFactory,
gradlePropertiesController
),
projectRegistry
);
}
}
@@ -0,0 +1,45 @@
/*
* Copyright 2020 the original author or 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 org.gradle.initialization;

import org.gradle.api.internal.properties.GradleProperties;

import java.io.File;

/**
* Controls the state (not loaded / loaded) of the attached {@link GradleProperties} instance
* so that the set of Gradle properties is deterministically loaded only once per build.
*/
public interface GradlePropertiesController {

/**
* The {@link GradleProperties} instance attached to this service.
*/
GradleProperties getGradleProperties();

/**
* Loads the immutable set of {@link GradleProperties} from the given directory and
* makes it available to the build.
*
* This method should be called only once per build but multiple calls with the
* same argument are allowed.
*
* @param settingsDir directory where to look for the {@code gradle.properties} file
* @throws IllegalStateException if called with a different argument in the same build
*/
void loadGradlePropertiesFrom(File settingsDir);
}
Expand Up @@ -18,13 +18,13 @@

import org.gradle.StartParameter;
import org.gradle.api.internal.DynamicObjectAware;
import org.gradle.internal.extensibility.ExtensibleDynamicObject;
import org.gradle.api.internal.GradleInternal;
import org.gradle.api.internal.SettingsInternal;
import org.gradle.api.internal.initialization.ClassLoaderScope;
import org.gradle.api.internal.initialization.ScriptHandlerFactory;
import org.gradle.api.internal.initialization.ScriptHandlerInternal;
import org.gradle.groovy.scripts.ScriptSource;
import org.gradle.internal.extensibility.ExtensibleDynamicObject;
import org.gradle.internal.metaobject.DynamicObject;
import org.gradle.internal.reflect.Instantiator;
import org.gradle.internal.service.scopes.ServiceRegistryFactory;
Expand Down

0 comments on commit 7d0bf6d

Please sign in to comment.