use of org.apache.beam.vendor.calcite.v1_28_0.com.google.common.collect.ImmutableSet in project buck by facebook.
the class AndroidBinary method addDexingSteps.
/**
* Create dex artifacts for all of the individual directories of compiled .class files (or
* the obfuscated jar files if proguard is used). If split dex is used, multiple dex artifacts
* will be produced.
* @param classpathEntriesToDex Full set of classpath entries that must make
* their way into the final APK structure (but not necessarily into the
* primary dex).
* @param secondaryDexDirectories The contract for updating this builder must match that
* of {@link PreDexMerge#getSecondaryDexDirectories()}.
* @param steps List of steps to add to.
* @param primaryDexPath Output path for the primary dex file.
*/
@VisibleForTesting
void addDexingSteps(Set<Path> classpathEntriesToDex, Supplier<ImmutableMap<String, HashCode>> classNamesToHashesSupplier, ImmutableSet.Builder<Path> secondaryDexDirectories, ImmutableList.Builder<Step> steps, Path primaryDexPath, Optional<SourcePath> dexReorderToolFile, Optional<SourcePath> dexReorderDataDumpFile, ImmutableMultimap<APKModule, Path> additionalDexStoreToJarPathMap, SourcePathResolver resolver) {
final Supplier<Set<Path>> primaryInputsToDex;
final Optional<Path> secondaryDexDir;
final Optional<Supplier<Multimap<Path, Path>>> secondaryOutputToInputs;
Path secondaryDexParentDir = getBinPath("__%s_secondary_dex__/");
Path additionalDexParentDir = getBinPath("__%s_additional_dex__/");
Path additionalDexAssetsDir = additionalDexParentDir.resolve("assets");
final Optional<ImmutableSet<Path>> additionalDexDirs;
if (shouldSplitDex()) {
Optional<Path> proguardFullConfigFile = Optional.empty();
Optional<Path> proguardMappingFile = Optional.empty();
if (packageType.isBuildWithObfuscation()) {
Path proguardConfigDir = getProguardTextFilesPath();
proguardFullConfigFile = Optional.of(proguardConfigDir.resolve("configuration.txt"));
proguardMappingFile = Optional.of(proguardConfigDir.resolve("mapping.txt"));
}
// DexLibLoader expects that metadata.txt and secondary jar files are under this dir
// in assets.
// Intermediate directory holding the primary split-zip jar.
Path splitZipDir = getBinPath("__%s_split_zip__");
steps.add(new MakeCleanDirectoryStep(getProjectFilesystem(), splitZipDir));
Path primaryJarPath = splitZipDir.resolve("primary.jar");
Path secondaryJarMetaDirParent = splitZipDir.resolve("secondary_meta");
Path secondaryJarMetaDir = secondaryJarMetaDirParent.resolve(SECONDARY_DEX_SUBDIR);
steps.add(new MakeCleanDirectoryStep(getProjectFilesystem(), secondaryJarMetaDir));
Path secondaryJarMeta = secondaryJarMetaDir.resolve("metadata.txt");
// Intermediate directory holding _ONLY_ the secondary split-zip jar files. This is
// important because SmartDexingCommand will try to dx every entry in this directory. It
// does this because it's impossible to know what outputs split-zip will generate until it
// runs.
final Path secondaryZipDir = getBinPath("__%s_secondary_zip__");
steps.add(new MakeCleanDirectoryStep(getProjectFilesystem(), secondaryZipDir));
// Intermediate directory holding the directories holding _ONLY_ the additional split-zip
// jar files that are intended for that dex store.
final Path additionalDexStoresZipDir = getBinPath("__%s_dex_stores_zip__");
steps.add(new MakeCleanDirectoryStep(getProjectFilesystem(), additionalDexStoresZipDir));
for (APKModule dexStore : additionalDexStoreToJarPathMap.keySet()) {
steps.add(new MakeCleanDirectoryStep(getProjectFilesystem(), additionalDexStoresZipDir.resolve(dexStore.getName())));
steps.add(new MakeCleanDirectoryStep(getProjectFilesystem(), secondaryJarMetaDirParent.resolve("assets").resolve(dexStore.getName())));
}
// Run the split-zip command which is responsible for dividing the large set of input
// classpaths into a more compact set of jar files such that no one jar file when dexed will
// yield a dex artifact too large for dexopt or the dx method limit to handle.
Path zipSplitReportDir = getBinPath("__%s_split_zip_report__");
steps.add(new MakeCleanDirectoryStep(getProjectFilesystem(), zipSplitReportDir));
SplitZipStep splitZipCommand = new SplitZipStep(getProjectFilesystem(), classpathEntriesToDex, secondaryJarMeta, primaryJarPath, secondaryZipDir, "secondary-%d.jar", secondaryJarMetaDirParent, additionalDexStoresZipDir, proguardFullConfigFile, proguardMappingFile, skipProguard, dexSplitMode, dexSplitMode.getPrimaryDexScenarioFile().map(resolver::getAbsolutePath), dexSplitMode.getPrimaryDexClassesFile().map(resolver::getAbsolutePath), dexSplitMode.getSecondaryDexHeadClassesFile().map(resolver::getAbsolutePath), dexSplitMode.getSecondaryDexTailClassesFile().map(resolver::getAbsolutePath), additionalDexStoreToJarPathMap, enhancementResult.getAPKModuleGraph(), zipSplitReportDir);
steps.add(splitZipCommand);
// smart dexing command. Smart dex will handle "cleaning" this directory properly.
if (reorderClassesIntraDex) {
secondaryDexDir = Optional.of(secondaryDexParentDir.resolve(SMART_DEX_SECONDARY_DEX_SUBDIR));
Path intraDexReorderSecondaryDexDir = secondaryDexParentDir.resolve(SECONDARY_DEX_SUBDIR);
steps.add(new MakeCleanDirectoryStep(getProjectFilesystem(), secondaryDexDir.get()));
steps.add(new MakeCleanDirectoryStep(getProjectFilesystem(), intraDexReorderSecondaryDexDir));
} else {
secondaryDexDir = Optional.of(secondaryDexParentDir.resolve(SECONDARY_DEX_SUBDIR));
steps.add(new MkdirStep(getProjectFilesystem(), secondaryDexDir.get()));
}
if (additionalDexStoreToJarPathMap.isEmpty()) {
additionalDexDirs = Optional.empty();
} else {
ImmutableSet.Builder<Path> builder = ImmutableSet.builder();
for (APKModule dexStore : additionalDexStoreToJarPathMap.keySet()) {
Path dexStorePath = additionalDexAssetsDir.resolve(dexStore.getName());
builder.add(dexStorePath);
steps.add(new MakeCleanDirectoryStep(getProjectFilesystem(), dexStorePath));
}
additionalDexDirs = Optional.of(builder.build());
}
if (dexSplitMode.getDexStore() == DexStore.RAW) {
secondaryDexDirectories.add(secondaryDexDir.get());
} else {
secondaryDexDirectories.add(secondaryJarMetaDirParent);
secondaryDexDirectories.add(secondaryDexParentDir);
}
if (additionalDexDirs.isPresent()) {
secondaryDexDirectories.add(additionalDexParentDir);
}
// Adjust smart-dex inputs for the split-zip case.
primaryInputsToDex = Suppliers.ofInstance(ImmutableSet.of(primaryJarPath));
Supplier<Multimap<Path, Path>> secondaryOutputToInputsMap = splitZipCommand.getOutputToInputsMapSupplier(secondaryDexDir.get(), additionalDexAssetsDir);
secondaryOutputToInputs = Optional.of(secondaryOutputToInputsMap);
} else {
// Simple case where our inputs are the natural classpath directories and we don't have
// to worry about secondary jar/dex files.
primaryInputsToDex = Suppliers.ofInstance(classpathEntriesToDex);
secondaryDexDir = Optional.empty();
secondaryOutputToInputs = Optional.empty();
}
HashInputJarsToDexStep hashInputJarsToDexStep = new HashInputJarsToDexStep(getProjectFilesystem(), primaryInputsToDex, secondaryOutputToInputs, classNamesToHashesSupplier);
steps.add(hashInputJarsToDexStep);
// Stores checksum information from each invocation to intelligently decide when dx needs
// to be re-run.
Path successDir = getBinPath("__%s_smart_dex__/.success");
steps.add(new MkdirStep(getProjectFilesystem(), successDir));
// Add the smart dexing tool that is capable of avoiding the external dx invocation(s) if
// it can be shown that the inputs have not changed. It also parallelizes dx invocations
// where applicable.
//
// Note that by not specifying the number of threads this command will use it will select an
// optimal default regardless of the value of --num-threads. This decision was made with the
// assumption that --num-threads specifies the threading of build rule execution and does not
// directly apply to the internal threading/parallelization details of various build commands
// being executed. For example, aapt is internally threaded by default when preprocessing
// images.
EnumSet<DxStep.Option> dxOptions = PackageType.RELEASE.equals(packageType) ? EnumSet.of(DxStep.Option.NO_LOCALS) : EnumSet.of(DxStep.Option.NO_OPTIMIZE);
Path selectedPrimaryDexPath = primaryDexPath;
if (reorderClassesIntraDex) {
String primaryDexFileName = primaryDexPath.getFileName().toString();
String smartDexPrimaryDexFileName = "smart-dex-" + primaryDexFileName;
Path smartDexPrimaryDexPath = Paths.get(primaryDexPath.toString().replace(primaryDexFileName, smartDexPrimaryDexFileName));
selectedPrimaryDexPath = smartDexPrimaryDexPath;
}
SmartDexingStep smartDexingCommand = new SmartDexingStep(getProjectFilesystem(), selectedPrimaryDexPath, primaryInputsToDex, secondaryDexDir, secondaryOutputToInputs, hashInputJarsToDexStep, successDir, dxOptions, dxExecutorService, xzCompressionLevel, dxMaxHeapSize);
steps.add(smartDexingCommand);
if (reorderClassesIntraDex) {
IntraDexReorderStep intraDexReorderStep = new IntraDexReorderStep(getProjectFilesystem(), resolver.getAbsolutePath(dexReorderToolFile.get()), resolver.getAbsolutePath(dexReorderDataDumpFile.get()), getBuildTarget(), selectedPrimaryDexPath, primaryDexPath, secondaryOutputToInputs, SMART_DEX_SECONDARY_DEX_SUBDIR, SECONDARY_DEX_SUBDIR);
steps.add(intraDexReorderStep);
}
}
use of org.apache.beam.vendor.calcite.v1_28_0.com.google.common.collect.ImmutableSet in project buck by facebook.
the class AndroidBinary method getBuildSteps.
@SuppressWarnings("PMD.PrematureDeclaration")
@Override
public ImmutableList<Step> getBuildSteps(BuildContext context, BuildableContext buildableContext) {
ImmutableList.Builder<Step> steps = ImmutableList.builder();
// The `HasInstallableApk` interface needs access to the manifest, so make sure we create our
// own copy of this so that we don't have a runtime dep on the `AaptPackageResources` step.
Path manifestPath = context.getSourcePathResolver().getRelativePath(getManifestPath());
steps.add(new MkdirStep(getProjectFilesystem(), manifestPath.getParent()));
steps.add(CopyStep.forFile(getProjectFilesystem(), context.getSourcePathResolver().getRelativePath(androidManifestPath), manifestPath));
buildableContext.recordArtifact(manifestPath);
// Create the .dex files if we aren't doing pre-dexing.
DexFilesInfo dexFilesInfo = addFinalDxSteps(buildableContext, context.getSourcePathResolver(), steps);
////
// BE VERY CAREFUL adding any code below here.
// Any inputs to apkbuilder must be reflected in the hash returned by getAbiKeyForDeps.
////
AndroidPackageableCollection packageableCollection = enhancementResult.getPackageableCollection();
ImmutableSet.Builder<Path> nativeLibraryDirectoriesBuilder = ImmutableSet.builder();
// Copy the transitive closure of native-libs-as-assets to a single directory, if any.
ImmutableSet.Builder<Path> nativeLibraryAsAssetDirectories = ImmutableSet.builder();
for (final APKModule module : enhancementResult.getAPKModuleGraph().getAPKModules()) {
boolean shouldPackageAssetLibraries = packageAssetLibraries || !module.isRootModule();
if (!ExopackageMode.enabledForNativeLibraries(exopackageModes) && enhancementResult.getCopyNativeLibraries().isPresent() && enhancementResult.getCopyNativeLibraries().get().containsKey(module)) {
CopyNativeLibraries copyNativeLibraries = enhancementResult.getCopyNativeLibraries().get().get(module);
if (shouldPackageAssetLibraries) {
nativeLibraryDirectoriesBuilder.add(copyNativeLibraries.getPathToNativeLibsDir());
} else {
nativeLibraryDirectoriesBuilder.add(copyNativeLibraries.getPathToNativeLibsDir());
nativeLibraryDirectoriesBuilder.add(copyNativeLibraries.getPathToNativeLibsAssetsDir());
}
}
if ((!packageableCollection.getNativeLibAssetsDirectories().isEmpty()) || (!packageableCollection.getNativeLinkablesAssets().isEmpty() && shouldPackageAssetLibraries)) {
Path pathForNativeLibsAsAssets = getPathForNativeLibsAsAssets();
final Path libSubdirectory = pathForNativeLibsAsAssets.resolve("assets").resolve(module.isRootModule() ? "lib" : module.getName());
ImmutableCollection<SourcePath> nativeLibDirs = packageableCollection.getNativeLibAssetsDirectories().get(module);
getStepsForNativeAssets(context.getSourcePathResolver(), steps, nativeLibDirs == null ? Optional.empty() : Optional.of(nativeLibDirs), libSubdirectory, module.isRootModule() ? "metadata.txt" : "libs.txt", module);
nativeLibraryAsAssetDirectories.add(pathForNativeLibsAsAssets);
}
}
// If non-english strings are to be stored as assets, pass them to ApkBuilder.
ImmutableSet.Builder<Path> zipFiles = ImmutableSet.builder();
RichStream.from(primaryApkAssetsZips).map(context.getSourcePathResolver()::getRelativePath).forEach(zipFiles::add);
if (ExopackageMode.enabledForNativeLibraries(exopackageModes)) {
// We need to include a few dummy native libraries with our application so that Android knows
// to run it as 32-bit. Android defaults to 64-bit when no libraries are provided at all,
// causing us to fail to load our 32-bit exopackage native libraries later.
String fakeNativeLibraryBundle = System.getProperty("buck.native_exopackage_fake_path");
if (fakeNativeLibraryBundle == null) {
throw new RuntimeException("fake native bundle not specified in properties");
}
zipFiles.add(Paths.get(fakeNativeLibraryBundle));
}
ImmutableSet<Path> allAssetDirectories = ImmutableSet.<Path>builder().addAll(nativeLibraryAsAssetDirectories.build()).addAll(dexFilesInfo.secondaryDexDirs).build();
SourcePathResolver resolver = context.getSourcePathResolver();
Path signedApkPath = getSignedApkPath();
final Path pathToKeystore = resolver.getAbsolutePath(keystorePath);
Supplier<KeystoreProperties> keystoreProperties = Suppliers.memoize(() -> {
try {
return KeystoreProperties.createFromPropertiesFile(pathToKeystore, resolver.getAbsolutePath(keystorePropertiesPath), getProjectFilesystem());
} catch (IOException e) {
throw new RuntimeException();
}
});
ApkBuilderStep apkBuilderCommand = new ApkBuilderStep(getProjectFilesystem(), context.getSourcePathResolver().getAbsolutePath(resourcesApkPath), getSignedApkPath(), dexFilesInfo.primaryDexPath, allAssetDirectories, nativeLibraryDirectoriesBuilder.build(), zipFiles.build(), packageableCollection.getPathsToThirdPartyJars().stream().map(resolver::getAbsolutePath).collect(MoreCollectors.toImmutableSet()), pathToKeystore, keystoreProperties, /* debugMode */
false, javaRuntimeLauncher);
steps.add(apkBuilderCommand);
// The `ApkBuilderStep` delegates to android tools to build a ZIP with timestamps in it, making
// the output non-deterministic. So use an additional scrubbing step to zero these out.
steps.add(new ZipScrubberStep(getProjectFilesystem(), signedApkPath));
Path apkToRedexAndAlign;
// Optionally, compress the resources file in the .apk.
if (this.isCompressResources()) {
Path compressedApkPath = getCompressedResourcesApkPath();
apkToRedexAndAlign = compressedApkPath;
RepackZipEntriesStep arscComp = new RepackZipEntriesStep(getProjectFilesystem(), signedApkPath, compressedApkPath, ImmutableSet.of("resources.arsc"));
steps.add(arscComp);
} else {
apkToRedexAndAlign = signedApkPath;
}
boolean applyRedex = redexOptions.isPresent();
Path apkPath = context.getSourcePathResolver().getRelativePath(getSourcePathToOutput());
Path apkToAlign = apkToRedexAndAlign;
// redex
if (applyRedex) {
Path proguardConfigDir = getProguardTextFilesPath();
Path redexedApk = apkPath.getParent().resolve(apkPath.getFileName().toString() + ".redex");
apkToAlign = redexedApk;
ImmutableList<Step> redexSteps = ReDexStep.createSteps(getProjectFilesystem(), resolver, redexOptions.get(), apkToRedexAndAlign, redexedApk, keystoreProperties, proguardConfigDir, context.getSourcePathResolver());
steps.addAll(redexSteps);
}
steps.add(new ZipalignStep(getProjectFilesystem().getRootPath(), apkToAlign, apkPath));
buildableContext.recordArtifact(apkPath);
return steps.build();
}
use of org.apache.beam.vendor.calcite.v1_28_0.com.google.common.collect.ImmutableSet in project buck by facebook.
the class AndroidLibraryDescription method createBuildRule.
@Override
public <A extends Arg> BuildRule createBuildRule(TargetGraph targetGraph, BuildRuleParams params, BuildRuleResolver resolver, A args) throws NoSuchBuildTargetException {
if (params.getBuildTarget().getFlavors().contains(JavaLibrary.SRC_JAR)) {
return new JavaSourceJar(params, args.srcs, args.mavenCoords);
}
SourcePathRuleFinder ruleFinder = new SourcePathRuleFinder(resolver);
JavacOptions javacOptions = JavacOptionsFactory.create(defaultOptions, params, resolver, ruleFinder, args);
final ImmutableSet.Builder<BuildRule> queriedDepsBuilder = ImmutableSet.builder();
if (args.depsQuery.isPresent()) {
queriedDepsBuilder.addAll(QueryUtils.resolveDepQuery(params, args.depsQuery.get(), resolver, targetGraph).collect(Collectors.toList()));
}
final ImmutableSet<BuildRule> queriedDeps = queriedDepsBuilder.build();
AndroidLibraryGraphEnhancer graphEnhancer = new AndroidLibraryGraphEnhancer(params.getBuildTarget(), params.copyReplacingExtraDeps(Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>naturalOrder().addAll(queriedDeps).addAll(resolver.getAllRules(args.exportedDeps)).build())), javacOptions, DependencyMode.FIRST_ORDER, /* forceFinalResourceIds */
false, args.resourceUnionPackage, args.finalRName, false);
boolean hasDummyRDotJavaFlavor = params.getBuildTarget().getFlavors().contains(DUMMY_R_DOT_JAVA_FLAVOR);
if (CalculateAbi.isAbiTarget(params.getBuildTarget())) {
if (hasDummyRDotJavaFlavor) {
return graphEnhancer.getBuildableForAndroidResourcesAbi(resolver, ruleFinder);
}
BuildTarget libraryTarget = CalculateAbi.getLibraryTarget(params.getBuildTarget());
BuildRule libraryRule = resolver.requireRule(libraryTarget);
return CalculateAbi.of(params.getBuildTarget(), ruleFinder, params, Preconditions.checkNotNull(libraryRule.getSourcePathToOutput()));
}
Optional<DummyRDotJava> dummyRDotJava = graphEnhancer.getBuildableForAndroidResources(resolver, /* createBuildableIfEmpty */
hasDummyRDotJavaFlavor);
if (hasDummyRDotJavaFlavor) {
return dummyRDotJava.get();
} else {
ImmutableSet<Either<SourcePath, Path>> additionalClasspathEntries = ImmutableSet.of();
if (dummyRDotJava.isPresent()) {
additionalClasspathEntries = ImmutableSet.of(Either.ofLeft(dummyRDotJava.get().getSourcePathToOutput()));
ImmutableSortedSet<BuildRule> newDeclaredDeps = ImmutableSortedSet.<BuildRule>naturalOrder().addAll(params.getDeclaredDeps().get()).add(dummyRDotJava.get()).build();
params = params.copyReplacingDeclaredAndExtraDeps(Suppliers.ofInstance(newDeclaredDeps), params.getExtraDeps());
}
AndroidLibraryCompiler compiler = compilerFactory.getCompiler(args.language.orElse(JvmLanguage.JAVA));
ImmutableSortedSet<BuildRule> exportedDeps = resolver.getAllRules(args.exportedDeps);
ImmutableSortedSet.Builder<BuildRule> declaredDepsBuilder = ImmutableSortedSet.<BuildRule>naturalOrder().addAll(params.getDeclaredDeps().get()).addAll(queriedDeps).addAll(compiler.getDeclaredDeps(args, resolver));
ImmutableSortedSet<BuildRule> declaredDeps = declaredDepsBuilder.build();
ImmutableSortedSet<BuildRule> extraDeps = ImmutableSortedSet.<BuildRule>naturalOrder().addAll(params.getExtraDeps().get()).addAll(BuildRules.getExportedRules(Iterables.concat(declaredDeps, exportedDeps, resolver.getAllRules(args.providedDeps)))).addAll(ruleFinder.filterBuildRuleInputs(javacOptions.getInputs(ruleFinder))).addAll(compiler.getExtraDeps(args, resolver)).build();
SourcePathResolver pathResolver = new SourcePathResolver(ruleFinder);
BuildRuleParams androidLibraryParams = params.copyReplacingDeclaredAndExtraDeps(Suppliers.ofInstance(declaredDeps), Suppliers.ofInstance(extraDeps));
return new AndroidLibrary(androidLibraryParams, pathResolver, ruleFinder, args.srcs, ResourceValidator.validateResources(pathResolver, params.getProjectFilesystem(), args.resources), args.proguardConfig, args.postprocessClassesCommands, exportedDeps, resolver.getAllRules(args.providedDeps), JavaLibraryRules.getAbiInputs(resolver, androidLibraryParams.getDeps()), additionalClasspathEntries, javacOptions, compiler.trackClassUsage(javacOptions), compiler.compileToJar(args, javacOptions, resolver), args.resourcesRoot, args.mavenCoords, args.manifest, args.tests);
}
}
use of org.apache.beam.vendor.calcite.v1_28_0.com.google.common.collect.ImmutableSet in project buck by facebook.
the class AndroidBinaryDescription method addFallbackLocales.
private ImmutableSet<String> addFallbackLocales(ImmutableSet<String> locales) {
ImmutableSet.Builder<String> allLocales = ImmutableSet.builder();
for (String locale : locales) {
allLocales.add(locale);
Matcher matcher = COUNTRY_LOCALE_PATTERN.matcher(locale);
if (matcher.matches()) {
allLocales.add(matcher.group(1));
}
}
return allLocales.build();
}
use of org.apache.beam.vendor.calcite.v1_28_0.com.google.common.collect.ImmutableSet in project buck by facebook.
the class AppleCoreSimulatorServiceController method getMatchingServiceNames.
private ImmutableSet<String> getMatchingServiceNames(Pattern serviceNamePattern) throws IOException, InterruptedException {
ImmutableList<String> launchctlListCommand = ImmutableList.of("launchctl", "list");
LOG.debug("Getting list of services with %s", launchctlListCommand);
ProcessExecutorParams launchctlListParams = ProcessExecutorParams.builder().setCommand(launchctlListCommand).build();
ProcessExecutor.LaunchedProcess launchctlListProcess = processExecutor.launchProcess(launchctlListParams);
ImmutableSet.Builder<String> resultBuilder = ImmutableSet.builder();
try (InputStreamReader stdoutReader = new InputStreamReader(launchctlListProcess.getInputStream(), StandardCharsets.UTF_8);
BufferedReader bufferedStdoutReader = new BufferedReader(stdoutReader)) {
String line;
while ((line = bufferedStdoutReader.readLine()) != null) {
Matcher launchctlListOutputMatcher = LAUNCHCTL_LIST_OUTPUT_PATTERN.matcher(line);
if (launchctlListOutputMatcher.matches()) {
String serviceName = launchctlListOutputMatcher.group(3);
Matcher serviceNameMatcher = serviceNamePattern.matcher(serviceName);
if (serviceNameMatcher.find()) {
LOG.debug("Found matching service name: %s", serviceName);
resultBuilder.add(serviceName);
}
}
}
} finally {
processExecutor.destroyLaunchedProcess(launchctlListProcess);
processExecutor.waitForLaunchedProcess(launchctlListProcess);
}
return resultBuilder.build();
}
Aggregations