2011-01-10 00:22:25 +01:00
|
|
|
<?php
|
|
|
|
|
2011-02-19 20:36:08 +01:00
|
|
|
/**
|
|
|
|
* Interfaces with the VCS in the working copy.
|
|
|
|
*
|
|
|
|
* @group workingcopy
|
|
|
|
*/
|
2011-01-10 00:22:25 +01:00
|
|
|
abstract class ArcanistRepositoryAPI {
|
|
|
|
|
|
|
|
const FLAG_MODIFIED = 1;
|
|
|
|
const FLAG_ADDED = 2;
|
|
|
|
const FLAG_DELETED = 4;
|
|
|
|
const FLAG_UNTRACKED = 8;
|
|
|
|
const FLAG_CONFLICT = 16;
|
|
|
|
const FLAG_MISSING = 32;
|
|
|
|
const FLAG_UNSTAGED = 64;
|
|
|
|
const FLAG_UNCOMMITTED = 128;
|
|
|
|
const FLAG_EXTERNALS = 256;
|
|
|
|
|
2011-03-13 02:57:35 +01:00
|
|
|
// Occurs in SVN when you replace a file with a directory without telling
|
|
|
|
// SVN about it.
|
2011-01-10 00:22:25 +01:00
|
|
|
const FLAG_OBSTRUCTED = 512;
|
|
|
|
|
2011-03-13 02:57:35 +01:00
|
|
|
// Occurs in SVN when an update was interrupted or failed, e.g. you ^C'd it.
|
|
|
|
const FLAG_INCOMPLETE = 1024;
|
|
|
|
|
2011-01-10 00:22:25 +01:00
|
|
|
protected $path;
|
|
|
|
protected $diffLinesOfContext = 0x7FFF;
|
2012-06-14 21:02:41 +02:00
|
|
|
private $baseCommitExplanation = '???';
|
2012-04-04 01:06:43 +02:00
|
|
|
private $workingCopyIdentity;
|
Add a DSL for selecting base commits
Summary:
New optional mode. If you set 'base' in local, project or global config or pass '--base' to 'arc diff' or 'arc which', it switches to DSL mode.
In DSL mode, lists of rules from args, local, project and global config are resolved, in that order. Rules can manipulate the rule machine or resolve into actual commits. Provides support for some 'arc' rules (mostly machine manipulation) and 'git' rules (symbolic ref and merge-base).
Test Plan:
Ran unit tests. Also:
```$ arc which --show-base --base 'arc:prompt'
Against which commit? HEAD
HEAD
$ arc which --show-base --base 'git:HEAD'
HEAD
$ arc which --show-base --base 'git:fake'
Usage Exception: None of the rules in your 'base' configuration matched a valid commit. Adjust rules or specify which commit you want to use explicitly.
$ arc which --show-base --base 'git:origin/master'
origin/master
$ arc which --show-base --base 'git:upstream'
Usage Exception: None of the rules in your 'base' configuration matched a valid commit. Adjust rules or specify which commit you want to use explicitly.
$ arc which --show-base --base 'literal:derp'
derp
$ arc which --show-base --base 'arc:halt'
Usage Exception: None of the rules in your 'base' configuration matched a valid commit. Adjust rules or specify which commit you want to use explicitly.
$ arc set-config --local base git:origin/master
Set key 'base' = 'git:origin/master' in local config.
$ arc which --show-base
origin/master
$ arc which --show-base --base 'git:HEAD^'
HEAD^
$ arc which --show-base --base 'arc:yield, git:HEAD^'
origin/master
$ arc which --show-base --base 'arc:global, git:HEAD^'
HEAD^
$ arc which --show-base --base 'arc:global, git:merge-base(origin/master)'
3f4f8992fba8d1f142974da36a82bae900e247c0```
Reviewers: dschleimer, vrana
Reviewed By: dschleimer
CC: aran
Maniphest Tasks: T1233
Differential Revision: https://secure.phabricator.com/D2748
2012-06-15 23:01:28 +02:00
|
|
|
private $baseCommitArgumentRules;
|
2011-01-10 00:22:25 +01:00
|
|
|
|
|
|
|
abstract public function getSourceControlSystemName();
|
|
|
|
|
|
|
|
public function getDiffLinesOfContext() {
|
|
|
|
return $this->diffLinesOfContext;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setDiffLinesOfContext($lines) {
|
|
|
|
$this->diffLinesOfContext = $lines;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2012-04-04 01:06:43 +02:00
|
|
|
public function getWorkingCopyIdentity() {
|
|
|
|
return $this->workingCopyIdentity;
|
|
|
|
}
|
|
|
|
|
2011-01-10 00:22:25 +01:00
|
|
|
public static function newAPIFromWorkingCopyIdentity(
|
|
|
|
ArcanistWorkingCopyIdentity $working_copy) {
|
|
|
|
|
|
|
|
$root = $working_copy->getProjectRoot();
|
|
|
|
|
|
|
|
if (!$root) {
|
|
|
|
throw new ArcanistUsageException(
|
|
|
|
"There is no readable '.arcconfig' file in the working directory or ".
|
|
|
|
"any parent directory. Create an '.arcconfig' file to configure arc.");
|
|
|
|
}
|
|
|
|
|
2012-03-09 22:37:48 +01:00
|
|
|
// check if we're in an svn working copy
|
|
|
|
list($err) = exec_manual('svn info');
|
|
|
|
if (!$err) {
|
2012-05-31 01:04:45 +02:00
|
|
|
$api = new ArcanistSubversionAPI($root);
|
2012-04-04 01:06:43 +02:00
|
|
|
$api->workingCopyIdentity = $working_copy;
|
|
|
|
return $api;
|
2011-01-10 00:22:25 +01:00
|
|
|
}
|
|
|
|
|
Basic Mercurial support for Arcanist
Summary:
There's a lot of ground left to cover but this makes "arc diff" work (on one
trivial diff) in my sandbox, at least, and supports parsing of Mercurial native
diffs (which are unified + a custom header). Piles of missing features, still.
Some of this is blocked by me not understanding the mercurial model well yet.
This is also a really good opportunity for cleanup (especially, reducing the
level of "instanceof" in the diff workflow), I'll try to do a bunch of that in
followup diffs.
Test Plan: Ran "arc diff" in a mercurial repository, got a diff out of it.
Reviewed By: aran
Reviewers: Makinde, jungejason, tuomaspelkonen, aran, codeblock
CC: aran, epriestley, codeblock, fratrik
Differential Revision: 792
2011-08-09 18:00:29 +02:00
|
|
|
if (Filesystem::pathExists($root.'/.hg')) {
|
2012-05-31 01:04:45 +02:00
|
|
|
$api = new ArcanistMercurialAPI($root);
|
2012-04-04 01:06:43 +02:00
|
|
|
$api->workingCopyIdentity = $working_copy;
|
|
|
|
return $api;
|
Basic Mercurial support for Arcanist
Summary:
There's a lot of ground left to cover but this makes "arc diff" work (on one
trivial diff) in my sandbox, at least, and supports parsing of Mercurial native
diffs (which are unified + a custom header). Piles of missing features, still.
Some of this is blocked by me not understanding the mercurial model well yet.
This is also a really good opportunity for cleanup (especially, reducing the
level of "instanceof" in the diff workflow), I'll try to do a bunch of that in
followup diffs.
Test Plan: Ran "arc diff" in a mercurial repository, got a diff out of it.
Reviewed By: aran
Reviewers: Makinde, jungejason, tuomaspelkonen, aran, codeblock
CC: aran, epriestley, codeblock, fratrik
Differential Revision: 792
2011-08-09 18:00:29 +02:00
|
|
|
}
|
|
|
|
|
2011-01-10 00:22:25 +01:00
|
|
|
$git_root = self::discoverGitBaseDirectory($root);
|
|
|
|
if ($git_root) {
|
|
|
|
if (!Filesystem::pathsAreEquivalent($root, $git_root)) {
|
|
|
|
throw new ArcanistUsageException(
|
|
|
|
"'.arcconfig' file is located at '{$root}', but working copy root ".
|
|
|
|
"is '{$git_root}'. Move '.arcconfig' file to the working copy root.");
|
|
|
|
}
|
Basic Mercurial support for Arcanist
Summary:
There's a lot of ground left to cover but this makes "arc diff" work (on one
trivial diff) in my sandbox, at least, and supports parsing of Mercurial native
diffs (which are unified + a custom header). Piles of missing features, still.
Some of this is blocked by me not understanding the mercurial model well yet.
This is also a really good opportunity for cleanup (especially, reducing the
level of "instanceof" in the diff workflow), I'll try to do a bunch of that in
followup diffs.
Test Plan: Ran "arc diff" in a mercurial repository, got a diff out of it.
Reviewed By: aran
Reviewers: Makinde, jungejason, tuomaspelkonen, aran, codeblock
CC: aran, epriestley, codeblock, fratrik
Differential Revision: 792
2011-08-09 18:00:29 +02:00
|
|
|
|
2012-05-31 01:04:45 +02:00
|
|
|
$api = new ArcanistGitAPI($root);
|
2012-04-04 01:06:43 +02:00
|
|
|
$api->workingCopyIdentity = $working_copy;
|
|
|
|
return $api;
|
2011-01-10 00:22:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
throw new ArcanistUsageException(
|
|
|
|
"The current working directory is not part of a working copy for a ".
|
Basic Mercurial support for Arcanist
Summary:
There's a lot of ground left to cover but this makes "arc diff" work (on one
trivial diff) in my sandbox, at least, and supports parsing of Mercurial native
diffs (which are unified + a custom header). Piles of missing features, still.
Some of this is blocked by me not understanding the mercurial model well yet.
This is also a really good opportunity for cleanup (especially, reducing the
level of "instanceof" in the diff workflow), I'll try to do a bunch of that in
followup diffs.
Test Plan: Ran "arc diff" in a mercurial repository, got a diff out of it.
Reviewed By: aran
Reviewers: Makinde, jungejason, tuomaspelkonen, aran, codeblock
CC: aran, epriestley, codeblock, fratrik
Differential Revision: 792
2011-08-09 18:00:29 +02:00
|
|
|
"supported version control system (svn, git or mercurial).");
|
2011-01-10 00:22:25 +01:00
|
|
|
}
|
|
|
|
|
Basic Mercurial support for Arcanist
Summary:
There's a lot of ground left to cover but this makes "arc diff" work (on one
trivial diff) in my sandbox, at least, and supports parsing of Mercurial native
diffs (which are unified + a custom header). Piles of missing features, still.
Some of this is blocked by me not understanding the mercurial model well yet.
This is also a really good opportunity for cleanup (especially, reducing the
level of "instanceof" in the diff workflow), I'll try to do a bunch of that in
followup diffs.
Test Plan: Ran "arc diff" in a mercurial repository, got a diff out of it.
Reviewed By: aran
Reviewers: Makinde, jungejason, tuomaspelkonen, aran, codeblock
CC: aran, epriestley, codeblock, fratrik
Differential Revision: 792
2011-08-09 18:00:29 +02:00
|
|
|
public function __construct($path) {
|
2011-01-10 00:22:25 +01:00
|
|
|
$this->path = $path;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getPath($to_file = null) {
|
|
|
|
if ($to_file !== null) {
|
2012-03-25 18:32:20 +02:00
|
|
|
return $this->path.DIRECTORY_SEPARATOR.
|
|
|
|
ltrim($to_file, DIRECTORY_SEPARATOR);
|
2011-01-10 00:22:25 +01:00
|
|
|
} else {
|
2012-03-25 18:32:20 +02:00
|
|
|
return $this->path.DIRECTORY_SEPARATOR;
|
2011-01-10 00:22:25 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getUntrackedChanges() {
|
|
|
|
return $this->getWorkingCopyFilesWithMask(self::FLAG_UNTRACKED);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getUnstagedChanges() {
|
|
|
|
return $this->getWorkingCopyFilesWithMask(self::FLAG_UNSTAGED);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getUncommittedChanges() {
|
|
|
|
return $this->getWorkingCopyFilesWithMask(self::FLAG_UNCOMMITTED);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getMergeConflicts() {
|
|
|
|
return $this->getWorkingCopyFilesWithMask(self::FLAG_CONFLICT);
|
|
|
|
}
|
|
|
|
|
2011-03-13 02:57:35 +01:00
|
|
|
public function getIncompleteChanges() {
|
|
|
|
return $this->getWorkingCopyFilesWithMask(self::FLAG_INCOMPLETE);
|
|
|
|
}
|
|
|
|
|
2011-01-10 00:22:25 +01:00
|
|
|
private function getWorkingCopyFilesWithMask($mask) {
|
|
|
|
$match = array();
|
|
|
|
foreach ($this->getWorkingCopyStatus() as $file => $flags) {
|
|
|
|
if ($flags & $mask) {
|
|
|
|
$match[] = $file;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $match;
|
|
|
|
}
|
|
|
|
|
|
|
|
private static function discoverGitBaseDirectory($root) {
|
|
|
|
try {
|
2012-03-05 22:22:04 +01:00
|
|
|
|
|
|
|
// NOTE: This awkward construction is to make sure things work on Windows.
|
|
|
|
$future = new ExecFuture('git rev-parse --show-cdup');
|
|
|
|
$future->setCWD($root);
|
|
|
|
list($stdout) = $future->resolvex();
|
|
|
|
|
2011-01-10 00:22:25 +01:00
|
|
|
return Filesystem::resolvePath(rtrim($stdout, "\n"), $root);
|
|
|
|
} catch (CommandException $ex) {
|
|
|
|
if (preg_match('/^fatal: Not a git repository/', $ex->getStdErr())) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
throw $ex;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-09 08:22:29 +01:00
|
|
|
/**
|
|
|
|
* @return Traversable
|
|
|
|
*/
|
|
|
|
abstract public function getAllFiles();
|
|
|
|
|
2011-01-10 00:22:25 +01:00
|
|
|
abstract public function getBlame($path);
|
|
|
|
abstract public function getWorkingCopyStatus();
|
|
|
|
abstract public function getRawDiffText($path);
|
2011-01-11 22:02:38 +01:00
|
|
|
abstract public function getOriginalFileData($path);
|
|
|
|
abstract public function getCurrentFileData($path);
|
2011-08-24 03:48:55 +02:00
|
|
|
abstract public function getLocalCommitInformation();
|
2011-12-03 01:21:14 +01:00
|
|
|
abstract public function getSourceControlBaseRevision();
|
2012-03-09 23:40:47 +01:00
|
|
|
abstract public function getCanonicalRevisionName($string);
|
2012-11-07 09:50:17 +01:00
|
|
|
abstract public function getBranchName();
|
|
|
|
abstract public function getSourceControlPath();
|
2012-06-04 21:30:50 +02:00
|
|
|
abstract public function isHistoryDefaultImmutable();
|
|
|
|
abstract public function supportsAmend();
|
2011-09-15 03:44:54 +02:00
|
|
|
abstract public function supportsRelativeLocalCommits();
|
2011-12-03 01:21:14 +01:00
|
|
|
abstract public function getWorkingCopyRevision();
|
2012-03-16 21:40:33 +01:00
|
|
|
abstract public function updateWorkingCopy();
|
2012-06-12 21:39:15 +02:00
|
|
|
abstract public function getMetadataPath();
|
2012-01-24 17:07:38 +01:00
|
|
|
abstract public function loadWorkingCopyDifferentialRevisions(
|
|
|
|
ConduitClient $conduit,
|
|
|
|
array $query);
|
2011-09-15 03:44:54 +02:00
|
|
|
|
2012-10-19 19:10:25 +02:00
|
|
|
/**
|
|
|
|
* Set the base commit to a reasonable default value so that working copy
|
|
|
|
* status checks can do something meaningful and won't invoke configured
|
|
|
|
* 'base' rules.
|
|
|
|
*
|
|
|
|
* This is primarily useful for workflows which do not operate on commit
|
|
|
|
* ranges but need to verify the working copy is not dirty, like "amend",
|
|
|
|
* "upgrade" and "patch".
|
|
|
|
*
|
|
|
|
* @return this
|
|
|
|
*/
|
|
|
|
public function setDefaultBaseCommit() {
|
|
|
|
throw new ArcanistCapabilityNotSupportedException($this);
|
|
|
|
}
|
|
|
|
|
2012-11-09 08:26:27 +01:00
|
|
|
public function getChangedFiles($since_commit) {
|
|
|
|
throw new ArcanistCapabilityNotSupportedException($this);
|
|
|
|
}
|
|
|
|
|
2012-06-08 04:36:30 +02:00
|
|
|
public function amendCommit($message) {
|
2012-06-04 21:30:50 +02:00
|
|
|
throw new ArcanistCapabilityNotSupportedException($this);
|
|
|
|
}
|
|
|
|
|
2012-04-23 23:09:29 +02:00
|
|
|
public function getAllBranches() {
|
|
|
|
// TODO: Implement for Mercurial/SVN and make abstract.
|
|
|
|
return array();
|
|
|
|
}
|
|
|
|
|
2012-03-07 22:02:53 +01:00
|
|
|
public function hasLocalCommit($commit) {
|
|
|
|
throw new ArcanistCapabilityNotSupportedException($this);
|
|
|
|
}
|
|
|
|
|
2012-07-01 20:06:05 +02:00
|
|
|
public function getCommitMessage($commit) {
|
2012-01-13 04:03:11 +01:00
|
|
|
throw new ArcanistCapabilityNotSupportedException($this);
|
|
|
|
}
|
|
|
|
|
2011-09-15 03:44:54 +02:00
|
|
|
public function parseRelativeLocalCommit(array $argv) {
|
Add an "arc merge" workflow
Summary:
This should support conservative rewrite policies in git fairly well, under an
assumed workflow of:
- Develop in local branches, never rewrite history.
- Commit with "-m" or by typing a brief, non-template commit message
describing the checkpoint.
- Provide rich information in the web console (reviewers, etc.)
- Finalize with "git checkout master && arc merge branch && git push" or some
flavor thereof.
This supports Mercurial somewhat. The major problem is that "hg merge" fails if
the local is a fastforward of the remote, at which point there's nowhere we can
throw the commit message. Oh well. Just push it and we'll do our best to link
them up based on local commit info.
I am increasingly forming an opinion that Mercurial is "saftey-scissors git".
But also maybe I have no clue what I'm doing. I just don't understand why anyone
would think it's a good idea to have a trunk consisting of ~50% known-broken
revisions, random checkpoint parts, whitespace changes, typo fixes, etc. If you
use git with branching you can avoid this by making a trunk out of merges or
with rebase/amend, but there seems to be no way to have "one commit = one idea"
in any real sense in Mercurial.
Test Plan: Execute "arc merge" in git and mercurial.
Reviewers: fratrik, Makinde, aran, jungejason, tuomaspelkonen
Reviewed By: Makinde
CC: aran, epriestley, Makinde
Differential Revision: 860
2011-08-26 01:02:03 +02:00
|
|
|
throw new ArcanistCapabilityNotSupportedException($this);
|
2011-09-15 03:44:54 +02:00
|
|
|
}
|
|
|
|
|
2012-05-11 15:07:33 +02:00
|
|
|
public function getCommitSummary($commit) {
|
|
|
|
throw new ArcanistCapabilityNotSupportedException($this);
|
|
|
|
}
|
|
|
|
|
2011-09-15 03:44:54 +02:00
|
|
|
public function getAllLocalChanges() {
|
Add an "arc merge" workflow
Summary:
This should support conservative rewrite policies in git fairly well, under an
assumed workflow of:
- Develop in local branches, never rewrite history.
- Commit with "-m" or by typing a brief, non-template commit message
describing the checkpoint.
- Provide rich information in the web console (reviewers, etc.)
- Finalize with "git checkout master && arc merge branch && git push" or some
flavor thereof.
This supports Mercurial somewhat. The major problem is that "hg merge" fails if
the local is a fastforward of the remote, at which point there's nowhere we can
throw the commit message. Oh well. Just push it and we'll do our best to link
them up based on local commit info.
I am increasingly forming an opinion that Mercurial is "saftey-scissors git".
But also maybe I have no clue what I'm doing. I just don't understand why anyone
would think it's a good idea to have a trunk consisting of ~50% known-broken
revisions, random checkpoint parts, whitespace changes, typo fixes, etc. If you
use git with branching you can avoid this by making a trunk out of merges or
with rebase/amend, but there seems to be no way to have "one commit = one idea"
in any real sense in Mercurial.
Test Plan: Execute "arc merge" in git and mercurial.
Reviewers: fratrik, Makinde, aran, jungejason, tuomaspelkonen
Reviewed By: Makinde
CC: aran, epriestley, Makinde
Differential Revision: 860
2011-08-26 01:02:03 +02:00
|
|
|
throw new ArcanistCapabilityNotSupportedException($this);
|
|
|
|
}
|
|
|
|
|
|
|
|
abstract public function supportsLocalBranchMerge();
|
|
|
|
|
|
|
|
public function performLocalBranchMerge($branch, $message) {
|
|
|
|
throw new ArcanistCapabilityNotSupportedException($this);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getFinalizedRevisionMessage() {
|
|
|
|
throw new ArcanistCapabilityNotSupportedException($this);
|
2011-09-15 03:44:54 +02:00
|
|
|
}
|
|
|
|
|
2012-07-01 20:06:05 +02:00
|
|
|
public function execxLocal($pattern /* , ... */) {
|
2012-03-03 01:47:34 +01:00
|
|
|
$args = func_get_args();
|
|
|
|
return $this->buildLocalFuture($args)->resolvex();
|
|
|
|
}
|
|
|
|
|
2012-07-01 20:06:05 +02:00
|
|
|
public function execManualLocal($pattern /* , ... */) {
|
2012-03-03 01:47:34 +01:00
|
|
|
$args = func_get_args();
|
|
|
|
return $this->buildLocalFuture($args)->resolve();
|
|
|
|
}
|
|
|
|
|
2012-07-01 20:06:05 +02:00
|
|
|
public function execFutureLocal($pattern /* , ... */) {
|
2012-03-25 18:32:20 +02:00
|
|
|
$args = func_get_args();
|
|
|
|
return $this->buildLocalFuture($args);
|
|
|
|
}
|
|
|
|
|
2012-03-03 01:47:34 +01:00
|
|
|
abstract protected function buildLocalFuture(array $argv);
|
|
|
|
|
Revenge of the git relative commit default
Summary:
The default of "arc diff" to "arc diff HEAD^" in git is universally confusing to everyone not at Facebook.
Drive the default with configuration instead. Even at Facebook, "origin/trunk" (or whatever) is probably a better default than "HEAD^".
See D863 for the last attempt at this.
NOTE: This is contentious!
Test Plan: Ran "arc diff", got prompted to set a default. Ran "arc diff" from a zero-commit repo, got sensible behavior
Reviewers: btrahan, vrana, nh, jungejason, tuomaspelkonen
Reviewed By: btrahan
CC: aran, epriestley, zeeg, davidreuss
Maniphest Tasks: T651
Differential Revision: https://secure.phabricator.com/D1861
2012-04-03 01:52:20 +02:00
|
|
|
|
|
|
|
/* -( Scratch Files )------------------------------------------------------ */
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Try to read a scratch file, if it exists and is readable.
|
|
|
|
*
|
|
|
|
* @param string Scratch file name.
|
|
|
|
* @return mixed String for file contents, or false for failure.
|
|
|
|
* @task scratch
|
|
|
|
*/
|
|
|
|
public function readScratchFile($path) {
|
|
|
|
$full_path = $this->getScratchFilePath($path);
|
|
|
|
if (!$full_path) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!Filesystem::pathExists($full_path)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
$result = Filesystem::readFile($full_path);
|
|
|
|
} catch (FilesystemException $ex) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Try to write a scratch file, if there's somewhere to put it and we can
|
|
|
|
* write there.
|
|
|
|
*
|
|
|
|
* @param string Scratch file name to write.
|
|
|
|
* @param string Data to write.
|
|
|
|
* @return bool True on success, false on failure.
|
|
|
|
* @task scratch
|
|
|
|
*/
|
|
|
|
public function writeScratchFile($path, $data) {
|
|
|
|
$dir = $this->getScratchFilePath('');
|
|
|
|
if (!$dir) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!Filesystem::pathExists($dir)) {
|
|
|
|
try {
|
|
|
|
Filesystem::createDirectory($dir);
|
|
|
|
} catch (Exception $ex) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
Filesystem::writeFile($this->getScratchFilePath($path), $data);
|
|
|
|
} catch (FilesystemException $ex) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Try to remove a scratch file.
|
|
|
|
*
|
|
|
|
* @param string Scratch file name to remove.
|
|
|
|
* @return bool True if the file was removed successfully.
|
|
|
|
* @task scratch
|
|
|
|
*/
|
|
|
|
public function removeScratchFile($path) {
|
|
|
|
$full_path = $this->getScratchFilePath($path);
|
|
|
|
if (!$full_path) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
Filesystem::remove($full_path);
|
|
|
|
} catch (FilesystemException $ex) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get a human-readable description of the scratch file location.
|
|
|
|
*
|
|
|
|
* @param string Scratch file name.
|
|
|
|
* @return mixed String, or false on failure.
|
|
|
|
* @task scratch
|
|
|
|
*/
|
|
|
|
public function getReadableScratchFilePath($path) {
|
|
|
|
$full_path = $this->getScratchFilePath($path);
|
|
|
|
if ($full_path) {
|
|
|
|
return Filesystem::readablePath(
|
|
|
|
$full_path,
|
|
|
|
$this->getPath());
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the path to a scratch file, if possible.
|
|
|
|
*
|
|
|
|
* @param string Scratch file name.
|
|
|
|
* @return mixed File path, or false on failure.
|
|
|
|
* @task scratch
|
|
|
|
*/
|
|
|
|
public function getScratchFilePath($path) {
|
2012-06-12 21:39:15 +02:00
|
|
|
$new_scratch_path = Filesystem::resolvePath(
|
|
|
|
'arc',
|
|
|
|
$this->getMetadataPath());
|
|
|
|
|
|
|
|
static $checked = false;
|
|
|
|
if (!$checked) {
|
|
|
|
$checked = true;
|
|
|
|
$old_scratch_path = $this->getPath('.arc');
|
|
|
|
// we only want to do the migration once
|
|
|
|
// unfortunately, people have checked in .arc directories which
|
|
|
|
// means that the old one may get recreated after we delete it
|
|
|
|
if (Filesystem::pathExists($old_scratch_path) &&
|
|
|
|
!Filesystem::pathExists($new_scratch_path)) {
|
|
|
|
Filesystem::createDirectory($new_scratch_path);
|
|
|
|
$existing_files = Filesystem::listDirectory($old_scratch_path, true);
|
|
|
|
foreach ($existing_files as $file) {
|
|
|
|
$new_path = Filesystem::resolvePath($file, $new_scratch_path);
|
|
|
|
$old_path = Filesystem::resolvePath($file, $old_scratch_path);
|
|
|
|
Filesystem::writeFile(
|
|
|
|
$new_path,
|
|
|
|
Filesystem::readFile($old_path));
|
|
|
|
}
|
|
|
|
Filesystem::remove($old_scratch_path);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Filesystem::resolvePath($path, $new_scratch_path);
|
Revenge of the git relative commit default
Summary:
The default of "arc diff" to "arc diff HEAD^" in git is universally confusing to everyone not at Facebook.
Drive the default with configuration instead. Even at Facebook, "origin/trunk" (or whatever) is probably a better default than "HEAD^".
See D863 for the last attempt at this.
NOTE: This is contentious!
Test Plan: Ran "arc diff", got prompted to set a default. Ran "arc diff" from a zero-commit repo, got sensible behavior
Reviewers: btrahan, vrana, nh, jungejason, tuomaspelkonen
Reviewed By: btrahan
CC: aran, epriestley, zeeg, davidreuss
Maniphest Tasks: T651
Differential Revision: https://secure.phabricator.com/D1861
2012-04-03 01:52:20 +02:00
|
|
|
}
|
|
|
|
|
Add a DSL for selecting base commits
Summary:
New optional mode. If you set 'base' in local, project or global config or pass '--base' to 'arc diff' or 'arc which', it switches to DSL mode.
In DSL mode, lists of rules from args, local, project and global config are resolved, in that order. Rules can manipulate the rule machine or resolve into actual commits. Provides support for some 'arc' rules (mostly machine manipulation) and 'git' rules (symbolic ref and merge-base).
Test Plan:
Ran unit tests. Also:
```$ arc which --show-base --base 'arc:prompt'
Against which commit? HEAD
HEAD
$ arc which --show-base --base 'git:HEAD'
HEAD
$ arc which --show-base --base 'git:fake'
Usage Exception: None of the rules in your 'base' configuration matched a valid commit. Adjust rules or specify which commit you want to use explicitly.
$ arc which --show-base --base 'git:origin/master'
origin/master
$ arc which --show-base --base 'git:upstream'
Usage Exception: None of the rules in your 'base' configuration matched a valid commit. Adjust rules or specify which commit you want to use explicitly.
$ arc which --show-base --base 'literal:derp'
derp
$ arc which --show-base --base 'arc:halt'
Usage Exception: None of the rules in your 'base' configuration matched a valid commit. Adjust rules or specify which commit you want to use explicitly.
$ arc set-config --local base git:origin/master
Set key 'base' = 'git:origin/master' in local config.
$ arc which --show-base
origin/master
$ arc which --show-base --base 'git:HEAD^'
HEAD^
$ arc which --show-base --base 'arc:yield, git:HEAD^'
origin/master
$ arc which --show-base --base 'arc:global, git:HEAD^'
HEAD^
$ arc which --show-base --base 'arc:global, git:merge-base(origin/master)'
3f4f8992fba8d1f142974da36a82bae900e247c0```
Reviewers: dschleimer, vrana
Reviewed By: dschleimer
CC: aran
Maniphest Tasks: T1233
Differential Revision: https://secure.phabricator.com/D2748
2012-06-15 23:01:28 +02:00
|
|
|
|
|
|
|
/* -( Base Commits )------------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
|
|
public function getBaseCommitExplanation() {
|
|
|
|
return $this->baseCommitExplanation;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setBaseCommitExplanation($explanation) {
|
|
|
|
$this->baseCommitExplanation = $explanation;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function resolveBaseCommitRule($rule, $source) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setBaseCommitArgumentRules($base_commit_argument_rules) {
|
|
|
|
$this->baseCommitArgumentRules = $base_commit_argument_rules;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getBaseCommitArgumentRules() {
|
|
|
|
return $this->baseCommitArgumentRules;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function resolveBaseCommit() {
|
|
|
|
$working_copy = $this->getWorkingCopyIdentity();
|
|
|
|
$global_config = ArcanistBaseWorkflow::readGlobalArcConfig();
|
2012-06-26 00:14:11 +02:00
|
|
|
$system_config = ArcanistBaseWorkflow::readSystemArcConfig();
|
Add a DSL for selecting base commits
Summary:
New optional mode. If you set 'base' in local, project or global config or pass '--base' to 'arc diff' or 'arc which', it switches to DSL mode.
In DSL mode, lists of rules from args, local, project and global config are resolved, in that order. Rules can manipulate the rule machine or resolve into actual commits. Provides support for some 'arc' rules (mostly machine manipulation) and 'git' rules (symbolic ref and merge-base).
Test Plan:
Ran unit tests. Also:
```$ arc which --show-base --base 'arc:prompt'
Against which commit? HEAD
HEAD
$ arc which --show-base --base 'git:HEAD'
HEAD
$ arc which --show-base --base 'git:fake'
Usage Exception: None of the rules in your 'base' configuration matched a valid commit. Adjust rules or specify which commit you want to use explicitly.
$ arc which --show-base --base 'git:origin/master'
origin/master
$ arc which --show-base --base 'git:upstream'
Usage Exception: None of the rules in your 'base' configuration matched a valid commit. Adjust rules or specify which commit you want to use explicitly.
$ arc which --show-base --base 'literal:derp'
derp
$ arc which --show-base --base 'arc:halt'
Usage Exception: None of the rules in your 'base' configuration matched a valid commit. Adjust rules or specify which commit you want to use explicitly.
$ arc set-config --local base git:origin/master
Set key 'base' = 'git:origin/master' in local config.
$ arc which --show-base
origin/master
$ arc which --show-base --base 'git:HEAD^'
HEAD^
$ arc which --show-base --base 'arc:yield, git:HEAD^'
origin/master
$ arc which --show-base --base 'arc:global, git:HEAD^'
HEAD^
$ arc which --show-base --base 'arc:global, git:merge-base(origin/master)'
3f4f8992fba8d1f142974da36a82bae900e247c0```
Reviewers: dschleimer, vrana
Reviewed By: dschleimer
CC: aran
Maniphest Tasks: T1233
Differential Revision: https://secure.phabricator.com/D2748
2012-06-15 23:01:28 +02:00
|
|
|
|
|
|
|
$parser = new ArcanistBaseCommitParser($this);
|
|
|
|
$commit = $parser->resolveBaseCommit(
|
|
|
|
array(
|
|
|
|
'args' => $this->getBaseCommitArgumentRules(),
|
|
|
|
'local' => $working_copy->getLocalConfig('base', ''),
|
|
|
|
'project' => $working_copy->getConfig('base', ''),
|
|
|
|
'global' => idx($global_config, 'base', ''),
|
2012-06-26 00:14:11 +02:00
|
|
|
'system' => idx($system_config, 'base', ''),
|
Add a DSL for selecting base commits
Summary:
New optional mode. If you set 'base' in local, project or global config or pass '--base' to 'arc diff' or 'arc which', it switches to DSL mode.
In DSL mode, lists of rules from args, local, project and global config are resolved, in that order. Rules can manipulate the rule machine or resolve into actual commits. Provides support for some 'arc' rules (mostly machine manipulation) and 'git' rules (symbolic ref and merge-base).
Test Plan:
Ran unit tests. Also:
```$ arc which --show-base --base 'arc:prompt'
Against which commit? HEAD
HEAD
$ arc which --show-base --base 'git:HEAD'
HEAD
$ arc which --show-base --base 'git:fake'
Usage Exception: None of the rules in your 'base' configuration matched a valid commit. Adjust rules or specify which commit you want to use explicitly.
$ arc which --show-base --base 'git:origin/master'
origin/master
$ arc which --show-base --base 'git:upstream'
Usage Exception: None of the rules in your 'base' configuration matched a valid commit. Adjust rules or specify which commit you want to use explicitly.
$ arc which --show-base --base 'literal:derp'
derp
$ arc which --show-base --base 'arc:halt'
Usage Exception: None of the rules in your 'base' configuration matched a valid commit. Adjust rules or specify which commit you want to use explicitly.
$ arc set-config --local base git:origin/master
Set key 'base' = 'git:origin/master' in local config.
$ arc which --show-base
origin/master
$ arc which --show-base --base 'git:HEAD^'
HEAD^
$ arc which --show-base --base 'arc:yield, git:HEAD^'
origin/master
$ arc which --show-base --base 'arc:global, git:HEAD^'
HEAD^
$ arc which --show-base --base 'arc:global, git:merge-base(origin/master)'
3f4f8992fba8d1f142974da36a82bae900e247c0```
Reviewers: dschleimer, vrana
Reviewed By: dschleimer
CC: aran
Maniphest Tasks: T1233
Differential Revision: https://secure.phabricator.com/D2748
2012-06-15 23:01:28 +02:00
|
|
|
));
|
|
|
|
|
|
|
|
return $commit;
|
|
|
|
}
|
|
|
|
|
2011-01-10 00:22:25 +01:00
|
|
|
}
|