88 */
99namespace OC \Core \Command \Db \Migrations ;
1010
11- use OC \DB \Connection ;
12- use OC \DB \MigrationService ;
13- use OCP \Migration \Attributes \GenericMigrationAttribute ;
11+ use OC \Migration \MetadataManager ;
12+ use OC \Updater \ReleaseMetadata ;
1413use OCP \Migration \Attributes \MigrationAttribute ;
15- use OCP \Migration \Exceptions \AttributeException ;
16- use Psr \Log \LoggerInterface ;
1714use Symfony \Component \Console \Command \Command ;
1815use Symfony \Component \Console \Helper \Table ;
1916use Symfony \Component \Console \Helper \TableCell ;
2421use Symfony \Component \Console \Output \OutputInterface ;
2522
2623class PreviewCommand extends Command {
24+ private bool $ initiated = false ;
2725 public function __construct (
28- private readonly Connection $ connection ,
29- private readonly LoggerInterface $ logger ,
26+ private readonly MetadataManager $ metadataManager ,
27+ private readonly ReleaseMetadata $ releaseMetadata ,
3028 ) {
3129 parent ::__construct ();
3230 }
3331
34- protected function configure () {
32+ protected function configure (): void {
3533 $ this
3634 ->setName ('migrations:preview ' )
3735 ->setDescription ('Get preview of available DB migrations in case of initiating an upgrade ' )
@@ -42,21 +40,37 @@ protected function configure() {
4240
4341 public function execute (InputInterface $ input , OutputInterface $ output ): int {
4442 $ version = $ input ->getArgument ('version ' );
43+ if (filter_var ($ version , FILTER_VALIDATE_URL )) {
44+ $ metadata = $ this ->releaseMetadata ->downloadMetadata ($ version );
45+ } elseif (str_starts_with ($ version , '/ ' )) {
46+ $ metadata = json_decode (file_get_contents ($ version ), true , flags: JSON_THROW_ON_ERROR );
47+ } else {
48+ $ metadata = $ this ->releaseMetadata ->getMetadata ($ version );
49+ }
4550
46- $ metadata = $ this ->getMetadata ($ version );
47- $ parsed = $ this ->getMigrationsAttributes ($ metadata );
51+ $ parsed = $ this ->metadataManager ->getMigrationsAttributesFromReleaseMetadata ($ metadata ['migrations ' ] ?? [], true );
4852
4953 $ table = new Table ($ output );
50- $ this ->displayMigrations ($ table , 'core ' , $ parsed ['core ' ]);
51-
54+ $ this ->displayMigrations ($ table , 'core ' , $ parsed ['core ' ] ?? []);
55+ foreach ($ parsed ['apps ' ] as $ appId => $ migrations ) {
56+ if (!empty ($ migrations )) {
57+ $ this ->displayMigrations ($ table , $ appId , $ migrations );
58+ }
59+ }
5260 $ table ->render ();
5361
5462 return 0 ;
5563 }
5664
5765 private function displayMigrations (Table $ table , string $ appId , array $ data ): void {
58- $ done = $ this ->getDoneMigrations ($ appId );
59- $ done = array_diff ($ done , ['30000Date20240429122720 ' ]);
66+ if (empty ($ data )) {
67+ return ;
68+ }
69+
70+ if ($ this ->initiated ) {
71+ $ table ->addRow (new TableSeparator ());
72+ }
73+ $ this ->initiated = true ;
6074
6175 $ table ->addRow (
6276 [
@@ -70,13 +84,9 @@ private function displayMigrations(Table $table, string $appId, array $data): vo
7084 ]
7185 )->addRow (new TableSeparator ());
7286
87+ /** @var MigrationAttribute[] $attributes */
7388 foreach ($ data as $ migration => $ attributes ) {
74- if (in_array ($ migration , $ done )) {
75- continue ;
76- }
77-
7889 $ attributesStr = [];
79- /** @var MigrationAttribute[] $attributes */
8090 foreach ($ attributes as $ attribute ) {
8191 $ definition = '<info> ' . $ attribute ->definition () . "</info> " ;
8292 $ definition .= empty ($ attribute ->getDescription ()) ? '' : "\n " . $ attribute ->getDescription ();
@@ -85,78 +95,5 @@ private function displayMigrations(Table $table, string $appId, array $data): vo
8595 }
8696 $ table ->addRow ([$ migration , implode ("\n" , $ attributesStr )]);
8797 }
88-
89- }
90-
91-
92-
93-
94-
95- private function getMetadata (string $ version ): array {
96- $ metadata = json_decode (file_get_contents ('/tmp/nextcloud- ' . $ version . '.metadata ' ), true );
97- if (!$ metadata ) {
98- throw new \Exception ();
99- }
100- return $ metadata ['migrations ' ] ?? [];
101- }
102-
103- private function getDoneMigrations (string $ appId ): array {
104- $ ms = new MigrationService ($ appId , $ this ->connection );
105- return $ ms ->getMigratedVersions ();
106- }
107-
108- private function getMigrationsAttributes (array $ metadata ): array {
109- $ appsAttributes = [];
110- foreach (array_keys ($ metadata ['apps ' ]) as $ appId ) {
111- $ appsAttributes [$ appId ] = $ this ->parseMigrations ($ metadata ['apps ' ][$ appId ] ?? []);
112- }
113-
114- return [
115- 'core ' => $ this ->parseMigrations ($ metadata ['core ' ] ?? []),
116- 'apps ' => $ appsAttributes
117- ];
118- }
119-
120- private function parseMigrations (array $ migrations ): array {
121- $ parsed = [];
122- foreach (array_keys ($ migrations ) as $ entry ) {
123- $ items = $ migrations [$ entry ];
124- $ parsed [$ entry ] = [];
125- foreach ($ items as $ item ) {
126- try {
127- $ parsed [$ entry ][] = $ this ->createAttribute ($ item );
128- } catch (AttributeException $ e ) {
129- $ this ->logger ->warning (
130- 'exception while trying to create attribute ' ,
131- ['exception ' => $ e , 'item ' => json_encode ($ item )]
132- );
133- $ parsed [$ entry ][] = new GenericMigrationAttribute ($ item );
134- }
135- }
136- }
137-
138- return $ parsed ;
139- }
140-
141- /**
142- * @param array $item
143- *
144- * @return MigrationAttribute|null
145- * @throws AttributeException
146- */
147- private function createAttribute (array $ item ): ?MigrationAttribute {
148- $ class = $ item ['class ' ] ?? '' ;
149- $ namespace = 'OCP\Migration\Attributes \\' ;
150- if (!str_starts_with ($ class , $ namespace )
151- || !ctype_alpha (substr ($ class , strlen ($ namespace )))) {
152- throw new AttributeException ('class name does not looks valid ' );
153- }
154-
155- try {
156- $ attribute = new $ class ();
157- return $ attribute ->import ($ item );
158- } catch (\Error ) {
159- throw new AttributeException ('cannot import Attribute ' );
160- }
16198 }
16299}
0 commit comments