|
1 | 1 | /*
|
2 |
| - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. |
| 2 | + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. |
3 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
4 | 4 | *
|
5 | 5 | * The Universal Permissive License (UPL), Version 1.0
|
|
40 | 40 | */
|
41 | 41 | package com.oracle.graal.python.resources;
|
42 | 42 |
|
| 43 | +import java.io.File; |
43 | 44 | import java.io.IOException;
|
44 | 45 | import java.io.InputStream;
|
45 | 46 | import java.nio.file.InvalidPathException;
|
46 | 47 | import java.nio.file.Path;
|
| 48 | +import java.util.ArrayList; |
| 49 | +import java.util.Collections; |
47 | 50 | import java.util.List;
|
| 51 | +import java.util.function.Predicate; |
| 52 | +import java.util.regex.Pattern; |
| 53 | +import java.util.regex.PatternSyntaxException; |
48 | 54 |
|
49 | 55 | import com.oracle.truffle.api.CompilerDirectives;
|
50 | 56 | import com.oracle.truffle.api.InternalResource;
|
@@ -100,20 +106,106 @@ public final class PythonResource implements InternalResource {
|
100 | 106 | public void unpackFiles(Env env, Path targetDirectory) throws IOException {
|
101 | 107 | OS os = env.getOS();
|
102 | 108 | Path osArch = Path.of(os.toString()).resolve(env.getCPUArchitecture().toString());
|
| 109 | + ResourcesFilter filter = new ResourcesFilter(); |
103 | 110 | if (os.equals(OS.WINDOWS)) {
|
104 |
| - env.unpackResourceFiles(BASE_PATH.resolve(LIBPYTHON_FILES), targetDirectory.resolve("Lib"), BASE_PATH.resolve(LIBPYTHON)); |
105 |
| - env.unpackResourceFiles(BASE_PATH.resolve(LIBGRAALPY_FILES), targetDirectory.resolve("lib-graalpython"), BASE_PATH.resolve(LIBGRAALPY)); |
106 |
| - env.unpackResourceFiles(BASE_PATH.resolve(INCLUDE_FILES), targetDirectory.resolve("Include"), BASE_PATH.resolve(INCLUDE)); |
| 111 | + env.unpackResourceFiles(BASE_PATH.resolve(LIBPYTHON_FILES), targetDirectory.resolve("Lib"), BASE_PATH.resolve(LIBPYTHON), filter); |
| 112 | + env.unpackResourceFiles(BASE_PATH.resolve(LIBGRAALPY_FILES), targetDirectory.resolve("lib-graalpython"), BASE_PATH.resolve(LIBGRAALPY), filter); |
| 113 | + env.unpackResourceFiles(BASE_PATH.resolve(INCLUDE_FILES), targetDirectory.resolve("Include"), BASE_PATH.resolve(INCLUDE), filter); |
107 | 114 | } else {
|
108 | 115 | String pythonMajMin = "python" + PYTHON_MAJOR + "." + PYTHON_MINOR;
|
109 |
| - env.unpackResourceFiles(BASE_PATH.resolve(LIBPYTHON_FILES), targetDirectory.resolve("lib").resolve(pythonMajMin), BASE_PATH.resolve(LIBPYTHON)); |
110 |
| - env.unpackResourceFiles(BASE_PATH.resolve(LIBGRAALPY_FILES), targetDirectory.resolve("lib").resolve("graalpy" + GRAALVM_MAJOR + "." + GRAALVM_MINOR), BASE_PATH.resolve(LIBGRAALPY)); |
111 |
| - env.unpackResourceFiles(BASE_PATH.resolve(INCLUDE_FILES), targetDirectory.resolve("include").resolve(pythonMajMin), BASE_PATH.resolve(INCLUDE)); |
| 116 | + env.unpackResourceFiles(BASE_PATH.resolve(LIBPYTHON_FILES), targetDirectory.resolve("lib").resolve(pythonMajMin), BASE_PATH.resolve(LIBPYTHON), filter); |
| 117 | + env.unpackResourceFiles(BASE_PATH.resolve(LIBGRAALPY_FILES), targetDirectory.resolve("lib").resolve("graalpy" + GRAALVM_MAJOR + "." + GRAALVM_MINOR), BASE_PATH.resolve(LIBGRAALPY), |
| 118 | + filter); |
| 119 | + env.unpackResourceFiles(BASE_PATH.resolve(INCLUDE_FILES), targetDirectory.resolve("include").resolve(pythonMajMin), BASE_PATH.resolve(INCLUDE), filter); |
112 | 120 | }
|
113 | 121 | // ni files are in the same place on all platforms
|
114 |
| - env.unpackResourceFiles(BASE_PATH.resolve(NI_FILES), targetDirectory, BASE_PATH); |
| 122 | + env.unpackResourceFiles(BASE_PATH.resolve(NI_FILES), targetDirectory, BASE_PATH, filter); |
115 | 123 | // native files already have the correct structure
|
116 |
| - env.unpackResourceFiles(BASE_PATH.resolve(osArch).resolve(NATIVE_FILES), targetDirectory, BASE_PATH.resolve(osArch)); |
| 124 | + env.unpackResourceFiles(BASE_PATH.resolve(osArch).resolve(NATIVE_FILES), targetDirectory, BASE_PATH.resolve(osArch), filter); |
| 125 | + |
| 126 | + if (filter.log) { |
| 127 | + System.out.println("unpacked python resources:"); |
| 128 | + System.out.println("include pattern: '" + filter.include + "'"); |
| 129 | + System.out.println("exclude pattern: '" + filter.exclude + "'"); |
| 130 | + listFiles("included files:", filter.included); |
| 131 | + listFiles("excluded files:", filter.excluded); |
| 132 | + } |
| 133 | + } |
| 134 | + |
| 135 | + private static void listFiles(String header, List<String> l) { |
| 136 | + if (!l.isEmpty()) { |
| 137 | + Collections.sort(l); |
| 138 | + System.out.println(header); |
| 139 | + for (String s : l) { |
| 140 | + System.out.println("\t" + s); |
| 141 | + } |
| 142 | + } |
| 143 | + } |
| 144 | + |
| 145 | + private static class ResourcesFilter implements Predicate<Path> { |
| 146 | + |
| 147 | + private final boolean log; |
| 148 | + private final Pattern includePattern; |
| 149 | + private final Pattern excludePattern; |
| 150 | + private final String exclude; |
| 151 | + private final String include; |
| 152 | + private final List<String> excluded; |
| 153 | + private final List<String> included; |
| 154 | + private static final String INCLUDE_PROP = "org.graalvm.python.resources.include"; |
| 155 | + private static final String EXCLUDE_PROP = "org.graalvm.python.resources.exclude"; |
| 156 | + |
| 157 | + private static final String LOG_PROP = "org.graalvm.python.resources.exclude"; |
| 158 | + |
| 159 | + private ResourcesFilter() { |
| 160 | + include = getProperty(INCLUDE_PROP); |
| 161 | + exclude = getProperty(EXCLUDE_PROP); |
| 162 | + log = Boolean.parseBoolean(getProperty(LOG_PROP)); |
| 163 | + includePattern = include != null ? compile(include, INCLUDE_PROP) : null; |
| 164 | + excludePattern = exclude != null ? compile(exclude, EXCLUDE_PROP) : null; |
| 165 | + included = log ? new ArrayList<>() : null; |
| 166 | + excluded = log ? new ArrayList<>() : null; |
| 167 | + } |
| 168 | + |
| 169 | + private static Pattern compile(String re, String property) { |
| 170 | + try { |
| 171 | + return Pattern.compile(re); |
| 172 | + } catch (PatternSyntaxException pse) { |
| 173 | + throw new IllegalArgumentException("could not compile regex pattern '" + re + "' provided by system property '" + property + "'", pse); |
| 174 | + } |
| 175 | + } |
| 176 | + |
| 177 | + @Override |
| 178 | + public boolean test(Path path) { |
| 179 | + String absolutePath = path.toAbsolutePath().toString(); |
| 180 | + if (File.separator.equals("\\")) { |
| 181 | + absolutePath = absolutePath.replaceAll("\\\\", "/"); |
| 182 | + } |
| 183 | + if ((includePattern != null && !includePattern.matcher(absolutePath).matches()) || |
| 184 | + (excludePattern != null && excludePattern.matcher(absolutePath).matches())) { |
| 185 | + if (log) { |
| 186 | + excluded.add(absolutePath); |
| 187 | + } |
| 188 | + return false; |
| 189 | + } else { |
| 190 | + if (log) { |
| 191 | + included.add(absolutePath); |
| 192 | + } |
| 193 | + return true; |
| 194 | + } |
| 195 | + } |
| 196 | + |
| 197 | + private static String getProperty(String prop) { |
| 198 | + String s = System.getProperty(prop); |
| 199 | + if (s != null) { |
| 200 | + if (s.isEmpty()) { |
| 201 | + s = null; |
| 202 | + } else if (s.startsWith("\"") && s.endsWith("\"")) { |
| 203 | + // native-gradle-plugin sends system properties wrapped in " |
| 204 | + s = s.substring(1, s.length() - 1); |
| 205 | + } |
| 206 | + } |
| 207 | + return s; |
| 208 | + } |
117 | 209 | }
|
118 | 210 |
|
119 | 211 | @Override
|
|
0 commit comments