Revision 1298:4f746d8966dd .svn/pristine/1c

View differences:

.svn/pristine/1c/1c133f685ba1e7aa677a1a8d5d646e268fcc08fc.svn-base
1
# Redmine - project management software
2
# Copyright (C) 2006-2011  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.expand_path('../../test_helper', __FILE__)
19

  
20
begin
21
  require 'mocha'
22
rescue
23
  # Won't run some tests
24
end
25

  
26
class AccountTest < ActionController::IntegrationTest
27
  fixtures :users, :roles
28

  
29
  # Replace this with your real tests.
30
  def test_login
31
    get "my/page"
32
    assert_redirected_to "/login?back_url=http%3A%2F%2Fwww.example.com%2Fmy%2Fpage"
33
    log_user('jsmith', 'jsmith')
34

  
35
    get "my/account"
36
    assert_response :success
37
    assert_template "my/account"
38
  end
39

  
40
  def test_autologin
41
    user = User.find(1)
42
    Setting.autologin = "7"
43
    Token.delete_all
44

  
45
    # User logs in with 'autologin' checked
46
    post '/login', :username => user.login, :password => 'admin', :autologin => 1
47
    assert_redirected_to '/my/page'
48
    token = Token.find :first
49
    assert_not_nil token
50
    assert_equal user, token.user
51
    assert_equal 'autologin', token.action
52
    assert_equal user.id, session[:user_id]
53
    assert_equal token.value, cookies['autologin']
54

  
55
    # Session is cleared
56
    reset!
57
    User.current = nil
58
    # Clears user's last login timestamp
59
    user.update_attribute :last_login_on, nil
60
    assert_nil user.reload.last_login_on
61

  
62
    # User comes back with his autologin cookie
63
    cookies[:autologin] = token.value
64
    get '/my/page'
65
    assert_response :success
66
    assert_template 'my/page'
67
    assert_equal user.id, session[:user_id]
68
    assert_not_nil user.reload.last_login_on
69
    assert user.last_login_on.utc > 10.second.ago.utc
70
  end
71

  
72
  def test_lost_password
73
    Token.delete_all
74

  
75
    get "account/lost_password"
76
    assert_response :success
77
    assert_template "account/lost_password"
78

  
79
    post "account/lost_password", :mail => 'jSmith@somenet.foo'
80
    assert_redirected_to "/login"
81

  
82
    token = Token.find(:first)
83
    assert_equal 'recovery', token.action
84
    assert_equal 'jsmith@somenet.foo', token.user.mail
85
    assert !token.expired?
86

  
87
    get "account/lost_password", :token => token.value
88
    assert_response :success
89
    assert_template "account/password_recovery"
90

  
91
    post "account/lost_password", :token => token.value, :new_password => 'newpass', :new_password_confirmation => 'newpass'
92
    assert_redirected_to "/login"
93
    assert_equal 'Password was successfully updated.', flash[:notice]
94

  
95
    log_user('jsmith', 'newpass')
96
    assert_equal 0, Token.count
97
  end
98

  
99
  def test_register_with_automatic_activation
100
    Setting.self_registration = '3'
101

  
102
    get 'account/register'
103
    assert_response :success
104
    assert_template 'account/register'
105

  
106
    post 'account/register', :user => {:login => "newuser", :language => "en", :firstname => "New", :lastname => "User", :mail => "newuser@foo.bar"},
107
                             :password => "newpass", :password_confirmation => "newpass"
108
    assert_redirected_to '/my/account'
109
    follow_redirect!
110
    assert_response :success
111
    assert_template 'my/account'
112

  
113
    user = User.find_by_login('newuser')
114
    assert_not_nil user
115
    assert user.active?
116
    assert_not_nil user.last_login_on
117
  end
118

  
119
  def test_register_with_manual_activation
120
    Setting.self_registration = '2'
121

  
122
    post 'account/register', :user => {:login => "newuser", :language => "en", :firstname => "New", :lastname => "User", :mail => "newuser@foo.bar"},
123
                             :password => "newpass", :password_confirmation => "newpass"
124
    assert_redirected_to '/login'
125
    assert !User.find_by_login('newuser').active?
126
  end
127

  
128
  def test_register_with_email_activation
129
    Setting.self_registration = '1'
130
    Token.delete_all
131

  
132
    post 'account/register', :user => {:login => "newuser", :language => "en", :firstname => "New", :lastname => "User", :mail => "newuser@foo.bar"},
133
                             :password => "newpass", :password_confirmation => "newpass"
134
    assert_redirected_to '/login'
135
    assert !User.find_by_login('newuser').active?
136

  
137
    token = Token.find(:first)
138
    assert_equal 'register', token.action
139
    assert_equal 'newuser@foo.bar', token.user.mail
140
    assert !token.expired?
141

  
142
    get 'account/activate', :token => token.value
143
    assert_redirected_to '/login'
144
    log_user('newuser', 'newpass')
145
  end
146

  
147
  if Object.const_defined?(:Mocha)
148

  
149
  def test_onthefly_registration
150
    # disable registration
151
    Setting.self_registration = '0'
152
    AuthSource.expects(:authenticate).returns({:login => 'foo', :firstname => 'Foo', :lastname => 'Smith', :mail => 'foo@bar.com', :auth_source_id => 66})
153

  
154
    post 'account/login', :username => 'foo', :password => 'bar'
155
    assert_redirected_to '/my/page'
156

  
157
    user = User.find_by_login('foo')
158
    assert user.is_a?(User)
159
    assert_equal 66, user.auth_source_id
160
    assert user.hashed_password.blank?
161
  end
162

  
163
  def test_onthefly_registration_with_invalid_attributes
164
    # disable registration
165
    Setting.self_registration = '0'
166
    AuthSource.expects(:authenticate).returns({:login => 'foo', :lastname => 'Smith', :auth_source_id => 66})
167

  
168
    post 'account/login', :username => 'foo', :password => 'bar'
169
    assert_response :success
170
    assert_template 'account/register'
171
    assert_tag :input, :attributes => { :name => 'user[firstname]', :value => '' }
172
    assert_tag :input, :attributes => { :name => 'user[lastname]', :value => 'Smith' }
173
    assert_no_tag :input, :attributes => { :name => 'user[login]' }
174
    assert_no_tag :input, :attributes => { :name => 'user[password]' }
175

  
176
    post 'account/register', :user => {:firstname => 'Foo', :lastname => 'Smith', :mail => 'foo@bar.com'}
177
    assert_redirected_to '/my/account'
178

  
179
    user = User.find_by_login('foo')
180
    assert user.is_a?(User)
181
    assert_equal 66, user.auth_source_id
182
    assert user.hashed_password.blank?
183
  end
184

  
185
  def test_login_and_logout_should_clear_session
186
    get '/login'
187
    sid = session[:session_id]
188

  
189
    post '/login', :username => 'admin', :password => 'admin'
190
    assert_redirected_to '/my/page'
191
    assert_not_equal sid, session[:session_id], "login should reset session"
192
    assert_equal 1, session[:user_id]
193
    sid = session[:session_id]
194

  
195
    get '/'
196
    assert_equal sid, session[:session_id]
197

  
198
    get '/logout'
199
    assert_not_equal sid, session[:session_id], "logout should reset session"
200
    assert_nil session[:user_id]
201
  end
202

  
203
  else
204
    puts 'Mocha is missing. Skipping tests.'
205
  end
206
end
.svn/pristine/1c/1c27182fa8ab48906fb7a4d556796242f651644e.svn-base
1
# encoding: utf-8
2
#
3
# Redmine - project management software
4
# Copyright (C) 2006-2013  Jean-Philippe Lang
5
#
6
# This program is free software; you can redistribute it and/or
7
# modify it under the terms of the GNU General Public License
8
# as published by the Free Software Foundation; either version 2
9
# of the License, or (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful,
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
# GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19

  
20
module Redmine
21
  module Pagination
22
    class Paginator
23
      attr_reader :item_count, :per_page, :page, :page_param
24

  
25
      def initialize(*args)
26
        if args.first.is_a?(ActionController::Base)
27
          args.shift
28
          ActiveSupport::Deprecation.warn "Paginator no longer takes a controller instance as the first argument. Remove it from #new arguments."
29
        end
30
        item_count, per_page, page, page_param = *args
31

  
32
        @item_count = item_count
33
        @per_page = per_page
34
        page = (page || 1).to_i
35
        if page < 1
36
          page = 1
37
        end
38
        @page = page
39
        @page_param = page_param || :page
40
      end
41

  
42
      def offset
43
        (page - 1) * per_page
44
      end
45

  
46
      def first_page
47
        if item_count > 0
48
          1
49
        end
50
      end
51

  
52
      def previous_page
53
        if page > 1
54
          page - 1
55
        end
56
      end
57

  
58
      def next_page
59
        if last_item < item_count
60
          page + 1
61
        end
62
      end
63

  
64
      def last_page
65
        if item_count > 0
66
          (item_count - 1) / per_page + 1
67
        end
68
      end
69

  
70
      def first_item
71
        item_count == 0 ? 0 : (offset + 1)
72
      end
73

  
74
      def last_item
75
        l = first_item + per_page - 1
76
        l > item_count ? item_count : l
77
      end
78

  
79
      def linked_pages
80
        pages = []
81
        if item_count > 0
82
          pages += [first_page, page, last_page]
83
          pages += ((page-2)..(page+2)).to_a.select {|p| p > first_page && p < last_page}
84
        end
85
        pages = pages.compact.uniq.sort
86
        if pages.size > 1
87
          pages
88
        else
89
          []
90
        end
91
      end
92

  
93
      def items_per_page
94
        ActiveSupport::Deprecation.warn "Paginator#items_per_page will be removed. Use #per_page instead."
95
        per_page
96
      end
97

  
98
      def current
99
        ActiveSupport::Deprecation.warn "Paginator#current will be removed. Use .offset instead of .current.offset."
100
        self
101
      end
102
    end
103

  
104
    # Paginates the given scope or model. Returns a Paginator instance and
105
    # the collection of objects for the current page.
106
    #
107
    # Options:
108
    #   :parameter     name of the page parameter
109
    #
110
    # Examples:
111
    #   @user_pages, @users = paginate User.where(:status => 1)
112
    #
113
    def paginate(scope, options={})
114
      options = options.dup
115
      finder_options = options.extract!(
116
        :conditions,
117
        :order,
118
        :joins,
119
        :include,
120
        :select
121
      )
122
      if scope.is_a?(Symbol) || finder_options.values.compact.any?
123
        return deprecated_paginate(scope, finder_options, options)
124
      end
125

  
126
      paginator = paginator(scope.count, options)
127
      collection = scope.limit(paginator.per_page).offset(paginator.offset).to_a
128

  
129
      return paginator, collection
130
    end
131

  
132
    def deprecated_paginate(arg, finder_options, options={})
133
      ActiveSupport::Deprecation.warn "#paginate with a Symbol and/or find options is depreceted and will be removed. Use a scope instead."
134
      klass = arg.is_a?(Symbol) ? arg.to_s.classify.constantize : arg
135
      scope = klass.scoped(finder_options)
136
      paginate(scope, options)
137
    end
138

  
139
    def paginator(item_count, options={})
140
      options.assert_valid_keys :parameter, :per_page
141

  
142
      page_param = options[:parameter] || :page
143
      page = (params[page_param] || 1).to_i
144
      per_page = options[:per_page] || per_page_option
145
      Paginator.new(item_count, per_page, page, page_param)
146
    end
147

  
148
    module Helper
149
      include Redmine::I18n
150

  
151
      # Renders the pagination links for the given paginator.
152
      #
153
      # Options:
154
      #   :per_page_links    if set to false, the "Per page" links are not rendered
155
      #
156
      def pagination_links_full(*args)
157
        pagination_links_each(*args) do |text, parameters, options|
158
          if block_given?
159
            yield text, parameters, options
160
          else
161
            link_to text, params.merge(parameters), options
162
          end
163
        end
164
      end
165

  
166
      # Yields the given block with the text and parameters
167
      # for each pagination link and returns a string that represents the links
168
      def pagination_links_each(paginator, count=nil, options={}, &block)
169
        options.assert_valid_keys :per_page_links
170

  
171
        per_page_links = options.delete(:per_page_links)
172
        per_page_links = false if count.nil?
173
        page_param = paginator.page_param
174

  
175
        html = ''
176
        if paginator.previous_page
177
          # \xc2\xab(utf-8) = &#171;
178
          text = "\xc2\xab " + l(:label_previous)
179
          html << yield(text, {page_param => paginator.previous_page}, :class => 'previous') + ' '
180
        end
181

  
182
        previous = nil
183
        paginator.linked_pages.each do |page|
184
          if previous && previous != page - 1
185
            html << content_tag('span', '...', :class => 'spacer') + ' '
186
          end
187
          if page == paginator.page
188
            html << content_tag('span', page.to_s, :class => 'current page')
189
          else
190
            html << yield(page.to_s, {page_param => page}, :class => 'page')
191
          end
192
          html << ' '
193
          previous = page
194
        end
195

  
196
        if paginator.next_page
197
          # \xc2\xbb(utf-8) = &#187;
198
          text = l(:label_next) + " \xc2\xbb"
199
          html << yield(text, {page_param => paginator.next_page}, :class => 'next') + ' '
200
        end
201

  
202
        html << content_tag('span', "(#{paginator.first_item}-#{paginator.last_item}/#{paginator.item_count})", :class => 'items') + ' '
203

  
204
        if per_page_links != false && links = per_page_links(paginator, &block)
205
          html << content_tag('span', links.to_s, :class => 'per-page')
206
        end
207

  
208
        html.html_safe
209
      end
210

  
211
      # Renders the "Per page" links.
212
      def per_page_links(paginator, &block)
213
        values = per_page_options(paginator.per_page, paginator.item_count)
214
        if values.any?
215
          links = values.collect do |n|
216
            if n == paginator.per_page
217
              content_tag('span', n.to_s)
218
            else
219
              yield(n, :per_page => n, paginator.page_param => nil)
220
            end
221
          end
222
          l(:label_display_per_page, links.join(', ')).html_safe
223
        end
224
      end
225

  
226
      def per_page_options(selected=nil, item_count=nil)
227
        options = Setting.per_page_options_array
228
        if item_count && options.any?
229
          if item_count > options.first
230
            max = options.detect {|value| value >= item_count} || item_count
231
          else
232
            max = item_count
233
          end
234
          options = options.select {|value| value <= max || value == selected}
235
        end
236
        if options.empty? || (options.size == 1 && options.first == selected)
237
          []
238
        else
239
          options
240
        end
241
      end
242
    end
243
  end
244
end
.svn/pristine/1c/1c5257cafbf7d7508949bf6ef73182b08b1fa87d.svn-base
1
#
2
# setup.rb
3
#
4
# Copyright (c) 2000-2005 Minero Aoki
5
#
6
# This program is free software.
7
# You can distribute/modify this program under the terms of
8
# the GNU LGPL, Lesser General Public License version 2.1.
9
#
10

  
11
unless Enumerable.method_defined?(:map)   # Ruby 1.4.6
12
  module Enumerable
13
    alias map collect
14
  end
15
end
16

  
17
unless File.respond_to?(:read)   # Ruby 1.6
18
  def File.read(fname)
19
    open(fname) {|f|
20
      return f.read
21
    }
22
  end
23
end
24

  
25
unless Errno.const_defined?(:ENOTEMPTY)   # Windows?
26
  module Errno
27
    class ENOTEMPTY
28
      # We do not raise this exception, implementation is not needed.
29
    end
30
  end
31
end
32

  
33
def File.binread(fname)
34
  open(fname, 'rb') {|f|
35
    return f.read
36
  }
37
end
38

  
39
# for corrupted Windows' stat(2)
40
def File.dir?(path)
41
  File.directory?((path[-1,1] == '/') ? path : path + '/')
42
end
43

  
44

  
45
class ConfigTable
46

  
47
  include Enumerable
48

  
49
  def initialize(rbconfig)
50
    @rbconfig = rbconfig
51
    @items = []
52
    @table = {}
53
    # options
54
    @install_prefix = nil
55
    @config_opt = nil
56
    @verbose = true
57
    @no_harm = false
58
  end
59

  
60
  attr_accessor :install_prefix
61
  attr_accessor :config_opt
62

  
63
  attr_writer :verbose
64

  
65
  def verbose?
66
    @verbose
67
  end
68

  
69
  attr_writer :no_harm
70

  
71
  def no_harm?
72
    @no_harm
73
  end
74

  
75
  def [](key)
76
    lookup(key).resolve(self)
77
  end
78

  
79
  def []=(key, val)
80
    lookup(key).set val
81
  end
82

  
83
  def names
84
    @items.map {|i| i.name }
85
  end
86

  
87
  def each(&block)
88
    @items.each(&block)
89
  end
90

  
91
  def key?(name)
92
    @table.key?(name)
93
  end
94

  
95
  def lookup(name)
96
    @table[name] or setup_rb_error "no such config item: #{name}"
97
  end
98

  
99
  def add(item)
100
    @items.push item
101
    @table[item.name] = item
102
  end
103

  
104
  def remove(name)
105
    item = lookup(name)
106
    @items.delete_if {|i| i.name == name }
107
    @table.delete_if {|name, i| i.name == name }
108
    item
109
  end
110

  
111
  def load_script(path, inst = nil)
112
    if File.file?(path)
113
      MetaConfigEnvironment.new(self, inst).instance_eval File.read(path), path
114
    end
115
  end
116

  
117
  def savefile
118
    '.config'
119
  end
120

  
121
  def load_savefile
122
    begin
123
      File.foreach(savefile()) do |line|
124
        k, v = *line.split(/=/, 2)
125
        self[k] = v.strip
126
      end
127
    rescue Errno::ENOENT
128
      setup_rb_error $!.message + "\n#{File.basename($0)} config first"
129
    end
130
  end
131

  
132
  def save
133
    @items.each {|i| i.value }
134
    File.open(savefile(), 'w') {|f|
135
      @items.each do |i|
136
        f.printf "%s=%s\n", i.name, i.value if i.value? and i.value
137
      end
138
    }
139
  end
140

  
141
  def load_standard_entries
142
    standard_entries(@rbconfig).each do |ent|
143
      add ent
144
    end
145
  end
146

  
147
  def standard_entries(rbconfig)
148
    c = rbconfig
149

  
150
    rubypath = File.join(c['bindir'], c['ruby_install_name'] + c['EXEEXT'])
151

  
152
    major = c['MAJOR'].to_i
153
    minor = c['MINOR'].to_i
154
    teeny = c['TEENY'].to_i
155
    version = "#{major}.#{minor}"
156

  
157
    # ruby ver. >= 1.4.4?
158
    newpath_p = ((major >= 2) or
159
                 ((major == 1) and
160
                  ((minor >= 5) or
161
                   ((minor == 4) and (teeny >= 4)))))
162

  
163
    if c['rubylibdir']
164
      # V > 1.6.3
165
      libruby         = "#{c['prefix']}/lib/ruby"
166
      librubyver      = c['rubylibdir']
167
      librubyverarch  = c['archdir']
168
      siteruby        = c['sitedir']
169
      siterubyver     = c['sitelibdir']
170
      siterubyverarch = c['sitearchdir']
171
    elsif newpath_p
172
      # 1.4.4 <= V <= 1.6.3
173
      libruby         = "#{c['prefix']}/lib/ruby"
174
      librubyver      = "#{c['prefix']}/lib/ruby/#{version}"
175
      librubyverarch  = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}"
176
      siteruby        = c['sitedir']
177
      siterubyver     = "$siteruby/#{version}"
178
      siterubyverarch = "$siterubyver/#{c['arch']}"
179
    else
180
      # V < 1.4.4
181
      libruby         = "#{c['prefix']}/lib/ruby"
182
      librubyver      = "#{c['prefix']}/lib/ruby/#{version}"
183
      librubyverarch  = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}"
184
      siteruby        = "#{c['prefix']}/lib/ruby/#{version}/site_ruby"
185
      siterubyver     = siteruby
186
      siterubyverarch = "$siterubyver/#{c['arch']}"
187
    end
188
    parameterize = lambda {|path|
189
      path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix')
190
    }
191

  
192
    if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg }
193
      makeprog = arg.sub(/'/, '').split(/=/, 2)[1]
194
    else
195
      makeprog = 'make'
196
    end
197

  
198
    [
199
      ExecItem.new('installdirs', 'std/site/home',
200
                   'std: install under libruby; site: install under site_ruby; home: install under $HOME')\
201
          {|val, table|
202
            case val
203
            when 'std'
204
              table['rbdir'] = '$librubyver'
205
              table['sodir'] = '$librubyverarch'
206
            when 'site'
207
              table['rbdir'] = '$siterubyver'
208
              table['sodir'] = '$siterubyverarch'
209
            when 'home'
210
              setup_rb_error '$HOME was not set' unless ENV['HOME']
211
              table['prefix'] = ENV['HOME']
212
              table['rbdir'] = '$libdir/ruby'
213
              table['sodir'] = '$libdir/ruby'
214
            end
215
          },
216
      PathItem.new('prefix', 'path', c['prefix'],
217
                   'path prefix of target environment'),
218
      PathItem.new('bindir', 'path', parameterize.call(c['bindir']),
219
                   'the directory for commands'),
220
      PathItem.new('libdir', 'path', parameterize.call(c['libdir']),
221
                   'the directory for libraries'),
222
      PathItem.new('datadir', 'path', parameterize.call(c['datadir']),
223
                   'the directory for shared data'),
224
      PathItem.new('mandir', 'path', parameterize.call(c['mandir']),
225
                   'the directory for man pages'),
226
      PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']),
227
                   'the directory for system configuration files'),
228
      PathItem.new('localstatedir', 'path', parameterize.call(c['localstatedir']),
229
                   'the directory for local state data'),
230
      PathItem.new('libruby', 'path', libruby,
231
                   'the directory for ruby libraries'),
232
      PathItem.new('librubyver', 'path', librubyver,
233
                   'the directory for standard ruby libraries'),
234
      PathItem.new('librubyverarch', 'path', librubyverarch,
235
                   'the directory for standard ruby extensions'),
236
      PathItem.new('siteruby', 'path', siteruby,
237
          'the directory for version-independent aux ruby libraries'),
238
      PathItem.new('siterubyver', 'path', siterubyver,
239
                   'the directory for aux ruby libraries'),
240
      PathItem.new('siterubyverarch', 'path', siterubyverarch,
241
                   'the directory for aux ruby binaries'),
242
      PathItem.new('rbdir', 'path', '$siterubyver',
243
                   'the directory for ruby scripts'),
244
      PathItem.new('sodir', 'path', '$siterubyverarch',
245
                   'the directory for ruby extentions'),
246
      PathItem.new('rubypath', 'path', rubypath,
247
                   'the path to set to #! line'),
248
      ProgramItem.new('rubyprog', 'name', rubypath,
249
                      'the ruby program using for installation'),
250
      ProgramItem.new('makeprog', 'name', makeprog,
251
                      'the make program to compile ruby extentions'),
252
      SelectItem.new('shebang', 'all/ruby/never', 'ruby',
253
                     'shebang line (#!) editing mode'),
254
      BoolItem.new('without-ext', 'yes/no', 'no',
255
                   'does not compile/install ruby extentions')
256
    ]
257
  end
258
  private :standard_entries
259

  
260
  def load_multipackage_entries
261
    multipackage_entries().each do |ent|
262
      add ent
263
    end
264
  end
265

  
266
  def multipackage_entries
267
    [
268
      PackageSelectionItem.new('with', 'name,name...', '', 'ALL',
269
                               'package names that you want to install'),
270
      PackageSelectionItem.new('without', 'name,name...', '', 'NONE',
271
                               'package names that you do not want to install')
272
    ]
273
  end
274
  private :multipackage_entries
275

  
276
  ALIASES = {
277
    'std-ruby'         => 'librubyver',
278
    'stdruby'          => 'librubyver',
279
    'rubylibdir'       => 'librubyver',
280
    'archdir'          => 'librubyverarch',
281
    'site-ruby-common' => 'siteruby',     # For backward compatibility
282
    'site-ruby'        => 'siterubyver',  # For backward compatibility
283
    'bin-dir'          => 'bindir',
284
    'bin-dir'          => 'bindir',
285
    'rb-dir'           => 'rbdir',
286
    'so-dir'           => 'sodir',
287
    'data-dir'         => 'datadir',
288
    'ruby-path'        => 'rubypath',
289
    'ruby-prog'        => 'rubyprog',
290
    'ruby'             => 'rubyprog',
291
    'make-prog'        => 'makeprog',
292
    'make'             => 'makeprog'
293
  }
294

  
295
  def fixup
296
    ALIASES.each do |ali, name|
297
      @table[ali] = @table[name]
298
    end
299
    @items.freeze
300
    @table.freeze
301
    @options_re = /\A--(#{@table.keys.join('|')})(?:=(.*))?\z/
302
  end
303

  
304
  def parse_opt(opt)
305
    m = @options_re.match(opt) or setup_rb_error "config: unknown option #{opt}"
306
    m.to_a[1,2]
307
  end
308

  
309
  def dllext
310
    @rbconfig['DLEXT']
311
  end
312

  
313
  def value_config?(name)
314
    lookup(name).value?
315
  end
316

  
317
  class Item
318
    def initialize(name, template, default, desc)
319
      @name = name.freeze
320
      @template = template
321
      @value = default
322
      @default = default
323
      @description = desc
324
    end
325

  
326
    attr_reader :name
327
    attr_reader :description
328

  
329
    attr_accessor :default
330
    alias help_default default
331

  
332
    def help_opt
333
      "--#{@name}=#{@template}"
334
    end
335

  
336
    def value?
337
      true
338
    end
339

  
340
    def value
341
      @value
342
    end
343

  
344
    def resolve(table)
345
      @value.gsub(%r<\$([^/]+)>) { table[$1] }
346
    end
347

  
348
    def set(val)
349
      @value = check(val)
350
    end
351

  
352
    private
353

  
354
    def check(val)
355
      setup_rb_error "config: --#{name} requires argument" unless val
356
      val
357
    end
358
  end
359

  
360
  class BoolItem < Item
361
    def config_type
362
      'bool'
363
    end
364

  
365
    def help_opt
366
      "--#{@name}"
367
    end
368

  
369
    private
370

  
371
    def check(val)
372
      return 'yes' unless val
373
      case val
374
      when /\Ay(es)?\z/i, /\At(rue)?\z/i then 'yes'
375
      when /\An(o)?\z/i, /\Af(alse)\z/i  then 'no'
376
      else
377
        setup_rb_error "config: --#{@name} accepts only yes/no for argument"
378
      end
379
    end
380
  end
381

  
382
  class PathItem < Item
383
    def config_type
384
      'path'
385
    end
386

  
387
    private
388

  
389
    def check(path)
390
      setup_rb_error "config: --#{@name} requires argument"  unless path
391
      path[0,1] == '$' ? path : File.expand_path(path)
392
    end
393
  end
394

  
395
  class ProgramItem < Item
396
    def config_type
397
      'program'
398
    end
399
  end
400

  
401
  class SelectItem < Item
402
    def initialize(name, selection, default, desc)
403
      super
404
      @ok = selection.split('/')
405
    end
406

  
407
    def config_type
408
      'select'
409
    end
410

  
411
    private
412

  
413
    def check(val)
414
      unless @ok.include?(val.strip)
415
        setup_rb_error "config: use --#{@name}=#{@template} (#{val})"
416
      end
417
      val.strip
418
    end
419
  end
420

  
421
  class ExecItem < Item
422
    def initialize(name, selection, desc, &block)
423
      super name, selection, nil, desc
424
      @ok = selection.split('/')
425
      @action = block
426
    end
427

  
428
    def config_type
429
      'exec'
430
    end
431

  
432
    def value?
433
      false
434
    end
435

  
436
    def resolve(table)
437
      setup_rb_error "$#{name()} wrongly used as option value"
438
    end
439

  
440
    undef set
441

  
442
    def evaluate(val, table)
443
      v = val.strip.downcase
444
      unless @ok.include?(v)
445
        setup_rb_error "invalid option --#{@name}=#{val} (use #{@template})"
446
      end
447
      @action.call v, table
448
    end
449
  end
450

  
451
  class PackageSelectionItem < Item
452
    def initialize(name, template, default, help_default, desc)
453
      super name, template, default, desc
454
      @help_default = help_default
455
    end
456

  
457
    attr_reader :help_default
458

  
459
    def config_type
460
      'package'
461
    end
462

  
463
    private
464

  
465
    def check(val)
466
      unless File.dir?("packages/#{val}")
467
        setup_rb_error "config: no such package: #{val}"
468
      end
469
      val
470
    end
471
  end
472

  
473
  class MetaConfigEnvironment
474
    def initialize(config, installer)
475
      @config = config
476
      @installer = installer
477
    end
478

  
479
    def config_names
480
      @config.names
481
    end
482

  
483
    def config?(name)
484
      @config.key?(name)
485
    end
486

  
487
    def bool_config?(name)
488
      @config.lookup(name).config_type == 'bool'
489
    end
490

  
491
    def path_config?(name)
492
      @config.lookup(name).config_type == 'path'
493
    end
494

  
495
    def value_config?(name)
496
      @config.lookup(name).config_type != 'exec'
497
    end
498

  
499
    def add_config(item)
500
      @config.add item
501
    end
502

  
503
    def add_bool_config(name, default, desc)
504
      @config.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc)
505
    end
506

  
507
    def add_path_config(name, default, desc)
508
      @config.add PathItem.new(name, 'path', default, desc)
509
    end
510

  
511
    def set_config_default(name, default)
512
      @config.lookup(name).default = default
513
    end
514

  
515
    def remove_config(name)
516
      @config.remove(name)
517
    end
518

  
519
    # For only multipackage
520
    def packages
521
      raise '[setup.rb fatal] multi-package metaconfig API packages() called for single-package; contact application package vendor' unless @installer
522
      @installer.packages
523
    end
524

  
525
    # For only multipackage
526
    def declare_packages(list)
527
      raise '[setup.rb fatal] multi-package metaconfig API declare_packages() called for single-package; contact application package vendor' unless @installer
528
      @installer.packages = list
529
    end
530
  end
531

  
532
end   # class ConfigTable
533

  
534

  
535
# This module requires: #verbose?, #no_harm?
536
module FileOperations
537

  
538
  def mkdir_p(dirname, prefix = nil)
539
    dirname = prefix + File.expand_path(dirname) if prefix
540
    $stderr.puts "mkdir -p #{dirname}" if verbose?
541
    return if no_harm?
542

  
543
    # Does not check '/', it's too abnormal.
544
    dirs = File.expand_path(dirname).split(%r<(?=/)>)
545
    if /\A[a-z]:\z/i =~ dirs[0]
546
      disk = dirs.shift
547
      dirs[0] = disk + dirs[0]
548
    end
549
    dirs.each_index do |idx|
550
      path = dirs[0..idx].join('')
551
      Dir.mkdir path unless File.dir?(path)
552
    end
553
  end
554

  
555
  def rm_f(path)
556
    $stderr.puts "rm -f #{path}" if verbose?
557
    return if no_harm?
558
    force_remove_file path
559
  end
560

  
561
  def rm_rf(path)
562
    $stderr.puts "rm -rf #{path}" if verbose?
563
    return if no_harm?
564
    remove_tree path
565
  end
566

  
567
  def remove_tree(path)
568
    if File.symlink?(path)
569
      remove_file path
570
    elsif File.dir?(path)
571
      remove_tree0 path
572
    else
573
      force_remove_file path
574
    end
575
  end
576

  
577
  def remove_tree0(path)
578
    Dir.foreach(path) do |ent|
579
      next if ent == '.'
580
      next if ent == '..'
581
      entpath = "#{path}/#{ent}"
582
      if File.symlink?(entpath)
583
        remove_file entpath
584
      elsif File.dir?(entpath)
585
        remove_tree0 entpath
586
      else
587
        force_remove_file entpath
588
      end
589
    end
590
    begin
591
      Dir.rmdir path
592
    rescue Errno::ENOTEMPTY
593
      # directory may not be empty
594
    end
595
  end
596

  
597
  def move_file(src, dest)
598
    force_remove_file dest
599
    begin
600
      File.rename src, dest
601
    rescue
602
      File.open(dest, 'wb') {|f|
603
        f.write File.binread(src)
604
      }
605
      File.chmod File.stat(src).mode, dest
606
      File.unlink src
607
    end
608
  end
609

  
610
  def force_remove_file(path)
611
    begin
612
      remove_file path
613
    rescue
614
    end
615
  end
616

  
617
  def remove_file(path)
618
    File.chmod 0777, path
619
    File.unlink path
620
  end
621

  
622
  def install(from, dest, mode, prefix = nil)
623
    $stderr.puts "install #{from} #{dest}" if verbose?
624
    return if no_harm?
625

  
626
    realdest = prefix ? prefix + File.expand_path(dest) : dest
627
    realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest)
628
    str = File.binread(from)
629
    if diff?(str, realdest)
630
      verbose_off {
631
        rm_f realdest if File.exist?(realdest)
632
      }
633
      File.open(realdest, 'wb') {|f|
634
        f.write str
635
      }
636
      File.chmod mode, realdest
637

  
638
      File.open("#{objdir_root()}/InstalledFiles", 'a') {|f|
639
        if prefix
640
          f.puts realdest.sub(prefix, '')
641
        else
642
          f.puts realdest
643
        end
644
      }
645
    end
646
  end
647

  
648
  def diff?(new_content, path)
649
    return true unless File.exist?(path)
650
    new_content != File.binread(path)
651
  end
652

  
653
  def command(*args)
654
    $stderr.puts args.join(' ') if verbose?
655
    system(*args) or raise RuntimeError,
656
        "system(#{args.map{|a| a.inspect }.join(' ')}) failed"
657
  end
658

  
659
  def ruby(*args)
660
    command config('rubyprog'), *args
661
  end
662
  
663
  def make(task = nil)
664
    command(*[config('makeprog'), task].compact)
665
  end
666

  
667
  def extdir?(dir)
668
    File.exist?("#{dir}/MANIFEST") or File.exist?("#{dir}/extconf.rb")
669
  end
670

  
671
  def files_of(dir)
672
    Dir.open(dir) {|d|
673
      return d.select {|ent| File.file?("#{dir}/#{ent}") }
674
    }
675
  end
676

  
677
  DIR_REJECT = %w( . .. CVS SCCS RCS CVS.adm .svn )
678

  
679
  def directories_of(dir)
680
    Dir.open(dir) {|d|
681
      return d.select {|ent| File.dir?("#{dir}/#{ent}") } - DIR_REJECT
682
    }
683
  end
684

  
685
end
686

  
687

  
688
# This module requires: #srcdir_root, #objdir_root, #relpath
689
module HookScriptAPI
690

  
691
  def get_config(key)
692
    @config[key]
693
  end
694

  
695
  alias config get_config
696

  
697
  # obsolete: use metaconfig to change configuration
698
  def set_config(key, val)
699
    @config[key] = val
700
  end
701

  
702
  #
703
  # srcdir/objdir (works only in the package directory)
704
  #
705

  
706
  def curr_srcdir
707
    "#{srcdir_root()}/#{relpath()}"
708
  end
709

  
710
  def curr_objdir
711
    "#{objdir_root()}/#{relpath()}"
712
  end
713

  
714
  def srcfile(path)
715
    "#{curr_srcdir()}/#{path}"
716
  end
717

  
718
  def srcexist?(path)
719
    File.exist?(srcfile(path))
720
  end
721

  
722
  def srcdirectory?(path)
723
    File.dir?(srcfile(path))
724
  end
725
  
726
  def srcfile?(path)
727
    File.file?(srcfile(path))
728
  end
729

  
730
  def srcentries(path = '.')
731
    Dir.open("#{curr_srcdir()}/#{path}") {|d|
732
      return d.to_a - %w(. ..)
733
    }
734
  end
735

  
736
  def srcfiles(path = '.')
737
    srcentries(path).select {|fname|
738
      File.file?(File.join(curr_srcdir(), path, fname))
739
    }
740
  end
741

  
742
  def srcdirectories(path = '.')
743
    srcentries(path).select {|fname|
744
      File.dir?(File.join(curr_srcdir(), path, fname))
745
    }
746
  end
747

  
748
end
749

  
750

  
751
class ToplevelInstaller
752

  
753
  Version   = '3.4.1'
754
  Copyright = 'Copyright (c) 2000-2005 Minero Aoki'
755

  
756
  TASKS = [
757
    [ 'all',      'do config, setup, then install' ],
758
    [ 'config',   'saves your configurations' ],
759
    [ 'show',     'shows current configuration' ],
760
    [ 'setup',    'compiles ruby extentions and others' ],
761
    [ 'install',  'installs files' ],
762
    [ 'test',     'run all tests in test/' ],
763
    [ 'clean',    "does `make clean' for each extention" ],
764
    [ 'distclean',"does `make distclean' for each extention" ]
765
  ]
766

  
767
  def ToplevelInstaller.invoke
768
    config = ConfigTable.new(load_rbconfig())
769
    config.load_standard_entries
770
    config.load_multipackage_entries if multipackage?
771
    config.fixup
772
    klass = (multipackage?() ? ToplevelInstallerMulti : ToplevelInstaller)
773
    klass.new(File.dirname($0), config).invoke
774
  end
775

  
776
  def ToplevelInstaller.multipackage?
777
    File.dir?(File.dirname($0) + '/packages')
778
  end
779

  
780
  def ToplevelInstaller.load_rbconfig
781
    if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg }
782
      ARGV.delete(arg)
783
      load File.expand_path(arg.split(/=/, 2)[1])
784
      $".push 'rbconfig.rb'
785
    else
786
      require 'rbconfig'
787
    end
788
    ::Config::CONFIG
789
  end
790

  
791
  def initialize(ardir_root, config)
792
    @ardir = File.expand_path(ardir_root)
793
    @config = config
794
    # cache
795
    @valid_task_re = nil
796
  end
797

  
798
  def config(key)
799
    @config[key]
800
  end
801

  
802
  def inspect
803
    "#<#{self.class} #{__id__()}>"
804
  end
805

  
806
  def invoke
807
    run_metaconfigs
808
    case task = parsearg_global()
809
    when nil, 'all'
810
      parsearg_config
811
      init_installers
812
      exec_config
813
      exec_setup
814
      exec_install
815
    else
816
      case task
817
      when 'config', 'test'
818
        ;
819
      when 'clean', 'distclean'
820
        @config.load_savefile if File.exist?(@config.savefile)
821
      else
822
        @config.load_savefile
823
      end
824
      __send__ "parsearg_#{task}"
825
      init_installers
826
      __send__ "exec_#{task}"
827
    end
828
  end
829
  
830
  def run_metaconfigs
831
    @config.load_script "#{@ardir}/metaconfig"
832
  end
833

  
834
  def init_installers
835
    @installer = Installer.new(@config, @ardir, File.expand_path('.'))
836
  end
837

  
838
  #
839
  # Hook Script API bases
840
  #
841

  
842
  def srcdir_root
843
    @ardir
844
  end
845

  
846
  def objdir_root
847
    '.'
848
  end
849

  
850
  def relpath
851
    '.'
852
  end
853

  
854
  #
855
  # Option Parsing
856
  #
857

  
858
  def parsearg_global
859
    while arg = ARGV.shift
860
      case arg
861
      when /\A\w+\z/
862
        setup_rb_error "invalid task: #{arg}" unless valid_task?(arg)
863
        return arg
864
      when '-q', '--quiet'
865
        @config.verbose = false
866
      when '--verbose'
867
        @config.verbose = true
868
      when '--help'
869
        print_usage $stdout
870
        exit 0
871
      when '--version'
872
        puts "#{File.basename($0)} version #{Version}"
873
        exit 0
874
      when '--copyright'
875
        puts Copyright
876
        exit 0
877
      else
878
        setup_rb_error "unknown global option '#{arg}'"
879
      end
880
    end
881
    nil
882
  end
883

  
884
  def valid_task?(t)
885
    valid_task_re() =~ t
886
  end
887

  
888
  def valid_task_re
889
    @valid_task_re ||= /\A(?:#{TASKS.map {|task,desc| task }.join('|')})\z/
890
  end
891

  
892
  def parsearg_no_options
893
    unless ARGV.empty?
894
      task = caller(0).first.slice(%r<`parsearg_(\w+)'>, 1)
895
      setup_rb_error "#{task}: unknown options: #{ARGV.join(' ')}"
896
    end
897
  end
898

  
899
  alias parsearg_show       parsearg_no_options
900
  alias parsearg_setup      parsearg_no_options
901
  alias parsearg_test       parsearg_no_options
902
  alias parsearg_clean      parsearg_no_options
903
  alias parsearg_distclean  parsearg_no_options
904

  
905
  def parsearg_config
906
    evalopt = []
907
    set = []
908
    @config.config_opt = []
909
    while i = ARGV.shift
910
      if /\A--?\z/ =~ i
911
        @config.config_opt = ARGV.dup
912
        break
913
      end
914
      name, value = *@config.parse_opt(i)
915
      if @config.value_config?(name)
916
        @config[name] = value
917
      else
918
        evalopt.push [name, value]
919
      end
920
      set.push name
921
    end
922
    evalopt.each do |name, value|
923
      @config.lookup(name).evaluate value, @config
924
    end
925
    # Check if configuration is valid
926
    set.each do |n|
927
      @config[n] if @config.value_config?(n)
928
    end
929
  end
930

  
931
  def parsearg_install
932
    @config.no_harm = false
933
    @config.install_prefix = ''
934
    while a = ARGV.shift
935
      case a
936
      when '--no-harm'
937
        @config.no_harm = true
938
      when /\A--prefix=/
939
        path = a.split(/=/, 2)[1]
940
        path = File.expand_path(path) unless path[0,1] == '/'
941
        @config.install_prefix = path
942
      else
943
        setup_rb_error "install: unknown option #{a}"
944
      end
945
    end
946
  end
947

  
948
  def print_usage(out)
949
    out.puts 'Typical Installation Procedure:'
950
    out.puts "  $ ruby #{File.basename $0} config"
951
    out.puts "  $ ruby #{File.basename $0} setup"
952
    out.puts "  # ruby #{File.basename $0} install (may require root privilege)"
953
    out.puts
954
    out.puts 'Detailed Usage:'
955
    out.puts "  ruby #{File.basename $0} <global option>"
956
    out.puts "  ruby #{File.basename $0} [<global options>] <task> [<task options>]"
957

  
958
    fmt = "  %-24s %s\n"
959
    out.puts
960
    out.puts 'Global options:'
961
    out.printf fmt, '-q,--quiet',   'suppress message outputs'
962
    out.printf fmt, '   --verbose', 'output messages verbosely'
963
    out.printf fmt, '   --help',    'print this message'
964
    out.printf fmt, '   --version', 'print version and quit'
965
    out.printf fmt, '   --copyright',  'print copyright and quit'
966
    out.puts
967
    out.puts 'Tasks:'
968
    TASKS.each do |name, desc|
969
      out.printf fmt, name, desc
970
    end
971

  
972
    fmt = "  %-24s %s [%s]\n"
973
    out.puts
974
    out.puts 'Options for CONFIG or ALL:'
975
    @config.each do |item|
976
      out.printf fmt, item.help_opt, item.description, item.help_default
977
    end
978
    out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's"
979
    out.puts
980
    out.puts 'Options for INSTALL:'
981
    out.printf fmt, '--no-harm', 'only display what to do if given', 'off'
982
    out.printf fmt, '--prefix=path',  'install path prefix', ''
983
    out.puts
984
  end
985

  
986
  #
987
  # Task Handlers
988
  #
989

  
990
  def exec_config
991
    @installer.exec_config
992
    @config.save   # must be final
993
  end
994

  
995
  def exec_setup
996
    @installer.exec_setup
997
  end
998

  
999
  def exec_install
1000
    @installer.exec_install
1001
  end
1002

  
1003
  def exec_test
1004
    @installer.exec_test
1005
  end
1006

  
1007
  def exec_show
1008
    @config.each do |i|
1009
      printf "%-20s %s\n", i.name, i.value if i.value?
1010
    end
1011
  end
1012

  
1013
  def exec_clean
1014
    @installer.exec_clean
1015
  end
1016

  
1017
  def exec_distclean
1018
    @installer.exec_distclean
1019
  end
1020

  
1021
end   # class ToplevelInstaller
1022

  
1023

  
1024
class ToplevelInstallerMulti < ToplevelInstaller
1025

  
1026
  include FileOperations
1027

  
1028
  def initialize(ardir_root, config)
1029
    super
1030
    @packages = directories_of("#{@ardir}/packages")
1031
    raise 'no package exists' if @packages.empty?
1032
    @root_installer = Installer.new(@config, @ardir, File.expand_path('.'))
1033
  end
1034

  
1035
  def run_metaconfigs
1036
    @config.load_script "#{@ardir}/metaconfig", self
1037
    @packages.each do |name|
1038
      @config.load_script "#{@ardir}/packages/#{name}/metaconfig"
1039
    end
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff