Add pkl project package --install to local cache (#1795)

This commit is contained in:
Jen Basch
2026-07-30 07:26:21 +00:00
committed by GitHub
parent 8ad5759630
commit 2ca2aaf9ec
12 changed files with 215 additions and 11 deletions
@@ -56,4 +56,7 @@ public interface PackageResolver extends Closeable {
boolean hasElement(PackageAssetUri uri, @Nullable Checksums checksums)
throws IOException, SecurityManagerException;
Pair<Path, Path> writePackage(PackageUri packageUri, Path metadataFile, Path zipFile)
throws IOException;
}
@@ -317,6 +317,11 @@ final class PackageResolvers {
throw new UnsupportedOperationException();
}
@Override
public Pair<Path, Path> writePackage(PackageUri packageUri, Path metadataFile, Path zipFile) {
throw new UnsupportedOperationException();
}
@Override
public byte[] getBytes(
PackageAssetUri uri, boolean allowDirectories, @Nullable Checksums checksums)
@@ -428,6 +433,7 @@ final class PackageResolvers {
private final Path tmpDir;
// if updated, also update CliProjectPackagerTest.`install package to local cache`
private static final String CACHE_DIR_PREFIX = "package-2";
@GuardedBy("lock")
@@ -503,12 +509,16 @@ final class PackageResolvers {
}
}
private Path doGetMetadataPath(PackageUri packageUri) {
var metadataFileName = getLastSegmentName(packageUri) + ".json";
var metadataRelativePath = getRelativePath(packageUri).resolve(metadataFileName);
return cacheDir.resolve(metadataRelativePath);
}
private Path getMetadataPath(
PackageUri packageUri, URI requestUri, @Nullable Checksums checksums)
throws IOException, SecurityManagerException {
var metadataFileName = getLastSegmentName(packageUri) + ".json";
var metadataRelativePath = getRelativePath(packageUri).resolve(metadataFileName);
var cachePath = cacheDir.resolve(metadataRelativePath);
var cachePath = doGetMetadataPath(packageUri);
if (Files.exists(cachePath)) {
return cachePath;
}
@@ -556,11 +566,15 @@ final class PackageResolvers {
return metadata;
}
private Path getZipFilePath(PackageUri packageUri, DependencyMetadata dependencyMetadata)
throws IOException, SecurityManagerException {
private Path doGetZipFilePath(PackageUri packageUri) {
var packageZipName = getLastSegmentName(packageUri) + ".zip";
var relativePath = getRelativePath(packageUri).resolve(packageZipName);
var cachePath = cacheDir.resolve(relativePath);
return cacheDir.resolve(relativePath);
}
private Path getZipFilePath(PackageUri packageUri, DependencyMetadata dependencyMetadata)
throws IOException, SecurityManagerException {
var cachePath = doGetZipFilePath(packageUri);
if (Files.exists(cachePath)) {
return cachePath;
}
@@ -684,5 +698,28 @@ final class PackageResolvers {
fileSystems.clear();
}
}
@Override
public Pair<Path, Path> writePackage(PackageUri packageUri, Path metadataFile, Path zipFile)
throws IOException {
Files.createDirectories(tmpDir);
var tmpSubpath = IoUtils.encodePath(packageUri.toString().replace("/", "-"));
return Pair.of(
writePackagePart(metadataFile, doGetMetadataPath(packageUri), tmpSubpath, ".json"),
writePackagePart(zipFile, doGetZipFilePath(packageUri), tmpSubpath, ".zip"));
}
private Path writePackagePart(Path srcFile, Path cacheFile, String tmpSubpath, String suffix)
throws IOException {
var tmpFile = Files.createTempFile(tmpDir, tmpSubpath, suffix);
Files.createDirectories(cacheFile.getParent());
Files.copy(srcFile, tmpFile, StandardCopyOption.REPLACE_EXISTING);
Files.move(
tmpFile, cacheFile, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE);
if (!IoUtils.isWindows()) {
Files.setPosixFilePermissions(cacheFile, FILE_PERMISSIONS);
}
return cacheFile;
}
}
}
@@ -37,6 +37,7 @@ import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.graalvm.collections.EconomicMap;
import org.jspecify.annotations.Nullable;
import org.pkl.core.PklBugException;
import org.pkl.core.PklException;
import org.pkl.core.SecurityManager;
@@ -100,6 +101,7 @@ public final class ProjectPackager {
private final boolean color;
private final SecurityManager securityManager;
private final PackageResolver packageResolver;
private final @Nullable PackageResolver packageWriteResolver;
private final boolean skipPublishCheck;
private final Writer outputWriter;
@@ -112,6 +114,8 @@ public final class ProjectPackager {
SecurityManager securityManager,
HttpClient httpClient,
boolean skipPublishCheck,
boolean install,
@Nullable Path cacheDir,
Writer outputWriter) {
this.projects = projects;
this.workingDir = workingDir;
@@ -123,6 +127,14 @@ public final class ProjectPackager {
this.packageResolver = PackageResolver.getInstance(securityManager, httpClient, null);
this.skipPublishCheck = skipPublishCheck;
this.outputWriter = outputWriter;
if (install) {
if (cacheDir == null) {
throw new PklException(ErrorMessages.create("cannotInstallPackageWithNoCache"));
}
packageWriteResolver = PackageResolver.getInstance(securityManager, httpClient, cacheDir);
} else {
packageWriteResolver = null;
}
}
private void writeLine(String line) throws IOException {
@@ -137,6 +149,12 @@ public final class ProjectPackager {
writeLine(IoUtils.relativize(packageResult.metadataChecksumFile(), workingDir).toString());
writeLine(IoUtils.relativize(packageResult.zipFile(), workingDir).toString());
writeLine(IoUtils.relativize(packageResult.zipChecksumFile(), workingDir).toString());
if (packageResult.cacheMetadataFile() != null) {
writeLine(packageResult.cacheMetadataFile().normalize().toString());
}
if (packageResult.cacheZipFile() != null) {
writeLine(packageResult.cacheZipFile().normalize().toString());
}
outputWriter.flush();
}
}
@@ -174,9 +192,29 @@ public final class ProjectPackager {
if (!skipPublishCheck) {
checkAlreadyPublishedPackage(pkg, metadataFileChecksum);
}
var result =
new PackageResult(
metadataFile, metadataChecksumFile, zipFile, zipChecksumFile, metadataFileChecksum);
PackageResult result;
if (packageWriteResolver != null) {
var cachePaths = packageWriteResolver.writePackage(pkg.uri(), metadataFile, zipFile);
result =
new PackageResult(
metadataFile,
metadataChecksumFile,
zipFile,
zipChecksumFile,
metadataFileChecksum,
cachePaths.getFirst(),
cachePaths.getSecond());
} else {
result =
new PackageResult(
metadataFile,
metadataChecksumFile,
zipFile,
zipChecksumFile,
metadataFileChecksum,
null,
null);
}
packageResults.put(pkg.uri(), result);
return result;
}
@@ -457,7 +495,9 @@ public final class ProjectPackager {
Path zipChecksumFile,
Path metadataFile,
Path metadataChecksumFile,
String metadataChecksum) {
String metadataChecksum,
@Nullable Path cacheMetadataFile,
@Nullable Path cacheZipFile) {
/**
* @deprecated As of 0.28.0, replaced by {@link #zipFile()}.
*/
@@ -1205,3 +1205,6 @@ Redirected to: `{1}`
invalidReferenceTypeAnnotationWithConstraint=\
`Reference` referent type argument may not include type constraints.
cannotInstallPackageWithNoCache=\
Cannot install package to module cache dir when module cache is disabled.