| package org.jetbrains.jps.android; |
| |
| import com.android.sdklib.IAndroidTarget; |
| import com.android.tools.idea.jps.AndroidTargetBuilder; |
| import com.intellij.openapi.util.io.FileUtil; |
| import com.intellij.util.ArrayUtil; |
| import com.intellij.util.PathUtilRt; |
| import com.intellij.util.Processor; |
| import org.jetbrains.android.compiler.tools.AndroidApt; |
| import org.jetbrains.android.util.AndroidCompilerMessageKind; |
| import org.jetbrains.annotations.NonNls; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| import org.jetbrains.jps.android.builder.AndroidResourcePackagingBuildTarget; |
| import org.jetbrains.jps.android.model.JpsAndroidModuleExtension; |
| import org.jetbrains.jps.builders.BuildOutputConsumer; |
| import org.jetbrains.jps.builders.BuildRootDescriptor; |
| import org.jetbrains.jps.builders.DirtyFilesHolder; |
| import org.jetbrains.jps.incremental.CompileContext; |
| import org.jetbrains.jps.incremental.ProjectBuildException; |
| import org.jetbrains.jps.incremental.StopBuildException; |
| import org.jetbrains.jps.incremental.messages.BuildMessage; |
| import org.jetbrains.jps.incremental.messages.CompilerMessage; |
| import org.jetbrains.jps.incremental.messages.ProgressMessage; |
| import org.jetbrains.jps.indices.IgnoredFileIndex; |
| import org.jetbrains.jps.model.module.JpsModule; |
| |
| import java.io.File; |
| import java.io.FileFilter; |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.Map; |
| |
| /** |
| * @author Eugene.Kudelevsky |
| */ |
| public class AndroidResourcePackagingBuilder extends AndroidTargetBuilder<BuildRootDescriptor, AndroidResourcePackagingBuildTarget> { |
| @NonNls private static final String BUILDER_NAME = "Android Resource Packaging"; |
| |
| protected AndroidResourcePackagingBuilder() { |
| super(Collections.singletonList(AndroidResourcePackagingBuildTarget.MyTargetType.INSTANCE)); |
| } |
| |
| @Override |
| protected void buildTarget(@NotNull AndroidResourcePackagingBuildTarget target, |
| @NotNull DirtyFilesHolder<BuildRootDescriptor, AndroidResourcePackagingBuildTarget> holder, |
| @NotNull BuildOutputConsumer outputConsumer, |
| @NotNull CompileContext context) throws ProjectBuildException, IOException { |
| final boolean releaseBuild = AndroidJpsUtil.isReleaseBuild(context); |
| final AndroidPackagingStateStorage packagingStateStorage = |
| context.getProjectDescriptor().dataManager.getStorage(target, AndroidPackagingStateStorage.Provider.INSTANCE); |
| |
| if (!holder.hasDirtyFiles() && !holder.hasRemovedFiles()) { |
| final AndroidPackagingStateStorage.MyState savedState = packagingStateStorage.read(); |
| |
| if (savedState != null && savedState.isRelease() == releaseBuild) { |
| return; |
| } |
| } |
| assert !AndroidJpsUtil.isLightBuild(context); |
| |
| if (!packageResources(target, context, outputConsumer, releaseBuild)) { |
| throw new StopBuildException(); |
| } |
| packagingStateStorage.saveState(new AndroidPackagingStateStorage.MyState(releaseBuild)); |
| } |
| |
| @NotNull |
| @Override |
| public String getPresentableName() { |
| return BUILDER_NAME; |
| } |
| |
| private static boolean packageResources(@NotNull AndroidResourcePackagingBuildTarget target, |
| @NotNull CompileContext context, |
| @NotNull BuildOutputConsumer outputConsumer, |
| boolean releaseBuild) { |
| final JpsModule module = target.getModule(); |
| final JpsAndroidModuleExtension extension = AndroidJpsUtil.getExtension(module); |
| assert extension != null && !extension.isLibrary(); |
| |
| context.processMessage(new ProgressMessage(AndroidJpsBundle.message("android.jps.progress.packaging.resources", module.getName()))); |
| |
| final File manifestFile = AndroidJpsUtil.getPreprocessedManifestFile(extension, context. |
| getProjectDescriptor().dataManager.getDataPaths()); |
| |
| if (manifestFile == null || !manifestFile.exists()) { |
| context.processMessage(new CompilerMessage( |
| BUILDER_NAME, BuildMessage.Kind.ERROR, |
| AndroidJpsBundle.message("android.jps.errors.manifest.not.found", module.getName()))); |
| return false; |
| } |
| final ArrayList<String> assetsDirPaths = new ArrayList<String>(); |
| AndroidResourcePackagingBuildTarget.collectAssetDirs(extension, assetsDirPaths, true); |
| |
| final String outputFilePath = target.getOutputFile(context).getPath(); |
| File outputDir = new File(outputFilePath).getParentFile(); |
| assert outputDir != null; |
| outputDir = AndroidJpsUtil.createDirIfNotExist(outputDir, context, BUILDER_NAME); |
| |
| if (outputDir == null) { |
| return false; |
| } |
| final AndroidPlatform platform = AndroidJpsUtil.getAndroidPlatform(module, context, BUILDER_NAME); |
| |
| if (platform == null) { |
| return false; |
| } |
| final IAndroidTarget androidTarget = platform.getTarget(); |
| final String[] resourceDirPaths = AndroidJpsUtil.collectResourceDirsForCompilation(extension, true, context, true); |
| |
| final String customManifestPackage = extension.isUseCustomManifestPackage() |
| ? extension.getCustomManifestPackage() |
| : null; |
| final String additionalParameters = extension.getAdditionalPackagingCommandLineParameters(); |
| |
| return doPackageResources(context, manifestFile, androidTarget, resourceDirPaths, ArrayUtil.toStringArray(assetsDirPaths), |
| outputFilePath, releaseBuild, module.getName(), outputConsumer, customManifestPackage, additionalParameters); |
| } |
| |
| private static boolean doPackageResources(@NotNull final CompileContext context, |
| @NotNull File manifestFile, |
| @NotNull IAndroidTarget target, |
| @NotNull String[] resourceDirPaths, |
| @NotNull String[] assetsDirPaths, |
| @NotNull String outputPath, |
| boolean releasePackage, |
| @NotNull String moduleName, |
| @NotNull BuildOutputConsumer outputConsumer, |
| @Nullable String customManifestPackage, |
| @Nullable String additionalParameters) { |
| try { |
| final IgnoredFileIndex ignoredFileIndex = context.getProjectDescriptor().getIgnoredFileIndex(); |
| |
| final Map<AndroidCompilerMessageKind, List<String>> messages = AndroidApt |
| .packageResources(target, -1, manifestFile.getPath(), resourceDirPaths, assetsDirPaths, outputPath, null, |
| !releasePackage, 0, customManifestPackage, additionalParameters, new FileFilter() { |
| @Override |
| public boolean accept(File pathname) { |
| return !ignoredFileIndex.isIgnored(PathUtilRt.getFileName(pathname.getPath())); |
| } |
| }); |
| |
| AndroidJpsUtil.addMessages(context, messages, BUILDER_NAME, moduleName); |
| final boolean success = messages.get(AndroidCompilerMessageKind.ERROR).size() == 0; |
| |
| if (success) { |
| final List<String> srcFiles = new ArrayList<String>(); |
| srcFiles.add(manifestFile.getPath()); |
| fillRecursively(resourceDirPaths, srcFiles); |
| fillRecursively(assetsDirPaths, srcFiles); |
| |
| outputConsumer.registerOutputFile(new File(outputPath), srcFiles); |
| } |
| return success; |
| } |
| catch (final IOException e) { |
| AndroidJpsUtil.reportExceptionError(context, null, e, BUILDER_NAME); |
| return false; |
| } |
| } |
| |
| private static void fillRecursively(String[] roots, final List<String> result) { |
| for (String root : roots) { |
| FileUtil.processFilesRecursively(new File(root), new Processor<File>() { |
| @Override |
| public boolean process(File file) { |
| if (file.isFile()) { |
| result.add(file.getPath()); |
| } |
| return true; |
| } |
| }); |
| } |
| } |
| } |