Mercurial > hg > soundsoftware-site
diff extra/soundsoftware/convert-external-repos.rb @ 217:ed8222a04634 feature_73
* Start on external repo conversion script
author | Chris Cannam <chris.cannam@soundsoftware.ac.uk> |
---|---|
date | Fri, 11 Feb 2011 15:32:41 +0000 |
parents | |
children | 7658d21a1493 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extra/soundsoftware/convert-external-repos.rb Fri Feb 11 15:32:41 2011 +0000 @@ -0,0 +1,183 @@ +#!/usr/bin/env ruby + +# == Synopsis +# +# convert-external-repos: Update local Mercurial mirrors of external repos +# +# This command is specific to the SoundSoftware Redmine instance and +# its use of Mercurial repositories. It makes use of the hg convert extension. +# +# == Usage +# +# convert-external-repos [OPTIONS...] -s [DIR] -r [HOST] +# +# == Arguments (mandatory) +# +# -h, --hg-dir=DIR use DIR as base directory for repositories +# -r, --redmine-host=HOST assume Redmine is hosted on HOST. Examples: +# -r redmine.example.net +# -r http://redmine.example.net +# -r https://example.net/redmine +# -k, --key=KEY use KEY as the Redmine API key +# +# == Options +# +# --http-user=USER User for HTTP Basic authentication with Redmine WS +# --http-pass=PASSWORD Password for Basic authentication with Redmine WS +# -t, --test only show what should be done +# -h, --help show help and exit +# -v, --verbose verbose +# -V, --version print version and exit +# -q, --quiet no log + + +require 'getoptlong' +require 'rdoc/usage' +require 'find' +require 'etc' + +Version = "1.0" + +opts = GetoptLong.new( + ['--hg-dir', '-h', GetoptLong::REQUIRED_ARGUMENT], + ['--redmine-host', '-r', GetoptLong::REQUIRED_ARGUMENT], + ['--key', '-k', GetoptLong::REQUIRED_ARGUMENT], + ['--http-user', GetoptLong::REQUIRED_ARGUMENT], + ['--http-pass', GetoptLong::REQUIRED_ARGUMENT], + ['--test', '-t', GetoptLong::NO_ARGUMENT], + ['--verbose', '-v', GetoptLong::NO_ARGUMENT], + ['--version', '-V', GetoptLong::NO_ARGUMENT], + ['--help' , '-h', GetoptLong::NO_ARGUMENT], + ['--quiet' , '-q', GetoptLong::NO_ARGUMENT] + ) + +$verbose = 0 +$quiet = false +$redmine_host = '' +$repos_base = '' +$http_user = '' +$http_pass = '' +$test = false + +def log(text, options={}) + level = options[:level] || 0 + puts text unless $quiet or level > $verbose + exit 1 if options[:exit] +end + +def system_or_raise(command) + raise "\"#{command}\" failed" unless system command +end + +begin + opts.each do |opt, arg| + case opt + when '--hg-dir'; $repos_base = arg.dup + when '--redmine-host'; $redmine_host = arg.dup + when '--key'; $api_key = arg.dup + when '--http-user'; $http_user = arg.dup + when '--http-pass'; $http_pass = arg.dup + when '--verbose'; $verbose += 1 + when '--test'; $test = true + when '--version'; puts Version; exit + when '--help'; RDoc::usage + when '--quiet'; $quiet = true + end + end +rescue + exit 1 +end + +if $test + log("running in test mode") +end + +if ($redmine_host.empty? or $repos_base.empty?) + RDoc::usage +end + +unless File.directory?($repos_base) + log("directory '#{$repos_base}' doesn't exist", :exit => true) +end + +begin + require 'active_resource' +rescue LoadError + log("This script requires activeresource.\nRun 'gem install activeresource' to install it.", :exit => true) +end + +class Project < ActiveResource::Base + self.headers["User-agent"] = "SoundSoftware external repository converter/#{Version}" +end + +log("querying Redmine for projects...", :level => 1); + +$redmine_host.gsub!(/^/, "http://") unless $redmine_host.match("^https?://") +$redmine_host.gsub!(/\/$/, '') + +Project.site = "#{$redmine_host}/sys"; +Project.user = $http_user; +Project.password = $http_pass; + +begin + # Get all active projects that have the Repository module enabled + projects = Project.find(:all, :params => {:key => $api_key}) +rescue => e + log("Unable to connect to #{Project.site}: #{e}", :exit => true) +end + +if projects.nil? + log('no project found, perhaps you forgot to "Enable WS for repository management"', :exit => true) +end + +log("retrieved #{projects.size} projects", :level => 1) + +projects.each do |project| + log("treating project #{project.name}", :level => 1) + + if project.identifier.empty? + log("\tno identifier for project #{project.name}") + next + elsif not project.identifier.match(/^[a-z0-9\-]+$/) + log("\tinvalid identifier for project #{project.name} : #{project.identifier}"); + next + end + + if !project.respond_to?(:repository) or !project.repository.is_external? + log("\tproject #{project.identifier} does not use an external repository"); + next + end + + external_url = project.repository.external_url; + log("\tproject #{project.identifier} has external repository url #{external_url}"); + + if !external_url.match(/^[a-z][a-z+]{0,8}[a-z]:\/\//) + log("\tthis doesn't look like a plausible url to me, skipping") + next + end + + repos_path = File.join($repos_base, project.identifier).gsub(File::SEPARATOR, File::ALT_SEPARATOR || File::SEPARATOR) + + unless File.directory?($repos_path) + log("project repo directory '#{$repos_path}' doesn't exist") + next + end + + # We need to handle different source repository types separately. + # + # The convert extension cannot convert directly from a remote git + # repo; we have to mirror to a local repo first. Incremental + # conversions do work though. + # + # We can of course convert directly from remote Subversion repos, + # but we need to keep track of that -- you can ask to convert into a + # repo that has already been used (for Mercurial) and it'll do so + # happily; we don't want that. + # + # Converting from a remote Hg repo should be fine! + # + + + +end +