/* * Copyright (C) 2009 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.sdklib.internal.repository.packages; import com.android.SdkConstants; import com.android.annotations.NonNull; import com.android.annotations.Nullable; import com.android.annotations.VisibleForTesting; import com.android.annotations.VisibleForTesting.Visibility; import com.android.sdklib.SdkManager; import com.android.sdklib.repository.IDescription; import com.android.sdklib.internal.repository.ITaskMonitor; import com.android.sdklib.internal.repository.archives.Archive; import com.android.sdklib.internal.repository.sources.SdkSource; import com.android.sdklib.repository.FullRevision; import com.android.sdklib.repository.FullRevision.PreviewComparison; import com.android.sdklib.repository.PkgProps; import com.android.sdklib.repository.SdkRepoConstants; import com.android.sdklib.repository.descriptors.IPkgDesc; import com.android.sdklib.repository.descriptors.PkgDesc; import com.android.utils.GrabProcessOutput; import com.android.utils.GrabProcessOutput.IProcessOutput; import com.android.utils.GrabProcessOutput.Wait; import org.w3c.dom.Node; import java.io.File; import java.util.Map; import java.util.Properties; /** * Represents a tool XML node in an SDK repository. * * @deprecated * com.android.sdklib.internal.repository has moved into Studio as * com.android.tools.idea.sdk.remote.internal. */ @Deprecated public class ToolPackage extends FullRevisionPackage implements IMinPlatformToolsDependency { /** The value returned by {@link ToolPackage#installId()}. */ public static final String INSTALL_ID = "tools"; //$NON-NLS-1$ /** The value returned by {@link ToolPackage#installId()}. */ private static final String INSTALL_ID_PREVIEW = "tools-preview"; //$NON-NLS-1$ /** * The minimal revision of the platform-tools package required by this package * or {@link #MIN_PLATFORM_TOOLS_REV_INVALID} if the value was missing. */ private final FullRevision mMinPlatformToolsRevision; private final IPkgDesc mPkgDesc; /** * Creates a new tool package from the attributes and elements of the given XML node. * This constructor should throw an exception if the package cannot be created. * * @param source The {@link SdkSource} where this is loaded from. * @param packageNode The XML element being parsed. * @param nsUri The namespace URI of the originating XML document, to be able to deal with * parameters that vary according to the originating XML schema. * @param licenses The licenses loaded from the XML originating document. */ public ToolPackage(SdkSource source, Node packageNode, String nsUri, Map<String,String> licenses) { super(source, packageNode, nsUri, licenses); mMinPlatformToolsRevision = PackageParserUtils.parseFullRevisionElement( PackageParserUtils.findChildElement(packageNode, SdkRepoConstants.NODE_MIN_PLATFORM_TOOLS_REV)); if (mMinPlatformToolsRevision.equals(MIN_PLATFORM_TOOLS_REV_INVALID)) { // This revision number is mandatory starting with sdk-repository-3.xsd // and did not exist before. Complain if the URI has level >= 3. if (SdkRepoConstants.versionGreaterOrEqualThan(nsUri, 3)) { throw new IllegalArgumentException( String.format("Missing %1$s element in %2$s package", SdkRepoConstants.NODE_MIN_PLATFORM_TOOLS_REV, SdkRepoConstants.NODE_PLATFORM_TOOL)); } } mPkgDesc = setDescriptions(PkgDesc.Builder .newTool(getRevision(), mMinPlatformToolsRevision)) .create(); } /** * Manually create a new package with one archive and the given attributes or properties. * This is used to create packages from local directories in which case there must be * one archive which URL is the actual target location. * <p/> * By design, this creates a package with one and only one archive. */ public static Package create( SdkSource source, Properties props, int revision, String license, String description, String descUrl, String archiveOsPath) { return new ToolPackage(source, props, revision, license, description, descUrl, archiveOsPath); } @VisibleForTesting(visibility=Visibility.PRIVATE) protected ToolPackage( SdkSource source, Properties props, int revision, String license, String description, String descUrl, String archiveOsPath) { super(source, props, revision, license, description, descUrl, archiveOsPath); // Setup min-platform-tool String revStr = getProperty(props, PkgProps.MIN_PLATFORM_TOOLS_REV, null); FullRevision rev = MIN_PLATFORM_TOOLS_REV_INVALID; if (revStr != null) { try { rev = FullRevision.parseRevision(revStr); } catch (NumberFormatException ignore) {} } mMinPlatformToolsRevision = rev; mPkgDesc = setDescriptions(PkgDesc.Builder .newTool(getRevision(), mMinPlatformToolsRevision)) .create(); } @Override @NonNull public IPkgDesc getPkgDesc() { return mPkgDesc; } @Override public FullRevision getMinPlatformToolsRevision() { return mMinPlatformToolsRevision; } /** * Returns a string identifier to install this package from the command line. * For tools, we use "tools" or "tools-preview" since this package is unique. * <p/> * {@inheritDoc} */ @Override public String installId() { if (getRevision().isPreview()) { return INSTALL_ID_PREVIEW; } else { return INSTALL_ID; } } /** * Returns a description of this package that is suitable for a list display. * <p/> * {@inheritDoc} */ @Override public String getListDescription() { String ld = getListDisplay(); return String.format("%1$s%2$s", ld.isEmpty() ? "Android SDK Tools" : ld, isObsolete() ? " (Obsolete)" : ""); } /** * Returns a short description for an {@link IDescription}. */ @Override public String getShortDescription() { String ld = getListDisplay(); if (!ld.isEmpty()) { return String.format("%1$s, revision %2$s%3$s", ld, getRevision().toShortString(), isObsolete() ? " (Obsolete)" : ""); } return String.format("Android SDK Tools, revision %1$s%2$s", getRevision().toShortString(), isObsolete() ? " (Obsolete)" : ""); } /** Returns a long description for an {@link IDescription}. */ @Override public String getLongDescription() { String s = getDescription(); if (s == null || s.isEmpty()) { s = getShortDescription(); } if (s.indexOf("revision") == -1) { s += String.format("\nRevision %1$s%2$s", getRevision().toShortString(), isObsolete() ? " (Obsolete)" : ""); } return s; } /** * Computes a potential installation folder if an archive of this package were * to be installed right away in the given SDK root. * <p/> * A "tool" package should always be located in SDK/tools. * * @param osSdkRoot The OS path of the SDK root folder. * @param sdkManager An existing SDK manager to list current platforms and addons. * @return A new {@link File} corresponding to the directory to use to install this package. */ @Override public File getInstallFolder(String osSdkRoot, SdkManager sdkManager) { return new File(osSdkRoot, SdkConstants.FD_TOOLS); } /** * Check whether 2 tool packages are the same <em>and</em> have the * same preview bit. */ @Override public boolean sameItemAs(Package pkg) { return sameItemAs(pkg, PreviewComparison.COMPARE_TYPE); } @Override public boolean sameItemAs(Package pkg, PreviewComparison comparePreview) { // only one tool package so any platform-tool package is the same item. if (pkg instanceof ToolPackage) { switch (comparePreview) { case IGNORE: return true; case COMPARE_NUMBER: // Voluntary break-through. case COMPARE_TYPE: // There's only one tool so the preview number doesn't matter; // however previews can only match previews by default so both cases // are treated the same. return pkg.getRevision().isPreview() == getRevision().isPreview(); } } return false; } @Override public void saveProperties(Properties props) { super.saveProperties(props); if (!getMinPlatformToolsRevision().equals(MIN_PLATFORM_TOOLS_REV_INVALID)) { props.setProperty(PkgProps.MIN_PLATFORM_TOOLS_REV, getMinPlatformToolsRevision().toShortString()); } } /** * The tool package executes tools/lib/post_tools_install[.bat|.sh] * {@inheritDoc} */ @Override public void postInstallHook(Archive archive, final ITaskMonitor monitor, File installFolder) { super.postInstallHook(archive, monitor, installFolder); if (installFolder == null) { return; } File libDir = new File(installFolder, SdkConstants.FD_LIB); if (!libDir.isDirectory()) { return; } String scriptName = "post_tools_install"; //$NON-NLS-1$ String shell = ""; //$NON-NLS-1$ if (SdkConstants.currentPlatform() == SdkConstants.PLATFORM_WINDOWS) { shell = "cmd.exe /c "; //$NON-NLS-1$ scriptName += ".bat"; //$NON-NLS-1$ } else { scriptName += ".sh"; //$NON-NLS-1$ } File scriptFile = new File(libDir, scriptName); if (!scriptFile.isFile()) { return; } int status = -1; try { Process proc = Runtime.getRuntime().exec( shell + scriptName, // command null, // environment libDir); // working dir final String tag = scriptName; status = GrabProcessOutput.grabProcessOutput( proc, Wait.WAIT_FOR_PROCESS, new IProcessOutput() { @Override public void out(@Nullable String line) { if (line != null) { monitor.log("[%1$s] %2$s", tag, line); } } @Override public void err(@Nullable String line) { if (line != null) { monitor.logError("[%1$s] Error: %2$s", tag, line); } } }); } catch (Exception e) { monitor.logError("Exception: %s", e.toString()); } if (status != 0) { monitor.logError("Failed to execute %s", scriptName); return; } } @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + ((mMinPlatformToolsRevision == null) ? 0 : mMinPlatformToolsRevision.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj)) { return false; } if (!(obj instanceof ToolPackage)) { return false; } ToolPackage other = (ToolPackage) obj; if (mMinPlatformToolsRevision == null) { if (other.mMinPlatformToolsRevision != null) { return false; } } else if (!mMinPlatformToolsRevision.equals(other.mMinPlatformToolsRevision)) { return false; } return true; } }