|  | /* | 
|  | * Copyright 2012-present Facebook, Inc. | 
|  | * | 
|  | * 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.facebook.buck.android; | 
|  |  | 
|  | import com.android.common.annotations.NonNull; | 
|  | import com.android.manifmerger.ICallback; | 
|  | import com.android.manifmerger.IMergerLog; | 
|  | import com.android.manifmerger.ManifestMerger; | 
|  | import com.android.manifmerger.MergerLog; | 
|  | import com.facebook.buck.step.ExecutionContext; | 
|  | import com.facebook.buck.step.Step; | 
|  | import com.facebook.buck.util.HumanReadableException; | 
|  | import com.facebook.buck.util.environment.Platform; | 
|  | import com.google.common.base.Charsets; | 
|  | import com.google.common.base.Objects; | 
|  | import com.google.common.base.Preconditions; | 
|  | import com.google.common.base.Strings; | 
|  | import com.google.common.collect.ImmutableSet; | 
|  | import com.google.common.collect.Iterables; | 
|  | import com.google.common.collect.Lists; | 
|  | import com.google.common.io.Files; | 
|  |  | 
|  | import java.io.File; | 
|  | import java.io.IOException; | 
|  | import java.util.List; | 
|  |  | 
|  | public class GenerateManifestStep implements Step { | 
|  |  | 
|  | private static final int BASE_SDK_LEVEL = 1; | 
|  |  | 
|  | private String skeletonManifestPath; | 
|  | private ImmutableSet<String> libraryManifestPaths; | 
|  | private String outManifestPath; | 
|  |  | 
|  | public GenerateManifestStep( | 
|  | String skeletonManifestPath, | 
|  | ImmutableSet<String> libraryManifestPaths, | 
|  | String outManifestPath) { | 
|  | this.skeletonManifestPath = Preconditions.checkNotNull(skeletonManifestPath); | 
|  | this.libraryManifestPaths = ImmutableSet.copyOf(libraryManifestPaths); | 
|  | this.outManifestPath = Preconditions.checkNotNull(outManifestPath); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public int execute(ExecutionContext context) { | 
|  |  | 
|  | if (Strings.isNullOrEmpty(skeletonManifestPath)) { | 
|  | throw new HumanReadableException("Skeleton manifest filepath is missing"); | 
|  | } | 
|  |  | 
|  | if (Strings.isNullOrEmpty(outManifestPath)) { | 
|  | throw new HumanReadableException("Output Manifest filepath is missing"); | 
|  | } | 
|  |  | 
|  | if (libraryManifestPaths == null || libraryManifestPaths.isEmpty()) { | 
|  | warnUser(context, "No library manifests found. Aborting manifest merge step."); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | try { | 
|  | Files.createParentDirs(new File(outManifestPath)); | 
|  | } catch (IOException e) { | 
|  | e.printStackTrace(context.getStdErr()); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | List<File> libraryManifestFiles = Lists.newArrayList(); | 
|  |  | 
|  | for (String path : libraryManifestPaths) { | 
|  | libraryManifestFiles.add(new File(path)); | 
|  | } | 
|  |  | 
|  | File skeletonManifestFile = new File(skeletonManifestPath); | 
|  |  | 
|  | ICallback callback = new ICallback() { | 
|  | @Override | 
|  | public int queryCodenameApiLevel(@NonNull String codename) { | 
|  | return BASE_SDK_LEVEL; | 
|  | } | 
|  | }; | 
|  |  | 
|  | IMergerLog log = MergerLog.wrapSdkLog(new BuckEventAndroidLogger(context.getBuckEventBus())); | 
|  |  | 
|  | ManifestMerger merger = new ManifestMerger(log, callback); | 
|  |  | 
|  | File outManifestFile = new File(outManifestPath); | 
|  | if (!merger.process( | 
|  | outManifestFile, | 
|  | skeletonManifestFile, | 
|  | Iterables.toArray(libraryManifestFiles, File.class))) { | 
|  | throw new HumanReadableException("Error generating manifest file"); | 
|  | } | 
|  |  | 
|  | if (context.getPlatform() == Platform.WINDOWS) { | 
|  | // Convert line endings to Lf on Windows. | 
|  | try { | 
|  | String xmlText = Files.toString(outManifestFile, Charsets.UTF_8); | 
|  | xmlText = xmlText.replace("\r\n", "\n"); | 
|  | Files.write(xmlText.getBytes(Charsets.UTF_8), outManifestFile); | 
|  | } catch (IOException e) { | 
|  | throw new HumanReadableException("Error converting line endings of manifest file"); | 
|  | } | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public String getDescription(ExecutionContext context) { | 
|  | return String.format("generate-manifest %s", skeletonManifestPath); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public String getShortName() { | 
|  | return "generate_manifest"; | 
|  | } | 
|  |  | 
|  | private void warnUser(ExecutionContext context, String message) { | 
|  | context.getStdErr().println(context.getAnsi().asWarningText(message)); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public boolean equals(Object obj) { | 
|  | if (!(obj instanceof GenerateManifestStep)) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | GenerateManifestStep that = (GenerateManifestStep)obj; | 
|  | return Objects.equal(this.skeletonManifestPath, that.skeletonManifestPath) | 
|  | && Objects.equal(this.libraryManifestPaths, that.libraryManifestPaths) | 
|  | && Objects.equal(this.outManifestPath, that.outManifestPath); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public int hashCode() { | 
|  | return Objects.hashCode( | 
|  | skeletonManifestPath, | 
|  | libraryManifestPaths, | 
|  | outManifestPath); | 
|  | } | 
|  | } |