diff --git a/src/IDF/Scm/Monotone.php b/src/IDF/Scm/Monotone.php index b9c0b9e..dba1460 100644 --- a/src/IDF/Scm/Monotone.php +++ b/src/IDF/Scm/Monotone.php @@ -36,7 +36,7 @@ class IDF_Scm_Monotone_Stdio do not output it and are therefor incompatible */ public static $SUPPORTED_STDIO_VERSION = 2; - private $repo; + private $project; private $proc; private $pipes; private $oob; @@ -46,11 +46,11 @@ class IDF_Scm_Monotone_Stdio /** * Constructor - starts the stdio process * - * @param string Repository path + * @param IDF_Project */ - public function __construct($repo) + public function __construct(IDF_Project $project) { - $this->repo = $repo; + $this->project = $project; $this->start(); } @@ -70,10 +70,35 @@ class IDF_Scm_Monotone_Stdio if (is_resource($this->proc)) $this->stop(); - $cmd = Pluf::f('idf_exec_cmd_prefix', '') - .sprintf("%s -d %s automate stdio --no-workspace --norc", - Pluf::f('mtn_path', 'mtn'), - escapeshellarg($this->repo)); + $remote_db_access = Pluf::f('mtn_db_access', 'remote') == "remote"; + + $cmd = Pluf::f('idf_exec_cmd_prefix', '') . + Pluf::f('mtn_path', 'mtn') . ' '; + + $opts = Pluf::f('mtn_opts', array()); + foreach ($opts as $opt) + { + $cmd .= sprintf('%s ', escapeshellarg($opt)); + } + + // FIXME: we might want to add an option for anonymous / no key + // access, but upstream bug #30237 prevents that for now + if ($remote_db_access) + { + $host = sprintf(Pluf::f('mtn_remote_url'), $this->project->shortname); + $cmd .= sprintf('automate remote_stdio %s', escapeshellarg($host)); + } + else + { + $repo = sprintf(Pluf::f('mtn_repositories'), $this->project->shortname); + if (!file_exists($repo)) + { + throw new IDF_Scm_Exception( + "repository file '$repo' does not exist" + ); + } + $cmd .= sprintf('--db %s automate stdio', escapeshellarg($repo)); + } $descriptors = array( 0 => array("pipe", "r"), @@ -369,11 +394,10 @@ class IDF_Scm_Monotone extends IDF_Scm /** * @see IDF_Scm::__construct() */ - public function __construct($repo, $project=null) + public function __construct($project) { - $this->repo = $repo; $this->project = $project; - $this->stdio = new IDF_Scm_Monotone_Stdio($repo); + $this->stdio = new IDF_Scm_Monotone_Stdio($project); } /** @@ -381,14 +405,16 @@ class IDF_Scm_Monotone extends IDF_Scm */ public function getRepositorySize() { - if (!file_exists($this->repo)) { + // FIXME: this obviously won't work with remote databases - upstream + // needs to implement mtn db info in automate at first + $repo = sprintf(Pluf::f('mtn_repositories'), $this->project->shortname); + if (!file_exists($repo)) + { return 0; } - // FIXME: this won't work with remote databases - upstream - // needs to implement mtn db info in automate at first $cmd = Pluf::f('idf_exec_cmd_prefix', '').'du -sk ' - .escapeshellarg($this->repo); + .escapeshellarg($repo); $out = explode(' ', self::shell_exec('IDF_Scm_Monotone::getRepositorySize', $cmd), 2); @@ -821,22 +847,13 @@ class IDF_Scm_Monotone extends IDF_Scm } } - $protocol = Pluf::f('mtn_remote_protocol', 'netsync'); - - if ($protocol == "ssh") + $remote_url = Pluf::f('mtn_remote_url', ''); + if (empty($remote_url)) { - // ssh is protocol + host + db-path + branch - return "ssh://" . - sprintf(Pluf::f('mtn_remote_host'), $project->shortname) . - sprintf(Pluf::f('mtn_repositories'), $project->shortname) . - " " . $branch; + return ''; } - // netsync is the default - return sprintf( - Pluf::f('mtn_remote_host'), - $project->shortname - )." ".$branch; + return sprintf($remote_url, $project->shortname)."?".$branch; } /** @@ -844,7 +861,8 @@ class IDF_Scm_Monotone extends IDF_Scm */ public static function getAuthAccessUrl($project, $user, $commit = null) { - return self::getAnonymousAccessUrl($project, $commit); + $url = self::getAnonymousAccessUrl($project, $commit); + return preg_replace("#^ssh://#", "ssh://$user@", $url); } /** @@ -855,8 +873,7 @@ class IDF_Scm_Monotone extends IDF_Scm */ public static function factory($project) { - $rep = sprintf(Pluf::f('mtn_repositories'), $project->shortname); - return new IDF_Scm_Monotone($rep, $project); + return new IDF_Scm_Monotone($project); } /** diff --git a/src/IDF/conf/idf.php-dist b/src/IDF/conf/idf.php-dist index 38743fb..d759f94 100644 --- a/src/IDF/conf/idf.php-dist +++ b/src/IDF/conf/idf.php-dist @@ -75,27 +75,71 @@ $cfg['svn_remote_url'] = 'http://localhost/svn/%s'; # Path to the monotone binary $cfg['mtn_path'] = 'mtn'; -# Same as for git, you can have multiple repositories, one for each -# project or a single one for all the projects. Beware though that -# if you want to setup separate write access for the projects, you -# you have to setup different databases for each one. -# -# To access an mtn repository remotely you have two possibilities, -# via ssh and monotone's own netsync protocol. Usually each repository -# has to serve its contents in a separate process, but there exists a tool, -# called "usher", which acts as single entry point and distributes incoming -# requests further, based either on a particular branch pattern or configured -# host name (similar to SNI, the Server Name Indication, of TLS). -# -# A full HOWTO set this up is beyond this scope, please refer to the -# documentation of monotone and / or ask on their mailing list / IRC channel -# (irc.oftc.net/#monotone) +# Additional options for the started monotone process +$cfg['mtn_opts'] = array('--no-workspace', '--norc'); +# +# You can setup monotone for use with indefero in two ways: +# +# 1) One database for everything: +# Set 'mtn_repositories' below to a fixed database path, such as +# '/home/mtn/repositories/all_projects.mtn' +# +# Pro: - easy to setup and to manage +# Con: - while read access can be configured per-branch, +# granting write access rights to a user means that +# he can write anything in the global database +# - database lock problem: the database from which +# indefero reads its data cannot be used to serve the +# contents to the users, as the serve process locks +# the database +# +# 2) One database for every project with 'usher': +# Set 'mtn_remote_url' below to a string which matches your setup. +# Again, the '%s' placeholder will be expanded to the project's +# short name. Note that 'mtn_remote_url' is used as internal +# URI (to access the data for indefero) as well as external URI +# (for end users) at the same time. +# +# Then download and configure 'usher' +# (mtn clone mtn://monotone.ca?net.venge.monotone.contrib.usher) +# which acts as proxy in front of all single project databases. +# Usher's server name should be mapped to the project's short name, +# so you end up with something like this for every project: +# +# server "project" +# local "-d" "/home/mtn/repositories/project.mtn" "*" +# +# Alternatively if you assign every project a unique DNS such as +# 'project.my-hosting.biz', you can also configure it like this: +# +# host "project.my-hosting.biz" +# local "-d" "/home/mtn/repositories/project.mtn" "*" +# +# Pro: - read and write access can be granted per project +# - no database locking issues +# - one public server running on the one well-known port +# Con: - harder to setup +# +# Usher can also be used to forward sync requests to remote servers, +# please consult its README file for more information. +# +# monotone also allows to use SSH as transport protocol, so if you do not plan +# to setup a netsync server as described above, then just enter a URI like +# 'ssh://my-host.biz/home/mtn/repositories/%s.mtn' in 'mtn_remote_url'. +# $cfg['mtn_repositories'] = '/home/mtn/repositories/%s.mtn'; -# The preferred URL with which people can access this service. The placeholder -# denotes the unique project name which could be used as distinguishable SNI. -$cfg['mtn_remote_host'] = '%s.my.host.com'; -# Possible values 'ssh' and 'netsync' -$cfg['mtn_remote_protocol'] = 'netsync'; +$cfg['mtn_remote_url'] = 'mtn://my-host.biz/%s'; +# +# Whether the particular database(s) are accessed locally (via automate stdio) +# or remotely (via automate remote_stdio). 'remote' is the default for +# netsync setups, while 'local' access should be choosed for ssh access. +# +# Note that you need to setup the hook 'get_remote_automate_permitted' for +# each remotely accessible database. A full HOWTO set this up is beyond this +# scope, please refer to the documentation of monotone and / or ask on the +# mailing list / IRC channel (irc.oftc.net/#monotone) +# +$cfg['mtn_db_access'] = 'remote'; # Mercurial repositories path #$cfg['mercurial_repositories'] = '/home/mercurial/repositories/%s';