Separate built jar and dependency jars - kotlin

The application plugin copies the start scripts into 'bin', and copies the built jar and all dependencies into 'lib' (see here). How can I separate the dependency jars and the built jar. I would like to have the build jar in the root folder and change the classpath correspondingly. Tried the change "applicationDistribution" property with include/exclude but this does not work.
I'm able to do:
tasks.installDist {
from("$buildDir/libs") {
include("myLib*.jar")
}
doLast {
delete(fileTree("$buildDir/install/${project.name}/lib") {
include("myLib*.jar")
})
}
}
But this only works for installDist and does no reflect to distZip. How can I move the a jar from the 'lib' folder so that it will work for installDist, distZip and changes the classspath?
Classpath could probably be changed in tasks.startScripts, but therefor the jar should move correctly.
I'm using the Gradle Kotlin DSL.
Desired output would be something like this, where myBuilt.jar is moved from lib to root:
myProgram/
├── lib/
│ ├── lib1.jar
│ ├── lib2.jar
│ ├── ...
├── myProgram.bat
└── myBuilt.jar

Found a solution. I used eachFile (which I was not aware of before) an changed the destination directory:
distributions {
main {
contents {
eachFile {
if (sourceName.matches( Regex("myLib.*\\.jar"))) {
relativePath = RelativePath(true,
*relativePath.parent.replaceLastName(sourceName).segments)
}
}
}
}
}
The classpath for the start scripts has to be changed manually because CreateStartScript hard-coded the classpaths and appends "lib/" (see here).
var jarFileName = ""; // is filled in tasks.jar with archiveFileName
tasks.startScripts {
doLast {
val windowsScriptContent = windowsScript.readText().replace("%APP_HOME%\\lib\\$jarFileName",
"%APP_HOME%\\$jarFileName")
windowsScript.writeText(windowsScriptContent)
}
}
Alternative would be to make a runnable jar: insert classpath into manifest and modify starting script template.

Related

How to tell Vite to only build a specific component in library mode?

I have a Vue project that is able to load other Vue components bundled as .mjs files. I want to develop all those pluggable components inside a repository but instead of distributing all pluggable components in a single build I want to tell Vite which component to build. If that works I don't need to think about dealing with a Monorepo, Multirepo or something else.
After creating the library project I thought about organizing each plugin into a separate folder in the src directory
.
└── src
├── textWithBlueBackground
| ├── index.ts ( importing "TextWithBlueBackground" and exporting as "Renderer" )
| └── TextWithBlueBackground.vue
└── textWithRedBackground
├── index.ts ( importing "TextWithRedBackground" and exporting as "Renderer" )
└── TextWithRedBackground.vue
The problem is that I need to switch to library mode but I don't know what to pass in there
build: {
lib: {
entry: resolve(__dirname, "./src/index.ts"), // this is wrong
name: "Renderer",
fileName: "renderer",
},
rollupOptions: {
external: ["vue"],
output: {
globals: {
vue: "Vue",
},
},
},
},
After fixing that... Is it possible to tell Vite ( via CLI flag ) to only build a specific sub directory? E.g.
vite build ./src/{folderName}
If that's not possible I could create an index.ts in src
import { Renderer as TextWithBlueBackground } from "./textWithBlueBackground";
import { Renderer as TextWithRedBackground } from "./textWithRedBackground";
export { TextWithBlueBackground, TextWithRedBackground }
but how can I tell Vite to only build a specific component then?
The generated .mjs file should only contain the desired component, preferably as "Renderer" but I think the component name should be fine too.

How to reuse dependency versions in subprojects for Kotlin DSL?

I have a multi module Gradle project with Kotlin DSL as build file. Inside of the root build.gradle.kts there is dependencies section for root and subprojects with its own dependencies. I would like to create a variable that can keep version of some dependency and be used in all modules in build.gradle.kts.
Root build.gradle.kts looks like:
buildscript {
// ...
}
plugins {
// ...
}
subprojects {
// repositories, plugins, tasks, etc.
dependencies {
implementation("com.fasterxml.jackson.core:jackson-databind:2.10.4")
}
Submodule common-module/build.gradle.kts
dependencies {
implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-csv:2.10.4")
}
I would like to declare a variable and assign the version for these dependencies as a value and only reuse it on modules. Some thing like implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-csv:${jacksonVersion}").
How can I do that?
The most modern, type-safe solution of this problem is using version catalogs.
Update Gradle to 7.2.
Add this to your settings.gradle or settings.gradle.kts:
enableFeaturePreview("VERSION_CATALOGS")
gradle/libs.versions.toml:
[versions]
jackson = "2.12.5"
[libraries]
jackson-databind = { module = "com.fasterxml.jackson:jackson-databind", version.ref = "jackson" }
jackson-dataformat-csv = { module = "com.fasterxml.jackson.dataformat:jackson-dataformat-csv", version.ref = "jackson" }
Add dependencies like implementation(libs.jackson.dataformat.csv) in all the subprojects.

How to test custom gradle plugin both with JUnit and manually in same sample project

My goal is to have this project setup:
example-gradle-plugin
├── build.gradle
└── src
├── main
│   ├── java
│   │   └── com ....
└── test
├── java
│   └── example
│   └── integrationtest
│ │ # GradleRunner.create().withProjectDir(testProjectPath.toFile()).withPluginClasspath()
│   └── SimpleProjectRegressionTest.java //
└── resources
└── simple
│ # plugins { id "example-gradle-plugin" }
├── build.gradle
│ # // includeBuild ../../../../example-gradle-plugin
└── settings.gradle
So the folder src/test/resources/simple is both used from a JUnit test, but as well can be used to run gradle commands from the command line using the composite build approach.
So this should work
cd src/test/resources/simple
gradle build
And this unit test should also work:
#Test
public void testBuildSample() {
final ClassLoader classLoader = ProjectSetupHelper.class.getClassLoader();
final Path sampleSourceRootPath = Paths.get(classLoader.getResource("simple").toURI());
final BuildResult result = GradleRunner.create()
.withProjectDir(sampleSourceRootPath.toFile())
.withArguments("build")
.withPluginClasspath()
.build();
}
However, there is a caveat when running JUnit, the custom-plugin-sources are referred to in 2 different ways at the same time:
GradleRunner.create().withProjectDir(testProjectPath.toFile()).withPluginClasspath() means to add project custom plugin files to the classpath for running the build during the unit test
In src/test/resources/simple/settings.gradle, the includeBuild ... command also refers to the custom plugin.
Is there an easier or cleaner way to achieve the above: Having a sample project with composite build that can be used from the commandline to verify local changes to the plugin, and using that sample project also in a unit test of the plugin?
Currently in the unit test I copy the sample folder to a temporary folder without settings.gradle to avoid such complications.
A little late to the party, but here is what I did.
I wrote a custom gradle plugin and was able to test it successfully with JUnit.
MyCustomPlugin.java
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.artifacts.dsl.DependencyHandler;
public class MyCustomPlugin implements Plugin<Project>
{
#Override
public void apply(Project project)
{
DependencyHandler dependencyHandler = project.getDependencies();
dependencyHandler.add(JavaPlugin.IMPLEMENTATION_CONFIGURATION_NAME, "org.apache.commons:commons-lang3:3.12.0");
}
}
MyCustomPluginTest.java
import org.gradle.api.Project;
import org.gradle.testfixtures.ProjectBuilder;
import org.junit.jupiter.api.Test;
import static org.gradle.internal.impldep.org.junit.Assert.assertTrue;
public class MyCustomPluginTest {
#Test
public void testCustomPlugin()
{
Project project = ProjectBuilder.builder().build();
// Java plugin required for IMPLEMENTATION task in the custom plugin
project.getPluginManager().apply("java");
project.getPluginManager().apply("com.mycustomplugin");
assertTrue(project.getPluginManager().hasPlugin("com.mycustomplugin"));
}
}
Sources:
https://docs.gradle.org/current/userguide/custom_plugins.html#sec:writing_tests_for_your_plugin
https://www.baeldung.com/gradle-create-plugin

Apply local jar-plugin without using maven

I'd like to load my custom plugin from a local jar. The jar file compiles fine and when I check it, the manifest and the plugin class are there.
gradlePlugin {
plugins {
create("asdf") { // <-- I really call it "asdf" in the kts script
id = "asdf"
implementationClass = "pluginTest.TestPlugin"
version = "1.4.0"
}
}
}
The plugin doesn't do anything useful yet as it should be a proof-of-concept to make sure it actually works at all:
class TestPlugin : Plugin<Project> {
override fun apply(project: Project) {
println("Hallo TestPlugin!")
}
}
I then try to use it like this in another project:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath(files("..\\..\\path\\to\\pluginTest.jar"))
}
}
plugins {
id("asdf") version "1.4.0"
}
but it keeps telling me that:
Plugin [id: 'asdf', version: '1.4.0'] was not found in any of the following sources:
What am I missing here? I use Gradle v6.5.
When you have the plugin jar on the classpath, you can't have a version number in the plugin application. I guess this is because you can't have multiple jars with different versions on the classpath in the first place, so specifying a version here doesn't make any sense (except perhaps to validate that you are using the correct one). This won't fix the problem, but it is a start.
To be honest, I don't know why your approach still won't work. The buildscript block is supposed to set up dependencies for that particular script, and that should make the plugin visible to it. It doesn't for some reason.
Perhaps this is a bug or perhaps this is just an undocumented limitation on the use of the plugin {} block. Maybe you could ask over at the Gradle forums or create an issue for it. However, there are workarounds that don't involve publishing to a (local) Maven repository, which I agree can be a bit annoying.
If you use "apply from" instead of "plugins {}", it works. For some reason, the former can see the buildscript classpath whereas the latter can't:
// build.gradle (Groovy DSL)
buildscript {
dependencies {
classpath(files("..\\..\\path\\to\\pluginTest.jar"))
}
}
apply from: "asdf"
Alternatively, move the buildscript plugin from the build.gradle file to the settings.gradle file. This makes is available to the entire build classpath and will make it work with the plugin block:
// settings.gradle (Groovy DSL):
buildscript {
dependencies {
classpath(files("..\\..\\path\\to\\pluginTest.jar"))
}
}
// build.gradle (Groovy DSL)
plugins {
id("asdf")
}
Lastly, just in case you haven't considered it already, you may be able to add the plugin as a composite build. This will create a source dependency to the plugin and has the advantage that transitive dependencies will be carried over (the ones you put in the plugin's own dependency block) and that it will be built automatically if not up-to-date. I use this approach for integration testing my plugins and also sometimes to apply them to my other real projects to test them in a bigger setting before publishing new versions.
Do that with either:
// settings.gradle (Groovy DSL):
includeBuild("..\\..\\path\\to\\plugin")
// build.gradle (Groovy DSL):
plugins {
id("asdf")
}
Or without hard-coding it in the build (so you can dynamically switch between local and published versions):
// build.gradle (Groovy DSL):
plugins {
id("asdf") version "1.4.0" // Version is optional (will be ignored when the command line switch below)
}
// Run with:
./gradlew --include-build "..\\..\\path\\to\\plugin" build
With #BjørnVester's answer I figured it out!
You need to put the buildscript in settings.gradle.kts as it doesn't get executed in the build.gradle.kts even when placed before plugins.
buildscript {
repositories {
flatDir {
dirs("..\\reusable-kotlin\\build\\libs") // <-- folder with jars
}
}
dependencies {
classpath("com.hedev.kotlin:reusable-kotlin:1.4.0")
}
}
But there's a catch! You must use the file-name of the jar in the classpath's name identifier that goes like this:
group:file-name:version
The file gradle will look for will be file-name-version.jar or file-name.jar which you'll see in the error message if you make a mistake (I added the _ on purpose to trigger the error):
Could not resolve all artifacts for configuration 'classpath'.
Could not find com.hedev.kotlin:reusable-kotlin_:1.4.0. Searched in the following locations:
- file:/C:/some/path/reusable-kotlin/build/libs/reusable-kotlin_-1.4.0.jar
- file:/C:/some/path/reusable-kotlin/build/libs/reusable-kotlin_.jar
In order for this to work I also had to add the group property to the plugin itself:
gradlePlugin {
plugins {
create("asdf") {
id = "asdf"
implementationClass = "com.hedev.kotlin.gradle.TestPlugin"
version = "1.4.0"
group = "com.hedev.kotlin"
}
}
}
Finally you can apply it in build.gradle.kts with (no version here):
plugins {
id("asdf")
}

How to rewrite urls of images in vendor CSS files using Grunt

I am trying to move frontend dependencies out of the version control system. A combination of Bower.io and Grunt should be able to do this.
A problem however occurs that I am yet unable to solve with bundling multiple vendor libraries. For example assume I have the following directory structure where the components directory is the directory that Bower.io saves the dependencies in:
├── assets
└── components
├── bootstrap
│   ├── img
│   │   └── glyhs.gif
│   └── less
│   └── bootstrap.css
└── jquery-ui
├── css
│   └── style.css
└── images
├── next.gif
└── prev.gif
Now assume I want to bundle both jQuery's style.css and Bootstrap' bootstrap.css. I will save this bundled file in assets/bundled.css.
However in this file the references to the original images (../images/next.gif and ../img/glyhs.gif) are incorrect. They will have to be rewritten in order to work (so ../images/next.gif => ../components/jquery-ui/images/next.gif). I believe(d) this rewriting of URLs is something Grunt should be able to do. But I can not seem to get this to work using the cssmin/less/copy tasks. For example the following Grunt setup (only moving 1 file) fails to work:
module.exports = function (grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
less: {
options: {
compile: false,
relativeUrls: true
},
bootstrap: {
src: 'components/bootstrap/less/bootstrap.less',
dest: 'assets/bootstrap.css'
}
}
});
grunt.loadNpmTasks('grunt-contrib-less');
grunt.registerTask('dist-css', ['less']);
};
Either:
Have I misconfigured Grunt or done something wrong?
Or is the workflow I am describing simply not the right one and should I use another one instead.
Thanks!
You probably wat to take a look at this grunt package https://github.com/Ideame/grunt-css-urls.
This package seems to be intended to solve exactly your problem.
Edit: after looking at this plugin I didn't like the idea of rewriting my markup in order to make my build process smoother. So I ended up writing my own tiny function which does the rewrite for me.
I use grunt's concat plugin for bundling my css files. Good thing about this plugin is that it suports file processing function before concatenation. Now my gruntfile looks like this:
grunt.initConfig({
concat: {
options: {
separator: '\n',
process: function (src, filepath) {
var cssPatt = new RegExp('app(\/.*\/).*\.css$');
//filter out everithing except css files
var file = cssPatt.exec(filepath);
if (file) {
var urlPatt = /url\(\'(.*)\'\)/g;
console.log('In file: ' + filepath);
//replace every url(...) with its absolute path
return src.replace(urlPatt, function (match, p1) {
console.log(' * ' + match + ' -> ' + 'url(\'' + file[1] + p1 + '\')');
return 'url(\'' + file[1] + p1 + '\')';
});
}
return src;
}
},
}
Just for reference: there is now a solution readily available. I posted this same issue to the CleanCss grunt plugin, and they have accepted it and published this behaviour in their new 1.1 release.
You can find the issue on the GitHub tracker here: https://github.com/GoalSmashers/clean-css/issues/129
This library makes it possible to either use absolute rewriting (from a root directory) or alter relative image paths based on a new output directory. Look for the --root or --ouput directives.
Thanks for the tips and answers people!
You'll want to do some search/replace on your dist css file to generate the correct relative paths. There are a number of grunt plugins that can do this for you, personally I prefer grunt-replace. Set up your non compressed assets with variables and then produce a dist css with the URLs dynamically generated.. So:
body {
background:url(##IMG_PATH/background.jpg);
}
Becomes this in dist:
body {
background:url(path/to/background.jpg);
}
Hope this helps.