View
@@ -0,0 +1,168 @@
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you 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 org.openqa.selenium.tools;
import static com.github.javaparser.ParseStart.COMPILATION_UNIT;
import static net.bytebuddy.jar.asm.Opcodes.ACC_MANDATED;
import static net.bytebuddy.jar.asm.Opcodes.ACC_MODULE;
import static net.bytebuddy.jar.asm.Opcodes.ACC_TRANSITIVE;
import com.github.javaparser.JavaParser;
import com.github.javaparser.ParseResult;
import com.github.javaparser.ParserConfiguration;
import com.github.javaparser.Provider;
import com.github.javaparser.Providers;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.Modifier;
import com.github.javaparser.ast.expr.Name;
import com.github.javaparser.ast.modules.ModuleDeclaration;
import com.github.javaparser.ast.modules.ModuleExportsStmt;
import com.github.javaparser.ast.modules.ModuleOpensStmt;
import com.github.javaparser.ast.modules.ModuleProvidesStmt;
import com.github.javaparser.ast.modules.ModuleRequiresStmt;
import com.github.javaparser.ast.modules.ModuleUsesStmt;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
import net.bytebuddy.jar.asm.ClassWriter;
import net.bytebuddy.jar.asm.ModuleVisitor;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.FileTime;
import java.time.Instant;
import java.util.EnumSet;
import java.util.jar.JarOutputStream;
import java.util.zip.ZipEntry;
public class ModuleMaker {
// Starts at 1980-01-01. We'll match what buck uses
private static final long DOS_EPOCH = Instant.parse("1985-02-01T00:00:00.00Z").toEpochMilli();
public static void main(String[] args) throws IOException {
Path in = Paths.get(args[0]);
Path out = Paths.get(args[1]);
ParserConfiguration parserConfig = new ParserConfiguration()
.setLanguageLevel(ParserConfiguration.LanguageLevel.JAVA_9);
Provider provider = Providers.provider(in);
ParseResult<CompilationUnit> result = new JavaParser(parserConfig)
.parse(COMPILATION_UNIT, provider);
CompilationUnit unit = result.getResult()
.orElseThrow(() -> new RuntimeException("Unable to parse " + in));
ClassWriter classWriter = new ClassWriter(0);
classWriter.visit(
/* version 9 */
53,
ACC_MODULE,
"module-info",
null,
null,
null);
ModuleDeclaration moduleDeclaration = unit.getModule()
.orElseThrow(() -> new RuntimeException("No module declaration in " + in));
String name = moduleDeclaration.getName().asString();
ModuleVisitor moduleVisitor = classWriter.visitModule(name, 0, null);
moduleVisitor.visitRequire("java.base", ACC_MANDATED, null);
moduleDeclaration.accept(new MyModuleVisitor(moduleVisitor), null);
moduleVisitor.visitEnd();
classWriter.visitEnd();
try (OutputStream os = Files.newOutputStream(out);
JarOutputStream jos = new JarOutputStream(os)) {
byte[] bytes = classWriter.toByteArray();
ZipEntry entry = new ZipEntry("module-info.class");
entry.setTime(DOS_EPOCH);
entry.setCreationTime(FileTime.fromMillis(DOS_EPOCH));
entry.setLastModifiedTime(FileTime.fromMillis(DOS_EPOCH));
entry.setSize(bytes.length);
jos.putNextEntry(entry);
jos.write(bytes);
jos.closeEntry();
}
}
private static class MyModuleVisitor extends VoidVisitorAdapter<Void> {
private final ModuleVisitor byteBuddyVisitor;
MyModuleVisitor(ModuleVisitor byteBuddyVisitor) {
this.byteBuddyVisitor = byteBuddyVisitor;
}
@Override
public void visit(ModuleRequiresStmt n, Void arg) {
byteBuddyVisitor.visitRequire(
n.getNameAsString(),
getByteBuddyModifier(n.getModifiers()),
null);
}
@Override
public void visit(ModuleExportsStmt n, Void arg) {
byteBuddyVisitor.visitExport(
n.getNameAsString().replace('.', '/'),
0,
n.getModuleNames().stream().map(Name::asString).toArray(String[]::new));
}
@Override
public void visit(ModuleProvidesStmt n, Void arg) {
byteBuddyVisitor.visitProvide(
n.getTypeAsString().replace('.', '/'),
n.getWithTypes().stream().map(type -> type.asString().replace('.', '/')).toArray(String[]::new));
}
@Override
public void visit(ModuleUsesStmt n, Void arg) {
throw new UnsupportedOperationException(n.toString());
}
@Override
public void visit(ModuleOpensStmt n, Void arg) {
throw new UnsupportedOperationException(n.toString());
}
private int getByteBuddyModifier(EnumSet<Modifier> modifiers) {
return modifiers.stream()
.mapToInt(mod -> {
switch (mod) {
case TRANSITIVE:
return ACC_TRANSITIVE;
default:
throw new RuntimeException("Unknown modifier: " + mod);
}
})
.reduce(0, (l, r) -> l | r);
}
}
}
View
@@ -0,0 +1,24 @@
def java_library(name, module_info=None, deps=[], visibility=[], **kwargs):
if module_info:
native.genrule(
name = "%s-generate-module-info" % name,
srcs = [ module_info ],
out = 'module-info.jar',
cmd = "$(exe //java/client/src/org/openqa/selenium/tools:module-maker) $SRCS $OUT"
)
native.prebuilt_jar(
name = "%s-module-info" % name,
binary_jar = ":%s-generate-module-info" % name,
visibility = visibility,
)
deps += [ ":%s-module-info" % name ]
native.java_library(
name=name,
deps=deps,
visibility=visibility,
**kwargs)
View
@@ -5,6 +5,7 @@ prebuilt_jar(
source_jar = 'byte-buddy-1.8.15-sources.jar',
visibility = [
'//java/client/src/org/openqa/selenium/remote:remote',
'//java/client/src/org/openqa/selenium/tools:',
'//third_party/java/mockito:mockito-core',
],
)
View
@@ -4,7 +4,7 @@ prebuilt_jar(
binary_jar = 'javaparser-core-3.6.14.jar',
source_jar = 'javaparser-core-3.6.14-sources.jar',
visibility = [
'//java/client/src/org/openqa/selenium/tools:package-lib',
'//java/client/src/org/openqa/selenium/tools:',
],
)