Я написал следующий класс задач zip. Также протестировал его с различными сценариями ios и, похоже, что zip является инкрементным, так что в случаях, когда были изменены только несколько файлов, zip будет обрабатывать только эти файлы.
I тесты: модификация / добавление / удаление файлов. Также поврежден почтовый индекс и остановка почтового индекса во время выполнения задания.
Мой вопрос: почему это не является частью ядра gradle? Я уверен, что есть веская причина, но не могу придумать одну.
abstract class IncrementalZip extends DefaultTask {
@Incremental
@PathSensitive(PathSensitivity.RELATIVE)
@InputDirectory
abstract DirectoryProperty getInputDir()
@OutputFile
abstract RegularFileProperty getOutputFile()
@TaskAction
void execute(InputChanges inputChanges) {
logger.info "Zip destiantion: ${outputFile.get()}"
if (!inputChanges.incremental) {
logger.info "No incremental info - going to zip the all folder"
/* We do not have task history - we create the zip from scratch */
ant.zip(destfile: outputFile.get().asFile) {
fileset(dir: inputDir.get().asFile) {
}
}
} else {
logger.info "Incremental Zip"
/*
* Make use of Filesystem class in Java to:
* a) copy new and/or modified files
* b) remove all removed files
* Tested and worked in the below scenarios:
* 1) Adding a number of files
* 2) Remove a number of files
* 3) Rename a file with upper lower case
* 4) Remove an non empty folder
* */
Path outPutFileEx = outputFile.get().asFile.toPath()
assert Files.exists(outPutFileEx)
try {
FileSystem zipfs = FileSystems.newFileSystem(outPutFileEx, null)
Set<String> toBeCopy = []
Set<String> toBeRemoveItems = []
inputChanges.getFileChanges(inputDir).each { change ->
if (change.fileType == FileType.DIRECTORY) return
logger.info "${change.changeType}: ${change.normalizedPath}"
if (change.changeType == ChangeType.REMOVED) {
toBeRemoveItems.add(change.normalizedPath)
} else {
toBeCopy.add(change.normalizedPath)
}
}
if (!toBeCopy.isEmpty()) {
//copy into the zip - sorted by the shortest path to ensure folder will be created first
toBeCopy.stream().sorted(Comparator.naturalOrder()).each { String source ->
Path dest = zipfs.getPath(source)
Files.copy(inputDir.getAsFile().get().toPath().resolve(source), dest, StandardCopyOption.REPLACE_EXISTING)
}
}
if (!toBeRemoveItems.isEmpty()) {
//delete files - sorted by the longest path to ensure delete only empty folders
toBeRemoveItems.stream().sorted(Comparator.reverseOrder()).each { String source ->
Path target = zipfs.getPath(source)
boolean removed = Files.deleteIfExists(target)
removed ? logger.info("Removed: ${source}") : logger.info("Did not found: ${source}")
}
}
zipfs.close()
} catch (Exception e) {
/*
If for some reason we failed to remove some files or folder we must remove the output:
because next run the task will not remove the files that it wanted to remove in this execution
*/
Files.deleteIfExists(outPutFileEx)
throw new GradleScriptException(e.getMessage(), e)
}
}
}
}