Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F3295328
ArcanistPrompt.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Advanced/Developer...
View Handle
View Hovercard
Size
7 KB
Referenced Files
None
Subscribers
None
ArcanistPrompt.php
View Options
<?php
final
class
ArcanistPrompt
extends
Phobject
{
private
$key
;
private
$workflow
;
private
$description
;
private
$query
;
public
function
setKey
(
$key
)
{
$this
->
key
=
$key
;
return
$this
;
}
public
function
getKey
(
)
{
return
$this
->
key
;
}
public
function
setWorkflow
(
ArcanistWorkflow
$workflow
)
{
$this
->
workflow
=
$workflow
;
return
$this
;
}
public
function
getWorkflow
(
)
{
return
$this
->
workflow
;
}
public
function
setDescription
(
$description
)
{
$this
->
description
=
$description
;
return
$this
;
}
public
function
getDescription
(
)
{
return
$this
->
description
;
}
public
function
setQuery
(
$query
)
{
$this
->
query
=
$query
;
return
$this
;
}
public
function
getQuery
(
)
{
return
$this
->
query
;
}
public
function
execute
(
)
{
$workflow
=
$this
->
getWorkflow
(
)
;
if
(
$workflow
)
{
$workflow_ok
=
$workflow
->
hasPrompt
(
$this
->
getKey
(
)
)
;
}
else
{
$workflow_ok
=
false
;
}
if
(
!
$workflow_ok
)
{
throw
new
Exception
(
pht
(
'Prompt ("%s") is executing, but it is not properly bound to the '
.
'invoking workflow. You may have called "newPrompt()" to execute a '
.
'prompt instead of "getPrompt()". Use "newPrompt()" when defining '
.
'prompts and "getPrompt()" when executing them.'
,
$this
->
getKey
(
)
)
)
;
}
$query
=
$this
->
getQuery
(
)
;
if
(
!
strlen
(
$query
)
)
{
throw
new
Exception
(
pht
(
'Prompt ("%s") has no query text!'
,
$this
->
getKey
(
)
)
)
;
}
$options
=
'[y/N/?]'
;
$default
=
'n'
;
$saved_response
=
$this
->
getSavedResponse
(
)
;
try
{
phutil_console_require_tty
(
)
;
}
catch
(
PhutilConsoleStdinNotInteractiveException
$ex
)
{
// TOOLSETS: Clean this up to provide more details to the user about how
// they can configure prompts to be answered.
// Throw after echoing the prompt so the user has some idea what happened.
echo
$query
.
"\n"
;
throw
$ex
;
}
$stdin
=
fopen
(
'php://stdin'
,
'r'
)
;
if
(
!
$stdin
)
{
throw
new
Exception
(
pht
(
'Failed to open stdin for reading.'
)
)
;
}
// NOTE: We're making stdin nonblocking so that we can respond to signals
// immediately. If we don't, and you ^C during a prompt, the program does
// not handle the signal until fgets() returns.
// On Windows, we skip this because stdin can not be made nonblocking.
if
(
!
phutil_is_windows
(
)
)
{
$ok
=
stream_set_blocking
(
$stdin
,
false
)
;
if
(
!
$ok
)
{
throw
new
Exception
(
pht
(
'Unable to set stdin nonblocking.'
)
)
;
}
}
echo
"\n"
;
$result
=
null
;
$is_saved
=
false
;
while
(
true
)
{
if
(
$saved_response
!==
null
)
{
$is_saved
=
true
;
$response
=
$saved_response
;
$saved_response
=
null
;
}
else
{
echo
tsprintf
(
'**<bg:cyan> %s </bg>** %s %s '
,
'>>>'
,
$query
,
$options
)
;
$is_saved
=
false
;
if
(
phutil_is_windows
(
)
)
{
$response
=
fgets
(
$stdin
)
;
}
else
{
while
(
true
)
{
$read
=
array
(
$stdin
)
;
$write
=
array
(
)
;
$except
=
array
(
)
;
$ok
=
@
stream_select
(
$read
,
$write
,
$except
,
1
)
;
if
(
$ok
===
false
)
{
// NOTE: We may be interrupted by a system call, particularly if
// the window is resized while a prompt is shown and the terminal
// sends SIGWINCH.
// If we are, just continue below and try to read from stdin. If
// we were interrupted, we should read nothing and continue
// normally. If the pipe is broken, the read should fail.
}
$response
=
''
;
while
(
true
)
{
$bytes
=
fread
(
$stdin
,
8192
)
;
if
(
$bytes
===
false
)
{
throw
new
Exception
(
pht
(
'fread() from stdin failed with an error.'
)
)
;
}
if
(
!
strlen
(
$bytes
)
)
{
break
;
}
$response
.=
$bytes
;
}
if
(
!
strlen
(
$response
)
)
{
continue
;
}
break
;
}
}
$response
=
trim
(
$response
)
;
if
(
!
strlen
(
$response
)
)
{
$response
=
$default
;
}
}
$save_scope
=
null
;
if
(
!
$is_saved
)
{
$matches
=
null
;
if
(
preg_match
(
'(^(.*)([!*])\z)'
,
$response
,
$matches
)
)
{
$response
=
$matches
[
1
]
;
if
(
$matches
[
2
]
===
'*'
)
{
$save_scope
=
ArcanistConfigurationSource
::
SCOPE_USER
;
}
else
{
$save_scope
=
ArcanistConfigurationSource
::
SCOPE_WORKING_COPY
;
}
}
}
if
(
phutil_utf8_strtolower
(
$response
)
==
'y'
)
{
$result
=
true
;
break
;
}
if
(
phutil_utf8_strtolower
(
$response
)
==
'n'
)
{
$result
=
false
;
break
;
}
if
(
phutil_utf8_strtolower
(
$response
)
==
'?'
)
{
echo
tsprintf
(
"\n<bg:green>** %s **</bg> **%s**\n\n"
,
pht
(
'PROMPT'
)
,
$this
->
getKey
(
)
)
;
echo
tsprintf
(
"%s\n"
,
$this
->
getDescription
(
)
)
;
echo
tsprintf
(
"\n"
)
;
echo
tsprintf
(
"%s\n"
,
pht
(
'The default response to this prompt is "%s".'
,
$default
)
)
;
echo
tsprintf
(
"\n"
)
;
echo
tsprintf
(
"%?\n"
,
pht
(
'Use "*" after a response to save it in user configuration.'
)
)
;
echo
tsprintf
(
"%?\n"
,
pht
(
'Use "!" after a response to save it in working copy '
.
'configuration.'
)
)
;
echo
tsprintf
(
"%?\n"
,
pht
(
'Run "arc help prompts" for detailed help on configuring '
.
'responses.'
)
)
;
echo
tsprintf
(
"\n"
)
;
continue
;
}
}
if
(
$save_scope
!==
null
)
{
$this
->
saveResponse
(
$save_scope
,
$response
)
;
}
if
(
$is_saved
)
{
echo
tsprintf
(
"<bg:cyan>** %s **</bg> %s **<%s>**\n"
.
"<bg:cyan>** %s **</bg> (%s)\n\n"
,
'>>>'
,
$query
,
$response
,
'>>>'
,
pht
(
'Using saved response to prompt "%s".'
,
$this
->
getKey
(
)
)
)
;
}
if
(
!
$result
)
{
throw
new
ArcanistUserAbortException
(
)
;
}
}
private
function
getSavedResponse
(
)
{
$config_key
=
ArcanistArcConfigurationEngineExtension
::
KEY_PROMPTS
;
$workflow
=
$this
->
getWorkflow
(
)
;
$config
=
$workflow
->
getConfig
(
$config_key
)
;
$prompt_key
=
$this
->
getKey
(
)
;
$prompt_response
=
null
;
foreach
(
$config
as
$response
)
{
if
(
$response
->
getPrompt
(
)
===
$prompt_key
)
{
$prompt_response
=
$response
;
}
}
if
(
$prompt_response
===
null
)
{
return
null
;
}
return
$prompt_response
->
getResponse
(
)
;
}
private
function
saveResponse
(
$scope
,
$response_value
)
{
$config_key
=
ArcanistArcConfigurationEngineExtension
::
KEY_PROMPTS
;
$workflow
=
$this
->
getWorkflow
(
)
;
echo
tsprintf
(
"<bg:green>** %s **</bg> %s\n"
,
pht
(
'SAVE PROMPT'
)
,
pht
(
'Saving response "%s" to prompt "%s".'
,
$response_value
,
$this
->
getKey
(
)
)
)
;
$source_list
=
$workflow
->
getConfigurationSourceList
(
)
;
$source
=
$source_list
->
getWritableSourceFromScope
(
$scope
)
;
$response_list
=
$source_list
->
getConfigFromScopes
(
$config_key
,
array
(
$scope
)
)
;
foreach
(
$response_list
as
$key
=>
$response
)
{
if
(
$response
->
getPrompt
(
)
===
$this
->
getKey
(
)
)
{
unset
(
$response_list
[
$key
]
)
;
}
}
if
(
$response_value
!==
null
)
{
$response_list
[
]
=
id
(
new
ArcanistPromptResponse
(
)
)
->
setPrompt
(
$this
->
getKey
(
)
)
->
setResponse
(
$response_value
)
;
}
$option
=
$source_list
->
getConfigOption
(
$config_key
)
;
$option
->
writeValue
(
$source
,
$response_list
)
;
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Thu, Mar 27, 01:46 (1 w, 5 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1241787
Default Alt Text
ArcanistPrompt.php (7 KB)
Attached To
Mode
rARC Arcanist
Attached
Detach File
Event Timeline
Log In to Comment