Added the Mercurial repository serving synchronization.
This fixes ticket 79.
This commit is contained in:
parent
023cd73ebf
commit
0eeef34908
@ -101,9 +101,12 @@ To upgrade:
|
||||
$ php /home/www/pluf/src/migrate.php --conf=IDF/conf/idf.php -a -d -u
|
||||
$ php /home/www/pluf/src/migrate.php --conf=IDF/conf/idf.php -a -d
|
||||
|
||||
## Subversion Repository Synchronization
|
||||
## Repository Synchronization
|
||||
|
||||
The documentation is available in the `doc/syncsvn.mdtext` file.
|
||||
The documentation is available in the `doc` folder.
|
||||
|
||||
* Subversion: `doc/syncsvn.mdtext`.
|
||||
* Mercurial: `doc/syncmercurial.mdtext`.
|
||||
|
||||
## For the Apache Webserver Users
|
||||
|
||||
|
64
doc/syncmercurial.mdtext
Normal file
64
doc/syncmercurial.mdtext
Normal file
@ -0,0 +1,64 @@
|
||||
# Plugin SyncMercurial by Benjamin Jorand
|
||||
|
||||
The SyncMercurial plugin allows the direct creation and synchronisation of
|
||||
mercurial repositories with the InDefero database. The repositories will be
|
||||
published by hgwebdir.cgi using HTTP. It also handles private repositories.
|
||||
|
||||
SyncMercurial is adapted from SyncSvn by Baptiste Michaud.
|
||||
|
||||
## To Contact the Author
|
||||
|
||||
Benjamin Jorand <benjamin.jorand@gmail.com>
|
||||
|
||||
## Apache configuration
|
||||
|
||||
The simple way to share Mercurial repositories is to publish them
|
||||
using HTTP and `hgwebdir.cgi`.
|
||||
|
||||
It first requires a config file called hgweb.config in the same
|
||||
directory where you put hgwebdir.cgi (for example,
|
||||
`/home/indefero/scripts`):
|
||||
|
||||
[collections]
|
||||
/home/indefero/repositories/mercurial/ = /home/indefero/repositories/mercurial/
|
||||
|
||||
Then configure a vhost this way :
|
||||
|
||||
ScriptAliasMatch ^/hg(.*) /home/indefero/scripts/hgwebdir.cgi$1
|
||||
<Directory /home/indefero/scripts>
|
||||
Options +ExecCGI
|
||||
AuthName "Restricted"
|
||||
AuthType Basic
|
||||
AuthUserFile /home/indefero/auth/.htpasswd
|
||||
<Limit PUT POST>
|
||||
Require valid-user
|
||||
</Limit>
|
||||
</Directory>
|
||||
|
||||
Enable the authentification for private repositories :
|
||||
|
||||
Include /home/indefero/scripts/private_indefero.conf
|
||||
|
||||
## InDefero configuration
|
||||
|
||||
First, you need to install the File_Passwd PEAR package:
|
||||
|
||||
$ sudo pear install File_Passwd
|
||||
|
||||
Then, based on the paths provided in the Apache configuration, you
|
||||
need to put the following lines in your configuration file:
|
||||
|
||||
$cfg['idf_plugin_syncmercurial_passwd_file'] = '/home/indefero/auth/.htpasswd';
|
||||
$cfg['idf_plugin_syncmercurial_path'] = '/home/indefero/repositories/mercurial';
|
||||
$cfg['idf_plugin_syncmercurial_private_include'] = '/home/indefero/scripts/private_indefero.conf';
|
||||
$cfg['idf_plugin_syncmercurial_private_notify'] = '/home/indefero/tmp/notify.tmp';
|
||||
$cfg['idf_plugin_syncmercurial_private_url'] = '/hg/%s';
|
||||
|
||||
## Cron configuration
|
||||
|
||||
As InDefero modifies the private_indefero.conf, apache needs to be reloaded.
|
||||
Each time this file is modified, a temporary file is created.
|
||||
|
||||
*/5 * * * * /bin/sh /home/indefero/src/cron/SyncMercurial.sh
|
||||
|
||||
Edit this script and add correct values to `private_notify` and `reload_cmd`.
|
10
scripts/SyncMercurial.sh
Normal file
10
scripts/SyncMercurial.sh
Normal file
@ -0,0 +1,10 @@
|
||||
#!/bin/sh
|
||||
|
||||
private_notify="/home/indefero/tmp/notify.tmp"
|
||||
reload_cmd="/usr/sbin/apachectl -k graceful"
|
||||
|
||||
if [ -e $private_notify ]; then
|
||||
$reload_cmd
|
||||
rm -f $private_notify
|
||||
fi
|
||||
|
217
src/IDF/Plugin/SyncMercurial.php
Normal file
217
src/IDF/Plugin/SyncMercurial.php
Normal file
@ -0,0 +1,217 @@
|
||||
<?php
|
||||
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# This file is part of InDefero, an open source project management application.
|
||||
# Copyright (C) 2008 Céondo Ltd and contributors.
|
||||
#
|
||||
# InDefero is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# InDefero is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/**
|
||||
* This classes is a plugin which allows to synchronise access rights
|
||||
* between indefero and mercurial web-published repositories.
|
||||
*/
|
||||
class IDF_Plugin_SyncMercurial
|
||||
{
|
||||
|
||||
/**
|
||||
* Entry point of the plugin.
|
||||
*/
|
||||
static public function entry($signal, &$params)
|
||||
{
|
||||
// First check for the 3 mandatory config variables.
|
||||
if (!Pluf::f('idf_plugin_syncmercurial_passwd_file', false) or
|
||||
!Pluf::f('idf_plugin_syncmercurial_path', false) or
|
||||
!Pluf::f('idf_plugin_syncmercurial_hgrc', false)) {
|
||||
return;
|
||||
}
|
||||
include_once 'File/Passwd/Authdigest.php';
|
||||
$plug = new IDF_Plugin_SyncMercurial();
|
||||
switch ($signal) {
|
||||
case 'IDF_Project::created':
|
||||
$plug->processMercurialCreate($params['project']);
|
||||
break;
|
||||
case 'IDF_Project::membershipsUpdated':
|
||||
$plug->processSyncAuthz($params['project']);
|
||||
break;
|
||||
case 'Pluf_User::passwordUpdated':
|
||||
$plug->processSyncPasswd($params['user']);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run hg init command to create the corresponding Mercurial
|
||||
* repository.
|
||||
*
|
||||
* @param IDF_Project
|
||||
* @return bool Success
|
||||
*/
|
||||
function processMercurialCreate($project)
|
||||
{
|
||||
$shortname = $project->shortname;
|
||||
|
||||
if (false===($mercurial_path=Pluf::f('idf_plugin_syncmercurial_path',false))) {
|
||||
throw new Pluf_Exception_SettingError("'idf_plugin_syncmercurial_path' must be defined in your configuration file.");
|
||||
}
|
||||
|
||||
if (file_exists($mercurial_path.'/'.$shortname)) {
|
||||
throw new Exception(sprintf(__('The repository %s already exists.'),
|
||||
$mercurial_path.'/'.$shortname));
|
||||
}
|
||||
$return = 0;
|
||||
$output = array();
|
||||
$cmd = sprintf('hg init %s',
|
||||
escapeshellarg($mercurial_path.'/'.$shortname));
|
||||
$ll = exec($cmd, $output, $return);
|
||||
return ($return == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronise an user's password.
|
||||
*
|
||||
* @param Pluf_User
|
||||
*/
|
||||
function processSyncPasswd($user)
|
||||
{
|
||||
$passwd_file = Pluf::f('idf_plugin_syncmercurial_passwd_file');
|
||||
if (!file_exists($passwd_file) or !is_writable($passwd_file)) {
|
||||
return false;
|
||||
}
|
||||
$ht = new File_Passwd_Authbasic($passwd_file);
|
||||
$ht->load();
|
||||
$ht->setMode(FILE_PASSWD_SHA);
|
||||
if ($ht->userExists($user->login)) {
|
||||
$ht->changePasswd($user->login, $this->getMercurialPass($user));
|
||||
} else {
|
||||
$ht->addUser($user->login, $this->getMercurialPass($user));
|
||||
}
|
||||
$ht->save();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronize the hgrc file and the passwd file for the project.
|
||||
*
|
||||
* @param IDF_Project
|
||||
*/
|
||||
function processSyncAuthz($project)
|
||||
{
|
||||
$this->SyncAccess($project);
|
||||
$this->generateProjectPasswd($project);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the repository password for the user
|
||||
*/
|
||||
function getMercurialPass($user){
|
||||
return substr(sha1($user->password.Pluf::f('secret_key')), 0, 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* For a particular project: update all passwd information
|
||||
*/
|
||||
function generateProjectPasswd($project)
|
||||
{
|
||||
$passwd_file = Pluf::f('idf_plugin_syncmercurial_passwd_file');
|
||||
if (!file_exists($passwd_file) or !is_writable($passwd_file)) {
|
||||
throw new Exception (sprintf(__('%s does not exist or is not writable.'), $passwd_file));
|
||||
}
|
||||
$ht = new File_Passwd_Authbasic($passwd_file);
|
||||
$ht->setMode(FILE_PASSWD_SHA);
|
||||
$ht->load();
|
||||
$mem = $project->getMembershipData();
|
||||
$members = array_merge((array)$mem['members'], (array)$mem['owners'],
|
||||
(array)$mem['authorized']);
|
||||
foreach($members as $user) {
|
||||
if ($ht->userExists($user->login)) {
|
||||
$ht->changePasswd($user->login, $this->getMercurialPass($user));
|
||||
} else {
|
||||
$ht->addUser($user->login, $this->getMercurialPass($user));
|
||||
}
|
||||
}
|
||||
$ht->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the hgrc file
|
||||
*/
|
||||
function SyncAccess($project)
|
||||
{
|
||||
$shortname = $project->shortname;
|
||||
$hgrc_file = Pluf::f('idf_plugin_syncmercurial_path').sprintf('/%s/.hg/hgrc', $shortname);
|
||||
|
||||
// Get allow_push list
|
||||
$allow_push = '';
|
||||
$mem = $project->getMembershipData();
|
||||
foreach ($mem['owners'] as $v) {
|
||||
$allow_push .= $v->login.' ';
|
||||
}
|
||||
foreach ($mem['members'] as $v) {
|
||||
$allow_push .= $v->login.' ';
|
||||
}
|
||||
|
||||
// Generate hgrc content
|
||||
if (is_file($hgrc_file)) {
|
||||
$tmp_content = parse_ini_file($hgrc_file, true);
|
||||
$tmp_content['web']['allow_push'] = $allow_push;
|
||||
}
|
||||
else {
|
||||
$tmp_content = Pluf::f('idf_plugin_syncmercurial_hgrc');
|
||||
$tmp_content['web']['allow_push'] = $allow_push;
|
||||
}
|
||||
$fcontent = '';
|
||||
foreach ($tmp_content as $key => $elem){
|
||||
$fcontent .= '['.$key."]\n";
|
||||
foreach ($elem as $key2 => $elem2){
|
||||
$fcontent .= $key2.' = '.$elem2."\n";
|
||||
}
|
||||
}
|
||||
file_put_contents($hgrc_file, $fcontent, LOCK_EX);
|
||||
|
||||
// Generate private repository config file
|
||||
$private_file = Pluf::f('idf_plugin_syncmercurial_private_include');
|
||||
$notify_file = Pluf::f('idf_plugin_syncmercurial_private_notify');
|
||||
$fcontent = '';
|
||||
foreach (Pluf::factory('IDF_Project')->getList() as $project) {
|
||||
$conf = new IDF_Conf();
|
||||
$conf->setProject($project);
|
||||
if ($project->private == true){
|
||||
$mem = $project->getMembershipData();
|
||||
$user = '';
|
||||
foreach ($mem['owners'] as $v) {
|
||||
$user .= $v->login.' ';
|
||||
}
|
||||
foreach ($mem['members'] as $v) {
|
||||
$user .= $v->login.' ';
|
||||
}
|
||||
foreach ($mem['authorized'] as $v) {
|
||||
$user .= $v->login.' ';
|
||||
}
|
||||
$fcontent .= '<Location '. sprintf(Pluf::f('idf_plugin_syncmercurial_private_url'), $project->shortname).'>'."\n";
|
||||
$fcontent .= 'AuthType Basic'."\n";
|
||||
$fcontent .= 'AuthName "Restricted"'."\n";
|
||||
$fcontent .= sprintf('AuthUserFile %s', Pluf::f('idf_plugin_syncmercurial_passwd_file'))."\n";
|
||||
$fcontent .= sprintf('Require user %s', $user)."\n";
|
||||
$fcontent .= '</Location>'."\n\n";
|
||||
}
|
||||
}
|
||||
file_put_contents($private_file, $fcontent, LOCK_EX);
|
||||
file_put_contents($notify_file, ' ', LOCK_EX);
|
||||
return true;
|
||||
}
|
||||
}
|
@ -52,4 +52,12 @@ Pluf_Signal::connect('IDF_Project::created',
|
||||
Pluf_Signal::connect('Pluf_User::passwordUpdated',
|
||||
array('IDF_Plugin_SyncSvn', 'entry'));
|
||||
|
||||
#
|
||||
# Mercurial synchronization
|
||||
Pluf_Signal::connect('IDF_Project::membershipsUpdated',
|
||||
array('IDF_Plugin_SyncMercurial', 'entry'));
|
||||
Pluf_Signal::connect('IDF_Project::created',
|
||||
array('IDF_Plugin_SyncMercurial', 'entry'));
|
||||
Pluf_Signal::connect('Pluf_User::passwordUpdated',
|
||||
array('IDF_Plugin_SyncMercurial', 'entry'));
|
||||
return $m;
|
||||
|
Loading…
Reference in New Issue
Block a user