private void addResourceProcessingSteps( Path sourcePath, Path destinationPath, ImmutableList.Builder<Step> stepsBuilder) { String sourcePathExtension = Files.getFileExtension(sourcePath.toString()).toLowerCase(Locale.US); switch (sourcePathExtension) { case "plist": case "stringsdict": LOG.debug("Converting plist %s to binary plist %s", sourcePath, destinationPath); stepsBuilder.add( new PlistProcessStep( sourcePath, destinationPath, ImmutableMap.<String, NSObject>of(), ImmutableMap.<String, NSObject>of(), PlistProcessStep.OutputFormat.BINARY)); break; case "xib": String compiledNibFilename = Files.getNameWithoutExtension(destinationPath.toString()) + ".nib"; Path compiledNibPath = destinationPath.getParent().resolve(compiledNibFilename); LOG.debug("Compiling XIB %s to NIB %s", sourcePath, destinationPath); stepsBuilder.add( new IbtoolStep(ibtool.getCommandPrefix(getResolver()), sourcePath, compiledNibPath)); break; default: stepsBuilder.add(CopyStep.forFile(sourcePath, destinationPath)); break; } }
public void addStepsToCopyExtensionBundlesDependencies(ImmutableList.Builder<Step> stepsBuilder) { for (SourcePath sourcePath : extensionBundlePaths) { Path plugInsDestPath = bundleRoot.resolve(destinations.getPlugInsPath()); stepsBuilder.add(new MkdirStep(plugInsDestPath)); stepsBuilder.add( CopyStep.forDirectory( getResolver().getPath(sourcePath), plugInsDestPath, CopyStep.DirectoryMode.DIRECTORY_AND_CONTENTS)); } }
@Override public ImmutableList<Step> getBuildSteps( BuildContext context, final BuildableContext buildableContext) { ImmutableList.Builder<Step> steps = ImmutableList.builder(); // Create a copy of the JAR in case it was generated by another rule. Path resolvedBinaryJar = getResolver().getAbsolutePath(binaryJar); steps.add(new MkdirStep(getProjectFilesystem(), copiedBinaryJar.getParent())); steps.add(CopyStep.forFile(getProjectFilesystem(), resolvedBinaryJar, copiedBinaryJar)); buildableContext.recordArtifact(copiedBinaryJar); // Create a step to compute the ABI key. steps.add(new MkdirStep(getProjectFilesystem(), internalAbiJar.getParent())); steps.add(new RmStep(getProjectFilesystem(), internalAbiJar, true)); steps.add( new CalculateAbiStep( buildableContext, getProjectFilesystem(), resolvedBinaryJar, internalAbiJar)); JavaLibraryRules.addAccumulateClassNamesStep(this, buildableContext, steps); return steps.build(); }
@Override public ImmutableList<Step> getBuildSteps( BuildContext context, BuildableContext buildableContext) { ImmutableList.Builder<Step> stepsBuilder = ImmutableList.builder(); Path metadataPath = getMetadataPath(); Path infoPlistInputPath = getResolver().getPath(infoPlist); Path infoPlistSubstitutionTempPath = BuildTargets.getScratchPath(getBuildTarget(), "%s.plist"); Path infoPlistOutputPath = metadataPath.resolve("Info.plist"); stepsBuilder.add( new MakeCleanDirectoryStep(bundleRoot), new MkdirStep(metadataPath), // TODO(user): This is only appropriate for .app bundles. new WriteFileStep("APPLWRUN", metadataPath.resolve("PkgInfo"), /* executable */ false), new FindAndReplaceStep( infoPlistInputPath, infoPlistSubstitutionTempPath, InfoPlistSubstitution.createVariableExpansionFunction( withDefaults( infoPlistSubstitutions, ImmutableMap.of( "EXECUTABLE_NAME", binaryName, "PRODUCT_NAME", binaryName)))), new PlistProcessStep( infoPlistSubstitutionTempPath, infoPlistOutputPath, getInfoPlistAdditionalKeys(platformName, sdkName), getInfoPlistOverrideKeys(platformName), PlistProcessStep.OutputFormat.BINARY)); if (binary.isPresent() && binary.get().getPathToOutput() != null) { stepsBuilder.add(new MkdirStep(bundleRoot.resolve(this.destinations.getExecutablesPath()))); Path bundleBinaryPath = bundleRoot.resolve(binaryPath); stepsBuilder.add(CopyStep.forFile(binary.get().getPathToOutput(), bundleBinaryPath)); stepsBuilder.add( new DsymStep( dsymutil.getCommandPrefix(getResolver()), bundleBinaryPath, bundleBinaryPath.resolveSibling( bundleBinaryPath.getFileName().toString() + ".dSYM"))); stepsBuilder.add( new DefaultShellStep( ImmutableList.<String>builder() .addAll(strip.getCommandPrefix(getResolver())) .add("-S") .add(getProjectFilesystem().resolve(bundleBinaryPath).toString()) .build())); } Path bundleDestinationPath = bundleRoot.resolve(this.destinations.getResourcesPath()); for (SourcePath dir : resourceDirs) { stepsBuilder.add(new MkdirStep(bundleDestinationPath)); stepsBuilder.add( CopyStep.forDirectory( getResolver().getPath(dir), bundleDestinationPath, CopyStep.DirectoryMode.DIRECTORY_AND_CONTENTS)); } for (SourcePath dir : dirsContainingResourceDirs) { stepsBuilder.add(new MkdirStep(bundleDestinationPath)); stepsBuilder.add( CopyStep.forDirectory( getResolver().getPath(dir), bundleDestinationPath, CopyStep.DirectoryMode.CONTENTS_ONLY)); } for (SourcePath file : resourceFiles) { stepsBuilder.add(new MkdirStep(bundleDestinationPath)); Path resolvedFilePath = getResolver().getPath(file); Path destinationPath = bundleDestinationPath.resolve(resolvedFilePath.getFileName()); addResourceProcessingSteps(resolvedFilePath, destinationPath, stepsBuilder); } addStepsToCopyExtensionBundlesDependencies(stepsBuilder); if (resourceVariantFiles.isPresent()) { for (SourcePath variantSourcePath : resourceVariantFiles.get()) { Path variantFilePath = getResolver().getPath(variantSourcePath); Path variantDirectory = variantFilePath.getParent(); if (variantDirectory == null || !variantDirectory.toString().endsWith(".lproj")) { throw new HumanReadableException( "Variant files have to be in a directory with name ending in '.lproj', " + "but '%s' is not.", variantFilePath); } Path bundleVariantDestinationPath = bundleDestinationPath.resolve(variantDirectory.getFileName()); stepsBuilder.add(new MkdirStep(bundleVariantDestinationPath)); Path destinationPath = bundleVariantDestinationPath.resolve(variantFilePath.getFileName()); addResourceProcessingSteps(variantFilePath, destinationPath, stepsBuilder); } } if (assetCatalog.isPresent()) { Path bundleDir = assetCatalog.get().getOutputDir(); stepsBuilder.add( CopyStep.forDirectory(bundleDir, bundleRoot, CopyStep.DirectoryMode.CONTENTS_ONLY)); } // Copy the .mobileprovision file if the platform requires it. if (provisioningProfiles.isPresent()) { Optional<Path> entitlementsPlist = Optional.absent(); final String srcRoot = context.getProjectRoot().resolve(getBuildTarget().getBasePath()).toString(); Optional<String> entitlementsPlistString = InfoPlistSubstitution.getVariableExpansionForPlatform( CODE_SIGN_ENTITLEMENTS, platformName, withDefaults( infoPlistSubstitutions, ImmutableMap.of( "SOURCE_ROOT", srcRoot, "SRCROOT", srcRoot))); if (entitlementsPlistString.isPresent()) { entitlementsPlist = Optional.of(Paths.get(entitlementsPlistString.get())); } final Path signingEntitlementsTempPath = BuildTargets.getScratchPath(getBuildTarget(), "%s.xcent"); stepsBuilder.add( new ProvisioningProfileCopyStep( infoPlistOutputPath, Optional.<String>absent(), // Provisioning profile UUID -- find automatically. entitlementsPlist, provisioningProfiles.get(), bundleDestinationPath.resolve("embedded.mobileprovision"), signingEntitlementsTempPath)); stepsBuilder.add( new CodeSignStep( bundleDestinationPath, signingEntitlementsTempPath, codeSignIdentity.get().getHash())); } // Ensure the bundle directory is archived so we can fetch it later. buildableContext.recordArtifact(getPathToOutput()); return stepsBuilder.build(); }
@Override public ImmutableList<Step> getBuildSteps( BuildContext context, BuildableContext buildableContext) { ImmutableList.Builder<Step> commands = ImmutableList.builder(); // Create temp folder to store the files going to be zipped commands.add(new MakeCleanDirectoryStep(getProjectFilesystem(), temp)); // Remove the output .aar file commands.add(new RmStep(getProjectFilesystem(), pathToOutputFile, /* force delete */ true)); // put manifest into tmp folder commands.add( CopyStep.forFile( getProjectFilesystem(), manifest.getPathToOutput(), temp.resolve("AndroidManifest.xml"))); // put R.txt into tmp folder commands.add( CopyStep.forFile( getProjectFilesystem(), Preconditions.checkNotNull(androidResource.getPathToOutput()), temp.resolve("R.txt"))); // put res/ and assets/ into tmp folder commands.add( CopyStep.forDirectory( getProjectFilesystem(), assembledResourceDirectory, temp.resolve("res"), CopyStep.DirectoryMode.CONTENTS_ONLY)); commands.add( CopyStep.forDirectory( getProjectFilesystem(), assembledAssetsDirectory, temp.resolve("assets"), CopyStep.DirectoryMode.CONTENTS_ONLY)); // Create our Uber-jar, and place it in the tmp folder. commands.add( new JarDirectoryStep( getProjectFilesystem(), temp.resolve("classes.jar"), ImmutableSet.copyOf(getTransitiveClasspathEntries().values()), null, null)); // move native libs into tmp folder under jni/ if (assembledNativeLibs.isPresent()) { commands.add( CopyStep.forDirectory( getProjectFilesystem(), assembledNativeLibs.get(), temp.resolve("jni"), CopyStep.DirectoryMode.CONTENTS_ONLY)); } // move native assets into tmp folder under assets/lib/ for (SourcePath dir : nativeLibAssetsDirectories) { CopyNativeLibraries.copyNativeLibrary( getProjectFilesystem(), getResolver().getPath(dir), temp.resolve("assets").resolve("lib"), ImmutableSet.<TargetCpuType>of(), commands); } // do the zipping commands.add( new ZipStep( getProjectFilesystem(), pathToOutputFile, ImmutableSet.<Path>of(), false, ZipStep.DEFAULT_COMPRESSION_LEVEL, temp)); return commands.build(); }
public static void copyNativeLibrary( final ProjectFilesystem filesystem, Path sourceDir, final Path destinationDir, ImmutableSet<TargetCpuType> cpuFilters, ImmutableList.Builder<Step> steps) { if (cpuFilters.isEmpty()) { steps.add( CopyStep.forDirectory(sourceDir, destinationDir, CopyStep.DirectoryMode.CONTENTS_ONLY)); } else { for (TargetCpuType cpuType : cpuFilters) { Optional<String> abiDirectoryComponent = getAbiDirectoryComponent(cpuType); Preconditions.checkState(abiDirectoryComponent.isPresent()); final Path libSourceDir = sourceDir.resolve(abiDirectoryComponent.get()); Path libDestinationDir = destinationDir.resolve(abiDirectoryComponent.get()); final MkdirStep mkDirStep = new MkdirStep(libDestinationDir); final CopyStep copyStep = CopyStep.forDirectory( libSourceDir, libDestinationDir, CopyStep.DirectoryMode.CONTENTS_ONLY); steps.add( new Step() { @Override public int execute(ExecutionContext context) { // TODO(simons): Using a projectfilesystem here is almost definitely wrong. // This is because each library may come from different build rules, which may be in // different repos --- this check works by coincidence. if (!filesystem.exists(libSourceDir)) { return 0; } if (mkDirStep.execute(context) == 0 && copyStep.execute(context) == 0) { return 0; } return 1; } @Override public String getShortName() { return "copy_native_libraries"; } @Override public String getDescription(ExecutionContext context) { ImmutableList.Builder<String> stringBuilder = ImmutableList.builder(); stringBuilder.add(String.format("[ -d %s ]", libSourceDir.toString())); stringBuilder.add(mkDirStep.getDescription(context)); stringBuilder.add(copyStep.getDescription(context)); return Joiner.on(" && ").join(stringBuilder.build()); } }); } } // Rename native files named like "*-disguised-exe" to "lib*.so" so they will be unpacked // by the Android package installer. Then they can be executed like normal binaries // on the device. steps.add( new AbstractExecutionStep("rename_native_executables") { @Override public int execute(ExecutionContext context) { ProjectFilesystem filesystem = context.getProjectFilesystem(); final ImmutableSet.Builder<Path> executablesBuilder = ImmutableSet.builder(); try { filesystem.walkRelativeFileTree( destinationDir, new SimpleFileVisitor<Path>() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { if (file.toString().endsWith("-disguised-exe")) { executablesBuilder.add(file); } return FileVisitResult.CONTINUE; } }); for (Path exePath : executablesBuilder.build()) { Path fakeSoPath = Paths.get( MorePaths.pathWithUnixSeparators(exePath) .replaceAll("/([^/]+)-disguised-exe$", "/lib$1.so")); filesystem.move(exePath, fakeSoPath); } } catch (IOException e) { context.logError(e, "Renaming native executables failed."); return 1; } return 0; } }); }