Merge branch 'master' into blender-tweaks

This commit is contained in:
2019-06-19 10:37:08 +02:00
13 changed files with 244 additions and 219 deletions

View File

@@ -10,7 +10,7 @@ return array(
'conpherence.pkg.css' => '3c8a0668',
'conpherence.pkg.js' => '020aebcf',
'core.pkg.css' => 'efa1b78b',
'core.pkg.js' => 'ee320ca2',
'core.pkg.js' => 'f39ebda8',
'differential.pkg.css' => '8d8360fb',
'differential.pkg.js' => '67e02996',
'diffusion.pkg.css' => '42c75c37',
@@ -255,7 +255,7 @@ return array(
'rsrc/externals/javelin/lib/URI.js' => '2e255291',
'rsrc/externals/javelin/lib/Vector.js' => 'e9c80beb',
'rsrc/externals/javelin/lib/WebSocket.js' => 'fdc13e4e',
'rsrc/externals/javelin/lib/Workflow.js' => '958e9045',
'rsrc/externals/javelin/lib/Workflow.js' => 'e9c6d3c7',
'rsrc/externals/javelin/lib/__tests__/Cookie.js' => 'ca686f71',
'rsrc/externals/javelin/lib/__tests__/DOM.js' => '4566e249',
'rsrc/externals/javelin/lib/__tests__/JSON.js' => '710377ae',
@@ -754,7 +754,7 @@ return array(
'javelin-workboard-header' => '111bfd2d',
'javelin-workboard-header-template' => 'ebe83a6b',
'javelin-workboard-order-template' => '03e8891f',
'javelin-workflow' => '958e9045',
'javelin-workflow' => 'e9c6d3c7',
'maniphest-report-css' => '3d53188b',
'maniphest-task-edit-css' => '272daa84',
'maniphest-task-summary-css' => '61d1667e',
@@ -1712,17 +1712,6 @@ return array(
'javelin-stratcom',
'javelin-vector',
),
'958e9045' => array(
'javelin-stratcom',
'javelin-request',
'javelin-dom',
'javelin-vector',
'javelin-install',
'javelin-util',
'javelin-mask',
'javelin-uri',
'javelin-routable',
),
'9623adc1' => array(
'javelin-behavior',
'javelin-stratcom',
@@ -2110,6 +2099,17 @@ return array(
'phabricator-title',
'phabricator-favicon',
),
'e9c6d3c7' => array(
'javelin-stratcom',
'javelin-request',
'javelin-dom',
'javelin-vector',
'javelin-install',
'javelin-util',
'javelin-mask',
'javelin-uri',
'javelin-routable',
),
'e9c80beb' => array(
'javelin-install',
'javelin-event',

View File

@@ -485,7 +485,8 @@ final class PhabricatorAuditEditor
return $phids;
}
protected function getObjectLinkButtonLabelForMail() {
protected function getObjectLinkButtonLabelForMail(
PhabricatorLiskDAO $object) {
return pht('View Commit');
}

View File

@@ -601,7 +601,8 @@ final class DifferentialTransactionEditor
return $xactions;
}
protected function getObjectLinkButtonLabelForMail() {
protected function getObjectLinkButtonLabelForMail(
PhabricatorLiskDAO $object) {
return pht('View Revision');
}
@@ -614,8 +615,7 @@ final class DifferentialTransactionEditor
$body = id(new PhabricatorMetaMTAMailBody())
->setViewer($viewer);
$revision_uri = $object->getURI();
$revision_uri = PhabricatorEnv::getProductionURI($revision_uri);
$revision_uri = $this->getObjectLinkButtonURIForMail($object);
$new_uri = $revision_uri.'/new/';
$this->addHeadersAndCommentsToMailBody(

View File

@@ -62,6 +62,23 @@ final class DiffusionRepositoryBranchesManagementPanel
->setDisabled(!$can_edit)
->setWorkflow(!$can_edit));
$drequest = DiffusionRequest::newFromDictionary(
array(
'user' => $viewer,
'repository' => $repository,
));
$view_uri = $drequest->generateURI(
array(
'action' => 'branches',
));
$action_list->addAction(
id(new PhabricatorActionView())
->setIcon('fa-code-fork')
->setName(pht('View Branches'))
->setHref($view_uri));
return $this->newCurtainView()
->setActionList($action_list);
}
@@ -111,98 +128,6 @@ final class DiffusionRepositoryBranchesManagementPanel
$content[] = $this->newBox(pht('Branches'), $view);
if (!$repository->isImporting()) {
$request = $this->getRequest();
$pager = id(new PHUIPagerView())
->readFromRequest($request);
$params = array(
'offset' => $pager->getOffset(),
'limit' => $pager->getPageSize() + 1,
'repository' => $repository->getID(),
);
$branches = id(new ConduitCall('diffusion.branchquery', $params))
->setUser($viewer)
->execute();
$branches = DiffusionRepositoryRef::loadAllFromDictionaries($branches);
$branches = $pager->sliceResults($branches);
$can_close_branches = ($repository->isHg());
$publisher = $repository->newPublisher();
$rows = array();
foreach ($branches as $branch) {
$branch_name = $branch->getShortName();
$permanent = $publisher->shouldPublishRef($branch);
$default = $repository->getDefaultBranch();
$icon = null;
if ($default == $branch->getShortName()) {
$icon = id(new PHUIIconView())
->setIcon('fa-code-fork');
}
$fields = $branch->getRawFields();
$closed = idx($fields, 'closed');
if ($closed) {
$status = pht('Closed');
} else {
$status = pht('Open');
}
if ($publishing_disabled) {
$permanent_status = pht('Publishing Disabled');
} else {
if ($permanent) {
$permanent_status = pht('Permanent');
} else {
$permanent_status = pht('Not Permanent');
}
}
$rows[] = array(
$icon,
$branch_name,
$status,
$permanent_status,
);
}
$branch_table = new AphrontTableView($rows);
$branch_table->setHeaders(
array(
'',
pht('Branch'),
pht('Status'),
pht('Permanent'),
));
$branch_table->setColumnClasses(
array(
'',
'pri',
'narrow',
'wide',
));
$branch_table->setColumnVisibility(
array(
true,
true,
$can_close_branches,
true,
));
$box = $this->newBox(pht('Branch Status'), $branch_table);
$box->setPager($pager);
$content[] = $box;
} else {
$content[] = id(new PHUIInfoView())
->setSeverity(PHUIInfoView::SEVERITY_NOTICE)
->appendChild(
pht(
'Branch status is unavailable while the repository is still '.
'importing.'));
}
return $content;
}

View File

@@ -187,61 +187,76 @@ final class DiffusionGitUploadPackWireProtocol
// <hash> <ref-name>\0<capabilities>
// <hash> <ref-name>
// ...
//
// See T13309. The end of this list (which may be empty if a repository
// does not have any refs) has a list of zero or more of these:
//
// shallow <hash>
//
// These entries are present if the repository is a shallow clone
// which was made with the "--depth" flag.
//
// Note that "shallow" frames do not advertise capabilities, and if
// a repository has only "shallow" frames, capabilities are never
// advertised.
$bytes = $frame['bytes'];
$matches = array();
if ($is_first) {
$ok = preg_match(
'('.
'^'.
'(?P<hash>[0-9a-f]{40})'.
' '.
'(?P<name>[^\0\n]+)'.
'\0'.
'(?P<capabilities>[^\n]+)'.
'\n'.
'\z'.
')',
$bytes,
$matches);
if (!$ok) {
$capabilities_pattern = '\0(?P<capabilities>[^\n]+)';
} else {
$capabilities_pattern = '';
}
$ok = preg_match(
'('.
'^'.
'(?:'.
'(?P<hash>[0-9a-f]{40}) (?P<name>[^\0\n]+)'.$capabilities_pattern.
'|'.
'shallow (?P<shallow>[0-9a-f]{40})'.
')'.
'\n'.
'\z'.
')',
$bytes,
$matches);
if (!$ok) {
if ($is_first) {
throw new Exception(
pht(
'Unexpected "git upload-pack" initial protocol frame: expected '.
'"<hash> <name>\0<capabilities>\n", got "%s".',
'"<hash> <name>\0<capabilities>\n", or '.
'"shallow <hash>\n", got "%s".',
$bytes));
}
} else {
$ok = preg_match(
'('.
'^'.
'(?P<hash>[0-9a-f]{40})'.
' '.
'(?P<name>[^\0\n]+)'.
'\n'.
'\z'.
')',
$bytes,
$matches);
if (!$ok) {
} else {
throw new Exception(
pht(
'Unexpected "git upload-pack" protocol frame: expected '.
'"<hash> <name>\n", got "%s".',
'"<hash> <name>\n", or "shallow <hash>\n", got "%s".',
$bytes));
}
}
$hash = $matches['hash'];
$name = $matches['name'];
if (isset($matches['shallow'])) {
$name = null;
$hash = $matches['shallow'];
$is_shallow = true;
} else {
$name = $matches['name'];
$hash = $matches['hash'];
$is_shallow = false;
}
if ($is_first) {
if (isset($matches['capabilities'])) {
$capabilities = $matches['capabilities'];
}
$refs[] = array(
'hash' => $hash,
'name' => $name,
'shallow' => $is_shallow,
);
}
@@ -252,10 +267,16 @@ final class DiffusionGitUploadPackWireProtocol
->setCapabilities($capabilities);
foreach ($refs as $ref) {
$ref_list->addRef(
id(new DiffusionGitWireProtocolRef())
->setName($ref['name'])
->setHash($ref['hash']));
$wire_ref = id(new DiffusionGitWireProtocolRef())
->setHash($ref['hash']);
if ($ref['shallow']) {
$wire_ref->setIsShallow(true);
} else {
$wire_ref->setName($ref['name']);
}
$ref_list->addRef($wire_ref);
}
// TODO: Here, we have a structured list of refs. In a future change,
@@ -275,10 +296,19 @@ final class DiffusionGitUploadPackWireProtocol
// a little surprising, but is consistent with the native behavior of the
// protocol.
// Likewise, we don't send back any capabilities if we're sending only
// "shallow" frames.
$output = array();
$is_first = true;
foreach ($refs as $ref) {
if ($is_first) {
$is_shallow = $ref->getIsShallow();
if ($is_shallow) {
$result = sprintf(
"shallow %s\n",
$ref->getHash());
} else if ($is_first) {
$result = sprintf(
"%s %s\0%s\n",
$ref->getHash(),

View File

@@ -5,6 +5,7 @@ final class DiffusionGitWireProtocolRef
private $name;
private $hash;
private $isShallow;
public function setName($name) {
$this->name = $name;
@@ -24,9 +25,19 @@ final class DiffusionGitWireProtocolRef
return $this->hash;
}
public function setIsShallow($is_shallow) {
$this->isShallow = $is_shallow;
return $this;
}
public function getIsShallow() {
return $this->isShallow;
}
public function newSortVector() {
return id(new PhutilSortVector())
->addString($this->getName());
->addInt((int)$this->getIsShallow())
->addString((string)$this->getName());
}
}

View File

@@ -206,7 +206,8 @@ final class ManiphestTransactionEditor
->setSubject("T{$id}: {$title}");
}
protected function getObjectLinkButtonLabelForMail() {
protected function getObjectLinkButtonLabelForMail(
PhabricatorLiskDAO $object) {
return pht('View Task');
}

View File

@@ -252,12 +252,24 @@ final class PhabricatorRepositoryManagementReparseWorkflow
);
foreach ($classes as $class) {
PhabricatorWorker::scheduleTask(
$class,
$spec,
array(
'priority' => PhabricatorWorker::PRIORITY_IMPORT,
));
try {
PhabricatorWorker::scheduleTask(
$class,
$spec,
array(
'priority' => PhabricatorWorker::PRIORITY_IMPORT,
));
} catch (PhabricatorWorkerPermanentFailureException $ex) {
// See T13315. We expect some reparse steps to occasionally raise
// permanent failures: for example, because they are no longer
// reachable. This is a routine condition, not a catastrophic
// failure, so let the user know something happened but continue
// reparsing any remaining commits.
echo tsprintf(
"<bg:yellow>** %s **</bg> %s\n",
pht('WARN'),
$ex->getMessage());
}
}
$progress->update(1);

View File

@@ -94,7 +94,7 @@ final class PhabricatorExternalAccountsSettingsPanel
->setViewer($viewer)
->withIsEnabled(true)
->execute();
$configs = msort($configs, 'getSortVector');
$configs = msortv($configs, 'getSortVector');
$account_map = mgroup($accounts, 'getProviderConfigPHID');

View File

@@ -3426,17 +3426,39 @@ abstract class PhabricatorApplicationTransactionEditor
->setContextObject($object);
$button_label = $this->getObjectLinkButtonLabelForMail($object);
$button_uri = $this->getObjectLinkButtonURIForMail($object);
$this->addHeadersAndCommentsToMailBody(
$body,
$xactions,
$button_label,
$button_uri);
$this->addHeadersAndCommentsToMailBody($body, $xactions, $button_label);
$this->addCustomFieldsToMailBody($body, $object, $xactions);
return $body;
}
protected function getObjectLinkButtonLabelForMail() {
protected function getObjectLinkButtonLabelForMail(
PhabricatorLiskDAO $object) {
return null;
}
protected function getObjectLinkButtonURIForMail(
PhabricatorLiskDAO $object) {
// Most objects define a "getURI()" method which does what we want, but
// this isn't formally part of an interface at time of writing. Try to
// call the method, expecting an exception if it does not exist.
try {
$uri = $object->getURI();
return PhabricatorEnv::getProductionURI($uri);
} catch (Exception $ex) {
return null;
}
}
/**
* @task mail
*/
@@ -3458,7 +3480,7 @@ abstract class PhabricatorApplicationTransactionEditor
PhabricatorMetaMTAMailBody $body,
array $xactions,
$object_label = null,
$object_href = null) {
$object_uri = null) {
// First, remove transactions which shouldn't be rendered in mail.
foreach ($xactions as $key => $xaction) {
@@ -3524,7 +3546,7 @@ abstract class PhabricatorApplicationTransactionEditor
$headers_html = phutil_implode_html(phutil_tag('br'), $headers_html);
$header_button = null;
if ($object_label !== null) {
if ($object_label !== null && $object_uri !== null) {
$button_style = array(
'text-decoration: none;',
'padding: 4px 8px;',
@@ -3543,7 +3565,7 @@ abstract class PhabricatorApplicationTransactionEditor
'a',
array(
'style' => implode(' ', $button_style),
'href' => $object_href,
'href' => $object_uri,
),
$object_label);
}

View File

@@ -42,7 +42,7 @@ but will only dump databases Phabricator owns.
Since most of this data is compressible, it may be helpful to run it through
gzip prior to storage. For example:
phabricator/ $ ./bin/storage dump | gzip > backup.sql.gz
phabricator/ $ ./bin/storage dump --compress --output backup.sql.gz
Then store the backup somewhere safe, like in a box buried under an old tree
stump. No one will ever think to look for it there.

View File

@@ -51,24 +51,59 @@ final class PhabricatorStorageManagementDumpWorkflow
}
public function didExecute(PhutilArgumentParser $args) {
$output_file = $args->getArg('output');
$is_compress = $args->getArg('compress');
$is_overwrite = $args->getArg('overwrite');
if ($is_compress) {
if ($output_file === null) {
throw new PhutilArgumentUsageException(
pht(
'The "--compress" flag can only be used alongside "--output".'));
}
if (!function_exists('gzopen')) {
throw new PhutilArgumentUsageException(
pht(
'The "--compress" flag requires the PHP "zlib" extension, but '.
'that extension is not available. Install the extension or '.
'omit the "--compress" option.'));
}
}
if ($is_overwrite) {
if ($output_file === null) {
throw new PhutilArgumentUsageException(
pht(
'The "--overwrite" flag can only be used alongside "--output".'));
}
}
if ($output_file !== null) {
if (Filesystem::pathExists($output_file)) {
if (!$is_overwrite) {
throw new PhutilArgumentUsageException(
pht(
'Output file "%s" already exists. Use "--overwrite" '.
'to overwrite.',
$output_file));
}
}
}
$api = $this->getSingleAPI();
$patches = $this->getPatches();
$console = PhutilConsole::getConsole();
$with_indexes = !$args->getArg('no-indexes');
$applied = $api->getAppliedPatches();
if ($applied === null) {
$namespace = $api->getNamespace();
$console->writeErr(
throw new PhutilArgumentUsageException(
pht(
'**Storage Not Initialized**: There is no database storage '.
'initialized in this storage namespace ("%s"). Use '.
'**%s** to initialize storage.',
$namespace,
'./bin/storage upgrade'));
return 1;
'There is no database storage initialized in the current storage '.
'namespace ("%s"). Use "bin/storage upgrade" to initialize '.
'storage or use "--namespace" to choose a different namespace.',
$api->getNamespace()));
}
$ref = $api->getRef();
@@ -141,38 +176,6 @@ final class PhabricatorStorageManagementDumpWorkflow
}
}
$output_file = $args->getArg('output');
$is_compress = $args->getArg('compress');
$is_overwrite = $args->getArg('overwrite');
if ($is_compress) {
if ($output_file === null) {
throw new PhutilArgumentUsageException(
pht(
'The "--compress" flag can only be used alongside "--output".'));
}
}
if ($is_overwrite) {
if ($output_file === null) {
throw new PhutilArgumentUsageException(
pht(
'The "--overwrite" flag can only be used alongside "--output".'));
}
}
if ($output_file !== null) {
if (Filesystem::pathExists($output_file)) {
if (!$is_overwrite) {
throw new PhutilArgumentUsageException(
pht(
'Output file "%s" already exists. Use "--overwrite" '.
'to overwrite.',
$output_file));
}
}
}
$argv = array();
$argv[] = '--hex-blob';
$argv[] = '--single-transaction';

View File

@@ -75,6 +75,7 @@ JX.install('Workflow', {
var workflow = new JX.Workflow(link.href);
return workflow;
},
_push : function(workflow) {
JX.Mask.show();
JX.Workflow._stack.push(workflow);
@@ -85,8 +86,36 @@ JX.install('Workflow', {
dialog._destroy();
JX.Mask.hide();
},
disable : function() {
JX.Workflow._disabled = true;
_onlink: function(event) {
// See T13302. When a user clicks a link in a dialog and that link
// triggers a navigation event, we want to close the dialog as though
// they had pressed a button.
// When Quicksand is enabled, this is particularly relevant because
// the dialog will stay in the foreground while the page content changes
// in the background if we do not dismiss the dialog.
// If this is a Command-Click, the link will open in a new window.
var is_command = !!event.getRawEvent().metaKey;
if (is_command) {
return;
}
var link = event.getNode('tag:a');
// If the link is an anchor, or does not go anywhere, ignore the event.
var href = '' + link.href;
if (!href.length || href[0] === '#') {
return;
}
// This link will open in a new window.
if (link.target === '_blank') {
return;
}
// Close the dialog.
JX.Workflow._pop();
},
_onbutton : function(event) {
@@ -94,10 +123,6 @@ JX.install('Workflow', {
return;
}
if (JX.Workflow._disabled) {
return;
}
// Get the button (which is sometimes actually another tag, like an <a />)
// which triggered the event. In particular, this makes sure we get the
// right node if there is a <button> with an <img /> inside it or
@@ -124,9 +149,6 @@ JX.install('Workflow', {
if (JX.Stratcom.pass()) {
return;
}
if (JX.Workflow._disabled) {
return;
}
e.prevent();
var form = e.getNode('jx-dialog');
var button = JX.DOM.find(form, 'button', '__default__');
@@ -313,6 +335,9 @@ JX.install('Workflow', {
[],
JX.Workflow._onsyntheticsubmit);
var onlink = JX.Workflow._onlink;
JX.DOM.listen(this._root, 'click', 'tag:a', onlink);
JX.DOM.listen(
this._root,
'mousedown',
@@ -471,11 +496,6 @@ JX.install('Workflow', {
return;
}
if (JX.Workflow._disabled) {
// Workflows are disabled on this page.
return;
}
if (JX.Stratcom.pass()) {
// Something else swallowed the event.
return;