diff --git a/scripts/release-manifest.php b/scripts/release-manifest.php new file mode 100755 index 0000000..5c2a245 --- /dev/null +++ b/scripts/release-manifest.php @@ -0,0 +1,263 @@ +#!/usr/bin/env php + 'http://tarballs.openstack.org/groups/7.x', + 'debug' => FALSE, + 'verbose' => FALSE, + 'outfile' => 'manifest.xml', + 'help' => FALSE, +); + +// command line argument schema definition +$arg_schema = array( + 'version' => array( + '#required' => TRUE, + '#description' => 'release version (7.x-N.N or 7.x-N.x-dev)', + ), + 'md5' => array( + '#required' => TRUE, + '#description' => 'basename of release tar.gz file (eg. groups-N.N.tar.gz)', + ), + 'releasetar' => array( + '#required' => TRUE, + '#description' => 'md5 hash of release tar.gz file', + ), + 'debug' => array( + '#required' => FALSE, + '#description' => 'enable debug messages, defaults to FALSE', + ), + 'verbose' => array( + '#required' => FALSE, + '#description' => 'enable verbouse output, defaults to FALSE', + ), + 'manifest-url' => array( + '#required' => FALSE, + '#description' => 'url of original manifest file', + ), + 'outfile' => array( + '#required' => FALSE, + '#description' => 'write manifest to this file, defaults to manifest.xml', + ), + 'help' => array( + '#required' => FALSE, + '#description' => 'Show the help', + ), +); + +// manifest template +$manifest_template = ' + + Groups Portal + groups + project_distribution + 7.x + 0 + 0 + 0 + published + https://drupal.org/project/groups + + + Projects + Distributions + + + + +'; + +// log level constants +define('_LOG_DEBUG_', 'DEBUG'); +define('_LOG_INFO_', 'INFO'); +define('_LOG_ERROR_', 'ERROR'); + +/** + * Write a log message depending on configuration settings. + * + * @param string $type log level (debug, info, error) + * @param string $message log message + */ +function write_log($type, $message) { + global $config; + if (($type == 'DEBUG') && ($config['debug'] == FALSE)) { + // skip if debug mode disabled + return; + } + if (($type == 'INFO') && ($config['verbose'] == FALSE)) { + // skip if verbose disabled + return; + } + echo sprintf("%s [%s] %s\n", date('c'), $type, $message); +} + +/** + * Validate and decode a Drupal format version string + * into a key-value array. + * + * 7.x-1.0 converted to: + * array( + * 'major' => 1, + * 'patch' => 0, + * ) + * + * 7.x-1.x-dev converted to: + * array( + * 'major' => 1, + * 'extra' => 'dev', + * ) + * + * @param string $version version string + * @return array decoded version as key value array + */ +function match_version($version) { + $pattern = '/^7.x-(?P\d+).((?P\d+)|x-(?Pdev))$/'; + $matches = array(); + if (preg_match($pattern, $version, $matches)) { + foreach ($matches as $key => $value) { + if ((is_int($key)) || ($value == NULL)) { + unset($matches[$key]); + } + } + } else { + throw new Exception(sprintf('Invalid version number format: %s', $version)); + } + return $matches; +} + +/** + * Insert or update a release element in project xml. + * + * @param class $xml project xml as a simplexml object. + * @param string $version release version + * @param string $releaseTar basename of release tar.gz file + * @param string $md5 md5 hash of release tar.gz file + * @param string $fileSize file size of release (optional) + * @param string $releaseDate release date of the release (optional) + */ +function append_release($xml, $version, $releaseTar, $md5, $fileSize = NULL, $releaseDate = NULL) { + $downloadUrl = 'http://tarballs.openstack.org/groups/'.$releaseTar; + // remove previous release entry with same version + list($element) = $xml->xpath('/project/releases/release/version[. = "'.$version.'"]/parent::*'); + if (!empty($element)) { + unset($element[0]); + $verb = 'Override'; + } else { + $verb = 'Insert'; + } + write_log(_LOG_INFO_, sprintf('%s a release element [version=%s, releaseTar=%s, md5=%s]', + $verb, $version, $releaseTar, $md5)); + // add release elements + $release = $xml->releases->addChild('release'); + $release->addChild('name', 'groups '.$version); + $release->addChild('version', $version); + $release->addChild('tag', $version); + $release->addChild('status', 'published'); + $release->addChild('download_link', $downloadUrl); + $release->addChild('mdhash', $md5); + // append version + $v = match_version($version); + if (empty($v)) { + throw new Exception('Invalid version format.'); + } + foreach ($v as $key => $value) { + $release->addChild('version_'.$key, $value); + } + $files = $release->addChild('files'); + $file = $files->addChild('file'); + $file->addChild('url', $downloadUrl); + $file->addChild('archive_type', 'tar.gz'); + $file->addChild('variant', 'full'); + $file->addChild('md5', $md5); +} + +/** + * Show the help and construct parameter list by + * argument schema. + * + * @param array $arg_schema argument schema + */ +function print_help($arg_schema) { + echo "Generate Drupal manifest file to represent a project release history.\n\n"; + echo "Example:\n"; + echo " release-manifest.php --version=7.x-1.0 --releasetar=groups-1.0.tar.gz --md5=c59611415cea4bc6397b1351b2b36b7c\n\n"; + echo "Options:\n"; + foreach ($arg_schema as $key => $value) { + echo sprintf(" --%-16s %s\n", $key, $value['#description']); + } + echo "\n"; +} + +/** + * Parse and validate command line parameters based on + * predefined argument schema. + * + * @param array $argv command line arguments + * @param array $arg_schema argument schema + * @return array parsed parameters + */ +function get_cli_parameters($argv, $arg_schema) { + $params = array(); + // parse cli arguments + foreach ($argv as $arg) { + if (strpos($arg, '--') !== false) { + list($key, $value) = explode("=",$arg); + $key = substr($key, 2); + if (isset($arg_schema[$key]) == FALSE) { + print_help($arg_schema); + throw new Exception(sprintf('Invalid command line argument: %s', $key)); + } + if (isset($key)) { + $params[$key] = isset($value) ? $value : TRUE; + } + } + } + if (empty($params['help'])) { + // check required parameters + foreach ($arg_schema as $key => $value) { + if (($value['#required']) && (empty($params[$key]))) { + print_help($arg_schema); + throw new Exception(sprintf('Mandatory parameter %s missing.', $key)); + } + } + } + return $params; +} + +try { + // parse cli arguments and merge with config + $params = get_cli_parameters($argv, $arg_schema); + $config = array_replace($config, $params); + if ($config['help']) { + print_help($arg_schema); + exit(0); + } + if ($config['debug']) { + write_log(_LOG_DEBUG_, 'Command line args:'); + foreach ($config as $key => $value) { + write_log(_LOG_DEBUG_, sprintf(' %-16s = %s', $key, (string)$value)); + } + } + // load original manifest + $xml = @simplexml_load_file($config['manifest-url']); + if (!$xml) { + write_log(_LOG_INFO_, 'Create a new manifest file, failed to fetch from remote url.'); + $xml = simplexml_load_string($manifest_template); + } + append_release($xml, $params['version'], $params['releasetar'], $params['md5']); + $xml_content = $xml->asXML(); + write_log(_LOG_DEBUG_, sprintf("Generated manifest:\n %s", $xml_content)); + file_put_contents($config['outfile'], $xml_content); +} catch (Exception $e) { + write_log(_LOG_ERROR_, $e->getMessage()); + exit(1); +} \ No newline at end of file