diff options
author | Andrew Pellegrini <apell@google.com> | 2017-03-13 18:02:16 +0000 |
---|---|---|
committer | Yun Peng <pcloudy@google.com> | 2017-03-14 08:53:14 +0000 |
commit | 82122525effd106e551503f70050bac18d0f85cb (patch) | |
tree | 878a3e8f44945f292e450e19f075f61e70c737eb /src/tools/android/java/com/google/devtools/build/android/FullyQualifiedName.java | |
parent | 3a26d6924bf3a6e35d3718eb498def3693155ac6 (diff) |
Add <resources> attribute processing to the Android resource processing toolchain.
--
PiperOrigin-RevId: 149963021
MOS_MIGRATED_REVID=149963021
Diffstat (limited to 'src/tools/android/java/com/google/devtools/build/android/FullyQualifiedName.java')
-rw-r--r-- | src/tools/android/java/com/google/devtools/build/android/FullyQualifiedName.java | 295 |
1 files changed, 239 insertions, 56 deletions
diff --git a/src/tools/android/java/com/google/devtools/build/android/FullyQualifiedName.java b/src/tools/android/java/com/google/devtools/build/android/FullyQualifiedName.java index 5ae3e2cc07..836239d6be 100644 --- a/src/tools/android/java/com/google/devtools/build/android/FullyQualifiedName.java +++ b/src/tools/android/java/com/google/devtools/build/android/FullyQualifiedName.java @@ -13,6 +13,8 @@ // limitations under the License. package com.google.devtools.build.android; +import static com.google.common.base.Preconditions.checkNotNull; + import com.android.ide.common.resources.configuration.FolderConfiguration; import com.android.ide.common.resources.configuration.ResourceQualifier; import com.android.resources.ResourceType; @@ -46,6 +48,158 @@ import javax.annotation.concurrent.Immutable; */ @Immutable public class FullyQualifiedName implements DataKey { + /** Represents the type of a {@link FullyQualifiedName}. */ + public interface Type { + /** + * The category of type that a {@link Type} can be. + * + * <p> + * <em>Note:</em> used for strict ordering of {@link FullyQualifiedName}s. + */ + public enum ConcreteType { + RESOURCE_TYPE, + VIRTUAL_TYPE; + } + + public String getName(); + public ConcreteType getType(); + public boolean isOverwritable(); + public int compareTo(Type other); + @Override public boolean equals(Object obj); + @Override public int hashCode(); + @Override public String toString(); + } + + private static Type createTypeFrom(String rawType) { + ResourceType resourceType = ResourceType.getEnum(rawType); + VirtualType virtualType = VirtualType.getEnum(rawType); + if (resourceType != null) { + return new ResourceTypeWrapper(resourceType); + } else if (virtualType != null) { + return virtualType; + } + return null; + } + + private static class ResourceTypeWrapper implements Type { + private final ResourceType resourceType; + + public ResourceTypeWrapper(ResourceType resourceType) { + this.resourceType = resourceType; + } + + @Override + public String getName() { + return resourceType.getName(); + } + + @Override + public ConcreteType getType() { + return ConcreteType.RESOURCE_TYPE; + } + + @Override + public boolean isOverwritable() { + return !(resourceType == ResourceType.ID + || resourceType == ResourceType.PUBLIC + || resourceType == ResourceType.STYLEABLE); + } + + @Override + public int compareTo(Type other) { + if (!(other instanceof ResourceTypeWrapper)) { + return getType().compareTo(other.getType()); + } + return resourceType.compareTo(((ResourceTypeWrapper) other).resourceType); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof ResourceTypeWrapper)) { + return false; + } + ResourceTypeWrapper other = (ResourceTypeWrapper) obj; + return Objects.equals(resourceType, other.resourceType); + } + + @Override + public int hashCode() { + return Objects.hashCode(resourceType); + } + + @Override + public String toString() { + return resourceType.toString(); + } + } + + /** The non-resource {@link Type}s of a {@link FullyQualifiedName}. */ + public enum VirtualType implements Type { + RESOURCES_ATTRIBUTE("<resources>", "Resources Attribute"); + + /** Returns the enum represented by the {@code name}. */ + public static VirtualType getEnum(String name) { + for (VirtualType type : values()) { + if (type.name.equals(name)) { + return type; + } + } + return null; + } + + /** Returns an array with all the names defined by this enum. */ + public static String[] getNames() { + VirtualType[] values = values(); + String[] names = new String[values.length]; + for (int i = values.length - 1; i >= 0; --i) { + names[i] = values[i].getName(); + } + return names; + } + + private final String name; + private final String displayName; + + private VirtualType(String name, String displayName) { + this.name = name; + this.displayName = displayName; + } + + /** Returns the resource type name. */ + @Override + public String getName() { + return name; + } + + /** Returns a translated display name for the resource type. */ + public String getDisplayName() { + return displayName; + } + + @Override + public ConcreteType getType() { + return ConcreteType.VIRTUAL_TYPE; + } + + @Override + public boolean isOverwritable() { + return true; + } + + @Override + public int compareTo(Type other) { + if (!(other instanceof VirtualType)) { + return getType().compareTo(other.getType()); + } + return compareTo(((VirtualType) other)); + } + + @Override + public String toString() { + return getName(); + } + } + public static final String DEFAULT_PACKAGE = "res-auto"; private static final Joiner DASH_JOINER = Joiner.on('-'); @@ -65,13 +219,19 @@ public class FullyQualifiedName implements DataKey { public static final String INVALID_QUALIFIED_NAME_MESSAGE_NO_MATCH = String.format( "%%s is not a valid qualified name. " - + "It should be in the pattern [package:]{%s}/resourcename", - Joiner.on(",").join(ResourceType.values())); + + "It should be in the pattern [package:]{%s}/name", + Joiner.on(",").join(ImmutableList.<String>builder() + .add(ResourceType.getNames()) + .add(VirtualType.getNames()) + .build())); public static final String INVALID_QUALIFIED_NAME_MESSAGE_NO_TYPE_OR_NAME = String.format( "Could not find either resource type (%%s) or name (%%s) in %%s. " - + "It should be in the pattern [package:]{%s}/resourcename", - Joiner.on(",").join(ResourceType.values())); + + "It should be in the pattern [package:]{%s}/name", + Joiner.on(",").join(ImmutableList.<String>builder() + .add(ResourceType.getNames()) + .add(VirtualType.getNames()) + .build())); public static final String INVALID_QUALIFIERS = "%s contains invalid qualifiers."; private final ImmutableList<String> qualifiers; private final String pkg; @@ -157,12 +317,16 @@ public class FullyQualifiedName implements DataKey { return from(ImmutableList.copyOf(qualifiers), DEFAULT_PACKAGE); } - public FullyQualifiedName create(ResourceType resourceType, String resourceName) { - return create(resourceType, resourceName, pkg); + public FullyQualifiedName create(Type type, String name, String pkg) { + return FullyQualifiedName.of(pkg, qualifiers, type, name); + } + + public FullyQualifiedName create(ResourceType type, String name) { + return create(new ResourceTypeWrapper(type), name, pkg); } - public FullyQualifiedName create(ResourceType resourceType, String resourceName, String pkg) { - return FullyQualifiedName.of(pkg, qualifiers, resourceType, resourceName); + public FullyQualifiedName create(VirtualType type, String name) { + return create(type, name, pkg); } /** @@ -179,16 +343,16 @@ public class FullyQualifiedName implements DataKey { String.format(INVALID_QUALIFIED_NAME_MESSAGE_NO_MATCH, raw)); } String parsedPackage = matcher.group("package"); - ResourceType resourceType = ResourceType.getEnum(matcher.group("type")); - String resourceName = matcher.group("name"); + Type type = createTypeFrom(matcher.group("type")); + String name = matcher.group("name"); - if (resourceType == null || resourceName == null) { + if (type == null || name == null) { throw new IllegalArgumentException( String.format( - INVALID_QUALIFIED_NAME_MESSAGE_NO_TYPE_OR_NAME, resourceType, resourceName, raw)); + INVALID_QUALIFIED_NAME_MESSAGE_NO_TYPE_OR_NAME, type, name, raw)); } return FullyQualifiedName.of( - parsedPackage == null ? pkg : parsedPackage, qualifiers, resourceType, resourceName); + parsedPackage == null ? pkg : parsedPackage, qualifiers, type, name); } /** @@ -230,44 +394,56 @@ public class FullyQualifiedName implements DataKey { } } - public static boolean isOverwritable(FullyQualifiedName name) { - return !(name.resourceType == ResourceType.ID - || name.resourceType == ResourceType.PUBLIC - || name.resourceType == ResourceType.STYLEABLE); - } - /** * Creates a new FullyQualifiedName with normalized qualifiers. * * @param pkg The resource package of the name. If unknown the default should be "res-auto" * @param qualifiers The resource qualifiers of the name, such as "en" or "xhdpi". - * @param resourceType The resource type of the name. - * @param resourceName The resource name of the name. + * @param type The type of the name. + * @param name The name of the name. * @return A new FullyQualifiedName. */ public static FullyQualifiedName of( - String pkg, List<String> qualifiers, ResourceType resourceType, String resourceName) { + String pkg, List<String> qualifiers, Type type, String name) { + checkNotNull(pkg); + checkNotNull(qualifiers); + checkNotNull(type); + checkNotNull(name); ImmutableList<String> immutableQualifiers = ImmutableList.copyOf(qualifiers); // TODO(corysmith): Address the GC thrash this creates by managing a simplified, mutable key to // do the instance check. - FullyQualifiedName name = - new FullyQualifiedName(pkg, immutableQualifiers, resourceType, resourceName); + FullyQualifiedName fqn = + new FullyQualifiedName(pkg, immutableQualifiers, type, name); // Use putIfAbsent to get the canonical instance, if there. If it isn't, putIfAbsent will // return null, and we should return the current instance. - FullyQualifiedName cached = instanceCache.putIfAbsent(name, name); + FullyQualifiedName cached = instanceCache.putIfAbsent(fqn, fqn); if (cached == null) { - return name; + return fqn; } else { cacheHit.incrementAndGet(); return cached; } } + /** + * Creates a new FullyQualifiedName with normalized qualifiers. + * + * @param pkg The resource package of the name. If unknown the default should be "res-auto" + * @param qualifiers The resource qualifiers of the name, such as "en" or "xhdpi". + * @param type The resource type of the name. + * @param name The name of the name. + * @return A new FullyQualifiedName. + */ + static FullyQualifiedName of( + String pkg, List<String> qualifiers, ResourceType type, String name) { + return of(pkg, qualifiers, new ResourceTypeWrapper(type), name); + } + public static FullyQualifiedName fromProto(SerializeFormat.DataKey protoKey) { return of( protoKey.getKeyPackage(), protoKey.getQualifiersList(), - ResourceType.valueOf(protoKey.getResourceType()), + createTypeFrom(protoKey.getResourceType()), protoKey.getKeyValue()); } @@ -281,8 +457,19 @@ public class FullyQualifiedName implements DataKey { private final String pkg; private final ImmutableList<String> qualifiers; - private final ResourceType resourceType; - private final String resourceName; + private final Type type; + private final String name; + + private FullyQualifiedName( + String pkg, + ImmutableList<String> qualifiers, + Type type, + String name) { + this.pkg = pkg; + this.qualifiers = qualifiers; + this.type = type; + this.name = name; + } /** * Returns a string path representation of the FullyQualifiedName. @@ -298,10 +485,10 @@ public class FullyQualifiedName implements DataKey { return Paths.get( DASH_JOINER.join( ImmutableList.<String>builder() - .add(resourceType.getName()) + .add(type.getName()) .addAll(qualifiers) .build()), - resourceName + sourceExtension) + name + sourceExtension) .toString(); } @@ -311,8 +498,8 @@ public class FullyQualifiedName implements DataKey { return String.format( "%s/%s", DASH_JOINER.join( - ImmutableList.<String>builder().add(resourceType.getName()).addAll(qualifiers).build()), - resourceName); + ImmutableList.<String>builder().add(type.getName()).addAll(qualifiers).build()), + name); } /** @@ -333,22 +520,18 @@ public class FullyQualifiedName implements DataKey { } public String name() { - return resourceName; + return name; } public ResourceType type() { - return resourceType; + if (type instanceof ResourceTypeWrapper) { + return ((ResourceTypeWrapper) type).resourceType; + } + return null; } - private FullyQualifiedName( - String pkg, - ImmutableList<String> qualifiers, - ResourceType resourceType, - String resourceName) { - this.pkg = pkg; - this.qualifiers = qualifiers; - this.resourceType = resourceType; - this.resourceName = resourceName; + public boolean isOverwritable() { + return type.isOverwritable(); } /** Creates a FullyQualifiedName from this one with a different package. */ @@ -357,12 +540,12 @@ public class FullyQualifiedName implements DataKey { if (pkg.equals(newPackage)) { return this; } - return of(newPackage, qualifiers, resourceType, resourceName); + return of(newPackage, qualifiers, type, name); } @Override public int hashCode() { - return Objects.hash(pkg, qualifiers, resourceType, resourceName); + return Objects.hash(pkg, qualifiers, type, name); } @Override @@ -372,8 +555,8 @@ public class FullyQualifiedName implements DataKey { } FullyQualifiedName other = getClass().cast(obj); return Objects.equals(pkg, other.pkg) - && Objects.equals(resourceType, other.resourceType) - && Objects.equals(resourceName, other.resourceName) + && Objects.equals(type, other.type) + && Objects.equals(name, other.name) && Objects.equals(qualifiers, other.qualifiers); } @@ -382,8 +565,8 @@ public class FullyQualifiedName implements DataKey { return MoreObjects.toStringHelper(getClass()) .add("pkg", pkg) .add("qualifiers", qualifiers) - .add("resourceType", resourceType) - .add("resourceName", resourceName) + .add("type", type) + .add("name", name) .toString(); } @@ -396,11 +579,11 @@ public class FullyQualifiedName implements DataKey { if (!pkg.equals(other.pkg)) { return pkg.compareTo(other.pkg); } - if (!resourceType.equals(other.resourceType)) { - return resourceType.compareTo(other.resourceType); + if (!type.equals(other.type)) { + return type.compareTo(other.type); } - if (!resourceName.equals(other.resourceName)) { - return resourceName.compareTo(other.resourceName); + if (!name.equals(other.name)) { + return name.compareTo(other.name); } if (!qualifiers.equals(other.qualifiers)) { if (qualifiers.size() != other.qualifiers.size()) { @@ -425,8 +608,8 @@ public class FullyQualifiedName implements DataKey { public SerializeFormat.DataKey.Builder toSerializedBuilder() { return SerializeFormat.DataKey.newBuilder() .setKeyPackage(pkg) - .setResourceType(resourceType.getName().toUpperCase()) + .setResourceType(type.getName()) .addAllQualifiers(qualifiers) - .setKeyValue(resourceName); + .setKeyValue(name); } } |