Mercurial > hg > soundsoftware-site
changeset 304:6c56a595dc1c cannam-pre-20110113-merge
Merge from branch "feature_73"
author | Chris Cannam |
---|---|
date | Mon, 28 Mar 2011 17:32:56 +0100 |
parents | 93b4cfd3aaaa (current diff) defe55be97b9 (diff) |
children | f5a3d57f3d90 |
files | config/locales/en-GB.yml config/locales/en.yml config/routes.rb |
diffstat | 8 files changed, 338 insertions(+), 33 deletions(-) [+] |
line wrap: on
line diff
--- a/app/controllers/sys_controller.rb Mon Mar 28 17:30:04 2011 +0100 +++ b/app/controllers/sys_controller.rb Mon Mar 28 17:32:56 2011 +0100 @@ -55,6 +55,20 @@ render :nothing => true, :status => 404 end + def get_external_repo_url + project = Project.find(params[:id]) + if project.repository + repo = project.repository + if repo.is_external? + render :text => repo.external_url, :status => 200 + else + render :nothing => true, :status => 200 + end + end + rescue ActiveRecord::RecordNotFound + render :nothing => true, :status => 404 + end + def set_embedded_active project = Project.find(params[:id]) mods = project.enabled_modules
--- a/app/helpers/repositories_helper.rb Mon Mar 28 17:30:04 2011 +0100 +++ b/app/helpers/repositories_helper.rb Mon Mar 28 17:32:56 2011 +0100 @@ -145,12 +145,6 @@ send(method, form, repository) if repository.is_a?(Repository) && respond_to?(method) && method != 'repository_field_tags' end - - def ssamr_scm_update(repository) - check_box_tag('repository_scm', value = "1", checked = false, onchange => remote_function(:url => { :controller => 'repositories', :action => 'ssamr_edit', :id => @project }, :method => :get, :with => "Form.serialize(this.form)")) - - end - def scm_select_tag(repository) scm_options = [["--- #{l(:actionview_instancetag_blank_option)} ---", '']] Redmine::Scm::Base.all.each do |scm|
--- a/app/views/projects/settings/_repository.rhtml Mon Mar 28 17:30:04 2011 +0100 +++ b/app/views/projects/settings/_repository.rhtml Mon Mar 28 17:32:56 2011 +0100 @@ -10,17 +10,16 @@ <div class="box tabular"> +<p> +<% if @repository %> + <%= l(:text_settings_repo_explanation) %></ br> + <% if @repository.is_external %> + <p><%= l(:text_settings_repo_is_external) %></ br> + <% else %> + <p><%= l(:text_settings_repo_is_internal) %></ br> + <% end %> +</p> -<% if @repository %> - <% if @repository.is_external %> - <%= l(:text_settings_repo_is_external) %></ br> - <% else %> - <%= l(:text_settings_repo_is_internal) %></ br> -<% end %> - <% else %> - <%= l(:text_settings_repo_creation) %></ br> -<% end %> - @@ -28,16 +27,17 @@ <p> <%= label_tag('repository_is_external', l(:label_is_external_repository)) %> <%= check_box :repository, :is_external, :onclick => "toggle_ext_url()" %> - <%= l(:setting_external_repository) %> + <br/><em><%= l(:setting_external_repository) %></em> </p> <p> <%= label_tag('repository_external_url', l(:label_repository_external_url)) %> - <%= text_field :repository, :external_url, :disabled => true %> - <%= l(:setting_external_repository_url) %> + <%= text_field :repository, :external_url, :disabled => !(@repository and @repository.is_external) %> + <br/><em><%= l(:setting_external_repository_url) %></em> </p> +<p><%= l(:text_settings_repo_need_help) %></p> </div> @@ -48,4 +48,9 @@ </div> <%= submit_tag(l(:button_save), :onclick => remote_function(:url => { :controller => 'repositories', :action => 'edit', :id => @project }, :method => :get, :with => "Form.serialize(this.form)")) %> + +<% else %> + <%= l(:text_settings_repo_creation) %></ br> <% end %> + +<% end %>
--- a/config/locales/en.yml Mon Mar 28 17:30:04 2011 +0100 +++ b/config/locales/en.yml Mon Mar 28 17:32:56 2011 +0100 @@ -306,9 +306,9 @@ field_text: Text field field_visible: Visible - setting_external_repository: "In the case you wish to follow an external repository" - setting_external_repository_url: "The external repository URL" - label_repository_external_url: "External rep URL" + setting_external_repository: "Select this if the project's main repository is hosted somewhere else" + setting_external_repository_url: "The URL of the existing external repository. Must be publicly accessible without a password" + label_repository_external_url: "External repository URL" setting_tipoftheday_text: Tip of the Day setting_notifications_text: Notifications field_terms_and_conditions: 'Terms and Conditions:' @@ -634,7 +634,7 @@ label_not_contains: doesn't contain label_day_plural: days label_repository: Repository - label_is_external_repository: External? + label_is_external_repository: Track an external repository label_repository_plural: Repositories label_browse: Browse label_modification: "{{count}} change" @@ -918,7 +918,7 @@ text_enumeration_destroy_question: "{{count}} objects are assigned to this value." text_enumeration_category_reassign_to: 'Reassign them to this value:' text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/email.yml and restart the application to enable them." - text_repository_usernames_mapping: "Select or update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." + text_repository_usernames_mapping: "Select the project member associated with each username found in the repository log.\nUsers whose name or email matches that in the repository are mapped automatically." text_diff_truncated: '... This diff was truncated because it exceeds the maximum size that can be displayed.' text_custom_field_possible_values_info: 'One line for each value' text_wiki_page_destroy_question: "This page has {{descendants}} child page(s) and descendant(s). What do you want to do?" @@ -929,9 +929,11 @@ text_zoom_in: Zoom in text_zoom_out: Zoom out text_files_active_change: <br>Click the star to switch active status for a download on or off.<br>Active files will be shown more prominently in the download page. - text_settings_repo_creation: The repository for a project should be set up automatically within a few minutes of the project being created.<br>You should not have to adjust any settings here.<br>Please check again in ten minutes, and <a href="/projects/soundsoftware-site/wiki/Help">contact us</a> if there is any problem. - text_settings_repo_is_internal: The repository for this project is an internal Mercurial Repository, hosted by SoundSoftware.ac.uk. - text_settings_repo_is_external: You are tracking an external repository, with a mirror Mercurial repository hosted by SoundSoftware.ac.uk. + text_settings_repo_creation: <b>Creating repository...</b></p><p>The source code repository for a project will be set up automatically within a few minutes of the project being created.</p><p>Please check again in five minutes, and <a href="/projects/soundsoftware-site/wiki/Help">contact us</a> if there is any problem.</p><p>If you wish to use this project to track a repository that is already hosted somewhere else, please wait until the repository has been created here and then return to this settings page to configure it.</p><p>If you don't want a repository at all, go to the Modules tab and switch it off there. + text_settings_repo_explanation: <b>External repositories</b><p>Normally your project's primary repository will be the Mercurial repository hosted at this site.<p>However, if you already have your project hosted somewhere else, you can specify your existing external repository's URL here – then this site will track that repository in a read-only “mirror” copy. External Mercurial, git and Subversion repositories can be tracked. Note that you cannot switch to an external repository if you have already made any commits to the repository hosted here. + text_settings_repo_is_internal: Currently the repository hosted at this site is the primary repository for this project. + text_settings_repo_is_external: Currently the repository hosted at this site is a read-only copy of an external repository. + text_settings_repo_need_help: Please <a href="/projects/soundsoftware-site/wiki/Help">contact us</a> if you need help deciding how best to set this up.<br>We can also import complete revision history from other systems into a new primary repository for you if you wish.
--- a/config/routes.rb Mon Mar 28 17:30:04 2011 +0100 +++ b/config/routes.rb Mon Mar 28 17:32:56 2011 +0100 @@ -236,6 +236,7 @@ map.with_options :controller => 'sys' do |sys| sys.connect 'sys/projects.:format', :action => 'projects', :conditions => {:method => :get} sys.connect 'sys/projects/:id/repository.:format', :action => 'create_project_repository', :conditions => {:method => :post} + sys.connect 'sys/projects/:id/external-repository.:format', :action => 'get_external_repo_url', :conditions => {:method => :get} sys.connect 'sys/projects/:id/embedded.:format', :action => 'set_embedded_active', :conditions => { :method => :post } end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extra/soundsoftware/convert-external-repos.rb Mon Mar 28 17:32:56 2011 +0100 @@ -0,0 +1,173 @@ +#!/usr/bin/env ruby + +# == Synopsis +# +# convert-external-repos: Update local Mercurial mirrors of external repos, +# by running an external command for each project requiring an update. +# +# == Usage +# +# convert-external-repos [OPTIONS...] -s [DIR] -r [HOST] +# +# == Arguments (mandatory) +# +# -s, --scm-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 +# -c, --command=COMMAND use this command to update each external +# repository: command is called with the name +# of the project, the path to its repo, and +# its external repo url as its three args +# +# == 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( + ['--scm-dir', '-s', GetoptLong::REQUIRED_ARGUMENT], + ['--redmine-host', '-r', GetoptLong::REQUIRED_ARGUMENT], + ['--key', '-k', GetoptLong::REQUIRED_ARGUMENT], + ['--http-user', GetoptLong::REQUIRED_ARGUMENT], + ['--http-pass', GetoptLong::REQUIRED_ARGUMENT], + ['--command' , '-c', 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 '--scm-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 '--command'; $command = 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? or $command.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("\tproject repo directory '#{repos_path}' doesn't exist") + next + end + + system($command, project.identifier, repos_path, external_url) + +end +
--- a/extra/soundsoftware/reposman-soundsoftware.rb Mon Mar 28 17:30:04 2011 +0100 +++ b/extra/soundsoftware/reposman-soundsoftware.rb Mon Mar 28 17:32:56 2011 +0100 @@ -9,12 +9,12 @@ # reposman [OPTIONS...] -s [DIR] -r [HOST] # # Examples: -# reposman --svn-dir=/var/svn --redmine-host=redmine.example.net --scm subversion +# reposman --scm-dir=/var/svn --redmine-host=redmine.example.net --scm subversion # reposman -s /var/git -r redmine.example.net -u http://svn.example.net --scm git # # == Arguments (mandatory) # -# -s, --svn-dir=DIR use DIR as base directory for svn repositories +# -s, --scm-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 @@ -70,7 +70,7 @@ SUPPORTED_SCM = %w( Subversion Darcs Mercurial Bazaar Git Filesystem ) opts = GetoptLong.new( - ['--svn-dir', '-s', GetoptLong::REQUIRED_ARGUMENT], + ['--scm-dir', '-s', GetoptLong::REQUIRED_ARGUMENT], ['--redmine-host', '-r', GetoptLong::REQUIRED_ARGUMENT], ['--key', '-k', GetoptLong::REQUIRED_ARGUMENT], ['--owner', '-o', GetoptLong::REQUIRED_ARGUMENT], @@ -133,7 +133,7 @@ begin opts.each do |opt, arg| case opt - when '--svn-dir'; $repos_base = arg.dup + when '--scm-dir'; $repos_base = arg.dup when '--redmine-host'; $redmine_host = arg.dup when '--key'; $api_key = arg.dup when '--owner'; $svn_owner = arg.dup; $use_groupid = false; @@ -174,7 +174,7 @@ end unless File.directory?($repos_base) - log("directory '#{$repos_base}' doesn't exists", :exit => true) + log("directory '#{$repos_base}' doesn't exist", :exit => true) end begin @@ -184,7 +184,7 @@ end class Project < ActiveResource::Base - self.headers["User-agent"] = "Redmine repository manager/#{Version}" + self.headers["User-agent"] = "SoundSoftware repository manager/#{Version}" end log("querying Redmine for projects...", :level => 1); @@ -346,5 +346,14 @@ log("\trepository #{repos_path} created"); end + if project.respond_to?(:repository) and project.repository.is_external? + external_url = project.repository.external_url; + log("\tproject #{project.identifier} has external repository url #{external_url}"); + if !external_url.match(/^https?:/) + # wot about git, svn/svn+ssh, etc? should we just check for a scheme at all? + log("\tthis is not an http(s) url: ignoring"); + end + end + end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extra/soundsoftware/update-external-repo.sh Mon Mar 28 17:32:56 2011 +0100 @@ -0,0 +1,107 @@ +#!/bin/sh + +mirrordir="/var/mirror" +logfile="/var/www/test-cannam/log/update-external-repo.log" + +project="$1" +local_repo="$2" +remote_repo="$3" + +if [ -z "$project" ] || [ -z "$local_repo" ] || [ -z "$remote_repo" ]; then + echo "Usage: $0 <project> <local-repo-path> <remote-repo-url>" + exit 2 +fi + + # We need to handle different source repository types separately. + # + # The convert extension cannot convert directly from a remote git + # repo; we'd have to mirror to a local repo first. Incremental + # conversions do work though. The hg-git plugin will convert + # directly from remote repositories, but not via all schemes + # (e.g. https is not currently supported). It's probably easier to + # use git itself to clone locally and then convert or hg-git from + # there. + # + # 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! + # + # One other thing -- we can't actually tell the difference between + # the various SCM types based on URL alone. We have to try them + # (ideally in an order determined by a guess based on the URL) and + # see what happens. + +project_mirror="$mirrordir/$project" +mkdir -p "$project_mirror" +project_repo_mirror="$project_mirror/repo" + + # Some test URLs: + # + # http://aimc.googlecode.com/svn/trunk/ + # http://aimc.googlecode.com/svn/ + # http://vagar.org/git/flam + # https://github.com/wslihgt/IMMF0salience.git + # http://hg.breakfastquay.com/dssi-vst/ + # git://github.com/schacon/hg-git.git + # http://svn.drobilla.net/lad (externals!) + +# If we are importing from another distributed system, then our aim is +# to create either a Hg repo or a git repo at $project_mirror, which +# we can then pull from directly to the Hg repo at $local_repo (using +# hg-git, in the case of a git repo). + +# Importing from SVN, we should use hg convert directly to the target +# hg repo (or should we?) but keep a record of the last changeset ID +# we brought in, and test each time whether it matches the last +# changeset ID actually in the repo + +success="" + +if [ -d "$project_repo_mirror" ]; then + + # Repo mirror exists: update it + echo "$$: Mirror for project $project exists at $project_repo_mirror, updating" 1>&2 + + if [ -d "$project_repo_mirror/.hg" ]; then + hg --config extensions.convert= convert --datesort "$remote_repo" "$project_repo_mirror" && success=true + elif [ -d "$project_repo_mirror/.git" ]; then + ( cd "$project_repo_mirror" && git fetch "$remote_repo" ) && success=true + else + echo "$$: ERROR: Repo mirror dir $project_repo_mirror exists but is not an Hg or git repo" 1>&2 + fi + +else + + # Repo mirror does not exist yet + echo "$$: Mirror for project $project does not yet exist at $project_repo_mirror, trying to convert or clone" 1>&2 + + case "$remote_repo" in + *git*) + git clone "$remote_repo" "$project_repo_mirror" || + hg --config extensions.convert= convert --datesort "$remote_repo" "$project_repo_mirror" + ;; + *) + hg --config extensions.convert= convert --datesort "$remote_repo" "$project_repo_mirror" || + git clone "$remote_repo" "$project_repo_mirror" || + hg clone "$remote_repo" "$project_repo_mirror" + ;; + esac && success=true + +fi + +echo "Success=$success" + +if [ -n "$success" ]; then + echo "$$: Update successful, pulling into local repo at $local_repo" + if [ -d "$project_repo_mirror/.git" ]; then + if [ ! -d "$local_repo" ]; then + hg init "$local_repo" + fi + ( cd "$local_repo" && hg --config extensions.hgext.git= pull "$project_repo_mirror" ) + else + ( cd "$local_repo" && hg pull "$project_repo_mirror" ) + fi +fi