// Copyright 2014 Google Inc. 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.lib.rules.objc; import com.google.common.base.Optional; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import com.google.devtools.build.lib.actions.Action; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.analysis.FilesToRunProvider; import com.google.devtools.build.lib.analysis.actions.ActionConstructionContext; import com.google.devtools.build.lib.analysis.actions.CommandLine; import com.google.devtools.build.lib.analysis.actions.SpawnAction; import com.google.devtools.build.lib.collect.nestedset.NestedSet; import com.google.devtools.build.xcode.util.Interspersing; /** * Supplies information regarding Infoplist merging for a particular binary. This includes: * */ class InfoplistMerging { static class Builder { private final ActionConstructionContext context; private NestedSet inputPlists; private FilesToRunProvider plmerge; private IntermediateArtifacts intermediateArtifacts; public Builder(ActionConstructionContext context) { this.context = Preconditions.checkNotNull(context); } public Builder setInputPlists(NestedSet inputPlists) { Preconditions.checkState(this.inputPlists == null); this.inputPlists = inputPlists; return this; } public Builder setPlmerge(FilesToRunProvider plmerge) { Preconditions.checkState(this.plmerge == null); this.plmerge = plmerge; return this; } public Builder setIntermediateArtifacts(IntermediateArtifacts intermediateArtifacts) { this.intermediateArtifacts = intermediateArtifacts; return this; } /** * This static factory method prevents retention of the outer {@link Builder} class reference by * the anonymous {@link CommandLine} instance. */ private static CommandLine mergeCommandLine( final NestedSet inputPlists, final Artifact mergedInfoplist) { return new CommandLine() { @Override public Iterable arguments() { return new ImmutableList.Builder() .addAll(Interspersing.beforeEach( "--source_file", Artifact.toExecPaths(inputPlists))) .add("--out_file", mergedInfoplist.getExecPathString()) .build(); } }; } public InfoplistMerging build() { Preconditions.checkNotNull(intermediateArtifacts, "intermediateArtifacts"); Optional plistWithEverything = Optional.absent(); Action[] mergeActions = new Action[0]; int inputs = Iterables.size(inputPlists); if (inputs == 1) { plistWithEverything = Optional.of(Iterables.getOnlyElement(inputPlists)); } else if (inputs > 1) { Artifact merged = intermediateArtifacts.mergedInfoplist(); plistWithEverything = Optional.of(merged); mergeActions = new SpawnAction.Builder() .setMnemonic("MergeInfoPlistFiles") .setExecutable(plmerge) .setCommandLine(mergeCommandLine(inputPlists, merged)) .addTransitiveInputs(inputPlists) .addOutput(merged) .build(context); } return new InfoplistMerging(plistWithEverything, mergeActions, inputPlists); } } private final Optional plistWithEverything; private final Action[] mergeActions; private final NestedSet inputPlists; private InfoplistMerging(Optional plistWithEverything, Action[] mergeActions, NestedSet inputPlists) { this.plistWithEverything = plistWithEverything; this.mergeActions = mergeActions; this.inputPlists = inputPlists; } /** * Creates action to merge multiple Info.plist files of a binary into a single Info.plist. No * action is necessary if there is only one source. */ public Action[] getMergeAction() { return mergeActions; } /** * An {@link Optional} with the merged infoplist, or {@link Optional#absent()} if there are no * merge inputs and it should not be included in the bundle. */ public Optional getPlistWithEverything() { return plistWithEverything; } public NestedSet getInputPlists() { return inputPlists; } }