1 <?php # vim:ts=2:sw=2:et:
2 /* For licensing and copyright terms, see the file named LICENSE */
4 if (function_exists('date_default_timezone_set')) {
5 date_default_timezone_set('UTC');
8 ini_set('memory_limit', 256*1024*1024);
9 $_GLOBALS['MTRACK_CONFIG_SKIP_BOOT'] = true;
10 include 'inc/common.php';
11 include 'bin/import-trac.php';
13 if (!file_exists("bin/init.php")) {
14 echo "You must run me from the top-level mtrack dir\n";
18 /* People doing this are not necessarily sane, make sure we have PDO and
20 if (!extension_loaded('PDO') || !extension_loaded('pdo_sqlite')) {
21 echo "Mtrack requires PDO and pdo_sqlite to function\n";
29 $config_file_name = 'config.ini';
33 $wiki_repo_type = null;
36 $SCMS = MTrackRepo::getAvailableSCMs();
40 while (count($argv)) {
41 $arg = array_shift($argv);
43 if ($arg == '--trac') {
44 if (count($argv) < 2) {
45 usage("Missing arguments to --trac");
47 $pname = array_shift($argv);
48 $tracdb = array_shift($argv);
50 if (!file_exists($tracdb)) {
51 usage("Tracdb path must be a sqlite database");
53 $tracs[$tracdb] = $pname;
54 $projects[$pname] = $pname;
58 if ($arg == '--author-alias') {
59 if (count($argv) < 1) {
60 usage("Missing argument to --author-alias");
62 $aliasfile = array_shift($argv);
65 if ($arg == '--author-info') {
66 if (count($argv) < 1) {
67 usage("Missing argument to --author-info");
69 $authorfile = array_shift($argv);
73 if ($arg == '--wiki-type') {
74 if (count($argv) < 1) {
75 usage("Missing argument to --wiki-type");
77 $wiki_repo_type = array_shift($argv);
78 if (!isset($SCMS[$wiki_repo_type])) {
79 usage("Invalid repo type $wiki_repo_type");
84 if ($arg == '--repo') {
85 if (count($argv) < 3) {
86 usage("Missing arguments to --repo");
88 $rname = array_shift($argv);
89 $rtype = array_shift($argv);
90 $rpath = realpath(array_shift($argv));
92 if (!isset($SCMS[$rtype])) {
93 usage("Invalid repo type $rtype");
98 if (!is_dir("$rpath/.hg")) {
99 usage("Repo path must be a local hg repo dir");
103 if (!is_dir("$rpath/.git")) {
104 usage("Repo path must be a local git repo dir");
108 if (!file_exists("$rpath/format")) {
109 usage("Repo path must be a svn repo");
113 usage("Invalid repo type $rtype");
116 $repos[$rname] = array($rname, $rtype, $rpath);
120 if ($arg == '--link') {
121 if (count($argv) < 3) {
122 usage("Missing arguments to --link");
124 $pname = array_shift($argv);
125 $rname = array_shift($argv);
126 $rloc = array_shift($argv);
128 $links[] = array($pname, $rname, $rloc);
129 $projects[$pname] = $pname;
133 if ($arg == '--vardir') {
134 if (count($argv) < 1) {
135 usage("Missing argument to --vardir");
137 $vardir = array_shift($argv);
141 if ($arg == '--config-file') {
142 if (count($argv) < 1) {
143 usage("Missing argument to --config-file");
145 $config_file_name = array_shift($argv);
149 if ($arg == '--dsn') {
150 if (count($argv) < 1) {
151 usage("Missing argument to --dsn");
153 $DSN = array_shift($argv);
161 usage("Unhandled arguments");
164 if (file_exists("$vardir/mtrac.db")) {
165 echo "Nothing to do (already configured)\n";
170 echo "Setting up mtrack with:\n";
173 echo join("\n ", $projects);
177 foreach ($repos as $repo) {
178 echo " " . join(" ", $repo) . "\n";
179 foreach ($links as $link) {
180 if ($link[1] == $repo[0]) {
181 echo " $link[2] -> $link[0]\n";
188 foreach ($tracs as $tname => $pname) {
189 echo "Import trac $name -> $pname\n";
193 function usage($msg = '')
200 --wiki-type specify the repo type to use when initializing wiki
201 Supported repo types are listed below.
202 To use a pre-existing wiki, don't use this option,
203 use --repo wiki instead.
205 --repo {name} {type} {repopath}
206 define a repo named {name} of {type} at {repopath}
207 --link {project} {repo} {location}
208 link a repo location to a project
209 --trac {project} {tracenv}
210 import data from a trac environment at {tracenv}
211 and associate with project {project}
213 --vardir {dir} where to store database and search engine state.
214 Defaults to "var" in the current directory; will
215 be created if it does not exist.
217 --config-file {filename} Where to create the configuration file.
218 defaults to config.ini in the current directory.
220 --author-alias {filename}
221 where to find an authors file that maps usernames.
222 This is used to initialize the canonicalizations
223 used by the system. The format is a file of the
224 form: sourcename=canonicalname
225 The import will replace all instances of sourcename
226 with canonicalname in the history, and will record
227 the mapping so that future items will respect it.
229 --author-info {filename}
230 Where to find a file that will be used to initialize
231 the userinfo table. The format is:
232 canonid,fullname,email,active,timezone
233 where canonid is the canonical username.
236 If specified, should be a compatible PDO DSN
237 locating the database to store the mtrack state.
238 If you want to use sqlite, simply omit this
239 parameter. If you want to use PostgreSQL, then
240 you should enter a string like:
241 pgsql:host=dbhostname
243 mtrack only supports SQLite and PostgreSQL in
247 Supported repo types:
252 foreach (MTrackRepo::getAvailableSCMs() as $t => $r) {
253 $d = $r->getSCMMetaData();
254 printf(" %10s %s\n", $t, $d['name']);
261 if (!is_dir($vardir)) {
263 chmod($vardir, 02777);
265 if (!is_dir("$vardir/attach")) {
266 mkdir("$vardir/attach");
267 chmod("$vardir/attach", 02777);
270 putenv("MTRACK_CONFIG_FILE=" . $config_file_name);
271 if (!file_exists($config_file_name)) {
272 /* create a new config file */
273 $CFG = file_get_contents("config.ini.sample");
274 $CFG = str_replace("@VARDIR@", realpath($vardir), $CFG);
275 if (count($projects)) {
276 list($pname) = array_keys($projects);
278 $pname = "mtrack demo";
280 $CFG = str_replace("@PROJECT@", $pname, $CFG);
282 $DSN = "sqlite:@{core:dblocation}";
284 $CFG = str_replace("@DSN@", "\"$DSN\"", $CFG);
286 $tools_to_find = array('diff', 'diff3', 'php', 'svn', 'hg',
287 'git', 'svnserve', 'svnlook', 'svnadmin');
288 foreach ($SCMS as $S) {
289 $m = $S->getSCMMetaData();
290 if (isset($m['tools'])) {
291 foreach ($m['tools'] as $t) {
292 $tools_to_find[] = $t;
297 /* find reasonable defaults for tools */
299 foreach ($tools_to_find as $toolname) {
300 foreach (explode(PATH_SEPARATOR, getenv('PATH')) as $pdir) {
301 if (DIRECTORY_SEPARATOR == '\\' &&
302 file_exists($pdir . DIRECTORY_SEPARATOR . $toolname . '.exe')) {
303 $tools[$toolname] = $pdir . DIRECTORY_SEPARATOR . $toolname . '.exe';
305 } else if (file_exists($pdir . DIRECTORY_SEPARATOR . $toolname)) {
306 $tools[$toolname] = $pdir . DIRECTORY_SEPARATOR . $toolname;
310 if (!isset($tools[$toolname])) {
311 // let the system find it in the path at runtime
312 $tools[$toolname] = $toolname;
316 foreach ($tools as $toolname => $toolpath) {
317 $toolscfg .= "$toolname = \"$toolpath\"\n";
319 $CFG = str_replace("@TOOLS@", $toolscfg, $CFG);
320 file_put_contents($config_file_name, $CFG);
322 unset($_GLOBALS['MTRACK_CONFIG_SKIP_BOOT']);
323 MTrackConfig::$ini = null;
324 MTrackDB::$db = null;
325 MTrackTicket_CustomFields::$me = null;
326 MTrackConfig::boot();
328 include dirname(__FILE__) . '/schema-tool.php';
330 if (file_exists("$vardir/mtrac.db")) {
331 chmod("$vardir/mtrac.db", 0666);
334 $db = MTrackDB::get();
336 # if the config has custom fields, or the runtime config from an earlier
337 # installation does, let's update the schema, if needed.
338 MTrackTicket_CustomFields::getInstance()->save();
340 MTrackChangeset::$use_txn = false;
341 $db->beginTransaction();
343 $CANON_USERS = array();
345 foreach (file($aliasfile) as $line) {
346 if (preg_match('/^\s*([^=]+)\s*=\s*(.*)\s*$/', $line, $M)) {
347 if (!strlen($M[1])) {
350 $CANON_USERS[$M[1]] = $M[2];
355 foreach ($CANON_USERS as $src => $dest) {
356 MTrackDB::q('insert into useraliases (alias, userid) values (?, ?)',
357 $src, strlen($dest) ? $dest : null);
361 foreach (file($authorfile) as $line) {
362 $author = explode(',', trim($line));
363 if (strlen($author[0])) {
364 MTrackDB::q('insert into userinfo (
365 userid, fullname, email, active, timezone) values
370 ((int)$author[3]) ? 1 : 0,
376 /* set up initial ACL tree structure */
377 $rootobjects = array(
378 'Reports', 'Browser', 'Wiki', 'Timeline', 'Roadmap', 'Tickets',
379 'Enumerations', 'Components', 'Projects', 'User', 'Snippets',
382 foreach ($rootobjects as $rootobj) {
383 MTrackACL::addRootObjectAndRoles($rootobj);
386 # Add forking permissions
387 $ents = MTrackACL::getACL('Browser', false);
388 $ents[] = array('BrowserCreator', 'fork', true);
389 $ents[] = array('BrowserForker', 'fork', true);
390 $ents[] = array('BrowserForker', 'read', true);
391 MTrackACL::setACL('Browser', false, $ents);
393 $CS = MTrackChangeset::begin('~setup~', 'initial setup');
395 foreach ($projects as $pname) {
396 $p = new MTrackProject;
397 $p->shortname = $pname;
400 $projects[$pname] = $p;
403 foreach ($repos as $repo) {
405 $r->shortname = $repo[0];
406 $r->scmtype = $repo[1];
407 $r->repopath = $repo[2];
409 foreach ($links as $link) {
410 list($pname, $rname, $loc) = $link;
411 if ($rname == $r->shortname) {
412 $p = $projects[$pname];
413 $r->addLink($p, $loc);
418 $repos[$r->shortname] = $r;
421 if (!isset($repos['wiki'])) {
422 // Set up the wiki repo (if they don't already have one named wiki)
424 if ($wiki_repo_type === null) {
425 $wiki_repo_type = MTrackConfig::get('tools', 'hg');
426 if (file_exists($wiki_repo_type)) {
427 $wiki_repo_type = 'hg';
429 $wiki_repo_type = 'svn';
434 $r->shortname = 'wiki';
435 $r->scmtype = $wiki_repo_type;
436 $r->repopath = realpath($vardir) . DIRECTORY_SEPARATOR . 'wiki';
437 $r->description = 'The mtrack wiki pages are stored here';
438 echo " ** Creating repo 'wiki' of type $r->scmtype to hold Wiki content at $r->repopath\n";
439 echo " ** (use --repo option to specify an alternate location)\n";
440 echo " ** (use --wiki-type option to specify an alternate type)\n";
444 $r->reconcileRepoSettings();
448 foreach (glob("defaults/wiki/*") as $filename) {
449 $name = basename($filename);
450 echo "wiki: $name\n";
452 $w = MTrackWikiItem::loadByPageName($name);
453 if ($name == 'WikiStart' && $w !== null) {
454 /* skip existing WikiStart, as it may have been customized */
458 $w = new MTrackWikiItem($name);
461 $w->content = file_get_contents($filename);
464 touch("$vardir/.initializing");
465 MTrackWikiItem::commitNow();
467 foreach (glob("defaults/reports/*") as $filename) {
468 $name = basename($filename);
469 echo "report: $name\n";
471 $rep = new MTrackReport;
472 $rep->summary = $name;
474 list($sql, $wiki) = explode("\n\n", file_get_contents($filename), 2);
476 $rep->description = $wiki;
480 if (count($tracs) == 0) {
481 // Default enumerations
482 foreach (array('defect', 'enhancement', 'task') as $v => $c) {
483 $cl = new MTrackClassification;
488 foreach (array('fixed', 'invalid', 'wontfix', 'duplicate', 'worksforme')
490 $cl = new MTrackResolution;
495 foreach (array('blocker', 'critical', 'major', 'normal', 'minor', 'trivial')
497 $cl = new MTrackSeverity;
502 foreach (array('highest', 'high', 'normal', 'low', 'lowest')
504 $cl = new MTrackPriority;
509 foreach (array('new', 'open', 'closed', 'reopened')
511 $cl = new MTrackTicketState;
520 foreach ($tracs as $tracdb => $pname) {
521 import_from_trac($projects[$pname], $tracdb, $i++);
523 echo "Committing\n"; flush();
526 unlink("$vardir/.initializing");