Skip to content
Snippets Groups Projects
Commit eb65cc85 authored by Andreas Åkre Solberg's avatar Andreas Åkre Solberg
Browse files

add module.php CLI to install modules

git-svn-id: https://simplesamlphp.googlecode.com/svn/trunk@2219 44740490-163a-0410-bde0-09ae8108e29a
parent 629acc49
No related branches found
No related tags found
No related merge requests found
#!/usr/bin/env php
<?php
/* This is the base directory of the simpleSAMLphp installation. */
$baseDir = dirname(dirname(__FILE__));
/* Add library autoloader. */
require_once($baseDir . '/lib/_autoload.php');
if (count($argv) < 1) {
echo "Wrong number of parameters. Run: " . $argv[0] . " [install,show] url [branch]\n"; exit;
}
// Needed in order to make session_start to be called before output is printed.
$session = SimpleSAML_Session::getInstance();
$config = SimpleSAML_Configuration::getConfig('config.php');
$action = $argv[1];
function getModinfo() {
global $argv;
if (count($argv) < 2)
throw new Exception('Missing second parameter: URL/ID');
return sspmod_core_ModuleDefinition::load($argv[2]);
}
function getBranch() {
global $argv;
if (isset($argv[3])) return $argv[3];
return NULL;
}
switch($action) {
case 'install':
$mod = getModinfo();
$installer = new sspmod_core_ModuleInstaller($mod);
$installer->install(getBranch());
break;
case 'remove':
$mod = getModinfo();
$installer = new sspmod_core_ModuleInstaller($mod);
$installer->remove(getBranch());
break;
case 'upgrade':
$mod = getModinfo();
$installer = new sspmod_core_ModuleInstaller($mod);
$installer->upgrade(getBranch());
break;
case 'upgrade-all' :
$mdir = scandir($config->getBaseDir() . 'modules/');
foreach($mdir AS $md) {
if (!sspmod_core_ModuleDefinition::validId($md)) continue;
if (!sspmod_core_ModuleDefinition::isDefined($md)) continue;
$moduledef = sspmod_core_ModuleDefinition::load($md, 'remote');
$installer = new sspmod_core_ModuleInstaller($moduledef);
if ($moduledef->updateExists() || $moduledef->alwaysUpdate()) {
echo "Upgrading [" . $md . "]\n";
$installer->upgrade();
} else {
echo "No updates available for [" . $md . "]\n";
}
}
break;
default:
throw new Exception('Unknown action [' . $action . ']');
}
<?php
class sspmod_core_ModuleDefinition {
public $def;
private static $cache;
private function __construct($def) {
$this->def = $def;
$this->requireValidIdentifier();
}
public static function validId($id) {
return preg_match('|^[a-zA-Z_]+$|', $id);
}
public static function isDefined($id) {
$config = SimpleSAML_Configuration::getConfig('config.php');
$basedir = $config->getBaseDir();
$filename = $basedir . 'modules/' . $id . '/definition.json';
return (file_exists($filename));
}
public static function load($id, $force = NULL) {
if (isset($cache[$id])) return $cache[$id];
if (self::validId($id)) {
$config = SimpleSAML_Configuration::getConfig('config.php');
$basedir = $config->getBaseDir();
$filename = $basedir . 'modules/' . $id . '/definition.json';
if (!file_exists($filename))
throw new Exception('Could not read definition file for module [' . $id . '] : ' . $filename);
$defraw = file_get_contents($filename);
$def = json_decode($defraw, TRUE);
} elseif(preg_match('|^http(s)?://.*$|', $id)) {
$defraw = file_get_contents($id);
$def = json_decode($defraw, TRUE);
} else {
throw new Exception('Could not resolve [' . $id . '] as URL nor module identifier.');
}
$cache[$id] = new sspmod_core_ModuleDefinition($def);
if (isset($force)) {
if ($force === 'local') {
if(preg_match('|^http(s)?://.*$|', $id)) {
return self::load($def['id']);
}
} elseif($force === 'remote') {
if (self::validId($id)) {
if (!isset($def['definition']))
throw new Exception('Could not load remote definition file for module [' . $id . ']');
return self::load($def['definition']);
}
}
}
return $cache[$id];
}
private function requireValidIdentifier() {
if (!isset($this->def['id']))
throw new Exception('Missing [id] value in module definition');
if (!preg_match('|^[a-zA-Z_]+$|', $this->def['id']))
throw new Exception('Illegal characters in [id] in module definition');
}
public function getVersion($branch = NULL) {
if (!isset($this->def['access'])) throw new Exception('Missing [access] statement in module definition');
if (!isset($this->def['branch'])) throw new Exception('Missing [branch] statement in module definition');
if (is_null($branch)) $branch = $this->def['branch'];
if (!isset($this->def['access'][$branch])) throw new Exception('Missing [access] information for branch [' . var_export($branch, TRUE) . ']');
if (!isset($this->def['access'][$branch]['version'])) throw new Exception('Missing version information in [access] in branch [' . var_export($branch, TRUE) . ']');
return $this->def['access'][$branch]['version'];
}
public function alwaysUpdate($branch = NULL) {
$access = $this->getAccess($branch);
if ($access['type'] === 'svn') return TRUE;
return FALSE;
}
public function getBranch($branch = NULL) {
if (!isset($this->def['branch'])) throw new Exception('Missing [branch] statement in module definition');
if (is_null($branch)) $branch = $this->def['branch'];
return $branch;
}
public function updateExists($branch = NULL) {
$branch = $this->getBranch($branch);
$localDef = self::load($this->def['id'], 'local');
$thisVersion = $localDef->getVersion($branch);
$remoteDef = self::load($this->def['definition'], 'remote');
$remoteVersion = $remoteDef->getVersion($branch);
#echo ' Comparing versions local [' . $thisVersion . '] and remote [' . $remoteVersion . ']' . "\n";
return version_compare($remoteVersion, $thisVersion, '>');
}
public function getAccess($branch = NULL) {
if (!isset($this->def['access'])) throw new Exception('Missing [access] statement in module definition');
if (!isset($this->def['branch'])) throw new Exception('Missing [branch] statement in module definition');
if (is_null($branch)) $branch = $this->def['branch'];
if (!isset($this->def['access'][$branch])) throw new Exception('Missing [access] information for branch [' . var_export($branch, TRUE) . ']');
return $this->def['access'][$branch];
}
}
\ No newline at end of file
<?php
class sspmod_core_ModuleInstaller {
public $module;
public function __construct(sspmod_core_ModuleDefinition $module) {
$this->module = $module;
}
public function remove($branch = NULL) {
$access = $this->module->getAccess($branch);
switch($access['type']) {
// case 'svn' :
// $this->requireInstalled();
// $this->remove($access);
// break;
default:
$this->requireInstalled();
$this->removeModuleDir($access);
break;
}
}
public function install($branch = NULL) {
$access = $this->module->getAccess($branch);
switch($access['type']) {
case 'svn' :
$this->requireNotInstalled();
$this->svnCheckout($access);
$this->enable();
$this->prepareConfig();
break;
case 'zip' :
$this->requireNotInstalled();
$this->zipLoad($access);
$this->enable();
$this->prepareConfig();
break;
default:
throw new Exception('Unknown access method type. Not one of [zip,tgz,svn]');
}
}
public static function exec($cmd) {
echo ' $ ' . $cmd . "\n";
$output = shell_exec(escapeshellcmd($cmd));
if (empty($output)) return;
$oa = explode("\n", $output);
foreach($oa AS $ol) {
echo ' > ' . $ol . "\n";
}
}
public function upgrade($branch = NULL) {
$access = $this->module->getAccess($branch);
switch($access['type']) {
case 'svn' :
$this->requireInstalled();
$this->svnUpdate($access);
$this->enable();
$this->prepareConfig();
break;
case 'zip' :
$this->requireInstalled();
$this->zipLoad($access);
$this->enable();
$this->prepareConfig();
break;
default:
throw new Exception('Unknown access method type. Not one of [zip,tgz,svn]');
}
}
public function dirExists() {
$config = SimpleSAML_Configuration::getConfig('config.php');
$basedir = $config->getBaseDir();
$dir = $basedir . 'modules/' . $this->module->def['id'];
return (file_exists($dir) && is_dir($dir));
}
public function requireValidURL($url) {
if (!preg_match('|http(s)?://[a-zA-Z0-9_-/.]|', $url))
throw new Exception('Invalid URL [' . $url . ']');
}
public function requireNotInstalled() {
if ($this->dirExists())
throw new Exception('The module [' . $this->module->def['id'] . '] is already installed.');
}
public function requireInstalled() {
if (!$this->dirExists())
throw new Exception('The module [' . $this->module->def['id'] . '] is not installed.');
}
public function svnCheckout($access) {
$config = SimpleSAML_Configuration::getConfig('config.php');
$basedir = $config->getBaseDir();
$cmd = "svn co " . escapeshellarg($access['url']) . " " . $basedir . "modules/" . $this->module->def['id'];
self::exec($cmd);
}
public function svnUpdate($access) {
$config = SimpleSAML_Configuration::getConfig('config.php');
$basedir = $config->getBaseDir();
$cmd = "svn up " . $basedir . "modules/" . $this->module->def['id'];
self::exec($cmd);
}
public function removeModuleDir($access) {
$config = SimpleSAML_Configuration::getConfig('config.php');
$basedir = $config->getBaseDir();
$cmd = "rm -rf " . $basedir . "modules/" . $this->module->def['id'];
self::exec($cmd);
}
public function enable() {
$config = SimpleSAML_Configuration::getConfig('config.php');
$basedir = $config->getBaseDir();
$this->requireInstalled();
$cmd = "touch " . $basedir . "modules/" . $this->module->def['id'] . '/enable';
self::exec($cmd);
}
public function prepareConfig() {
$config = SimpleSAML_Configuration::getConfig('config.php');
$basedir = $config->getBaseDir();
$this->requireInstalled();
$dir = $basedir . "modules/" . $this->module->def['id'] . '/config-templates';
if (!file_exists($dir)) return;
$files = scandir($dir);
foreach($files AS $file) {
if(!preg_match('|^.*\.php|', $file)) continue;
if (file_exists($basedir . 'config/' . $file)) {
echo "Configuration file [" . $file . "] already exists. Will not overwrite existing file.\n";
continue;
}
$cmd = 'cp ' . $dir . '/' . $file . ' ' . $basedir . 'config/';
self::exec($cmd);
}
}
public function zipLoad($access) {
$config = SimpleSAML_Configuration::getConfig('config.php');
$basedir = $config->getBaseDir();
$zipfile = $access['url'];
$localfile = tempnam(sys_get_temp_dir(), 'ssp-module-');
$filecontents = file_get_contents($zipfile);
file_put_contents($localfile, $filecontents);
$cmd = "unzip -qo " . escapeshellarg($localfile) . " -d " . $basedir . "modules/";
self::exec($cmd);
}
}
\ No newline at end of file
...@@ -13,5 +13,15 @@ ...@@ -13,5 +13,15 @@
}, },
"modlist_disabled": { "modlist_disabled": {
"en": "Disabled" "en": "Disabled"
},
"latest_version" : {
"en" : "Updated"
},
"update_exists" : {
"en" : "Update available"
},
"version" : {
"en" : "Version"
} }
} }
\ No newline at end of file
...@@ -10,15 +10,29 @@ $this->includeAtTemplateBase('includes/header.php'); ...@@ -10,15 +10,29 @@ $this->includeAtTemplateBase('includes/header.php');
<h2><?php echo($this->data['header']); ?></h2> <h2><?php echo($this->data['header']); ?></h2>
<table> <table class="modules" style="width: 100%">
<tr> <tr>
<th><?php echo($this->t('{modinfo:modinfo:modlist_name}')); ?></th> <th colspan="2"><?php echo($this->t('{modinfo:modinfo:modlist_name}')); ?></th>
<th><?php echo($this->t('{modinfo:modinfo:modlist_status}')); ?></th> <th ><?php echo($this->t('{modinfo:modinfo:modlist_status}')); ?></th>
<th colspan="2"><?php echo($this->t('{modinfo:modinfo:version}')); ?></th>
</tr> </tr>
<?php <?php
$i = 0;
foreach($this->data['modules'] as $id => $info) { foreach($this->data['modules'] as $id => $info) {
echo('<tr>'); echo('<tr class="' . ($i++ % 2 == 0 ? 'odd' : 'even') . '">');
echo('<td>' . htmlspecialchars($id) . '</td>');
if (isset($info['def'])) {
echo('<td><a href="http://simplesamlphp.org/modules/' . htmlspecialchars($id) . '">' . htmlspecialchars($info['def']->def['name']) . '</a></td>');
} else {
echo('<td> </td>');
}
echo('<td><tt>' . htmlspecialchars($id) . '</tt></td>');
if($info['enabled']) { if($info['enabled']) {
echo('<td><img src="/' . $this->data['baseurlpath'] . 'resources/icons/silk/accept.png" alt="' . echo('<td><img src="/' . $this->data['baseurlpath'] . 'resources/icons/silk/accept.png" alt="' .
htmlspecialchars($this->t('{modinfo:modinfo:modlist_enabled}')) . '" /></td>'); htmlspecialchars($this->t('{modinfo:modinfo:modlist_enabled}')) . '" /></td>');
...@@ -26,6 +40,22 @@ foreach($this->data['modules'] as $id => $info) { ...@@ -26,6 +40,22 @@ foreach($this->data['modules'] as $id => $info) {
echo('<td><img src="/' . $this->data['baseurlpath'] . 'resources/icons/silk/delete.png" alt="' . echo('<td><img src="/' . $this->data['baseurlpath'] . 'resources/icons/silk/delete.png" alt="' .
htmlspecialchars($this->t('{modinfo:modinfo:modlist_disabled}')) . '" /></td>'); htmlspecialchars($this->t('{modinfo:modinfo:modlist_disabled}')) . '" /></td>');
} }
if (isset($info['def'])) {
echo('<td>' . htmlspecialchars($info['def']->getVersion()) . ' (' .htmlspecialchars($info['def']->getBranch()) . ')</td>');
if ($info['def']->updateExists()) {
echo('<td><img style="display: inline" src="/' . $this->data['baseurlpath'] . 'resources/icons/silk/delete.png" alt="' .
htmlspecialchars($this->t('{modinfo:modinfo:update_exists}')) . '" /> ' .
htmlspecialchars($this->t('{modinfo:modinfo:update_exists}')) . '</td>');
} else {
echo('<td><img style="display: inline" src="/' . $this->data['baseurlpath'] . 'resources/icons/silk/accept.png" alt="' .
htmlspecialchars($this->t('{modinfo:modinfo:latest_version}')) . '" /> ' .
htmlspecialchars($this->t('{modinfo:modinfo:latest_version}')) . '</td>');
}
} else {
echo('<td colspan="2"> </td>');
}
echo('</tr>'); echo('</tr>');
} }
?> ?>
......
...@@ -9,7 +9,19 @@ foreach($modules as $m) { ...@@ -9,7 +9,19 @@ foreach($modules as $m) {
$modinfo[$m] = array( $modinfo[$m] = array(
'enabled' => SimpleSAML_Module::isModuleEnabled($m), 'enabled' => SimpleSAML_Module::isModuleEnabled($m),
); );
if (sspmod_core_ModuleDefinition::isDefined($m)) {
$modinfo[$m]['def'] = sspmod_core_ModuleDefinition::load($m);
}
}
function cmpa($a, $b) {
if (isset($a['def']) && !isset($b['def'])) return -1;
if (isset($b['def']) && !isset($a['def'])) return 1;
return 0;
} }
uasort($modinfo, 'cmpa');
$config = SimpleSAML_Configuration::getInstance(); $config = SimpleSAML_Configuration::getInstance();
$t = new SimpleSAML_XHTML_Template($config, 'modinfo:modlist.php'); $t = new SimpleSAML_XHTML_Template($config, 'modinfo:modlist.php');
......
...@@ -276,6 +276,15 @@ div.preferredidp { ...@@ -276,6 +276,15 @@ div.preferredidp {
padding: 2px 2em 2px 2em; padding: 2px 2em 2px 2em;
} }
table.modules {
border-collapse: collapse;
}
table.modules tr td {
border-bottom: 1px solid #ddd;
}
table.modules tr.even td {
background: #f0f0f0;
}
/* Attribute presentation in example page */ /* Attribute presentation in example page */
table.attributes { table.attributes {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment