Changeset View
Changeset View
Standalone View
Standalone View
src/workflow/ArcanistDiffWorkflow.php
Show First 20 Lines • Show All 109 Lines • ▼ Show 20 Lines | $arguments = array( | ||||
), | ), | ||||
'help' => pht( | 'help' => pht( | ||||
'When updating a revision under git, edit revision information '. | 'When updating a revision under git, edit revision information '. | ||||
'before updating.'), | 'before updating.'), | ||||
), | ), | ||||
'raw' => array( | 'raw' => array( | ||||
'help' => pht( | 'help' => pht( | ||||
'Read diff from stdin, not from the working copy. This disables '. | 'Read diff from stdin, not from the working copy. This disables '. | ||||
'many Arcanist/Phabricator features which depend on having access '. | 'many features which depend on having access to the working copy.'), | ||||
'to the working copy.'), | |||||
'conflicts' => array( | 'conflicts' => array( | ||||
'apply-patches' => pht('%s disables lint.', '--raw'), | 'apply-patches' => pht('%s disables lint.', '--raw'), | ||||
'never-apply-patches' => pht('%s disables lint.', '--raw'), | 'never-apply-patches' => pht('%s disables lint.', '--raw'), | ||||
'create' => pht( | 'create' => pht( | ||||
'%s and %s both need stdin. Use %s.', | '%s and %s both need stdin. Use %s.', | ||||
'--raw', | '--raw', | ||||
'--create', | '--create', | ||||
'--raw-command'), | '--raw-command'), | ||||
'edit' => pht( | 'edit' => pht( | ||||
'%s and %s both need stdin. Use %s.', | '%s and %s both need stdin. Use %s.', | ||||
'--raw', | '--raw', | ||||
'--edit', | '--edit', | ||||
'--raw-command'), | '--raw-command'), | ||||
'raw-command' => null, | 'raw-command' => null, | ||||
), | ), | ||||
), | ), | ||||
'raw-command' => array( | 'raw-command' => array( | ||||
'param' => 'command', | 'param' => 'command', | ||||
'help' => pht( | 'help' => pht( | ||||
'Generate diff by executing a specified command, not from the '. | 'Generate diff by executing a specified command, not from the '. | ||||
'working copy. This disables many Arcanist/Phabricator features '. | 'working copy. This disables many features which depend on having '. | ||||
'which depend on having access to the working copy.'), | 'access to the working copy.'), | ||||
'conflicts' => array( | 'conflicts' => array( | ||||
'apply-patches' => pht('%s disables lint.', '--raw-command'), | 'apply-patches' => pht('%s disables lint.', '--raw-command'), | ||||
'never-apply-patches' => pht('%s disables lint.', '--raw-command'), | 'never-apply-patches' => pht('%s disables lint.', '--raw-command'), | ||||
), | ), | ||||
), | ), | ||||
'create' => array( | 'create' => array( | ||||
'help' => pht('Always create a new revision.'), | 'help' => pht('Always create a new revision.'), | ||||
'conflicts' => array( | 'conflicts' => array( | ||||
▲ Show 20 Lines • Show All 170 Lines • ▼ Show 20 Lines | $arguments = array( | ||||
'browse' => array( | 'browse' => array( | ||||
'help' => pht( | 'help' => pht( | ||||
'After creating a diff or revision, open it in a web browser.'), | 'After creating a diff or revision, open it in a web browser.'), | ||||
), | ), | ||||
'*' => 'paths', | '*' => 'paths', | ||||
'head' => array( | 'head' => array( | ||||
'param' => 'commit', | 'param' => 'commit', | ||||
'help' => pht( | 'help' => pht( | ||||
'Specify the end of the commit range. This disables many '. | 'Specify the end of the commit range. This disables many features '. | ||||
'Arcanist/Phabricator features which depend on having access to '. | 'which depend on having access to the working copy.'), | ||||
'the working copy.'), | |||||
'supports' => array('git'), | 'supports' => array('git'), | ||||
'nosupport' => array( | 'nosupport' => array( | ||||
'svn' => pht('Subversion does not support commit ranges.'), | 'svn' => pht('Subversion does not support commit ranges.'), | ||||
'hg' => pht('Mercurial does not support %s yet.', '--head'), | 'hg' => pht('Mercurial does not support %s yet.', '--head'), | ||||
), | ), | ||||
), | ), | ||||
); | ); | ||||
▲ Show 20 Lines • Show All 172 Lines • ▼ Show 20 Lines | if ($this->shouldOnlyCreateDiff()) { | ||||
// TODO: This is hacky, but we don't currently receive a URI back | // TODO: This is hacky, but we don't currently receive a URI back | ||||
// from "differential.revision.edit". | // from "differential.revision.edit". | ||||
$result_uri = id(new PhutilURI($this->getConduitURI())) | $result_uri = id(new PhutilURI($this->getConduitURI())) | ||||
->setPath('/D'.$result_id); | ->setPath('/D'.$result_id); | ||||
} else { | } else { | ||||
if ($is_draft) { | if ($is_draft) { | ||||
throw new ArcanistUsageException( | throw new ArcanistUsageException( | ||||
pht( | pht( | ||||
'You have specified "--draft", but the version of Phabricator '. | 'You have specified "--draft", but the software version '. | ||||
'on the server is too old to support draft revisions. Omit '. | 'on the server is too old to support draft revisions. Omit '. | ||||
'the flag or upgrade the server software.')); | 'the flag or upgrade the server software.')); | ||||
} | } | ||||
$revision = $this->dispatchWillCreateRevisionEvent($revision); | $revision = $this->dispatchWillCreateRevisionEvent($revision); | ||||
$result = $conduit->callMethodSynchronous( | $result = $conduit->callMethodSynchronous( | ||||
'differential.createrevision', | 'differential.createrevision', | ||||
▲ Show 20 Lines • Show All 140 Lines • ▼ Show 20 Lines | if ($revision_id) { | ||||
'fields' => $use_fields, | 'fields' => $use_fields, | ||||
)); | )); | ||||
} | } | ||||
} | } | ||||
if ($should_edit) { | if ($should_edit) { | ||||
$edited = $this->newInteractiveEditor($remote_corpus) | $edited = $this->newInteractiveEditor($remote_corpus) | ||||
->setName('differential-edit-revision-info') | ->setName('differential-edit-revision-info') | ||||
->setTaskMessage(pht( | |||||
'Update the details for a revision, then save and exit.')) | |||||
->editInteractively(); | ->editInteractively(); | ||||
if ($edited != $remote_corpus) { | if ($edited != $remote_corpus) { | ||||
$remote_corpus = $edited; | $remote_corpus = $edited; | ||||
$edit_messages[$revision_id] = $remote_corpus; | $edit_messages[$revision_id] = $remote_corpus; | ||||
$this->writeScratchJSONFile('edit-messages.json', $edit_messages); | $this->writeScratchJSONFile('edit-messages.json', $edit_messages); | ||||
} | } | ||||
} | } | ||||
Show All 9 Lines | if ($revision_id) { | ||||
$revision['fields'] = $new_message->getFields(); | $revision['fields'] = $new_message->getFields(); | ||||
$xactions = $new_message->getTransactions(); | $xactions = $new_message->getTransactions(); | ||||
$revision['id'] = $revision_id; | $revision['id'] = $revision_id; | ||||
$this->revisionID = $revision_id; | $this->revisionID = $revision_id; | ||||
$revision['message'] = $this->getArgument('message'); | $revision['message'] = $this->getArgument('message'); | ||||
if (!strlen($revision['message'])) { | if ($revision['message'] === null) { | ||||
$update_messages = $this->readScratchJSONFile('update-messages.json'); | $update_messages = $this->readScratchJSONFile('update-messages.json'); | ||||
$update_messages[$revision_id] = $this->getUpdateMessage( | $update_messages[$revision_id] = $this->getUpdateMessage( | ||||
$revision['fields'], | $revision['fields'], | ||||
idx($update_messages, $revision_id)); | idx($update_messages, $revision_id)); | ||||
$revision['message'] = ArcanistCommentRemover::removeComments( | $revision['message'] = ArcanistCommentRemover::removeComments( | ||||
$update_messages[$revision_id]); | $update_messages[$revision_id]); | ||||
▲ Show 20 Lines • Show All 90 Lines • ▼ Show 20 Lines | EOTEXT | ||||
protected function generateChanges() { | protected function generateChanges() { | ||||
$parser = $this->newDiffParser(); | $parser = $this->newDiffParser(); | ||||
$is_raw = $this->isRawDiffSource(); | $is_raw = $this->isRawDiffSource(); | ||||
if ($is_raw) { | if ($is_raw) { | ||||
if ($this->getArgument('raw')) { | if ($this->getArgument('raw')) { | ||||
fwrite(STDERR, pht('Reading diff from stdin...')."\n"); | PhutilSystem::writeStderr( | ||||
tsprintf( | |||||
"%s\n", | |||||
pht('Reading diff from stdin...'))); | |||||
$raw_diff = file_get_contents('php://stdin'); | $raw_diff = file_get_contents('php://stdin'); | ||||
} else if ($this->getArgument('raw-command')) { | } else if ($this->getArgument('raw-command')) { | ||||
list($raw_diff) = execx('%C', $this->getArgument('raw-command')); | list($raw_diff) = execx('%C', $this->getArgument('raw-command')); | ||||
} else { | } else { | ||||
throw new Exception(pht('Unknown raw diff source.')); | throw new Exception(pht('Unknown raw diff source.')); | ||||
} | } | ||||
$changes = $parser->parseDiff($raw_diff); | $changes = $parser->parseDiff($raw_diff); | ||||
▲ Show 20 Lines • Show All 124 Lines • ▼ Show 20 Lines | foreach ($changes as $change) { | ||||
$is_binary = ArcanistDiffUtils::isHeuristicBinaryFile($corpus); | $is_binary = ArcanistDiffUtils::isHeuristicBinaryFile($corpus); | ||||
if (!$is_binary) { | if (!$is_binary) { | ||||
try { | try { | ||||
$try_encoding = $this->getRepositoryEncoding(); | $try_encoding = $this->getRepositoryEncoding(); | ||||
} catch (ConduitClientException $e) { | } catch (ConduitClientException $e) { | ||||
if ($e->getErrorCode() == 'ERR-BAD-ARCANIST-PROJECT') { | if ($e->getErrorCode() == 'ERR-BAD-ARCANIST-PROJECT') { | ||||
echo phutil_console_wrap( | echo phutil_console_wrap( | ||||
pht('Lookup of encoding in arcanist project failed: %s', | pht('Lookup of encoding in project failed: %s', | ||||
$e->getMessage())."\n"); | $e->getMessage())."\n"); | ||||
} else { | } else { | ||||
throw $e; | throw $e; | ||||
} | } | ||||
} | } | ||||
if ($try_encoding) { | if ($try_encoding) { | ||||
$corpus = phutil_utf8_convert($corpus, 'UTF-8', $try_encoding); | $corpus = phutil_utf8_convert($corpus, 'UTF-8', $try_encoding); | ||||
Show All 24 Lines | if ($utf8_problems) { | ||||
"%s\n\n%s\n\n %s\n", | "%s\n\n%s\n\n %s\n", | ||||
pht( | pht( | ||||
'This diff includes %s file(s) which are not valid UTF-8 (they '. | 'This diff includes %s file(s) which are not valid UTF-8 (they '. | ||||
'contain invalid byte sequences). You can either stop this '. | 'contain invalid byte sequences). You can either stop this '. | ||||
'workflow and fix these files, or continue. If you continue, '. | 'workflow and fix these files, or continue. If you continue, '. | ||||
'these files will be marked as binary.', | 'these files will be marked as binary.', | ||||
phutil_count($utf8_problems)), | phutil_count($utf8_problems)), | ||||
pht( | pht( | ||||
"You can learn more about how Phabricator handles character ". | "You can learn more about how this software handles character ". | ||||
"encodings (and how to configure encoding settings and detect and ". | "encodings (and how to configure encoding settings and detect and ". | ||||
"correct encoding problems) by reading 'User Guide: UTF-8 and ". | "correct encoding problems) by reading 'User Guide: UTF-8 and ". | ||||
"Character Encoding' in the Phabricator documentation."), | "Character Encoding' in the documentation."), | ||||
pht( | pht( | ||||
'%s AFFECTED FILE(S)', | '%s AFFECTED FILE(S)', | ||||
phutil_count($utf8_problems))); | phutil_count($utf8_problems))); | ||||
$confirm = pht( | $confirm = pht( | ||||
'Do you want to mark these %s file(s) as binary and continue?', | 'Do you want to mark these %s file(s) as binary and continue?', | ||||
phutil_count($utf8_problems)); | phutil_count($utf8_problems)); | ||||
echo phutil_console_format( | echo phutil_console_format( | ||||
▲ Show 20 Lines • Show All 468 Lines • ▼ Show 20 Lines | while (!$done) { | ||||
} | } | ||||
$template .= "\n"; | $template .= "\n"; | ||||
if ($first && $this->getArgument('verbatim') && !$template_is_default) { | if ($first && $this->getArgument('verbatim') && !$template_is_default) { | ||||
$new_template = $template; | $new_template = $template; | ||||
} else { | } else { | ||||
$new_template = $this->newInteractiveEditor($template) | $new_template = $this->newInteractiveEditor($template) | ||||
->setName('new-commit') | ->setName('new-commit') | ||||
->setTaskMessage(pht( | |||||
'Provide the details for a new revision, then save and exit.')) | |||||
->editInteractively(); | ->editInteractively(); | ||||
} | } | ||||
$first = false; | $first = false; | ||||
if ($template_is_default && ($new_template == $template)) { | if ($template_is_default && ($new_template == $template)) { | ||||
throw new ArcanistUsageException(pht('Template not edited.')); | throw new ArcanistUsageException(pht('Template not edited.')); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 244 Lines • ▼ Show 20 Lines | private function getUpdateMessage(array $fields, $template = '') { | ||||
// $ arc diff | // $ arc diff | ||||
// | // | ||||
// ...you shouldn't have to retype the update message. Similar things apply | // ...you shouldn't have to retype the update message. Similar things apply | ||||
// to Mercurial. | // to Mercurial. | ||||
if ($template == '') { | if ($template == '') { | ||||
$comments = $this->getDefaultUpdateMessage(); | $comments = $this->getDefaultUpdateMessage(); | ||||
$comments = phutil_string_cast($comments); | |||||
$comments = rtrim($comments); | |||||
$template = sprintf( | $template = sprintf( | ||||
"%s\n\n# %s\n#\n# %s\n# %s\n#\n# %s\n# $ %s\n\n", | "%s\n\n# %s\n#\n# %s\n# %s\n#\n# %s\n# $ %s\n\n", | ||||
rtrim($comments), | $comments, | ||||
pht( | pht( | ||||
'Updating %s: %s', | 'Updating %s: %s', | ||||
"D{$fields['revisionID']}", | "D{$fields['revisionID']}", | ||||
$fields['title']), | $fields['title']), | ||||
pht( | pht( | ||||
'Enter a brief description of the changes included in this update.'), | 'Enter a brief description of the changes included in this update.'), | ||||
pht('The first line is used as subject, next lines as comment.'), | pht('The first line is used as subject, next lines as comment.'), | ||||
pht('If you intended to create a new revision, use:'), | pht('If you intended to create a new revision, use:'), | ||||
'arc diff --create'); | 'arc diff --create'); | ||||
} | } | ||||
$comments = $this->newInteractiveEditor($template) | $comments = $this->newInteractiveEditor($template) | ||||
->setName('differential-update-comments') | ->setName('differential-update-comments') | ||||
->setTaskMessage(pht( | |||||
'Update the revision comments, then save and exit.')) | |||||
->editInteractively(); | ->editInteractively(); | ||||
return $comments; | return $comments; | ||||
} | } | ||||
private function getDefaultCreateFields() { | private function getDefaultCreateFields() { | ||||
$result = array(array(), array(), array()); | $result = array(array(), array(), array()); | ||||
▲ Show 20 Lines • Show All 586 Lines • ▼ Show 20 Lines | if (!($api instanceof ArcanistGitAPI)) { | ||||
return null; | return null; | ||||
} | } | ||||
// If we track an upstream branch either directly or indirectly, use that. | // If we track an upstream branch either directly or indirectly, use that. | ||||
$branch = $api->getBranchName(); | $branch = $api->getBranchName(); | ||||
if (strlen($branch)) { | if (strlen($branch)) { | ||||
$upstream_path = $api->getPathToUpstream($branch); | $upstream_path = $api->getPathToUpstream($branch); | ||||
$remote_branch = $upstream_path->getRemoteBranchName(); | $remote_branch = $upstream_path->getRemoteBranchName(); | ||||
if (strlen($remote_branch)) { | if ($remote_branch !== null) { | ||||
return array( | return array( | ||||
array( | array( | ||||
'type' => 'branch', | 'type' => 'branch', | ||||
'name' => $remote_branch, | 'name' => $remote_branch, | ||||
'kind' => 'upstream', | 'kind' => 'upstream', | ||||
), | ), | ||||
); | ); | ||||
} | } | ||||
} | } | ||||
// If "arc.land.onto.default" is configured, use that. | // If "arc.land.onto.default" is configured, use that. | ||||
$config_key = 'arc.land.onto.default'; | $config_key = 'arc.land.onto.default'; | ||||
$onto = $this->getConfigFromAnySource($config_key); | $onto = $this->getConfigFromAnySource($config_key); | ||||
if (strlen($onto)) { | if ($onto !== null) { | ||||
return array( | return array( | ||||
array( | array( | ||||
'type' => 'branch', | 'type' => 'branch', | ||||
'name' => $onto, | 'name' => $onto, | ||||
'kind' => 'arc.land.onto.default', | 'kind' => 'arc.land.onto.default', | ||||
), | ), | ||||
); | ); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 258 Lines • ▼ Show 20 Lines | if ($staging === null) { | ||||
pht('The server does not support staging areas.')); | pht('The server does not support staging areas.')); | ||||
return self::STAGING_REPOSITORY_UNAVAILABLE; | return self::STAGING_REPOSITORY_UNAVAILABLE; | ||||
} | } | ||||
$supported = idx($staging, 'supported'); | $supported = idx($staging, 'supported'); | ||||
if (!$supported) { | if (!$supported) { | ||||
$this->writeInfo( | $this->writeInfo( | ||||
pht('SKIP STAGING'), | pht('SKIP STAGING'), | ||||
pht('Phabricator does not support staging areas for this repository.')); | pht('The server does not support staging areas for this repository.')); | ||||
return self::STAGING_REPOSITORY_UNSUPPORTED; | return self::STAGING_REPOSITORY_UNSUPPORTED; | ||||
} | } | ||||
$staging_uri = idx($staging, 'uri'); | $staging_uri = idx($staging, 'uri'); | ||||
if (!$staging_uri) { | if (!$staging_uri) { | ||||
$this->writeInfo( | $this->writeInfo( | ||||
pht('SKIP STAGING'), | pht('SKIP STAGING'), | ||||
pht('No staging area is configured for this repository.')); | pht('No staging area is configured for this repository.')); | ||||
▲ Show 20 Lines • Show All 236 Lines • Show Last 20 Lines |
Content licensed under Creative Commons Attribution-ShareAlike 4.0 (CC-BY-SA) unless otherwise noted; code licensed under Apache 2.0 or other open source licenses. · CC BY-SA 4.0 · Apache 2.0