Skip to content

Commit

Permalink
Consolidate all hashing and caching into a single properties file ins…
Browse files Browse the repository at this point in the history
…tead of multiple files
  • Loading branch information
gbevin committed Jul 19, 2024
1 parent 604f5ba commit 9614bd8
Show file tree
Hide file tree
Showing 8 changed files with 330 additions and 231 deletions.
Binary file modified lib/bld/bld-wrapper.jar
Binary file not shown.
70 changes: 5 additions & 65 deletions src/main/java/rife/bld/BaseProject.java
Original file line number Diff line number Diff line change
Expand Up @@ -1595,83 +1595,23 @@ public void executeAutoDownloadPurge()
purge();
}

private static final String BLD_BUILD_HASH = "bld-build.hash";

private void performAutoDownloadPurge() {
// verify and update the fingerprint hash file,
// don't download and purge if the hash is identical
var hash_file = new File(libBldDirectory(), BLD_BUILD_HASH);
var hash = createHash();
if (validateHash(hash_file, hash)) {
var resolution = new VersionResolution(properties());
var cache = new BldCache(libBldDirectory(), resolution);
cache.fingerprintDependencies(repositories(), dependencies(), downloadSources(), downloadJavadoc());
if (cache.isDependenciesHashValid()) {
return;
}

try {
executeAutoDownloadPurge();

writeHash(hash_file, hash);
cache.writeCache();
} catch (Exception e) {
throw new RuntimeException(e);
}
}

private String createHash() {
var resolution = new VersionResolution(properties());
var finger_print = new StringBuilder();
finger_print.append(String.join("\n", resolution.versionOverrides().entrySet().stream().map(e -> e.getKey() + ":" + e.getValue()).toList()));
for (var repository : repositories()) {
finger_print.append(repository.toString());
finger_print.append('\n');
}
for (var entry : dependencies().entrySet()) {
finger_print.append(entry.getKey());
finger_print.append('\n');
if (entry.getValue() != null) {
for (var dependency : entry.getValue()) {
finger_print.append(dependency.toString());
finger_print.append('\n');
}
}
}
finger_print.append(downloadSources())
.append('\n')
.append(downloadJavadoc())
.append('\n');

try {
var digest = MessageDigest.getInstance("SHA-1");
digest.update(finger_print.toString().getBytes(StandardCharsets.UTF_8));
return StringUtils.encodeHexLower(digest.digest());
} catch (NoSuchAlgorithmException e) {
// should not happen
throw new RuntimeException(e);
}
}

private boolean validateHash(File hashFile, String hash) {
try {
if (hashFile.exists()) {
var current_hash = FileUtils.readString(hashFile);
if (current_hash.equals(hash)) {
return true;
}
hashFile.delete();
}
return false;
} catch (FileUtilsErrorException e) {
throw new RuntimeException(e);
}
}

private void writeHash(File hashFile, String hash) {
try {
hashFile.getParentFile().mkdirs();
FileUtils.writeString(hash, hashFile);
} catch (FileUtilsErrorException e) {
throw new RuntimeException(e);
}
}

@Override
public int execute(String[] arguments) {
if (!offline() &&
Expand Down
200 changes: 200 additions & 0 deletions src/main/java/rife/bld/BldCache.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
/*
* Copyright 2001-2023 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
*/
package rife.bld;

import rife.bld.dependencies.DependencyScopes;
import rife.bld.dependencies.Repository;
import rife.bld.dependencies.VersionResolution;
import rife.bld.wrapper.Wrapper;
import rife.tools.StringUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Collection;
import java.util.List;
import java.util.Properties;

/**
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @since 2.0
*/
public class BldCache {
public static final String BLD_CACHE = "bld.cache";

private static final String PROPERTY_SUFFIX_HASH = ".hash";
private static final String PROPERTY_SUFFIX_LOCAL = ".local";

public static final String WRAPPER_PROPERTIES_HASH = Wrapper.WRAPPER_PROPERTIES + PROPERTY_SUFFIX_HASH;
public static final String BLD_BUILD_HASH = "bld-build" + PROPERTY_SUFFIX_HASH;

private static final String PROPERTY_EXTENSIONS_PREFIX = "bld.extensions";
private static final String PROPERTY_EXTENSIONS_HASH = PROPERTY_EXTENSIONS_PREFIX + PROPERTY_SUFFIX_HASH;
private static final String PROPERTY_EXTENSIONS_LOCAL = PROPERTY_EXTENSIONS_PREFIX + PROPERTY_SUFFIX_LOCAL;

private static final String PROPERTY_DEPENDENCIES_PREFIX = "bld.dependencies";
private static final String PROPERTY_DEPENDENCIES_HASH = PROPERTY_DEPENDENCIES_PREFIX + PROPERTY_SUFFIX_HASH;

private final File hashFile_;
private final Properties hashProperties_ = new Properties();
private final VersionResolution resolution_;
private String extensionsHash_;
private String dependenciesHash_;

public BldCache(File bldLibDir, VersionResolution resolution) {
hashFile_ = new File(bldLibDir, BLD_CACHE);
resolution_ = resolution;

new File(bldLibDir, WRAPPER_PROPERTIES_HASH).delete();
new File(bldLibDir, BLD_BUILD_HASH).delete();

if (hashFile_.exists()) {
try {
hashProperties_.load(new FileInputStream(hashFile_));
} catch (IOException e) {
// no-op, we'll store a new properties file when we're writing the cache
}
}
}

public void fingerprintExtensions(Collection<String> repositories, Collection<String> extensions, boolean downloadSources, boolean downloadJavadoc) {
try {
var overrides_fp = String.join("\n", resolution_.versionOverrides().entrySet().stream().map(e -> e.getKey() + ":" + e.getValue()).toList());
var repositories_fp = String.join("\n", repositories);
var extensions_fp = String.join("\n", extensions);
var fingerprint = overrides_fp + "\n" + repositories_fp + "\n" + extensions_fp + "\n" + downloadSources + "\n" + downloadJavadoc;
var digest = MessageDigest.getInstance("SHA-1");
digest.update(fingerprint.getBytes(StandardCharsets.UTF_8));

extensionsHash_ = StringUtils.encodeHexLower(digest.digest());
} catch (NoSuchAlgorithmException e) {
// should not happen
throw new RuntimeException(e);
}
}

public void fingerprintDependencies(List<Repository> repositories, DependencyScopes dependencies, boolean downloadSources, boolean downloadJavadoc) {
var finger_print = new StringBuilder();
finger_print.append(String.join("\n", resolution_.versionOverrides().entrySet().stream().map(e -> e.getKey() + ":" + e.getValue()).toList()));
for (var repository : repositories) {
finger_print.append(repository.toString());
finger_print.append('\n');
}
for (var entry : dependencies.entrySet()) {
finger_print.append(entry.getKey());
finger_print.append('\n');
if (entry.getValue() != null) {
for (var dependency : entry.getValue()) {
finger_print.append(dependency.toString());
finger_print.append('\n');
}
}
}
finger_print.append(downloadSources)
.append('\n')
.append(downloadJavadoc)
.append('\n');

try {
var digest = MessageDigest.getInstance("SHA-1");
digest.update(finger_print.toString().getBytes(StandardCharsets.UTF_8));
dependenciesHash_ = StringUtils.encodeHexLower(digest.digest());
} catch (NoSuchAlgorithmException e) {
// should not happen
throw new RuntimeException(e);
}
}

public boolean isExtensionHashValid() {
return validateExtensionsHash(extensionsHash_);
}

private boolean validateExtensionsHash(String hash) {
if (!hashFile_.exists() || hashProperties_.isEmpty()) {
return false;
}

if (!hash.equals(hashProperties_.getProperty(PROPERTY_EXTENSIONS_HASH))) {
return false;
}

var local_files = hashProperties_.getProperty(PROPERTY_EXTENSIONS_LOCAL);
if (local_files != null && !local_files.isEmpty()) {
var lines = StringUtils.split(local_files, "\n");
if (!lines.isEmpty()) {
// other lines are last modified timestamps of local files
// that were dependency artifacts
while (!lines.isEmpty()) {
var line = lines.get(0);
var parts = line.split(":", 2);
// verify that the local file has the same modified timestamp still
if (parts.length == 2) {
var file = new File(parts[1]);
if (!file.exists() || !file.canRead() || file.lastModified() != Long.parseLong(parts[0])) {
break;
}
} else {
break;
}
lines.remove(0);
}

// there were no invalid lines, so the hash file contents are valid
return lines.isEmpty();
}
}

return true;
}

public boolean isDependenciesHashValid() {
return validateDependenciesHash(dependenciesHash_);
}

private boolean validateDependenciesHash(String hash) {
if (!hashFile_.exists() || hashProperties_.isEmpty()) {
return false;
}

return hash.equals(hashProperties_.getProperty(PROPERTY_DEPENDENCIES_HASH));
}

public void writeCache() {
writeCache(null);
}

public void writeCache(List<File> extensionsLocalArtifacts) {
try {
if (extensionsHash_ != null) {
hashProperties_.put(PROPERTY_EXTENSIONS_HASH, extensionsHash_);
}

if (extensionsLocalArtifacts != null) {
var extensions_local = new StringBuilder();
for (var file : extensionsLocalArtifacts) {
if (file.exists() && file.canRead()) {
extensions_local.append("\n").append(file.lastModified()).append(':').append(file.getAbsolutePath());
}
}
hashProperties_.put(PROPERTY_EXTENSIONS_LOCAL, extensions_local.toString());
}

if (dependenciesHash_ != null) {
hashProperties_.put(PROPERTY_DEPENDENCIES_HASH, dependenciesHash_);
}

hashFile_.getParentFile().mkdirs();
hashProperties_.store(new FileOutputStream(hashFile_), null);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

10 changes: 9 additions & 1 deletion src/main/java/rife/bld/BuildExecutor.java
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,7 @@ public boolean executeCommand(String command)

// try to find a match for the provided command amongst
// the ones that are known
var matched = false;
if (definition == null) {
// try to find starting matching options
var matches = new ArrayList<>(buildCommands().keySet().stream()
Expand All @@ -463,7 +464,7 @@ public boolean executeCommand(String command)
// only proceed if exactly one match was found
if (matches.size() == 1) {
matched_command = matches.get(0);
System.out.println("Executing matched command: " + matched_command);
matched = true;
definition = buildCommands().get(matched_command);
}
}
Expand All @@ -473,6 +474,13 @@ public boolean executeCommand(String command)
currentCommandName_.set(matched_command);
currentCommandDefinition_.set(definition);
try {
if (matched) {
System.out.println("Executing matched command: " + matched_command);
}
else {
System.out.println("Executing command: " + currentCommandName_);
}

definition.execute();
} catch (ExitStatusException e) {
exitStatus(e.getExitStatus());
Expand Down
12 changes: 6 additions & 6 deletions src/main/java/rife/bld/wrapper/Wrapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,23 +44,23 @@ private enum LaunchMode {
public static final String OFFLINE_ARGUMENT = "--offline";
public static final String HELP_COMMAND = "help";

public static final String WRAPPER_PREFIX = "bld-wrapper";
public static final String WRAPPER_PROPERTIES = WRAPPER_PREFIX + ".properties";

static final String MAVEN_CENTRAL = "https://repo1.maven.org/maven2/";
static final String SONATYPE_SNAPSHOTS = "https://s01.oss.sonatype.org/content/repositories/snapshots/";
static final String DOWNLOAD_LOCATION = MAVEN_CENTRAL + "com/uwyn/rife2/bld/${version}/";
static final String DOWNLOAD_LOCATION_SNAPSHOT = SONATYPE_SNAPSHOTS + "com/uwyn/rife2/bld/${version}/";
static final String BLD_CACHE = "bld.cache";
static final String BLD_FILENAME = "bld-${version}.jar";
static final String BLD_SOURCES_FILENAME = "bld-${version}-sources.jar";
static final String BLD_VERSION = "BLD_VERSION";
static final String BLD_BUILD_HASH = "bld-build.hash";
static final String WRAPPER_PREFIX = "bld-wrapper";
static final String WRAPPER_PROPERTIES = WRAPPER_PREFIX + ".properties";
static final String WRAPPER_JAR = WRAPPER_PREFIX + ".jar";
static final String BLD_PROPERTY_VERSION = "bld.version";
static final String RIFE2_PROPERTY_DOWNLOAD_LOCATION = "rife2.downloadLocation";
static final String BLD_PROPERTY_DOWNLOAD_LOCATION = "bld.downloadLocation";
static final String PROPERTY_REPOSITORIES = "bld.repositories";
static final String PROPERTY_EXTENSION_PREFIX = "bld.extension";
static final String PROPERTY_EXTENSIONS = "bld.extensions";
static final String PROPERTY_DOWNLOAD_EXTENSION_SOURCES = "bld.downloadExtensionSources";
static final String PROPERTY_DOWNLOAD_EXTENSION_JAVADOC = "bld.downloadExtensionJavadoc";
static final String PROPERTY_SOURCE_DIRECTORIES = "bld.sourceDirectories";
Expand Down Expand Up @@ -637,9 +637,9 @@ private void resolveExtensions() {

try {
var resolver_class = classloader_.loadClass("rife.bld.wrapper.WrapperExtensionResolver");
var constructor = resolver_class.getConstructor(File.class, File.class, File.class, Properties.class, Properties.class, Collection.class, Collection.class, boolean.class, boolean.class);
var constructor = resolver_class.getConstructor(File.class, File.class, Properties.class, Properties.class, Collection.class, Collection.class, boolean.class, boolean.class);
var update_method = resolver_class.getMethod("updateExtensions");
var resolver = constructor.newInstance(currentDir_, new File(wrapperPropertiesFile_.getAbsolutePath() + ".hash"), libBldDirectory(),
var resolver = constructor.newInstance(currentDir_, libBldDirectory(),
jvmProperties_, wrapperProperties_,
repositories_, extensions_,
downloadExtensionSources_, downloadExtensionJavadoc_);
Expand Down
Loading

0 comments on commit 9614bd8

Please sign in to comment.