diff options
author | Googler <noreply@google.com> | 2015-12-08 20:27:30 +0000 |
---|---|---|
committer | David Chen <dzc@google.com> | 2015-12-08 22:26:51 +0000 |
commit | 8ca78e61630f525d1f97c711952208efd14606f8 (patch) | |
tree | 9f12783d3354c8f1ef53b04e4da345249bc5a62e /src/objc_tools | |
parent | dfa6368490224a2f98d967736cef5803a82c3989 (diff) |
Plmerge receives arguments by a protobuf, introduces variable substitutions to plmerge.
As of this change plmerge can consume either a protobuf or command line arguments. Once bazel uses plmerge strictly with protobufs, the command line arguments will be deprecated.
--
MOS_MIGRATED_REVID=109716003
Diffstat (limited to 'src/objc_tools')
4 files changed, 215 insertions, 37 deletions
diff --git a/src/objc_tools/plmerge/BUILD b/src/objc_tools/plmerge/BUILD index 2dd46af95a..81268bc9b1 100644 --- a/src/objc_tools/plmerge/BUILD +++ b/src/objc_tools/plmerge/BUILD @@ -8,6 +8,7 @@ java_binary( deps = [ ":plmerge_lib", "//src/main/java/com/google/devtools/common/options", + "//src/main/protobuf:plmerge_proto", "//third_party:guava", "//third_party/java/dd_plist", ], @@ -17,9 +18,10 @@ java_library( name = "plmerge_lib", srcs = glob( ["java/**/*.java"], - exclude = ["java/**/PlMerge.java"], ), deps = [ + "//src/main/java/com/google/devtools/common/options", + "//src/main/protobuf:plmerge_proto", "//src/tools/xcode-common/java/com/google/devtools/build/xcode/common", "//src/tools/xcode-common/java/com/google/devtools/build/xcode/util", "//third_party:guava", diff --git a/src/objc_tools/plmerge/java/com/google/devtools/build/xcode/plmerge/MergingArguments.java b/src/objc_tools/plmerge/java/com/google/devtools/build/xcode/plmerge/MergingArguments.java new file mode 100644 index 0000000000..d278dc870a --- /dev/null +++ b/src/objc_tools/plmerge/java/com/google/devtools/build/xcode/plmerge/MergingArguments.java @@ -0,0 +1,117 @@ +// Copyright 2015 The Bazel Authors. All rights reserved. +// +// 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.google.devtools.build.xcode.plmerge; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableList.Builder; +import com.google.common.collect.ImmutableMap; +import com.google.devtools.build.xcode.plmerge.PlMerge.PlMergeOptions; +import com.google.devtools.build.xcode.plmerge.proto.PlMergeProtos.Control; + +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.util.List; +import java.util.Map; + +/** + * Container for data consumed by plmerge + */ +class MergingArguments { + + private final FileSystem fileSystem = FileSystems.getDefault(); + private final List<Path> sourceFilePaths; + private final String outFile; + private final Map<String, String> variableSubstitutions; + private final String primaryBundleId; + private final String fallbackBundleId; + + /** + * Build MergingArguments from a plmerge protobuf. + */ + public MergingArguments(Control control) { + ImmutableList.Builder<Path> sourceFilePathsBuilder = new Builder<>(); + for (String pathString : control.getSourceFileList()) { + sourceFilePathsBuilder.add(fileSystem.getPath(pathString)); + } + sourceFilePaths = sourceFilePathsBuilder.build(); + outFile = control.getOutFile(); + variableSubstitutions = control.getVariableSubstitutionMap(); + primaryBundleId = control.getPrimaryBundleId(); + fallbackBundleId = control.getFallbackBundleId(); + } + + /** + * Build MergingArguments from command line arguments passed to the plmerge executable. + */ + public MergingArguments(PlMergeOptions options) { + ImmutableList.Builder<Path> sourceFilePathsBuilder = new Builder<Path>(); + for (String sourceFile : options.sourceFiles) { + sourceFilePathsBuilder.add(fileSystem.getPath(sourceFile)); + } + + sourceFilePaths = sourceFilePathsBuilder.build(); + outFile = options.outFile; + variableSubstitutions = ImmutableMap.<String, String>of(); + primaryBundleId = options.primaryBundleId; + fallbackBundleId = options.fallbackBundleId; + } + + /** + * Returns paths to the plist files to merge relative to plmerge. These can be + * binary, XML, or ASCII format. + */ + public List<Path> getSourceFilePaths() { + return sourceFilePaths; + } + + /** + * Returns path to the output file to merge relative to plmerge. + */ + public String getOutFile() { + return outFile; + } + + /** + * Returns a reverse-DNS string identifier for this bundle associated with output + * binary plist. Overrides the bundle id specified in the CFBundleIdentifier + * plist field. + */ + public String getPrimaryBundleId() { + return primaryBundleId; + } + + /** + * Returns a fallback reverse-DNS string identifier for this bundle when bundle + * identifier is not specified in primary_bundle_id or an associated plist + * file. + */ + public String getFallbackBundleId() { + return fallbackBundleId; + } + + /** + * Returns key-value substitutions to support templating for plists. A substitution + * is made if the substitution key appears as a value for any key-value pair + * in any source_file. + * For example, a plist with the entry: + * <pre><key>CFBundleExectuable</key> + * <string>EXECUTABLE_NAME</string></pre> + * could be templated by passing a variable substitution like + * {"EXECUTABLE_NAME", "PrenotCalculator"} + */ + public Map<String, String> getVariableSubstitutions() { + return variableSubstitutions; + } +} diff --git a/src/objc_tools/plmerge/java/com/google/devtools/build/xcode/plmerge/PlMerge.java b/src/objc_tools/plmerge/java/com/google/devtools/build/xcode/plmerge/PlMerge.java index ea13c29ab9..40eaa57ade 100644 --- a/src/objc_tools/plmerge/java/com/google/devtools/build/xcode/plmerge/PlMerge.java +++ b/src/objc_tools/plmerge/java/com/google/devtools/build/xcode/plmerge/PlMerge.java @@ -15,6 +15,7 @@ package com.google.devtools.build.xcode.plmerge; import com.google.common.collect.ImmutableMap; +import com.google.devtools.build.xcode.plmerge.proto.PlMergeProtos.Control; import com.google.devtools.common.options.Option; import com.google.devtools.common.options.Options; import com.google.devtools.common.options.OptionsBase; @@ -24,81 +25,123 @@ import com.google.devtools.common.options.OptionsParsingException; import com.dd.plist.NSObject; import java.io.IOException; +import java.io.InputStream; import java.nio.file.FileSystem; import java.nio.file.FileSystems; -import java.nio.file.Path; -import java.util.ArrayList; +import java.nio.file.Files; import java.util.List; /** * Entry point for the {@code plmerge} tool, which merges the data from one or more plists into a * single binary plist. This tool's functionality is similar to that of the * {@code builtin-infoPlistUtility} in Xcode. + * + * <p>For backwards compatibility, PlMerge can consume either a control protobuf, passed using + * --control, or the command line arguments --source_file, --out_file, --primary_bundle_id, + * and --fallback_bundle_id. If a --control is not provided, PlMerge will fall back on the other + * command line arguments. If --control is provided, all other command line arguments are ignored. */ public class PlMerge { + /** * Options for {@link PlMerge}. */ public static class PlMergeOptions extends OptionsBase { + @Option( - name = "source_file", - help = "Paths to the plist files to merge. These can be binary, XML, or ASCII format. " - + "Repeat this flag to specify multiple files. Required.", - allowMultiple = true, - defaultValue = "null") + name = "source_file", + help = + "Paths to the plist files to merge. These can be binary, XML, or ASCII format. " + + "Repeat this flag to specify multiple files. Required.", + allowMultiple = true, + defaultValue = "null" + ) public List<String> sourceFiles; - @Option( - name = "out_file", - help = "Path to the output file. Required.", - defaultValue = "null") + @Option(name = "out_file", help = "Path to the output file. Required.", defaultValue = "null") public String outFile; @Option( - name = "primary_bundle_id", - help = "A reverse-DNS string identifier for this bundle associated with output binary " - + "plist. This flag overrides the bundle id specified in field CFBundleIdentifier in " - + "the associated plist file.", - defaultValue = "null") + name = "primary_bundle_id", + help = + "A reverse-DNS string identifier for this bundle associated with output binary " + + "plist. This flag overrides the bundle id specified in field CFBundleIdentifier in " + + "the associated plist file.", + defaultValue = "null" + ) public String primaryBundleId; @Option( - name = "fallback_bundle_id", - help = "A fallback reverse-DNS string identifier for this bundle when the bundle " - + "identifier is not specified in flag primary_bundle_id or associated plist file", - defaultValue = "null") + name = "fallback_bundle_id", + help = + "A fallback reverse-DNS string identifier for this bundle when the bundle " + + "identifier is not specified in flag primary_bundle_id or associated plist file", + defaultValue = "null" + ) public String fallbackBundleId; + + @Option( + name = "control", + help = + "Absolute path of the Control protobuf. Data can be passed to plmerge through this " + + "protobuf or through source_file, out_file, primary_bundle_id and " + + "fallback_bundle_id.", + defaultValue = "null" + ) + public String controlPath; } + + public static void main(String[] args) throws OptionsParsingException, IOException { - public static void main(String[] args) throws IOException, OptionsParsingException { + FileSystem fileSystem = FileSystems.getDefault(); OptionsParser parser = OptionsParser.newOptionsParser(PlMergeOptions.class); parser.parse(args); PlMergeOptions options = parser.getOptions(PlMergeOptions.class); - if (options.sourceFiles.isEmpty()) { - missingArg("At least one --source_file"); - } - if (options.outFile == null) { - missingArg("--out_file"); - } - FileSystem fileSystem = FileSystems.getDefault(); - List<Path> sourceFilePaths = new ArrayList<>(); - for (String sourceFile : options.sourceFiles) { - sourceFilePaths.add(fileSystem.getPath(sourceFile)); + MergingArguments data = null; + + if (usingControlProtobuf(options)) { + InputStream in = Files.newInputStream(fileSystem.getPath(options.controlPath)); + Control control = Control.parseFrom(in); + validateControl(control); + data = new MergingArguments(control); + } else if (usingCommandLineArgs(options)) { + data = new MergingArguments(options); + } else { + missingArg("Either --control or --out_file and at least one --source_file"); } - PlistMerging merging = PlistMerging.from(sourceFilePaths, ImmutableMap.<String, NSObject>of(), - ImmutableMap.<String, String>of(), new KeysToRemoveIfEmptyString()); - if (options.primaryBundleId != null || options.fallbackBundleId != null) { + PlistMerging merging = + PlistMerging.from( + data, + ImmutableMap.<String, NSObject>of(), + new KeysToRemoveIfEmptyString("CFBundleIconFile", "NSPrincipalClass")); + if (data.getPrimaryBundleId() != null || data.getFallbackBundleId() != null) { // Only set the bundle identifier if we were passed arguments to do so. // This prevents CFBundleIdentifiers being put into strings files. - merging.setBundleIdentifier(options.primaryBundleId, options.fallbackBundleId); + merging.setBundleIdentifier(data.getPrimaryBundleId(), data.getFallbackBundleId()); } - merging.writePlist(fileSystem.getPath(options.outFile)); + merging.writePlist(fileSystem.getPath(data.getOutFile())); } + private static void validateControl(Control control) { + if (control.getSourceFileList().isEmpty()) { + missingArg("At least one source_file"); + } else if (!control.hasOutFile()) { + missingArg("out_file"); + } + } + private static void missingArg(String flag) { throw new IllegalArgumentException(flag + " is required:\n" + Options.getUsage(PlMergeOptions.class)); } + + private static boolean usingControlProtobuf(PlMergeOptions options) { + return options.controlPath != null; + } + + private static boolean usingCommandLineArgs(PlMergeOptions options) { + return (!options.sourceFiles.isEmpty()) && (options.outFile != null); + } } diff --git a/src/objc_tools/plmerge/java/com/google/devtools/build/xcode/plmerge/PlistMerging.java b/src/objc_tools/plmerge/java/com/google/devtools/build/xcode/plmerge/PlistMerging.java index 31201eeb2b..4dae6fc7fb 100644 --- a/src/objc_tools/plmerge/java/com/google/devtools/build/xcode/plmerge/PlistMerging.java +++ b/src/objc_tools/plmerge/java/com/google/devtools/build/xcode/plmerge/PlistMerging.java @@ -176,6 +176,22 @@ public class PlistMerging extends Value<PlistMerging> { * Generates a Plistmerging combining values from sourceFiles and automaticEntries, and modifying * them based on subsitutions and keysToRemoveIfEmptyString. */ + public static PlistMerging from( + MergingArguments mergingArguments, + Map<String, NSObject> automaticEntries, + KeysToRemoveIfEmptyString keysToRemoveIfEmptyString) + throws IOException { + return from( + mergingArguments.getSourceFilePaths(), + automaticEntries, + mergingArguments.getVariableSubstitutions(), + keysToRemoveIfEmptyString); + } + + /** + * Generates a Plistmerging combining values from sourceFiles and automaticEntries, and modifying + * them based on subsitutions and keysToRemoveIfEmptyString. + */ public static PlistMerging from(List<Path> sourceFiles, Map<String, NSObject> automaticEntries, Map<String, String> substitutions, KeysToRemoveIfEmptyString keysToRemoveIfEmptyString) throws IOException { |