Revision 2435
Added by Jean-Philippe Lang over 16 years ago
trunk/app/apis/sys_api.rb | ||
---|---|---|
1 |
# redMine - project management software |
|
2 |
# Copyright (C) 2006-2007 Jean-Philippe Lang |
|
3 |
# |
|
4 |
# This program is free software; you can redistribute it and/or |
|
5 |
# modify it under the terms of the GNU General Public License |
|
6 |
# as published by the Free Software Foundation; either version 2 |
|
7 |
# of the License, or (at your option) any later version. |
|
8 |
# |
|
9 |
# This program is distributed in the hope that it will be useful, |
|
10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 |
# GNU General Public License for more details. |
|
13 |
# |
|
14 |
# You should have received a copy of the GNU General Public License |
|
15 |
# along with this program; if not, write to the Free Software |
|
16 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
17 |
|
|
18 |
class AWSProjectWithRepository < ActionWebService::Struct |
|
19 |
member :id, :int |
|
20 |
member :identifier, :string |
|
21 |
member :name, :string |
|
22 |
member :is_public, :bool |
|
23 |
member :repository, Repository |
|
24 |
end |
|
25 |
|
|
26 |
class SysApi < ActionWebService::API::Base |
|
27 |
api_method :projects_with_repository_enabled, |
|
28 |
:expects => [], |
|
29 |
:returns => [[AWSProjectWithRepository]] |
|
30 |
api_method :repository_created, |
|
31 |
:expects => [:string, :string, :string], |
|
32 |
:returns => [:int] |
|
33 |
end |
|
34 | 0 |
trunk/app/controllers/sys_controller.rb | ||
---|---|---|
1 |
# redMine - project management software
|
|
2 |
# Copyright (C) 2006-2007 Jean-Philippe Lang
|
|
1 |
# Redmine - project management software
|
|
2 |
# Copyright (C) 2006-2009 Jean-Philippe Lang
|
|
3 | 3 |
# |
4 | 4 |
# This program is free software; you can redistribute it and/or |
5 | 5 |
# modify it under the terms of the GNU General Public License |
... | ... | |
16 | 16 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
17 | 17 |
|
18 | 18 |
class SysController < ActionController::Base |
19 |
wsdl_service_name 'Sys' |
|
20 |
web_service_api SysApi |
|
21 |
web_service_scaffold :invoke |
|
19 |
before_filter :check_enabled |
|
22 | 20 |
|
23 |
before_invocation :check_enabled |
|
21 |
def projects |
|
22 |
p = Project.active.has_module(:repository).find(:all, :include => :repository, :order => 'identifier') |
|
23 |
render :xml => p.to_xml(:include => :repository) |
|
24 |
end |
|
24 | 25 |
|
25 |
# Returns the projects list, with their repositories |
|
26 |
def projects_with_repository_enabled |
|
27 |
Project.has_module(:repository).find(:all, :include => :repository, :order => 'identifier') |
|
26 |
def create_project_repository |
|
27 |
project = Project.find(params[:id]) |
|
28 |
if project.repository |
|
29 |
render :nothing => true, :status => 409 |
|
30 |
else |
|
31 |
logger.info "Repository for #{project.name} was reported to be created by #{request.remote_ip}." |
|
32 |
project.repository = Repository.factory(params[:vendor], params[:repository]) |
|
33 |
if project.repository && project.repository.save |
|
34 |
render :xml => project.repository, :status => 201 |
|
35 |
else |
|
36 |
render :nothing => true, :status => 422 |
|
37 |
end |
|
38 |
end |
|
28 | 39 |
end |
29 | 40 |
|
30 |
# Registers a repository for the given project identifier |
|
31 |
def repository_created(identifier, vendor, url) |
|
32 |
project = Project.find_by_identifier(identifier) |
|
33 |
# Do not create the repository if the project has already one |
|
34 |
return 0 unless project && project.repository.nil? |
|
35 |
logger.debug "Repository for #{project.name} was created" |
|
36 |
repository = Repository.factory(vendor, :project => project, :url => url) |
|
37 |
repository.save |
|
38 |
repository.id || 0 |
|
39 |
end |
|
41 |
protected |
|
40 | 42 |
|
41 |
protected |
|
42 |
|
|
43 |
def check_enabled(name, args) |
|
44 |
Setting.sys_api_enabled? |
|
43 |
def check_enabled |
|
44 |
User.current = nil |
|
45 |
unless Setting.sys_api_enabled? |
|
46 |
render :nothing => 'Access denied. Repository management WS is disabled.', :status => 403 |
|
47 |
return false |
|
48 |
end |
|
45 | 49 |
end |
46 | 50 |
end |
trunk/config/routes.rb | ||
---|---|---|
246 | 246 |
omap.repositories_entry 'repositories/annotate/:id/*path', :action => 'annotate' |
247 | 247 |
omap.connect 'repositories/revision/:id/:rev', :action => 'revision' |
248 | 248 |
end |
249 |
|
|
250 |
# Allow downloading Web Service WSDL as a file with an extension |
|
251 |
# instead of a file named 'wsdl' |
|
252 |
map.connect ':controller/service.wsdl', :action => 'wsdl' |
|
249 |
|
|
250 |
map.with_options :controller => 'sys' do |sys| |
|
251 |
sys.connect 'sys/projects.:format', :action => 'projects', :conditions => {:method => :get} |
|
252 |
sys.connect 'sys/projects/:id/repository.:format', :action => 'create_project_repository', :conditions => {:method => :post} |
|
253 |
end |
|
253 | 254 |
|
254 | 255 |
# Install the default route as the lowest priority. |
255 | 256 |
map.connect ':controller/:action/:id' |
trunk/extra/svn/reposman.rb | ||
---|---|---|
57 | 57 |
|
58 | 58 |
require 'getoptlong' |
59 | 59 |
require 'rdoc/usage' |
60 |
require 'soap/wsdlDriver' |
|
61 | 60 |
require 'find' |
62 | 61 |
require 'etc' |
63 | 62 |
|
64 |
Version = "1.1"
|
|
63 |
Version = "1.2"
|
|
65 | 64 |
SUPPORTED_SCM = %w( Subversion Darcs Mercurial Bazaar Git Filesystem ) |
66 | 65 |
|
67 | 66 |
opts = GetoptLong.new( |
... | ... | |
164 | 163 |
log("directory '#{$repos_base}' doesn't exists", :exit => true) |
165 | 164 |
end |
166 | 165 |
|
166 |
begin |
|
167 |
require 'activeresource' |
|
168 |
rescue LoadError |
|
169 |
log("This script requires activeresource.\nRun 'gem install activeresource' to install it.", :exit => true) |
|
170 |
end |
|
171 |
|
|
172 |
class Project < ActiveResource::Base; end |
|
173 |
|
|
167 | 174 |
log("querying Redmine for projects...", :level => 1); |
168 | 175 |
|
169 | 176 |
$redmine_host.gsub!(/^/, "http://") unless $redmine_host.match("^https?://") |
170 | 177 |
$redmine_host.gsub!(/\/$/, '') |
171 | 178 |
|
172 |
wsdl_url = "#{$redmine_host}/sys/service.wsdl";
|
|
179 |
Project.site = "#{$redmine_host}/sys";
|
|
173 | 180 |
|
174 | 181 |
begin |
175 |
soap = SOAP::WSDLDriverFactory.new(wsdl_url).create_rpc_driver |
|
182 |
# Get all active projects that have the Repository module enabled |
|
183 |
projects = Project.find(:all) |
|
176 | 184 |
rescue => e |
177 |
log("Unable to connect to #{wsdl_url} : #{e}", :exit => true)
|
|
185 |
log("Unable to connect to #{Project.site}: #{e}", :exit => true)
|
|
178 | 186 |
end |
179 | 187 |
|
180 |
projects = soap.ProjectsWithRepositoryEnabled |
|
181 |
|
|
182 | 188 |
if projects.nil? |
183 | 189 |
log('no project found, perhaps you forgot to "Enable WS for repository management"', :exit => true) |
184 | 190 |
end |
... | ... | |
247 | 253 |
else |
248 | 254 |
# if repository is already declared in redmine, we don't create |
249 | 255 |
# unless user use -f with reposman |
250 |
if $force == false and not project.repository.nil?
|
|
256 |
if $force == false and project.respond_to?(:repository)
|
|
251 | 257 |
log("\trepository for project #{project.identifier} already exists in Redmine", :level => 1) |
252 | 258 |
next |
253 | 259 |
end |
... | ... | |
274 | 280 |
end |
275 | 281 |
|
276 | 282 |
if $svn_url |
277 |
ret = soap.RepositoryCreated project.identifier, $scm, "#{$svn_url}#{project.identifier}"
|
|
278 |
if ret > 0
|
|
283 |
begin
|
|
284 |
project.post(:repository, :vendor => $scm, :repository => {:url => "#{$svn_url}#{project.identifier}"})
|
|
279 | 285 |
log("\trepository #{repos_path} registered in Redmine with url #{$svn_url}#{project.identifier}"); |
280 |
else
|
|
281 |
log("\trepository #{repos_path} not registered in Redmine. Look in your log to find why.");
|
|
286 |
rescue => e
|
|
287 |
log("\trepository #{repos_path} not registered in Redmine: #{e.message}");
|
|
282 | 288 |
end |
283 | 289 |
end |
284 | 290 |
|
trunk/test/functional/sys_api_test.rb | ||
---|---|---|
1 |
require File.dirname(__FILE__) + '/../test_helper' |
|
2 |
require 'sys_controller' |
|
3 |
|
|
4 |
# Re-raise errors caught by the controller. |
|
5 |
class SysController; def rescue_action(e) raise e end; end |
|
6 |
|
|
7 |
class SysControllerTest < Test::Unit::TestCase |
|
8 |
fixtures :projects, :enabled_modules, :repositories |
|
9 |
|
|
10 |
def setup |
|
11 |
@controller = SysController.new |
|
12 |
@request = ActionController::TestRequest.new |
|
13 |
@response = ActionController::TestResponse.new |
|
14 |
# Enable WS |
|
15 |
Setting.sys_api_enabled = 1 |
|
16 |
end |
|
17 |
|
|
18 |
def test_projects_with_repository_enabled |
|
19 |
result = invoke :projects_with_repository_enabled |
|
20 |
assert_equal EnabledModule.count(:all, :conditions => {:name => 'repository'}), result.size |
|
21 |
|
|
22 |
project = result.first |
|
23 |
assert project.is_a?(AWSProjectWithRepository) |
|
24 |
|
|
25 |
assert project.respond_to?(:id) |
|
26 |
assert_equal 1, project.id |
|
27 |
|
|
28 |
assert project.respond_to?(:identifier) |
|
29 |
assert_equal 'ecookbook', project.identifier |
|
30 |
|
|
31 |
assert project.respond_to?(:name) |
|
32 |
assert_equal 'eCookbook', project.name |
|
33 |
|
|
34 |
assert project.respond_to?(:is_public) |
|
35 |
assert project.is_public |
|
36 |
|
|
37 |
assert project.respond_to?(:repository) |
|
38 |
assert project.repository.is_a?(Repository) |
|
39 |
end |
|
40 |
|
|
41 |
def test_repository_created |
|
42 |
project = Project.find(3) |
|
43 |
assert_nil project.repository |
|
44 |
assert invoke(:repository_created, project.identifier, 'Subversion', 'http://localhost/svn') |
|
45 |
project.reload |
|
46 |
assert_not_nil project.repository |
|
47 |
assert project.repository.is_a?(Repository::Subversion) |
|
48 |
assert_equal 'http://localhost/svn', project.repository.url |
|
49 |
end |
|
50 |
end |
|
51 | 0 |
trunk/test/functional/sys_controller_test.rb | ||
---|---|---|
1 |
# Redmine - project management software |
|
2 |
# Copyright (C) 2006-2009 Jean-Philippe Lang |
|
3 |
# |
|
4 |
# This program is free software; you can redistribute it and/or |
|
5 |
# modify it under the terms of the GNU General Public License |
|
6 |
# as published by the Free Software Foundation; either version 2 |
|
7 |
# of the License, or (at your option) any later version. |
|
8 |
# |
|
9 |
# This program is distributed in the hope that it will be useful, |
|
10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 |
# GNU General Public License for more details. |
|
13 |
# |
|
14 |
# You should have received a copy of the GNU General Public License |
|
15 |
# along with this program; if not, write to the Free Software |
|
16 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
17 |
|
|
18 |
require File.dirname(__FILE__) + '/../test_helper' |
|
19 |
require 'sys_controller' |
|
20 |
|
|
21 |
# Re-raise errors caught by the controller. |
|
22 |
class SysController; def rescue_action(e) raise e end; end |
|
23 |
|
|
24 |
class SysControllerTest < Test::Unit::TestCase |
|
25 |
fixtures :projects, :repositories |
|
26 |
|
|
27 |
def setup |
|
28 |
@controller = SysController.new |
|
29 |
@request = ActionController::TestRequest.new |
|
30 |
@response = ActionController::TestResponse.new |
|
31 |
Setting.sys_api_enabled = '1' |
|
32 |
end |
|
33 |
|
|
34 |
def test_projects_with_repository_enabled |
|
35 |
get :projects |
|
36 |
assert_response :success |
|
37 |
assert_equal 'application/xml', @response.content_type |
|
38 |
with_options :tag => 'projects' do |test| |
|
39 |
test.assert_tag :children => { :count => Project.active.has_module(:repository).count } |
|
40 |
end |
|
41 |
end |
|
42 |
|
|
43 |
def test_create_project_repository |
|
44 |
assert_nil Project.find(4).repository |
|
45 |
|
|
46 |
post :create_project_repository, :id => 4, |
|
47 |
:vendor => 'Subversion', |
|
48 |
:repository => { :url => 'file:///create/project/repository/subproject2'} |
|
49 |
assert_response :created |
|
50 |
|
|
51 |
r = Project.find(4).repository |
|
52 |
assert r.is_a?(Repository::Subversion) |
|
53 |
assert_equal 'file:///create/project/repository/subproject2', r.url |
|
54 |
end |
|
55 |
end |
|
0 | 56 |
trunk/vendor/plugins/actionwebservice/Rakefile | ||
---|---|---|
1 |
require 'rubygems' |
|
2 |
require 'rake' |
|
3 |
require 'rake/testtask' |
|
4 |
require 'rake/rdoctask' |
|
5 |
require 'rake/packagetask' |
|
6 |
require 'rake/gempackagetask' |
|
7 |
require 'rake/contrib/rubyforgepublisher' |
|
8 |
require 'fileutils' |
|
9 |
require File.join(File.dirname(__FILE__), 'lib', 'action_web_service', 'version') |
|
10 |
|
|
11 |
PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : '' |
|
12 |
PKG_NAME = 'actionwebservice' |
|
13 |
PKG_VERSION = ActionWebService::VERSION::STRING + PKG_BUILD |
|
14 |
PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}" |
|
15 |
PKG_DESTINATION = ENV["RAILS_PKG_DESTINATION"] || "../#{PKG_NAME}" |
|
16 |
|
|
17 |
RELEASE_NAME = "REL #{PKG_VERSION}" |
|
18 |
|
|
19 |
RUBY_FORGE_PROJECT = "aws" |
|
20 |
RUBY_FORGE_USER = "webster132" |
|
21 |
|
|
22 |
desc "Default Task" |
|
23 |
task :default => [ :test ] |
|
24 |
|
|
25 |
|
|
26 |
# Run the unit tests |
|
27 |
Rake::TestTask.new { |t| |
|
28 |
t.libs << "test" |
|
29 |
t.test_files = Dir['test/*_test.rb'] |
|
30 |
t.verbose = true |
|
31 |
} |
|
32 |
|
|
33 |
SCHEMA_PATH = File.join(File.dirname(__FILE__), *%w(test fixtures db_definitions)) |
|
34 |
|
|
35 |
desc 'Build the MySQL test database' |
|
36 |
task :build_database do |
|
37 |
%x( mysqladmin create actionwebservice_unittest ) |
|
38 |
%x( mysql actionwebservice_unittest < #{File.join(SCHEMA_PATH, 'mysql.sql')} ) |
|
39 |
end |
|
40 |
|
|
41 |
|
|
42 |
# Generate the RDoc documentation |
|
43 |
Rake::RDocTask.new { |rdoc| |
|
44 |
rdoc.rdoc_dir = 'doc' |
|
45 |
rdoc.title = "Action Web Service -- Web services for Action Pack" |
|
46 |
rdoc.options << '--line-numbers' << '--inline-source' |
|
47 |
rdoc.options << '--charset' << 'utf-8' |
|
48 |
rdoc.template = "#{ENV['template']}.rb" if ENV['template'] |
|
49 |
rdoc.rdoc_files.include('README') |
|
50 |
rdoc.rdoc_files.include('CHANGELOG') |
|
51 |
rdoc.rdoc_files.include('lib/action_web_service.rb') |
|
52 |
rdoc.rdoc_files.include('lib/action_web_service/*.rb') |
|
53 |
rdoc.rdoc_files.include('lib/action_web_service/api/*.rb') |
|
54 |
rdoc.rdoc_files.include('lib/action_web_service/client/*.rb') |
|
55 |
rdoc.rdoc_files.include('lib/action_web_service/container/*.rb') |
|
56 |
rdoc.rdoc_files.include('lib/action_web_service/dispatcher/*.rb') |
|
57 |
rdoc.rdoc_files.include('lib/action_web_service/protocol/*.rb') |
|
58 |
rdoc.rdoc_files.include('lib/action_web_service/support/*.rb') |
|
59 |
} |
|
60 |
|
|
61 |
|
|
62 |
# Create compressed packages |
|
63 |
spec = Gem::Specification.new do |s| |
|
64 |
s.platform = Gem::Platform::RUBY |
|
65 |
s.name = PKG_NAME |
|
66 |
s.summary = "Web service support for Action Pack." |
|
67 |
s.description = %q{Adds WSDL/SOAP and XML-RPC web service support to Action Pack} |
|
68 |
s.version = PKG_VERSION |
|
69 |
|
|
70 |
s.author = "Leon Breedt" |
|
71 |
s.email = "[email protected]" |
|
72 |
s.rubyforge_project = "aws" |
|
73 |
s.homepage = "http://www.rubyonrails.org" |
|
74 |
|
|
75 |
s.add_dependency('actionpack', '= 1.13.5' + PKG_BUILD) |
|
76 |
s.add_dependency('activerecord', '= 1.15.5' + PKG_BUILD) |
|
77 |
|
|
78 |
s.has_rdoc = true |
|
79 |
s.requirements << 'none' |
|
80 |
s.require_path = 'lib' |
|
81 |
s.autorequire = 'action_web_service' |
|
82 |
|
|
83 |
s.files = [ "Rakefile", "setup.rb", "README", "TODO", "CHANGELOG", "MIT-LICENSE" ] |
|
84 |
s.files = s.files + Dir.glob( "examples/**/*" ).delete_if { |item| item.include?( "\.svn" ) } |
|
85 |
s.files = s.files + Dir.glob( "lib/**/*" ).delete_if { |item| item.include?( "\.svn" ) } |
|
86 |
s.files = s.files + Dir.glob( "test/**/*" ).delete_if { |item| item.include?( "\.svn" ) } |
|
87 |
end |
|
88 |
Rake::GemPackageTask.new(spec) do |p| |
|
89 |
p.gem_spec = spec |
|
90 |
p.need_tar = true |
|
91 |
p.need_zip = true |
|
92 |
end |
|
93 |
|
|
94 |
|
|
95 |
# Publish beta gem |
|
96 |
desc "Publish the API documentation" |
|
97 |
task :pgem => [:package] do |
|
98 |
Rake::SshFilePublisher.new("[email protected]", "public_html/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload |
|
99 |
`ssh [email protected] './gemupdate.sh'` |
|
100 |
end |
|
101 |
|
|
102 |
# Publish documentation |
|
103 |
desc "Publish the API documentation" |
|
104 |
task :pdoc => [:rdoc] do |
|
105 |
Rake::SshDirPublisher.new("[email protected]", "public_html/aws", "doc").upload |
|
106 |
end |
|
107 |
|
|
108 |
|
|
109 |
def each_source_file(*args) |
|
110 |
prefix, includes, excludes, open_file = args |
|
111 |
prefix ||= File.dirname(__FILE__) |
|
112 |
open_file = true if open_file.nil? |
|
113 |
includes ||= %w[lib\/action_web_service\.rb$ lib\/action_web_service\/.*\.rb$] |
|
114 |
excludes ||= %w[lib\/action_web_service\/vendor] |
|
115 |
Find.find(prefix) do |file_name| |
|
116 |
next if file_name =~ /\.svn/ |
|
117 |
file_name.gsub!(/^\.\//, '') |
|
118 |
continue = false |
|
119 |
includes.each do |inc| |
|
120 |
if file_name.match(/#{inc}/) |
|
121 |
continue = true |
|
122 |
break |
|
123 |
end |
|
124 |
end |
|
125 |
next unless continue |
|
126 |
excludes.each do |exc| |
|
127 |
if file_name.match(/#{exc}/) |
|
128 |
continue = false |
|
129 |
break |
|
130 |
end |
|
131 |
end |
|
132 |
next unless continue |
|
133 |
if open_file |
|
134 |
File.open(file_name) do |f| |
|
135 |
yield file_name, f |
|
136 |
end |
|
137 |
else |
|
138 |
yield file_name |
|
139 |
end |
|
140 |
end |
|
141 |
end |
|
142 |
|
|
143 |
desc "Count lines of the AWS source code" |
|
144 |
task :lines do |
|
145 |
total_lines = total_loc = 0 |
|
146 |
puts "Per File:" |
|
147 |
each_source_file do |file_name, f| |
|
148 |
file_lines = file_loc = 0 |
|
149 |
while line = f.gets |
|
150 |
file_lines += 1 |
|
151 |
next if line =~ /^\s*$/ |
|
152 |
next if line =~ /^\s*#/ |
|
153 |
file_loc += 1 |
|
154 |
end |
|
155 |
puts " #{file_name}: Lines #{file_lines}, LOC #{file_loc}" |
|
156 |
total_lines += file_lines |
|
157 |
total_loc += file_loc |
|
158 |
end |
|
159 |
puts "Total:" |
|
160 |
puts " Lines #{total_lines}, LOC #{total_loc}" |
|
161 |
end |
|
162 |
|
|
163 |
desc "Publish the release files to RubyForge." |
|
164 |
task :release => [ :package ] do |
|
165 |
require 'rubyforge' |
|
166 |
|
|
167 |
packages = %w( gem tgz zip ).collect{ |ext| "pkg/#{PKG_NAME}-#{PKG_VERSION}.#{ext}" } |
|
168 |
|
|
169 |
rubyforge = RubyForge.new |
|
170 |
rubyforge.login |
|
171 |
rubyforge.add_release(PKG_NAME, PKG_NAME, "REL #{PKG_VERSION}", *packages) |
|
172 |
end |
|
173 | 0 |
trunk/vendor/plugins/actionwebservice/setup.rb | ||
---|---|---|
1 |
# |
|
2 |
# setup.rb |
|
3 |
# |
|
4 |
# Copyright (c) 2000-2004 Minero Aoki |
|
5 |
# |
|
6 |
# Permission is hereby granted, free of charge, to any person obtaining |
|
7 |
# a copy of this software and associated documentation files (the |
|
8 |
# "Software"), to deal in the Software without restriction, including |
|
9 |
# without limitation the rights to use, copy, modify, merge, publish, |
|
10 |
# distribute, sublicense, and/or sell copies of the Software, and to |
|
11 |
# permit persons to whom the Software is furnished to do so, subject to |
|
12 |
# the following conditions: |
|
13 |
# |
|
14 |
# The above copyright notice and this permission notice shall be |
|
15 |
# included in all copies or substantial portions of the Software. |
|
16 |
# |
|
17 |
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
|
18 |
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|
19 |
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
|
20 |
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
|
21 |
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
|
22 |
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
|
23 |
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
24 |
# |
|
25 |
# Note: Originally licensed under LGPL v2+. Using MIT license for Rails |
|
26 |
# with permission of Minero Aoki. |
|
27 |
|
|
28 |
# |
|
29 |
|
|
30 |
unless Enumerable.method_defined?(:map) # Ruby 1.4.6 |
|
31 |
module Enumerable |
|
32 |
alias map collect |
|
33 |
end |
|
34 |
end |
|
35 |
|
|
36 |
unless File.respond_to?(:read) # Ruby 1.6 |
|
37 |
def File.read(fname) |
|
38 |
open(fname) {|f| |
|
39 |
return f.read |
|
40 |
} |
|
41 |
end |
|
42 |
end |
|
43 |
|
|
44 |
def File.binread(fname) |
|
45 |
open(fname, 'rb') {|f| |
|
46 |
return f.read |
|
47 |
} |
|
48 |
end |
|
49 |
|
|
50 |
# for corrupted windows stat(2) |
|
51 |
def File.dir?(path) |
|
52 |
File.directory?((path[-1,1] == '/') ? path : path + '/') |
|
53 |
end |
|
54 |
|
|
55 |
|
|
56 |
class SetupError < StandardError; end |
|
57 |
|
|
58 |
def setup_rb_error(msg) |
|
59 |
raise SetupError, msg |
|
60 |
end |
|
61 |
|
|
62 |
# |
|
63 |
# Config |
|
64 |
# |
|
65 |
|
|
66 |
if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg } |
|
67 |
ARGV.delete(arg) |
|
68 |
require arg.split(/=/, 2)[1] |
|
69 |
$".push 'rbconfig.rb' |
|
70 |
else |
|
71 |
require 'rbconfig' |
|
72 |
end |
|
73 |
|
|
74 |
def multipackage_install? |
|
75 |
FileTest.directory?(File.dirname($0) + '/packages') |
|
76 |
end |
|
77 |
|
|
78 |
|
|
79 |
class ConfigItem |
|
80 |
def initialize(name, template, default, desc) |
|
81 |
@name = name.freeze |
|
82 |
@template = template |
|
83 |
@value = default |
|
84 |
@default = default.dup.freeze |
|
85 |
@description = desc |
|
86 |
end |
|
87 |
|
|
88 |
attr_reader :name |
|
89 |
attr_reader :description |
|
90 |
|
|
91 |
attr_accessor :default |
|
92 |
alias help_default default |
|
93 |
|
|
94 |
def help_opt |
|
95 |
"--#{@name}=#{@template}" |
|
96 |
end |
|
97 |
|
|
98 |
def value |
|
99 |
@value |
|
100 |
end |
|
101 |
|
|
102 |
def eval(table) |
|
103 |
@value.gsub(%r<\$([^/]+)>) { table[$1] } |
|
104 |
end |
|
105 |
|
|
106 |
def set(val) |
|
107 |
@value = check(val) |
|
108 |
end |
|
109 |
|
|
110 |
private |
|
111 |
|
|
112 |
def check(val) |
|
113 |
setup_rb_error "config: --#{name} requires argument" unless val |
|
114 |
val |
|
115 |
end |
|
116 |
end |
|
117 |
|
|
118 |
class BoolItem < ConfigItem |
|
119 |
def config_type |
|
120 |
'bool' |
|
121 |
end |
|
122 |
|
|
123 |
def help_opt |
|
124 |
"--#{@name}" |
|
125 |
end |
|
126 |
|
|
127 |
private |
|
128 |
|
|
129 |
def check(val) |
|
130 |
return 'yes' unless val |
|
131 |
unless /\A(y(es)?|n(o)?|t(rue)?|f(alse))\z/i =~ val |
|
132 |
setup_rb_error "config: --#{@name} accepts only yes/no for argument" |
|
133 |
end |
|
134 |
(/\Ay(es)?|\At(rue)/i =~ value) ? 'yes' : 'no' |
|
135 |
end |
|
136 |
end |
|
137 |
|
|
138 |
class PathItem < ConfigItem |
|
139 |
def config_type |
|
140 |
'path' |
|
141 |
end |
|
142 |
|
|
143 |
private |
|
144 |
|
|
145 |
def check(path) |
|
146 |
setup_rb_error "config: --#{@name} requires argument" unless path |
|
147 |
path[0,1] == '$' ? path : File.expand_path(path) |
|
148 |
end |
|
149 |
end |
|
150 |
|
|
151 |
class ProgramItem < ConfigItem |
|
152 |
def config_type |
|
153 |
'program' |
|
154 |
end |
|
155 |
end |
|
156 |
|
|
157 |
class SelectItem < ConfigItem |
|
158 |
def initialize(name, template, default, desc) |
|
159 |
super |
|
160 |
@ok = template.split('/') |
|
161 |
end |
|
162 |
|
|
163 |
def config_type |
|
164 |
'select' |
|
165 |
end |
|
166 |
|
|
167 |
private |
|
168 |
|
|
169 |
def check(val) |
|
170 |
unless @ok.include?(val.strip) |
|
171 |
setup_rb_error "config: use --#{@name}=#{@template} (#{val})" |
|
172 |
end |
|
173 |
val.strip |
|
174 |
end |
|
175 |
end |
|
176 |
|
|
177 |
class PackageSelectionItem < ConfigItem |
|
178 |
def initialize(name, template, default, help_default, desc) |
|
179 |
super name, template, default, desc |
|
180 |
@help_default = help_default |
|
181 |
end |
|
182 |
|
|
183 |
attr_reader :help_default |
|
184 |
|
|
185 |
def config_type |
|
186 |
'package' |
|
187 |
end |
|
188 |
|
|
189 |
private |
|
190 |
|
|
191 |
def check(val) |
|
192 |
unless File.dir?("packages/#{val}") |
|
193 |
setup_rb_error "config: no such package: #{val}" |
|
194 |
end |
|
195 |
val |
|
196 |
end |
|
197 |
end |
|
198 |
|
|
199 |
class ConfigTable_class |
|
200 |
|
|
201 |
def initialize(items) |
|
202 |
@items = items |
|
203 |
@table = {} |
|
204 |
items.each do |i| |
|
205 |
@table[i.name] = i |
|
206 |
end |
|
207 |
ALIASES.each do |ali, name| |
|
208 |
@table[ali] = @table[name] |
|
209 |
end |
|
210 |
end |
|
211 |
|
|
212 |
include Enumerable |
|
213 |
|
|
214 |
def each(&block) |
|
215 |
@items.each(&block) |
|
216 |
end |
|
217 |
|
|
218 |
def key?(name) |
|
219 |
@table.key?(name) |
|
220 |
end |
|
221 |
|
|
222 |
def lookup(name) |
|
223 |
@table[name] or raise ArgumentError, "no such config item: #{name}" |
|
224 |
end |
|
225 |
|
|
226 |
def add(item) |
|
227 |
@items.push item |
|
228 |
@table[item.name] = item |
|
229 |
end |
|
230 |
|
|
231 |
def remove(name) |
|
232 |
item = lookup(name) |
|
233 |
@items.delete_if {|i| i.name == name } |
|
234 |
@table.delete_if {|name, i| i.name == name } |
|
235 |
item |
|
236 |
end |
|
237 |
|
|
238 |
def new |
|
239 |
dup() |
|
240 |
end |
|
241 |
|
|
242 |
def savefile |
|
243 |
'.config' |
|
244 |
end |
|
245 |
|
|
246 |
def load |
|
247 |
begin |
|
248 |
t = dup() |
|
249 |
File.foreach(savefile()) do |line| |
|
250 |
k, v = *line.split(/=/, 2) |
|
251 |
t[k] = v.strip |
|
252 |
end |
|
253 |
t |
|
254 |
rescue Errno::ENOENT |
|
255 |
setup_rb_error $!.message + "#{File.basename($0)} config first" |
|
256 |
end |
|
257 |
end |
|
258 |
|
|
259 |
def save |
|
260 |
@items.each {|i| i.value } |
|
261 |
File.open(savefile(), 'w') {|f| |
|
262 |
@items.each do |i| |
|
263 |
f.printf "%s=%s\n", i.name, i.value if i.value |
|
264 |
end |
|
265 |
} |
|
266 |
end |
|
267 |
|
|
268 |
def [](key) |
|
269 |
lookup(key).eval(self) |
|
270 |
end |
|
271 |
|
|
272 |
def []=(key, val) |
|
273 |
lookup(key).set val |
|
274 |
end |
|
275 |
|
|
276 |
end |
|
277 |
|
|
278 |
c = ::Config::CONFIG |
|
279 |
|
|
280 |
rubypath = c['bindir'] + '/' + c['ruby_install_name'] |
|
281 |
|
|
282 |
major = c['MAJOR'].to_i |
|
283 |
minor = c['MINOR'].to_i |
|
284 |
teeny = c['TEENY'].to_i |
|
285 |
version = "#{major}.#{minor}" |
|
286 |
|
|
287 |
# ruby ver. >= 1.4.4? |
|
288 |
newpath_p = ((major >= 2) or |
|
289 |
((major == 1) and |
|
290 |
((minor >= 5) or |
|
291 |
((minor == 4) and (teeny >= 4))))) |
|
292 |
|
|
293 |
if c['rubylibdir'] |
|
294 |
# V < 1.6.3 |
|
295 |
_stdruby = c['rubylibdir'] |
|
296 |
_siteruby = c['sitedir'] |
|
297 |
_siterubyver = c['sitelibdir'] |
|
298 |
_siterubyverarch = c['sitearchdir'] |
|
299 |
elsif newpath_p |
|
300 |
# 1.4.4 <= V <= 1.6.3 |
|
301 |
_stdruby = "$prefix/lib/ruby/#{version}" |
|
302 |
_siteruby = c['sitedir'] |
|
303 |
_siterubyver = "$siteruby/#{version}" |
|
304 |
_siterubyverarch = "$siterubyver/#{c['arch']}" |
|
305 |
else |
|
306 |
# V < 1.4.4 |
|
307 |
_stdruby = "$prefix/lib/ruby/#{version}" |
|
308 |
_siteruby = "$prefix/lib/ruby/#{version}/site_ruby" |
|
309 |
_siterubyver = _siteruby |
|
310 |
_siterubyverarch = "$siterubyver/#{c['arch']}" |
|
311 |
end |
|
312 |
libdir = '-* dummy libdir *-' |
|
313 |
stdruby = '-* dummy rubylibdir *-' |
|
314 |
siteruby = '-* dummy site_ruby *-' |
|
315 |
siterubyver = '-* dummy site_ruby version *-' |
|
316 |
parameterize = lambda {|path| |
|
317 |
path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix')\ |
|
318 |
.sub(/\A#{Regexp.quote(libdir)}/, '$libdir')\ |
|
319 |
.sub(/\A#{Regexp.quote(stdruby)}/, '$stdruby')\ |
|
320 |
.sub(/\A#{Regexp.quote(siteruby)}/, '$siteruby')\ |
|
321 |
.sub(/\A#{Regexp.quote(siterubyver)}/, '$siterubyver') |
|
322 |
} |
|
323 |
libdir = parameterize.call(c['libdir']) |
|
324 |
stdruby = parameterize.call(_stdruby) |
|
325 |
siteruby = parameterize.call(_siteruby) |
|
326 |
siterubyver = parameterize.call(_siterubyver) |
|
327 |
siterubyverarch = parameterize.call(_siterubyverarch) |
|
328 |
|
|
329 |
if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg } |
|
330 |
makeprog = arg.sub(/'/, '').split(/=/, 2)[1] |
|
331 |
else |
|
332 |
makeprog = 'make' |
|
333 |
end |
|
334 |
|
|
335 |
common_conf = [ |
|
336 |
PathItem.new('prefix', 'path', c['prefix'], |
|
337 |
'path prefix of target environment'), |
|
338 |
PathItem.new('bindir', 'path', parameterize.call(c['bindir']), |
|
339 |
'the directory for commands'), |
|
340 |
PathItem.new('libdir', 'path', libdir, |
|
341 |
'the directory for libraries'), |
|
342 |
PathItem.new('datadir', 'path', parameterize.call(c['datadir']), |
|
343 |
'the directory for shared data'), |
|
344 |
PathItem.new('mandir', 'path', parameterize.call(c['mandir']), |
|
345 |
'the directory for man pages'), |
|
346 |
PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']), |
|
347 |
'the directory for man pages'), |
|
348 |
PathItem.new('stdruby', 'path', stdruby, |
|
349 |
'the directory for standard ruby libraries'), |
|
350 |
PathItem.new('siteruby', 'path', siteruby, |
|
351 |
'the directory for version-independent aux ruby libraries'), |
|
352 |
PathItem.new('siterubyver', 'path', siterubyver, |
|
353 |
'the directory for aux ruby libraries'), |
|
354 |
PathItem.new('siterubyverarch', 'path', siterubyverarch, |
|
355 |
'the directory for aux ruby binaries'), |
|
356 |
PathItem.new('rbdir', 'path', '$siterubyver', |
|
357 |
'the directory for ruby scripts'), |
|
358 |
PathItem.new('sodir', 'path', '$siterubyverarch', |
|
359 |
'the directory for ruby extentions'), |
|
360 |
PathItem.new('rubypath', 'path', rubypath, |
|
361 |
'the path to set to #! line'), |
|
362 |
ProgramItem.new('rubyprog', 'name', rubypath, |
|
363 |
'the ruby program using for installation'), |
|
364 |
ProgramItem.new('makeprog', 'name', makeprog, |
|
365 |
'the make program to compile ruby extentions'), |
|
366 |
SelectItem.new('shebang', 'all/ruby/never', 'ruby', |
|
367 |
'shebang line (#!) editing mode'), |
|
368 |
BoolItem.new('without-ext', 'yes/no', 'no', |
|
369 |
'does not compile/install ruby extentions') |
|
370 |
] |
|
371 |
class ConfigTable_class # open again |
|
372 |
ALIASES = { |
|
373 |
'std-ruby' => 'stdruby', |
|
374 |
'site-ruby-common' => 'siteruby', # For backward compatibility |
|
375 |
'site-ruby' => 'siterubyver', # For backward compatibility |
|
376 |
'bin-dir' => 'bindir', |
|
377 |
'bin-dir' => 'bindir', |
|
378 |
'rb-dir' => 'rbdir', |
|
379 |
'so-dir' => 'sodir', |
|
380 |
'data-dir' => 'datadir', |
|
381 |
'ruby-path' => 'rubypath', |
|
382 |
'ruby-prog' => 'rubyprog', |
|
383 |
'ruby' => 'rubyprog', |
|
384 |
'make-prog' => 'makeprog', |
|
385 |
'make' => 'makeprog' |
|
386 |
} |
|
387 |
end |
|
388 |
multipackage_conf = [ |
|
389 |
PackageSelectionItem.new('with', 'name,name...', '', 'ALL', |
|
390 |
'package names that you want to install'), |
|
391 |
PackageSelectionItem.new('without', 'name,name...', '', 'NONE', |
|
392 |
'package names that you do not want to install') |
|
393 |
] |
|
394 |
if multipackage_install? |
|
395 |
ConfigTable = ConfigTable_class.new(common_conf + multipackage_conf) |
|
396 |
else |
|
397 |
ConfigTable = ConfigTable_class.new(common_conf) |
|
398 |
end |
|
399 |
|
|
400 |
|
|
401 |
module MetaConfigAPI |
|
402 |
|
|
403 |
def eval_file_ifexist(fname) |
|
404 |
instance_eval File.read(fname), fname, 1 if File.file?(fname) |
|
405 |
end |
|
406 |
|
|
407 |
def config_names |
|
408 |
ConfigTable.map {|i| i.name } |
|
409 |
end |
|
410 |
|
|
411 |
def config?(name) |
|
412 |
ConfigTable.key?(name) |
|
413 |
end |
|
414 |
|
|
415 |
def bool_config?(name) |
|
416 |
ConfigTable.lookup(name).config_type == 'bool' |
|
417 |
end |
|
418 |
|
|
419 |
def path_config?(name) |
|
420 |
ConfigTable.lookup(name).config_type == 'path' |
|
421 |
end |
|
422 |
|
|
423 |
def value_config?(name) |
|
424 |
case ConfigTable.lookup(name).config_type |
|
425 |
when 'bool', 'path' |
|
426 |
true |
|
427 |
else |
|
428 |
false |
|
429 |
end |
|
430 |
end |
|
431 |
|
|
432 |
def add_config(item) |
|
433 |
ConfigTable.add item |
|
434 |
end |
|
435 |
|
|
436 |
def add_bool_config(name, default, desc) |
|
437 |
ConfigTable.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc) |
|
438 |
end |
|
439 |
|
|
440 |
def add_path_config(name, default, desc) |
|
441 |
ConfigTable.add PathItem.new(name, 'path', default, desc) |
|
442 |
end |
|
443 |
|
|
444 |
def set_config_default(name, default) |
|
445 |
ConfigTable.lookup(name).default = default |
|
446 |
end |
|
447 |
|
|
448 |
def remove_config(name) |
|
449 |
ConfigTable.remove(name) |
|
450 |
end |
|
451 |
|
|
452 |
end |
|
453 |
|
|
454 |
|
|
455 |
# |
|
456 |
# File Operations |
|
457 |
# |
|
458 |
|
|
459 |
module FileOperations |
|
460 |
|
|
461 |
def mkdir_p(dirname, prefix = nil) |
|
462 |
dirname = prefix + File.expand_path(dirname) if prefix |
|
463 |
$stderr.puts "mkdir -p #{dirname}" if verbose? |
|
464 |
return if no_harm? |
|
465 |
|
|
466 |
# does not check '/'... it's too abnormal case |
|
467 |
dirs = File.expand_path(dirname).split(%r<(?=/)>) |
|
468 |
if /\A[a-z]:\z/i =~ dirs[0] |
|
469 |
disk = dirs.shift |
|
470 |
dirs[0] = disk + dirs[0] |
|
471 |
end |
|
472 |
dirs.each_index do |idx| |
|
473 |
path = dirs[0..idx].join('') |
|
474 |
Dir.mkdir path unless File.dir?(path) |
|
475 |
end |
|
476 |
end |
|
477 |
|
|
478 |
def rm_f(fname) |
|
479 |
$stderr.puts "rm -f #{fname}" if verbose? |
|
480 |
return if no_harm? |
|
481 |
|
|
482 |
if File.exist?(fname) or File.symlink?(fname) |
|
483 |
File.chmod 0777, fname |
|
484 |
File.unlink fname |
|
485 |
end |
|
486 |
end |
|
487 |
|
|
488 |
def rm_rf(dn) |
|
489 |
$stderr.puts "rm -rf #{dn}" if verbose? |
|
490 |
return if no_harm? |
|
491 |
|
|
492 |
Dir.chdir dn |
|
493 |
Dir.foreach('.') do |fn| |
|
494 |
next if fn == '.' |
|
495 |
next if fn == '..' |
|
496 |
if File.dir?(fn) |
|
497 |
verbose_off { |
|
498 |
rm_rf fn |
|
499 |
} |
|
500 |
else |
|
501 |
verbose_off { |
|
502 |
rm_f fn |
|
503 |
} |
|
504 |
end |
|
505 |
end |
|
506 |
Dir.chdir '..' |
|
507 |
Dir.rmdir dn |
|
508 |
end |
|
509 |
|
|
510 |
def move_file(src, dest) |
|
511 |
File.unlink dest if File.exist?(dest) |
|
512 |
begin |
|
513 |
File.rename src, dest |
|
514 |
rescue |
|
515 |
File.open(dest, 'wb') {|f| f.write File.binread(src) } |
|
516 |
File.chmod File.stat(src).mode, dest |
|
517 |
File.unlink src |
|
518 |
end |
|
519 |
end |
|
520 |
|
|
521 |
def install(from, dest, mode, prefix = nil) |
|
522 |
$stderr.puts "install #{from} #{dest}" if verbose? |
|
523 |
return if no_harm? |
|
524 |
|
|
525 |
realdest = prefix ? prefix + File.expand_path(dest) : dest |
|
526 |
realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest) |
|
527 |
str = File.binread(from) |
|
528 |
if diff?(str, realdest) |
|
529 |
verbose_off { |
|
530 |
rm_f realdest if File.exist?(realdest) |
|
531 |
} |
|
532 |
File.open(realdest, 'wb') {|f| |
|
533 |
f.write str |
|
534 |
} |
|
535 |
File.chmod mode, realdest |
|
536 |
|
|
537 |
File.open("#{objdir_root()}/InstalledFiles", 'a') {|f| |
|
538 |
if prefix |
|
539 |
f.puts realdest.sub(prefix, '') |
|
540 |
else |
|
541 |
f.puts realdest |
|
542 |
end |
|
543 |
} |
|
544 |
end |
|
545 |
end |
|
546 |
|
|
547 |
def diff?(new_content, path) |
|
548 |
return true unless File.exist?(path) |
|
549 |
new_content != File.binread(path) |
|
550 |
end |
|
551 |
|
|
552 |
def command(str) |
|
553 |
$stderr.puts str if verbose? |
|
554 |
system str or raise RuntimeError, "'system #{str}' failed" |
|
555 |
end |
|
556 |
|
|
557 |
def ruby(str) |
|
558 |
command config('rubyprog') + ' ' + str |
|
559 |
end |
|
560 |
|
|
561 |
def make(task = '') |
|
562 |
command config('makeprog') + ' ' + task |
|
563 |
end |
|
564 |
|
|
565 |
def extdir?(dir) |
|
566 |
File.exist?(dir + '/MANIFEST') |
|
567 |
end |
|
568 |
|
|
569 |
def all_files_in(dirname) |
|
570 |
Dir.open(dirname) {|d| |
|
571 |
return d.select {|ent| File.file?("#{dirname}/#{ent}") } |
|
572 |
} |
|
573 |
end |
|
574 |
|
|
575 |
REJECT_DIRS = %w( |
|
576 |
CVS SCCS RCS CVS.adm .svn |
|
577 |
) |
|
578 |
|
|
579 |
def all_dirs_in(dirname) |
|
580 |
Dir.open(dirname) {|d| |
|
581 |
return d.select {|n| File.dir?("#{dirname}/#{n}") } - %w(. ..) - REJECT_DIRS |
|
582 |
} |
|
583 |
end |
|
584 |
|
|
585 |
end |
|
586 |
|
|
587 |
|
|
588 |
# |
|
589 |
# Main Installer |
|
590 |
# |
|
591 |
|
|
592 |
module HookUtils |
|
593 |
|
|
594 |
def run_hook(name) |
|
595 |
try_run_hook "#{curr_srcdir()}/#{name}" or |
|
596 |
try_run_hook "#{curr_srcdir()}/#{name}.rb" |
|
597 |
end |
|
598 |
|
|
599 |
def try_run_hook(fname) |
|
600 |
return false unless File.file?(fname) |
|
601 |
begin |
|
602 |
instance_eval File.read(fname), fname, 1 |
|
603 |
rescue |
|
604 |
setup_rb_error "hook #{fname} failed:\n" + $!.message |
|
605 |
end |
|
606 |
true |
|
607 |
end |
|
608 |
|
|
609 |
end |
|
610 |
|
|
611 |
|
|
612 |
module HookScriptAPI |
|
613 |
|
|
614 |
def get_config(key) |
|
615 |
@config[key] |
|
616 |
end |
|
617 |
|
|
618 |
alias config get_config |
|
619 |
|
|
620 |
def set_config(key, val) |
|
621 |
@config[key] = val |
|
622 |
end |
|
623 |
|
|
624 |
# |
|
625 |
# srcdir/objdir (works only in the package directory) |
|
626 |
# |
|
627 |
|
|
628 |
#abstract srcdir_root |
|
629 |
#abstract objdir_root |
|
630 |
#abstract relpath |
|
631 |
|
|
632 |
def curr_srcdir |
|
633 |
"#{srcdir_root()}/#{relpath()}" |
|
634 |
end |
|
635 |
|
|
636 |
def curr_objdir |
|
637 |
"#{objdir_root()}/#{relpath()}" |
|
638 |
end |
|
639 |
|
|
640 |
def srcfile(path) |
|
641 |
"#{curr_srcdir()}/#{path}" |
|
642 |
end |
|
643 |
|
|
644 |
def srcexist?(path) |
|
645 |
File.exist?(srcfile(path)) |
|
646 |
end |
|
647 |
|
|
648 |
def srcdirectory?(path) |
|
649 |
File.dir?(srcfile(path)) |
|
650 |
end |
|
651 |
|
|
652 |
def srcfile?(path) |
|
653 |
File.file? srcfile(path) |
|
654 |
end |
|
655 |
|
|
656 |
def srcentries(path = '.') |
|
657 |
Dir.open("#{curr_srcdir()}/#{path}") {|d| |
|
658 |
return d.to_a - %w(. ..) |
|
659 |
} |
|
660 |
end |
|
661 |
|
|
662 |
def srcfiles(path = '.') |
|
663 |
srcentries(path).select {|fname| |
|
664 |
File.file?(File.join(curr_srcdir(), path, fname)) |
|
665 |
} |
|
666 |
end |
|
667 |
|
|
668 |
def srcdirectories(path = '.') |
|
669 |
srcentries(path).select {|fname| |
|
670 |
File.dir?(File.join(curr_srcdir(), path, fname)) |
|
671 |
} |
|
672 |
end |
|
673 |
|
|
674 |
end |
|
675 |
|
|
676 |
|
|
677 |
class ToplevelInstaller |
|
678 |
|
|
679 |
Version = '3.3.1' |
|
680 |
Copyright = 'Copyright (c) 2000-2004 Minero Aoki' |
|
681 |
|
|
682 |
TASKS = [ |
|
683 |
[ 'all', 'do config, setup, then install' ], |
|
684 |
[ 'config', 'saves your configurations' ], |
|
685 |
[ 'show', 'shows current configuration' ], |
|
686 |
[ 'setup', 'compiles ruby extentions and others' ], |
|
687 |
[ 'install', 'installs files' ], |
|
688 |
[ 'clean', "does `make clean' for each extention" ], |
|
689 |
[ 'distclean',"does `make distclean' for each extention" ] |
|
690 |
] |
|
691 |
|
|
692 |
def ToplevelInstaller.invoke |
|
693 |
instance().invoke |
|
694 |
end |
|
695 |
|
|
696 |
@singleton = nil |
|
697 |
|
|
698 |
def ToplevelInstaller.instance |
|
699 |
@singleton ||= new(File.dirname($0)) |
|
700 |
@singleton |
|
701 |
end |
|
702 |
|
|
703 |
include MetaConfigAPI |
|
704 |
|
|
705 |
def initialize(ardir_root) |
|
706 |
@config = nil |
|
707 |
@options = { 'verbose' => true } |
|
708 |
@ardir = File.expand_path(ardir_root) |
|
709 |
end |
|
710 |
|
|
711 |
def inspect |
|
712 |
"#<#{self.class} #{__id__()}>" |
|
713 |
end |
|
714 |
|
|
715 |
def invoke |
|
716 |
run_metaconfigs |
|
717 |
case task = parsearg_global() |
|
718 |
when nil, 'all' |
|
719 |
@config = load_config('config') |
|
720 |
parsearg_config |
|
721 |
init_installers |
|
722 |
exec_config |
|
723 |
exec_setup |
|
724 |
exec_install |
|
725 |
else |
|
726 |
@config = load_config(task) |
|
727 |
__send__ "parsearg_#{task}" |
|
728 |
init_installers |
|
729 |
__send__ "exec_#{task}" |
|
730 |
end |
|
731 |
end |
|
732 |
|
|
733 |
def run_metaconfigs |
|
734 |
eval_file_ifexist "#{@ardir}/metaconfig" |
|
735 |
end |
|
736 |
|
|
737 |
def load_config(task) |
|
738 |
case task |
|
739 |
when 'config' |
|
740 |
ConfigTable.new |
|
741 |
when 'clean', 'distclean' |
|
742 |
if File.exist?(ConfigTable.savefile) |
|
743 |
then ConfigTable.load |
|
744 |
else ConfigTable.new |
|
745 |
end |
|
746 |
else |
|
747 |
ConfigTable.load |
|
748 |
end |
|
749 |
end |
|
750 |
|
|
751 |
def init_installers |
|
752 |
@installer = Installer.new(@config, @options, @ardir, File.expand_path('.')) |
|
753 |
end |
|
754 |
|
|
755 |
# |
|
756 |
# Hook Script API bases |
|
757 |
# |
|
758 |
|
|
759 |
def srcdir_root |
|
760 |
@ardir |
|
761 |
end |
|
762 |
|
|
763 |
def objdir_root |
|
764 |
'.' |
|
765 |
end |
|
766 |
|
|
767 |
def relpath |
|
768 |
'.' |
|
769 |
end |
|
770 |
|
|
771 |
# |
|
772 |
# Option Parsing |
|
773 |
# |
|
774 |
|
|
775 |
def parsearg_global |
|
776 |
valid_task = /\A(?:#{TASKS.map {|task,desc| task }.join '|'})\z/ |
|
777 |
|
|
778 |
while arg = ARGV.shift |
|
779 |
case arg |
|
780 |
when /\A\w+\z/ |
|
781 |
setup_rb_error "invalid task: #{arg}" unless valid_task =~ arg |
|
782 |
return arg |
|
783 |
|
|
784 |
when '-q', '--quiet' |
|
785 |
@options['verbose'] = false |
|
786 |
|
|
787 |
when '--verbose' |
|
788 |
@options['verbose'] = true |
|
789 |
|
|
790 |
when '-h', '--help' |
|
791 |
print_usage $stdout |
|
792 |
exit 0 |
|
793 |
|
|
794 |
when '-v', '--version' |
|
795 |
puts "#{File.basename($0)} version #{Version}" |
|
796 |
exit 0 |
|
797 |
|
|
798 |
when '--copyright' |
|
799 |
puts Copyright |
|
800 |
exit 0 |
|
801 |
|
|
802 |
else |
|
803 |
setup_rb_error "unknown global option '#{arg}'" |
|
804 |
end |
|
805 |
end |
|
806 |
|
|
807 |
nil |
|
808 |
end |
|
809 |
|
|
810 |
|
|
811 |
def parsearg_no_options |
|
812 |
unless ARGV.empty? |
|
813 |
setup_rb_error "#{task}: unknown options: #{ARGV.join ' '}" |
|
814 |
end |
|
815 |
end |
|
816 |
|
|
817 |
alias parsearg_show parsearg_no_options |
|
818 |
alias parsearg_setup parsearg_no_options |
|
819 |
alias parsearg_clean parsearg_no_options |
|
820 |
alias parsearg_distclean parsearg_no_options |
|
821 |
|
|
822 |
def parsearg_config |
|
823 |
re = /\A--(#{ConfigTable.map {|i| i.name }.join('|')})(?:=(.*))?\z/ |
|
824 |
@options['config-opt'] = [] |
|
825 |
|
|
826 |
while i = ARGV.shift |
|
827 |
if /\A--?\z/ =~ i |
|
828 |
@options['config-opt'] = ARGV.dup |
|
829 |
break |
|
830 |
end |
|
831 |
m = re.match(i) or setup_rb_error "config: unknown option #{i}" |
|
832 |
name, value = *m.to_a[1,2] |
|
833 |
@config[name] = value |
|
834 |
end |
|
835 |
end |
|
836 |
|
|
837 |
def parsearg_install |
|
838 |
@options['no-harm'] = false |
|
839 |
@options['install-prefix'] = '' |
|
840 |
while a = ARGV.shift |
|
841 |
case a |
|
842 |
when /\A--no-harm\z/ |
|
843 |
@options['no-harm'] = true |
|
844 |
when /\A--prefix=(.*)\z/ |
|
845 |
path = $1 |
|
846 |
path = File.expand_path(path) unless path[0,1] == '/' |
|
847 |
@options['install-prefix'] = path |
|
848 |
else |
|
849 |
setup_rb_error "install: unknown option #{a}" |
|
850 |
end |
|
851 |
end |
|
852 |
end |
|
853 |
|
|
854 |
def print_usage(out) |
|
855 |
out.puts 'Typical Installation Procedure:' |
|
856 |
out.puts " $ ruby #{File.basename $0} config" |
|
857 |
out.puts " $ ruby #{File.basename $0} setup" |
|
858 |
out.puts " # ruby #{File.basename $0} install (may require root privilege)" |
|
859 |
out.puts |
|
860 |
out.puts 'Detailed Usage:' |
|
861 |
out.puts " ruby #{File.basename $0} <global option>" |
|
862 |
out.puts " ruby #{File.basename $0} [<global options>] <task> [<task options>]" |
|
863 |
|
|
864 |
fmt = " %-24s %s\n" |
|
865 |
out.puts |
|
866 |
out.puts 'Global options:' |
|
867 |
out.printf fmt, '-q,--quiet', 'suppress message outputs' |
|
868 |
out.printf fmt, ' --verbose', 'output messages verbosely' |
|
869 |
out.printf fmt, '-h,--help', 'print this message' |
|
870 |
out.printf fmt, '-v,--version', 'print version and quit' |
|
871 |
out.printf fmt, ' --copyright', 'print copyright and quit' |
|
872 |
out.puts |
|
873 |
out.puts 'Tasks:' |
|
874 |
TASKS.each do |name, desc| |
|
875 |
out.printf fmt, name, desc |
|
876 |
end |
|
877 |
|
|
878 |
fmt = " %-24s %s [%s]\n" |
|
879 |
out.puts |
|
880 |
out.puts 'Options for CONFIG or ALL:' |
|
881 |
ConfigTable.each do |item| |
|
882 |
out.printf fmt, item.help_opt, item.description, item.help_default |
|
883 |
end |
|
884 |
out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's" |
|
885 |
out.puts |
|
886 |
out.puts 'Options for INSTALL:' |
|
887 |
out.printf fmt, '--no-harm', 'only display what to do if given', 'off' |
|
888 |
out.printf fmt, '--prefix=path', 'install path prefix', '$prefix' |
|
889 |
out.puts |
|
890 |
end |
|
891 |
|
|
892 |
# |
|
893 |
# Task Handlers |
|
894 |
# |
|
895 |
|
|
896 |
def exec_config |
|
897 |
@installer.exec_config |
|
898 |
@config.save # must be final |
|
899 |
end |
|
900 |
|
|
901 |
def exec_setup |
|
902 |
@installer.exec_setup |
|
903 |
end |
|
904 |
|
|
905 |
def exec_install |
|
906 |
@installer.exec_install |
|
907 |
end |
|
908 |
|
|
909 |
def exec_show |
|
910 |
ConfigTable.each do |i| |
|
911 |
printf "%-20s %s\n", i.name, i.value |
|
912 |
end |
|
913 |
end |
|
914 |
|
|
915 |
def exec_clean |
|
916 |
@installer.exec_clean |
|
917 |
end |
|
918 |
|
|
919 |
def exec_distclean |
|
920 |
@installer.exec_distclean |
|
921 |
end |
|
922 |
|
|
923 |
end |
|
924 |
|
|
925 |
|
|
926 |
class ToplevelInstallerMulti < ToplevelInstaller |
|
927 |
|
|
928 |
include HookUtils |
|
929 |
include HookScriptAPI |
|
930 |
include FileOperations |
|
931 |
|
|
932 |
def initialize(ardir) |
|
933 |
super |
|
934 |
@packages = all_dirs_in("#{@ardir}/packages") |
|
935 |
raise 'no package exists' if @packages.empty? |
|
936 |
end |
|
937 |
|
|
938 |
def run_metaconfigs |
|
939 |
eval_file_ifexist "#{@ardir}/metaconfig" |
|
940 |
@packages.each do |name| |
|
941 |
eval_file_ifexist "#{@ardir}/packages/#{name}/metaconfig" |
|
942 |
end |
|
943 |
end |
|
944 |
|
|
945 |
def init_installers |
|
946 |
@installers = {} |
|
947 |
@packages.each do |pack| |
|
948 |
@installers[pack] = Installer.new(@config, @options, |
|
949 |
"#{@ardir}/packages/#{pack}", |
|
950 |
"packages/#{pack}") |
|
951 |
end |
|
952 |
|
|
953 |
with = extract_selection(config('with')) |
|
954 |
without = extract_selection(config('without')) |
|
955 |
@selected = @installers.keys.select {|name| |
|
956 |
(with.empty? or with.include?(name)) \ |
|
957 |
and not without.include?(name) |
|
958 |
} |
|
959 |
end |
|
960 |
|
|
961 |
def extract_selection(list) |
|
962 |
a = list.split(/,/) |
|
963 |
a.each do |name| |
|
964 |
setup_rb_error "no such package: #{name}" unless @installers.key?(name) |
|
965 |
end |
|
966 |
a |
|
967 |
end |
|
968 |
|
|
969 |
def print_usage(f) |
|
970 |
super |
|
971 |
f.puts 'Included packages:' |
|
972 |
f.puts ' ' + @packages.sort.join(' ') |
|
973 |
f.puts |
Also available in: Unified diff
Replaces the repositories management SOAP API with a simple REST API.
reposman usage is unchanged but the script now requires activeresource.
actionwebservice is now longer used and thus removed from plugins.