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

Groovy 发布工件覆盖Gradle中的其他工件,groovy,gradle,ivy,Groovy,Gradle,Ivy,我正在用Gradle做实验来构建几个jar,而不是维护一个包含EJB的类的列表,这样我就可以单独部署它们了。我认为在制作jar时扫描这些类可能会很方便 我认为使用asm扫描类可能比加载类并使用反射获取注释更简单,因此在其中一个任务中使用chuncky ClassReader 我不认为这是一个可以忽略的问题,基本上我有两个任务用于定义JAR的内容,两个任务都报告不同的内容通过每个文件打印输出进入JAR,但是当我查看发布存储库位置时,两个文件和关联的sha1都是相同的 要么格拉德尔破产了,要么更可能

我正在用Gradle做实验来构建几个jar,而不是维护一个包含EJB的类的列表,这样我就可以单独部署它们了。我认为在制作jar时扫描这些类可能会很方便

我认为使用asm扫描类可能比加载类并使用反射获取注释更简单,因此在其中一个任务中使用chuncky ClassReader

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

要么格拉德尔破产了,要么更可能的是,我做了一些疯狂的事情,但看不出是什么,有人能帮忙吗

顺便说一句,如果我禁用其中一个jar文件的发布,那么创建的jar文件是正确的,因此我认为发布有问题,而不是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 bug

简化形式为:

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-unspecified.jar中的两个文件
这两个文件都是相同的,但是我想我知道为什么要看到我后面的答案。

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

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

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

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

上述答案在短期内有效,但确实揭示了Gradle世界的另一个短期趋势


目前还不确定Gradle是否就是它的全部,而且到目前为止还没有人回答我的问题,所以它可能没有那么积极地开发

上述答案在短期内有效,但确实揭示了格拉德尔世界的另一个短期趋势


目前还不确定Gradle是否就是它的全部,而且到目前为止还没有人回答我的问题,所以它可能没有那么积极地开发

我不是Gradle这方面的专家,但您使用的功能标记为“”;您正在使用的新发布功能可能完整,也可能不完整。也许你应该用做事的方法。通过使用
工件
闭包,您似乎也在混合这两种方式。

我在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 '**/*'
}

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

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

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

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 '**/*'
}

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

感谢您的关注,但“旧方法”链接向我准确显示了我已经在做什么,除了我使用的是常春藤回购协议而不是平面文件这一事实。因为某些东西处于孵化状态并不意味着它不应该被使用,也不意味着就不应该提出关于它的问题,这就是开源如此迅速发展的本质。事实上,我现在已经发现了这个问题,因为用于在配置中定位工件的名称不是唯一的,并且将发布一个完整的描述,以避免其他Gradle用户遇到同样的麻烦。感谢您的关注,但“旧方法”链接向我准确地显示了我已经在做什么,除了我使用的是常春藤回购文件而不是平面文件这一事实之外。因为某些东西处于孵化状态并不意味着它不应该被使用,也不意味着就不应该提出关于它的问题,这就是开源如此迅速发展的本质。事实上,我现在已经确定了这个问题,因为用于在配置中定位工件的名称不是唯一的,并且将发布一个完整的描述来保存其他Gradle用户相同的hassl