Skip to content

Commit

Permalink
Adds a translation layer for ObjcProvider values between java and sky…
Browse files Browse the repository at this point in the history
…lark to allow for the exposure of values that are not typed as skylark primatives.

--
MOS_MIGRATED_REVID=122838580
  • Loading branch information
calpeyser authored and hermione521 committed May 23, 2016
1 parent c1b4175 commit ef238f9
Show file tree
Hide file tree
Showing 2 changed files with 151 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,8 @@
import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
import com.google.devtools.build.lib.rules.cpp.CppModuleMap;
import com.google.devtools.build.lib.rules.cpp.LinkerInputs;
import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
import com.google.devtools.build.lib.syntax.ClassObject.SkylarkClassObject;
import com.google.devtools.build.lib.syntax.SkylarkNestedSet;
import com.google.devtools.build.lib.syntax.SkylarkType;
import com.google.devtools.build.lib.util.Preconditions;
import com.google.devtools.build.lib.vfs.PathFragment;
import com.google.devtools.build.xcode.xcodegen.proto.XcodeGenProtos.TargetControl;
Expand Down Expand Up @@ -342,10 +339,6 @@ public enum Flag {
/**
* All keys in ObjcProvider that will be passed in the corresponding Skylark provider.
*/
// Only keys for Artifact or primitive types can be in the Skylark provider, as other types
// are not supported as Skylark types.
// Note: This list is only required to support objcprovider <-> skylarkprovider conversion, which
// will be removed in favor of native skylark ObjcProvider access once that is implemented.
static final ImmutableList<Key<?>> KEYS_FOR_SKYLARK =
ImmutableList.<Key<?>>of(
LIBRARY,
Expand All @@ -370,7 +363,13 @@ public enum Flag {
STRINGS,
LINKOPT,
J2OBJC_LIBRARY,
ROOT_MERGE_ZIP);
ROOT_MERGE_ZIP,
INCLUDE,
INCLUDE_SYSTEM,
GENERAL_RESOURCE_DIR,
BUNDLE_IMPORT_DIR,
XCASSETS_DIR,
FRAMEWORK_DIR);

/**
* Returns the skylark key for the given string, or null if no such key exists or is available
Expand Down Expand Up @@ -433,20 +432,6 @@ public boolean hasAssetCatalogs() {
return !get(XCASSETS_DIR).isEmpty();
}

@SkylarkCallable(
name = "include",
structField = true,
doc = "Returns a set of include search paths."
)
public SkylarkNestedSet getIncludeDirs() {
// TODO(b/28615250): Generalize this conversion.
NestedSetBuilder<String> includes = NestedSetBuilder.stableOrder();
for (PathFragment path : get(INCLUDE)) {
includes.add(path.getSafePathString());
}
return SkylarkNestedSet.of(String.class, includes.build());
}

/**
* A builder for this context with an API that is optimized for collecting information from
* several transitive dependencies.
Expand Down Expand Up @@ -613,20 +598,7 @@ public <E> Builder addAllForDirectDependents(Key<E> key, Iterable<? extends E> t
* an appropriate SkylarkNestedSet.
*/
void addElementsFromSkylark(Key<?> key, Object toAdd) {
if (!(toAdd instanceof SkylarkNestedSet)) {
throw new IllegalArgumentException(
String.format(
AppleSkylarkCommon.NOT_SET_ERROR, key.getSkylarkKeyName(), toAdd.getClass()));
} else if (!((SkylarkNestedSet) toAdd).getContentType().canBeCastTo(key.getType())) {
throw new IllegalArgumentException(
String.format(
AppleSkylarkCommon.BAD_SET_TYPE_ERROR,
key.getSkylarkKeyName(),
key.getType(),
((SkylarkNestedSet) toAdd).getContentType().getType()));
} else {
uncheckedAddAll(key, (SkylarkNestedSet) toAdd, this.items);
}
uncheckedAddAll(key, ObjcProviderSkylarkConverters.convertToJava(key, toAdd), this.items);
}

/**
Expand Down Expand Up @@ -674,23 +646,26 @@ public ObjcProvider build() {

ImmutableMap.Builder<String, Object> skylarkFields = new ImmutableMap.Builder<>();
for (Key<?> key : KEYS_FOR_SKYLARK) {
SkylarkType type = SkylarkType.of(key.getType());
if (propagated.containsKey(key) && strictDependency.containsKey(key)) {
NestedSet<?> union = new NestedSetBuilder(STABLE_ORDER)
.addTransitive(propagated.get(key))
.addTransitive(strictDependency.get(key))
.build();
skylarkFields.put(key.getSkylarkKeyName(), SkylarkNestedSet.of(type, union));
skylarkFields.put(
key.getSkylarkKeyName(), ObjcProviderSkylarkConverters.convertToSkylark(key, union));
} else if (items.containsKey(key)) {
skylarkFields.put(
key.getSkylarkKeyName(), SkylarkNestedSet.of(type, propagated.get(key)));
key.getSkylarkKeyName(),
ObjcProviderSkylarkConverters.convertToSkylark(key, propagated.get(key)));
} else if (strictDependency.containsKey(key)) {
skylarkFields.put(
key.getSkylarkKeyName(), SkylarkNestedSet.of(type, strictDependency.get(key)));
key.getSkylarkKeyName(),
ObjcProviderSkylarkConverters.convertToSkylark(key, strictDependency.get(key)));
} else {
skylarkFields.put(
skylarkFields.put(
key.getSkylarkKeyName(),
SkylarkNestedSet.of(type, new NestedSetBuilder(STABLE_ORDER).build()));
ObjcProviderSkylarkConverters.convertToSkylark(
key, new NestedSetBuilder(STABLE_ORDER).build()));
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
// Copyright 2016 The Bazel Authors. All rights reserved.
//
// 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.google.devtools.build.lib.rules.objc;

import static com.google.devtools.build.lib.rules.objc.AppleSkylarkCommon.BAD_SET_TYPE_ERROR;
import static com.google.devtools.build.lib.rules.objc.AppleSkylarkCommon.NOT_SET_ERROR;

import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
import com.google.devtools.build.lib.rules.objc.ObjcProvider.Key;
import com.google.devtools.build.lib.syntax.SkylarkNestedSet;
import com.google.devtools.build.lib.syntax.SkylarkType;
import com.google.devtools.build.lib.vfs.PathFragment;

/**
* A utility class for converting ObjcProvider values between java and skylark representation.
*/
public class ObjcProviderSkylarkConverters {

/**
* A map of possible NestedSet types to the converters that should define their treatment
* in translating between a java and skylark ObjcProvider.
*/
private static final ImmutableMap<Class<?>, Converter> CONVERTERS =
ImmutableMap.<Class<?>, Converter>builder()
.put(Artifact.class, new DirectConverter())
.put(String.class, new DirectConverter())
.put(PathFragment.class, new PathFragmentToStringConverter())
.build();

/**
* Returns a value for a skylark attribute given a java ObjcProvider key and value.
*/
public static Object convertToSkylark(Key<?> javaKey, NestedSet<?> javaValue) {
return CONVERTERS.get(javaKey.getType()).valueForSkylark(javaKey, javaValue);
}

/**
* Returns a value for a java ObjcProvider given a key and a corresponding skylark value.
*/
public static Iterable<?> convertToJava(Key<?> javaKey, Object skylarkValue) {
return CONVERTERS.get(javaKey.getType()).valueForJava(javaKey, skylarkValue);
}

/**
* A converter for ObjcProvider values.
*/
private static interface Converter {
/**
* Translates a java ObjcProvider value to a skylark ObjcProvider value.
*/
abstract Object valueForSkylark(Key<?> javaKey, NestedSet<?> javaValue);

/**
* Translates a skylark ObjcProvider value to a java ObjcProvider value.
*/
abstract Iterable<?> valueForJava(Key<?> javaKey, Object skylarkValue);
}

/**
* A converter that uses the same value for java and skylark.
*/
private static class DirectConverter implements Converter {

@Override
public Object valueForSkylark(Key<?> javaKey, NestedSet<?> javaValue) {
SkylarkType type = SkylarkType.of(javaKey.getType());
return SkylarkNestedSet.of(type, javaValue);
}

@Override
public Iterable<?> valueForJava(Key<?> javaKey, Object skylarkValue) {
validateTypes(skylarkValue, javaKey.getType(), javaKey.getSkylarkKeyName());
return (SkylarkNestedSet) skylarkValue;
}
}

/**
* A converter that that translates between a java PathFragment and a skylark string.
*/
private static class PathFragmentToStringConverter implements Converter {

@SuppressWarnings("unchecked")
@Override
public Object valueForSkylark(Key<?> javaKey, NestedSet<?> javaValue) {
NestedSetBuilder<String> result = NestedSetBuilder.stableOrder();
for (PathFragment path : (Iterable<PathFragment>) javaValue) {
result.add(path.getSafePathString());
}
return SkylarkNestedSet.of(String.class, result.build());
}

@SuppressWarnings("unchecked")
@Override
public Iterable<?> valueForJava(Key<?> javaKey, Object skylarkValue) {
validateTypes(skylarkValue, String.class, javaKey.getSkylarkKeyName());
NestedSetBuilder<PathFragment> result = NestedSetBuilder.stableOrder();
for (String path : (Iterable<String>) skylarkValue) {
result.add(new PathFragment(path));
}
return result.build();
}
}

/**
* Throws an error if the given object is not a nested set of the given type.
*/
private static void validateTypes(Object toCheck, Class<?> expectedSetType, String keyName) {
if (!(toCheck instanceof SkylarkNestedSet)) {
throw new IllegalArgumentException(String.format(NOT_SET_ERROR, keyName, toCheck.getClass()));
} else if (!((SkylarkNestedSet) toCheck).getContentType().canBeCastTo(expectedSetType)) {
throw new IllegalArgumentException(
String.format(
BAD_SET_TYPE_ERROR,
keyName,
expectedSetType,
((SkylarkNestedSet) toCheck).getContentType().getType()));
}
}
}

0 comments on commit ef238f9

Please sign in to comment.