Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 97
0.00% covered (danger)
0.00%
0 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
LoadJsonDump
0.00% covered (danger)
0.00%
0 / 91
0.00% covered (danger)
0.00%
0 / 3
462
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
2
 execute
0.00% covered (danger)
0.00%
0 / 47
0.00% covered (danger)
0.00%
0 / 1
132
 makeEdit
0.00% covered (danger)
0.00%
0 / 29
0.00% covered (danger)
0.00%
0 / 1
90
1<?php
2
3/**
4 * WikiLambda loadJsonDump maintenance script
5 *
6 * Loads specified dump of objects from production
7 *
8 * @file
9 * @ingroup Extensions
10 * @copyright 2020– Abstract Wikipedia team; see AUTHORS.txt
11 * @license MIT
12 */
13
14use MediaWiki\Extension\WikiLambda\ZErrorException;
15use MediaWiki\Extension\WikiLambda\ZObjectStore;
16use MediaWiki\Logger\LoggerFactory;
17use MediaWiki\Maintenance\Maintenance;
18use MediaWiki\Title\Title;
19use MediaWiki\Title\TitleFactory;
20
21$IP = getenv( 'MW_INSTALL_PATH' );
22if ( $IP === false ) {
23    $IP = __DIR__ . '/../../..';
24}
25require_once "$IP/maintenance/Maintenance.php";
26
27class LoadJsonDump extends Maintenance {
28
29    /**
30     * @inheritDoc
31     */
32    public function __construct() {
33        parent::__construct();
34        $this->requireExtension( 'WikiLambda' );
35        $this->addDescription( 'Loads all the latest versions of the objects located in the specified directory' );
36
37        $this->addOption(
38            'dir',
39            'Directory name of the wikifunctions dump',
40            false,
41            true
42        );
43
44        $this->addOption(
45            'zid',
46            'Particular zid to push',
47            false,
48            true
49        );
50    }
51
52    /**
53     * @inheritDoc
54     */
55    public function execute() {
56        // Construct the ZObjectStore, because ServiceWiring hasn't run
57        $services = $this->getServiceContainer();
58        $titleFactory = $services->getTitleFactory();
59        $zObjectStore = new ZObjectStore(
60            $services->getDBLoadBalancerFactory(),
61            $services->getTitleFactory(),
62            $services->getWikiPageFactory(),
63            $services->getRevisionStore(),
64            $services->getUserGroupManager(),
65            LoggerFactory::getInstance( 'WikiLambda' )
66        );
67
68        // Dump path:
69        $dumpDir = $this->getOption( 'dir' );
70        if ( !$dumpDir ) {
71            $this->fatalError( "Please specify the folder where the cached ZObjects are stored. E.g.:\n"
72                . "docker compose exec mediawiki php extensions/WikiLambda/maintenance/loadJsonDump.php "
73                . "--dir zobjectcache" );
74        }
75        $path = dirname( __DIR__ ) . '/' . $dumpDir;
76
77        // Dump only one zid:
78        $pushZid = $this->getOption( 'zid' );
79
80        // Get data files
81        // Load Z0.json
82        $indexFile = file_get_contents( "$path/Z0.json" );
83        if ( $indexFile === false ) {
84            $this->fatalError( "Could not load Z0.json guide file.\n"
85                . "The directory must contain the objects downloaded with "
86                . "https://gitlab.wikimedia.org/repos/abstract-wiki/wikifunctions-content-download" );
87        }
88        $index = json_decode( $indexFile, true );
89
90        $success = 0;
91        $failure = 0;
92
93        // If only one to insertZid, push it and exit early
94        if ( $pushZid ) {
95            if ( array_key_exists( $pushZid, $index ) ) {
96                $revision = $index[ $pushZid ];
97                $filename = "$pushZid.$revision.json";
98                $response = $this->makeEdit( $titleFactory, $zObjectStore, $pushZid, $path, $filename );
99                $this->output( "The ZObject $pushZid was loaded successfully.\n" );
100            } else {
101                $this->fatalError( "The Zid provided doesn't exist in the directory" );
102            }
103            return;
104        }
105
106        // Go through all the zid-version index and push one by one
107        foreach ( $index as $zid => $revision ) {
108            $filename = "$zid.$revision.json";
109            $response = $this->makeEdit( $titleFactory, $zObjectStore, $zid, $path, $filename );
110
111            switch ( $response ) {
112                case 1:
113                    $success++;
114                    break;
115
116                case -1:
117                    $failure++;
118                    break;
119
120                default:
121                    throw new RuntimeException( 'Unrecognised return value!' );
122            }
123        }
124
125        if ( $success > 0 ) {
126            $this->output( "$success objects were created or updated successfully.\n" );
127        }
128
129        if ( $failure > 0 ) {
130            $this->fatalError( "$failure objects failed on creation or update.\n" );
131        }
132    }
133
134    /**
135     * Pushes the object from the given filename.
136     *
137     * @param TitleFactory $titleFactory
138     * @param ZObjectStore $zObjectStore
139     * @param string $zid
140     * @param string $path
141     * @param string $filename
142     * @return int 1=success, -1=failure, 0=skipped
143     */
144    private function makeEdit(
145        TitleFactory $titleFactory,
146        ZObjectStore $zObjectStore,
147        string $zid,
148        string $path,
149        string $filename
150    ) {
151        $data = file_get_contents( "$path/$filename" );
152
153        if ( !$data ) {
154            $this->error( "The file $filename was not found in the path $path\n" );
155            return -1;
156        }
157
158        $title = $titleFactory->newFromText( $zid, NS_MAIN );
159        if ( !( $title instanceof Title ) ) {
160            $this->error( "The ZObject $zid cannot be loaded: invalid name\n" );
161            return -1;
162        }
163
164        $creating = !$title->exists();
165        $summary = wfMessage(
166            $creating
167                ? 'wikilambda-bootstrapcreationeditsummary'
168                : 'wikilambda-bootstrapupdatingeditsummary'
169        )->inLanguage( 'en' )->text();
170
171        // We create or update the ZObject
172        try {
173            $zObjectStore->pushZObject( $zid, $data, $summary );
174            $this->output( ( $creating ? 'Created' : 'Updated' ) . " $zid\n" );
175            return 1;
176        } catch ( ZErrorException $e ) {
177            $this->error( "Problem " . ( $creating ? 'creating' : 'updating' ) . " $zid:" );
178            $this->error( $e->getMessage() );
179            $this->error( $e->getZErrorMessage() );
180            $this->error( "\n" );
181            return -1;
182        } catch ( \Exception $e ) {
183            $this->error( "Problem " . ( $creating ? 'creating' : 'updating' ) . " $zid:" );
184            $this->error( $e->getMessage() );
185            $this->error( $e->getTraceAsString() );
186            $this->error( "\n" );
187            return -1;
188        }
189    }
190}
191
192$maintClass = LoadJsonDump::class;
193require_once RUN_MAINTENANCE_IF_MAIN;