/*
* Copyright 2010 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.configuration;
import org.gradle.api.initialization.dsl.ScriptHandler;
import org.gradle.api.internal.DocumentationRegistry;
import org.gradle.api.internal.file.FileLookup;
import org.gradle.api.internal.initialization.ClassLoaderScope;
import org.gradle.api.internal.initialization.ScriptHandlerFactory;
import org.gradle.api.internal.project.ProjectScript;
import org.gradle.api.plugins.PluginAware;
import org.gradle.groovy.scripts.*;
import org.gradle.groovy.scripts.internal.BuildScriptTransformer;
import org.gradle.groovy.scripts.internal.PluginsAndBuildscriptTransformer;
import org.gradle.groovy.scripts.internal.StatementExtractingScriptTransformer;
import org.gradle.internal.Factory;
import org.gradle.internal.reflect.Instantiator;
import org.gradle.internal.service.DefaultServiceRegistry;
import org.gradle.logging.LoggingManagerInternal;
import org.gradle.model.dsl.internal.transform.ClosureCreationInterceptingVerifier;
import org.gradle.model.internal.inspect.ModelRuleSourceDetector;
import org.gradle.plugin.use.internal.PluginDependenciesService;
import org.gradle.plugin.use.internal.PluginRequest;
import org.gradle.plugin.use.internal.PluginRequestApplicator;
import java.util.List;
public class DefaultScriptPluginFactory implements ScriptPluginFactory {
private final ScriptCompilerFactory scriptCompilerFactory;
private final ImportsReader importsReader;
private final Factory<LoggingManagerInternal> loggingManagerFactory;
private final Instantiator instantiator;
private final ScriptHandlerFactory scriptHandlerFactory;
private final PluginRequestApplicator pluginRequestApplicator;
private final FileLookup fileLookup;
private final DocumentationRegistry documentationRegistry;
private final ModelRuleSourceDetector modelRuleSourceDetector;
public DefaultScriptPluginFactory(ScriptCompilerFactory scriptCompilerFactory,
ImportsReader importsReader,
Factory<LoggingManagerInternal> loggingManagerFactory,
Instantiator instantiator,
ScriptHandlerFactory scriptHandlerFactory,
PluginRequestApplicator pluginRequestApplicator,
FileLookup fileLookup,
DocumentationRegistry documentationRegistry,
ModelRuleSourceDetector modelRuleSourceDetector) {
this.scriptCompilerFactory = scriptCompilerFactory;
this.importsReader = importsReader;
this.loggingManagerFactory = loggingManagerFactory;
this.instantiator = instantiator;
this.scriptHandlerFactory = scriptHandlerFactory;
this.pluginRequestApplicator = pluginRequestApplicator;
this.fileLookup = fileLookup;
this.documentationRegistry = documentationRegistry;
this.modelRuleSourceDetector = modelRuleSourceDetector;
}
public ScriptPlugin create(ScriptSource scriptSource, ScriptHandler scriptHandler, ClassLoaderScope targetScope, ClassLoaderScope baseScope, String classpathClosureName, Class<? extends BasicScript> scriptClass, boolean ownerScript) {
return new ScriptPluginImpl(scriptSource, scriptHandler, targetScope, baseScope, classpathClosureName, scriptClass, ownerScript);
}
private class ScriptPluginImpl implements ScriptPlugin {
private final ScriptSource scriptSource;
private final ClassLoaderScope targetScope;
private final ClassLoaderScope baseScope;
private final String classpathClosureName;
private final Class<? extends BasicScript> scriptType;
private final ScriptHandler scriptHandler;
private final boolean ownerScript;
public ScriptPluginImpl(ScriptSource scriptSource, ScriptHandler scriptHandler, ClassLoaderScope targetScope, ClassLoaderScope baseScope, String classpathClosureName, Class<? extends BasicScript> scriptType, boolean ownerScript) {
this.scriptSource = scriptSource;
this.targetScope = targetScope;
this.baseScope = baseScope;
this.classpathClosureName = classpathClosureName;
this.scriptHandler = scriptHandler;
this.scriptType = scriptType;
this.ownerScript = ownerScript;
}
public ScriptSource getSource() {
return scriptSource;
}
public void apply(final Object target) {
DefaultServiceRegistry services = new DefaultServiceRegistry();
services.add(ScriptPluginFactory.class, DefaultScriptPluginFactory.this);
services.add(ScriptHandlerFactory.class, scriptHandlerFactory);
services.add(ClassLoaderScope.class, targetScope);
services.add(LoggingManagerInternal.class, loggingManagerFactory.create());
services.add(Instantiator.class, instantiator);
services.add(ScriptHandler.class, scriptHandler);
services.add(FileLookup.class, fileLookup);
services.add(ModelRuleSourceDetector.class, modelRuleSourceDetector);
ScriptSource withImports = importsReader.withImports(scriptSource);
PluginDependenciesService pluginDependenciesService = new PluginDependenciesService(getSource());
services.add(PluginDependenciesService.class, pluginDependenciesService);
ScriptCompiler compiler = scriptCompilerFactory.createCompiler(withImports);
compiler.setClassloader(baseScope.getExportClassLoader());
boolean supportsPluginsBlock = ProjectScript.class.isAssignableFrom(scriptType);
String onPluginBlockError = supportsPluginsBlock ? null : "Only Project build scripts can contain plugins {} blocks";
PluginsAndBuildscriptTransformer scriptBlockTransformer = new PluginsAndBuildscriptTransformer(classpathClosureName, onPluginBlockError, documentationRegistry);
StatementExtractingScriptTransformer classpathScriptTransformer = new StatementExtractingScriptTransformer(classpathClosureName, scriptBlockTransformer);
compiler.setTransformer(classpathScriptTransformer);
ScriptRunner<? extends BasicScript> classPathScriptRunner = compiler.compile(scriptType);
classPathScriptRunner.getScript().init(target, services);
classPathScriptRunner.run();
List<PluginRequest> pluginRequests = pluginDependenciesService.getRequests();
PluginAware pluginAware = target instanceof PluginAware ? (PluginAware) target : null;
pluginRequestApplicator.applyPlugins(pluginRequests, scriptHandler, pluginAware, targetScope);
compiler.setClassloader(targetScope.getLocalClassLoader());
BuildScriptTransformer transformer = new BuildScriptTransformer("no_" + classpathScriptTransformer.getId(), classpathScriptTransformer.invert(), scriptSource);
compiler.setTransformer(transformer);
// TODO - find a less tangled way of getting this in here, see the verifier impl for why it's needed
compiler.setVerifier(new ClosureCreationInterceptingVerifier());
ScriptRunner<? extends BasicScript> runner = compiler.compile(scriptType);
BasicScript script = runner.getScript();
script.init(target, services);
if (ownerScript && target instanceof ScriptAware) {
((ScriptAware) target).setScript(script);
}
runner.run();
}
}
}