MediaWiki master
installPreConfigured.php
Go to the documentation of this file.
1<?php
2
14use Symfony\Component\Yaml\Yaml;
15
16require_once __DIR__ . '/Maintenance.php';
17
24 private $taskContext;
25
26 public function __construct() {
27 parent::__construct();
28 $this->addDescription( 'Create the database and tables for a new wiki, ' .
29 'using a pre-existing LocalSettings.php' );
30 $this->addOption( 'task',
31 'Execute only the specified task', false, true );
32 $this->addOption( 'skip',
33 'Skip the specified task', false, true, false, true );
34 $this->addOption( 'override-config',
35 'Specify a configuration variable with name=value. The value is in YAML format.',
36 false, true, 'c', true );
37 $this->addOption( 'override-option',
38 'Specify an installer option with name=value. The value is in YAML format.',
39 false, true, 'o', true );
40 $this->addOption( 'show-tasks',
41 'Show the list of tasks to be executed, do not actually install' );
42 }
43
44 public function getDbType() {
45 return Maintenance::DB_ADMIN;
46 }
47
48 public function finalSetup( SettingsBuilder $settingsBuilder ) {
49 parent::finalSetup( $settingsBuilder );
50
51 // Apply override-config options. Doing this here instead of in
52 // AddWikiTaskContext::setConfigVar() allows the options to be available
53 // globally for use in LoadExtensionSchemaUpdates.
54 foreach ( $this->getOption( 'override-config' ) ?? [] as $str ) {
55 [ $name, $value ] = $this->parseKeyValue( $str );
56 if ( str_starts_with( $name, 'wg' ) ) {
57 $name = substr( $name, 2 );
58 }
59 $settingsBuilder->putConfigValue( $name, $value );
60 }
61 }
62
63 public function execute() {
64 $context = $this->getTaskContext();
65 $taskFactory = $this->createTaskFactory( $context );
66 $taskList = $this->createTaskList( $taskFactory );
67 $taskRunner = $this->createTaskRunner( $taskList, $taskFactory );
68
69 Installer::disableStorage( $this->getConfig(), 'en' );
70
71 if ( $this->hasOption( 'show-tasks' ) ) {
72 $taskRunner->loadExtensions();
73 echo $taskRunner->dumpTaskList();
74 return false;
75 }
76
77 if ( $this->hasOption( 'task' ) ) {
78 $status = $taskRunner->runNamedTask( $this->getOption( 'task' ) );
79 } else {
80 $status = $taskRunner->execute();
81 }
82
83 if ( $status->isOK() ) {
84 $this->output( "Installation complete.\n" );
85 return true;
86 } else {
87 $this->error( "Installation failed at task \"" .
88 $taskRunner->getCurrentTaskName() . '"' );
89 return false;
90 }
91 }
92
100 private function parseKeyValue( string $str ) {
101 $parts = explode( '=', $str, 2 );
102 if ( count( $parts ) !== 2 ) {
103 $this->fatalError( "Invalid configuration variable \"$str\"" );
104 }
105 return [ $parts[0], Yaml::parse( $parts[1], Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE ) ];
106 }
107
111 protected function getTaskContext() {
112 if ( !$this->taskContext ) {
113 $this->taskContext = $this->createTaskContext();
114 }
115 return $this->taskContext;
116 }
117
124 private function createTaskContext() {
125 $context = new AddWikiTaskContext(
126 $this->getConfig(),
127 $this->getServiceContainer()->getDBLoadBalancerFactory()
128 );
129
130 // Make sure ExtensionTablesTask isn't skipped
131 $context->setOption( 'Extensions',
132 array_keys( ExtensionRegistry::getInstance()->getAllThings() ) );
133
134 foreach ( $this->getOption( 'override-option' ) ?? [] as $str ) {
135 [ $name, $value ] = $this->parseKeyValue( $str );
136 $context->setOption( $name, $value );
137 }
138 foreach ( $this->getSubclassDefaultOptions() as $name => $value ) {
139 $context->setOption( $name, $value );
140 }
141
142 return $context;
143 }
144
151 protected function getSubclassDefaultOptions() {
152 return [];
153 }
154
161 private function createTaskList( TaskFactory $taskFactory ) {
162 $taskList = new TaskList;
163 $taskFactory->registerMainTasks( $taskList, TaskFactory::PROFILE_ADD_WIKI );
164 $reg = ExtensionRegistry::getInstance();
165 $taskList->add( $taskFactory->create(
166 [
167 'class' => CannedProvider::class,
168 'args' => [
169 'extensions',
170 [
171 'HookContainer' => $this->getHookContainer(),
172 'VirtualDomains' => $reg->getAttribute( 'DatabaseVirtualDomains' ),
173 'ExtensionTaskSpecs' => $reg->getAttribute( 'InstallerTasks' ),
174 ]
175 ]
176 ]
177 ) );
178 foreach ( $this->getExtraTaskSpecs() as $spec ) {
179 $taskList->add( $taskFactory->create( $spec ) );
180 }
181 return $taskList;
182 }
183
193 protected function getExtraTaskSpecs() {
194 return [];
195 }
196
204 private function createTaskRunner( TaskList $taskList, TaskFactory $taskFactory ) {
205 $taskRunner = new TaskRunner( $taskList, $taskFactory, TaskFactory::PROFILE_ADD_WIKI );
206 $taskRunner->setSkippedTasks( $this->getOption( 'skip' ) ?? [] );
207
208 $taskRunner->addTaskStartListener( function ( Task $task ) {
209 $name = $task->getName();
210 $desc = $task->getDescriptionMessage()->plain();
211 $this->output( "[$name] $desc... " );
212 } );
213
214 $taskRunner->addTaskEndListener( function ( $task, StatusValue $status ) {
215 if ( $status->isOK() ) {
216 $this->output( "done\n" );
217 } else {
218 $this->output( "\n" );
219 }
220 if ( !$status->isGood() ) {
221 try {
222 $this->error( $status );
223 } catch ( InvalidArgumentException $e ) {
224 $this->error( (string)$status );
225 }
226 }
227 } );
228
229 return $taskRunner;
230 }
231
238 private function createTaskFactory( ITaskContext $context ) {
239 return new TaskFactory(
240 $this->getServiceContainer()->getObjectFactory(),
241 $context
242 );
243 }
244}
245
246$maintClass = InstallPreConfigured::class;
247require_once RUN_MAINTENANCE_IF_MAIN;
getDbType()
Does the script need different DB access? By default, we give Maintenance scripts normal rights to th...
finalSetup(SettingsBuilder $settingsBuilder)
Handle some last-minute setup here.
execute()
Do the actual work.
__construct()
Default constructor.
getSubclassDefaultOptions()
Get installer options overridden by a subclass.
getExtraTaskSpecs()
Subclasses can override this to provide specification arrays for extra tasks to run during install.
Base installer class.
Definition Installer.php:85
A task context for use in installPreConfigured.php.
A scheduled provider which simply provides data given to it through its constructor.
Factory for installer tasks.
registerMainTasks(TaskList $list, string $profile)
Populate the task list with core installer tasks which are shared by the various installation methods...
create(array $spec)
Create a task object.
A container for tasks, with sorting of tasks by their declared dependencies.
Definition TaskList.php:13
add(Task $task)
Add a task to the list.
Definition TaskList.php:23
Base class for installer tasks.
Definition Task.php:24
getName()
Get the symbolic name of the task.
getDescriptionMessage()
Get the description as a Message object.
Definition Task.php:81
Abstract maintenance class for quickly writing and churning out maintenance scripts with minimal effo...
output( $out, $channel=null)
Throw some output to the user.
fatalError( $msg, $exitCode=1)
Output a message and terminate the current script.
addOption( $name, $description, $required=false, $withArg=false, $shortName=false, $multiOccurrence=false)
Add a parameter to the script.
hasOption( $name)
Checks to see if a particular option was set.
getOption( $name, $default=null)
Get an option, or return the default.
error( $err, $die=0)
Throw an error to the user.
getServiceContainer()
Returns the main service container.
addDescription( $text)
Set the description text.
Load JSON files, and uses a Processor to extract information.
Builder class for constructing a Config object from a set of sources during bootstrap.
putConfigValue(string $key, $value)
Puts a value into a config variable.
Generic operation result class Has warning/error list, boolean status and arbitrary value.
isOK()
Returns whether the operation completed.
isGood()
Returns whether the operation completed and didn't have any error or warnings.
Dependency bundle and execution context for installer tasks.