Android studio - build gradle - Illegal escape entry - gradle

I'm having an error [enter image description here][1]called 'Illegal escape character in string literal' when I tried to add the repositories in an android app's build Gradle to link a flutter module. How do I get rid of it?
String storageUrl = System.env.FLUTTER_STORAGE_BASE_URL ?: "https://storage.googleapis.com"
repositories {
maven {
url 'C:\Users\Acabes\AndroidStudioProjects\fresh_screen\build\host\outputs\repo'
}
maven {
url "$storageUrl/download.flutter.io"
}
}
It shows error in the line 'C:\Users\Acabes\AndroidStudioProjects\fresh_screen\build\host\outputs\repo'
[https://i.stack.imgur.com/pGFvy.png][1]:

You should use double \ on the directory
'C:\\Users\\Acabes\\AndroidStudioProjects\\fresh_screen\\build\\host\\outputs\\repo'

Related

Unable to publish jar to Gitlab package registry with gradle

I am trying to publish some jar artefacts on gitlab package registry but I get this error from the server :
Received status code 415 from server: Unsupported Media Type
Here is the publishing section of my build.gradle.kts :
publishing {
publications {
create<MavenPublication>("maven"){
artifact(tasks["bootJar"])
}
}
repositories {
maven {
url = uri("https://gitlab.com/api/v4/groups/my-group/-/packages/maven")
name = "Gitlab"
credentials(HttpHeaderCredentials::class) {
name = "Token"
value = System.getenv("CI_JOB_TOKEN")
}
authentication {
create<HttpHeaderAuthentication>("header")
}
}
}
}
In my gitlab-ci, I added a task for publish the artefacts :
deploy:
stage: deploy
script: gradle publish
only:
- master
Any help would be appreciated
Quick answer
Replace your publishing url pointing to the group-scope with the one pointing to the specific-package-repository, e.g. on gitlab.com:
https://gitlab.com/api/v4/projects/<your-project-id>/packages/maven
You need to replace <your-project-id> with your specific project-id of course.
Related to this a quote from docs.gitlab:
Note: In all cases, you need a project specific URL for uploading a package in the distributionManagement section.
Or in other words: Only the general repositories section can use your groups-url for searching other already published artifacts! (I also had to understand that). So:
you cannot publish to the group-package-store on gitlab, you can just search there.
Publication goes always to the project-specific package-store, which will then be visible at group-scope too.
Example gradle config (kotlin-dsl)
repositories {
mavenCenter()
jcenter()
// Here you USE the group api/v4 url for SEARCHING packages
maven {
name = "GitLab"
url = uri("https://gitlab.com/api/v4/groups/my-group/-/packages/maven")
credentials(HttpHeaderCredentials::class) {
name = "Job-Token"
value = System.getenv("CI_JOB_TOKEN")
}
authentication {
create<HttpHeaderAuthentication>("header")
}
}
}
publishing {
publications {
create<MavenPublication>("maven"){
artifact(tasks["bootJar"])
}
}
repositories {
maven {
// here your PROVIDE the PROJECT-URI for publishing your package
// in the project-specific package-space which is also visible at
// the group scope above
url = uri("https://gitlab.com/api/v4/projects/<your-project-id>/packages/maven")
name = "Gitlab"
credentials(HttpHeaderCredentials::class) {
name = "Job-Token"
value = System.getenv("CI_JOB_TOKEN")
}
authentication {
create<HttpHeaderAuthentication>("header")
}
}
}
}
More Info
There are multiple scenarios on how you may interact with the maven-repository-space on GitLab. The three switches are:
The place where you want to look for existing published packages
project-scope (https://.../api/v4/projects/<project-id>/packages/maven)
group-scope (https://.../api/v4/groups/<group-id>/-/packages/maven)
instance-scope (https://.../api/v4/packages/maven)
The authorization-method you want to use
PERSONAL_ACCESS_TOKEN
DEPLOY_TOKEN
CI_JOB_TOKEN
The place where your want to publish your package
this must always be a specific project-url (https://.../api/v4/projects/<project-id>/packages/maven)
I think the most important thing is to make sure you've enabled archives in your project:
Go to Project Settings
Expand Permissions
Switch on "Packages"
Apparently, there are also other reasons for the response status 415 Unsupported Media Type:
I ran into the same error message while trying to publish to the project repository. The error that I made was to use the URL-encoded path of the project instead of the project ID in the repository URL.
From the Gitlab documentation (emphasis added):
For retrieving artifacts, use either the URL-encoded path of the project
(like group%2Fproject) or the project's ID (like 42). However, only the
project's ID can be used for publishing.
This is the build.gradle.kts configuration that worked for me on my self-hosted Gitlab instance for publishing a Spring Boot fat JAR:
plugins {
/* ... other stuff ... */
`java-library`
`maven-publish`
}
publishing {
publications {
create<MavenPublication>("bootJava") {
artifact(tasks.getByName("bootJar"))
}
}
repositories {
maven {
val projectId = System.getenv("CI_PROJECT_ID")
name = "Project Name"
url = uri("https://gitlab.example.com/api/v4/projects/${projectId}/packages/maven")
credentials(HttpHeaderCredentials::class) {
name = "Job-Token"
value = System.getenv("CI_JOB_TOKEN")
}
authentication {
create<HttpHeaderAuthentication>("header")
}
}
}
}

How do I replace a Maven repository with a local directory after it is defined in a Gradle build?

I'm trying to write tests for a build process, so my unit test wants to replace the actual repository locations with local locations to avoid poisoning the real server. (Plus, I suppose, the person running the test might not have access to publish anyway.)
In the build itself:
publishing {
repositories {
maven {
name = 'snapshot'
url = "${artifactory_contextUrl}/libs-snapshot-local"
credentials {
username artifactory_user
password artifactory_password
}
}
maven {
name = 'release'
url = "${artifactory_contextUrl}/libs-release-local"
credentials {
username artifactory_user
password artifactory_password
}
}
}
}
In my test build, I'm trying to override it with this:
publishing {
repositories {
getByName('snapshot') {
url = uri('/tmp/local-repo/snapshots')
}
getByName('release') {
url = uri('/tmp/local-repo/release')
}
}
}
When I try to run the build, I get:
Execution failed for task ':publishMavenJavaPublicationToReleaseRepository'.
> Failed to publish publication 'mavenJava' to repository 'release'
> Authentication scheme 'all'(Authentication) is not supported by protocol 'file'
There are a lot of posts out on the web about this specific error, but it always seems to be people who accidentally put a file path in when they should have put a URI. I'm putting in a URI deliberately, though, so is there a way to get this to work?
I have also tried this:
publishing {
repositories {
clear()
maven {
name = 'snapshot'
url = uri('/tmp/local-repo/snapshots')
}
maven {
name = 'release'
url = uri('/tmp/local-repo/release')
}
}
}
That fails with:
A problem occurred configuring root project 'test-common-plugin1913987501683151177'.
> Exception thrown while executing model rule: PublishingPluginRules#publishing(ExtensionContainer)
> Cannot add task 'publishMavenJavaPublicationToSnapshotRepository' as a task with that name already exists.
I was surprised that deleting all the repositories doesn't also delete all the tasks they own. When I try to programmatically delete the task it's complaining about, Gradle claims that it doesn't exist.
Alright, I ended up having to read the source of Gradle (again), but I found a way to do it. Essentially you can directly set credentials back to null, like this:
publishing {
repositories {
getByName('snapshot') {
url = uri('/tmp/local-repo/snapshots')
configuredCredentials = null
}
getByName('release') {
url = uri('/tmp/local-repo/release')
configuredCredentials = null
}
}
}

setting credentials in gradle via maven-publish

I am using gradle v3.4 and have populated properties from a secrets.properties file (passed into project.ext) but when I use the variables in the credentials section, I get an error from nexus complianing about authentication issues which makes me believe the string interpolation is not working correctly. I can print the variable value just before the credentials section.
build.gradle
maven {
credentials {
println(project.nexusUsername) //prints the value
username '${project.nexusUsername}'
password '${project.nexusPassword}'
}
if (project.version.endsWith("-SNAPSHOT")) {
url "http://nexus.somewhere.com/repository/some-java-snapshot/"
} else {
url "http://nexus.somewhere.com/repository/some-java-release/"
}
}
Update
I updated the credentials section above to use double quotes (not single) but that did not solve the issue. Single quotes are String literals - if you need String interpolation, you need to use double quotes in groovy.
The issue was how the properties was specified in the external properties file. I was using double quotes for the String values in the properties file and that was resulting in authentication failures. Once I removed the double quotes from the external properties file, I was able to publish to nexus.
Incorrect external properties file setting
someUsername="someuser"
Correct external properties file setting
someUsername=someuser
build.gradle
publishing {
publications {
shadow(MavenPublication) {
from components.shadow
groupId project.group
artifactId project.artifactId
}
}
repositories {
maven {
credentials {
username project.someUsername
password project.somePassword
}
if (project.version.endsWith("-SNAPSHOT")) {
url project.someSnapshot
} else {
url project.someRelease
}
}
}
}
this works.
Single quotes denote a String literal without variable expansion;
Please use
username project.nexusUsername
password project.nexusPassword
Reference: http://docs.groovy-lang.org/latest/html/documentation/#_single_quoted_string

Get uri of published artifact using maven-publish gradle plugin

After a publish, I want to know what the url of the published artifact is (to use it in other gradle tasks for automated deployment).
Is there any way to capture this generated url?
#Hollerweger answer is probably the least hackish, but it's wrong in couple of ways:
AbstractPublishToMaven is the superclass of PublishToMavenLocal and PublishToMavenRepository. Extending it and printing a message saying artifact is published to Nexus is wrong, because that message is going to be printed even when publishing to the local Maven repo. The correct task class to use is PublishToMavenRepository that publishes to the remote repo.
There's no need to know the remote repo URL; publication has a repository property.
Putting it all together:
tasks.withType(PublishToMavenRepository) {
doFirst {
println("Publishing ${publication.groupId}:${publication.artifactId}:${publication.version} to ${repository.url}")
}
}
I found a local copy of a file called maven-metadata-remote.xml that gets uploaded. It is under this dir: build/tmp/publishMavenPublicationToNexusRepository/
Example:
$ cat build/tmp/publishMavenPublicationToNexusRepository/com/example/my.package/0.1.0-SNAPSHOT/maven-metadata-remote.xml
<?xml version="1.0" encoding="UTF-8"?>
<metadata>
<groupId>com.example</groupId>
<artifactId>my.package</artifactId>
<version>0.1.0-SNAPSHOT</version>
<versioning>
<snapshot>
<timestamp>20180326.191238</timestamp>
<buildNumber>36</buildNumber>
</snapshot>
<lastUpdated>20180326191238</lastUpdated>
</versioning>
</metadata>
So I was able to ingest that file by adding something like this to the bottom of the build.gradle file:
tasks.withType(PublishToMavenRepository) {
doLast {
def metadata_file_path = "build/tmp/publishMavenPublicationToNexusRepository/com/example/my.package/0.1.0-SNAPSHOT"
def metadata_XML = new File("${metadata_file_path}/maven-metadata-remote.xml").text
def metadata = new groovy.util.XmlSlurper().parseText(metadata_XML)
def BN = metadata.versioning.snapshot.buildNumber
def TS = metadata.versioning.snapshot.timestamp
println "INFO: uploaded version 0.1.0-${TS}-${BN}.pom to Nexus"
...
Sadly this information is unavailable via the gradle build system... What you can do is create a task that finalizes the publish task. Then have that task query the maven repository for the most recent build. Maven will look in the maven-metadata.xml file and return the <release> tag value or the most recent upload if that's missing. You can get the exact download url from the response's Location header.
Here is an example of how you would query a maven repo
$ curl -Is 'http://my.nexus.repo.com:8081/nexus/service/local/artifact/maven/redirect?r=Release&g=com.my.group.id&a=myArtifactId&v=RELEASE&p=war' | grep -Fi Location | cut -d' ' -f2
http://my.nexus.repo.com:8081/nexus/service/local/repositories/Release/content/com/my/group/id/myArtifactId/1.0.012/myArtifactId-1.0.012.war
Explaining the command
curl -Is http://<nexus-url>:<nexus-port>/nexus/service/local/artifact/maven/redirect?r=<nexus-repository>&g=<artifact-group-id>&a=<artifact-name>&v=<artifact-version>
curl
-I # only print return headers
-s # quiet output of curl's downloading progress
url params
r # nexus-repository name, tends to be Release or Snapshot
g # group id for the artifact
a # artifact id
v # artifact version or a link like RELEASE (don't use LATEST it's problematic)
## you can also supply classifier and extension if needed
c # artifact classifier
e # artifact extension
You can extend all maven publish tasks and compute the the url again:
I just needed the folder - For release artifacts you can also add the artifact at the end but I haven't found a good solution for SNAPSHOTs. The nexus base repo URL is expected to be known.
tasks.withType(AbstractPublishToMaven) {
doLast {
String urlString = nexusUrl.toString() + convertPackageNameToPath(publication.groupId) + "/" + publication.artifactId + "/" + publication.version
println "Artifact URL: " + urlString
}
}
static String convertPackageNameToPath(String packageName) {
return packageName.replace(".", "/");
}
Starting from #Abhijit Sarkar's answer, you can write universal solution for both remote and local publish direction:
tasks.withType(AbstractPublishToMaven) {
doLast {
println("Published ${publication.groupId}:${publication.artifactId}:${publication.version} to ${name.contains('Local') ? "local maven repository" : repositories.maven.url}")
}
}
Tasks publishing to local repo, contain 'Local' in its name (letter case matter), so the ternary operator defines a correct direction.
The DefaultMavenPublication class exposes the following method:
#Override
public PublishedFile getPublishedFile(final PublishArtifact source) {
final String publishedUrl = getPublishedUrl(source);
final String publishedName = source.getFile().getName();
return new PublishedFile() {
#Override
public String getName() {
return publishedName;
}
#Override
public String getUri() {
return publishedUrl;
}
};
}
introduced in this commit.
Maybe this could do the trick.

Gradle offline build does not work with Mac 10.9.3

I want to use my android studio 6.0 without internet connection, to do this, I set this options:
Preferences > Gradle > Offline work
but I am still get the message:
Gradle project sync failed. Basic functionality (e.g. editing,
debugging) will not work properly
When I try to compile, I get the Error:
Error running app: Gradle project sync failed. Please fix your project
and try again.
Could anyone help me or got the same problem?
Thank you
While I don't know what the exact problem is, I can suggest a workaround.
Change build.gradle to start with that:
buildscript {
repositories {
if ('allow' == System.properties['build.network_access']) {
mavenCentral()
} else {
maven {
url 'dependencies'
}
}
}
dependencies {
classpath 'com.android.tools.build:gradle:1.2.0-beta2'
}
}
apply plugin: 'com.android.application'
So, when build.network_access=allow gradle system property is defined, online mavenCentral() repository will be used. Otherwise, build will use local offline maven repository inside dependencies folder.
The trick now is to generate that local offline maven repository. For that I use this script (fetch_dependencies.py):
#!/usr/bin/python
import sys
import os
import subprocess
import glob
import shutil
# Place this in build.gradle:
# repositories {
# if ('allow' == System.properties['build.network_access']) {
# mavenCentral()
# } else {
# maven { url 'dependencies' }
# }
# }
def main(argv):
project_dir = os.path.dirname(os.path.realpath(__file__))
repo_dir = os.path.join(project_dir, "dependencies")
temp_home = os.path.join(project_dir, ".gradle_home")
if not os.path.isdir(temp_home):
os.makedirs(temp_home)
subprocess.call(["gradle", "-g", temp_home, "-Dbuild.network_access=allow"])
cache_files = os.path.join(temp_home, "caches/modules-*/files-*")
for cache_dir in glob.glob(cache_files):
for cache_group_id in os.listdir(cache_dir):
cache_group_dir = os.path.join(cache_dir, cache_group_id)
repo_group_dir = os.path.join(repo_dir, cache_group_id.replace('.', '/'))
for cache_artifact_id in os.listdir(cache_group_dir):
cache_artifact_dir = os.path.join(cache_group_dir, cache_artifact_id)
repo_artifact_dir = os.path.join(repo_group_dir, cache_artifact_id)
for cache_version_id in os.listdir(cache_artifact_dir):
cache_version_dir = os.path.join(cache_artifact_dir, cache_version_id)
repo_version_dir = os.path.join(repo_artifact_dir, cache_version_id)
if not os.path.isdir(repo_version_dir):
os.makedirs(repo_version_dir)
cache_items = os.path.join(cache_version_dir, "*/*")
for cache_item in glob.glob(cache_items):
cache_item_name = os.path.basename(cache_item)
repo_item_path = os.path.join(repo_version_dir, cache_item_name)
print "%s:%s:%s (%s)" % (cache_group_id, cache_artifact_id, cache_version_id, cache_item_name)
shutil.copyfile(cache_item, repo_item_path)
shutil.rmtree(temp_home)
return 0
if __name__ == "__main__":
sys.exit(main(sys.argv))
It will run the build in online mode to download all dependencies. After that, it will copy jars and poms into dependencies folder creating a local maven repository there. You can even push this dependencies folder into the source control.
After that you can build offline either with gradle --offline build (or just gradle build) or with Android Studio.

Resources