1 <?php # vim:ts=2:sw=2:et:
2 /* For licensing and copyright terms, see the file named LICENSE */
3 die("make a class of me");
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);
162 usage("Unhandled arguments");
165 if (file_exists("$vardir/mtrac.db")) {
166 echo "Nothing to do (already configured)\n";
171 echo "Setting up mtrack with:\n";
174 echo join("\n ", $projects);
178 foreach ($repos as $repo) {
179 echo " " . join(" ", $repo) . "\n";
180 foreach ($links as $link) {
181 if ($link[1] == $repo[0]) {
182 echo " $link[2] -> $link[0]\n";
189 foreach ($tracs as $tname => $pname) {
190 echo "Import trac $name -> $pname\n";
194 function usage($msg = '')
201 --wiki-type specify the repo type to use when initializing wiki
202 Supported repo types are listed below.
203 To use a pre-existing wiki, don't use this option,
204 use --repo wiki instead.
206 --repo {name} {type} {repopath}
207 define a repo named {name} of {type} at {repopath}
208 --link {project} {repo} {location}
209 link a repo location to a project
210 --trac {project} {tracenv}
211 import data from a trac environment at {tracenv}
212 and associate with project {project}
214 --vardir {dir} where to store database and search engine state.
215 Defaults to "var" in the current directory; will
216 be created if it does not exist.
218 --config-file {filename} Where to create the configuration file.
219 defaults to config.ini in the current directory.
221 --author-alias {filename}
222 where to find an authors file that maps usernames.
223 This is used to initialize the canonicalizations
224 used by the system. The format is a file of the
225 form: sourcename=canonicalname
226 The import will replace all instances of sourcename
227 with canonicalname in the history, and will record
228 the mapping so that future items will respect it.
230 --author-info {filename}
231 Where to find a file that will be used to initialize
232 the userinfo table. The format is:
233 canonid,fullname,email,active,timezone
234 where canonid is the canonical username.
237 If specified, should be a compatible PDO DSN
238 locating the database to store the mtrack state.
239 If you want to use sqlite, simply omit this
240 parameter. If you want to use PostgreSQL, then
241 you should enter a string like:
242 pgsql:host=dbhostname
244 mtrack only supports SQLite and PostgreSQL in
248 Supported repo types:
253 foreach (MTrackRepo::getAvailableSCMs() as $t => $r) {
254 $d = $r->getSCMMetaData();
255 printf(" %10s %s\n", $t, $d['name']);
262 if (!is_dir($vardir)) {
264 chmod($vardir, 02777);
266 if (!is_dir("$vardir/attach")) {
267 mkdir("$vardir/attach");
268 chmod("$vardir/attach", 02777);
271 putenv("MTRACK_CONFIG_FILE=" . $config_file_name);
272 if (!file_exists($config_file_name)) {
273 /* create a new config file */
274 $CFG = file_get_contents("config.ini.sample");
275 $CFG = str_replace("@VARDIR@", realpath($vardir), $CFG);
276 if (count($projects)) {
277 list($pname) = array_keys($projects);
279 $pname = "mtrack demo";
281 $CFG = str_replace("@PROJECT@", $pname, $CFG);
283 $DSN = "sqlite:@{core:dblocation}";
285 $CFG = str_replace("@DSN@", "\"$DSN\"", $CFG);
287 $tools_to_find = array('diff', 'diff3', 'php', 'svn', 'hg',
288 'git', 'svnserve', 'svnlook', 'svnadmin');
289 foreach ($SCMS as $S) {
290 $m = $S->getSCMMetaData();
291 if (isset($m['tools'])) {
292 foreach ($m['tools'] as $t) {
293 $tools_to_find[] = $t;
298 /* find reasonable defaults for tools */
300 foreach ($tools_to_find as $toolname) {
301 foreach (explode(PATH_SEPARATOR, getenv('PATH')) as $pdir) {
302 if (DIRECTORY_SEPARATOR == '\\' &&
303 file_exists($pdir . DIRECTORY_SEPARATOR . $toolname . '.exe')) {
304 $tools[$toolname] = $pdir . DIRECTORY_SEPARATOR . $toolname . '.exe';
306 } else if (file_exists($pdir . DIRECTORY_SEPARATOR . $toolname)) {
307 $tools[$toolname] = $pdir . DIRECTORY_SEPARATOR . $toolname;
311 if (!isset($tools[$toolname])) {
312 // let the system find it in the path at runtime
313 $tools[$toolname] = $toolname;
317 foreach ($tools as $toolname => $toolpath) {
318 $toolscfg .= "$toolname = \"$toolpath\"\n";
320 $CFG = str_replace("@TOOLS@", $toolscfg, $CFG);
321 file_put_contents($config_file_name, $CFG);
323 unset($_GLOBALS['MTRACK_CONFIG_SKIP_BOOT']);
324 MTrackConfig::$ini = null;
325 MTrackDB::$db = null;
326 MTrackTicket_CustomFields::$me = null;
327 MTrackConfig::boot();
329 include dirname(__FILE__) . '/schema-tool.php';
331 if (file_exists("$vardir/mtrac.db")) {
332 chmod("$vardir/mtrac.db", 0666);
335 $db = MTrackDB::get();
337 # if the config has custom fields, or the runtime config from an earlier
338 # installation does, let's update the schema, if needed.
339 MTrackTicket_CustomFields::getInstance()->save();
341 MTrackChangeset::$use_txn = false;
342 $db->beginTransaction();
344 $CANON_USERS = array();
346 foreach (file($aliasfile) as $line) {
347 if (preg_match('/^\s*([^=]+)\s*=\s*(.*)\s*$/', $line, $M)) {
348 if (!strlen($M[1])) {
351 $CANON_USERS[$M[1]] = $M[2];
356 foreach ($CANON_USERS as $src => $dest) {
357 MTrackDB::q('insert into useraliases (alias, userid) values (?, ?)',
358 $src, strlen($dest) ? $dest : null);
362 foreach (file($authorfile) as $line) {
363 $author = explode(',', trim($line));
364 if (strlen($author[0])) {
365 MTrackDB::q('insert into userinfo (
366 userid, fullname, email, active, timezone) values
371 ((int)$author[3]) ? 1 : 0,
377 /* set up initial ACL tree structure */
378 $rootobjects = array(
379 'Reports', 'Browser', 'Wiki', 'Timeline', 'Roadmap', 'Tickets',
380 'Enumerations', 'Components', 'Projects', 'User', 'Snippets',
383 foreach ($rootobjects as $rootobj) {
384 MTrackACL::addRootObjectAndRoles($rootobj);
387 # Add forking permissions
388 $ents = MTrackACL::getACL('Browser', false);
389 $ents[] = array('BrowserCreator', 'fork', true);
390 $ents[] = array('BrowserForker', 'fork', true);
391 $ents[] = array('BrowserForker', 'read', true);
392 MTrackACL::setACL('Browser', false, $ents);
394 $CS = MTrackChangeset::begin('~setup~', 'initial setup');
396 foreach ($projects as $pname) {
397 $p = new MTrackProject;
398 $p->shortname = $pname;
401 $projects[$pname] = $p;
404 foreach ($repos as $repo) {
406 $r->shortname = $repo[0];
407 $r->scmtype = $repo[1];
408 $r->repopath = $repo[2];
410 foreach ($links as $link) {
411 list($pname, $rname, $loc) = $link;
412 if ($rname == $r->shortname) {
413 $p = $projects[$pname];
414 $r->addLink($p, $loc);
419 $repos[$r->shortname] = $r;
422 if (!isset($repos['wiki'])) {
423 // Set up the wiki repo (if they don't already have one named wiki)
425 if ($wiki_repo_type === null) {
426 $wiki_repo_type = MTrackConfig::get('tools', 'hg');
427 if (file_exists($wiki_repo_type)) {
428 $wiki_repo_type = 'hg';
430 $wiki_repo_type = 'svn';
435 $r->shortname = 'wiki';
436 $r->scmtype = $wiki_repo_type;
437 $r->repopath = realpath($vardir) . DIRECTORY_SEPARATOR . 'wiki';
438 $r->description = 'The mtrack wiki pages are stored here';
439 echo " ** Creating repo 'wiki' of type $r->scmtype to hold Wiki content at $r->repopath\n";
440 echo " ** (use --repo option to specify an alternate location)\n";
441 echo " ** (use --wiki-type option to specify an alternate type)\n";
445 $r->reconcileRepoSettings();
449 foreach (glob("defaults/wiki/*") as $filename) {
450 $name = basename($filename);
451 echo "wiki: $name\n";
453 $w = MTrackWikiItem::loadByPageName($name);
454 if ($name == 'WikiStart' && $w !== null) {
455 /* skip existing WikiStart, as it may have been customized */
459 $w = new MTrackWikiItem($name);
462 $w->content = file_get_contents($filename);
465 touch("$vardir/.initializing");
466 MTrackWikiItem::commitNow();
468 foreach (glob("defaults/reports/*") as $filename) {
469 $name = basename($filename);
470 echo "report: $name\n";
472 $rep = new MTrack_Report;
473 $rep->summary = $name;
475 list($sql, $wiki) = explode("\n\n", file_get_contents($filename), 2);
477 $rep->description = $wiki;
481 if (count($tracs) == 0) {
482 // Default enumerations
483 foreach (array('defect', 'enhancement', 'task') as $v => $c) {
484 $cl = new MTrackClassification;
489 foreach (array('fixed', 'invalid', 'wontfix', 'duplicate', 'worksforme')
491 $cl = new MTrackResolution;
496 foreach (array('blocker', 'critical', 'major', 'normal', 'minor', 'trivial')
498 $cl = new MTrackSeverity;
503 foreach (array('highest', 'high', 'normal', 'low', 'lowest')
505 $cl = new MTrackPriority;
510 foreach (array('new', 'open', 'closed', 'reopened')
512 $cl = new MTrackTicketState;
521 foreach ($tracs as $tracdb => $pname) {
522 import_from_trac($projects[$pname], $tracdb, $i++);
524 echo "Committing\n"; flush();
527 unlink("$vardir/.initializing");