Gradle build null console object

I'm trying to get my gradle builds to prompt at the console for a password using examples from stack overflow

When I have a statment such as:

def password = System.console().readLine("Enter keystore password ")

When I run I get the error

Cannot invoke method readLine() on null object

It seems console is coming out as null. What I've read this requires java 6 which if I go to a command prompt and type java -version I'm running Java(TM) SE Runtime Environment (build 1.6.0_27-b07).

This issue is being tracked in Gradle's Github repo: Can't use System.console() with the Gradle Daemon.

Answers


For some reason, running gradle in daemon mode causes a null console object. If you specify the appropriate command line flag,

./gradlew assembleRelease --no-daemon

it'll work.


I found a solution here at https://www.timroes.de/2014/01/19/using-password-prompts-with-gradle-build-files and slightly modified it. Nevertheless, all credits go to Tim Roes!

gradle.taskGraph.whenReady { taskGraph ->
if(taskGraph.hasTask(':app:assembleRelease')) {
    def storePass = ''
    def keyPass = ''
    if(System.console() == null) {
        new SwingBuilder().edt {
            dialog(modal: true, title: 'Enter password', alwaysOnTop: true, resizable: false, locationRelativeTo: null, pack: true, show: true) {
                vbox { // Put everything below each other
                    label(text: "Please enter store passphrase:")
                    def input1 = passwordField()
                    label(text: "Please enter key passphrase:")
                    def input2 = passwordField()
                    button(defaultButton: true, text: 'OK', actionPerformed: {
                        storePass = input1.password;
                        keyPass = input2.password;
                        dispose();
                    })
                }
            }
        }
    } else {
        storePass = System.console().readPassword("\nPlease enter store passphrase: ")
        keyPass = System.console().readPassword("\nPlease enter key passphrase: ")
    }

    if(storePass.size() <= 0 || keyPass.size() <= 0) {
        throw new InvalidUserDataException("You must enter the passwords to proceed.")
    }

    storePass = new String(storePass)
    keyPass = new String(keyPass)

    android.signingConfigs.release.storePassword = storePass
    android.signingConfigs.release.keyPassword = keyPass
    }
}

Somewhere in the some gradle file, you have the configuration for the release signing defined.

android {
...
signingConfigs {
    ...
    release {
        storeFile file(System.getProperty("user.home")+"\\android-key")
        storePassword ''
        keyAlias "standard"
        keyPassword ''
    }
}

...
}

(Don't forget to import groovy.swing.SwingBuilder.)

Regarding the second part, you may also have a look at How to create a release signed apk file using Gradle?


Ok, the reason why this didn't work was silly, but just in case anyone else comes across it I thought I'd post.

I was running the task through android studio and didn't realise that the console object would always be null. When running from the command line the "command" object isn't null and it works ok.


Executing System.getConsole() from Gradle when org.gradle.daemon property is true, or when it's executed from an IDE like IntelliJ or Android Studio it returns null. So for example do System.console().readLine() becomes not possible.

Furthermore starting from Gradle 3.0 gradle.daemon is turned on by default.

Then instead of a workaround to use System.getConsole() I purpose an alternative, use ant.input like so:

task avoidNullOnConsole << {
    ant.input(message: 'Enter keystore password:', addproperty: 'userInputPassword', defaultValue : '1234')
    def password = ant.properties.userInputPassword
}

In this case ant.input shows the message and adds the user input in ant.properties using as a property name the value defined in addProperty. If there is no user input then the value defined in default attribute is used.

Once executed you can get the user input using ant.properties.yourProperty or ant.properties['yourProperty'].

You can check the rest of the ant.input attributes here.

Note: If you want to use ant.input multiple times take in account that you cannot override and existing property so addProperty attribute must be different for each one.


Take a look at this blog post (https://www.timroes.de/2013/09/22/handling-signing-configs-with-gradle/).

It describes multiple ways to handle signing configs and one of them is exactly your question regarding console input for the password.


Simple solution to this is to check the console object for null:

def password = null
def console = System.console()
if (console != null) {
    password = console.readLine("Enter keystore password: ")
}

Android Studio no longer complaints about the null object.

To hide typed chars use readPassword() instead of readLine():

password = new String(console.readPassword("\nEnter key password: "))

You can execute your script also with:

-Dorg.gradle.daemon=false


To workaround this problem I used the standard input stream as next:

println "Enter keystore password"
def password = System.in.newReader().readLine()

create a simple function to request a password:

import javax.swing.JOptionPane

def askPass() {
  def msg = 'Enter keystore password'
  if (System.console() != null) {
    return System.console().readLine(msg)
  } else {
    return javax.swing.JOptionPane.showInputDialog(msg)
  }
}

or if you want Y/n answer:

import javax.swing.JOptionPane

def ask(msg) {
  if (System.console() != null) {
    return System.console().readLine(msg + ' [y/n]') == 'y'
  } else {
    def res = JOptionPane.showConfirmDialog(null, msg, "Confirm operation", JOptionPane.YES_NO_OPTION)
    return res == JOptionPane.YES_OPTION
  }
}

// usage:

task run() {
  doFirst {
    if (file('out.txt').exists() && !ask('overwrite output?')) {
      System.exit(2)
    }
  }
  ...
}

password System.console() != null ? System.console().readLine("\ password: ") : ""

Need Your Help

java 8 syntax conversion for processing 2 (twitter4j)

java java-8 processing twitter4j

I was informed that this code will not work in processing because it is java 8 syntax, which is not supported in processing. I need help converting it to work in processing. What syntax can Process...

want to create diamond shape using while in C

c++ c turbo-c++

i have created the diamond using for loop but i am not able to convert it into While.