Updated the plugin to match InDefero's coding standards.

This commit is contained in:
Loic d'Anterroches 2008-12-03 23:02:59 +01:00
parent 39cf9f985a
commit b60aeb0ca1
5 changed files with 205 additions and 113 deletions

View File

@ -6,3 +6,4 @@ Much appreciated contributors:
Nicolas Lassalle <http://www.beroot.org/> - Subversion support Nicolas Lassalle <http://www.beroot.org/> - Subversion support
bohwaz <http://bohwaz.net/> bohwaz <http://bohwaz.net/>
Benjamin Jorand <benjamin.jorand@gmail.com> - Mercurial support Benjamin Jorand <benjamin.jorand@gmail.com> - Mercurial support
Baptiste Michaud <bactisme@gmail.com> - Subversion synchronization

75
doc/syncsvn.mdtext Normal file
View File

@ -0,0 +1,75 @@
# Plugin SyncSvn by Baptiste Michaud
The SyncSvn plugin allow the direct creation and synchronisation of
subversion repositories with the InDefero database. This requires
giving access to the repositories using the DAV_SVN module of Apache2.
## To Contact the Author
Baptiste Michaud
bactisme@gmail.com
webplay.fr - frandroid.com - lost-in-translation.fr
## Apache configuration
You will first need to install the DAV_SVN module for Apache. On
Debian/Ubuntu based systems just run:
$ sudo apt-get install libapache2-svn
$ sudo a2enmod dav_svn
Then, you need to configure dav_svn, this is an example of
configuration:
<Location /svn>
DAV svn
SVNParentPath /home/svn/repositories
AuthzSVNAccessFile /home/svn/dav_svn.authz
Satisfy Any
Require valid-user
AuthType Basic
AuthName "Subversion Repository"
AuthUserFile /home/svn/dav_svn.passwd
</Location>
Be sure to [read the documentation before](http://svnbook.red-bean.com/en/1.5/svn.serverconfig.httpd.html).
The files `/home/svn/dav_svn.authz`, `/home/svn/dav_svn.passwd` and
the directory `/home/svn/repositories` must be writable by your
webserver process. To ensure that, do:
$ sudo mkdir --parents /home/svn/repositories
$ sudo touch /home/svn/dav_svn.authz
$ sudo touch /home/svn/dav_svn.passwd
$ sudo chown -R www-data:www-data /home/svn
Now, you need to restart apache:
$ sudo /etc/init.d/apache2 force-reload
## InDefero Configuration
Based on the paths provided in the Apache configuration and if your
Apache server is serving the domain `www.mydomain.com`, the you need
to put the following in your configuration file:
$cfg['svn_repositories'] = 'file:///home/svn/repositories/%s';
// We add "trunk" to invite people to checkout the trunk of the
// project.
$cfg['svn_remote_url'] = 'http://www.mydomain.com/svn/%s/trunk';
// Synchronisation specific configuration variables
$cfg['idf_plugin_syncsvn_authz_file'] = '/home/svn/dav_svn.authz';
$cfg['idf_plugin_syncsvn_passwd_file'] = '/home/svn/dav_svn.passwd';
$cfg['idf_plugin_syncsvn_svn_path'] = '/home/svn/repositories';
You can have more control over the permissions given to the owners,
members, extra authorized users and anonymous users if you want with
the following configuration variables:
* **idf_plugin_syncsvn_access_owners ('rw')**: Access for the project owners.
* **idf_plugin_syncsvn_access_members ('rw')**: Access for the project members.
* **idf_plugin_syncsvn_access_extra ('r')**: Access for the extra authorized people in case of a private project.
* **idf_plugin_syncsvn_access_public ('r')**: Anonymous access.
* **idf_plugin_syncsvn_access_private ('')**: Anonymous access in the case of a private project.

View File

@ -97,6 +97,7 @@ class IDF_Form_TabsConf extends Pluf_Form
$this->project->private = 0; $this->project->private = 0;
} }
$this->project->update(); $this->project->update();
$this->project->membershipsUpdated();
} }
} }

View File

@ -24,171 +24,175 @@
require_once 'File/Passwd/Authdigest.php'; // $ pear install File_Passwd require_once 'File/Passwd/Authdigest.php'; // $ pear install File_Passwd
/** /**
* This classes is a plugin which allows to synchronise access rights between indefero * This classes is a plugin which allows to synchronise access rights
* and a DAV powered SVN repository. * between indefero and a DAV powered Subversion repository.
*/ */
class IDF_Plugin_SyncSvn class IDF_Plugin_SyncSvn
{ {
/** /**
* Entry point of the each plugins. * Entry point of the plugin.
*/ */
static function entry($signal, $params){ static public function entry($signal, $params)
// if not actif, do nothing {
// First check for the 3 mandatory config variables.
if ($signal == 'IDF_Project::created'){ if (!Pluf::f('idf_plugin_syncsvn_authz_file', false) or
$project = $params['project']; !Pluf::f('idf_plugin_syncsvn_passwd_file', false) or
!Pluf::f('idf_plugin_syncsvn_svn_path'. false)) {
$plug = new IDF_Plugin_SyncSVN(); return;
//$plug->processSVNCreate($project->shortname); }
$plug = new IDF_Plugin_SyncSvn();
}else if ($signal == 'IDF_Project::membershipsUpdated'){ switch ($signal) {
$project = $params['project']; case 'IDF_Project::created':
$plug->processSvnCreate($params['project']);
$plug = new IDF_Plugin_SyncSVN(); break;
$plug->processSyncAuthz($project); case 'IDF_Project::membershipsUpdated':
$plug->processSyncAuthz($params['project']);
}else if ($signal == 'IDF_User::passwordUpdated'){ break;
$plug = new IDF_Plugin_SyncSVN(); case 'Pluf_User::passwordUpdated':
$plug->processSyncPasswd($params['user']); $plug->processSyncPasswd($params['user']);
}else { break;
// do nothing
} }
} }
/** /**
* Run svnadmin command to create a usable SVN repository * Run svnadmin command to create the corresponding Subversion
* @param Project name * repository.
*
* @param IDF_Project
* @return bool Success
*/ */
function processSVNCreate($shortname){ function processSvnCreate($project)
{
$svn_path = Pluf::f('idf_plugin_syncsvn_svn_path'); $shortname = $project->shortname;
$svn_import_path = Pluf::f('idf_plugin_syncsvn_svn_import_path'); if (false===($svn_path=Pluf::f('idf_plugin_syncsvn_svn_path',false))) {
$chown_user = Pluf::f('idf_plugin_syncsvn_svn_import_path'); throw new Pluf_Exception_SettingError("'idf_plugin_syncsvn_svn_path' must be defined in your configuration file.");
$c = 0;
$createsvn = "svnadmin create ".$svn_path."/".$shortname;
Pluf_Utils::runExternal($createsvn, $c);
if ($svn_import_path != ""){
//perform initial import
// TODO
} }
if (file_exists($svn_path.'/'.$shortname)) {
if ($chown_user != ""){ throw new Exception(sprintf(__('The repository %s already exists.'),
$chown = "chown ".$chown_user." ".$svn_path."/".$shortname." -R"; $svn_path.'/'.$shortname));
Pluf_Utils::runExternal($chown, $c);
} }
$return = 0;
$output = array();
$cmd = sprintf('svnadmin create %s',
escapeshellarg($svn_path.'/'.$shortname));
$ll = exec($cmd, $output, $return);
return ($return == 0);
} }
/** /**
* Synchronise an user's password * Synchronise an user's password.
* @param $user Pluf_User *
* @param Pluf_User
*/ */
function processSyncPasswd($user){ function processSyncPasswd($user)
{
$passwd_file = Pluf::f('idf_plugin_syncsvn_passwd_file'); $passwd_file = Pluf::f('idf_plugin_syncsvn_passwd_file');
if (!file_exists($passwd_file) or !is_writable($passwd_file)) {
return false;
}
$ht = new File_Passwd_Authbasic($passwd_file); $ht = new File_Passwd_Authbasic($passwd_file);
$ht->parse(); $ht->parse();
$ht->setMode(FILE_PASSWD_SHA); // not anymore a option $ht->setMode(FILE_PASSWD_SHA);
$ht->addUser($user, $this->getSVNPass($user)); if ($ht->userExists($user->login)) {
$ht->changePasswd($user->login, $this->getSvnPass($user));
} else {
$ht->addUser($user->login, $this->getSvnPass($user));
}
$ht->save(); $ht->save();
return true;
} }
/** /**
* Synchronize the authz file and the passwd file for the project * Synchronize the authz file and the passwd file for the project.
* @param $project IDF_Project *
* @param IDF_Project
*/ */
function processSyncAuthz($project){ function processSyncAuthz($project)
//synchronise authz file {
$this->SyncAccess(); $this->SyncAccess();
//synchronise pass file for
$this->generateProjectPasswd($project); $this->generateProjectPasswd($project);
} }
/** /**
* Get the repository password for the user * Get the repository password for the user
*/ */
function getSVNPass($user){ function getSvnPass($user){
return substr(sha1($user->password.Pluf::f('secret_key')), 0, 8); return substr(sha1($user->password.Pluf::f('secret_key')), 0, 8);
} }
/** /**
* For a particular project: update all passwd information * For a particular project: update all passwd information
*/ */
function generateProjectPasswd($project){ function generateProjectPasswd($project)
{
$passwd_file = Pluf::f('idf_plugin_syncsvn_passwd_file'); $passwd_file = Pluf::f('idf_plugin_syncsvn_passwd_file');
$ht = new File_Passwd_Authbasic($passwd_file); if (!file_exists($passwd_file) or !is_writable($passwd_file)) {
return false;
$ht->setMode(FILE_PASSWD_SHA); // not anymore a option }
$ht->parse(); $ht = new File_Passwd_Authbasic($passwd_file);
$ht->setMode(FILE_PASSWD_SHA);
$mem = $project->getMembershipData(); $ht->parse();
$members = $mem['members']; $mem = $project->getMembershipData();
$owners = $mem['owners']; $members = array_merge((array)$mem['members'], (array)$mem['owners'],
(array)$mem['authorized']);
foreach($owners as $v){ foreach($members as $user) {
$ht->addUser($v->login, $this->getSVNPass($v)); if ($ht->userExists($user->login)) {
$ht->changePasswd($user->login, $this->getSvnPass($user));
} else {
$ht->addUser($user->login, $this->getSvnPass($user));
} }
foreach($members as $v){
$ht->addUser($v->login, $this->getSVNPass($v));
} }
$ht->save(); $ht->save();
} }
/** /**
* Generate the dav_svn.authz file * Generate the dav_svn.authz file
*
* We rebuild the complete file each time. This is just to be sure
* not to bork the rights when trying to just edit part of the
* file.
*/ */
function SyncAccess(){ function SyncAccess()
{
$authz_file = Pluf::f('idf_plugin_syncsvn_authz_file'); $authz_file = Pluf::f('idf_plugin_syncsvn_authz_file');
$access_owners = Pluf::f('idf_plugin_syncsvn_access_owners'); $access_owners = Pluf::f('idf_plugin_syncsvn_access_owners', 'rw');
$access_members = Pluf::f('idf_plugin_syncsvn_access_members'); $access_members = Pluf::f('idf_plugin_syncsvn_access_members', 'rw');
$access_all = Pluf::f('idf_plugin_syncsvn_access_all'); $access_extra = Pluf::f('idf_plugin_syncsvn_access_extra', 'r');
$access_all_pivate = Pluf::f('idf_plugin_syncsvn_access_all_pivate'); $access_public = Pluf::f('idf_plugin_syncsvn_access_public', 'r');
$access_public_priv = Pluf::f('idf_plugin_syncsvn_access_private', '');
$projects = Pluf::factory('IDF_Project')->getList(); if (!file_exists($authz_file) or !is_writable($authz_file)) {
return false;
$fcontent = ""; }
$fcontent = '';
// for each project foreach (Pluf::factory('IDF_Project')->getList() as $project) {
foreach($projects as $project){
$conf = new IDF_Conf(); $conf = new IDF_Conf();
$conf->setProject($project); $conf->setProject($project);
if ($conf->getVal('scm') != 'svn' or
if ($conf->getVal('scm', "") == "svn"){ strlen($conf->getVal('svn_remote_url')) > 0) {
continue;
}
$mem = $project->getMembershipData(); $mem = $project->getMembershipData();
$members = $mem['members'];
$owners = $mem['owners'];
// [shortname:/] // [shortname:/]
$fcontent .= "[".$project->shortname.":/]\n"; $fcontent .= '['.$project->shortname.':/]'."\n";
foreach ($mem['owners'] as $v) {
// login = rw $fcontent .= $v->login.' = '.$access_owners."\n";
foreach($owners as $v){
$fcontent .= $v->login." = ".$access_owners."\n";
} }
// login = rw foreach ($mem['members'] as $v) {
foreach($members as $v){ $fcontent .= $v->login.' = '.$access_members."\n";
$fcontent .= $v->login." = ".$access_members."\n";
} }
// access for all users // access for all users
if ($project->private == true){ if ($project->private == true) {
$fcontent .= "* = ".$access_all_pivate."\n"; foreach ($mem['authorized'] as $v) {
}else{ $fcontent .= $v->login.' = '.$access_extra."\n";
$fcontent .= "* = ".$access_all."\n"; }
$fcontent .= '* = '.$access_public_priv."\n";
} else {
$fcontent .= '* = '.$access_public."\n";
} }
$fcontent .= "\n"; $fcontent .= "\n";
} //end if SVN
} }
file_put_contents($authz_file, $fcontent, LOCK_EX); file_put_contents($authz_file, $fcontent, LOCK_EX);
return true;
return 0;
} }
} }
?>

View File

@ -38,4 +38,15 @@ $m['IDF_Review'] = array('relate_to' => array('IDF_Project', 'Pluf_User', 'IDF_T
$m['IDF_Review_Patch'] = array('relate_to' => array('IDF_Review', 'Pluf_User')); $m['IDF_Review_Patch'] = array('relate_to' => array('IDF_Review', 'Pluf_User'));
$m['IDF_Review_FileComment'] = array('relate_to' => array('IDF_Review_Patch', 'Pluf_User')); $m['IDF_Review_FileComment'] = array('relate_to' => array('IDF_Review_Patch', 'Pluf_User'));
# -- Standard plugins, they will run only if configured --
#
# Subversion synchronization
Pluf_Signal::connect('IDF_Project::membershipsUpdated',
array('IDF_Plugin_SyncSvn', 'entry'));
Pluf_Signal::connect('IDF_Project::created',
array('IDF_Plugin_SyncSvn', 'entry'));
Pluf_Signal::connect('Pluf_User::passwordUpdated',
array('IDF_Plugin_SyncSvn', 'entry'));
return $m; return $m;