Is possible to replace class files into a jar keeping the MANIFEST file with Gradle?
I need to do it to apply a patch from the vendor that give me only the class files.
Id tried this:
task applayPatch(type: Jar) {
destinationDir = new File("${rootProject.projectDir}/libs/tool")
archiveName = "myfile.jar"
from(zipTree("${rootProject.projectDir}/libs/myfile.jar")) {
exclude "com/tool/frontoffice/partymanager/partysearch/DynamicPartySearchWidget.class"
}
from ("${rootProject.projectDir}/point-release/FFO-33758/com/fineos/frontoffice/partymanager/partysearch") {
include "MyClass.class"
}
}
but didn't work giving me a jar with an empty MANIFEST and only the class MyClass.class
Try using a task of type Zip instead of Jar to avoid having Gradle generate a new manifest for you.
task patchedJar(type: Zip, dependsOn: jar) {
extension 'jar'
from(zipTree(jar.archivePath)) {
exclude '**/MyClass.class'
}
from("patches/dir") {
include 'com/foo/package/MyClass.class'
}
}
Take note that by default this puts the resulting jar in build/distributions. Simply change the destinationDir property if you would like the output somewhere else.
Related
I want to create automatic crossplatform installation builder for my project. For this reason I made this file myprojectpackage.qbs:
Product {
type: "mypackage"
Depends { name: "myproject" } // <- this one has type "application"
Depends { name: "applicationpackage" }
}
applicationpackage.qbs uses some submodules and looks like:
Module {
name: "applicationpackage"
Depends { name: "qtlibsbinariespackage" }
Depends { name: "3rdpartybinariespackage" }
Depends { name: "resourcepackage" }
}
All these modules try to find something and copy to package directory. After they finish, I have a folder with a portable version of application. Every module of this group have typical structure:
Module {
name: "somepackage"
Rule {
condition: qbs.targetOS.contains("windows")
multiplex: true
alwaysRun: true
inputsFromDependencies: ["application"]
Artifact {
filePath: "Copied_files.txt"
fileTags: "mypackage"
}
prepare: {
var cmdQt = new JavaScriptCommand()
// prepare paths
cmdQt.sourceCode = function() {
// copy some files and write to Copied_files.txt
}
return [cmdQt]
}
}
}
After portable folder package complete, I want to make a zip archieve. So, I need another Module, which will run after package modules. I think, that only way to do like this is taking .txt files, that were created by modules in applicationpackage, as inputs for another Rule.
I have tried a lot of things (FileTaggers, outputFileTags etc.), but noone worked properly. So is there any way to do make modules work in pipeline as I want to do?
Do I understand correctly that you want to "merge" the contents of the txt files tagged "mypackage" into the archive, i.e. everything listed in all the files is supposed to end up there?
If so, then you simply need a "top-level" rule that does the aggregation. Your existing rules would tag their outputs as e.g. "mypackage.part" and then a multiplex rule would take these as inputs and create a "mypackage" artifact.
Note that there is the archiver module (https://doc.qt.io/qbs/archiver-module.html) that can do the final step of creating the package for you from the aggregated txt file.
For a couple of years, I have been releasing updates to a modest app on a yearly basis -- just before the summer swim league starts up.
In the past, I have specified the various icons (volume, app, etc.) by placing them in the package/macosx/ folder. The filenames, MyApp-volume.icns etc., matched the <fx:application name="MyApp" .../> and everything worked just fine.
But starting with this year's build and deployment, the app's name will contain the year -- i.e., MyApp 2016. However, I don't want to be changing the icon filenames each year; I would like to keep them as they are (MyApp-volume.icns, MyApp.icns).
Is there a way to tell the Java packager to use a specific icon filename, one that is different from that of the app name or title? (I have looked at Oracle docs, but I don't see anything.)
-Bicon=<path to icon relative to project resourses>
is this what you looking for?
or you could just add it to your main app Stage.
hope it is usefull
As I wrote in my first comment to my question, javapackager doesn't have an option to do this.
Here's the solution that I worked out:
Create a new folder at the same level as the folder package (this doesn't refer to Java package but to Custom Resources). Name the new folder package-base.
Move the macosx and windows folders from package to package-base. (I don't produce an executable for Linux because none of my users use Linux.) Now, the package folder is empty.
In my build script, I added a step which, for every build that produces a "self-contained application package" (Oracle's terminology), cleans the package folder, and then copies the contents of package-base to package.
The files are renamed as they are copied to include the desired wording -- in my case, that means the year is appended to the filename. For example, MyApp-volume.icns when copied is renamed MyApp-2018-volume.icns.
Here are the relevant Gradle snippets:
import org.gradle.internal.os.OperatingSystem
...
def getYear() {
new Date().format('yyyy')
}
...
ext {
...
year = getYear()
appNameBase = "MyApp"
appName = appNameBase + " " + year
...
}
...
task macCleanPackage {
doLast {
if (OperatingSystem.current().isMacOsX()) {
delete fileTree(dir: "./package/macosx", include: "*.*")
}
}
}
task macCopyAndRenamePackageResources {
dependsOn macCleanPackage
doLast {
if (OperatingSystem.current().isMacOsX()) {
def toDir = "./package/macosx"
copy {
from './package-base/macosx'
into "${toDir}"
include "*${appNameBase}*.*"
rename { String fileName -> fileName.replace("$appNameBase", "${appName}") }
}
ant.replaceregexp(file: "${toDir}/${appName}-dmg-setup.scpt", match:"${appNameBase}", replace:"${appName}", flags:'g')
}
}
}
task windowsCleanPackage {
doLast {
if (OperatingSystem.current().isWindows()) {
delete fileTree(dir: "package/windows", includes: ["*.bmp", "*.ico", "*.iss"])
}
}
}
task windowsCopyAndRenamePackageResources {
dependsOn windowsCleanPackage
doLast {
if (OperatingSystem.current().isWindows()) {
def toDir = "./package/windows"
copy {
from './package-base/windows'
into "${toDir}"
include "*${appNameBase}*.*"
rename { String fileName -> fileName.replace("$appNameBase", "${appName}") }
}
// Replace app name in iss setup script to include year.
def issFilename = "./package/windows/${appName}.iss"
ant.replaceregexp(file: "${issFilename}", match: "${appNameBase}", replace: "${appName}", flags: "g")
ant.replaceregexp(file: "${issFilename}", match: "AppCopyright=Copyright (C)", replace: "AppCopyright=Copyright (C) ${year}", byline: "on")
ant.replaceregexp(file: "${issFilename}", match: "AppVersion=", replace: "AppVersion=${year} build ${buildNumber}", byline: "on")
ant.replaceregexp(file: "${issFilename}", match: "OutputBaseFilename=.*", replace: "OutputBaseFilename=${appName}-(build ${buildNumber})", byline: "on")
}
}
}
I don't just change filenames.
For the OS X release, ant.replaceregexp is used to modify the app's name in the custom AppleScript file.
For the Windows release, ant.replaceregexp is used extensively to replace version numbers, copyright, as well as the application's name (including the year) in the InnoSetup configuration file.
It may seem like a lot of extra work, but once the script is written, it just works.
I am providing below what I have at the moment.
In the example below, the Jar task produces a Jar with a Zip file ( artifact from another project ) inside it.
But, My ultimate aim is to produce an uber jar that will self contain it's dependencies. I came by Shadow plugin and it seems a clean solution.
I tried to tell my ShadowJar task to include the Zip file - but it doesn't work. See commented out ShadowJar section.
So, what I have now is to create the shadow jar but then producing another jar that includes the contents of shadow jar and the zip. I can see that this path is full of gotchas (I had to enforce the Manifest again) ....
Ideally I would think that there is an way to include a artifact from different configuration in Shadow Jar and it is my limitation of Gradle knowledge that is failing here.
buildscript {
repositories { jcenter() }
dependencies {
classpath 'com.github.jengelman.gradle.plugins:shadow:1.1.1'
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'com.github.johnrengelman.shadow'
project.version = rootProject.ext.deployerVersion
// In this section you declare where to find the dependencies of your project
repositories {
// Use 'maven central' for resolving your dependencies.
// You can declare any Maven/Ivy/file repository here.
mavenCentral()
}
configurations {
pkg
}
// In this section you declare the dependencies for your production and test code
dependencies {
compile project(':Concenter.Foundation')
pkg project(path: ':Concenter.Platform', configuration: 'pkg')
// Declare the dependency for your favourite test framework you want to use in your tests.
// TestNG is also supported by the Gradle Test task. Just change the
// testCompile dependency to testCompile 'org.testng:testng:6.8.1' and add
// 'test.useTestNG()' to your build script.
testCompile 'junit:junit:4.11'
}
jar {
dependsOn ':Concenter.Platform:distZip'
manifest {
attributes(
'Main-Class': 'aqilco.concenter.deployer.Deployer',
)
}
from configurations.pkg
}
/*
shadowJar {
dependsOn ':Concenter.Platform:distZip'
manifest {
attributes(
'Main-Class': 'aqilco.concenter.deployer.Deployer',
)
}
from configurations.pkg
}
*/
task pkg(type: Jar) {
dependsOn ':Concenter.Platform:distZip'
dependsOn 'shadowJar'
archiveName = jar.baseName + "-" + jar.version + "-pkg." + jar.extension
from zipTree(shadowJar.archivePath)
from configurations.pkg
manifest {
attributes(
'Main-Class': 'aqilco.concenter.deployer.Deployer',
)
}
}
I am interested in building a single jar containing all the module dependencies and external jars in a single executable jar file which I will be able to run with java -jar myApp.jar.
I have module A which is dependent on module B.
Currently I'm using gradle, and my build.gradlescript looks like this:
apply plugin: 'fatjar'
description = "A_Project"
dependencies {
compile project(':B_Project')
compile "com.someExternalDependency::3.0"
}
When I build it through gradle command: clean build fatjar a fat jar 'A.jar' is created as expected.
But running it with as I written above results in:
no main manifest attribute, in A.jar
How can I modify my build.gradle file and specify the main class, or the manifest?
I have figured it out myself:
I've used uberjar Gradle task.
now my build.gradle file looks like this:
apply plugin: 'java'
apply plugin: 'application'
mainClassName = 'com.organization.project.package.mainClassName'
version = '1.0'
task uberjar(type: Jar) {
from files(sourceSets.main.output.classesDir)
from {configurations.compile.collect {zipTree(it)}} {
exclude "META-INF/*.SF"
exclude "META-INF/*.DSA"
exclude "META-INF/*.RSA"
}
manifest {
attributes 'Main-Class': 'com.organization.project.package.mainClassName'
}
}
dependencies {
compile project(':B_Project')
compile "com.someExternalDependency::3.0"
}
and now I i use it with the command:
clean build uberjar
and it builds one nice runnable jar :)
To get it working using fatjar, I added a manifest section in fatJar task:
task fatJar(type: Jar) {
baseName = project.name + '-all'
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
with jar
manifest {
attributes 'Implementation-Title': 'Gradle Quickstart', 'Implementation-Version': version
attributes 'Main-Class': 'com.organization.project.package.mainClassName'
}
}
I am trying to add a web module in an Ear file. I put it in my customized deployment descriptor using webModule(":wars/myweb","/mywebapp"). It is not including the war file in the ear file. It is just adding a entry in the generated application.xml with these details.
Can you please help in including a web module in ear, using customized deployment descriptor?
My ear task looks like this in build.gradle
ear {
libDirName ''
deploymentDescriptor {
// custom entries for application.xml:
// fileName = "application.xml" // same as the default value
version = "1.4" // same as the default value
applicationName = "myapp"
initializeInOrder = true
displayName = "myear" // defaults to project.name
description = "EAR for the basic package" // defaults to project.description
webModule(':wars/myweb','/mywebapp')
}
}
My settings.xml in the same dir as build.gradle looks like this
include "wars/myweb"
Appreciate your help.
I use this way to tie war dependencies to the webModules. The warMap provides a connection between the artifact id and the context path:
Map warMap = [
'my-war': 'contextpath',
'my2-war': 'contextpath2'
}
dependencies {
warMap.each {
deploy project(":$it.key")
}
}
ear {
deploymentDescriptor {
warMap.each {
webModule(it.key + '-' + project.version + ".war", it.value)
}
}
}