Skip to content

Commit

Permalink
Reinstate PropertiesLoadingSettingsProcessor
Browse files Browse the repository at this point in the history
To ensure `GradleProperties` is loaded before processing the settings scripts of
any included builds.

The integration with instant execution is mediated by the newly introduced
`GradlePropertiesController` service which guarantees `GradleProperties` is
loaded only once during a build and from the correct location.

Fixes #12381
  • Loading branch information
bamboo committed Mar 4, 2020
1 parent 50234ac commit 6abcc3f
Show file tree
Hide file tree
Showing 8 changed files with 403 additions and 17 deletions.
@@ -0,0 +1,59 @@
/*
* 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:
createDir("included") {
file("gradle.properties") << """
theProperty=included
"""
file("settings.gradle") << """
println("included settings script: " + theProperty)
"""
file("build.gradle") << """
println("included build script: " + theProperty)
"""
}
file("gradle.properties") << """
theProperty=root
"""
settingsFile << """
includeBuild 'included'
println("root settings script: " + theProperty)
"""
buildFile << """
println("root build script: " + theProperty)
"""

when:
run('help')

then:
outputContains("root settings script: root")
outputContains("root build script: root")
outputContains("included settings script: included")
outputContains("included build script: included")
}
}
@@ -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.getGradleProperties();
}
}

private interface State {

GradleProperties getGradleProperties();

State loadGradlePropertiesFrom(File settingsDir);
}

private class NotLoaded implements State {

@Override
public GradleProperties getGradleProperties() {
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 getGradleProperties() {
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;
}
}
}
@@ -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);
}
@@ -0,0 +1,47 @@
/*
* 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.StartParameter;
import org.gradle.api.internal.GradleInternal;
import org.gradle.api.internal.SettingsInternal;
import org.gradle.api.internal.initialization.ClassLoaderScope;

public class PropertiesLoadingSettingsProcessor implements SettingsProcessor {

private final SettingsProcessor delegate;
private final GradlePropertiesController gradlePropertiesController;

public PropertiesLoadingSettingsProcessor(
SettingsProcessor delegate,
GradlePropertiesController gradlePropertiesController
) {
this.delegate = delegate;
this.gradlePropertiesController = gradlePropertiesController;
}

@Override
public SettingsInternal process(
GradleInternal gradle,
SettingsLocation settingsLocation,
ClassLoaderScope buildRootClassLoaderScope,
StartParameter startParameter
) {
gradlePropertiesController.loadGradlePropertiesFrom(settingsLocation.getSettingsDir());
return delegate.process(gradle, settingsLocation, buildRootClassLoaderScope, startParameter);
}
}
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
Expand Up @@ -121,10 +121,12 @@
import org.gradle.initialization.ClassLoaderScopeListeners;
import org.gradle.initialization.ClassLoaderScopeRegistry;
import org.gradle.initialization.DefaultClassLoaderScopeRegistry;
import org.gradle.initialization.DefaultGradlePropertiesController;
import org.gradle.initialization.DefaultGradlePropertiesLoader;
import org.gradle.initialization.DefaultProjectDescriptorRegistry;
import org.gradle.initialization.DefaultSettingsLoaderFactory;
import org.gradle.initialization.DefaultSettingsPreparer;
import org.gradle.initialization.GradlePropertiesController;
import org.gradle.initialization.IGradlePropertiesLoader;
import org.gradle.initialization.InitScriptHandler;
import org.gradle.initialization.InstantiatingBuildLoader;
Expand All @@ -133,6 +135,7 @@
import org.gradle.initialization.ProjectAccessListener;
import org.gradle.initialization.ProjectDescriptorRegistry;
import org.gradle.initialization.ProjectPropertySettingBuildLoader;
import org.gradle.initialization.PropertiesLoadingSettingsProcessor;
import org.gradle.initialization.RootBuildCacheControllerSettingsProcessor;
import org.gradle.initialization.ScriptEvaluatingSettingsProcessor;
import org.gradle.initialization.SettingsEvaluatedCallbackFiringSettingsProcessor;
Expand Down Expand Up @@ -271,6 +274,18 @@ protected IsolatedAntBuilder createIsolatedAntBuilder(ClassPathRegistry classPat
return new DefaultIsolatedAntBuilder(classPathRegistry, classLoaderFactory, moduleRegistry);
}

protected GradleProperties createGradleProperties(
GradlePropertiesController gradlePropertiesController
) {
return gradlePropertiesController.getGradleProperties();
}

protected GradlePropertiesController createGradlePropertiesController(
IGradlePropertiesLoader propertiesLoader
) {
return new DefaultGradlePropertiesController(propertiesLoader);
}

protected IGradlePropertiesLoader createGradlePropertiesLoader() {
return new DefaultGradlePropertiesLoader((StartParameterInternal) get(StartParameter.class));
}
Expand All @@ -295,13 +310,6 @@ protected ProviderFactory createProviderFactory(ValueSourceProviderFactory value
return new DefaultProviderFactory(valueSourceProviderFactory);
}

protected GradleProperties createGradleProperties(
IGradlePropertiesLoader propertiesLoader,
BuildLayout buildLayout
) {
return propertiesLoader.loadGradleProperties(buildLayout.getRootDirectory());
}

protected ActorFactory createActorFactory() {
return new DefaultActorFactory(get(ExecutorFactory.class));
}
Expand Down Expand Up @@ -441,22 +449,26 @@ protected SettingsProcessor createSettingsProcessor(
ScriptHandlerFactory scriptHandlerFactory,
Instantiator instantiator,
ServiceRegistryFactory serviceRegistryFactory,
GradlePropertiesController gradlePropertiesController,
GradleProperties gradleProperties,
BuildOperationExecutor buildOperationExecutor,
TextFileResourceLoader textFileResourceLoader
) {
return new BuildOperationSettingsProcessor(
new RootBuildCacheControllerSettingsProcessor(
new SettingsEvaluatedCallbackFiringSettingsProcessor(
new ScriptEvaluatingSettingsProcessor(
scriptPluginFactory,
new SettingsFactory(
instantiator,
serviceRegistryFactory,
scriptHandlerFactory
new PropertiesLoadingSettingsProcessor(
new ScriptEvaluatingSettingsProcessor(
scriptPluginFactory,
new SettingsFactory(
instantiator,
serviceRegistryFactory,
scriptHandlerFactory
),
gradleProperties,
textFileResourceLoader
),
gradleProperties,
textFileResourceLoader
gradlePropertiesController
)
)
),
Expand Down

0 comments on commit 6abcc3f

Please sign in to comment.