Skip to content

Commit

Permalink
Allow setting file timestamps from plugins (#1818)
Browse files Browse the repository at this point in the history
* Allow setting file timestamps from plugins (#1608) (#1782)

* Allow setting file timestamps from plugins (#1608)
* Addressed comment related to unnecessary extraDirectories modificationTimes configuration
* Addressed remaining comments

* Fix integration tests / Clean up

* Fix integration test

* Handle invalid config value

* Refactor

* Refactor

* Add tests

* Refactor and add tests

* Take mod time into account when retrieving local application cache

* Fix Javadoc

* Update error messages

* Add Gradle integration tests

* Clean up

* Remove KEEP_ORIGINAL

* Rename methods and variables

* Rename things / minor updates

* Restore LayerEntriesSelector to consider target modification time too

* Fix test

* Pass correct argument

* format

* Fix Javadoc
  • Loading branch information
chanseokoh authored Jul 30, 2019
1 parent b1af34b commit 62c9cab
Show file tree
Hide file tree
Showing 44 changed files with 660 additions and 177 deletions.
2 changes: 1 addition & 1 deletion jib-core/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ All notable changes to this project will be documented in this file.

### Added

- Overloads for `LayerConfiguration#addEntryRecursive` that take providers allowing for setting file permissions/file modification timestamps on a per-file basis ([#1607](https://github.com/GoogleContainerTools/jib/issues/1607))
- Overloads for `LayerConfiguration#addEntryRecursive` that take providers to set file permissions and file modification time on a per-file basis ([#1607](https://github.com/GoogleContainerTools/jib/issues/1607))

### Changed

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,15 @@
import java.nio.file.NoSuchFileException;
import java.nio.file.NotDirectoryException;
import java.nio.file.Path;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.BiFunction;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
Expand Down Expand Up @@ -175,6 +177,8 @@ public static JavaContainerBuilder from(RegistryImage registryImage) {
private RelativeUnixPath dependenciesDestination = RelativeUnixPath.get("libs");
private RelativeUnixPath othersDestination = RelativeUnixPath.get("classpath");
@Nullable private String mainClass;
private BiFunction<Path, AbsoluteUnixPath, Instant> modificationTimeProvider =
LayerConfiguration.DEFAULT_MODIFICATION_TIME_PROVIDER;

private JavaContainerBuilder(JibContainerBuilder jibContainerBuilder) {
this.jibContainerBuilder = jibContainerBuilder;
Expand Down Expand Up @@ -484,6 +488,19 @@ public JavaContainerBuilder setMainClass(String mainClass) {
return this;
}

/**
* Sets the modification time provider for container files.
*
* @param modificationTimeProvider a provider that takes a source path and destination path on the
* container and returns the file modification time that should be set for that path
* @return this
*/
public JavaContainerBuilder setModificationTimeProvider(
BiFunction<Path, AbsoluteUnixPath, Instant> modificationTimeProvider) {
this.modificationTimeProvider = modificationTimeProvider;
return this;
}

/**
* Returns a new {@link JibContainerBuilder} using the parameters specified on the {@link
* JavaContainerBuilder}.
Expand Down Expand Up @@ -643,7 +660,8 @@ private void addFileToLayer(
if (!layerBuilders.containsKey(layerType)) {
layerBuilders.put(layerType, LayerConfiguration.builder());
}
layerBuilders.get(layerType).addEntry(sourceFile, pathInContainer);
Instant modificationTime = modificationTimeProvider.apply(sourceFile, pathInContainer);
layerBuilders.get(layerType).addEntry(sourceFile, pathInContainer, modificationTime);
}

private void addDirectoryContentsToLayer(
Expand All @@ -665,7 +683,8 @@ private void addDirectoryContentsToLayer(
path -> {
AbsoluteUnixPath pathOnContainer =
basePathInContainer.resolve(sourceRoot.relativize(path));
builder.addEntry(path, pathOnContainer);
Instant modificationTime = modificationTimeProvider.apply(path, pathOnContainer);
builder.addEntry(path, pathOnContainer, modificationTime);
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -99,23 +99,40 @@ public Builder addEntry(Path sourceFile, AbsoluteUnixPath pathInContainer) {
*/
public Builder addEntry(
Path sourceFile, AbsoluteUnixPath pathInContainer, FilePermissions permissions) {
return addEntry(sourceFile, pathInContainer, permissions, DEFAULT_MODIFICATION_TIME);
}

/**
* Adds an entry to the layer with the given file modification time. Only adds the single source
* file to the exact path in the container file system. See {@link Builder#addEntry(Path,
* AbsoluteUnixPath)} for more information.
*
* @param sourceFile the source file to add to the layer
* @param pathInContainer the path in the container file system corresponding to the {@code
* sourceFile}
* @param modificationTime the file modification time
* @return this
* @see Builder#addEntry(Path, AbsoluteUnixPath)
*/
public Builder addEntry(
Path sourceFile, AbsoluteUnixPath pathInContainer, Instant modificationTime) {
return addEntry(
sourceFile,
pathInContainer,
permissions,
DEFAULT_MODIFIED_TIME_PROVIDER.apply(sourceFile, pathInContainer));
DEFAULT_FILE_PERMISSIONS_PROVIDER.apply(sourceFile, pathInContainer),
modificationTime);
}

/**
* Adds an entry to the layer with the given permissions. Only adds the single source file to
* the exact path in the container file system. See {@link Builder#addEntry(Path,
* AbsoluteUnixPath)} for more information.
* Adds an entry to the layer with the given permissions and file modification time. Only adds
* the single source file to the exact path in the container file system. See {@link
* Builder#addEntry(Path, AbsoluteUnixPath)} for more information.
*
* @param sourceFile the source file to add to the layer
* @param pathInContainer the path in the container file system corresponding to the {@code
* sourceFile}
* @param permissions the file permissions on the container
* @param lastModifiedTime the file modification timestamp
* @param modificationTime the file modification time
* @return this
* @see Builder#addEntry(Path, AbsoluteUnixPath)
* @see FilePermissions#DEFAULT_FILE_PERMISSIONS
Expand All @@ -125,8 +142,8 @@ public Builder addEntry(
Path sourceFile,
AbsoluteUnixPath pathInContainer,
FilePermissions permissions,
Instant lastModifiedTime) {
return addEntry(new LayerEntry(sourceFile, pathInContainer, permissions, lastModifiedTime));
Instant modificationTime) {
return addEntry(new LayerEntry(sourceFile, pathInContainer, permissions, modificationTime));
}

/**
Expand Down Expand Up @@ -167,7 +184,7 @@ public Builder addEntryRecursive(
BiFunction<Path, AbsoluteUnixPath, FilePermissions> filePermissionProvider)
throws IOException {
return addEntryRecursive(
sourceFile, pathInContainer, filePermissionProvider, DEFAULT_MODIFIED_TIME_PROVIDER);
sourceFile, pathInContainer, filePermissionProvider, DEFAULT_MODIFICATION_TIME_PROVIDER);
}

/**
Expand All @@ -179,7 +196,7 @@ public Builder addEntryRecursive(
* sourceFile}
* @param filePermissionProvider a provider that takes a source path and destination path on the
* container and returns the file permissions that should be set for that path
* @param lastModifiedTimeProvider a provider that takes a source path and destination path on
* @param modificationTimeProvider a provider that takes a source path and destination path on
* the container and returns the file modification time that should be set for that path
* @return this
* @throws IOException if an exception occurred when recursively listing the directory
Expand All @@ -188,11 +205,11 @@ public Builder addEntryRecursive(
Path sourceFile,
AbsoluteUnixPath pathInContainer,
BiFunction<Path, AbsoluteUnixPath, FilePermissions> filePermissionProvider,
BiFunction<Path, AbsoluteUnixPath, Instant> lastModifiedTimeProvider)
BiFunction<Path, AbsoluteUnixPath, Instant> modificationTimeProvider)
throws IOException {
FilePermissions permissions = filePermissionProvider.apply(sourceFile, pathInContainer);
Instant modifiedTime = lastModifiedTimeProvider.apply(sourceFile, pathInContainer);
addEntry(sourceFile, pathInContainer, permissions, modifiedTime);
Instant modificationTime = modificationTimeProvider.apply(sourceFile, pathInContainer);
addEntry(sourceFile, pathInContainer, permissions, modificationTime);
if (!Files.isDirectory(sourceFile)) {
return this;
}
Expand All @@ -202,7 +219,7 @@ public Builder addEntryRecursive(
file,
pathInContainer.resolve(file.getFileName()),
filePermissionProvider,
lastModifiedTimeProvider);
modificationTimeProvider);
}
}
return this;
Expand All @@ -227,11 +244,12 @@ public LayerConfiguration build() {
: FilePermissions.DEFAULT_FILE_PERMISSIONS;

/** Default file modification time (EPOCH + 1 second). */
public static final Instant DEFAULT_MODIFIED_TIME = Instant.ofEpochSecond(1);
public static final Instant DEFAULT_MODIFICATION_TIME = Instant.ofEpochSecond(1);

/** Provider that returns default file modification time (EPOCH + 1 second). */
public static final BiFunction<Path, AbsoluteUnixPath, Instant> DEFAULT_MODIFIED_TIME_PROVIDER =
(sourcePath, destinationPath) -> DEFAULT_MODIFIED_TIME;
public static final BiFunction<Path, AbsoluteUnixPath, Instant>
DEFAULT_MODIFICATION_TIME_PROVIDER =
(sourcePath, destinationPath) -> DEFAULT_MODIFICATION_TIME;

/**
* Gets a new {@link Builder} for {@link LayerConfiguration}.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public class LayerEntry {
private final Path sourceFile;
private final AbsoluteUnixPath extractionPath;
private final FilePermissions permissions;
private final Instant lastModifiedTime;
private final Instant modificationTime;

/**
* Instantiates with a source file and the path to place the source file in the container file
Expand All @@ -55,27 +55,26 @@ public class LayerEntry {
* @param extractionPath the path in the container file system corresponding to the {@code
* sourceFile}
* @param permissions the file permissions on the container
* @param lastModifiedTime the file modification time, default to 1 second since the epoch
* (https://github.com/GoogleContainerTools/jib/issues/1079)
* @param modificationTime the file modification time
*/
public LayerEntry(
Path sourceFile,
AbsoluteUnixPath extractionPath,
FilePermissions permissions,
Instant lastModifiedTime) {
Instant modificationTime) {
this.sourceFile = sourceFile;
this.extractionPath = extractionPath;
this.permissions = permissions;
this.lastModifiedTime = lastModifiedTime;
this.modificationTime = modificationTime;
}

/**
* Returns the modification time of the file in the entry.
*
* @return the modification time
*/
public Instant getLastModifiedTime() {
return lastModifiedTime;
public Instant getModificationTime() {
return modificationTime;
}

/**
Expand Down Expand Up @@ -119,11 +118,11 @@ public boolean equals(Object other) {
return sourceFile.equals(otherLayerEntry.sourceFile)
&& extractionPath.equals(otherLayerEntry.extractionPath)
&& Objects.equals(permissions, otherLayerEntry.permissions)
&& Objects.equals(lastModifiedTime, otherLayerEntry.lastModifiedTime);
&& Objects.equals(modificationTime, otherLayerEntry.modificationTime);
}

@Override
public int hashCode() {
return Objects.hash(sourceFile, extractionPath, permissions, lastModifiedTime);
return Objects.hash(sourceFile, extractionPath, permissions, modificationTime);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,15 @@
* {
* "sourceFile": "source/file/for/layer/entry/1",
* "extractionPath": "/extraction/path/for/layer/entry/1"
* "lastModifiedTime": "2018-10-03T15:48:32.416152Z"
* "sourceModificationTime": "2018-10-03T15:48:32.416152Z"
* "targetModificationTime": "1970-01-01T00:00:01Z",
* "permissions": "777"
* },
* {
* "sourceFile": "source/file/for/layer/entry/2",
* "extractionPath": "/extraction/path/for/layer/entry/2"
* "lastModifiedTime": "2018-10-03T15:48:32.416152Z"
* "sourceModificationTime": "2018-10-03T15:48:32.416152Z"
* "targetModificationTime": "1970-01-01T00:00:01Z",
* "permissions": "777"
* }
* ]
Expand All @@ -61,14 +63,16 @@ static class LayerEntryTemplate implements JsonTemplate, Comparable<LayerEntryTe

private final String sourceFile;
private final String extractionPath;
private final Instant lastModifiedTime;
private final Instant sourceModificationTime;
private final Instant targetModificationTime;
private final String permissions;

@VisibleForTesting
LayerEntryTemplate(LayerEntry layerEntry) throws IOException {
sourceFile = layerEntry.getSourceFile().toAbsolutePath().toString();
extractionPath = layerEntry.getExtractionPath().toString();
lastModifiedTime = Files.getLastModifiedTime(layerEntry.getSourceFile()).toInstant();
sourceModificationTime = Files.getLastModifiedTime(layerEntry.getSourceFile()).toInstant();
targetModificationTime = layerEntry.getModificationTime();
permissions = layerEntry.getPermissions().toOctalString();
}

Expand All @@ -83,10 +87,15 @@ public int compareTo(LayerEntryTemplate otherLayerEntryTemplate) {
if (extractionPathComparison != 0) {
return extractionPathComparison;
}
int lastModifiedTimeComparison =
lastModifiedTime.compareTo(otherLayerEntryTemplate.lastModifiedTime);
if (lastModifiedTimeComparison != 0) {
return lastModifiedTimeComparison;
int sourceModificationTimeComparison =
sourceModificationTime.compareTo(otherLayerEntryTemplate.sourceModificationTime);
if (sourceModificationTimeComparison != 0) {
return sourceModificationTimeComparison;
}
int targetModificationTimeComparison =
targetModificationTime.compareTo(otherLayerEntryTemplate.targetModificationTime);
if (targetModificationTimeComparison != 0) {
return targetModificationTimeComparison;
}
return permissions.compareTo(otherLayerEntryTemplate.permissions);
}
Expand All @@ -102,13 +111,15 @@ public boolean equals(Object other) {
LayerEntryTemplate otherLayerEntryTemplate = (LayerEntryTemplate) other;
return sourceFile.equals(otherLayerEntryTemplate.sourceFile)
&& extractionPath.equals(otherLayerEntryTemplate.extractionPath)
&& lastModifiedTime.equals(otherLayerEntryTemplate.lastModifiedTime)
&& sourceModificationTime.equals(otherLayerEntryTemplate.sourceModificationTime)
&& targetModificationTime.equals(otherLayerEntryTemplate.targetModificationTime)
&& permissions.equals(otherLayerEntryTemplate.permissions);
}

@Override
public int hashCode() {
return Objects.hash(sourceFile, extractionPath, lastModifiedTime, permissions);
return Objects.hash(
sourceFile, extractionPath, sourceModificationTime, targetModificationTime, permissions);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ private static class UniqueTarArchiveEntries {
/**
* Adds a {@link TarArchiveEntry} if its extraction path does not exist yet. Also adds all of
* the parent directories on the extraction path, if the parent does not exist. Parent will have
* modified time to set to {@link LayerConfiguration#DEFAULT_MODIFIED_TIME}.
* modification time set to {@link LayerConfiguration#DEFAULT_MODIFICATION_TIME}.
*
* @param tarArchiveEntry the {@link TarArchiveEntry}
*/
Expand All @@ -73,7 +73,7 @@ private void add(TarArchiveEntry tarArchiveEntry) {
Path namePath = Paths.get(tarArchiveEntry.getName());
if (namePath.getParent() != namePath.getRoot()) {
TarArchiveEntry dir = new TarArchiveEntry(DIRECTORY_FILE, namePath.getParent().toString());
dir.setModTime(LayerConfiguration.DEFAULT_MODIFIED_TIME.toEpochMilli());
dir.setModTime(LayerConfiguration.DEFAULT_MODIFICATION_TIME.toEpochMilli());
add(dir);
}

Expand Down Expand Up @@ -113,7 +113,7 @@ public Blob build() {
// Sets the entry's permissions by masking out the permission bits from the entry's mode (the
// lowest 9 bits) then using a bitwise OR to set them to the layerEntry's permissions.
entry.setMode((entry.getMode() & ~0777) | layerEntry.getPermissions().getPermissionBits());
entry.setModTime(layerEntry.getLastModifiedTime().toEpochMilli());
entry.setModTime(layerEntry.getModificationTime().toEpochMilli());

uniqueTarArchiveEntries.add(entry);
}
Expand All @@ -127,7 +127,7 @@ public Blob build() {
TarStreamBuilder tarStreamBuilder = new TarStreamBuilder();
for (TarArchiveEntry entry : sortedFilesystemEntries) {
// Strips out all non-reproducible elements from tar archive entries.
// Modified time is configured per entry
// Modification time is configured per entry
entry.setGroupId(0);
entry.setUserId(0);
entry.setUserName("");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ private static LayerEntry defaultLayerEntry(Path source, AbsoluteUnixPath destin
source,
destination,
LayerConfiguration.DEFAULT_FILE_PERMISSIONS_PROVIDER.apply(source, destination),
LayerConfiguration.DEFAULT_MODIFIED_TIME);
LayerConfiguration.DEFAULT_MODIFICATION_TIME);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ private static LayerEntry defaultLayerEntry(Path source, AbsoluteUnixPath destin
source,
destination,
LayerConfiguration.DEFAULT_FILE_PERMISSIONS_PROVIDER.apply(source, destination),
LayerConfiguration.DEFAULT_MODIFIED_TIME);
LayerConfiguration.DEFAULT_MODIFICATION_TIME);
}

@Rule public final TemporaryFolder temporaryFolder = new TemporaryFolder();
Expand Down
Loading

0 comments on commit 62c9cab

Please sign in to comment.