From ffe624dfdd009a42bd52357fd2045793015e4ec1 Mon Sep 17 00:00:00 2001 From: Tor Norbye Date: Thu, 11 Dec 2014 14:59:27 -0800 Subject: 82393: Fix template instantiation in ADT First, implement a couple of new freemarker methods required by the templates. Second, switch the manifest merger over to the new Manifest merger. Change-Id: I26200d0a861ebddd4c4c92ebbba418ccb88fcb20 (cherry picked from commit d7d481fa5e19353d1636f4df8b9bf875539bbc81) --- .../templates/FmEscapePropertyValueMethod.java | 64 ++++++++++++++++++++++ .../wizards/templates/FmExtractLettersMethod.java | 4 +- .../wizards/templates/FmHasDependencyMethod.java | 49 +++++++++++++++++ .../wizards/templates/TemplateHandler.java | 55 ++++++++++++++++++- 4 files changed, 169 insertions(+), 3 deletions(-) create mode 100644 eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmEscapePropertyValueMethod.java create mode 100644 eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmHasDependencyMethod.java (limited to 'eclipse/plugins') diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmEscapePropertyValueMethod.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmEscapePropertyValueMethod.java new file mode 100644 index 0000000..c6dc704 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmEscapePropertyValueMethod.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * 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 com.android.ide.eclipse.adt.internal.wizards.templates; + +import com.android.utils.SdkUtils; +import freemarker.template.SimpleScalar; +import freemarker.template.TemplateMethodModel; +import freemarker.template.TemplateModel; +import freemarker.template.TemplateModelException; + +import java.io.IOException; +import java.io.StringWriter; +import java.util.List; +import java.util.Properties; + +/** Escapes a property value (such that its syntax is valid in a Java properties file */ +public class FmEscapePropertyValueMethod implements TemplateMethodModel { + @Override + public TemplateModel exec(List args) throws TemplateModelException { + if (args.size() != 1) { + throw new TemplateModelException("Wrong arguments"); + } + + // Slow, stupid implementation, but is 100% compatible with Java's property file implementation + Properties properties = new Properties(); + String value = args.get(0).toString(); + properties.setProperty("k", value); // key doesn't matter + StringWriter writer = new StringWriter(); + String escaped; + try { + properties.store(writer, null); + String s = writer.toString(); + int end = s.length(); + + // Writer inserts trailing newline + String lineSeparator = SdkUtils.getLineSeparator(); + if (s.endsWith(lineSeparator)) { + end -= lineSeparator.length(); + } + + int start = s.indexOf('='); + assert start != -1 : s; + escaped = s.substring(start + 1, end); + } + catch (IOException e) { + escaped = value; // shouldn't happen; we're not going to disk + } + + return new SimpleScalar(escaped); + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmExtractLettersMethod.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmExtractLettersMethod.java index 09fa81c..1f50161 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmExtractLettersMethod.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmExtractLettersMethod.java @@ -15,13 +15,13 @@ */ package com.android.ide.eclipse.adt.internal.wizards.templates; +import java.util.List; + import freemarker.template.SimpleScalar; import freemarker.template.TemplateMethodModel; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; -import java.util.List; - /** * Method invoked by FreeMarker to extract letters from a string; this will remove * any whitespace, punctuation and digits. diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmHasDependencyMethod.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmHasDependencyMethod.java new file mode 100644 index 0000000..1618969 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/FmHasDependencyMethod.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * 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 com.android.ide.eclipse.adt.internal.wizards.templates; + +import java.util.List; +import java.util.Map; + +import freemarker.template.TemplateBooleanModel; +import freemarker.template.TemplateMethodModelEx; +import freemarker.template.TemplateModel; +import freemarker.template.TemplateModelException; + +/** + * Method invoked by FreeMarker to check whether a given dependency is available + * in this module + */ +public class FmHasDependencyMethod implements TemplateMethodModelEx { + private final Map myParamMap; + + public FmHasDependencyMethod(Map paramMap) { + myParamMap = paramMap; + } + + @Override + public TemplateModel exec(List args) throws TemplateModelException { + if (args.size() != 1) { + throw new TemplateModelException("Wrong arguments"); + } + + // TODO: Try to figure out if the project has appcompat etc + // com.android.support:appcompat-v7 + + // Not yet implemented + return TemplateBooleanModel.FALSE; + } +} \ No newline at end of file diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateHandler.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateHandler.java index 8e11841..569e017 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateHandler.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateHandler.java @@ -43,9 +43,15 @@ import com.android.ide.eclipse.adt.internal.editors.layout.gle2.DomUtilities; import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; import com.android.ide.eclipse.adt.internal.sdk.AdtManifestMergeCallback; import com.android.manifmerger.ManifestMerger; +import com.android.manifmerger.ManifestMerger2; +import com.android.manifmerger.ManifestMerger2.Invoker.Feature; +import com.android.manifmerger.ManifestMerger2.MergeType; import com.android.manifmerger.MergerLog; +import com.android.manifmerger.MergingReport; +import com.android.manifmerger.XmlDocument; import com.android.resources.ResourceFolderType; import com.android.utils.SdkUtils; +import com.android.utils.StdLogger; import com.google.common.base.Charsets; import com.google.common.collect.Lists; import com.google.common.io.Files; @@ -351,7 +357,9 @@ class TemplateHandler { paramMap.put("escapeXmlAttribute", new FmEscapeXmlStringMethod()); //$NON-NLS-1$ paramMap.put("escapeXmlText", new FmEscapeXmlStringMethod()); //$NON-NLS-1$ paramMap.put("escapeXmlString", new FmEscapeXmlStringMethod()); //$NON-NLS-1$ + paramMap.put("escapePropertyValue", new FmEscapePropertyValueMethod()); //$NON-NLS-1$ paramMap.put("extractLetters", new FmExtractLettersMethod()); //$NON-NLS-1$ + paramMap.put("hasDependency", new FmHasDependencyMethod(paramMap)); //$NON-NLS-1$ // This should be handled better: perhaps declared "required packages" as part of the // inputs? (It would be better if we could conditionally disable template based @@ -757,7 +765,17 @@ class TemplateHandler { boolean ok; String fileName = to.getName(); if (fileName.equals(SdkConstants.FN_ANDROID_MANIFEST_XML)) { - modified = ok = mergeManifest(currentDocument, fragment); + if (Boolean.getBoolean("adt.use_old_manifest_merger")) { + modified = ok = mergeManifest(currentDocument, fragment); + } else { + XmlDocument doc = mergeManifest(currentXml, xml); + if (doc != null) { + currentDocument = doc.getXml(); + ok = modified = true; + } else { + ok = modified = false; + } + } } else { // Merge plain XML files String parentFolderName = to.getParent().getName(); @@ -924,6 +942,41 @@ class TemplateHandler { merger.process(currentManifest, fragment); } + /** Merges the given manifest fragment into the given manifest file */ + @Nullable + private static XmlDocument mergeManifest(@NonNull String currentText, @NonNull String mergeText) { + File mergeFile = null; + File currentFile = null; + try { + mergeFile = File.createTempFile("manifmerge", DOT_XML); + currentFile = File.createTempFile("main", DOT_XML); + Files.write(currentText, currentFile, Charsets.UTF_8); + Files.write(mergeText, mergeFile, Charsets.UTF_8); + StdLogger logger = new StdLogger(StdLogger.Level.INFO); + ManifestMerger2.Invoker merger = ManifestMerger2 + .newMerger(currentFile, logger, MergeType.APPLICATION) + .withFeatures(Feature.EXTRACT_FQCNS) + .addLibraryManifest(mergeFile); + MergingReport mergeReport = merger.merge(); + if (mergeReport.getMergedDocument().isPresent()) { + return mergeReport.getMergedDocument().get(); + } + return null; + } catch (IOException e) { + AdtPlugin.log(e, null); + } catch (ManifestMerger2.MergeFailureException e) { + AdtPlugin.log(e, null); + } finally { + if (mergeFile != null) { + mergeFile.delete(); + } + if (currentFile != null) { + currentFile.delete(); + } + } + return null; + } + /** * Makes a backup of the given file, if it exists, by renaming it to name~ * (and removing an old name~ file if it exists) -- cgit v1.1