Skip to content

Commit

Permalink
Support Scala3 .tasty files
Browse files Browse the repository at this point in the history
**ijar** tool support Kotlin modules by [not stripped out](bazelbuild@088d8de)  files in `META-INF/*.kotlin_module`.
This PR add support for new Scala 3 (and Scala 2.13.4+) [TASTy](https://dotty.epfl.ch/docs/reference/metaprogramming/toc.html) format to have ability to use Scala 3 modules.

Closes bazelbuild#12529.

PiperOrigin-RevId: 346068234
  • Loading branch information
timothyklim authored and ulfjack committed Mar 5, 2021
1 parent eeecfa0 commit 192b599
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 3 deletions.
13 changes: 11 additions & 2 deletions third_party/ijar/ijar.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ const char *CLASS_EXTENSION = ".class";
const size_t CLASS_EXTENSION_LENGTH = strlen(CLASS_EXTENSION);
const char *KOTLIN_MODULE_EXTENSION = ".kotlin_module";
const size_t KOTLIN_MODULE_EXTENSION_LENGTH = strlen(KOTLIN_MODULE_EXTENSION);
const char *SCALA_TASTY_EXTENSION = ".tasty";
const size_t SCALA_TASTY_EXTENSION_LENGTH = strlen(SCALA_TASTY_EXTENSION);

const char *MANIFEST_DIR_PATH = "META-INF/";
const size_t MANIFEST_DIR_PATH_LENGTH = strlen(MANIFEST_DIR_PATH);
Expand Down Expand Up @@ -101,9 +103,15 @@ static bool IsKotlinModule(const char *filename, const size_t filename_len) {
KOTLIN_MODULE_EXTENSION_LENGTH);
}

static bool IsScalaTasty(const char *filename, const size_t filename_len) {
return EndsWith(filename, filename_len, SCALA_TASTY_EXTENSION,
SCALA_TASTY_EXTENSION_LENGTH);
}

bool JarStripperProcessor::Accept(const char *filename, const u4 /*attr*/) {
const size_t filename_len = strlen(filename);
if (IsKotlinModule(filename, filename_len)) {
if (IsKotlinModule(filename, filename_len) ||
IsScalaTasty(filename, filename_len)) {
return true;
}
if (filename_len < CLASS_EXTENSION_LENGTH ||
Expand All @@ -129,7 +137,8 @@ void JarStripperProcessor::Process(const char *filename, const u4 /*attr*/,
if (verbose) {
fprintf(stderr, "INFO: StripClass: %s\n", filename);
}
if (IsModuleInfo(filename) || IsKotlinModule(filename, strlen(filename))) {
if (IsModuleInfo(filename) || IsKotlinModule(filename, strlen(filename)) ||
IsScalaTasty(filename, strlen(filename))) {
u1 *q = builder_->NewFile(filename, 0);
memcpy(q, data, size);
builder_->FinishFile(size, /* compress: */ false, /* compute_crc: */ true);
Expand Down
26 changes: 26 additions & 0 deletions third_party/ijar/test/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,31 @@ genrule(
tools = ["//third_party/ijar"],
)

java_binary(
name = "GenScalaTasty",
testonly = 1,
srcs = ["GenScalaTasty.java"],
main_class = "GenScalaTasty",
deps = ["//third_party:guava"],
)

genrule(
name = "scala_tasty",
testonly = 1,
outs = ["scala_tasty.jar"],
cmd = "$(location :GenScalaTasty) $@",
tools = [":GenScalaTasty"],
)

genrule(
name = "scala_tasty-interface",
testonly = 1,
srcs = [":scala_tasty.jar"],
outs = ["scala_tasty-interface.jar"],
cmd = "$(location //third_party/ijar) $< $@",
tools = ["//third_party/ijar"],
)

java_test(
name = "IjarTests",
size = "small",
Expand Down Expand Up @@ -295,6 +320,7 @@ java_test(
":liblocal_and_anonymous_lib.jar",
":local_and_anonymous-interface.jar",
":module_info-interface.jar",
":scala_tasty-interface.jar",
],
tags = ["zip"],
test_class = "IjarTests",
Expand Down
41 changes: 41 additions & 0 deletions third_party/ijar/test/GenScalaTasty.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright 2020 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.

import static java.nio.charset.StandardCharsets.UTF_8;

import com.google.common.io.ByteStreams;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.jar.JarOutputStream;
import java.util.zip.ZipEntry;

/** A generator for a jar file containing a .tasty file, and one real class file. */
public class GenScalaTasty {
public static void main(String[] args) throws IOException {
try (JarOutputStream jos = new JarOutputStream(Files.newOutputStream(Paths.get(args[0])))) {
addEntry(jos, "Bar.tasty");
jos.write("hello".getBytes(UTF_8));

addEntry(jos, "java/lang/String.class");
ByteStreams.copy(String.class.getResourceAsStream("/java/lang/String.class"), jos);
}
}

private static void addEntry(JarOutputStream jos, String name) throws IOException {
ZipEntry ze = new ZipEntry(name);
ze.setTime(0);
jos.putNextEntry(ze);
}
}
12 changes: 11 additions & 1 deletion third_party/ijar/test/IjarTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,9 @@ static Map<String, byte[]> readJar(String path) throws IOException {
Enumeration<JarEntry> entries = jf.entries();
while (entries.hasMoreElements()) {
JarEntry je = entries.nextElement();
if (!je.getName().endsWith(".class") && !je.getName().endsWith(".kotlin_module")) {
if (!je.getName().endsWith(".class")
&& !je.getName().endsWith(".kotlin_module")
&& !je.getName().endsWith(".tasty")) {
continue;
}
classes.put(je.getName(), ByteStreams.toByteArray(jf.getInputStream(je)));
Expand Down Expand Up @@ -291,6 +293,14 @@ public void kotlinModule() throws Exception {
assertThat(new String(lib.get("META-INF/bar.kotlin_module"), UTF_8)).isEqualTo("hello");
}

@Test
public void scalaTasty() throws Exception {
Map<String, byte[]> lib = readJar("third_party/ijar/test/scala_tasty-interface.jar");
assertThat(lib.keySet()).containsExactly("java/lang/String.class", "Bar.tasty");
// ijar passes scala tasty files through unmodified
assertThat(new String(lib.get("Bar.tasty"), UTF_8)).isEqualTo("hello");
}

@Test
public void testTargetLabel() throws Exception {
try (JarFile jf =
Expand Down

0 comments on commit 192b599

Please sign in to comment.