Это правильная реализация задачи Gradle Incremental Zip? - PullRequest
1 голос
/ 10 января 2020

Я написал следующий класс задач 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)
            }
        }
    }
}
...