Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't use System.console() with the Gradle Daemon #1251

Open
eriwen opened this issue Jan 24, 2017 · 25 comments
Open

Can't use System.console() with the Gradle Daemon #1251

eriwen opened this issue Jan 24, 2017 · 25 comments

Comments

@eriwen
Copy link
Member

@eriwen eriwen commented Jan 24, 2017

In this environment, System.console() returns null.

Possible solutions:

  1. Inject a console impl to be returned by System.console() that works with the daemon client (not sure if we can inject here)
  2. Provide a "Gradle console" object that is daemon aware

Context

Migrated from GRADLE-2310 with 16 votes.

From Luke:

I don't think this will be too hard to implement. The “hardest” part will be working out the public API for this, as we can't just use the JDK entry points as they are blocked off for extension.

Workaround

Note that a simple swingbuilder can be used as a workaround, to query the user's input

@adammurdoch
Copy link
Member

@adammurdoch adammurdoch commented Jan 31, 2017

It would be better to think of this as 'provide a way for build logic to receive input from the build user'.

I wouldn't change System.console() to mean anything other than what the Java spec says it means: if you're running in a process that is attached to a system console, it's not null and if you're not, it's null. Instead, I would add an API that allows build logic to query the user for input. This can then be backed be any number of implementations:

  • An implementation that prompts the user, if the user happen to be running Gradle from the command-line and happen to be attached to a console,
  • An implementation that prompts the users in the IDE via the TAPI, if the user happen to be using an IDE or some other TAPI backed GUI,
  • An implementation that uses values provided as command line options if the user happen to be using the CLI from something other than a console, or the user happens to be a tool of some kind,
  • An implementation that uses values from gradle.properties so the user can avoid having to answer the same question over and over or so that a CI agent can answer the questions.

@pioterj
Copy link
Member

@pioterj pioterj commented Apr 20, 2017

I think we should rename this story to something like "Allow receiving user input when using the daemon".

Another use case I came across is running a shell command that prompts for password using Exec task. It currently fails unless you disable the daemon.

@barbeau
Copy link

@barbeau barbeau commented Apr 20, 2017

My main use case for System.console() was keystore/key password input when signing Android release builds.

It seems that starting with 'com.android.tools.build:gradle:2.3.0' the Gradle Daemon is now enabled by default when running builds from the command line, which therefore broke our release process because System.console() started returning null (see OneBusAway/onebusaway-android#770 for details). I've implemented a workaround using SwingBuilder and a popup dialog to receive the user input at OneBusAway/onebusaway-android@fed5dd1#diff-e3b0302efca29d62561a92d244fd843fR299 but using System.console() was a much cleaner and simpler solution.

@adammurdoch
Copy link
Member

@adammurdoch adammurdoch commented Apr 23, 2017

I'd bust this into several features:

  • A specific solution for supplying credentials, such that when something is using Credentials the password is supplied by Gradle.
  • A general way for plugins and build logic to declare user inputs and have Gradle supply the values.

The thing these features have in common is that one potential strategy for supplying either kind of value is to prompt the user. This doesn't necessarily have to the case though, for example we might start simply by looking for a specific property specified using -D, and add support for prompting the user later on.

@staffanf
Copy link

@staffanf staffanf commented Apr 24, 2017

My main 2 use cases for this is:

  • Supplying a name for a template project. We have task that creates a subproject below the root dir that takes the name as input.
  • Supplying a user/password for p4 login. The user needs to login every day to get a ticket. If gradle is the first command executed against p4 then the ticket is invalid and needs a new login, prompting the user for a password with a timeout in this case is more natural than just failing with a not logged in message.
    We are currently using the SwingBuilder workaround for inputs.

@mkobit
Copy link
Contributor

@mkobit mkobit commented Apr 27, 2017

One use case I've wanted is to "run REPL with built code available", so being able to easily build and run the code in my project with the kotlin-jvm shell, groovysh, and (soon) jshell. There might be ways to do this now with something like jline but I have not spent time looking into it.

@EarthCitizen
Copy link

@EarthCitizen EarthCitizen commented May 1, 2017

I am also having an issue with this. My use case is that I need my task output to be in color or without color based on the setting of project.gradle.startParameter.consoleOutput. For Rich and Plain this is no problem. But with Auto I need to check System.console(), which, as stated here, is not working with the daemon. I would prefer to ask Gradle if there is a console or not rather than using System though.

@mepaJanitza
Copy link

@mepaJanitza mepaJanitza commented Jul 18, 2017

Im also having a similar issue. If i want to execute sudo commands where i have to enter the password ( generally everything with console out (output displayed delayed) and console in )

"Workaround": Its not really a workaround but Gradle 2.10 works without these problems.

With Gradle Versions >2.10 this issue is present (for me).

So if you use a wrapper change it in your gradle-wrapper.properties file (distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-bin.zip)

@roguexz
Copy link

@roguexz roguexz commented Jul 20, 2017

Is there relevant documentation that shows a plugin can be built which can handle communication between the front-end process and the daemon?

@bmuschko
Copy link
Contributor

@bmuschko bmuschko commented Jul 20, 2017

@roguexz There's no documentation. In fact at the moment it's not possible with the latest version of Gradle as it runs with the daemon by default.

@dchesterman
Copy link

@dchesterman dchesterman commented Oct 9, 2017

This has been an issue for 5 years now. Is there any chance of getting this resolved. Especially the password issue.

@pioterj
Copy link
Member

@pioterj pioterj commented Oct 10, 2017

@dchesterman There's some progress on this topic (via an API rather than System.console()). See #2842.

@cwocwo
Copy link

@cwocwo cwocwo commented Jan 13, 2018

@Vampire
Copy link
Contributor

@Vampire Vampire commented Jan 31, 2019

This issue is not restricted to input in the build logic.
If you for example use a JavaExec task to run some Java program that uses System.console(), it does not work as the returned console is null.
It is not really feasible to require a program you use to not use System.console() for its input.
Btw. System.in with a Scanner works fine from external program and also Gradle build script to request input. For external Program you have to set standardInput = System.in in the JavaExec task. But unfortunately this does not help for System.console().

@StefMa
Copy link
Contributor

@StefMa StefMa commented Jul 18, 2019

I just took a look into the InitBuild task how its done there.
And its pretty easy (yeah sure, you use internal APIs but at least we can use it, right 😉).

open class InputTask : DefaultTask() {

    @TaskAction
    fun askQuestion() {
        val userInput = services.get(UserInputHandler::class.java)
        val answer =userInput.askQuestion("Hey, how are you?", "Good")
        println(answer)
    }
}

That is all 🙃
TBH I'm not sure why this is not public 🤷‍♂

Sources:

@Vampire
Copy link
Contributor

@Vampire Vampire commented Aug 9, 2019

That is another work-around for #2842 besides using a GUI dialog, but it does not resolve the problem of 3rd party tools that use System.console() and are integrated into the build process.

@netvl
Copy link

@netvl netvl commented Oct 10, 2019

BTW, the UserInputHandler works incorrectly if it is expected for the task to print something before asking the user. Specifically, askQuestion() and other methods wait for the user input when they are called, but the task output (e.g. with println() or logger.quiet()) is displayed in bulk after the task is executed. This makes it impossible to use UserInputHandler for interactive tasks, i.e. when the user is expected to look at what the task outputs and decide on what to do next.

@stale
Copy link

@stale stale bot commented Nov 13, 2020

This issue has been automatically marked as stale because it has not had recent activity. Given the limited bandwidth of the team, it will be automatically closed if no further activity occurs. If you're interested in how we try to keep the backlog in a healthy state, please read our blog post on how we refine our backlog. If you feel this is something you could contribute, please have a look at our Contributor Guide. Thank you for your contribution.

@stale stale bot added the stale label Nov 13, 2020
@netvl
Copy link

@netvl netvl commented Nov 15, 2020

I think this does not deserve being closed as stale, it is an important piece of functionality for many purposes.

@stale stale bot removed the stale label Nov 15, 2020
@rieske
Copy link
Contributor

@rieske rieske commented Nov 16, 2020

In Gradle 6.6 we released a new feature for supplying credentials to Gradle that can be used to authenticate with artifact repositories or passed on to an external tool that might otherwise require the credentials to be supplied interactively.
Hopefully this can address some of the use cases raised in this issue.

@martinda
Copy link
Contributor

@martinda martinda commented Dec 8, 2020

It's more than credentials. We have a an extensive process that validate user inputs, and then we ask for user confirmation before proceeding, using a yes/no question. We also have another process that can fall into interactive debug mode where all the keyboard input is passed to the underlying process after a certain key combination is typed. Interactive access is needed for us in some circumstances. I am okay with not using the daemon in these cases.

@ghabiger
Copy link

@ghabiger ghabiger commented May 11, 2021

This issue is not restricted to input in the build logic.
If you for example use a JavaExec task to run some Java program that uses System.console(), it does not work as the returned console is null.
It is not really feasible to require a program you use to not use System.console() for its input.

I am currently facing this problem. Thanks for putting it so clearly, couldn't have said it better.

I'm trying to run a JavaExec task for a Java program which utilizes System.console(), and so far I've found no easy way of making this work (except ugly Swing terminal hacks with org.beryx.textio).
Would be great if this were solved after 4 years of being an open issue, because currently it seems Gradle can not be used to run arbitrary JavaExec tasks on the commandline :)

@JavaJoeS
Copy link

@JavaJoeS JavaJoeS commented Nov 9, 2021

Just bumped up against this too, running gradle 7.2 using JavaExec from command line hits 3rd party code that used System.Console() and it got the NPE.

@mrsolarius
Copy link

@mrsolarius mrsolarius commented Mar 13, 2022

There is a workaround today that not use java swing or any graphical interface thing?

@bric3
Copy link

@bric3 bric3 commented Mar 16, 2022

@mrsolarius Nope I misread :(
As far as I know there's only the external tool approach

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests