在初始化阶段主要是对settings.gradle文件进行处理建立项目的构建工程结构
settings处理过程如下:
1.获取gradle命令行参数,在之前已解析成StartParameter
2.根据命令行参数和gradle惯例查找需要的Settings.gradle文件
3.找到对应的buildSrc目录,并编译相应的代码资源
4.根据以上的结果创建Settings对象
5.为Settings对象设置默认工程
1.gradle命令行参数
以上是命令行下的gradle命令参数
如果在命令中使用-p/-b/-c/-u等选项,会影响到Settings文件的定位
2.Settings.gradle文件的定位
策略:
1.在命令行参数里指定了Settings文件,使用指定的文件
2.未指定Settings文件默认从当前目录下开始向上递归查找,在父目录下查找,未找到则在父目录下的master目录下查找,重复以上步骤。
源码实现如下
/**
* Determines the layout of the build, given a current directory and some other configuration.
*/
public BuildLayout getLayoutFor(BuildLayoutConfiguration configuration) {
if (configuration.isUseEmptySettings()) {
return new BuildLayout(configuration.getCurrentDir(), configuration.getCurrentDir(), null);
}
File explicitSettingsFile = configuration.getSettingsFile();
if (explicitSettingsFile != null) {
if (!explicitSettingsFile.isFile()) {
throw new ResourceNotFoundException(explicitSettingsFile.toURI(), String.format("Could not read settings file '%s' as it does not exist.", explicitSettingsFile.getAbsolutePath()));
}
return new BuildLayout(configuration.getCurrentDir(), configuration.getCurrentDir(), explicitSettingsFile);
}
File currentDir = configuration.getCurrentDir();
boolean searchUpwards = configuration.isSearchUpwards();
return getLayoutFor(currentDir, searchUpwards ? null : currentDir.getParentFile());
}
BuildLayout getLayoutFor(File currentDir, File stopAt) {
File settingsFile = new File(currentDir, "settings.gradle");
if (settingsFile.isFile()) {
return layout(currentDir, currentDir, settingsFile);
}
for (File candidate = currentDir.getParentFile(); candidate != null && !candidate.equals(stopAt); candidate = candidate.getParentFile()) {
settingsFile = new File(candidate, "settings.gradle");
if (settingsFile.isFile()) {
return layout(candidate, candidate, settingsFile);
}
settingsFile = new File(candidate, "master/settings.gradle");
if (settingsFile.isFile()) {
return layout(candidate, settingsFile.getParentFile(), settingsFile);
}
}
return layout(currentDir, currentDir, settingsFile);
}
3.buildSrc目录处理
// We found the desired settings file, now build the associated buildSrc before loading settings. This allows the settings script to reference classes in the buildSrc.
以上是源码只能给的一段注释:在找到Settings文件以后,在加载Settings文件之前需要先对BuildSrc下的文件进行编译,以便zaiSettings脚本里引用buildSrc中的类。
我们可以在buildSrc目录下创建groovy脚本文件或者创建plugin
具体使用参考资料:自定义Task类型
4.Settings对象创建
首先看一下BuildScopeServices中创建的SettingsProcessor
protected SettingsProcessor createSettingsProcessor(ScriptPluginFactory scriptPluginFactory, ScriptHandlerFactory scriptHandlerFactory, Instantiator instantiator, ServiceRegistryFactory serviceRegistryFactory, IGradlePropertiesLoader propertiesLoader, BuildOperationExecutor buildOperationExecutor) {
return new NotifyingSettingsProcessor(
new PropertiesLoadingSettingsProcessor(
new ScriptEvaluatingSettingsProcessor(
scriptPluginFactory,
scriptHandlerFactory,
new SettingsFactory(
instantiator,
serviceRegistryFactory
),
propertiesLoader
),
propertiesLoader
),
buildOperationExecutor);
}
这里的Processor有三级的链式处理,ScriptEvaluatingSettingsProcessor最终处理交给SettingsFactory生成DefaultSettings 对象
Settings构建工程结构解析如下
public void include(String[] projectPaths) {
for (String projectPath : projectPaths) {
String subPath = "";
String[] pathElements = removeTrailingColon(projectPath).split(":");
DefaultProjectDescriptor parentProjectDescriptor = rootProjectDescriptor;
for (String pathElement : pathElements) {
subPath = subPath + ":" + pathElement;
DefaultProjectDescriptor projectDescriptor = getProjectDescriptorRegistry().getProject(subPath);
if (projectDescriptor == null) {
parentProjectDescriptor = createProjectDescriptor(parentProjectDescriptor, pathElement, new File(parentProjectDescriptor.getProjectDir(), pathElement));
} else {
parentProjectDescriptor = projectDescriptor;
}
}
}
}
5.设置默认工程DefaultProject
默认的工程目录是当前工作目录,在命令行使用-p选项可以指定工程目录,当用-b指定构建文件build.gradle,用-p指定构建工程时有不同的策略确定默认构建工程
@Override
public SettingsInternal findAndLoadSettings(GradleInternal gradle) {
StartParameter startParameter = gradle.getStartParameter();
SettingsInternal settings = findSettingsAndLoadIfAppropriate(gradle, startParameter);
ProjectSpec spec = ProjectSpecs.forStartParameter(startParameter, settings);
if (spec.containsProject(settings.getProjectRegistry())) {
setDefaultProject(spec, settings);
return settings;
}
// Try again with empty settings
StartParameter noSearchParameter = startParameter.newInstance();
noSearchParameter.useEmptySettings();
settings = findSettingsAndLoadIfAppropriate(gradle, noSearchParameter);
// Set explicit build file, if required
if (noSearchParameter.getBuildFile() != null) {
ProjectDescriptor rootProject = settings.getRootProject();
rootProject.setBuildFileName(noSearchParameter.getBuildFile().getName());
}
setDefaultProject(spec, settings);
return settings;
}
class ProjectSpecs {
static ProjectSpec forStartParameter(StartParameter startParameter, SettingsInternal settings) {
File explicitProjectDir = startParameter.getProjectDir();
File explicitBuildFile = startParameter.getBuildFile();
if (explicitBuildFile != null) {
return new BuildFileProjectSpec(explicitBuildFile);
}
if (explicitProjectDir != null) {
return new ProjectDirectoryProjectSpec(explicitProjectDir);
}
return new DefaultProjectSpec(startParameter.getCurrentDir(), settings);
}
}