2011-01-10 00:22:25 +01:00
|
|
|
<?php
|
|
|
|
|
|
|
|
/*
|
2011-12-03 01:21:14 +01:00
|
|
|
* Copyright 2012 Facebook, Inc.
|
2011-01-10 00:22:25 +01:00
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
2011-02-19 20:36:08 +01:00
|
|
|
/**
|
|
|
|
* Exports changes from Differential or the working copy to a file.
|
|
|
|
*
|
|
|
|
* @group workflow
|
|
|
|
*/
|
2011-01-10 00:22:25 +01:00
|
|
|
final class ArcanistExportWorkflow extends ArcanistBaseWorkflow {
|
|
|
|
|
|
|
|
const SOURCE_LOCAL = 'local';
|
|
|
|
const SOURCE_DIFF = 'diff';
|
|
|
|
const SOURCE_REVISION = 'revision';
|
|
|
|
|
|
|
|
const FORMAT_GIT = 'git';
|
|
|
|
const FORMAT_UNIFIED = 'unified';
|
|
|
|
const FORMAT_BUNDLE = 'arcbundle';
|
|
|
|
|
|
|
|
private $source;
|
|
|
|
private $sourceID;
|
|
|
|
private $format;
|
|
|
|
|
|
|
|
public function getCommandHelp() {
|
|
|
|
return phutil_console_format(<<<EOTEXT
|
|
|
|
**export** [__paths__] __format__ (svn)
|
|
|
|
**export** [__commit_range__] __format__ (git)
|
|
|
|
**export** __--revision__ __revision_id__ __format__
|
|
|
|
**export** __--diff__ __diff_id__ __format__
|
|
|
|
Supports: git, svn
|
|
|
|
Export the local changeset (or a Differential changeset) to a file,
|
|
|
|
in some __format__: git diff (__--git__), unified diff
|
|
|
|
(__--unified__), or arc bundle (__--arcbundle__ __path__) format.
|
|
|
|
EOTEXT
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getArguments() {
|
|
|
|
return array(
|
|
|
|
'git' => array(
|
|
|
|
'help' =>
|
|
|
|
"Export change as a git patch. This format is more complete than ".
|
|
|
|
"unified, but less complete than arc bundles. These patches can be ".
|
|
|
|
"applied with 'git apply' or 'arc patch'.",
|
|
|
|
),
|
|
|
|
'unified' => array(
|
|
|
|
'help' =>
|
|
|
|
"Export change as a unified patch. This format is less complete ".
|
|
|
|
"than git patches or arc bundles. These patches can be applied with ".
|
|
|
|
"'patch' or 'arc patch'.",
|
|
|
|
),
|
|
|
|
'arcbundle' => array(
|
|
|
|
'param' => 'file',
|
|
|
|
'help' =>
|
|
|
|
"Export change as an arc bundle. This format can represent all ".
|
|
|
|
"changes. These bundles can be applied with 'arc patch'.",
|
|
|
|
),
|
|
|
|
'revision' => array(
|
|
|
|
'param' => 'revision_id',
|
|
|
|
'help' =>
|
|
|
|
"Instead of exporting changes from the working copy, export them ".
|
|
|
|
"from a Differential revision."
|
|
|
|
),
|
|
|
|
'diff' => array(
|
|
|
|
'param' => 'diff_id',
|
|
|
|
'help' =>
|
|
|
|
"Instead of exporting changes from the working copy, export them ".
|
|
|
|
"from a Differential diff."
|
|
|
|
),
|
|
|
|
'*' => 'paths',
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected function didParseArguments() {
|
|
|
|
$source = self::SOURCE_LOCAL;
|
|
|
|
$requested = 0;
|
|
|
|
if ($this->getArgument('revision')) {
|
|
|
|
$source = self::SOURCE_REVISION;
|
|
|
|
$requested++;
|
|
|
|
}
|
|
|
|
if ($this->getArgument('diff')) {
|
|
|
|
$source = self::SOURCE_DIFF;
|
|
|
|
$requested++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($requested > 1) {
|
|
|
|
throw new ArcanistUsageException(
|
|
|
|
"Options '--revision' and '--diff' are not compatible. Choose exactly ".
|
|
|
|
"one change source.");
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->source = $source;
|
|
|
|
$this->sourceID = $this->getArgument($source);
|
|
|
|
|
|
|
|
$format = null;
|
|
|
|
$requested = 0;
|
|
|
|
if ($this->getArgument('git')) {
|
|
|
|
$format = self::FORMAT_GIT;
|
|
|
|
$requested++;
|
|
|
|
}
|
|
|
|
if ($this->getArgument('unified')) {
|
|
|
|
$format = self::FORMAT_UNIFIED;
|
|
|
|
$requested++;
|
|
|
|
}
|
|
|
|
if ($this->getArgument('arcbundle')) {
|
|
|
|
$format = self::FORMAT_BUNDLE;
|
|
|
|
$requested++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($requested === 0) {
|
|
|
|
throw new ArcanistUsageException(
|
|
|
|
"Specify one of '--git', '--unified' or '--arcbundle <path>' to ".
|
|
|
|
"choose an export format.");
|
|
|
|
} else if ($requested > 1) {
|
|
|
|
throw new ArcanistUsageException(
|
|
|
|
"Options '--git', '--unified' and '--arcbundle' are not compatible. ".
|
|
|
|
"Choose exactly one export format.");
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->format = $format;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function requiresConduit() {
|
|
|
|
return $this->getSource() != self::SOURCE_LOCAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function requiresAuthentication() {
|
|
|
|
return $this->requiresConduit();
|
|
|
|
}
|
|
|
|
|
|
|
|
public function requiresRepositoryAPI() {
|
|
|
|
return $this->getSource() == self::SOURCE_LOCAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function requiresWorkingCopy() {
|
|
|
|
return $this->getSource() == self::SOURCE_LOCAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
private function getSource() {
|
|
|
|
return $this->source;
|
|
|
|
}
|
|
|
|
|
|
|
|
private function getSourceID() {
|
|
|
|
return $this->sourceID;
|
|
|
|
}
|
|
|
|
|
|
|
|
private function getFormat() {
|
|
|
|
return $this->format;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function run() {
|
|
|
|
|
|
|
|
$source = $this->getSource();
|
|
|
|
|
|
|
|
switch ($source) {
|
|
|
|
case self::SOURCE_LOCAL:
|
|
|
|
$repository_api = $this->getRepositoryAPI();
|
|
|
|
$parser = new ArcanistDiffParser();
|
2011-02-06 22:04:01 +01:00
|
|
|
|
2011-01-29 21:45:37 +01:00
|
|
|
if ($repository_api instanceof ArcanistGitAPI) {
|
2011-10-18 04:22:48 +02:00
|
|
|
$repository_api->parseRelativeLocalCommit(
|
2011-01-29 21:45:37 +01:00
|
|
|
$this->getArgument('paths'));
|
|
|
|
$diff = $repository_api->getFullGitDiff();
|
|
|
|
$changes = $parser->parseDiff($diff);
|
|
|
|
} else {
|
|
|
|
// TODO: paths support
|
|
|
|
$paths = $repository_api->getWorkingCopyStatus();
|
|
|
|
$changes = $parser->parseSubversionDiff(
|
|
|
|
$repository_api,
|
|
|
|
$paths);
|
|
|
|
}
|
2011-01-10 00:22:25 +01:00
|
|
|
|
|
|
|
$bundle = ArcanistBundle::newFromChanges($changes);
|
2011-11-30 07:27:40 +01:00
|
|
|
$bundle->setProjectID($this->getWorkingCopy()->getProjectID());
|
2011-12-03 01:21:14 +01:00
|
|
|
$bundle->setBaseRevision(
|
|
|
|
$repository_api->getSourceControlBaseRevision());
|
2012-01-18 00:47:00 +01:00
|
|
|
// note we can't get a revision ID for SOURCE_LOCAL
|
2011-01-10 00:22:25 +01:00
|
|
|
break;
|
|
|
|
case self::SOURCE_REVISION:
|
|
|
|
$bundle = $this->loadRevisionBundleFromConduit(
|
|
|
|
$this->getConduit(),
|
|
|
|
$this->getSourceID());
|
|
|
|
break;
|
|
|
|
case self::SOURCE_DIFF:
|
|
|
|
$bundle = $this->loadDiffBundleFromConduit(
|
|
|
|
$this->getConduit(),
|
|
|
|
$this->getSourceID());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
$format = $this->getFormat();
|
|
|
|
|
|
|
|
switch ($format) {
|
|
|
|
case self::FORMAT_GIT:
|
|
|
|
echo $bundle->toGitPatch();
|
|
|
|
break;
|
|
|
|
case self::FORMAT_UNIFIED:
|
|
|
|
echo $bundle->toUnifiedDiff();
|
|
|
|
break;
|
|
|
|
case self::FORMAT_BUNDLE:
|
|
|
|
$path = $this->getArgument('arcbundle');
|
2011-05-21 16:52:49 +02:00
|
|
|
echo "Writing bundle to '{$path}'...\n";
|
2011-01-10 00:22:25 +01:00
|
|
|
$bundle->writeToDisk($path);
|
|
|
|
echo "done.\n";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|