Skip to content

Commit 746ecf4

Browse files
committed
First import
1 parent 673fb8f commit 746ecf4

File tree

10 files changed

+305
-0
lines changed

10 files changed

+305
-0
lines changed

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
bazel-*
2+
.idea
3+
*.jar
4+
user.bazelrc
5+
external
6+
build.j

BUILD

Whitespace-only changes.

InjectionManager.java

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
import java.lang.reflect.Method;
2+
import java.net.URL;
3+
import java.net.URLClassLoader;
4+
import java.lang.ClassLoader;
5+
import java.util.Arrays;
6+
import java.io.BufferedReader;
7+
import java.io.InputStreamReader;
8+
import java.io.File;
9+
import java.util.Map;
10+
import java.io.InputStream;
11+
import java.io.FileOutputStream;
12+
import java.io.FileInputStream;
13+
14+
// Injects user jars into Bazel, then starts the server
15+
public class InjectionManager {
16+
private Thread nativeRuleJVMThread;
17+
18+
public InjectionManager() {}
19+
20+
private URLClassLoader loadJar(String path) throws Exception {
21+
URL serverJarURL = new URL(path);
22+
URLClassLoader loader = new URLClassLoader(
23+
new URL[] {serverJarURL},
24+
this.getClass().getClassLoader()
25+
);
26+
return loader;
27+
}
28+
29+
// Injects injectJar into baseJar
30+
int injectJar(String injectorPath, String baseJar, String injectJar) throws Exception {
31+
String[] command = {"/bin/bash", "-c", "source " + injectorPath};
32+
ProcessBuilder pb = new ProcessBuilder(command);
33+
// Consider refactoring this a bit
34+
Map<String, String> env = pb.environment();
35+
env.put("BAZEL_JAR", baseJar);
36+
if (injectJar != null) {
37+
env.put("INJECT_JAR", injectJar);
38+
}
39+
40+
Process cmdProc = pb.start();
41+
BufferedReader stdoutReader = new BufferedReader(
42+
new InputStreamReader(cmdProc.getInputStream()));
43+
String line;
44+
while ((line = stdoutReader.readLine()) != null) {
45+
System.out.println(line);
46+
}
47+
48+
BufferedReader stderrReader = new BufferedReader(
49+
new InputStreamReader(cmdProc.getErrorStream()));
50+
while ((line = stderrReader.readLine()) != null) {
51+
System.err.println(line);
52+
}
53+
cmdProc.waitFor();
54+
return cmdProc.exitValue();
55+
}
56+
57+
// Load the injector script from this archive
58+
String unpackInjector() throws Exception {
59+
File folder = new File("bazel-inject/");
60+
if (!folder.exists()) {
61+
folder.mkdirs();
62+
}
63+
String injector = "jar_injector.sh";
64+
File injectorF = new File(folder, injector);
65+
FileOutputStream output = new FileOutputStream(injectorF);
66+
int bytesRead = 0;
67+
byte[] buffer = new byte[4096];
68+
InputStream input = InjectionManager.class.getResourceAsStream(injector);
69+
while ((bytesRead = input.read(buffer)) != -1) {
70+
output.write(buffer, 0, bytesRead);
71+
}
72+
return injectorF.getPath();
73+
}
74+
75+
void callMain(String workspaceRoot, String[] serverArgs, String baseJar, String injectJar) throws Exception {
76+
String injector = unpackInjector();
77+
int injectStatus = injectJar(injector, baseJar, injectJar);
78+
if (injectStatus != 0) {
79+
throw new java.lang.Error("Failed to inject" + baseJar);
80+
}
81+
82+
// Load the injected server
83+
String server = "file://" + workspaceRoot + "/bazel-inject/A-Server.jar";
84+
URLClassLoader loader = loadJar(server);
85+
86+
// src/main/java/com/google/devtools/build/lib/bazel/Bazel.java
87+
Class classToLoad = Class.forName("com.google.devtools.build.lib.bazel.Bazel", true, loader);
88+
Method method = classToLoad.getMethod("main", java.lang.String[].class);
89+
System.err.println("[INFO] loaded injector class..");
90+
method.invoke(null, new Object[]{serverArgs});
91+
}
92+
93+
// The gist of this method is that we'll call Bazel's main - giving us the
94+
// ability to govern what modules are loaded: replacing/adding our own
95+
public void startBazel(String[] args) throws Exception {
96+
System.err.println("[Info] Bazelwrapper starting");
97+
98+
if (args.length < 3) {
99+
throw new java.lang.Error("Invalid args" + Arrays.toString(args));
100+
}
101+
102+
// Get/drop JVM args: e.g. [-jar, /var/tmp/_bazel_$x/install/$yx/A-server.jar,..]
103+
// These 2 lines have assuptions on Bazel CLI / invocation process
104+
String bazelJar = args[1];
105+
String[] serverArgs = Arrays.copyOfRange(args, 2, args.length);
106+
107+
// TODO: Update to proposed API:
108+
// A new --blaze_module starup option - to define a jar
109+
// --blaze_module=com.my.bazel.module=/path/to/module.jar
110+
String injectJar = null;
111+
for (int i = 0; i < serverArgs.length; i++) {
112+
String arg = serverArgs[i];
113+
if (arg.startsWith("--host_jvm_args=-Dbazel.inject=") && arg.endsWith(".jar")) {
114+
injectJar = arg.substring(arg.lastIndexOf("=") + 1, arg.length());
115+
break;
116+
}
117+
}
118+
// Assume they launch from the workspace dir
119+
String workspaceDir = System.getProperty("user.dir");
120+
callMain(workspaceDir, serverArgs, bazelJar, injectJar);
121+
}
122+
123+
public static void main(java.lang.String[] args) {
124+
InjectionManager im = new InjectionManager();
125+
try {
126+
im.startBazel(args);
127+
} catch(Exception e) {
128+
System.err.println("[ERROR] Failed");
129+
System.err.println(e);
130+
System.exit(1);
131+
}
132+
}
133+
}

MANIFEST.MF

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Main-Class: InjectionManager
2+

Makefile

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
all: jar
2+
3+
clean:
4+
rm -rf bazel-inject
5+
6+
jar: clean
7+
# Consider moving this to Bazel
8+
mkdir -p bazel-inject/META-INF
9+
cp -f MANIFEST.MF bazel-inject/META-INF/MANIFEST.MF
10+
cp -f tools/jar_injector.sh bazel-inject
11+
javac -d bazel-inject InjectionManager.java
12+
cd bazel-inject && jar cmfv \
13+
META-INF/MANIFEST.MF BazelInject.jar \
14+
*.class *.sh
15+
16+
## Development helpers
17+
18+
run:
19+
echo "Running with jar $$(shasum libmain.jar)"
20+
bazel shutdown
21+
bazel build tests/...
22+

WORKSPACE

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
load("//tests:rules.bzl", "x_repo")
2+
3+
# Loading some test rules
4+
x_repo(
5+
name = "x",
6+
path = "z",
7+
)

tests/BUILD

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
load("//tests:rules.bzl", "x_rule")
2+
x_rule(name="x", path="z")
3+
4+
genrule(
5+
name = "foo",
6+
srcs = [],
7+
outs = ["foo.h"],
8+
cmd = "echo xx > $(OUTS)",
9+
)

tests/rules.bzl

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
def _repo_impl(ctx):
2+
print("PATH", ctx.attr.path)
3+
ctx.execute(["mkdir", "-p", "external/" + ctx.name])
4+
ctx.execute(["touch", "BUILD"])
5+
6+
x_repo = repository_rule(
7+
implementation = _repo_impl,
8+
local = True,
9+
# fragments = [],
10+
attrs = {
11+
"path": attr.label(
12+
mandatory = True,
13+
),
14+
},
15+
)
16+
17+
def _rule_impl(ctx):
18+
print("PATH", ctx.attr.path)
19+
# Here we call our custom swift_common
20+
# print("PKG", swift_common.compile(copts=["Some", "Other"]))
21+
22+
x_rule = rule(
23+
implementation = _rule_impl,
24+
attrs = {
25+
"path": attr.string(
26+
mandatory = True,
27+
),
28+
},
29+
)

tools/bazel

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
#!/bin/bash
2+
3+
set -euo pipefail
4+
5+
readonly REPO_DIR="$( cd "$( dirname "$(dirname "${BASH_SOURCE[0]}" )" )" >/dev/null 2>&1 && pwd )"
6+
7+
bazel_options=()
8+
passthrough_env=(
9+
"CC=clang"
10+
"PATH=/usr/bin:/bin"
11+
"USER=${USER:-build}"
12+
)
13+
14+
if [[ -n "${HOME:-}" ]]; then
15+
passthrough_env+=("HOME=$HOME")
16+
fi
17+
if [[ -n "${TERM:-}" ]]; then
18+
passthrough_env+=("TERM=$TERM")
19+
fi
20+
if [[ -n "${COLUMNS:-}" ]]; then
21+
passthrough_env+=("COLUMNS=$COLUMNS")
22+
fi
23+
24+
# This is a development helper
25+
setup_injector() {
26+
local injector_main="InjectionManager.java"
27+
28+
# shasum to noop compilation and reboot when it changes
29+
local jarf="injector.$(/usr/bin/shasum $injector_main | cut -d ' ' -f1).jar"
30+
local srcroot=$REPO_DIR
31+
if [[ ! -f "$srcroot/bazel-inject/$jarf" ]]; then
32+
echo "Bundling jar $injector_main.."
33+
rm -rf $srcroot/bazel-inject
34+
mkdir -p "$srcroot/bazel-inject/META-INF"
35+
cp -f MANIFEST.MF "$srcroot/bazel-inject/META-INF/MANIFEST.MF"
36+
cp -f $srcroot/tools/jar_injector.sh "$srcroot/bazel-inject"
37+
javac -d "$srcroot/bazel-inject" "$injector_main"
38+
(cd "$srcroot/bazel-inject" && jar cmfv \
39+
META-INF/MANIFEST.MF "$jarf" \
40+
*.class *.sh)
41+
fi
42+
43+
# For development - put a file libmain.jar inside of the repo - we'll inject
44+
bazel_options+=(--host_jvm_args '-Dcom.google.devtools.build.lib.util.LogHandlerQuerier.class=null')
45+
bazel_options+=(--host_jvm_args -Dbazel.inject=$REPO_DIR/libmain.jar)
46+
47+
# This seems to have to go last for now.
48+
bazel_options+=(--host_jvm_args -jar)
49+
bazel_options+=(--host_jvm_args $srcroot/bazel-inject/$jarf)
50+
}
51+
52+
setup_injector
53+
54+
if [[ -n "${BAZELISK_SKIP_WRAPPER:-}" ]]; then
55+
passthrough_env+=("BAZELISK_SKIP_WRAPPER=$BAZELISK_SKIP_WRAPPER")
56+
fi
57+
58+
env -i \
59+
"${passthrough_env[@]}" \
60+
"$BAZEL_REAL" \
61+
${bazel_options[@]-} \
62+
"$@"

tools/jar_injector.sh

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#!/bin/bash
2+
# A helper file to dynamically load BlazeModules at startup
3+
set -e
4+
5+
readonly REPO_DIR="$( cd "$( dirname "$(dirname "${BASH_SOURCE[0]}" )" )" >/dev/null 2>&1 && pwd )"
6+
7+
jar_injector() {
8+
local srcroot="$1"
9+
10+
local user_jar="$INJECT_JAR"
11+
[[ -f "$user_jar" ]] || (echo "error: missing jar $1" && exit 1)
12+
13+
local injected_jar_n="injector.server.$(/usr/bin/shasum $user_jar | cut -d ' ' -f1).jar"
14+
15+
# injecting A-Server.jar inside of this dir
16+
local wd="$srcroot/bazel-inject/"
17+
mkdir -p "$wd"
18+
local injected_jar="$srcroot/bazel-inject/$injected_jar_n"
19+
20+
if [[ ! -f "$injected_jar" ]]; then
21+
local bazel_jar="$BAZEL_JAR"
22+
[[ -f "$bazel_jar" ]] || \
23+
(echo "missing install $bazel_jar" && exit 1)
24+
cp "$bazel_jar" "$injected_jar"
25+
26+
(cd "$wd" && rm -rf injectsrc)
27+
(cd "$wd" && mkdir injectsrc && cd injectsrc && unzip $user_jar)
28+
(cd "$wd" && find injectsrc) # Diagnostics
29+
(cd "$wd" && jar -uf $injected_jar -C injectsrc/ .)
30+
(cd "$wd" && cp $injected_jar A-Server.jar)
31+
fi
32+
echo "injected $injected_jar"
33+
}
34+
35+
jar_injector "$REPO_DIR"

0 commit comments

Comments
 (0)