Reading Gradle properties in settings.gradle.kts - android

So I'm using Gradle Kotlin DSL, I want to know if it's possible to read gradle properties inside settings.gradle.kts?
I have gradle.properties file like this:
nexus_username=something
nexus_password=somepassword
I've done it like this, but still can't read the properties.
dependencyResolutionManagement {
repositories {
mavenCentral()
google()
maven { setUrl("https://developer.huawei.com/repo/") }
maven { setUrl("https://jitpack.io") }
maven {
setUrl("https://some.repository/")
credentials {
val properties =
File(System.getProperty("user.home")+"\\.gradle", "gradle.properties").inputStream().use {
java.util.Properties().apply { load(it) }
}
username = properties["nexus_username"].toString()
password = properties["nexus_password"].toString()
}
}
}
}

You can access values set in gradle.properties in both build.gradle.kts and settings.gradle.kts using delegate properties (Kotlin DSL only, because delegate properties is a Kotlin feature!).
gradle.properties
kotlin.code.style=official
# Your values here
testValue=coolStuff
build.gradle.kts
val testValue: String by project
settings.gradle.kts
val testValue: String by settings

You can access gradle parameters using providers (since 6.2)
val usernameProvider = providers.gradleProperty("nexus_username")
val passwordProvider = providers.gradleProperty("nexus_password")
dependencyResolutionManagement {
repositories {
maven {
setUrl("https://some.repository/")
credentials {
username = usernameProvider.getOrNull()
password = passwordProvider.getOrNull()
}
}
}
}
To work on Groovy, you need to replace the variable declaration with:
def usernameProvider = providers.gradleProperty("nexus_username")
def passwordProvider = providers.gradleProperty("nexus_password")
Based on answer

Related

gradle kotlin dsl: how to create a shared function which uses a plugin class?

A simplified child module build.gradle.kts:
plugins {
id("com.android.library")
kotlin("android")
}
android {
androidComponents.beforeVariants { it: com.android.build.api.variant.LibraryVariantBuilder ->
it.enabled = run {
// logic to calculate if
it.productFlavors[0].second == "flavor" && it.buildType == "debug"
}
}
}
Is it possible to extract function for calculation of enabled state of buildVariant?
fun calculateIsEnabled(lvb: com.android.build.api.variant.LibraryVariantBuilder): Boolean {
return lvb.productFlavors[0].second == "flavor" && lvb.buildType == "debug"
}
I tried to declare the function in the root build.gradle.kts but I don't know how to access it from submodule and if it is possible at all
I tried to declare it in buildSrc module, but com.android.build.api.variant.LibraryVariantBuilder is undefined here because the plugin com.android.library is not present here and I think it is not allowed and/or meaningless
So, the question is: where to declare a shared function that uses types defined in a gradle plugin and need to be accessible in all submodules of type android library?
After several tries I solved it:
buildSrc/build.gradle.kts
repositories {
google()
mavenCentral()
}
plugins {
`kotlin-dsl`
}
dependencies {
// important: dependency only in simple string format!
implementation("com.android.tools.build:gradle:7.2.0-alpha03")
}
buildSrc/src/main/kotlin/Flavors.kt
import com.android.build.api.variant.LibraryVariantBuilder
import com.android.build.api.variant.ApplicationVariantBuilder
private fun isFlavorEnabled(flavor1: String, buildType: String): Boolean {
return flavor1 == "flavor" && buildType == "debug"
}
fun isFlavorEnabled(lvb: LibraryVariantBuilder): Boolean {
// productFlavors are pairs of flavorType(dimension) - flavorName(selectedFlavor)
return lvb.run { isFlavorEnabled(productFlavors[0].second, buildType ?: "") }
}
fun isFlavorEnabled(avb: ApplicationVariantBuilder): Boolean {
return avb.run { isFlavorEnabled(productFlavors[0].second, buildType ?: "") }
}
In library/build.gradle.kts and app/build.gradle.kts
android {
androidComponents.beforeVariants {
it.enabled = isFlavorEnabled(it)
}
}

Android - gradle script or function for duplicate maven project repository template

In my top-level build.gradle file for my Android project, I have to import several maven project repositories. The structure looks like this:
allprojects {
repositories {
google()
jcenter()
// How can I avoid this duplicate code block?
maven {
url "https://my_maven_project_url"
credentials(HttpHeaderCredentials) {
def jobToken = System.getenv("CI_JOB_TOKEN")
if (jobToken == null || jobToken.empty) {
name = "Private-Token"
value = "myAccessToken"
} else {
name = "Job-Token"
value = jobToken
}
}
authentication {
header(HttpHeaderAuthentication)
}
}
url "https://my_maven_project_url" and "myAccessToken" are the 2 things I need to pass in for each project. Can I write a script or a function that basically does the maven { ... } portion as a template and I just pass those 2 values in for each project?
The issue is that I think in a function we would need to create the maven { ... } portion programmatically instead of in the template form like shown above, but I may be understanding incorrectly...
You can write method like this
ext.myMethod = { param1, param2 ->
// Method body here
}
and call method
myMethod('param1', 'param2')

How to write a custom mavenArtifactRepositoryContainer?

In my Android project I am maintaining the URL to a local Maven server in a few places in build.gradle files:
buildscript {
repositories {
maven { url "https://example.com/nexus/content/groups/com.example.android.public/" }
}
}
I also maintain dependencies in a Kotlin class within the buildSrc folder:
object Plugins {
private object Versions {
const val android = "3.4.2"
}
const val android = "com.android.tools.build:gradle:${Versions.android}"
}
Is there a way I can define a mavenCompany variable in the buildSrc Kotlin file and invoke it from the build.gradle file(s) in my modules? Basically, I want the same as mavenLocal(). One of the related files is org.gradle.api.artifacts.ArtifactRepositoryContainer which defines a few constants:
public interface ArtifactRepositoryContainer extends
NamedDomainObjectList<ArtifactRepository>,
Configurable<ArtifactRepositoryContainer> {
String DEFAULT_MAVEN_CENTRAL_REPO_NAME = "MavenRepo";
String DEFAULT_MAVEN_LOCAL_REPO_NAME = "MavenLocal";
String MAVEN_CENTRAL_URL = "https://repo.maven.apache.org/maven2/";
String GOOGLE_URL = "https://dl.google.com/dl/android/maven2/";
I could not figure out how to write my own.

Refactor maven block in gradle

I'm working on an android project, and have a number of custom repositories using the same credentials:
repositories {
maven {
url "<url1>"
credentials {
username = "<username>"
password = "<password>"
}
}
maven {
url "<url2>"
credentials {
username = "<username>"
password = "<password>"
}
}
}
Is there a way to define a method (block?) so that I can define the username and password once and not have to repeat it every time? I'd like to be able to do:
repositories {
customMaven { url "<url1>"}
customMaven { url "<url2>"}
}
Apologies if I'm using terms incorrectly here - gradle syntax is somewhat of a mystery to me.
First answer provided by #ToYonos will work fine, but if you are looking for a solution based on a configuration block, you can use the method MavenArtifactRepository maven(Action<? super MavenArtifactRepository> action) from RepositoryHandler class (see here), as follows:
// a Closure that builds an Action for configuring a MavenArtifactRepository instance
def customMavenRepo = { url ->
return new Action<MavenArtifactRepository>() {
void execute(MavenArtifactRepository repo) {
repo.setUrl(url)
repo.credentials(new Action<PasswordCredentials>() {
void execute(PasswordCredentials credentials) {
credentials.setUsername("<username>")
credentials.setPassword("<password>")
}
});
}
};
}
// usage
repositories {
jcenter()
maven customMavenRepo("http://company.com/repo1")
maven customMavenRepo("http://company.com/repo2")
maven customMavenRepo("http://company.com/repo3")
}
EDIT from comments below: solution will Closure would look as follow. I think the use of curry method (see Currying closure) is needed here, but maybe there are other ways to simplify...
// one closure with URL as parameter
ext.myCustomMavenClosure = { pUrl ->
url pUrl
credentials {
username = "<username>"
password = "<password>"
}
}
// helper function to return a "curried" closure
Closure myCustomMaven (url){
return myCustomMavenClosure.curry(url)
}
repositories {
// use closure directly
maven myCustomMavenClosure.curry ("http://mycompany.com/repo1")
// or use helper method
maven myCustomMaven("http://mycompany.com/repo2")
}
Gradle is all about this kind of customization :
repositories {
['<url1>', '<url2>'].each { u ->
maven {
url u
credentials {
username = "<username>"
password = "<password>"
}
}
}
}

Gradle dynamic flavor

I would like to create dynamic flavors from the directory tree.
It works great!
But Android Studio uses gradle in its tmp file like:
/home/svirch_n/.IntelliJIdea14/system/compile-server
and my script doesn't work anymore because it uses relative paths like this:
Closure getFlavors = { rootDir, basePackage ->
def result = [:]
new File("$rootDir").eachDir() { dir ->
def name = dir.getName()
if ("$name" != "main")
result.put("$name", "$basePackage.$name")
}
return result
}
// This is an ugly closure.
// If I can get rid of this, my problem will be solved
Closure getSrcPath = {
if (System.getProperty("user.dir").split("/").last() == "app") {
return "src"
} else {
return "app/src"
}
}
android {
...
def myFlavors = getFlavors(getSrcPath(), "com.example.app")
productFlavors {
myFlavors.each { flavorName, flavorPackage ->
"$flavorName" {
applicationId "$flavorPackage"
}
}
}
}
Do you have an idea how to solve this?
Thanks in advance for your help
P.S: I want dynamic flavors cause my git project has public and private repositories and not everyone can have all the flavors but I want them to compile anyway.
Assuming I am in the subproject 'app', I can use:
project(":app").getProjectDir().getPath()

Categories

Resources