Skip to content

Commit

Permalink
Prevent ijar from stripping out .kotlin_module files, which are neede…
Browse files Browse the repository at this point in the history
…d for extension functions.

PiperOrigin-RevId: 198579700
  • Loading branch information
Googler authored and Copybara-Service committed May 30, 2018
1 parent 547b43e commit 088d8de
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 2 deletions.
25 changes: 24 additions & 1 deletion third_party/ijar/ijar.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ bool StripClass(u1 *&classdata_out, const u1 *classdata_in, size_t in_length);

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 *MANIFEST_DIR_PATH = "META-INF/";
const size_t MANIFEST_DIR_PATH_LENGTH = strlen(MANIFEST_DIR_PATH);
Expand Down Expand Up @@ -81,8 +83,29 @@ class JarStripperProcessor : public JarExtractorProcessor {
const char *injecting_rule_kind);
};

static bool StartsWith(const char *str, const size_t str_len,
const char *prefix, const size_t prefix_len) {
return str_len >= prefix_len && strncmp(str, prefix, prefix_len) == 0;
}

static bool EndsWith(const char *str, const size_t str_len, const char *suffix,
const size_t suffix_len) {
return str_len >= suffix_len &&
strcmp(str + str_len - suffix_len, suffix) == 0;
}

static bool IsKotlinModule(const char *filename, const size_t filename_len) {
return StartsWith(filename, filename_len, MANIFEST_DIR_PATH,
MANIFEST_DIR_PATH_LENGTH) &&
EndsWith(filename, filename_len, KOTLIN_MODULE_EXTENSION,
KOTLIN_MODULE_EXTENSION_LENGTH);
}

bool JarStripperProcessor::Accept(const char *filename, const u4 /*attr*/) {
const size_t filename_len = strlen(filename);
if (IsKotlinModule(filename, filename_len)) {
return true;
}
if (filename_len < CLASS_EXTENSION_LENGTH ||
strcmp(filename + filename_len - CLASS_EXTENSION_LENGTH,
CLASS_EXTENSION) != 0) {
Expand All @@ -106,7 +129,7 @@ void JarStripperProcessor::Process(const char *filename, const u4 /*attr*/,
if (verbose) {
fprintf(stderr, "INFO: StripClass: %s\n", filename);
}
if (IsModuleInfo(filename)) {
if (IsModuleInfo(filename) || IsKotlinModule(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 @@ -223,6 +223,31 @@ genrule(
tools = ["//third_party/ijar"],
)

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

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

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

java_test(
name = "IjarTests",
size = "small",
Expand All @@ -247,6 +272,7 @@ java_test(
":jar_with_manifest_nostrip",
":jar_without_manifest_nostrip",
":jar_without_manifest_nostrip_idempotence",
":kotlin_module-interface.jar",
":liblocal_and_anonymous_lib.jar",
":local_and_anonymous-interface.jar",
":module_info-interface.jar",
Expand Down
41 changes: 41 additions & 0 deletions third_party/ijar/test/GenKotlinModule.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright 2017 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 .kotlin-module file, and one real class file. */
public class GenKotlinModule {
public static void main(String[] args) throws IOException {
try (JarOutputStream jos = new JarOutputStream(Files.newOutputStream(Paths.get(args[0])))) {
addEntry(jos, "META-INF/bar.kotlin_module");
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);
}
}
11 changes: 10 additions & 1 deletion third_party/ijar/test/IjarTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ 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")) {
if (!je.getName().endsWith(".class") && !je.getName().endsWith(".kotlin_module")) {
continue;
}
classes.put(je.getName(), ByteStreams.toByteArray(jf.getInputStream(je)));
Expand Down Expand Up @@ -284,6 +284,15 @@ public void moduleInfo() throws Exception {
assertThat(new String(lib.get("foo/module-info.class"), UTF_8)).isEqualTo("goodbye");
}

@Test
public void kotlinModule() throws Exception {
Map<String, byte[]> lib = readJar("third_party/ijar/test/kotlin_module-interface.jar");
assertThat(lib.keySet())
.containsExactly("java/lang/String.class", "META-INF/bar.kotlin_module");
// ijar passes kotlin modules through unmodified
assertThat(new String(lib.get("META-INF/bar.kotlin_module"), UTF_8)).isEqualTo("hello");
}

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

0 comments on commit 088d8de

Please sign in to comment.