首页 > 解决方案 > 具有惰性包含属性的 Gradle zip 任务包含自身

问题描述

嗨,我收到了这个 zip 任务,效果很好:

def dir = new File("${projectDir.parentFile}/test/")

task testZip(type: Zip) {
    from dir
    destinationDirectory = dir
    include 'toast/**'

    archiveFileName = 'test.zip'
}

但是当我使包含属性变得懒惰时(因为我需要在我的真实情况下)

def dir = new File("${projectDir.parentFile}/test/")

task testZip(type: Zip) {
    from dir
    destinationDirectory = dir
    include {
        'toast/**'
    }

    archiveFileName = 'test.zip'
}

然后它会创建一个包含文件夹中所有内容的 zip,(因此也生成了存档)。在这个测试案例中,内部 zip 只是损坏了(不会无限运行),但在现实世界的案例中,它确实会产生无限 zip。(不知道为什么,也许我最好的情况是文件太少或太小)。无论哪种方式测试用例都显示了问题,生成的 zip 包含一个 zip,即使它应该只包含 toast 目录及其所有内容。

我该如何解决?我需要一个惰性包含,因为我要包含的目录是由其他任务计算的。我遇到了完全相同的问题,Tar除了它拒绝创建存档,因为它包含自己。

使用exclude '*.zip'是一种愚蠢的解决方法,它使存档包含我不想要的其他文件夹。我只想懒惰地包含一个特定的文件夹。

这是怪物在现实世界中的样子。我基本上需要从 Java 中检索项目的版本,然后使用该版本来命名我正在打包的文件夹。(制作一个 libGDX 游戏并使用 jre 打包它packr)。有问题的任务是'makeArchive_' + platform


String jumpaiVersion;

task fetchVersion(type: JavaExec) {
    outputs.upToDateWhen { jumpaiVersion != null }

    main = 'net.jumpai.Version'
    classpath = sourceSets.main.runtimeClasspath
    standardOutput new ByteArrayOutputStream()
    doLast {
        jumpaiVersion = standardOutput.toString().replaceAll("\\s+", "")
    }
}

def names = [
    'win64' : "Jumpai-%%VERSION%%-Windows-64Bit",
    'win32' : "Jumpai-%%VERSION%%-Windows-32Bit",
    'linux64' : "Jumpai-%%VERSION%%-Linux-64Bit",
    'linux32' : "Jumpai-%%VERSION%%-Linux-32Bit",
    'mac' : "Jumpai-%%VERSION%%-Mac.app"
]

def platforms = names.keySet() as String[]

def jdks = [
    'win64' : 'https://cdn.azul.com/zulu/bin/zulu9.0.7.1-jdk9.0.7-win_x64.zip',
    'win32' : 'https://cdn.azul.com/zulu/bin/zulu9.0.7.1-jdk9.0.7-win_i686.zip',
    'linux64' : 'https://cdn.azul.com/zulu/bin/zulu9.0.7.1-jdk9.0.7-linux_x64.tar.gz',
    'linux32' : 'https://cdn.azul.com/zulu/bin/zulu9.0.7.1-jdk9.0.7-linux_i686.tar.gz',
    'mac' : 'https://cdn.azul.com/zulu/bin/zulu9.0.7.1-jdk9.0.7-macosx_x64.zip'
]

def formats = [
    'win64' : 'ZIP',
    'win32' : 'ZIP',
    'linux64' : 'TAR_GZ',
    'linux32' : 'TAR_GZ',
    'mac' : 'ZIP'
]
File jdksDir = new File(project.buildscript.sourceFile.parentFile.parentFile, 'out/jdks')
File gameJar = new File("${projectDir.parentFile}/desktop/build/libs/Jumpai.jar")
File gameData = new File("${projectDir.parentFile}/desktop/build/libs/Jumpai.data")

File packrDir = new File("${projectDir.parentFile}/out/packr/")

File minimalTmpDir = new File("${projectDir.parentFile}/desktop/build/libs/minimal-tmp")

task minimizeGameJar {
    dependsOn ':desktop:dist'
    doFirst {
        minimalTmpDir.mkdirs()
        copy {
            from zipTree(gameJar)
            into minimalTmpDir
        }

        for(file in minimalTmpDir.listFiles())
            if(file.getName().contains("humble"))
                file.delete()
    }
}

task makeMinimal(type: Zip) {
    dependsOn minimizeGameJar
    dependsOn fetchVersion

    from minimalTmpDir
    include '**'
    archiveFileName = provider {
        "Jumpai-${->jumpaiVersion}-Minimal.jar"
    }
    destinationDir packrDir

    doLast {
        minimalTmpDir.deleteDir()
    }
}

task copyGameJar(type: Copy) {
    outputs.upToDateWhen { gameData.exists() }

    dependsOn ':desktop:dist'
    from gameJar.getAbsolutePath()
    into gameData.getParentFile()
    rename("Jumpai.jar", "Jumpai.data")
}

task setWindowsIcons(type: Exec) {
    dependsOn fetchVersion
    workingDir '.'
    commandLine 'cmd', '/c', 'set_windows_icons.bat', "${->jumpaiVersion}"
}

for(platform in platforms) {
    task("getJdk_" + platform) {
        String url = jdks[platform]
        File jdkDir = new File(jdksDir, platform + "-jdk")
        File jdkFile = new File(jdkDir, url.split("/").last())
        outputs.upToDateWhen { jdkFile.exists() }

        doFirst {

            if(!jdkDir.exists())
                jdkDir.mkdirs()

            if(jdkFile.exists())
            {
                println jdkFile.getName() + " is already present"
                return
            }
            else
            {
                println "Downloading " + jdkFile.getName()
                new URL(url).withInputStream {
                    i -> jdkFile.withOutputStream { it << i }
                }
            }

            for(file in jdkDir.listFiles()) {
                if(file.equals(jdkFile))
                    continue

                if(file.isFile()) {
                    if (!file.delete())
                        println "ERROR: could not delete " + file.getAbsoluteFile()
                } else if(!file.deleteDir())
                    println "ERROR: could not delete content of " + file.getAbsoluteFile()
            }

            if(url.endsWith(".tar.gz"))// don't mix up archive type of what we downloaded vs archive type of what we compress (in formats)
            {
                copy {
                    from tarTree(resources.gzip(jdkFile))
                    into jdkDir
                }
            }
            else if(url.endsWith(".zip"))
            {
                copy {
                    from zipTree(jdkFile)
                    into jdkDir
                }
            }
        }
    }

    File packrInDir = new File(packrDir, platform)
    String platformRawName = names[platform]

    task("packr_" + platform, type: JavaExec) {
        outputs.upToDateWhen { new File(packrDir, platformRawName.replace("%%VERSION%%", jumpaiVersion)).exists() }

        dependsOn fetchVersion
        dependsOn copyGameJar
        dependsOn 'getJdk_' + platform

        main = 'com.badlogicgames.packr.Packr'
        classpath = sourceSets.main.runtimeClasspath
        args 'tools/res/packr_config/' + platform + '.json'

        workingDir = project.buildscript.sourceFile.parentFile.parentFile
        doLast {
            File packrOutDir = new File(packrDir, platformRawName.replace("%%VERSION%%", jumpaiVersion));
            packrOutDir.deleteDir()

            if(packrOutDir.exists())
            {
                println "ERROR Could not delete packr output " + packrOutDir.getAbsolutePath()
                return
            }

            if(!packrInDir.renameTo(packrOutDir))
                println "ERROR Could not rename packr output dir for " + packrInDir.getName()
        }
    }

    if(formats[platform] == 'ZIP')
    {
        task('makeArchive_' + platform, type: Zip) {
            if(platform.contains("win"))
                dependsOn setWindowsIcons
            dependsOn fetchVersion
            dependsOn 'packr_' + platform

            from packrDir
            destinationDirectory = packrDir

            include {
                platformRawName.replace("%%VERSION%%", jumpaiVersion) + "/"
            }

            archiveFileName = provider {
                platformRawName.replace("%%VERSION%%", jumpaiVersion) + ".zip"
            }
        }
    }
    else if(formats[platform] == 'TAR_GZ')
    {
        task('makeArchive_' + platform, type: Tar) {
            dependsOn 'packr_' + platform
            from packrDir
            destinationDirectory = packrDir
            include {
                platformRawName.replace("%%VERSION%%", jumpaiVersion) + '/**'
            }
            archiveFileName = provider {
                platformRawName.replace("%%VERSION%%", jumpaiVersion) + ".tar.gz"
            }
            extension 'tar'
            compression = Compression.GZIP
        }
    }
    else
        println 'Unsupported format for ' + platform
}

task deploy {
    dependsOn makeMinimal
    for(platform in platforms)
        dependsOn 'makeArchive_' + platform
}

标签: gradlelibgdx

解决方案


我该如何解决?我需要一个惰性包含,因为我要包含的目录是由其他任务计算的。我遇到了与 Tar 完全相同的问题,只是它拒绝创建存档,因为它包含自己。

您可以通过使用 doFirst 方法并使用传递的操作修改任务属性来获得所需的内容。

task('makeArchive_' + platform, type: Zip) {
    if(platform.contains("win"))
        dependsOn setWindowsIcons
    dependsOn fetchVersion
    dependsOn 'packr_' + platform

    from packrDir
    destinationDirectory = packrDir

    archiveFileName = provider {
        platformRawName.replace("%%VERSION%%", jumpaiVersion) + ".zip"
    }

    doFirst {
        def includeDir = platformRawName.replace("%%VERSION%%", jumpaiVersion)
        // Include only files and directories from 'includeDir'
        include {
            it.relativePath.segments[ 0 ].equalsIgnoreCase(includeDir)
        }
    }
}

另请查看此类似问题的答案。我的解决方案只是一种解决方法。如果您在配置阶段知道您的版本,您可以更轻松地实现您想要的。编写自己的自定义任务或插件也有助于清理构建脚本。


推荐阅读