@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.)
hq.recaptime.dev/wiki/Phorge
phorge
phabricator
1<?php
2
3final class HarbormasterManagementArchiveLogsWorkflow
4 extends HarbormasterManagementWorkflow {
5
6 protected function didConstruct() {
7 $this
8 ->setName('archive-logs')
9 ->setExamples('**archive-logs** [__options__] --mode __mode__')
10 ->setSynopsis(pht('Compress, decompress, store or destroy build logs.'))
11 ->setArguments(
12 array(
13 array(
14 'name' => 'mode',
15 'param' => 'mode',
16 'help' => pht(
17 'Use "plain" to remove encoding, or "compress" to compress '.
18 'logs.'),
19 ),
20 array(
21 'name' => 'details',
22 'help' => pht(
23 'Show more details about operations as they are performed. '.
24 'Slow! But also very reassuring!'),
25 ),
26 ));
27 }
28
29 public function execute(PhutilArgumentParser $args) {
30 $viewer = $this->getViewer();
31
32 $mode = $args->getArg('mode');
33 if (!$mode) {
34 throw new PhutilArgumentUsageException(
35 pht('Choose an archival mode with --mode.'));
36 }
37
38 $valid_modes = array(
39 'plain',
40 'compress',
41 );
42
43 $valid_modes = array_fuse($valid_modes);
44 if (empty($valid_modes[$mode])) {
45 throw new PhutilArgumentUsageException(
46 pht(
47 'Unknown mode "%s". Valid modes are: %s.',
48 $mode,
49 implode(', ', $valid_modes)));
50 }
51
52 $log_table = new HarbormasterBuildLog();
53 $logs = new LiskMigrationIterator($log_table);
54
55 $show_details = $args->getArg('details');
56
57 if ($show_details) {
58 $total_old = 0;
59 $total_new = 0;
60 }
61
62 foreach ($logs as $log) {
63 echo tsprintf(
64 "%s\n",
65 pht('Processing Harbormaster build log #%d...', $log->getID()));
66
67 if ($show_details) {
68 $old_stats = $this->computeDetails($log);
69 }
70
71 switch ($mode) {
72 case 'plain':
73 $log->decompressLog();
74 break;
75 case 'compress':
76 $log->compressLog();
77 break;
78 }
79
80 if ($show_details) {
81 $new_stats = $this->computeDetails($log);
82 $this->printStats($old_stats, $new_stats);
83
84 $total_old += $old_stats['bytes'];
85 $total_new += $new_stats['bytes'];
86 }
87 }
88
89 if ($show_details) {
90 echo tsprintf(
91 "%s\n",
92 pht(
93 'Done. Total byte size of affected logs: %s -> %s.',
94 new PhutilNumber($total_old),
95 new PhutilNumber($total_new)));
96 }
97
98 return 0;
99 }
100
101 private function computeDetails(HarbormasterBuildLog $log) {
102 $bytes = 0;
103 $chunks = 0;
104 $hash = hash_init('sha1');
105
106 foreach ($log->newChunkIterator() as $chunk) {
107 $bytes += strlen($chunk->getChunk());
108 $chunks++;
109 hash_update($hash, $chunk->getChunkDisplayText());
110 }
111
112 return array(
113 'bytes' => $bytes,
114 'chunks' => $chunks,
115 'hash' => hash_final($hash),
116 );
117 }
118
119 private function printStats(array $old_stats, array $new_stats) {
120 echo tsprintf(
121 " %s\n",
122 pht(
123 '%s: %s -> %s',
124 pht('Stored Bytes'),
125 new PhutilNumber($old_stats['bytes']),
126 new PhutilNumber($new_stats['bytes'])));
127
128 echo tsprintf(
129 " %s\n",
130 pht(
131 '%s: %s -> %s',
132 pht('Stored Chunks'),
133 new PhutilNumber($old_stats['chunks']),
134 new PhutilNumber($new_stats['chunks'])));
135
136 echo tsprintf(
137 " %s\n",
138 pht(
139 '%s: %s -> %s',
140 pht('Data Hash'),
141 $old_stats['hash'],
142 $new_stats['hash']));
143
144 if ($old_stats['hash'] !== $new_stats['hash']) {
145 throw new Exception(
146 pht('Log data hashes differ! Something is tragically wrong!'));
147 }
148 }
149
150}