Gradle CopySpec.eachFile 中的 FileCopyDetails 评估
Evaluation of FileCopyDetails in Gradle CopySpec.eachFile
我正在尝试做一件看似相当简单的事情:显示我正在复制的文件的目标路径 使用 Gradle Copy
任务或方法。
为此,我使用 CopySpec.eachFile
方法,其中我使用 FileCopyDetails
访问目标路径,正如我认为在 Gradle javadoc.[=58= 中解释的那样]
这是一个使用 Copy
任务的示例(与 Copy
方法的行为相同):
task copyTaskUsingEachFile(type: Copy) {
from("$projectDir/resources/file-with-tokens.txt")
into('generated/subfolder')
filter(ReplaceTokens, tokens: [sampleProp: 'Hello sample property!'])
eachFile { println """ ---- content of FileCopyDetails object used in eachFile :
object toString = $it
name = $it.name
path = $it.path
relativePath = $it.relativePath
sourceName = $it.sourceName
sourcePath = $it.sourcePath
"""
}
}
问题是:eachFile
中使用的基础FileCopyDetails
对象的每个属性都评估为相同的值:
:copyTaskUsingEachFile
---- content of FileCopyDetails object used in eachFile :
object toString = file 'C:\<some path>\resources\file-with-tokens.txt'
name = file-with-tokens.txt
path = file-with-tokens.txt
relativePath = file-with-tokens.txt
sourceName = file-with-tokens.txt
sourcePath = file-with-tokens.txt
我希望 Gradle 显示:
sourceName = resources/file-with-tokens.txt
path = generated/subfolder/file-with-tokens.txt
仔细阅读 FileCopyDetails
文档后:
Provides details about a file or directory about to be copied, and allows some aspects of the destination file to be modified
我开始认为,在 eachFile
中打印此对象时,尚未设置 "final" 目标路径。
我尝试使用 child CopySpec,使用 from (...) {...}
语法,猜测它可能会影响评估时间:
task copyTaskUsingEachFileAndChildCopySpec(type: Copy) {
into 'generated'
from("$projectDir/resources/file-with-tokens.txt") {
into('subfolder')
}
filter(ReplaceTokens, tokens: [sampleProp: 'Hello sample property!'])
eachFile { println """ ---- content of FileCopyDetails object used in eachFile :
object toString = $it
name = $it.name
path = $it.path
relativePath = $it.relativePath
sourceName = $it.sourceName
sourcePath = $it.sourcePath
"""
}
}
这次我得到以下结果:
:copyTaskUsingEachFileAndChildCopySpec
---- content of FileCopyDetails object used in eachFile :
object toString = file 'C:\<some path>\resources\file-with-tokens.txt'
name = file-with-tokens.txt
path = subfolder/file-with-tokens.txt
relativePath = subfolder/file-with-tokens.txt
sourceName = file-with-tokens.txt
sourcePath = file-with-tokens.txt
所以所有目标路径都显示了它们的子 CopySpec 值,但不是从父 CopySpec 继承的部分(generated
在当前情况下)。
所以我有两个问题:
- 有人知道
FileCopyDetails
如何/何时在 CopySpec.eachFile
中解析吗?
- 有人知道如何显示
Copy
任务(或方法)复制的文件的完整目标路径吗?
任何帮助或部分解释将不胜感激。
更新
使用 ,我知道在 CopySpec.eachFile
中成功打印了我复制的文件的完整 目标路径 。
为此,我使用了 Copy.destinationDir
字段。
task copyMultipleFilesDisplayTargetFolder(type: Copy) {
printTask 'copyMultipleFilesDisplayTargetFolder'
into 'generated'
filter(ReplaceTokens, tokens: [sampleProp: 'Hello sample property!'])
/* Here, we print the complete destination path of the copied files, BUT,
I don't know how to print their complete SOURCE path.
*/
eachFile {
println "file $it.name copied to $destinationDir/$it.path"
println ''
}
from("$projectDir/resources/file-with-tokens.txt") {
into('subfolder')
}
from("$projectDir/resources2/file-with-tokens-2.txt") {
into('subfolder2')
}
from("$projectDir/resources3/file-with-tokens-3.txt") {
into('subfolder3')
}
}
给出:
------------ TASK ------------ copyMultipleFilesDisplayTargetFolder
:copyMultipleFilesDisplayTargetFolder
file file-with-tokens.txt copied to C:\<some path>\generated/subfolder/file-with-tokens.txt
file file-with-tokens-2.txt copied to C:\<some path>\generated/subfolder2/file-with-tokens-2.txt
file file-with-tokens-3.txt copied to C:\<some path>\generated/subfolder3/file-with-tokens-3.txt
现在唯一缺少的是能够以简单的方式打印复制文件的完整源路径。
"easy way" 我的意思是,举例来说,在单个 eachFile
中,所有子 CopySpec
将继承(如上所述)。
目前,我可以使用Copy.source
字段和FileCollection.getAsPath
方法来显示它,但在eachFile
.
中集成并不那么容易
更新 2
吸血鬼又说对了,你可以用FileCopyDetails.getFile()
访问一个代表源的File
对象,这样你就可以显示完整的源路径:
task copyMultipleFilesDisplayTargetFolder(type: Copy) {
printTask 'copyMultipleFilesDisplayTargetFolder'
into 'generated'
//filter(ReplaceTokens, tokens: [sampleProp: 'Hello sample property!'])
eachFile {
println "file $it.name copied to $destinationDir/$it.path"
/* !!!! BEWARE !!!!
You can't use the below FileCopyDetails.getFile() when also using a filter operation.
Check https://discuss.gradle.org/t/combining-eachfile-filter-results-in-failure/14801/2
*/
println "Initial source path: ${it.getFile().getCanonicalPath()}"
println ''
}
from("$projectDir/resources/file-with-tokens.txt") {
into('subfolder')
}
from("$projectDir/resources2/file-with-tokens-2.txt") {
into('subfolder2')
}
from("$projectDir/resources3/file-with-tokens-3.txt") {
into('subfolder3')
}
}
但是,你不能在同时使用filter
操作时使用FileCopyDetails.getFile()
!
这是一个神秘的 Gradle 错误,在此处解释:https://discuss.gradle.org/t/combining-eachfile-filter-results-in-failure/14801/2
查看 Gradle 源代码时,DefaultFileCopyDetails
class 包含以下代码:
public File getFile() {
if (filterChain.hasFilters()) {
throw new UnsupportedOperationException();
} else {
return fileDetails.getFile();
}
}
不幸的是,这解释了这个问题。
无论如何,在任何其他情况下,我最初的 2 个问题都找到了新的答案,谢谢!
更新 3(最终)
再次感谢 Vampire(他专门针对此问题开设了一个 Gradle 案例),他为我们提供了前一个 filter
/ getFile
错误的解决方案。
查看他的 https://github.com/gradle/gradle/issues/1588 了解详细信息,但是,简而言之,为避免此问题,在 same CopySpec 中,您只需调用filter
AFTER 调用 eachFile
.
我确认它正在工作。
如果你更深入地阅读 JavaDoc,你会在 getPath()
和 getRelativePath()
的第一句中找到解释,即 Returns the path of this file, relative to the root of the copy destination.
。
在您的第一个示例中,您调用 eachFile
方法的 CopySpec
的复制目标是 generated/subfolder
,因此目标文件的相对路径是 file-with-tokens.txt
.
在您的第二个示例中,您调用 eachFile
方法的 CopySpec
的复制目标是 generated
,因此目标文件的相对路径是 subfolder/file-with-tokens.txt
.
将CopySpec
的复制目标与相对路径连接起来,您将得到目标文件的完整路径。
如果你e。 G。在您的 eachFile
调用之前添加一个 rename
调用,如 rename { 'foo-' + it }
,然后您将看到相对路径将变为 foo-file-with-tokens.txt
,而源路径仍将是 file-with-tokens.txt
.
如果需要文件的源路径,直接使用FileCopyDetails
的file
属性即可。每个 FileCopyDetails
也是一个 FileTreeElement
(它的超类),因此有一个指向源文件的文件 属性(File
对象)。
请注意 filter
可能会受到干扰。如果您在同一复制规范中且在 eachFile
之前有一个 filter
,或者在您执行 eachFile
的父复制规范中有一个 filter
,无论如果之前或之后,那么你将得到一个 UnsupportedOperationException
。如果您在同一复制规范中的 eachFile
之后执行 filter
,它就可以工作。有关详细信息,请参阅 https://github.com/gradle/gradle/issues/1588。
我正在尝试做一件看似相当简单的事情:显示我正在复制的文件的目标路径 使用 Gradle Copy
任务或方法。
为此,我使用 CopySpec.eachFile
方法,其中我使用 FileCopyDetails
访问目标路径,正如我认为在 Gradle javadoc.[=58= 中解释的那样]
这是一个使用 Copy
任务的示例(与 Copy
方法的行为相同):
task copyTaskUsingEachFile(type: Copy) {
from("$projectDir/resources/file-with-tokens.txt")
into('generated/subfolder')
filter(ReplaceTokens, tokens: [sampleProp: 'Hello sample property!'])
eachFile { println """ ---- content of FileCopyDetails object used in eachFile :
object toString = $it
name = $it.name
path = $it.path
relativePath = $it.relativePath
sourceName = $it.sourceName
sourcePath = $it.sourcePath
"""
}
}
问题是:eachFile
中使用的基础FileCopyDetails
对象的每个属性都评估为相同的值:
:copyTaskUsingEachFile
---- content of FileCopyDetails object used in eachFile :
object toString = file 'C:\<some path>\resources\file-with-tokens.txt'
name = file-with-tokens.txt
path = file-with-tokens.txt
relativePath = file-with-tokens.txt
sourceName = file-with-tokens.txt
sourcePath = file-with-tokens.txt
我希望 Gradle 显示:
sourceName = resources/file-with-tokens.txt
path = generated/subfolder/file-with-tokens.txt
仔细阅读 FileCopyDetails
文档后:
Provides details about a file or directory about to be copied, and allows some aspects of the destination file to be modified
我开始认为,在 eachFile
中打印此对象时,尚未设置 "final" 目标路径。
我尝试使用 child CopySpec,使用 from (...) {...}
语法,猜测它可能会影响评估时间:
task copyTaskUsingEachFileAndChildCopySpec(type: Copy) {
into 'generated'
from("$projectDir/resources/file-with-tokens.txt") {
into('subfolder')
}
filter(ReplaceTokens, tokens: [sampleProp: 'Hello sample property!'])
eachFile { println """ ---- content of FileCopyDetails object used in eachFile :
object toString = $it
name = $it.name
path = $it.path
relativePath = $it.relativePath
sourceName = $it.sourceName
sourcePath = $it.sourcePath
"""
}
}
这次我得到以下结果:
:copyTaskUsingEachFileAndChildCopySpec
---- content of FileCopyDetails object used in eachFile :
object toString = file 'C:\<some path>\resources\file-with-tokens.txt'
name = file-with-tokens.txt
path = subfolder/file-with-tokens.txt
relativePath = subfolder/file-with-tokens.txt
sourceName = file-with-tokens.txt
sourcePath = file-with-tokens.txt
所以所有目标路径都显示了它们的子 CopySpec 值,但不是从父 CopySpec 继承的部分(generated
在当前情况下)。
所以我有两个问题:
- 有人知道
FileCopyDetails
如何/何时在CopySpec.eachFile
中解析吗? - 有人知道如何显示
Copy
任务(或方法)复制的文件的完整目标路径吗?
任何帮助或部分解释将不胜感激。
更新
使用 CopySpec.eachFile
中成功打印了我复制的文件的完整 目标路径 。
为此,我使用了 Copy.destinationDir
字段。
task copyMultipleFilesDisplayTargetFolder(type: Copy) {
printTask 'copyMultipleFilesDisplayTargetFolder'
into 'generated'
filter(ReplaceTokens, tokens: [sampleProp: 'Hello sample property!'])
/* Here, we print the complete destination path of the copied files, BUT,
I don't know how to print their complete SOURCE path.
*/
eachFile {
println "file $it.name copied to $destinationDir/$it.path"
println ''
}
from("$projectDir/resources/file-with-tokens.txt") {
into('subfolder')
}
from("$projectDir/resources2/file-with-tokens-2.txt") {
into('subfolder2')
}
from("$projectDir/resources3/file-with-tokens-3.txt") {
into('subfolder3')
}
}
给出:
------------ TASK ------------ copyMultipleFilesDisplayTargetFolder
:copyMultipleFilesDisplayTargetFolder
file file-with-tokens.txt copied to C:\<some path>\generated/subfolder/file-with-tokens.txt
file file-with-tokens-2.txt copied to C:\<some path>\generated/subfolder2/file-with-tokens-2.txt
file file-with-tokens-3.txt copied to C:\<some path>\generated/subfolder3/file-with-tokens-3.txt
现在唯一缺少的是能够以简单的方式打印复制文件的完整源路径。
"easy way" 我的意思是,举例来说,在单个 eachFile
中,所有子 CopySpec
将继承(如上所述)。
目前,我可以使用Copy.source
字段和FileCollection.getAsPath
方法来显示它,但在eachFile
.
更新 2
吸血鬼又说对了,你可以用FileCopyDetails.getFile()
访问一个代表源的File
对象,这样你就可以显示完整的源路径:
task copyMultipleFilesDisplayTargetFolder(type: Copy) {
printTask 'copyMultipleFilesDisplayTargetFolder'
into 'generated'
//filter(ReplaceTokens, tokens: [sampleProp: 'Hello sample property!'])
eachFile {
println "file $it.name copied to $destinationDir/$it.path"
/* !!!! BEWARE !!!!
You can't use the below FileCopyDetails.getFile() when also using a filter operation.
Check https://discuss.gradle.org/t/combining-eachfile-filter-results-in-failure/14801/2
*/
println "Initial source path: ${it.getFile().getCanonicalPath()}"
println ''
}
from("$projectDir/resources/file-with-tokens.txt") {
into('subfolder')
}
from("$projectDir/resources2/file-with-tokens-2.txt") {
into('subfolder2')
}
from("$projectDir/resources3/file-with-tokens-3.txt") {
into('subfolder3')
}
}
但是,你不能在同时使用filter
操作时使用FileCopyDetails.getFile()
!
这是一个神秘的 Gradle 错误,在此处解释:https://discuss.gradle.org/t/combining-eachfile-filter-results-in-failure/14801/2
查看 Gradle 源代码时,DefaultFileCopyDetails
class 包含以下代码:
public File getFile() {
if (filterChain.hasFilters()) {
throw new UnsupportedOperationException();
} else {
return fileDetails.getFile();
}
}
不幸的是,这解释了这个问题。
无论如何,在任何其他情况下,我最初的 2 个问题都找到了新的答案,谢谢!
更新 3(最终)
再次感谢 Vampire(他专门针对此问题开设了一个 Gradle 案例),他为我们提供了前一个 filter
/ getFile
错误的解决方案。
查看他的 https://github.com/gradle/gradle/issues/1588 了解详细信息,但是,简而言之,为避免此问题,在 same CopySpec 中,您只需调用filter
AFTER 调用 eachFile
.
我确认它正在工作。
如果你更深入地阅读 JavaDoc,你会在 getPath()
和 getRelativePath()
的第一句中找到解释,即 Returns the path of this file, relative to the root of the copy destination.
。
在您的第一个示例中,您调用 eachFile
方法的 CopySpec
的复制目标是 generated/subfolder
,因此目标文件的相对路径是 file-with-tokens.txt
.
在您的第二个示例中,您调用 eachFile
方法的 CopySpec
的复制目标是 generated
,因此目标文件的相对路径是 subfolder/file-with-tokens.txt
.
将CopySpec
的复制目标与相对路径连接起来,您将得到目标文件的完整路径。
如果你e。 G。在您的 eachFile
调用之前添加一个 rename
调用,如 rename { 'foo-' + it }
,然后您将看到相对路径将变为 foo-file-with-tokens.txt
,而源路径仍将是 file-with-tokens.txt
.
如果需要文件的源路径,直接使用FileCopyDetails
的file
属性即可。每个 FileCopyDetails
也是一个 FileTreeElement
(它的超类),因此有一个指向源文件的文件 属性(File
对象)。
请注意 filter
可能会受到干扰。如果您在同一复制规范中且在 eachFile
之前有一个 filter
,或者在您执行 eachFile
的父复制规范中有一个 filter
,无论如果之前或之后,那么你将得到一个 UnsupportedOperationException
。如果您在同一复制规范中的 eachFile
之后执行 filter
,它就可以工作。有关详细信息,请参阅 https://github.com/gradle/gradle/issues/1588。