mirror of
https://we.phorge.it/source/arcanist.git
synced 2024-11-26 00:32:41 +01:00
make arc patch issue a warning if applying a patch against a different project
Summary: adds a little bit of sanity checking to the arc patch workflow. in short, if the working copy project is not the same as the patch project, don't apply the patch Test Plan: ran arc patch DX arc patch DX --force in the top line directory for project A and proejct B. DX is for project A. verified for project A that the patch was applied and for project B i was issued warnings as expected. also verified in project B case that saying Y or N to the warning had the desired effect. Reviewers: epriestley Reviewed By: epriestley CC: aran, btrahan, epriestley Differential Revision: 1140
This commit is contained in:
parent
1f69ab5fdb
commit
d81d97f9c6
4 changed files with 76 additions and 2 deletions
|
@ -27,11 +27,20 @@ class ArcanistBundle {
|
||||||
private $conduit;
|
private $conduit;
|
||||||
private $blobs = array();
|
private $blobs = array();
|
||||||
private $diskPath;
|
private $diskPath;
|
||||||
|
private $projectID;
|
||||||
|
|
||||||
public function setConduit(ConduitClient $conduit) {
|
public function setConduit(ConduitClient $conduit) {
|
||||||
$this->conduit = $conduit;
|
$this->conduit = $conduit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setProjectID($project_id) {
|
||||||
|
$this->projectID = $project_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getProjectID() {
|
||||||
|
return $this->projectID;
|
||||||
|
}
|
||||||
|
|
||||||
public static function newFromChanges(array $changes) {
|
public static function newFromChanges(array $changes) {
|
||||||
$obj = new ArcanistBundle();
|
$obj = new ArcanistBundle();
|
||||||
$obj->changes = $changes;
|
$obj->changes = $changes;
|
||||||
|
@ -41,6 +50,27 @@ class ArcanistBundle {
|
||||||
public static function newFromArcBundle($path) {
|
public static function newFromArcBundle($path) {
|
||||||
$path = Filesystem::resolvePath($path);
|
$path = Filesystem::resolvePath($path);
|
||||||
|
|
||||||
|
$future = new ExecFuture(
|
||||||
|
csprintf(
|
||||||
|
'tar tfO %s',
|
||||||
|
$path));
|
||||||
|
list($stdout, $file_list) = $future->resolvex();
|
||||||
|
$file_list = explode("\n", trim($file_list));
|
||||||
|
|
||||||
|
if (in_array('meta.json', $file_list)) {
|
||||||
|
$future = new ExecFuture(
|
||||||
|
csprintf(
|
||||||
|
'tar xfO %s meta.json',
|
||||||
|
$path));
|
||||||
|
$meta_info = $future->resolveJSON();
|
||||||
|
$version = idx($meta_info, 'version', 0);
|
||||||
|
$project_name = idx($meta_info, 'projectName');
|
||||||
|
// this arc bundle was probably made before we started storing meta info
|
||||||
|
} else {
|
||||||
|
$version = 0;
|
||||||
|
$project_name = null;
|
||||||
|
}
|
||||||
|
|
||||||
$future = new ExecFuture(
|
$future = new ExecFuture(
|
||||||
csprintf(
|
csprintf(
|
||||||
'tar xfO %s changes.json',
|
'tar xfO %s changes.json',
|
||||||
|
@ -54,7 +84,6 @@ class ArcanistBundle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
foreach ($changes as $change_key => $change) {
|
foreach ($changes as $change_key => $change) {
|
||||||
$changes[$change_key] = ArcanistDiffChange::newFromDictionary($change);
|
$changes[$change_key] = ArcanistDiffChange::newFromDictionary($change);
|
||||||
}
|
}
|
||||||
|
@ -62,6 +91,7 @@ class ArcanistBundle {
|
||||||
$obj = new ArcanistBundle();
|
$obj = new ArcanistBundle();
|
||||||
$obj->changes = $changes;
|
$obj->changes = $changes;
|
||||||
$obj->diskPath = $path;
|
$obj->diskPath = $path;
|
||||||
|
$obj->setProjectID($project_name);
|
||||||
|
|
||||||
return $obj;
|
return $obj;
|
||||||
}
|
}
|
||||||
|
@ -108,10 +138,14 @@ class ArcanistBundle {
|
||||||
$blobs[$phid] = $this->getBlob($phid);
|
$blobs[$phid] = $this->getBlob($phid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$meta_info = array('version' => 1,
|
||||||
|
'projectName' => $this->getProjectID());
|
||||||
|
|
||||||
$dir = Filesystem::createTemporaryDirectory();
|
$dir = Filesystem::createTemporaryDirectory();
|
||||||
Filesystem::createDirectory($dir.'/hunks');
|
Filesystem::createDirectory($dir.'/hunks');
|
||||||
Filesystem::createDirectory($dir.'/blobs');
|
Filesystem::createDirectory($dir.'/blobs');
|
||||||
Filesystem::writeFile($dir.'/changes.json', json_encode($change_list));
|
Filesystem::writeFile($dir.'/changes.json', json_encode($change_list));
|
||||||
|
Filesystem::writeFile($dir.'/meta.json', json_encode($meta_info));
|
||||||
foreach ($hunks as $key => $hunk) {
|
foreach ($hunks as $key => $hunk) {
|
||||||
Filesystem::writeFile($dir.'/hunks/'.$key, $hunk);
|
Filesystem::writeFile($dir.'/hunks/'.$key, $hunk);
|
||||||
}
|
}
|
||||||
|
|
|
@ -751,6 +751,7 @@ class ArcanistBaseWorkflow {
|
||||||
}
|
}
|
||||||
$bundle = ArcanistBundle::newFromChanges($changes);
|
$bundle = ArcanistBundle::newFromChanges($changes);
|
||||||
$bundle->setConduit($conduit);
|
$bundle->setConduit($conduit);
|
||||||
|
$bundle->setProjectID($diff['projectName']);
|
||||||
return $bundle;
|
return $bundle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -186,6 +186,7 @@ EOTEXT
|
||||||
}
|
}
|
||||||
|
|
||||||
$bundle = ArcanistBundle::newFromChanges($changes);
|
$bundle = ArcanistBundle::newFromChanges($changes);
|
||||||
|
$bundle->setProjectID($this->getWorkingCopy()->getProjectID());
|
||||||
break;
|
break;
|
||||||
case self::SOURCE_REVISION:
|
case self::SOURCE_REVISION:
|
||||||
$bundle = $this->loadRevisionBundleFromConduit(
|
$bundle = $this->loadRevisionBundleFromConduit(
|
||||||
|
|
|
@ -75,6 +75,10 @@ EOTEXT
|
||||||
'help' =>
|
'help' =>
|
||||||
"Apply changes from a git patchfile or unified patchfile.",
|
"Apply changes from a git patchfile or unified patchfile.",
|
||||||
),
|
),
|
||||||
|
'force' => array(
|
||||||
|
'help' =>
|
||||||
|
"Do not run any sanity checks.",
|
||||||
|
),
|
||||||
'*' => 'name',
|
'*' => 'name',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -186,7 +190,7 @@ EOTEXT
|
||||||
}
|
}
|
||||||
} catch (Exception $ex) {
|
} catch (Exception $ex) {
|
||||||
if ($ex->getErrorCode() == 'ERR-INVALID-SESSION') {
|
if ($ex->getErrorCode() == 'ERR-INVALID-SESSION') {
|
||||||
// Phabricator is not configured to allow anonymos access to
|
// Phabricator is not configured to allow anonymous access to
|
||||||
// Differential.
|
// Differential.
|
||||||
$this->authenticateConduit();
|
$this->authenticateConduit();
|
||||||
return $this->run();
|
return $this->run();
|
||||||
|
@ -195,6 +199,13 @@ EOTEXT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$force = $this->getArgument('force', false);
|
||||||
|
if ($force) {
|
||||||
|
// force means don't do any sanity checks about the patch
|
||||||
|
} else {
|
||||||
|
$this->sanityCheckPatch($bundle);
|
||||||
|
}
|
||||||
|
|
||||||
$repository_api = $this->getRepositoryAPI();
|
$repository_api = $this->getRepositoryAPI();
|
||||||
if ($repository_api instanceof ArcanistSubversionAPI) {
|
if ($repository_api instanceof ArcanistSubversionAPI) {
|
||||||
$patch_err = 0;
|
$patch_err = 0;
|
||||||
|
@ -412,6 +423,33 @@ EOTEXT
|
||||||
return array('ARGUMENT');
|
return array('ARGUMENT');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do the best we can to prevent PEBKAC and id10t issues.
|
||||||
|
*/
|
||||||
|
private function sanityCheckPatch(ArcanistBundle $bundle) {
|
||||||
|
|
||||||
|
// Check to see if the bundle project id matches the working copy
|
||||||
|
// project id
|
||||||
|
$bundle_project_id = $bundle->getProjectID();
|
||||||
|
$working_copy_project_id = $this->getWorkingCopy()->getProjectID();
|
||||||
|
if (empty($bundle_project_id)) {
|
||||||
|
// this means $source is SOURCE_PATCH || SOURCE_BUNDLE
|
||||||
|
// they don't come with a project id so just do nothing
|
||||||
|
} else if ($bundle_project_id != $working_copy_project_id) {
|
||||||
|
$ok = phutil_console_confirm(
|
||||||
|
"This diff is for the '{$bundle_project_id}' project but the working ".
|
||||||
|
"copy belongs to the '{$working_copy_project_id}' project. ".
|
||||||
|
"Still try to apply it?",
|
||||||
|
$default_no = false
|
||||||
|
);
|
||||||
|
if (!$ok) {
|
||||||
|
throw new ArcanistUserAbortException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO -- more sanity checks here
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create parent directories one at a time, since we need to "svn add" each
|
* Create parent directories one at a time, since we need to "svn add" each
|
||||||
* one. (Technically we could "svn add" just the topmost new directory.)
|
* one. (Technically we could "svn add" just the topmost new directory.)
|
||||||
|
|
Loading…
Reference in a new issue