发布工件覆盖 Gradle 中的其他工件

Posted

技术标签:

【中文标题】发布工件覆盖 Gradle 中的其他工件【英文标题】:publish artifact overwrite other artifact in Gradle 【发布时间】:2013-03-30 13:58:18 【问题描述】:

我正在尝试使用 Gradle 构建几个 jar,而不是维护一个包含 EJB 的类列表以便我可以单独部署它们,我认为在制作 jar 时扫描这些类可能会很整洁。

与其加载类并使用反射来获取注释,我认为使用 asm 扫描类可能更简单,因此在其中一项任务中使用厚实的 ClassReader。

我认为这不是问题,所以可以忽略,基本上我有 2 个任务用于定义 jar 的内容,两者都报告不同的内容通过 eachFile 打印输出进入它们,但是当我在发布存储库位置查看文件和关联的 sha1 是相同的。

Gradle 坏了,或者更有可能是我做了一些疯狂的事情,但看不到它是什么,有人可以帮忙吗?

顺便说一句,如果我禁用任何一个 jar 文件的发布,那么创建的那个是正确的,所以我认为发布有问题而不是震动,但可能是错误的。

// ASM is used to interpret the class files, this avoids having to load all classes in the vm and use reflection
import org.objectweb.asm.*
task ejbJar(type: Jar) 
  //outputs.upToDateWhen  false 
  from "$project.buildDir/classes/main"
  eachFile  println "EJB server: $name" 
  include getEjbClassFiles(project.buildDir)


task clientEjbJar(type: Jar) 
  //outputs.upToDateWhen  false 
  from "$project.buildDir/classes/main/com/company/core/versioner"
  eachFile  println "Client EJB $name"   
  include '**/*'


artifacts     
  archives clientEjbJar
  archives ejbJar

String[] getEjbClassFiles(base) 
  def includedFiles = []
  def baseDir = project.file("$base/classes/main")
  def parentPath = baseDir.toPath()
  if (baseDir.isDirectory()) 
    baseDir.eachFileRecurse(groovy.io.FileType.FILES)  file ->
      if(file.name.endsWith('.class')) 
        //get hold of annotations in there --- org.objectweb.asm.Opcodes.ASM4
        def reader = new ClassReader(file.bytes).accept(
          new ClassVisitor(Opcodes.ASM4) 
            public AnnotationVisitor visitAnnotation(String desc, boolean visible) 
              if(desc.equals("Ljavax/ejb/Stateless;") ||
                desc.equals("Ljavax/ejb/Stateful;")) 
                includedFiles += parentPath.relativize(file.toPath())
              
              return null //no interest in actually visiting the annotation values
            
          , 
          ClassReader.SKIP_DEBUG | ClassReader.EXPAND_FRAMES | ClassReader.SKIP_FRAMES | ClassReader.SKIP_CODE
        )
      
    
  
  return includedFiles
    

publishing 
  publications 
    mypub(IvyPublication) 
      artifact(ejbJar) 
        name 'ejb' 
      
      artifact(clientEjbJar)  
        name 'client-ejb' 
      
    
  
  repositories 
    ivy 
      name 'personal'
      url "$ant['developer.repository']/"
      layout 'pattern', 
        artifact "[organisation]/[module]/[artifact]/[revision]/[type]/[artifact]-[revision].[ext]"
    ivy "[organisation]/[module]/[type]/[revision]/[type]/[type]-[revision].[ext]"
      
       
    

我确实把它分解成一个更简单的形式,因为我认为它可能是一个 Gradle 错误。

简化的形式是:

apply plugin: 'java'
apply plugin: 'ivy-publish'

task bigJar(type: Jar) 
  from "$rootDir/src/main/resources"
  include '**/*'


task smallJar(type: Jar) 
  from "$rootDir/src/main/resources/A/B"
  include '**/*'


group 'ICantBeEmpty'
artifacts 
  archives bigJar
  archives smallJar


publishing 
  publications 
    mypub(IvyPublication) 
      artifact(bigJar)  name 'biggie' 
      artifact(smallJar)  name 'smallie' 
    
    repositories 
  ivy 
    name 'personal'
    url "c:/temp/gradletest"
    layout 'pattern', 
      artifact "[organisation]/[module]/[artifact]/[revision]/[type]/[artifact]-[revision].[ext]"
      ivy "[organisation]/[module]/[type]/[revision]/[type]/[type]-[revision].[ext]"
    
      
    
  

这会在 c:/temp/gradletest/ICantBeEmpty/report-bug/biggie/unspecified/biggie-unspecified.jar 和 c:/temp/gradletest/ICantBeEmpty/report-bug/smallie/unspecified/smallie 中生成 2 个文件-未指定的.jar 这两个文件是相同的,但是我想我知道为什么看到我以后的答案。

【问题讨论】:

【参考方案1】:

在查看一些配置时,我注意到一些奇怪的行为导致我解决了这个问题,这是一个 Gradle 错误。

在我的构建中,我做了一个临时任务

configurations.archives.artifacts.each  println it 

这给了我 5 个不同的行输出,但是将其更改为这个

configurations.archives.artifacts.each  println it.file 

生成相同的文件名 5 次。

事实证明这与我的问题有关,尽管工件作为单独的实体存在,用于唯一标识它们的名称是相同的,因此在发布期间始终选择相同的文件。在 java 插件中,工件的名称默认由 $baseName-$appendix-$version-$classifier.$extension 给出。这意味着如果未指定附录或分类器,则工件将具有相同的名称。

我通过添加附录名称使用上面的示例代码对此进行了测试

task bigJar(type: Jar) 
  appendix = 'big'
  from "$rootDir/src/main/resources"
  include '**/*'


task smallJar(type: Jar) 
  appendix = 'small'
  from "$rootDir/src/main/resources/A/B"
  include '**/*'

使用这个而不是问题中的代码会产生 2 个不同的 jar。

【讨论】:

【参考方案2】:

这不是一个完整的答案,但已经足够好解决了,如果我添加一个新的发布定义,我可以将我想要的工件发布到我想要的位置,唯一的缺点是它会创建另一个 gradle 任务这并不理想。

   publications 
      mypub(IvyPublication) 
        artifact(ejbJar) 
          name 'ejb' 
        
      
      newpub(IvyPublication) 
        artifact(clientEjbJar)  
          name 'client-ejb' 
        
      
    

【讨论】:

【参考方案3】:

上述答案在短期内有效,但确实揭示了 Gradle 世界中的另一个不足enter link description here

不确定 Gradle 是不是目前的一切,到目前为止还没有人回答我的问题,所以也许它没有那么积极地开发!

【讨论】:

【参考方案4】:

我不是 Gradle 这部分的专家,但您使用的功能标记为“incubating”;您正在使用可能不完整的新发布功能。或许您应该使用old way 处事。您似乎也通过使用 artifacts 闭包来混合两种方式。

【讨论】:

感谢您的关注,但“旧​​方式”链接向我展示了我已经在做什么,除了我使用的是常春藤回购而不是平面文件这一事实。因为处于孵化状态的东西并不意味着它不应该被使用和提出关于它的问题,这就是开源发展如此之快的本质。我现在实际上已经确定了这个问题,因为用于在配置中定位工件的名称不是唯一的,并且会发布完整的描述以节省其他 Gradle 用户同样的麻烦。

以上是关于发布工件覆盖 Gradle 中的其他工件的主要内容,如果未能解决你的问题,请参考以下文章

在 Artifactory 中阻止覆盖 NuGet 工件

完全覆盖工件 PyPI 包

覆盖Artifactory工件(和历史)?

使用 maven 程序集插件覆盖资源文件

重新发布 gradle 工件

Gradle 5 Kotlin DSL:多模块项目中的常见任务和 Maven 工件