<commit_before>/*
 * Copyright 2000-2010 JetBrains s.r.o.
 *
 * 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 org.jetbrains.android.compiler;

import com.android.sdklib.IAndroidTarget;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.compiler.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.android.compiler.tools.AndroidApt;
import org.jetbrains.android.dom.manifest.Application;
import org.jetbrains.android.dom.manifest.Manifest;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.facet.AndroidFacetConfiguration;
import org.jetbrains.android.facet.AndroidRootUtil;
import org.jetbrains.android.sdk.AndroidPlatform;
import org.jetbrains.android.util.AndroidBundle;
import org.jetbrains.android.util.AndroidUtils;
import org.jetbrains.annotations.NotNull;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.File;
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 AndroidResourcesPackagingCompiler implements ClassPostProcessingCompiler {
  private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.compiler.AndroidResourcesPackagingCompiler");

  public static final String RELEASE_SUFFIX = ".release";

  @NotNull
  @Override
  public ProcessingItem[] getProcessingItems(CompileContext context) {
    final List<ProcessingItem> items = new ArrayList<ProcessingItem>();
    for (Module module : ModuleManager.getInstance(context.getProject()).getModules()) {
      AndroidFacet facet = AndroidFacet.getInstance(module);
      if (facet != null && !facet.getConfiguration().LIBRARY_PROJECT) {
        VirtualFile manifestFile = AndroidRootUtil.getManifestFileForCompiler(facet);
        VirtualFile assetsDir = AndroidRootUtil.getAssetsDir(module);
        if (manifestFile == null) {
          context.addMessage(CompilerMessageCategory.ERROR, AndroidBundle.message("android.compilation.error.manifest.not.found"),
                             null, -1, -1);
          continue;
        }
        AndroidFacetConfiguration configuration = facet.getConfiguration();
        VirtualFile outputDir = AndroidDexCompiler.getOutputDirectoryForDex(module);
        if (outputDir != null) {
          String outputPath = getOutputFile(module, outputDir).getPath();
          
          final AndroidPlatform platform = configuration.getAndroidPlatform();
          
          if (platform != null) {
            String assetsDirPath = assetsDir != null ? assetsDir.getPath() : null;
            String[] resourcesDirPaths = AndroidCompileUtil.collectResourceDirs(facet, true, context);
            final IAndroidTarget target = platform.getTarget();
            final int platformToolsRevision = platform.getSdk().getPlatformToolsRevision();

            if (resourcesDirPaths.length == 0) {
              context.addMessage(CompilerMessageCategory.WARNING, "Resource directory not found for module " + module.getName(),
                                 null, -1, -1);
            }

            items.add(new MyItem(module, target, platformToolsRevision, manifestFile, resourcesDirPaths, assetsDirPath, outputPath,
                                 configuration.GENERATE_UNSIGNED_APK, AndroidCompileUtil.isReleaseBuild(context)));
            //items.add(new MyItem(module, target, manifestFile, resourcesDirPaths, assetsDirPath, outputPath + RELEASE_SUFFIX, true));
          }
        }
      }
    }
    return items.toArray(new ProcessingItem[items.size()]);
  }

  static File getOutputFile(Module module, VirtualFile outputDir) {
    return new File(outputDir.getPath(), module.getName() + ".apk.res");
  }

  @Override
  public ProcessingItem[] process(final CompileContext context, ProcessingItem[] items) {
    if (!AndroidCompileUtil.isFullBuild(context)) {
      return ProcessingItem.EMPTY_ARRAY;
    }

    context.getProgressIndicator().setText("Packaging Android resources...");
    final List<ProcessingItem> result = new ArrayList<ProcessingItem>();
    for (ProcessingItem processingItem : items) {
      MyItem item = (MyItem)processingItem;

      if (!AndroidCompileUtil.isModuleAffected(context, item.myModule)) {
        continue;
      }

      doProcess(context, item, false);

      if (context.getMessages(CompilerMessageCategory.ERROR).length == 0) {
        doProcess(context, item, true);
      }

      if (context.getMessages(CompilerMessageCategory.ERROR).length == 0) {
        result.add(item);
      }
    }
    return result.toArray(new ProcessingItem[result.size()]);
  }

  private static void doProcess(final CompileContext context, MyItem item, boolean releasePackage) {
    if (!AndroidPackagingCompiler.shouldGenerateApk(item.myModule, context, releasePackage)) {
      return;
    }

    final VirtualFile preprocessedManifestFile;
    try {
      preprocessedManifestFile = releasePackage
                                 ? item.myManifestFile
                                 : copyManifestAndSetDebuggableToTrue(item.myModule, item.myManifestFile);
    }
    catch (IOException e) {
      LOG.info(e);
      context.addMessage(CompilerMessageCategory.ERROR, "Cannot preprocess AndroidManifest.xml for debug build",
                         item.myManifestFile.getUrl(), -1, -1);
      return;
    }

    final Map<VirtualFile, VirtualFile> presentableFilesMap = Collections.singletonMap(item.myManifestFile, preprocessedManifestFile);

    try {
      final String outputPath = releasePackage
                                ? item.myOutputPath + RELEASE_SUFFIX
                                : item.myOutputPath;

      Map<CompilerMessageCategory, List<String>> messages = AndroidApt.packageResources(item.myAndroidTarget,
                                                                                        item.myPlatformToolsRevision,
                                                                                        preprocessedManifestFile.getPath(),
                                                                                        item.myResourceDirPaths,
                                                                                        item.myAssetsDirPath,
                                                                                        outputPath, null, false, 0);
      AndroidCompileUtil.addMessages(context, messages, presentableFilesMap);
    }
    catch (final IOException e) {
      ApplicationManager.getApplication().runReadAction(new Runnable() {
        public void run() {
          if (context.getProject().isDisposed()) return;
          context.addMessage(CompilerMessageCategory.ERROR, e.getMessage(), null, -1, -1);
        }
      });
    }
  }

  private static VirtualFile copyManifestAndSetDebuggableToTrue(@NotNull final Module module, @NotNull final VirtualFile manifestFile)
    throws IOException {
<commit_msg>android packaging: correct value of 'debug-mode' parameter<commit_after>/*
 * Copyright 2000-2010 JetBrains s.r.o.
 *
 * 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 org.jetbrains.android.compiler;

import com.android.sdklib.IAndroidTarget;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.compiler.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.android.compiler.tools.AndroidApt;
import org.jetbrains.android.dom.manifest.Application;
import org.jetbrains.android.dom.manifest.Manifest;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.facet.AndroidFacetConfiguration;
import org.jetbrains.android.facet.AndroidRootUtil;
import org.jetbrains.android.sdk.AndroidPlatform;
import org.jetbrains.android.util.AndroidBundle;
import org.jetbrains.android.util.AndroidUtils;
import org.jetbrains.annotations.NotNull;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.File;
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 AndroidResourcesPackagingCompiler implements ClassPostProcessingCompiler {
  private static final Logger LOG = Logger.getInstance("#org.jetbrains.android.compiler.AndroidResourcesPackagingCompiler");

  public static final String RELEASE_SUFFIX = ".release";

  @NotNull
  @Override
  public ProcessingItem[] getProcessingItems(CompileContext context) {
    final List<ProcessingItem> items = new ArrayList<ProcessingItem>();
    for (Module module : ModuleManager.getInstance(context.getProject()).getModules()) {
      AndroidFacet facet = AndroidFacet.getInstance(module);
      if (facet != null && !facet.getConfiguration().LIBRARY_PROJECT) {
        VirtualFile manifestFile = AndroidRootUtil.getManifestFileForCompiler(facet);
        VirtualFile assetsDir = AndroidRootUtil.getAssetsDir(module);
        if (manifestFile == null) {
          context.addMessage(CompilerMessageCategory.ERROR, AndroidBundle.message("android.compilation.error.manifest.not.found"),
                             null, -1, -1);
          continue;
        }
        AndroidFacetConfiguration configuration = facet.getConfiguration();
        VirtualFile outputDir = AndroidDexCompiler.getOutputDirectoryForDex(module);
        if (outputDir != null) {
          String outputPath = getOutputFile(module, outputDir).getPath();
          
          final AndroidPlatform platform = configuration.getAndroidPlatform();
          
          if (platform != null) {
            String assetsDirPath = assetsDir != null ? assetsDir.getPath() : null;
            String[] resourcesDirPaths = AndroidCompileUtil.collectResourceDirs(facet, true, context);
            final IAndroidTarget target = platform.getTarget();
            final int platformToolsRevision = platform.getSdk().getPlatformToolsRevision();

            if (resourcesDirPaths.length == 0) {
              context.addMessage(CompilerMessageCategory.WARNING, "Resource directory not found for module " + module.getName(),
                                 null, -1, -1);
            }

            items.add(new MyItem(module, target, platformToolsRevision, manifestFile, resourcesDirPaths, assetsDirPath, outputPath,
                                 configuration.GENERATE_UNSIGNED_APK, AndroidCompileUtil.isReleaseBuild(context)));
            //items.add(new MyItem(module, target, manifestFile, resourcesDirPaths, assetsDirPath, outputPath + RELEASE_SUFFIX, true));
          }
        }
      }
    }
    return items.toArray(new ProcessingItem[items.size()]);
  }

  static File getOutputFile(Module module, VirtualFile outputDir) {
    return new File(outputDir.getPath(), module.getName() + ".apk.res");
  }

  @Override
  public ProcessingItem[] process(final CompileContext context, ProcessingItem[] items) {
    if (!AndroidCompileUtil.isFullBuild(context)) {
      return ProcessingItem.EMPTY_ARRAY;
    }

    context.getProgressIndicator().setText("Packaging Android resources...");
    final List<ProcessingItem> result = new ArrayList<ProcessingItem>();
    for (ProcessingItem processingItem : items) {
      MyItem item = (MyItem)processingItem;

      if (!AndroidCompileUtil.isModuleAffected(context, item.myModule)) {
        continue;
      }

      doProcess(context, item, false);

      if (context.getMessages(CompilerMessageCategory.ERROR).length == 0) {
        doProcess(context, item, true);
      }

      if (context.getMessages(CompilerMessageCategory.ERROR).length == 0) {
        result.add(item);
      }
    }
    return result.toArray(new ProcessingItem[result.size()]);
  }

  private static void doProcess(final CompileContext context, MyItem item, boolean releasePackage) {
    if (!AndroidPackagingCompiler.shouldGenerateApk(item.myModule, context, releasePackage)) {
      return;
    }

    final VirtualFile preprocessedManifestFile;
    try {
      preprocessedManifestFile = releasePackage
                                 ? item.myManifestFile
                                 : copyManifestAndSetDebuggableToTrue(item.myModule, item.myManifestFile);
    }
    catch (IOException e) {
      LOG.info(e);
      context.addMessage(CompilerMessageCategory.ERROR, "Cannot preprocess AndroidManifest.xml for debug build",
                         item.myManifestFile.getUrl(), -1, -1);
      return;
    }

    final Map<VirtualFile, VirtualFile> presentableFilesMap = Collections.singletonMap(item.myManifestFile, preprocessedManifestFile);

    try {
      final String outputPath = releasePackage
                                ? item.myOutputPath + RELEASE_SUFFIX
                                : item.myOutputPath;

      Map<CompilerMessageCategory, List<String>> messages = AndroidApt.packageResources(item.myAndroidTarget,
                                                                                        item.myPlatformToolsRevision,
                                                                                        preprocessedManifestFile.getPath(),
                                                                                        item.myResourceDirPaths,
                                                                                        item.myAssetsDirPath,
                                                                                        outputPath, null, !releasePackage, 0);
      AndroidCompileUtil.addMessages(context, messages, presentableFilesMap);
    }
    catch (final IOException e) {
      ApplicationManager.getApplication().runReadAction(new Runnable() {
        public void run() {
          if (context.getProject().isDisposed()) return;
          context.addMessage(CompilerMessageCategory.ERROR, e.getMessage(), null, -1, -1);
        }
      });
    }
  }

  private static VirtualFile copyManifestAndSetDebuggableToTrue(@NotNull final Module module, @NotNull final VirtualFile manifestFile)
    throws IOException {

{'fraction_non_alphanumeric': 0.0904899135446686, 'fraction_numerical': 0.003073967339097022, 'mean_word_length': 2.7847794474066894, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 52, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1093958', 'n_tokens_mistral': 3958, 'n_tokens_neox': 3841, 'n_words': 864}