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

View File

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

View File

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

View File

@@ -62,6 +62,23 @@ final class DiffusionRepositoryBranchesManagementPanel
->setDisabled(!$can_edit) ->setDisabled(!$can_edit)
->setWorkflow(!$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() return $this->newCurtainView()
->setActionList($action_list); ->setActionList($action_list);
} }
@@ -111,98 +128,6 @@ final class DiffusionRepositoryBranchesManagementPanel
$content[] = $this->newBox(pht('Branches'), $view); $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; return $content;
} }

View File

@@ -187,61 +187,76 @@ final class DiffusionGitUploadPackWireProtocol
// <hash> <ref-name>\0<capabilities> // <hash> <ref-name>\0<capabilities>
// <hash> <ref-name> // <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']; $bytes = $frame['bytes'];
$matches = array(); $matches = array();
if ($is_first) { if ($is_first) {
$ok = preg_match( $capabilities_pattern = '\0(?P<capabilities>[^\n]+)';
'('. } else {
'^'. $capabilities_pattern = '';
'(?P<hash>[0-9a-f]{40})'. }
' '.
'(?P<name>[^\0\n]+)'. $ok = preg_match(
'\0'. '('.
'(?P<capabilities>[^\n]+)'. '^'.
'\n'. '(?:'.
'\z'. '(?P<hash>[0-9a-f]{40}) (?P<name>[^\0\n]+)'.$capabilities_pattern.
')', '|'.
$bytes, 'shallow (?P<shallow>[0-9a-f]{40})'.
$matches); ')'.
if (!$ok) { '\n'.
'\z'.
')',
$bytes,
$matches);
if (!$ok) {
if ($is_first) {
throw new Exception( throw new Exception(
pht( pht(
'Unexpected "git upload-pack" initial protocol frame: expected '. '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)); $bytes));
} } else {
} else {
$ok = preg_match(
'('.
'^'.
'(?P<hash>[0-9a-f]{40})'.
' '.
'(?P<name>[^\0\n]+)'.
'\n'.
'\z'.
')',
$bytes,
$matches);
if (!$ok) {
throw new Exception( throw new Exception(
pht( pht(
'Unexpected "git upload-pack" protocol frame: expected '. 'Unexpected "git upload-pack" protocol frame: expected '.
'"<hash> <name>\n", got "%s".', '"<hash> <name>\n", or "shallow <hash>\n", got "%s".',
$bytes)); $bytes));
} }
} }
$hash = $matches['hash']; if (isset($matches['shallow'])) {
$name = $matches['name']; $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']; $capabilities = $matches['capabilities'];
} }
$refs[] = array( $refs[] = array(
'hash' => $hash, 'hash' => $hash,
'name' => $name, 'name' => $name,
'shallow' => $is_shallow,
); );
} }
@@ -252,10 +267,16 @@ final class DiffusionGitUploadPackWireProtocol
->setCapabilities($capabilities); ->setCapabilities($capabilities);
foreach ($refs as $ref) { foreach ($refs as $ref) {
$ref_list->addRef( $wire_ref = id(new DiffusionGitWireProtocolRef())
id(new DiffusionGitWireProtocolRef()) ->setHash($ref['hash']);
->setName($ref['name'])
->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, // 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 // a little surprising, but is consistent with the native behavior of the
// protocol. // protocol.
// Likewise, we don't send back any capabilities if we're sending only
// "shallow" frames.
$output = array(); $output = array();
$is_first = true; $is_first = true;
foreach ($refs as $ref) { 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( $result = sprintf(
"%s %s\0%s\n", "%s %s\0%s\n",
$ref->getHash(), $ref->getHash(),

View File

@@ -5,6 +5,7 @@ final class DiffusionGitWireProtocolRef
private $name; private $name;
private $hash; private $hash;
private $isShallow;
public function setName($name) { public function setName($name) {
$this->name = $name; $this->name = $name;
@@ -24,9 +25,19 @@ final class DiffusionGitWireProtocolRef
return $this->hash; return $this->hash;
} }
public function setIsShallow($is_shallow) {
$this->isShallow = $is_shallow;
return $this;
}
public function getIsShallow() {
return $this->isShallow;
}
public function newSortVector() { public function newSortVector() {
return id(new PhutilSortVector()) 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}"); ->setSubject("T{$id}: {$title}");
} }
protected function getObjectLinkButtonLabelForMail() { protected function getObjectLinkButtonLabelForMail(
PhabricatorLiskDAO $object) {
return pht('View Task'); return pht('View Task');
} }

View File

@@ -252,12 +252,24 @@ final class PhabricatorRepositoryManagementReparseWorkflow
); );
foreach ($classes as $class) { foreach ($classes as $class) {
PhabricatorWorker::scheduleTask( try {
$class, PhabricatorWorker::scheduleTask(
$spec, $class,
array( $spec,
'priority' => PhabricatorWorker::PRIORITY_IMPORT, 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); $progress->update(1);

View File

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

View File

@@ -3426,17 +3426,39 @@ abstract class PhabricatorApplicationTransactionEditor
->setContextObject($object); ->setContextObject($object);
$button_label = $this->getObjectLinkButtonLabelForMail($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); $this->addCustomFieldsToMailBody($body, $object, $xactions);
return $body; return $body;
} }
protected function getObjectLinkButtonLabelForMail() { protected function getObjectLinkButtonLabelForMail(
PhabricatorLiskDAO $object) {
return null; 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 * @task mail
*/ */
@@ -3458,7 +3480,7 @@ abstract class PhabricatorApplicationTransactionEditor
PhabricatorMetaMTAMailBody $body, PhabricatorMetaMTAMailBody $body,
array $xactions, array $xactions,
$object_label = null, $object_label = null,
$object_href = null) { $object_uri = null) {
// First, remove transactions which shouldn't be rendered in mail. // First, remove transactions which shouldn't be rendered in mail.
foreach ($xactions as $key => $xaction) { foreach ($xactions as $key => $xaction) {
@@ -3524,7 +3546,7 @@ abstract class PhabricatorApplicationTransactionEditor
$headers_html = phutil_implode_html(phutil_tag('br'), $headers_html); $headers_html = phutil_implode_html(phutil_tag('br'), $headers_html);
$header_button = null; $header_button = null;
if ($object_label !== null) { if ($object_label !== null && $object_uri !== null) {
$button_style = array( $button_style = array(
'text-decoration: none;', 'text-decoration: none;',
'padding: 4px 8px;', 'padding: 4px 8px;',
@@ -3543,7 +3565,7 @@ abstract class PhabricatorApplicationTransactionEditor
'a', 'a',
array( array(
'style' => implode(' ', $button_style), 'style' => implode(' ', $button_style),
'href' => $object_href, 'href' => $object_uri,
), ),
$object_label); $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 Since most of this data is compressible, it may be helpful to run it through
gzip prior to storage. For example: 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 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. 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) { 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(); $api = $this->getSingleAPI();
$patches = $this->getPatches(); $patches = $this->getPatches();
$console = PhutilConsole::getConsole();
$with_indexes = !$args->getArg('no-indexes'); $with_indexes = !$args->getArg('no-indexes');
$applied = $api->getAppliedPatches(); $applied = $api->getAppliedPatches();
if ($applied === null) { if ($applied === null) {
$namespace = $api->getNamespace(); throw new PhutilArgumentUsageException(
$console->writeErr(
pht( pht(
'**Storage Not Initialized**: There is no database storage '. 'There is no database storage initialized in the current storage '.
'initialized in this storage namespace ("%s"). Use '. 'namespace ("%s"). Use "bin/storage upgrade" to initialize '.
'**%s** to initialize storage.', 'storage or use "--namespace" to choose a different namespace.',
$namespace, $api->getNamespace()));
'./bin/storage upgrade'));
return 1;
} }
$ref = $api->getRef(); $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 = array();
$argv[] = '--hex-blob'; $argv[] = '--hex-blob';
$argv[] = '--single-transaction'; $argv[] = '--single-transaction';

View File

@@ -75,6 +75,7 @@ JX.install('Workflow', {
var workflow = new JX.Workflow(link.href); var workflow = new JX.Workflow(link.href);
return workflow; return workflow;
}, },
_push : function(workflow) { _push : function(workflow) {
JX.Mask.show(); JX.Mask.show();
JX.Workflow._stack.push(workflow); JX.Workflow._stack.push(workflow);
@@ -85,8 +86,36 @@ JX.install('Workflow', {
dialog._destroy(); dialog._destroy();
JX.Mask.hide(); JX.Mask.hide();
}, },
disable : function() { _onlink: function(event) {
JX.Workflow._disabled = true; // 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) { _onbutton : function(event) {
@@ -94,10 +123,6 @@ JX.install('Workflow', {
return; return;
} }
if (JX.Workflow._disabled) {
return;
}
// Get the button (which is sometimes actually another tag, like an <a />) // Get the button (which is sometimes actually another tag, like an <a />)
// which triggered the event. In particular, this makes sure we get the // 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 // right node if there is a <button> with an <img /> inside it or
@@ -124,9 +149,6 @@ JX.install('Workflow', {
if (JX.Stratcom.pass()) { if (JX.Stratcom.pass()) {
return; return;
} }
if (JX.Workflow._disabled) {
return;
}
e.prevent(); e.prevent();
var form = e.getNode('jx-dialog'); var form = e.getNode('jx-dialog');
var button = JX.DOM.find(form, 'button', '__default__'); var button = JX.DOM.find(form, 'button', '__default__');
@@ -313,6 +335,9 @@ JX.install('Workflow', {
[], [],
JX.Workflow._onsyntheticsubmit); JX.Workflow._onsyntheticsubmit);
var onlink = JX.Workflow._onlink;
JX.DOM.listen(this._root, 'click', 'tag:a', onlink);
JX.DOM.listen( JX.DOM.listen(
this._root, this._root,
'mousedown', 'mousedown',
@@ -471,11 +496,6 @@ JX.install('Workflow', {
return; return;
} }
if (JX.Workflow._disabled) {
// Workflows are disabled on this page.
return;
}
if (JX.Stratcom.pass()) { if (JX.Stratcom.pass()) {
// Something else swallowed the event. // Something else swallowed the event.
return; return;