Skip to content

Commit

Permalink
Merge pull request #3 from meteorcloudy/bzlmod-repo
Browse files Browse the repository at this point in the history
Fetching repositories from bzlmod generated repo info
  • Loading branch information
Wyverald authored Apr 21, 2021
2 parents 3cf941c + 350f104 commit 70ae3d2
Show file tree
Hide file tree
Showing 24 changed files with 983 additions and 11 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
load("@rules_java//java:defs.bzl", "java_library")

package(
default_visibility = ["//src:__subpackages__"],
)

java_library(
name = "repo_rule_value",
srcs = [
"BzlmodRepoRuleValue.java",
],
deps = [
"//src/main/java/com/google/devtools/build/lib/concurrent",
"//src/main/java/com/google/devtools/build/lib/packages",
"//src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec",
"//src/main/java/com/google/devtools/build/skyframe:skyframe-objects",
"//third_party:guava",
],
)

java_library(
name = "repo_info_values",
srcs = [
"BazelModuleRepoInfoValue.java",
"ModuleRuleRepoInfoValue.java",
"RepositoryInfo.java",
],
deps = [
"//src/main/java/com/google/devtools/build/lib/concurrent",
"//src/main/java/com/google/devtools/build/skyframe:skyframe-objects",
"//third_party:guava",
],
)

java_library(
name = "repo_info_functions",
srcs = [
"BazelModuleRepoInfoFunction.java",
"ModuleRuleRepoInfoFunction.java",
"LockFileParser.java",
],
deps = [
":repo_info_values",
"//src/main/java/com/google/devtools/build/lib/actions:file_metadata",
"//src/main/java/com/google/devtools/build/lib/pkgcache",
"//src/main/java/com/google/devtools/build/lib/skyframe:precomputed_value",
"//src/main/java/com/google/devtools/build/lib/vfs",
"//src/main/java/com/google/devtools/build/lib/vfs:pathfragment",
"//src/main/java/com/google/devtools/build/skyframe",
"//src/main/java/com/google/devtools/build/skyframe:skyframe-objects",
"//third_party:gson",
"//third_party:guava",
],
)

java_library(
name = "repo_rule_creator",
srcs = ["BzlmodRepoRuleCreator.java"],
deps = [
"//src/main/java/com/google/devtools/build/lib/events",
"//src/main/java/com/google/devtools/build/lib/packages",
"//src/main/java/net/starlark/java/eval",
],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package com.google.devtools.build.lib.bazel.bzlmod.repo;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.devtools.build.lib.actions.FileValue;
import com.google.devtools.build.lib.pkgcache.PathPackageLocator;
import com.google.devtools.build.lib.skyframe.PrecomputedValue;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.build.lib.vfs.PathFragment;
import com.google.devtools.build.lib.vfs.Root;
import com.google.devtools.build.lib.vfs.RootedPath;
import com.google.devtools.build.skyframe.SkyFunction;
import com.google.devtools.build.skyframe.SkyFunctionException;
import com.google.devtools.build.skyframe.SkyFunctionException.Transience;
import com.google.devtools.build.skyframe.SkyKey;
import com.google.devtools.build.skyframe.SkyValue;

import java.io.IOException;

import javax.annotation.Nullable;

public class BazelModuleRepoInfoFunction implements SkyFunction {

@Nullable
@Override
public SkyValue compute(SkyKey skyKey, Environment env)
throws SkyFunctionException, InterruptedException {
Preconditions.checkArgument(skyKey == BazelModuleRepoInfoValue.key());
PathPackageLocator packageLocator = PrecomputedValue.PATH_PACKAGE_LOCATOR.get(env);
ImmutableList<Root> packagePath = packageLocator.getPathEntries();

// In Bazel, there should be only one workspace root.
Root workspaceRoot = packagePath.get(0);
RootedPath lockFile = RootedPath.toRootedPath(workspaceRoot,
PathFragment.create("native_module_repos.json"));

FileValue fileValue = (FileValue) env.getValue(FileValue.key(lockFile));
if (env.valuesMissing()) {
return null;
}

if (!fileValue.exists() || !fileValue.isFile()) {
throw new ResolvedBazelModuleRepositoriesFunctionException(
new IOException("Expect lock file native_module_repos.json to exist at workspace root."),
Transience.TRANSIENT);
}

Path lockFilePath = lockFile.asPath();
byte[] bytes;
try {
bytes = FileSystemUtils.readWithKnownFileSize(lockFilePath, lockFilePath.getFileSize());
} catch (IOException ex) {
throw new ResolvedBazelModuleRepositoriesFunctionException(ex, Transience.TRANSIENT);
}

return new BazelModuleRepoInfoValue(
LockFileParser.loadRepositoryInfos(new String(bytes)));
}

@Nullable
@Override
public String extractTag(SkyKey skyKey) {
return null;
}

private static final class ResolvedBazelModuleRepositoriesFunctionException extends SkyFunctionException {
ResolvedBazelModuleRepositoriesFunctionException(IOException e, Transience transience) {
super(e, transience);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.google.devtools.build.lib.bazel.bzlmod.repo;

import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
import com.google.devtools.build.skyframe.SkyFunctionName;
import com.google.devtools.build.skyframe.SkyKey;
import com.google.devtools.build.skyframe.SkyValue;

// TODO(pcloudy): implement the actual SkyFunction for this
public class BazelModuleRepoInfoValue implements SkyValue {
public static final SkyFunctionName BAZEL_MODULE_REPO_INFO =
SkyFunctionName.createHermetic("BAZEL_MODULE_REPO_INFO");

@Immutable
public static class BazelModuleRepoInfoKey implements SkyKey {
private static final BazelModuleRepoInfoKey KEY = new BazelModuleRepoInfoKey();

private BazelModuleRepoInfoKey() {}

@Override
public SkyFunctionName functionName() {
return BAZEL_MODULE_REPO_INFO;
}
}

public static BazelModuleRepoInfoKey key() {
return BazelModuleRepoInfoKey.KEY;
}

private final ImmutableMap<String, RepositoryInfo> repositories;

public BazelModuleRepoInfoValue(ImmutableMap<String, RepositoryInfo> repositories) {
this.repositories = repositories;
}

public RepositoryInfo getRepository(String repositoryName) {
return repositories.getOrDefault(repositoryName, null);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.google.devtools.build.lib.bazel.bzlmod.repo;

import com.google.devtools.build.lib.events.EventHandler;
import com.google.devtools.build.lib.packages.Package;
import com.google.devtools.build.lib.packages.Rule;
import com.google.devtools.build.lib.packages.RuleFactory.InvalidRuleException;

import net.starlark.java.eval.StarlarkSemantics;

import java.util.Map;

public interface BzlmodRepoRuleCreator {
Rule createRule(Package.Builder pkg, StarlarkSemantics semantics, Map<String, Object> kwargs, EventHandler handler)
throws InterruptedException, InvalidRuleException;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package com.google.devtools.build.lib.bazel.bzlmod.repo;

import com.google.common.collect.Interner;
import com.google.devtools.build.lib.concurrent.BlazeInterners;
import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
import com.google.devtools.build.lib.packages.Rule;
import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
import com.google.devtools.build.skyframe.SkyFunctionName;
import com.google.devtools.build.skyframe.SkyKey;
import com.google.devtools.build.skyframe.SkyValue;

import java.util.Objects;

public class BzlmodRepoRuleValue implements SkyValue {
public static final SkyFunctionName BZLMOD_REPO_RULE =
SkyFunctionName.createHermetic("BZLMOD_REPO_RULE");

private final Rule rule;

public BzlmodRepoRuleValue(Rule rule) {
this.rule = rule;
}

public Rule getRule() {
return rule;
}

public static BzlmodRepoRuleKey key(String repositoryName, boolean forModuleRuleResolution) {
return BzlmodRepoRuleKey.create(repositoryName, forModuleRuleResolution);
}

/** Represents an unsuccessful repository lookup. */
public static final class RepoRuleNotFoundValue extends BzlmodRepoRuleValue {
private RepoRuleNotFoundValue() {
super(null);
}

@Override
public Rule getRule() {
throw new IllegalStateException();
}
}

public static final RepoRuleNotFoundValue REPO_RULE_NOT_FOUND_VALUE = new RepoRuleNotFoundValue();

/** Argument for the SkyKey to request a BzlmodRepoRuleValue. */
@Immutable
@AutoCodec
public static class BzlmodRepoRuleKey implements SkyKey {
private static final Interner<BzlmodRepoRuleValue.BzlmodRepoRuleKey> interner = BlazeInterners.newWeakInterner();

private final String repositoryName;
private final boolean forModuleRuleResolution;

private BzlmodRepoRuleKey(String repositoryName, boolean forModuleRuleResolution) {
this.repositoryName = repositoryName;
this.forModuleRuleResolution = forModuleRuleResolution;
}

@AutoCodec.VisibleForSerialization
@AutoCodec.Instantiator
static BzlmodRepoRuleValue.BzlmodRepoRuleKey create(
String repositoryName, boolean forModuleRuleResolution) {
return interner.intern(
new BzlmodRepoRuleValue.BzlmodRepoRuleKey(repositoryName, forModuleRuleResolution));
}

public String getRepositoryName() {
return repositoryName;
}

public boolean isForModuleRuleResolution() {
return forModuleRuleResolution;
}

@Override
public SkyFunctionName functionName() {
return BZLMOD_REPO_RULE;
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof BzlmodRepoRuleValue.BzlmodRepoRuleKey)) {
return false;
}
BzlmodRepoRuleValue.BzlmodRepoRuleKey other = (BzlmodRepoRuleValue.BzlmodRepoRuleKey) obj;
return this.repositoryName.equals(other.repositoryName)
&& this.forModuleRuleResolution == other.forModuleRuleResolution;
}

@Override
public int hashCode() {
return Objects.hash(BzlmodRepoRuleKey.class, repositoryName, forModuleRuleResolution);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package com.google.devtools.build.lib.bazel.bzlmod.repo;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.lib.bazel.bzlmod.repo.RepositoryInfo.Builder;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonPrimitive;

import java.util.Map.Entry;

public abstract class LockFileParser {
private static Object convertToJavaObject(JsonElement element) {
if (element.isJsonNull()) {
return null;
}
if (element.isJsonPrimitive()) {
JsonPrimitive value = element.getAsJsonPrimitive();
if (value.isBoolean()) {
return value.getAsBoolean();
} else if (value.isString()) {
return value.getAsString();
} else if (value.isNumber()) {
return value.getAsInt();
}
} else if (element.isJsonArray()) {
ImmutableList.Builder<Object> builder = ImmutableList.builder();
for (JsonElement e : element.getAsJsonArray()) {
builder.add(convertToJavaObject(e));
}
return builder.build();
} else if (element.isJsonObject()) {
ImmutableMap.Builder<String, Object> builder = ImmutableMap.builder();
for (Entry<String, JsonElement> entry : element.getAsJsonObject().entrySet()) {
builder.put(entry.getKey(), convertToJavaObject(entry.getValue()));
}
return builder.build();
}
throw new IllegalArgumentException("Wrong element type");
}

static ImmutableMap<String, RepositoryInfo> loadRepositoryInfos(String content) {
JsonParser parser = new JsonParser();
JsonElement json = parser.parse(content);

ImmutableMap.Builder<String, RepositoryInfo> repositoryInfos = ImmutableMap.builder();

for (JsonElement repoElement: json.getAsJsonObject().get("repositories").getAsJsonArray()) {
JsonObject repo = repoElement.getAsJsonObject();

ImmutableMap.Builder<String, Object> attributesBuilder = ImmutableMap.builder();
if (repo.get("rule_class").getAsString().contains("%")) {
attributesBuilder.put("visibility", ImmutableList.of());
}
for (Entry<String, JsonElement> entry : repo.get("attributes").getAsJsonObject().entrySet()) {
attributesBuilder.put(entry.getKey(), convertToJavaObject(entry.getValue()));
}

RepositoryInfo.Builder builder = new Builder();
String name = "@" + repo.get("name").getAsString();
RepositoryInfo repositoryInfo = builder.setName(name)
.setRuleClass(repo.get("rule_class").getAsString())
.setAttributes(attributesBuilder.build())
.setRepoDeps((ImmutableList) convertToJavaObject(repo.get("repo_deps")))
.setRepoMappings((ImmutableMap<String, String>) convertToJavaObject(repo.get("repo_mappings")))
.setVendorDir(repo.get("vendor_dir").getAsString())
.build();

repositoryInfos.put(name, repositoryInfo);
}

return repositoryInfos.build();
}
}
Loading

0 comments on commit 70ae3d2

Please sign in to comment.