Changeset View
Changeset View
Standalone View
Standalone View
src/workflow/ArcanistPatchWorkflow.php
| Show First 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | return array( | ||||
| 'help' => | 'help' => | ||||
| "Apply changes from a Differential revision, using the most recent ". | "Apply changes from a Differential revision, using the most recent ". | ||||
| "diff that has been attached to it. You can run 'arc patch D12345' ". | "diff that has been attached to it. You can run 'arc patch D12345' ". | ||||
| "as a shorthand.", | "as a shorthand.", | ||||
| ), | ), | ||||
| 'diff' => array( | 'diff' => array( | ||||
| 'param' => 'diff_id', | 'param' => 'diff_id', | ||||
| 'help' => | 'help' => | ||||
| "Apply changes from a Differential diff. Normally you want to use ". | 'Apply changes from a Differential diff. Normally you want to use '. | ||||
| "--revision to get the most recent changes, but you can ". | '--revision to get the most recent changes, but you can '. | ||||
| "specifically apply an out-of-date diff or a diff which was never ". | 'specifically apply an out-of-date diff or a diff which was never '. | ||||
| "attached to a revision by using this flag.", | 'attached to a revision by using this flag.', | ||||
| ), | ), | ||||
| 'arcbundle' => array( | 'arcbundle' => array( | ||||
| 'param' => 'bundlefile', | 'param' => 'bundlefile', | ||||
| 'paramtype' => 'file', | 'paramtype' => 'file', | ||||
| 'help' => | 'help' => | ||||
| "Apply changes from an arc bundle generated with 'arc export'.", | "Apply changes from an arc bundle generated with 'arc export'.", | ||||
| ), | ), | ||||
| 'patch' => array( | 'patch' => array( | ||||
| 'param' => 'patchfile', | 'param' => 'patchfile', | ||||
| 'paramtype' => 'file', | 'paramtype' => 'file', | ||||
| 'help' => | 'help' => | ||||
| "Apply changes from a git patchfile or unified patchfile.", | 'Apply changes from a git patchfile or unified patchfile.', | ||||
| ), | ), | ||||
| 'encoding' => array( | 'encoding' => array( | ||||
| 'param' => 'encoding', | 'param' => 'encoding', | ||||
| 'help' => | 'help' => | ||||
| "Attempt to convert non UTF-8 patch into specified encoding.", | 'Attempt to convert non UTF-8 patch into specified encoding.', | ||||
| ), | ), | ||||
| 'update' => array( | 'update' => array( | ||||
| 'supports' => array( | 'supports' => array( | ||||
| 'git', 'svn', 'hg' | 'git', 'svn', 'hg' | ||||
| ), | ), | ||||
| 'help' => | 'help' => | ||||
| "Update the local working copy before applying the patch.", | 'Update the local working copy before applying the patch.', | ||||
| 'conflicts' => array( | 'conflicts' => array( | ||||
| 'nobranch' => true, | 'nobranch' => true, | ||||
| 'bookmark' => true, | 'bookmark' => true, | ||||
| ), | ), | ||||
| ), | ), | ||||
| 'nocommit' => array( | 'nocommit' => array( | ||||
| 'supports' => array( | 'supports' => array( | ||||
| 'git', 'hg' | 'git', 'hg' | ||||
| ), | ), | ||||
| 'help' => | 'help' => | ||||
| "Normally under git/hg, if the patch is successful, the changes ". | 'Normally under git/hg, if the patch is successful, the changes '. | ||||
| "are committed to the working copy. This flag prevents the commit.", | 'are committed to the working copy. This flag prevents the commit.', | ||||
| ), | ), | ||||
| 'skip-dependencies' => array( | 'skip-dependencies' => array( | ||||
| 'supports' => array( | 'supports' => array( | ||||
| 'git', 'hg' | 'git', 'hg' | ||||
| ), | ), | ||||
| 'help' => | 'help' => | ||||
| 'Normally, if a patch has dependencies that are not present in the '. | 'Normally, if a patch has dependencies that are not present in the '. | ||||
| 'working copy, arc tries to apply them as well. This flag prevents '. | 'working copy, arc tries to apply them as well. This flag prevents '. | ||||
| 'such work.', | 'such work.', | ||||
| ), | ), | ||||
| 'nobranch' => array( | 'nobranch' => array( | ||||
| 'supports' => array( | 'supports' => array( | ||||
| 'git', 'hg' | 'git', 'hg' | ||||
| ), | ), | ||||
| 'help' => | 'help' => | ||||
| "Normally, a new branch (git) or bookmark (hg) is created and then ". | 'Normally, a new branch (git) or bookmark (hg) is created and then '. | ||||
| "the patch is applied and committed in the new branch/bookmark. ". | 'the patch is applied and committed in the new branch/bookmark. '. | ||||
| "This flag cherry-picks the resultant commit onto the original ". | 'This flag cherry-picks the resultant commit onto the original '. | ||||
| "branch and deletes the temporary branch.", | 'branch and deletes the temporary branch.', | ||||
| 'conflicts' => array( | 'conflicts' => array( | ||||
| 'update' => true, | 'update' => true, | ||||
| ), | ), | ||||
| ), | ), | ||||
| 'force' => array( | 'force' => array( | ||||
| 'help' => | 'help' => | ||||
| "Do not run any sanity checks.", | 'Do not run any sanity checks.', | ||||
| ), | ), | ||||
| '*' => 'name', | '*' => 'name', | ||||
| ); | ); | ||||
| } | } | ||||
| protected function didParseArguments() { | protected function didParseArguments() { | ||||
| $source = null; | $source = null; | ||||
| $requested = 0; | $requested = 0; | ||||
| Show All 13 Lines | if ($this->getArgument('patch')) { | ||||
| $source = self::SOURCE_PATCH; | $source = self::SOURCE_PATCH; | ||||
| $requested++; | $requested++; | ||||
| } | } | ||||
| $use_revision_id = null; | $use_revision_id = null; | ||||
| if ($this->getArgument('name')) { | if ($this->getArgument('name')) { | ||||
| $namev = $this->getArgument('name'); | $namev = $this->getArgument('name'); | ||||
| if (count($namev) > 1) { | if (count($namev) > 1) { | ||||
| throw new ArcanistUsageException("Specify at most one revision name."); | throw new ArcanistUsageException('Specify at most one revision name.'); | ||||
| } | } | ||||
| $source = self::SOURCE_REVISION; | $source = self::SOURCE_REVISION; | ||||
| $requested++; | $requested++; | ||||
| $use_revision_id = $this->normalizeRevisionID(head($namev)); | $use_revision_id = $this->normalizeRevisionID(head($namev)); | ||||
| } | } | ||||
| if ($requested === 0) { | if ($requested === 0) { | ||||
| ▲ Show 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | private function shouldBranch() { | ||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| private function getBranchName(ArcanistBundle $bundle) { | private function getBranchName(ArcanistBundle $bundle) { | ||||
| $branch_name = null; | $branch_name = null; | ||||
| $repository_api = $this->getRepositoryAPI(); | $repository_api = $this->getRepositoryAPI(); | ||||
| $revision_id = $bundle->getRevisionID(); | $revision_id = $bundle->getRevisionID(); | ||||
| $base_name = "arcpatch"; | $base_name = 'arcpatch'; | ||||
| if ($revision_id) { | if ($revision_id) { | ||||
| $base_name .= "-D{$revision_id}"; | $base_name .= "-D{$revision_id}"; | ||||
| } | } | ||||
| $suffixes = array(null, '_1', '_2', '_3'); | $suffixes = array(null, '_1', '_2', '_3'); | ||||
| foreach ($suffixes as $suffix) { | foreach ($suffixes as $suffix) { | ||||
| $proposed_name = $base_name.$suffix; | $proposed_name = $base_name.$suffix; | ||||
| Show All 9 Lines | foreach ($suffixes as $suffix) { | ||||
| } else { | } else { | ||||
| $branch_name = $proposed_name; | $branch_name = $proposed_name; | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| if (!$branch_name) { | if (!$branch_name) { | ||||
| throw new Exception( | throw new Exception( | ||||
| "Arc was unable to automagically make a name for this patch. ". | 'Arc was unable to automagically make a name for this patch. '. | ||||
| "Please clean up your working copy and try again." | 'Please clean up your working copy and try again.' | ||||
| ); | ); | ||||
| } | } | ||||
| return $branch_name; | return $branch_name; | ||||
| } | } | ||||
| private function getBookmarkName(ArcanistBundle $bundle) { | private function getBookmarkName(ArcanistBundle $bundle) { | ||||
| $bookmark_name = null; | $bookmark_name = null; | ||||
| $repository_api = $this->getRepositoryAPI(); | $repository_api = $this->getRepositoryAPI(); | ||||
| $revision_id = $bundle->getRevisionID(); | $revision_id = $bundle->getRevisionID(); | ||||
| $base_name = "arcpatch"; | $base_name = 'arcpatch'; | ||||
| if ($revision_id) { | if ($revision_id) { | ||||
| $base_name .= "-D{$revision_id}"; | $base_name .= "-D{$revision_id}"; | ||||
| } | } | ||||
| $suffixes = array(null, '-1', '-2', '-3'); | $suffixes = array(null, '-1', '-2', '-3'); | ||||
| foreach ($suffixes as $suffix) { | foreach ($suffixes as $suffix) { | ||||
| $proposed_name = $base_name.$suffix; | $proposed_name = $base_name.$suffix; | ||||
| Show All 10 Lines | foreach ($suffixes as $suffix) { | ||||
| } else { | } else { | ||||
| $bookmark_name = $proposed_name; | $bookmark_name = $proposed_name; | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| if (!$bookmark_name) { | if (!$bookmark_name) { | ||||
| throw new Exception( | throw new Exception( | ||||
| "Arc was unable to automagically make a name for this patch. ". | 'Arc was unable to automagically make a name for this patch. '. | ||||
| "Please clean up your working copy and try again." | 'Please clean up your working copy and try again.' | ||||
| ); | ); | ||||
| } | } | ||||
| return $bookmark_name; | return $bookmark_name; | ||||
| } | } | ||||
| private function createBranch(ArcanistBundle $bundle, $has_base_revision) { | private function createBranch(ArcanistBundle $bundle, $has_base_revision) { | ||||
| $repository_api = $this->getRepositoryAPI(); | $repository_api = $this->getRepositoryAPI(); | ||||
| ▲ Show 20 Lines • Show All 63 Lines • ▼ Show 20 Lines | public function run() { | ||||
| $param = $this->getSourceParam(); | $param = $this->getSourceParam(); | ||||
| try { | try { | ||||
| switch ($source) { | switch ($source) { | ||||
| case self::SOURCE_PATCH: | case self::SOURCE_PATCH: | ||||
| if ($param == '-') { | if ($param == '-') { | ||||
| $patch = @file_get_contents('php://stdin'); | $patch = @file_get_contents('php://stdin'); | ||||
| if (!strlen($patch)) { | if (!strlen($patch)) { | ||||
| throw new ArcanistUsageException( | throw new ArcanistUsageException( | ||||
| "Failed to read patch from stdin!"); | 'Failed to read patch from stdin!'); | ||||
| } | } | ||||
| } else { | } else { | ||||
| $patch = Filesystem::readFile($param); | $patch = Filesystem::readFile($param); | ||||
| } | } | ||||
| $bundle = ArcanistBundle::newFromDiff($patch); | $bundle = ArcanistBundle::newFromDiff($patch); | ||||
| break; | break; | ||||
| case self::SOURCE_BUNDLE: | case self::SOURCE_BUNDLE: | ||||
| $path = $this->getArgument('arcbundle'); | $path = $this->getArgument('arcbundle'); | ||||
| ▲ Show 20 Lines • Show All 306 Lines • ▼ Show 20 Lines | if ($repository_api instanceof ArcanistSubversionAPI) { | ||||
| echo phutil_console_format( | echo phutil_console_format( | ||||
| "\n<bg:red>** Patch Failed! **</bg>\n"); | "\n<bg:red>** Patch Failed! **</bg>\n"); | ||||
| // NOTE: Git patches may fail if they change the case of a filename | // NOTE: Git patches may fail if they change the case of a filename | ||||
| // (for instance, from 'example.c' to 'Example.c'). As of now, Git | // (for instance, from 'example.c' to 'Example.c'). As of now, Git | ||||
| // can not apply these patches on case-insensitive filesystems and | // can not apply these patches on case-insensitive filesystems and | ||||
| // there is no way to build a patch which works. | // there is no way to build a patch which works. | ||||
| throw new ArcanistUsageException("Unable to apply patch!"); | throw new ArcanistUsageException('Unable to apply patch!'); | ||||
| } | } | ||||
| // in case there were any submodule changes involved | // in case there were any submodule changes involved | ||||
| $repository_api->execpassthru( | $repository_api->execpassthru( | ||||
| 'submodule update --init --recursive'); | 'submodule update --init --recursive'); | ||||
| if ($this->shouldCommit()) { | if ($this->shouldCommit()) { | ||||
| if ($bundle->getFullAuthor()) { | if ($bundle->getFullAuthor()) { | ||||
| ▲ Show 20 Lines • Show All 397 Lines • Show Last 20 Lines | |||||