From af3df142d409a6d51c1ab9a339952ace67c135f3 Mon Sep 17 00:00:00 2001 From: Thomas Keller Date: Sat, 28 Aug 2010 23:10:08 +0000 Subject: [PATCH] First attempt on a monotone plugin which creates a new database upon project creation and adds the new server to the running usher instance. If everything goes well, the usher instance is told to reload its configuration, so the new server / database is picked up and started automatically. --- src/IDF/Plugin/SyncMonotone.php | 137 ++++++++++++++++++++++++++++++++ src/IDF/conf/idf.php-dist | 13 +-- src/IDF/relations.php | 42 +++++----- 3 files changed, 168 insertions(+), 24 deletions(-) create mode 100644 src/IDF/Plugin/SyncMonotone.php diff --git a/src/IDF/Plugin/SyncMonotone.php b/src/IDF/Plugin/SyncMonotone.php new file mode 100644 index 0000000..2280a0b --- /dev/null +++ b/src/IDF/Plugin/SyncMonotone.php @@ -0,0 +1,137 @@ +processMonotoneCreate($params['project']); + break; + } + } + + /** + * Run mtn init command to create the corresponding monotone + * repository and add the database to the configured usher instance + * + * @param IDF_Project + */ + function processMonotoneCreate($project) + { + if ($project->getConf()->getVal('scm') != 'mtn') { + return; + } + + $repotempl = Pluf::f('mtn_repositories', false); + if ($repotempl === false) { + throw new IDF_Scm_Exception( + '"mtn_repositories" must be defined in your configuration file.' + ); + } + + $usher_config = Pluf::f('mtn_usher', array()); + if (!array_key_exists('rcfile', $usher_config) || + !is_writable($usher_config['rcfile'])) { + throw new IDF_Scm_Exception( + '"rcfile" in "mtn_usher" does not exist or is not writable.' + ); + } + + $shortname = $project->shortname; + $dbfile = sprintf($repotempl, $shortname); + if (file_exists($dbfile)) { + throw new IDF_Scm_Exception(sprintf( + __('The repository %s already exists.'), $dbfile + )); + } + $return = 0; + $output = array(); + $cmd = sprintf( + Pluf::f('mtn_path', 'mtn').' db init -d %s', + escapeshellarg($dbfile) + ); + $cmd = Pluf::f('idf_exec_cmd_prefix', '').$cmd; + $ll = exec($cmd, $output, $return); + if ($return != 0) { + throw new IDF_Scm_Exception(sprintf( + __('Could not create repository %s - please check '. + 'your error log for details.'), + $dbfile + )); + } + + $usher_rc = file_get_contents($usher_config['rcfile']); + $parsed_config = array(); + try { + $parsed_config = IDF_Scm_Monotone_BasicIO::parse($usher_rc); + } + catch (Exception $e) { + throw new IDF_Scm_Exception(sprintf( + __('Could not parse usher configuration in "%s": %s'), + $usher_config['rcfile'], $e->getMessage() + )); + } + + // ensure we haven't configured a server with this name already + foreach ($parsed_config as $stanzas) + { + foreach ($stanzas as $stanza_line) + { + if ($stanza_line['key'] == 'server' && + $stanza_line['values'][0] == $shortname) + { + throw new IDF_Scm_Exception(sprintf( + __('usher configuration already contains a server '. + 'entry named "%s"'), + $shortname + )); + } + } + } + + $new_server = array( + array('key' => 'server', 'values' => array($shortname)), + array('key' => 'local', 'values' => array('-d', $dbfile)), + ); + + $parsed_config[] = $new_server; + $usher_rc = IDF_Scm_Monotone_BasicIO::compile($parsed_config); + + // FIXME: more sanity - what happens on failing writes? + $fp = fopen($usher_config['rcfile'], 'w'); + fwrite($fp, $usher_rc); + fclose($fp); + + IDF_Scm_Monotone_Usher::reload(); + } +} diff --git a/src/IDF/conf/idf.php-dist b/src/IDF/conf/idf.php-dist index 390ce36..31c4661 100644 --- a/src/IDF/conf/idf.php-dist +++ b/src/IDF/conf/idf.php-dist @@ -147,13 +147,16 @@ $cfg['mtn_db_access'] = 'remote'; # # 'host' and 'port' must be set to the specific bits from usher's # configured 'adminaddr', 'user' and 'pass' must match the values set for -# the configured 'userpass' combination +# the configured 'userpass' combination. The 'rcfile' variable must point +# to the full (writable) path of the usher configuration file which gets +# updated when new projects are added # #$cfg['mtn_usher'] = array( -# 'host' => 'localhost', -# 'port' => 12345, -# 'user' => 'admin', -# 'pass' => 'admin', +# 'host' => 'localhost', +# 'port' => 12345, +# 'user' => 'admin', +# 'pass' => 'admin', +# 'rcfile' => '/path/to/usher.conf', #); # diff --git a/src/IDF/relations.php b/src/IDF/relations.php index f5a5925..bf4e32e 100644 --- a/src/IDF/relations.php +++ b/src/IDF/relations.php @@ -49,51 +49,55 @@ Pluf_Signal::connect('Pluf_Template_Compiler::construct_template_tags_modifiers' # -- Standard plugins, they will run only if configured -- # # Subversion synchronization -Pluf_Signal::connect('IDF_Project::membershipsUpdated', +Pluf_Signal::connect('IDF_Project::membershipsUpdated', array('IDF_Plugin_SyncSvn', 'entry')); -Pluf_Signal::connect('IDF_Project::created', +Pluf_Signal::connect('IDF_Project::created', array('IDF_Plugin_SyncSvn', 'entry')); -Pluf_Signal::connect('Pluf_User::passwordUpdated', +Pluf_Signal::connect('Pluf_User::passwordUpdated', array('IDF_Plugin_SyncSvn', 'entry')); -Pluf_Signal::connect('IDF_Project::preDelete', +Pluf_Signal::connect('IDF_Project::preDelete', array('IDF_Plugin_SyncSvn', 'entry')); -Pluf_Signal::connect('svnpostcommit.php::run', +Pluf_Signal::connect('svnpostcommit.php::run', array('IDF_Plugin_SyncSvn', 'entry')); # # Mercurial synchronization -Pluf_Signal::connect('IDF_Project::membershipsUpdated', +Pluf_Signal::connect('IDF_Project::membershipsUpdated', array('IDF_Plugin_SyncMercurial', 'entry')); -Pluf_Signal::connect('IDF_Project::created', +Pluf_Signal::connect('IDF_Project::created', array('IDF_Plugin_SyncMercurial', 'entry')); -Pluf_Signal::connect('Pluf_User::passwordUpdated', +Pluf_Signal::connect('Pluf_User::passwordUpdated', array('IDF_Plugin_SyncMercurial', 'entry')); -Pluf_Signal::connect('hgchangegroup.php::run', +Pluf_Signal::connect('hgchangegroup.php::run', array('IDF_Plugin_SyncMercurial', 'entry')); # # Git synchronization -Pluf_Signal::connect('IDF_Project::membershipsUpdated', +Pluf_Signal::connect('IDF_Project::membershipsUpdated', array('IDF_Plugin_SyncGit', 'entry')); -Pluf_Signal::connect('IDF_Key::postSave', +Pluf_Signal::connect('IDF_Key::postSave', array('IDF_Plugin_SyncGit', 'entry')); -Pluf_Signal::connect('IDF_Project::created', +Pluf_Signal::connect('IDF_Project::created', array('IDF_Plugin_SyncGit', 'entry')); -Pluf_Signal::connect('IDF_Key::preDelete', +Pluf_Signal::connect('IDF_Key::preDelete', array('IDF_Plugin_SyncGit', 'entry')); -Pluf_Signal::connect('gitpostupdate.php::run', +Pluf_Signal::connect('gitpostupdate.php::run', array('IDF_Plugin_SyncGit', 'entry')); # +# monotone synchronization +Pluf_Signal::connect('IDF_Project::created', + array('IDF_Plugin_SyncMonotone', 'entry')); +# # -- Processing of the webhook queue -- -Pluf_Signal::connect('queuecron.php::run', +Pluf_Signal::connect('queuecron.php::run', array('IDF_Queue', 'process')); # -# Processing of a given webhook, the hook can be configured -# directly in the configuration file if a different solution +# Processing of a given webhook, the hook can be configured +# directly in the configuration file if a different solution # is required. -Pluf_Signal::connect('IDF_Queue::processItem', - Pluf::f('idf_hook_process_item', +Pluf_Signal::connect('IDF_Queue::processItem', + Pluf::f('idf_hook_process_item', array('IDF_Webhook', 'process'))); return $m;