blob: 23fe5acbc55689a098a425a8977f8a1ffb5bef9c [file] [log] [blame]
/*
* Copyright (C) 2013 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.VisibleForTesting;
import com.android.annotations.VisibleForTesting.Visibility;
import com.android.sdklib.SdkManager;
import com.android.sdklib.internal.repository.IDescription;
import com.android.sdklib.internal.repository.archives.Archive.Arch;
import com.android.sdklib.internal.repository.archives.Archive.Os;
import com.android.sdklib.internal.repository.sources.SdkSource;
import com.android.sdklib.repository.FullRevision;
import com.android.sdklib.repository.PkgProps;
import com.android.sdklib.repository.FullRevision.PreviewComparison;
import org.w3c.dom.Node;
import java.io.File;
import java.util.HashSet;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
/**
* Represents a build-tool XML node in an SDK repository.
*/
public class BuildToolPackage extends FullRevisionPackage {
/** The base value returned by {@link BuildToolPackage#installId()}. */
private static final String INSTALL_ID_BASE = SdkConstants.FD_BUILD_TOOLS + '-';
/**
* Creates a new build-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 BuildToolPackage(
SdkSource source,
Node packageNode,
String nsUri,
Map<String,String> licenses) {
super(source, packageNode, nsUri, licenses);
}
/**
* Creates either a valid {@link BuildToolPackage} or a {@link BrokenPackage}.
* <p/>
* If the build-tool directory contains valid properties,
* this creates a new {@link BuildToolPackage} with the reversion listed in the properties.
* Otherwise returns a new {@link BrokenPackage} with some explanation on what failed.
* <p/>
* Note that the folder name is not enforced. A build-tool directory must have a
* a source.props with a revision property and a few expected binaries inside to be
* valid.
*
* @param buildToolDir The SDK/build-tool/revision folder
* @param props The properties located in {@code buildToolDir} or null if not found.
* @return A new {@link BuildToolPackage} or a new {@link BrokenPackage}.
*/
public static Package create(File buildToolDir, Properties props) {
String error = null;
// Try to load the reversion from the sources.props.
// If we don't find them, the package is broken.
if (props == null) {
error = String.format("Missing file %1$s in build-tool/%2$s",
SdkConstants.FN_SOURCE_PROP,
buildToolDir.getName());
}
// Check we can find the revision in the source properties
FullRevision rev = null;
if (error == null) {
String revStr = getProperty(props, PkgProps.PKG_REVISION, null);
if (revStr != null) {
try {
rev = FullRevision.parseRevision(revStr);
} catch (NumberFormatException ignore) {}
}
if (rev == null) {
error = String.format("Missing revision property in %1$s",
SdkConstants.FN_SOURCE_PROP);
}
}
if (error == null) {
// Check the directory contains the expected binaries.
if (!buildToolDir.isDirectory()) {
error = String.format("build-tool/%1$s folder is missing",
buildToolDir.getName());
} else {
File[] files = buildToolDir.listFiles();
if (files == null || files.length == 0) {
error = String.format("build-tool/%1$s folder is empty",
buildToolDir.getName());
} else {
Set<String> names = new HashSet<String>();
for (File file : files) {
names.add(file.getName());
}
for (String name : new String[] { SdkConstants.FN_AAPT,
SdkConstants.FN_AIDL,
SdkConstants.FN_DX } ) {
if (!names.contains(name)) {
if (error == null) {
error = String.format("build-tool/%1$s folder is missing ",
buildToolDir.getName());
} else {
error += ", ";
}
error += name;
}
}
}
}
}
if (error == null && rev != null) {
return new BuildToolPackage(
null, //source
props,
0, //revision (extracted from props)
null, //license
null, //description
null, //descUrl
Os.getCurrentOs(), //archiveOs
Arch.getCurrentArch(), //archiveArch
buildToolDir.getAbsolutePath());
}
StringBuilder sb = new StringBuilder("Broken Build-Tools Package");
if (rev != null) {
sb.append(String.format(", revision %1$s", rev.toShortString()));
}
String shortDesc = sb.toString();
if (error != null) {
sb.append('\n').append(error);
}
String longDesc = sb.toString();
return new BrokenPackage(props, shortDesc, longDesc,
IMinApiLevelDependency.MIN_API_LEVEL_NOT_SPECIFIED,
IExactApiLevelDependency.API_LEVEL_INVALID,
buildToolDir.getAbsolutePath());
}
@VisibleForTesting(visibility=Visibility.PRIVATE)
protected BuildToolPackage(
SdkSource source,
Properties props,
int revision,
String license,
String description,
String descUrl,
Os archiveOs,
Arch archiveArch,
String archiveOsPath) {
super(source,
props,
revision,
license,
description,
descUrl,
archiveOs,
archiveArch,
archiveOsPath);
}
/**
* Returns a string identifier to install this package from the command line.
* For build-tools, we use "build-tools-" followed by the full revision string
* where spaces are changed to underscore to be more script-friendly.
* <p/>
* {@inheritDoc}
*/
@Override
public String installId() {
return INSTALL_ID_BASE + getRevision().toString().replace(' ', '_');
}
/**
* Returns a description of this package that is suitable for a list display.
* <p/>
* {@inheritDoc}
*/
@Override
public String getListDescription() {
return String.format("Android SDK Build-tools%1$s",
isObsolete() ? " (Obsolete)" : "");
}
/**
* Returns a short description for an {@link IDescription}.
*/
@Override
public String getShortDescription() {
return String.format("Android SDK Build-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.length() == 0) {
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 build-tool package is typically installed in SDK/build-tools/revision.
* Revision spaces are replaced by underscores for ease of use in command-line.
*
* @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) {
File folder = new File(osSdkRoot, SdkConstants.FD_BUILD_TOOLS);
folder = new File(folder, getRevision().toString().replace(' ', '_'));
return folder;
}
/**
* Check whether 2 platform-tool packages are the same <em>and</em> have the
* same preview bit.
*/
@Override
public boolean sameItemAs(Package pkg) {
// Implementation note: here we don't want to care about the preview number
// so we ignore the preview when calling sameItemAs(); however we do care
// about both packages being either previews or not previews (i.e. the type
// must match but the preview number doesn't need to.)
// The end result is that a package such as "1.2 rc 4" will be an update for "1.2 rc 3".
return sameItemAs(pkg, PreviewComparison.COMPARE_TYPE);
}
@Override
public boolean sameItemAs(Package pkg, PreviewComparison comparePreview) {
// Contrary to other package types, build-tools do not "update themselves"
// so 2 build tools with 2 different revisions are not the same item.
if (pkg instanceof BuildToolPackage) {
BuildToolPackage rhs = (BuildToolPackage) pkg;
return rhs.getRevision().compareTo(getRevision(), comparePreview) == 0;
}
return false;
}
/**
* For build-tool package use their revision number like version numbers and
* we want them sorted from higher to lower. To do that, insert a fake revision
* number using 9999-value into the sorting key.
* <p/>
* {@inheritDoc}
*/
@Override
protected String comparisonKey() {
String s = super.comparisonKey();
int pos = s.indexOf("|r:"); //$NON-NLS-1$
assert pos > 0;
FullRevision rev = getRevision();
String reverseSort = String.format("|rr:%1$04d.%2$04d.%3$04d.", //$NON-NLS-1$
9999 - rev.getMajor(),
9999 - rev.getMinor(),
9999 - rev.getMicro());
s = s.substring(0, pos) + reverseSort + s.substring(pos);
return s;
}
}