/* * Copyright (C) 2014 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.tools.idea.sdk; import com.android.sdklib.SdkManager; import com.android.sdklib.repository.FullRevision; import com.android.sdklib.repository.MajorRevision; import com.android.sdklib.repository.descriptors.IPkgDesc; import com.android.sdklib.repository.descriptors.PkgType; import com.android.sdklib.repository.local.LocalPkgInfo; import com.android.sdklib.repository.local.LocalSdk; import com.android.tools.idea.rendering.LogWrapper; import com.android.utils.ILogger; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.util.io.FileUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; import java.io.IOException; import java.util.Collection; import java.util.EnumSet; import java.util.Map; public class SdkMerger { private static final Logger LOG = Logger.getInstance(SdkMerger.class); public static void mergeSdks(@NotNull File srcDir, @NotNull File destDir, @Nullable ProgressIndicator indicator) { Collection<MergeablePackage> packages = compareSdks(srcDir, destDir); int numPackages = packages.size(); int i = 0; for (MergeablePackage pkg : packages) { if (indicator != null) { if (indicator.isCanceled()) { return; } indicator.setFraction((double)i++ / numPackages); indicator.setText(String.format("Copying SDK package %1s", pkg.srcPkg.getDesc().getInstallId())); } if (pkg.destPkg != null) { // Destination package exists but is older; delete the old and replace with the new. File destPkgDir = pkg.destPkg.getLocalDir(); try { FileUtil.delete(destPkgDir); } catch (RuntimeException e) { LOG.warn("Failed to delete destination directory " + destPkgDir.getPath(), e); } } try { FileUtil.copyDir(pkg.srcPkg.getLocalDir(), pkg.srcPkg.getDesc().getCanonicalInstallFolder(pkg.destLocation)); } catch (IOException e) { LOG.error("Unable to copy package " + pkg.srcPkg.getDesc().getInstallId(), e); } } if (indicator != null) { indicator.setFraction(1.0); } } public static boolean hasMergeableContent(@NotNull File srcDir, @NotNull File destDir) { return !compareSdks(srcDir, destDir).isEmpty(); } @NotNull private static Collection<MergeablePackage> compareSdks(@NotNull File srcDir, @NotNull File destDir) { Collection<MergeablePackage> results = Lists.newArrayList(); ILogger logger = new LogWrapper(LOG); SdkManager destManager = SdkManager.createManager(destDir.getPath(), logger); SdkManager srcManager = SdkManager.createManager(srcDir.getPath(), logger); if (srcManager == null || destManager == null) { return results; } LocalSdk srcSdk = srcManager.getLocalSdk(); LocalSdk destSdk = destManager.getLocalSdk(); LocalPkgInfo[] srcPkgs = srcSdk.getPkgsInfos(EnumSet.allOf(PkgType.class)); File destLocation = destSdk.getLocation(); if (destLocation == null) { return results; } Map<String, LocalPkgInfo> destPackages = Maps.newHashMap(); for (LocalPkgInfo pkg : destSdk.getPkgsInfos(EnumSet.allOf(PkgType.class))) { destPackages.put(pkg.getDesc().getInstallId(), pkg); } for (LocalPkgInfo srcPkg : srcPkgs) { IPkgDesc srcPkgDesc = srcPkg.getDesc(); LocalPkgInfo destPkg = destPackages.get(srcPkg.getDesc().getInstallId()); if (destPkg != null) { IPkgDesc destPkgDesc = destPkg.getDesc(); FullRevision srcFullRevision = srcPkgDesc.getFullRevision(); FullRevision destFullRevision = destPkgDesc.getFullRevision(); MajorRevision srcMajorRevision = srcPkgDesc.getMajorRevision(); MajorRevision destMajorRevision = destPkgDesc.getMajorRevision(); if ((srcFullRevision != null && destFullRevision != null && srcFullRevision.compareTo(destFullRevision) > 0) || (srcMajorRevision != null && destMajorRevision != null && srcMajorRevision.compareTo(destMajorRevision) > 0)) { // Package exists in destination but is old; replace it. results.add(new MergeablePackage(srcPkg, destPkg, destLocation)); } } else { // Package doesn't exist in destination; copy it over. results.add(new MergeablePackage(srcPkg, null, destLocation)); } } return results; } private static class MergeablePackage { @NotNull private final LocalPkgInfo srcPkg; @Nullable private final LocalPkgInfo destPkg; @NotNull private final File destLocation; private MergeablePackage(@NotNull LocalPkgInfo srcPkg, @Nullable LocalPkgInfo destPkg, @NotNull File destLocation) { this.srcPkg = srcPkg; this.destPkg = destPkg; this.destLocation = destLocation; } } }