| /* |
| * 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.repository.local; |
| |
| import com.android.annotations.NonNull; |
| import com.android.annotations.Nullable; |
| import com.android.sdklib.internal.repository.IDescription; |
| import com.android.sdklib.internal.repository.IListDescription; |
| import com.android.sdklib.internal.repository.packages.Package; |
| import com.android.sdklib.repository.descriptors.IPkgDesc; |
| import com.android.sdklib.repository.remote.RemotePkgInfo; |
| import com.android.sdklib.repository.remote.RemoteSdk; |
| |
| import java.io.File; |
| import java.util.Properties; |
| |
| /** |
| * Information about a locally installed package. |
| * <p/> |
| * Local package information is retrieved via the {@link LocalSdk} object. |
| * Clients should not need to create instances of {@link LocalPkgInfo} directly. |
| * Instead please use the {@link LocalSdk} methods to parse and retrieve packages. |
| * <p/> |
| * These objects can also contain optional information about updates available |
| * from remote servers. These are computed and set by the {@link RemoteSdk} object. |
| */ |
| public abstract class LocalPkgInfo |
| implements IDescription, IListDescription, Comparable<LocalPkgInfo> { |
| |
| private final LocalSdk mLocalSdk; |
| private final File mLocalDir; |
| private final Properties mSourceProperties; |
| |
| private Package mPackage; |
| private String mLoadError; |
| private RemotePkgInfo mUpdate; |
| |
| protected LocalPkgInfo(@NonNull LocalSdk localSdk, |
| @NonNull File localDir, |
| @NonNull Properties sourceProps) { |
| mLocalSdk = localSdk; |
| mLocalDir = localDir; |
| mSourceProperties = sourceProps; |
| } |
| |
| //---- Attributes ---- |
| |
| @NonNull |
| public LocalSdk getLocalSdk() { |
| return mLocalSdk; |
| } |
| |
| @NonNull |
| public File getLocalDir() { |
| return mLocalDir; |
| } |
| |
| @NonNull |
| public Properties getSourceProperties() { |
| return mSourceProperties; |
| } |
| |
| @Nullable |
| public String getLoadError() { |
| return mLoadError; |
| } |
| |
| /** |
| * Indicates whether this local package has an update available. |
| * This is only defined if {@link Update} has been used to decorate the packages. |
| * |
| * @return True if {@link #getUpdate()} would return a non-null {@link RemotePkgInfo}. |
| */ |
| public boolean hasUpdate() { |
| return mUpdate != null; |
| } |
| |
| /** |
| * Returns a {@link RemotePkgInfo} that can update this package, if available. |
| * This is only defined if {@link Update} has been used to decorate the packages. |
| * |
| * @return A {@link RemotePkgInfo} or null. |
| */ |
| @Nullable |
| public RemotePkgInfo getUpdate() { |
| return mUpdate; |
| } |
| |
| /** |
| * Used by {@link Update} to indicate if there's an update available for this package. |
| */ |
| void setUpdate(@Nullable RemotePkgInfo update) { |
| mUpdate = update; |
| } |
| |
| // ---- |
| |
| /** Returns the {@link IPkgDesc} describing this package. */ |
| @NonNull |
| public abstract IPkgDesc getDesc(); |
| |
| |
| //---- Ordering ---- |
| |
| /** |
| * Comparison is solely done based on the {@link IPkgDesc}. |
| * <p/> |
| * Other local attributes (local directory, source properties, updates available) |
| * are <em>not used</em> in the comparison. Consequently {@link #compareTo(LocalPkgInfo)} |
| * does not match {@link #equals(Object)} and the {@link #hashCode()} properties. |
| */ |
| @Override |
| public int compareTo(@NonNull LocalPkgInfo o) { |
| return getDesc().compareTo(o.getDesc()); |
| } |
| |
| /** String representation for debugging purposes. */ |
| @Override |
| public String toString() { |
| StringBuilder builder = new StringBuilder(); |
| builder.append('<').append(this.getClass().getSimpleName()).append(' '); |
| builder.append(getDesc().toString()); |
| if (mUpdate != null) { |
| builder.append(" Updated by: "); //$NON-NLS-1$ |
| builder.append(mUpdate.toString()); |
| } |
| builder.append('>'); |
| return builder.toString(); |
| } |
| |
| /** |
| * Computes a hash code specific to this instance based on the underlying |
| * {@link IPkgDesc} but also specific local properties such a local directory, |
| * update available and actual source properties. |
| */ |
| @Override |
| public int hashCode() { |
| final int prime = 31; |
| int result = 1; |
| result = prime * result + ((getDesc() == null) ? 0 : getDesc().hashCode()); |
| result = prime * result + ((mLocalDir == null) ? 0 : mLocalDir.hashCode()); |
| result = prime * result + ((mSourceProperties == null) ? 0 : mSourceProperties.hashCode()); |
| result = prime * result + ((mUpdate == null) ? 0 : mUpdate.hashCode()); |
| return result; |
| } |
| |
| /** |
| * Computes object equality to this instance based on the underlying |
| * {@link IPkgDesc} but also specific local properties such a local directory, |
| * update available and actual source properties. This is different from |
| * the behavior of {@link #compareTo(LocalPkgInfo)} which only uses the |
| * {@link IPkgDesc} for ordering. |
| */ |
| @Override |
| public boolean equals(Object obj) { |
| if (this == obj) { |
| return true; |
| } |
| if (obj == null) { |
| return false; |
| } |
| if (!(obj instanceof LocalPkgInfo)) { |
| return false; |
| } |
| LocalPkgInfo other = (LocalPkgInfo) obj; |
| |
| if (!getDesc().equals(other.getDesc())) { |
| return false; |
| } |
| if (mLocalDir == null) { |
| if (other.mLocalDir != null) { |
| return false; |
| } |
| } else if (!mLocalDir.equals(other.mLocalDir)) { |
| return false; |
| } |
| if (mSourceProperties == null) { |
| if (other.mSourceProperties != null) { |
| return false; |
| } |
| } else if (!mSourceProperties.equals(other.mSourceProperties)) { |
| return false; |
| } |
| if (mUpdate == null) { |
| if (other.mUpdate != null) { |
| return false; |
| } |
| } else if (!mUpdate.equals(other.mUpdate)) { |
| return false; |
| } |
| return true; |
| } |
| |
| |
| //---- Package Management ---- |
| |
| /** A "broken" package is installed but is not fully operational. |
| * |
| * For example an addon that lacks its underlying platform or a tool package |
| * that lacks some of its binaries or essentially files. |
| * <p/> |
| * Operational code should generally ignore broken packages. |
| * Only the SDK Updater cares about displaying them so that they can be fixed. |
| */ |
| public boolean hasLoadError() { |
| return mLoadError != null; |
| } |
| |
| void appendLoadError(@NonNull String format, Object...params) { |
| String loadError = String.format(format, params); |
| if (mLoadError == null) { |
| mLoadError = loadError; |
| } else { |
| mLoadError = mLoadError + '\n' + loadError; |
| } |
| } |
| |
| void setPackage(@Nullable Package pkg) { |
| mPackage = pkg; |
| } |
| |
| @Nullable |
| public Package getPackage() { |
| return mPackage; |
| } |
| |
| @NonNull |
| @Override |
| public String getListDescription() { |
| return getDesc().getListDescription(); |
| } |
| |
| @Override |
| public String getShortDescription() { |
| // TODO revisit to differentiate from list-description depending |
| // on how we'll use it in the sdkman UI. |
| return getListDescription(); |
| } |
| |
| @Override |
| public String getLongDescription() { |
| StringBuilder sb = new StringBuilder(); |
| IPkgDesc desc = getDesc(); |
| |
| sb.append(desc.getListDescription()).append('\n'); |
| |
| if (desc.hasVendor()) { |
| assert desc.getVendor() != null; |
| sb.append("By ").append(desc.getVendor().getDisplay()).append('\n'); |
| } |
| |
| if (desc.hasMinPlatformToolsRev()) { |
| assert desc.getMinPlatformToolsRev() != null; |
| sb.append("Requires Platform-Tools revision ").append(desc.getMinPlatformToolsRev().toShortString()).append('\n'); |
| } |
| |
| if (desc.hasMinToolsRev()) { |
| assert desc.getMinToolsRev() != null; |
| sb.append("Requires Tools revision ").append(desc.getMinToolsRev().toShortString()).append('\n'); |
| } |
| |
| sb.append("Location: ").append(mLocalDir.getAbsolutePath()); |
| |
| return sb.toString(); |
| } |
| |
| |
| } |
| |