1
0
Fork 0
mirror of https://we.phorge.it/source/arcanist.git synced 2024-11-29 10:12: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:
Bob Trahan 2011-11-29 22:27:40 -08:00
parent 1f69ab5fdb
commit d81d97f9c6
4 changed files with 76 additions and 2 deletions

View file

@ -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);
} }

View file

@ -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;
} }

View file

@ -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(

View file

@ -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.)