Changeset View
Changeset View
Standalone View
Standalone View
src/applications/diffusion/engine/DiffusionCommitHookEngine.php
Show All 33 Lines | final class DiffusionCommitHookEngine extends Phobject { | ||||
private $startTime; | private $startTime; | ||||
private $heraldViewerProjects; | private $heraldViewerProjects; | ||||
private $rejectCode = PhabricatorRepositoryPushLog::REJECT_BROKEN; | private $rejectCode = PhabricatorRepositoryPushLog::REJECT_BROKEN; | ||||
private $rejectDetails; | private $rejectDetails; | ||||
private $emailPHIDs = array(); | private $emailPHIDs = array(); | ||||
private $changesets = array(); | private $changesets = array(); | ||||
private $changesetsSize = 0; | private $changesetsSize = 0; | ||||
private $filesizeCache = array(); | |||||
/* -( Config )------------------------------------------------------------- */ | /* -( Config )------------------------------------------------------------- */ | ||||
public function setRemoteProtocol($remote_protocol) { | public function setRemoteProtocol($remote_protocol) { | ||||
$this->remoteProtocol = $remote_protocol; | $this->remoteProtocol = $remote_protocol; | ||||
return $this; | return $this; | ||||
▲ Show 20 Lines • Show All 121 Lines • ▼ Show 20 Lines | try { | ||||
} catch (DiffusionCommitHookRejectException $ex) { | } catch (DiffusionCommitHookRejectException $ex) { | ||||
// If we're rejecting oversized files, flag everything. | // If we're rejecting oversized files, flag everything. | ||||
$this->rejectCode = PhabricatorRepositoryPushLog::REJECT_OVERSIZED; | $this->rejectCode = PhabricatorRepositoryPushLog::REJECT_OVERSIZED; | ||||
throw $ex; | throw $ex; | ||||
} | } | ||||
try { | try { | ||||
if (!$is_initial_import) { | if (!$is_initial_import) { | ||||
$this->rejectCommitsAffectingTooManyPaths($content_updates); | |||||
} | |||||
} catch (DiffusionCommitHookRejectException $ex) { | |||||
$this->rejectCode = PhabricatorRepositoryPushLog::REJECT_TOUCHES; | |||||
throw $ex; | |||||
} | |||||
try { | |||||
if (!$is_initial_import) { | |||||
$this->rejectEnormousChanges($content_updates); | $this->rejectEnormousChanges($content_updates); | ||||
} | } | ||||
} catch (DiffusionCommitHookRejectException $ex) { | } catch (DiffusionCommitHookRejectException $ex) { | ||||
// If we're rejecting enormous changes, flag everything. | // If we're rejecting enormous changes, flag everything. | ||||
$this->rejectCode = PhabricatorRepositoryPushLog::REJECT_ENORMOUS; | $this->rejectCode = PhabricatorRepositoryPushLog::REJECT_ENORMOUS; | ||||
throw $ex; | throw $ex; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 1,084 Lines • ▼ Show 20 Lines | private function rejectOversizedFiles(array $content_updates) { | ||||
$limit = $repository->getFilesizeLimit(); | $limit = $repository->getFilesizeLimit(); | ||||
if (!$limit) { | if (!$limit) { | ||||
return; | return; | ||||
} | } | ||||
foreach ($content_updates as $update) { | foreach ($content_updates as $update) { | ||||
$identifier = $update->getRefNew(); | $identifier = $update->getRefNew(); | ||||
$sizes = $this->loadFileSizesForCommit($identifier); | $sizes = $this->getFileSizesForCommit($identifier); | ||||
foreach ($sizes as $path => $size) { | foreach ($sizes as $path => $size) { | ||||
if ($size <= $limit) { | if ($size <= $limit) { | ||||
continue; | continue; | ||||
} | } | ||||
$message = pht( | $message = pht( | ||||
'OVERSIZED FILE'. | 'OVERSIZED FILE'. | ||||
"\n". | "\n". | ||||
'This repository ("%s") is configured with a maximum individual '. | 'This repository ("%s") is configured with a maximum individual '. | ||||
'file size limit, but you are pushing a change ("%s") which causes '. | 'file size limit, but you are pushing a change ("%s") which causes '. | ||||
'the size of a file ("%s") to exceed the limit. The commit makes '. | 'the size of a file ("%s") to exceed the limit. The commit makes '. | ||||
'the file %s bytes long, but the limit for this repository is '. | 'the file %s bytes long, but the limit for this repository is '. | ||||
'%s bytes.', | '%s bytes.', | ||||
$repository->getDisplayName(), | $repository->getDisplayName(), | ||||
$identifier, | $identifier, | ||||
$path, | $path, | ||||
new PhutilNumber($size), | new PhutilNumber($size), | ||||
new PhutilNumber($limit)); | new PhutilNumber($limit)); | ||||
throw new DiffusionCommitHookRejectException($message); | throw new DiffusionCommitHookRejectException($message); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
public function loadFileSizesForCommit($identifier) { | private function rejectCommitsAffectingTooManyPaths(array $content_updates) { | ||||
$repository = $this->getRepository(); | |||||
$limit = $repository->getTouchLimit(); | |||||
if (!$limit) { | |||||
return; | |||||
} | |||||
foreach ($content_updates as $update) { | |||||
$identifier = $update->getRefNew(); | |||||
$sizes = $this->getFileSizesForCommit($identifier); | |||||
amckinley: Oh this is neat. Never would have imagined this code would get reused! I guess it's not worth… | |||||
if (count($sizes) > $limit) { | |||||
$message = pht( | |||||
'COMMIT AFFECTS TOO MANY PATHS'. | |||||
"\n". | |||||
'This repository ("%s") is configured with a touched files limit '. | |||||
'that caps the maximum number of paths any single commit may '. | |||||
'affect. You are pushing a change ("%s") which exceeds this '. | |||||
'limit: it affects %s paths, but the largest number of paths any '. | |||||
'commit may affect is %s paths.', | |||||
Not Done Inline ActionsConsistency between "affects" and "touches". amckinley: Consistency between "affects" and "touches". | |||||
$repository->getDisplayName(), | |||||
$identifier, | |||||
phutil_count($sizes), | |||||
new PhutilNumber($limit)); | |||||
throw new DiffusionCommitHookRejectException($message); | |||||
} | |||||
} | |||||
} | |||||
public function getFileSizesForCommit($identifier) { | |||||
if (!isset($this->filesizeCache[$identifier])) { | |||||
Not Done Inline ActionsOh, and we're caching the result so we only do this work once anyway. amckinley: Oh, and we're caching the result so we only do this work once anyway. | |||||
$file_sizes = $this->loadFileSizesForCommit($identifier); | |||||
$this->filesizeCache[$identifier] = $file_sizes; | |||||
} | |||||
return $this->filesizeCache[$identifier]; | |||||
} | |||||
private function loadFileSizesForCommit($identifier) { | |||||
$repository = $this->getRepository(); | $repository = $this->getRepository(); | ||||
return id(new DiffusionLowLevelFilesizeQuery()) | return id(new DiffusionLowLevelFilesizeQuery()) | ||||
->setRepository($repository) | ->setRepository($repository) | ||||
->withIdentifier($identifier) | ->withIdentifier($identifier) | ||||
->execute(); | ->execute(); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 119 Lines • Show Last 20 Lines |
Oh this is neat. Never would have imagined this code would get reused! I guess it's not worth fiddling with this to skip the work of computing the file sizes since the vast majority of commits are reasonably-sized anyway.