Skip to content

Commit

Permalink
Merge pull request #507 from gradle/6hundreds/pass-idea-registry-entries
Browse files Browse the repository at this point in the history
Pass idea.properties to studio
  • Loading branch information
6hundreds authored Jul 19, 2023
2 parents 5dd7dce + 1ed7b13 commit ce24642
Show file tree
Hide file tree
Showing 10 changed files with 113 additions and 36 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,8 @@ Here is an example:
android-studio-sync {
# Override default Android Studio jvm args
# studio-jvm-args = ["-Xms256m", "-Xmx4096m"]
# Pass an IDEA properties to Android Studio. This can be used to set a registry values as well
# idea-properties = ["gradle.tooling.models.parallel.fetch=true"]
}
}

Expand Down
12 changes: 4 additions & 8 deletions src/main/java/org/gradle/profiler/ScenarioLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,7 @@

import javax.annotation.Nullable;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.*;
import java.util.stream.Collectors;

class ScenarioLoader {
Expand Down Expand Up @@ -95,6 +89,7 @@ class ScenarioLoader {
private static final String TOOLING_API = "tooling-api";
private static final String ANDROID_STUDIO_SYNC = "android-studio-sync";
private static final String ANDROID_STUDIO_JVM_ARGS = "studio-jvm-args";
private static final String ANDROID_STUDIO_IDEA_PROPERTIES = "idea-properties";
private static final String JVM_ARGS = "jvm-args";

private static final Map<String, BuildMutatorConfigurator> BUILD_MUTATOR_CONFIGURATORS = ImmutableMap.<String, BuildMutatorConfigurator>builder()
Expand Down Expand Up @@ -314,7 +309,8 @@ static List<ScenarioDefinition> loadScenarios(File scenarioFile, InvocationSetti
private static StudioGradleScenarioDefinition newStudioGradleScenarioDefinition(GradleScenarioDefinition gradleScenarioDefinition, Config scenario) {
Config androidStudioSync = scenario.getConfig(ANDROID_STUDIO_SYNC);
List<String> studioJvmArgs = ConfigUtil.strings(androidStudioSync, ANDROID_STUDIO_JVM_ARGS, ImmutableList.of("-Xms256m", "-Xmx4096m"));
return new StudioGradleScenarioDefinition(gradleScenarioDefinition, studioJvmArgs);
List<String> ideaProperties = ConfigUtil.strings(androidStudioSync, ANDROID_STUDIO_IDEA_PROPERTIES, Collections.emptyList());
return new StudioGradleScenarioDefinition(gradleScenarioDefinition, studioJvmArgs, ideaProperties);
}

private static List<BuildMutator> getMutators(Config scenario, String scenarioName, InvocationSettings settings, int warmUpCount, int buildCount) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@

public class StudioGradleScenarioDefinition extends GradleScenarioDefinition {

public StudioGradleScenarioDefinition(GradleScenarioDefinition gradleScenarioDefinition, List<String> studioJvmArgs) {
public StudioGradleScenarioDefinition(GradleScenarioDefinition gradleScenarioDefinition, List<String> studioJvmArgs, List<String> ideaProperties) {
super(
gradleScenarioDefinition.getName(),
gradleScenarioDefinition.getTitle(),
gradleScenarioDefinition.getInvoker(),
new StudioGradleBuildConfiguration(gradleScenarioDefinition.getBuildConfiguration(), studioJvmArgs),
new StudioGradleBuildConfiguration(gradleScenarioDefinition.getBuildConfiguration(), studioJvmArgs, ideaProperties),
gradleScenarioDefinition.getAction(),
gradleScenarioDefinition.getCleanupAction(),
gradleScenarioDefinition.getGradleArgs(),
Expand All @@ -29,8 +29,9 @@ public StudioGradleScenarioDefinition(GradleScenarioDefinition gradleScenarioDef
public static class StudioGradleBuildConfiguration extends GradleBuildConfiguration {

private final List<String> studioJvmArgs;
private final List<String> ideaProperties;

StudioGradleBuildConfiguration(GradleBuildConfiguration gradleBuildConfiguration, List<String> studioJvmArguments) {
StudioGradleBuildConfiguration(GradleBuildConfiguration gradleBuildConfiguration, List<String> studioJvmArguments, List<String> ideaProperties) {
super(
gradleBuildConfiguration.getGradleVersion(),
gradleBuildConfiguration.getGradleHome(),
Expand All @@ -39,10 +40,15 @@ public static class StudioGradleBuildConfiguration extends GradleBuildConfigurat
gradleBuildConfiguration.isUsesScanPlugin()
);
this.studioJvmArgs = studioJvmArguments;
this.ideaProperties = ideaProperties;
}

public List<String> getStudioJvmArgs() {
return studioJvmArgs;
}

public List<String> getIdeaProperties() {
return ideaProperties;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

Expand All @@ -20,26 +21,31 @@ public class StudioLauncher {
private final Path studioInstallDir;
private final String headlessCommand;
private final List<String> additionalJvmArgs;
private final List<String> ideaProperties;
private final StudioSandbox studioSandbox;

public StudioLauncher(
Path startCommand,
String headlessCommand,
Path studioInstallDir,
List<String> additionalJvmArgs,
StudioSandbox studioSandbox
StudioSandbox studioSandbox,
List<String> ideaProperties
) {
this.startCommand = startCommand;
this.headlessCommand = headlessCommand;
this.studioInstallDir = studioInstallDir;
this.additionalJvmArgs = additionalJvmArgs;
this.studioSandbox = studioSandbox;
this.ideaProperties = ideaProperties;
}

public CommandExec.RunHandle launchStudio(File projectDir) {
List<String> commandLine = getCommandLine(projectDir);
logLauncherConfiguration(commandLine);
Map<String, String> environmentVariables = writeAdditionalJvmArgs();
Map<String, String> environmentVariables = new HashMap<>();
environmentVariables.putAll(writeAdditionalJvmArgs());
environmentVariables.putAll(writeIdeaProperties());
return new CommandExec()
.inDir(studioInstallDir.toFile())
.environmentVariables(environmentVariables)
Expand All @@ -59,14 +65,31 @@ private void logLauncherConfiguration(List<String> commandLine) {
System.out.println("* Start command: " + startCommand);
System.out.println("* Additional JVM args:");
additionalJvmArgs.forEach(arg -> System.out.println(" " + arg));
System.out.println("* Additional JVM args can be found at: " + studioSandbox.getJvmArgsDir().resolve("idea.vmoptions"));
System.out.println("* Additional JVM args can be found at: " + studioSandbox.getScenarioOptionsDir().resolve("idea.vmoptions"));
System.out.println("* IDEA properties:");
ideaProperties.forEach(property -> System.out.println(" " + property));
System.out.println("* IDEA properties can be found at: " + studioSandbox.getScenarioOptionsDir().resolve("idea.properties"));
System.out.println("* Android Studio logs can be found at: " + studioSandbox.getLogsDir().resolve("idea.log"));
System.out.printf("* Using command line: %s%n%n", String.join(" ", commandLine));
}

private Map<String, String> writeIdeaProperties() {
try {
Path ideaPropertiesFile = studioSandbox.getScenarioOptionsDir().resolve("idea.properties").toAbsolutePath();
Files.write(ideaPropertiesFile, ideaProperties);
return ImmutableMap.<String, String>builder()
.put("STUDIO_PROPERTIES", ideaPropertiesFile.toString())
.put("IDEA_PROPERTIES", ideaPropertiesFile.toString())
.build();

} catch (IOException e) {
throw new UncheckedIOException(e);
}
}

private Map<String, String> writeAdditionalJvmArgs() {
try {
Path additionJvmArgsFile = studioSandbox.getJvmArgsDir().resolve("idea.vmoptions").toAbsolutePath();
Path additionJvmArgsFile = studioSandbox.getScenarioOptionsDir().resolve("idea.vmoptions").toAbsolutePath();
Files.write(additionJvmArgsFile, additionalJvmArgs);
return ImmutableMap.<String, String>builder()
.put("STUDIO_VM_OPTIONS", additionJvmArgsFile.toString())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,18 @@ public class StudioLauncherProvider {
private final Path studioInstallDir;
private final StudioSandbox studioSandbox;
private final List<String> studioJvmArgs;
private final List<String> ideaProperties;
private boolean enableStudioPluginParameters;
private int studioPluginPort;
private boolean enableStudioAgentParameters;
private int studioAgentPort;
private int studioStartDetectorPort;

public StudioLauncherProvider(Path studioInstallDir, StudioSandbox studioSandbox, List<String> studioJvmArgs) {
public StudioLauncherProvider(Path studioInstallDir, StudioSandbox studioSandbox, List<String> studioJvmArgs, List<String> ideaProperties) {
this.studioInstallDir = studioInstallDir;
this.studioSandbox = studioSandbox;
this.studioJvmArgs = studioJvmArgs;
this.ideaProperties = ideaProperties;
}

public StudioLauncherProvider withStudioPluginParameters(int studioStartDetectorPort, int studioPluginPort) {
Expand All @@ -57,7 +59,7 @@ public StudioLauncher get() {
// Studio will fail since "missing Android SDK" modal will try to open
String headlessCommand = SHOULD_RUN_HEADLESS ? "headless-starter" : "";

return new StudioLauncher(startCommand, headlessCommand, studioInstallDir, additionalJvmArgs, studioSandbox);
return new StudioLauncher(startCommand, headlessCommand, studioInstallDir, additionalJvmArgs, studioSandbox, ideaProperties);
}

private List<String> getAdditionalJvmArgs() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ public class StudioProcess implements Closeable {
private final StudioConnections connections;
private final RunHandle process;

public StudioProcess(Path studioInstallDir, StudioSandbox sandbox, InvocationSettings invocationSettings, List<String> studioJvmArgs) {
public StudioProcess(Path studioInstallDir, StudioSandbox sandbox, InvocationSettings invocationSettings, List<String> studioJvmArgs, List<String> ideaProperties) {
Server studioStartDetectorServer = new Server("start-detector");
this.studioPluginServer = new Server("plugin");
this.studioAgentServer = new Server("agent");
StudioLauncher studioLauncher = new StudioLauncherProvider(studioInstallDir, sandbox, studioJvmArgs)
StudioLauncher studioLauncher = new StudioLauncherProvider(studioInstallDir, sandbox, studioJvmArgs, ideaProperties)
.withStudioPluginParameters(studioStartDetectorServer.getPort(), studioPluginServer.getPort())
.withStudioAgentParameters(studioAgentServer.getPort())
.get();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public boolean isProcessRunning() {
*/
public StudioProcess maybeStartProcess() {
if (!isProcessRunning()) {
process = new StudioProcess(studioInstallDir, sandbox, invocationSettings, buildConfiguration.getStudioJvmArgs());
process = new StudioProcess(studioInstallDir, sandbox, invocationSettings, buildConfiguration.getStudioJvmArgs(), buildConfiguration.getIdeaProperties());
process.getConnections().getAgentConnection().send(new StudioAgentConnectionParameters(buildConfiguration.getGradleHome()));
}
return process;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,17 @@ public static StudioSandbox createSandbox(@Nullable Path sandboxDir, String plug
Path path = newTempDir();
Path pluginsDir = createDir(new File(path.toFile(), pluginsDirName).toPath());
Path logsDir = createDir(new File(path.toFile(), "logs").toPath());
Path jvmArgsDir = createDir(new File(path.toFile(), "jvmArgs").toPath());
return StudioSandbox.partialSandbox(pluginsDir, logsDir, jvmArgsDir);
Path scenarioOptionsDir = createDir(new File(path.toFile(), "scenarioOptions").toPath());
return StudioSandbox.partialSandbox(pluginsDir, logsDir, scenarioOptionsDir);
}
File sandboxDirFile = sandboxDir.toFile();
Path configDir = createDir(new File(sandboxDirFile, "config").toPath());
Path systemDir = createDir(new File(sandboxDirFile, "system").toPath());
Path pluginsDir = createDir(new File(sandboxDirFile, pluginsDirName).toPath());
Path logDir = createDir(new File(sandboxDirFile, "logs").toPath());
Path jvmArgsDir = createDir(new File(sandboxDirFile, "jvmArgs").toPath());
Path scenarioOptionsDir = createDir(new File(sandboxDirFile, "scenarioOptions").toPath());
disableIdeUpdate(configDir);
return StudioSandbox.fullSandbox(configDir, systemDir, pluginsDir, logDir, jvmArgsDir);
return StudioSandbox.fullSandbox(configDir, systemDir, pluginsDir, logDir, scenarioOptionsDir);
}

private static boolean shouldCreatePartialSandbox(Path sandboxDir) {
Expand Down Expand Up @@ -92,14 +92,14 @@ public static class StudioSandbox {
private final Path systemDir;
private final Path pluginsDir;
private final Path logsDir;
private final Path jvmArgsDir;
private final Path scenarioOptionsDir;

private StudioSandbox(@Nullable Path configDir, @Nullable Path systemDir, Path pluginsDir, Path logsDir, Path jvmArgsDir) {
private StudioSandbox(@Nullable Path configDir, @Nullable Path systemDir, Path pluginsDir, Path logsDir, Path scenarioOptionsDir) {
this.configDir = configDir;
this.systemDir = systemDir;
this.pluginsDir = pluginsDir;
this.logsDir = logsDir;
this.jvmArgsDir = jvmArgsDir;
this.scenarioOptionsDir = scenarioOptionsDir;
}

public Optional<Path> getConfigDir() {
Expand All @@ -114,20 +114,20 @@ public Path getLogsDir() {
return logsDir;
}

public Path getJvmArgsDir() {
return jvmArgsDir;
public Path getScenarioOptionsDir() {
return scenarioOptionsDir;
}

public Path getPluginsDir() {
return pluginsDir;
}

public static StudioSandbox fullSandbox(Path configDir, Path systemDir, Path pluginsDir, Path logsDir, Path jvmArgsDir) {
return new StudioSandbox(configDir, systemDir, pluginsDir, logsDir, jvmArgsDir);
public static StudioSandbox fullSandbox(Path configDir, Path systemDir, Path pluginsDir, Path logsDir, Path scenarioOptionsDir) {
return new StudioSandbox(configDir, systemDir, pluginsDir, logsDir, scenarioOptionsDir);
}

public static StudioSandbox partialSandbox(Path pluginsDir, Path logsDir, Path jvmArgsDir) {
return new StudioSandbox(null, null, pluginsDir, logsDir, jvmArgsDir);
public static StudioSandbox partialSandbox(Path pluginsDir, Path logsDir, Path scenarioOptionsDir) {
return new StudioSandbox(null, null, pluginsDir, logsDir, scenarioOptionsDir);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ class AndroidStudioIntegrationTest extends AbstractProfilerIntegrationTest {
// We have to install plugin so also the first Studio process is run in the headless mode.
// We install plugin directory to a different "plugins-2" directory for first process otherwise cleaning plugin directory at start of second process fails on Windows.
StudioSandboxCreator.StudioSandbox sandbox = StudioSandboxCreator.createSandbox(sandboxDir.toPath(), "plugins-2")
StudioLauncher studioLauncher = new StudioLauncherProvider(studioHome.toPath(), sandbox, []).get()
StudioLauncher studioLauncher = new StudioLauncherProvider(studioHome.toPath(), sandbox, [], []).get()
StudioPluginInstaller pluginInstaller = new StudioPluginInstaller(sandbox.getPluginsDir())
// We have to install plugin, since a plugin contains headless starter and it makes it run headless on CI
pluginInstaller.installPlugin(Collections.singletonList(GradleInstrumentation.unpackPlugin("studio-plugin").toPath()))
Expand Down Expand Up @@ -173,7 +173,7 @@ class AndroidStudioIntegrationTest extends AbstractProfilerIntegrationTest {
// since if Android Studio writes to same project at the same time, it can fail
File otherStudioProjectDir = tmpDir.newFolder('project')
StudioSandboxCreator.StudioSandbox sandbox = StudioSandboxCreator.createSandbox(sandboxDir1.toPath())
StudioLauncher studioLauncher = new StudioLauncherProvider(studioHome.toPath(), sandbox, []).get()
StudioLauncher studioLauncher = new StudioLauncherProvider(studioHome.toPath(), sandbox, [], []).get()
// We have to install plugin, since a plugin contains headless starter and it makes it run headless on CI
StudioPluginInstaller pluginInstaller = new StudioPluginInstaller(sandbox.getPluginsDir())
pluginInstaller.installPlugin(Collections.singletonList(GradleInstrumentation.unpackPlugin("studio-plugin").toPath()))
Expand Down Expand Up @@ -270,7 +270,7 @@ class AndroidStudioIntegrationTest extends AbstractProfilerIntegrationTest {
then:
logFile.find("Full sync has completed in").size() == 2
logFile.find("and it SUCCEEDED").size() == 2
def vmOptionsFile = new File(sandboxDir, "jvmArgs/idea.vmoptions")
def vmOptionsFile = new File(sandboxDir, "scenarioOptions/idea.vmoptions")
vmOptionsFile.exists()
def vmOptions = vmOptionsFile.readLines()
vmOptions.contains("-Xmx1024m")
Expand Down Expand Up @@ -330,4 +330,25 @@ class AndroidStudioIntegrationTest extends AbstractProfilerIntegrationTest {
]
new Main().run(*args)
}

def "can add idea.properties"() {
given:
def scenarioFile = file("performance.scenarios") << """
$scenarioName {
android-studio-sync {
idea-properties = ["foo=true"]
}
}
"""

when:
runBenchmark(scenarioFile, 1, 1)

then:
logFile.find("Full sync has completed in").size() == 2
logFile.find("and it SUCCEEDED").size() == 2
def ideaPropertiesFile = new File(sandboxDir, "scenarioOptions/idea.properties")
def ideaProperties = ideaPropertiesFile.readLines()
ideaProperties.contains("foo=true")
}
}
Loading

0 comments on commit ce24642

Please sign in to comment.