@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 PhabricatorFilesManagementCompactWorkflow
4 extends PhabricatorFilesManagementWorkflow {
5
6 protected function didConstruct() {
7 $arguments = $this->newIteratorArguments();
8 $arguments[] = array(
9 'name' => 'dry-run',
10 'help' => pht('Show what would be compacted.'),
11 );
12
13 $this
14 ->setName('compact')
15 ->setSynopsis(
16 pht(
17 'Merge identical files to share the same storage. In some cases, '.
18 'this can repair files with missing data.'))
19 ->setArguments($arguments);
20 }
21
22 public function execute(PhutilArgumentParser $args) {
23 $console = PhutilConsole::getConsole();
24
25 $iterator = $this->buildIterator($args);
26 $is_dry_run = $args->getArg('dry-run');
27
28 foreach ($iterator as $file) {
29 $monogram = $file->getMonogram();
30
31 $hash = $file->getContentHash();
32 if (!$hash) {
33 $console->writeOut(
34 "%s\n",
35 pht('%s: No content hash.', $monogram));
36 continue;
37 }
38
39 // Find other files with the same content hash. We're going to point
40 // them at the data for this file.
41 $similar_files = id(new PhabricatorFile())->loadAllWhere(
42 'contentHash = %s AND id != %d AND
43 (storageEngine != %s OR storageHandle != %s)',
44 $hash,
45 $file->getID(),
46 $file->getStorageEngine(),
47 $file->getStorageHandle());
48 if (!$similar_files) {
49 $console->writeOut(
50 "%s\n",
51 pht('%s: No other files with the same content hash.', $monogram));
52 continue;
53 }
54
55 // Only compact files into this one if we can load the data. This
56 // prevents us from breaking working files if we're missing some data.
57 try {
58 $data = $file->loadFileData();
59 } catch (Exception $ex) {
60 $data = null;
61 }
62
63 if ($data === null) {
64 $console->writeOut(
65 "%s\n",
66 pht(
67 '%s: Unable to load file data; declining to compact.',
68 $monogram));
69 continue;
70 }
71
72 foreach ($similar_files as $similar_file) {
73 if ($is_dry_run) {
74 $console->writeOut(
75 "%s\n",
76 pht(
77 '%s: Would compact storage with %s.',
78 $monogram,
79 $similar_file->getMonogram()));
80 continue;
81 }
82
83 $console->writeOut(
84 "%s\n",
85 pht(
86 '%s: Compacting storage with %s.',
87 $monogram,
88 $similar_file->getMonogram()));
89
90 $old_instance = null;
91 try {
92 $old_instance = $similar_file->instantiateStorageEngine();
93 $old_engine = $similar_file->getStorageEngine();
94 $old_handle = $similar_file->getStorageHandle();
95 } catch (Exception $ex) {
96 // If the old stuff is busted, we just won't try to delete the
97 // old data.
98 phlog($ex);
99 }
100
101 $similar_file
102 ->setStorageEngine($file->getStorageEngine())
103 ->setStorageHandle($file->getStorageHandle())
104 ->save();
105
106 if ($old_instance) {
107 $similar_file->deleteFileDataIfUnused(
108 $old_instance,
109 $old_engine,
110 $old_handle);
111 }
112 }
113 }
114
115 return 0;
116 }
117
118}