blob: 96be88d706f48b2e4b5bc596c4ea840b89edecd3 [file] [log] [blame]
/*
* Copyright 2016 The Bazel Authors. All rights reserved.
*
* 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 com.google.idea.blaze.base.run;
import com.google.common.collect.Sets;
import com.google.idea.blaze.base.model.BlazeProjectData;
import com.google.idea.blaze.base.model.primitives.Label;
import com.google.idea.blaze.base.model.primitives.TargetExpression;
import com.google.idea.blaze.base.projectview.ProjectViewSet;
import com.google.idea.blaze.base.projectview.section.sections.RunConfigurationsSection;
import com.google.idea.blaze.base.projectview.section.sections.TargetSection;
import com.google.idea.blaze.base.run.exporter.RunConfigurationSerializer;
import com.google.idea.blaze.base.scope.BlazeContext;
import com.google.idea.blaze.base.settings.BlazeImportSettings;
import com.google.idea.blaze.base.sync.BlazeSyncParams.SyncMode;
import com.google.idea.blaze.base.sync.SyncListener;
import com.google.idea.blaze.base.sync.workspace.WorkspacePathResolver;
import com.google.idea.sdkcompat.transactions.Transactions;
import com.intellij.execution.RunManager;
import com.intellij.execution.RunnerAndConfigurationSettings;
import com.intellij.execution.configurations.RunConfiguration;
import com.intellij.openapi.project.Project;
import java.io.File;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* Imports run configurations specified in the project view, and creates run configurations for
* project view targets, where appropriate.
*/
public class BlazeRunConfigurationSyncListener extends SyncListener.Adapter {
@Override
public void onSyncComplete(
Project project,
BlazeContext context,
BlazeImportSettings importSettings,
ProjectViewSet projectViewSet,
BlazeProjectData blazeProjectData,
SyncMode syncMode,
SyncResult syncResult) {
if (syncMode == SyncMode.STARTUP) {
return;
}
Set<File> xmlFiles =
getImportedRunConfigurations(projectViewSet, blazeProjectData.workspacePathResolver);
Transactions.submitTransactionAndWait(
() -> {
// First, import from specified XML files. Then auto-generate from targets.
xmlFiles.forEach(
(file) -> RunConfigurationSerializer.loadFromXmlIgnoreExisting(project, file));
Set<Label> labelsWithConfigs = labelsWithConfigs(project);
Set<TargetExpression> targetExpressions =
Sets.newLinkedHashSet(projectViewSet.listItems(TargetSection.KEY));
// We only auto-generate configurations for rules listed in the project view.
for (TargetExpression target : targetExpressions) {
if (!(target instanceof Label) || labelsWithConfigs.contains(target)) {
continue;
}
Label label = (Label) target;
labelsWithConfigs.add(label);
maybeAddRunConfiguration(project, blazeProjectData, label);
}
});
}
private static Set<File> getImportedRunConfigurations(
ProjectViewSet projectViewSet, WorkspacePathResolver pathResolver) {
return projectViewSet
.listItems(RunConfigurationsSection.KEY)
.stream()
.map(pathResolver::resolveToFile)
.collect(Collectors.toCollection(LinkedHashSet::new));
}
/** Collects a set of all the Blaze labels that have an associated run configuration. */
private static Set<Label> labelsWithConfigs(Project project) {
List<RunConfiguration> configurations =
RunManager.getInstance(project).getAllConfigurationsList();
Set<Label> labelsWithConfigs = Sets.newHashSet();
for (RunConfiguration configuration : configurations) {
if (configuration instanceof BlazeRunConfiguration) {
BlazeRunConfiguration blazeRunConfiguration = (BlazeRunConfiguration) configuration;
TargetExpression target = blazeRunConfiguration.getTarget();
if (target instanceof Label) {
labelsWithConfigs.add((Label) target);
}
}
}
return labelsWithConfigs;
}
/**
* Adds a run configuration for an android_binary target if there is not already a configuration
* for that target.
*/
private static void maybeAddRunConfiguration(
Project project, BlazeProjectData blazeProjectData, Label label) {
final RunManager runManager = RunManager.getInstance(project);
for (BlazeRunConfigurationFactory configurationFactory :
BlazeRunConfigurationFactory.EP_NAME.getExtensions()) {
if (configurationFactory.handlesTarget(project, blazeProjectData, label)) {
final RunnerAndConfigurationSettings settings =
configurationFactory.createForTarget(project, runManager, label);
runManager.addConfiguration(settings, /* isShared */ false);
if (runManager.getSelectedConfiguration() == null) {
// TODO(joshgiles): Better strategy for picking initially selected config.
runManager.setSelectedConfiguration(settings);
}
break;
}
}
}
}