godfat-rubycas-server 0.8.0.20090918

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. data/CHANGELOG.txt +1 -0
  2. data/History.txt +273 -0
  3. data/LICENSE.txt +504 -0
  4. data/Manifest.txt +83 -0
  5. data/PostInstall.txt +3 -0
  6. data/README.rdoc +26 -0
  7. data/Rakefile +115 -0
  8. data/bin/rubycas-server +13 -0
  9. data/bin/rubycas-server-ctl +9 -0
  10. data/config.example.yml +555 -0
  11. data/config.ru +38 -0
  12. data/config/hoe.rb +78 -0
  13. data/config/requirements.rb +15 -0
  14. data/custom_views.example.rb +11 -0
  15. data/lib/casserver.rb +58 -0
  16. data/lib/casserver/authenticators/active_directory_ldap.rb +11 -0
  17. data/lib/casserver/authenticators/authlogic_crypto_providers/aes256.rb +43 -0
  18. data/lib/casserver/authenticators/authlogic_crypto_providers/bcrypt.rb +92 -0
  19. data/lib/casserver/authenticators/authlogic_crypto_providers/md5.rb +34 -0
  20. data/lib/casserver/authenticators/authlogic_crypto_providers/sha1.rb +35 -0
  21. data/lib/casserver/authenticators/authlogic_crypto_providers/sha512.rb +50 -0
  22. data/lib/casserver/authenticators/base.rb +48 -0
  23. data/lib/casserver/authenticators/client_certificate.rb +46 -0
  24. data/lib/casserver/authenticators/google.rb +54 -0
  25. data/lib/casserver/authenticators/ldap.rb +147 -0
  26. data/lib/casserver/authenticators/ntlm.rb +88 -0
  27. data/lib/casserver/authenticators/open_id.rb +22 -0
  28. data/lib/casserver/authenticators/sql.rb +119 -0
  29. data/lib/casserver/authenticators/sql_authlogic.rb +92 -0
  30. data/lib/casserver/authenticators/sql_encrypted.rb +92 -0
  31. data/lib/casserver/authenticators/sql_md5.rb +19 -0
  32. data/lib/casserver/authenticators/sql_rest_auth.rb +71 -0
  33. data/lib/casserver/authenticators/test.rb +19 -0
  34. data/lib/casserver/cas.rb +322 -0
  35. data/lib/casserver/conf.rb +75 -0
  36. data/lib/casserver/controllers.rb +463 -0
  37. data/lib/casserver/load_picnic.rb +19 -0
  38. data/lib/casserver/localization.rb +82 -0
  39. data/lib/casserver/models.rb +265 -0
  40. data/lib/casserver/postambles.rb +174 -0
  41. data/lib/casserver/utils.rb +30 -0
  42. data/lib/casserver/version.rb +9 -0
  43. data/lib/casserver/views.rb +249 -0
  44. data/lib/rubycas-server.rb +1 -0
  45. data/lib/rubycas-server/version.rb +1 -0
  46. data/po/de_DE/rubycas-server.po +119 -0
  47. data/po/es_ES/rubycas-server.po +115 -0
  48. data/po/fr_FR/rubycas-server.po +116 -0
  49. data/po/ja_JP/rubycas-server.po +118 -0
  50. data/po/pl_PL/rubycas-server.po +115 -0
  51. data/po/pt_BR/rubycas-server.po +115 -0
  52. data/po/ru_RU/rubycas-server.po +110 -0
  53. data/po/rubycas-server.pot +104 -0
  54. data/public/themes/cas.css +121 -0
  55. data/public/themes/notice.png +0 -0
  56. data/public/themes/ok.png +0 -0
  57. data/public/themes/simple/bg.png +0 -0
  58. data/public/themes/simple/login_box_bg.png +0 -0
  59. data/public/themes/simple/logo.png +0 -0
  60. data/public/themes/simple/theme.css +28 -0
  61. data/public/themes/urbacon/bg.png +0 -0
  62. data/public/themes/urbacon/login_box_bg.png +0 -0
  63. data/public/themes/urbacon/logo.png +0 -0
  64. data/public/themes/urbacon/theme.css +33 -0
  65. data/public/themes/warning.png +0 -0
  66. data/resources/init.d.sh +58 -0
  67. data/script/console +10 -0
  68. data/script/destroy +14 -0
  69. data/script/generate +14 -0
  70. data/script/txt2html +82 -0
  71. data/setup.rb +1585 -0
  72. data/tasks/deployment.rake +34 -0
  73. data/tasks/environment.rake +7 -0
  74. data/tasks/localization.rake +11 -0
  75. data/tasks/website.rake +17 -0
  76. data/vendor/isaac_0.9.1/LICENSE +26 -0
  77. data/vendor/isaac_0.9.1/README +78 -0
  78. data/vendor/isaac_0.9.1/TODO +3 -0
  79. data/vendor/isaac_0.9.1/VERSIONS +3 -0
  80. data/vendor/isaac_0.9.1/crypt/ISAAC.rb +171 -0
  81. data/vendor/isaac_0.9.1/isaac.gemspec +39 -0
  82. data/vendor/isaac_0.9.1/setup.rb +596 -0
  83. data/vendor/isaac_0.9.1/test/TC_ISAAC.rb +76 -0
  84. metadata +200 -0
@@ -0,0 +1,34 @@
1
+ desc 'Release the website and new gem version'
2
+ task :deploy => [:check_version, :website, :release] do
3
+ puts "Remember to create SVN tag:"
4
+ puts "svn copy svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/trunk " +
5
+ "svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/tags/REL-#{VERS} "
6
+ puts "Suggested comment:"
7
+ puts "Tagging release #{CHANGES}"
8
+ end
9
+
10
+ desc 'Runs tasks website_generate and install_gem as a local deployment of the gem'
11
+ task :local_deploy => [:website_generate, :install_gem]
12
+
13
+ task :check_version do
14
+ unless ENV['VERSION']
15
+ puts 'Must pass a VERSION=x.y.z release version'
16
+ exit
17
+ end
18
+ unless ENV['VERSION'] == VERS
19
+ puts "Please update your version.rb to match the release version, currently #{VERS}"
20
+ exit
21
+ end
22
+ end
23
+
24
+ desc 'Install the package as a gem, without generating documentation(ri/rdoc)'
25
+ task :install_gem_no_doc => [:clean, :package] do
26
+ sh "#{'sudo ' unless Hoe::WINDOZE }gem install pkg/*.gem --no-rdoc --no-ri"
27
+ end
28
+
29
+ namespace :manifest do
30
+ desc 'Recreate Manifest.txt to include ALL files'
31
+ task :refresh do
32
+ `rake check_manifest | patch -p0 > Manifest.txt`
33
+ end
34
+ end
@@ -0,0 +1,7 @@
1
+ task :ruby_env do
2
+ RUBY_APP = if RUBY_PLATFORM =~ /java/
3
+ "jruby"
4
+ else
5
+ "ruby"
6
+ end unless defined? RUBY_APP
7
+ end
@@ -0,0 +1,11 @@
1
+ desc 'Creates po files'
2
+ task :po do
3
+ require 'gettext/utils'
4
+ GetText.update_pofiles("rubycas-server", Dir.glob("{lib,bin}/**/*.{rb}"), "rubycas-server ")
5
+ end
6
+
7
+ desc 'Creates mo files from po files and puts them to locale dir'
8
+ task :mo do
9
+ require 'gettext/utils'
10
+ GetText.create_mofiles(true, "po", "locale")
11
+ end
@@ -0,0 +1,17 @@
1
+ desc 'Generate website files'
2
+ task :website_generate => :ruby_env do
3
+ (Dir['website/**/*.txt'] - Dir['website/version*.txt']).each do |txt|
4
+ sh %{ #{RUBY_APP} script/txt2html #{txt} > #{txt.gsub(/txt$/,'html')} }
5
+ end
6
+ end
7
+
8
+ desc 'Upload website files to rubyforge'
9
+ task :website_upload do
10
+ host = "#{rubyforge_username}@rubyforge.org"
11
+ remote_dir = "/var/www/gforge-projects/#{PATH}/"
12
+ local_dir = 'website'
13
+ sh %{rsync -aCv #{local_dir}/ #{host}:#{remote_dir}}
14
+ end
15
+
16
+ desc 'Generate and upload website files'
17
+ task :website => [:website_generate, :website_upload, :publish_docs]
@@ -0,0 +1,26 @@
1
+ Copyright (c) 2004 - 2005 Kirk Haines (khaines@enigo.com)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ For details about the ISAAC algorithm itself, see:
15
+
16
+ http://burtleburtle.net/bob/rand/isaac.html
17
+
18
+
19
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
23
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
+
@@ -0,0 +1,78 @@
1
+ Crypt::ISAAC README
2
+ ============
3
+
4
+ ISAAC is a cryptographically secure PRNG for generating high quality random
5
+ numbers. Detailed information about the algorithm can be found at:
6
+
7
+ http://burtleburtle.net/bob/rand/isaac.html
8
+
9
+ This is a pure Ruby implementation of the algorithm. It is reasonably fast for
10
+ a pure Ruby implementation. On an 800Mhz PIII computer running Ruby 1.8.2,
11
+ and while the machine is also serving as general desktop, the library seems to
12
+ consistently generate between 15000 and 16000 random numbers per second.
13
+
14
+ Ruby uses the Mersenne Twister as its PRNG, and while this the Twister is
15
+ a fast PRNG that produces highly random numbers, it is not strong for
16
+ cryptographic purposes, nor is it suitable when one needs multiple
17
+ independent streams of random numbers. Crypt::ISAAC is suitable for either
18
+ purpose.
19
+
20
+
21
+ Requirements
22
+ ------------
23
+
24
+ * Ruby 1.8 (should also run on 1.6.x)
25
+
26
+
27
+ Install
28
+ -------
29
+
30
+ If you have never installed Crypt::ISAAC, you may run the testsuite
31
+ to confirm that it works with:
32
+
33
+ # ruby setup.rb test
34
+
35
+ If you already have a version of Crypt::ISAAC installed, but want to
36
+ confirm this one before installing, run the test suite manually as
37
+ follows:
38
+
39
+ # ruby test/TC_ISAAC.rb local
40
+
41
+ When you are ready to install Crypt::ISAAC, type:
42
+
43
+ # ruby setup.rb install
44
+
45
+ This one step will install Crypt::ISAAC in your Ruby SITELIB. To test
46
+ the library after installation:
47
+
48
+ # ruby setup.rb test
49
+
50
+ Usage
51
+ -----
52
+
53
+ require 'crypt/ISAAC'
54
+
55
+ rng = Crypt::ISAAC.new
56
+
57
+ r1 = rng.rand() # returns a floating point between 0 and 1
58
+ r2 = rnd.rand(1000) # returns an integer between 0 and 999
59
+
60
+ rand() should work identically to the Kernel.rand().
61
+
62
+ Enjoy it. Let me know if you find anything that can be improved or that
63
+ needs to be fixed.
64
+
65
+
66
+ License
67
+ -------
68
+
69
+ The Crypt::ISAAC library is licensed with an MIT style licence.
70
+ See the LICENSE file for details. As for the ISAAC algorithm itself,
71
+ see:
72
+
73
+ http://burtleburtle.net/bob/rand/isaac.html
74
+
75
+
76
+
77
+ Kirk Haines
78
+ khaines@enigo.com
@@ -0,0 +1,3 @@
1
+ * Add a C version of the ISAAC algorithm and make it possible to install
2
+ the pure Ruby version and/or a version using a C extension for better
3
+ performance.
@@ -0,0 +1,3 @@
1
+ * 0.9 Initial public release. Pure Ruby.
2
+ * 0.9.1 Update to tweak a couple things and reorganize project struct.
3
+ Now uses a Package based installer, or can be installed as a gem.
@@ -0,0 +1,171 @@
1
+ module Crypt
2
+
3
+ # ISAAC is a fast, strong random number generator. Details on the
4
+ # algorithm can be found here: http://burtleburtle.net/bob/rand/isaac.html
5
+ # This provides a consistent and capable algorithm for producing
6
+ # independent streams of quality random numbers.
7
+
8
+ class ISAAC
9
+
10
+ attr_accessor :randrsl, :randcnt
11
+ attr_accessor :mm, :aa, :bb, :cc
12
+
13
+ # When a Crypt::ISAAC object is created, it needs to be seeded for
14
+ # random number generation. If the system has a /dev/urandom file,
15
+ # that will be used to do the seeding by default. If false is explictly
16
+ # passed when creating the object, it will instead use /dev/random to
17
+ # generate its seeds. Be warned that this may make for SLOW
18
+ # initialization.
19
+ # If the requested source (/dev/urandom or /dev/random) do not exist,
20
+ # the system will fall back to a simplistic initialization mechanism
21
+ # using the builtin Mersenne Twister PRNG.
22
+
23
+ def initialize(noblock = true)
24
+ @mm = []
25
+ @randrsl = []
26
+ # Best initialization of the generator would be by pulling
27
+ # numbers from /dev/random.
28
+ rnd_source = noblock ? '/dev/urandom' : '/dev/random'
29
+ if (FileTest.exist? rnd_source)
30
+ File.open(rnd_source,'r') do |r|
31
+ 256.times do |t|
32
+ z = r.read(4)
33
+ x = z.unpack('V')[0]
34
+ @randrsl[t] = x
35
+ end
36
+ end
37
+ else
38
+ # If urandom isn't available, the standard Ruby PRNG makes an
39
+ # adequate fallback.
40
+ 256.times do |t|
41
+ @randrsl[t] = Kernel.rand(4294967295)
42
+ end
43
+ end
44
+ randinit(true)
45
+ nil
46
+ end
47
+
48
+ # Works just like the standard rand() function. If called with an
49
+ # integer argument, rand() will return positive random number in
50
+ # the range of 0 to (argument - 1). If called without an integer
51
+ # argument, rand() returns a positive floating point number less than 1.
52
+
53
+ def rand(*num)
54
+ if (@randcnt == 1)
55
+ isaac
56
+ @randcnt = 256
57
+ end
58
+ @randcnt -= 1
59
+ if num[0].to_i > 0
60
+ @randrsl[@randcnt].modulo(num[0])
61
+ else
62
+ ".#{@randrsl[@randcnt]}".to_f
63
+ end
64
+ end
65
+
66
+ def isaac
67
+ i = 0
68
+ x = 0
69
+ y = 0
70
+
71
+ @cc += 1
72
+ @bb += @cc
73
+ @bb & 0xffffffff
74
+
75
+ while (i < 256) do
76
+ x = @mm[i]
77
+ @aa = (@mm[(i + 128) & 255] + (@aa^(@aa << 13)) ) & 0xffffffff
78
+ @mm[i] = y = (@mm[(x>>2)&255] + @aa + @bb ) & 0xffffffff
79
+ @randrsl[i] = @bb = (@mm[(y>>10)&255] + x ) & 0xffffffff
80
+ i += 1
81
+
82
+ x = @mm[i]
83
+ @aa = (@mm[(i+128)&255] + (@aa^(0x03ffffff & (@aa >> 6))) ) & 0xffffffff
84
+ @mm[i] = y = (@mm[(x>>2)&255] + @aa + @bb ) & 0xffffffff
85
+ @randrsl[i] = @bb = (@mm[(y>>10)&255] + x ) & 0xffffffff
86
+ i += 1
87
+
88
+ x = @mm[i]
89
+ @aa = (@mm[(i + 128)&255] + (@aa^(@aa << 2)) ) & 0xffffffff
90
+ @mm[i] = y = (@mm[(x>>2)&255] + @aa + @bb ) & 0xffffffff
91
+ @randrsl[i] = @bb = (@mm[(y>>10)&255] + x ) & 0xffffffff
92
+ i += 1
93
+
94
+ x = @mm[i]
95
+ @aa = (@mm[(i+128)&255] + (@aa^(0x0000ffff & (@aa >> 16))) ) & 0xffffffff
96
+ @mm[i] = y = (@mm[(x>>2)&255] + @aa + @bb ) & 0xffffffff
97
+ @randrsl[i] = @bb = (@mm[(y>>10)&255] + x ) & 0xffffffff
98
+ i += 1
99
+ end
100
+ end
101
+
102
+ def randinit(flag)
103
+ i = 0
104
+ a = 0
105
+ b = 0
106
+ c = 0
107
+ d = 0
108
+ e = 0
109
+ f = 0
110
+ g = 0
111
+ @aa = @bb = @cc = 0
112
+ a = b = c = d = e = f = g = h = 0x9e3779b9
113
+
114
+ while (i < 4) do
115
+ a ^= b<<1; d += a; b += c
116
+ b ^= 0x3fffffff & (c>>2); e += b; c += d
117
+ c ^= d << 8; f += c; d += e
118
+ d ^= 0x0000ffff & (e >> 16); g += d; e += f
119
+ e ^= f << 10; h += e; f += g
120
+ f ^= 0x0fffffff & (g >> 4); a += f; g += h
121
+ g ^= h << 8; b += g; h += a
122
+ h ^= 0x007fffff & (a >> 9); c += h; a += b
123
+ i += 1
124
+ end
125
+
126
+ i = 0
127
+ while (i < 256) do
128
+ if (flag)
129
+ a+=@randrsl[i ].to_i; b+=@randrsl[i+1].to_i;
130
+ c+=@randrsl[i+2]; d+=@randrsl[i+3];
131
+ e+=@randrsl[i+4]; f+=@randrsl[i+5];
132
+ g+=@randrsl[i+6]; h+=@randrsl[i+7];
133
+ end
134
+
135
+ a^=b<<11; d+=a; b+=c;
136
+ b^=0x3fffffff & (c>>2); e+=b; c+=d;
137
+ c^=d<<8; f+=c; d+=e;
138
+ d^=0x0000ffff & (e>>16); g+=d; e+=f;
139
+ e^=f<<10; h+=e; f+=g;
140
+ f^=0x0fffffff & (g>>4); a+=f; g+=h;
141
+ g^=h<<8; b+=g; h+=a;
142
+ h^=0x007fffff & (a>>9); c+=h; a+=b;
143
+ @mm[i]=a;@mm[i+1]=b; @mm[i+2]=c; @mm[i+3]=d;
144
+ @mm[i+4]=e; @mm[i+5]=f; @mm[i+6]=g; @mm[i+7]=h;
145
+ i += 8
146
+ end
147
+
148
+ if flag
149
+ i = 0
150
+ while (i < 256)
151
+ a+=@mm[i ]; b+=@mm[i+1]; c+=@mm[i+2]; d+=@mm[i+3];
152
+ e+=@mm[i+4]; f+=@mm[i+5]; g+=@mm[i+6]; h+=@mm[i+7];
153
+ a^=b<<11; d+=a; b+=c;
154
+ b^=0x3fffffff & (c>>2); e+=b; c+=d;
155
+ c^=d<<8; f+=c; d+=e;
156
+ d^=0x0000ffff & (e>>16); g+=d; e+=f;
157
+ e^=f<<10; h+=e; f+=g;
158
+ f^=0x0fffffff & (g>>4); a+=f; g+=h;
159
+ g^=h<<8; b+=g; h+=a;
160
+ h^=0x007fffff & (a>>9); c+=h; a+=b;
161
+ @mm[i ]=a; @mm[i+1]=b; @mm[i+2]=c; @mm[i+3]=d;
162
+ @mm[i+4]=e; @mm[i+5]=f; @mm[i+6]=g; @mm[i+7]=h;
163
+ i += 8
164
+ end
165
+ end
166
+
167
+ isaac()
168
+ @randcnt=256; # /* prepare to use the first set of results */
169
+ end
170
+ end
171
+ end
@@ -0,0 +1,39 @@
1
+ #####
2
+ # Crypt::ISAAC
3
+ # http://rubyforge.org/projects/crypt-isaac/
4
+ # Copyright 2004-2005 Kirk Haines
5
+ #
6
+ # Licensed under the Ruby License. See the README for details.
7
+ #
8
+ #####
9
+
10
+ spec = Gem::Specification.new do |s|
11
+ s.name = 'Crypt::ISAAC'
12
+ s.version = '0.9.1'
13
+ s.summary = %q(Ruby implementation of the ISAAC PRNG)
14
+ s.platform = Gem::Platform::RUBY
15
+
16
+ s.has_rdoc = true
17
+ s.rdoc_options = %w(--title Crypt::ISAAC --main README --line-numbers)
18
+ s.extra_rdoc_files = %w(README)
19
+
20
+ s.files = %w(README LICENSE TODO VERSIONS setup.rb isaac.gemspec test/TC_ISAAC.rb crypt/ISAAC.rb)
21
+
22
+ s.test_files = ['test/TC_ISAAC.rb']
23
+
24
+ s.require_paths = %w(crypt)
25
+
26
+ s.author = %q(Kirk Haines)
27
+ s.email = %q(khaines@enigo.com)
28
+ s.rubyforge_project = %q(crypt-isaac)
29
+ s.homepage = %q(http://rubyforge.org/projects/crypt-isaac)
30
+ description = []
31
+ File.open("README") do |file|
32
+ file.each do |line|
33
+ line.chomp!
34
+ break if line.empty?
35
+ description << "#{line.gsub(/\[\d\]/, '')}"
36
+ end
37
+ end
38
+ s.description = description[1..-1].join(" ")
39
+ end
@@ -0,0 +1,596 @@
1
+ require 'rbconfig'
2
+ require 'fileutils'
3
+ require 'pp'
4
+ require 'optparse'
5
+ require 'yaml'
6
+
7
+ module Package
8
+
9
+ class SpecificationError < StandardError; end
10
+ # forward declaration of the specification classes so we can keep all
11
+ # constants here
12
+ class PackageSpecification_1_0; end
13
+ # Default semantics
14
+ PackageSpecification = PackageSpecification_1_0
15
+
16
+ #TODO: could get this collected automatically with Class#inherited etc
17
+ SEMANTICS = { "1.0" => PackageSpecification_1_0 }
18
+
19
+ KINDS = [
20
+ :bin, :lib, :ext, :data, :conf, :doc
21
+ ]
22
+
23
+ #{{{ list of files to be ignored stolen from setup.rb
24
+ mapping = { '.' => '\.', '$' => '\$', '#' => '\#', '*' => '.*' }
25
+ ignore_files = %w[core RCSLOG tags TAGS .make.state .nse_depinfo
26
+ #* .#* cvslog.* ,* .del-* *.olb *~ *.old *.bak *.BAK *.orig *.rej _$* *$
27
+ *.org *.in .* ]
28
+ #end of robbery
29
+ IGNORE_FILES = ignore_files.map do |x|
30
+ Regexp.new('\A' + x.gsub(/[\.\$\#\*]/){|c| mapping[c]} + '\z')
31
+ end
32
+
33
+ def self.config(name)
34
+ # XXX use pathname
35
+ prefix = Regexp.quote(Config::CONFIG["prefix"])
36
+ exec_prefix = Regexp.quote(Config::CONFIG["exec_prefix"])
37
+ Config::CONFIG[name].gsub(/\A\/?(#{prefix}|#{exec_prefix})\/?/, '')
38
+ end
39
+
40
+ SITE_DIRS = {
41
+ :bin => config("bindir"),
42
+ :lib => config("sitelibdir"),
43
+ :ext => config("sitearchdir"),
44
+ :data => config("datadir"),
45
+ :conf => config("sysconfdir"),
46
+ :doc => File.join(config("datadir"), "doc"),
47
+ }
48
+
49
+ VENDOR_DIRS = {
50
+ :bin => config("bindir"),
51
+ :lib => config("rubylibdir"),
52
+ :ext => config("archdir"),
53
+ :data => config("datadir"),
54
+ :conf => config("sysconfdir"),
55
+ :doc => File.join(config("datadir"), "doc"),
56
+ }
57
+
58
+ MODES = {
59
+ :bin => 0755,
60
+ :lib => 0644,
61
+ :ext => 0755, # was: 0555,
62
+ :data => 0644,
63
+ :conf => 0644,
64
+ :doc => 0644,
65
+ }
66
+
67
+
68
+ SETUP_OPTIONS = {:parse_cmdline => true, :load_conf => true, :run_tasks => true}
69
+
70
+ def self.setup(version, options = {}, &instructions)
71
+ prefixes = dirs = nil
72
+ options = SETUP_OPTIONS.dup.update(options)
73
+
74
+ if options[:load_conf] && File.exist?("config.save")
75
+ config = YAML.load_file "config.save"
76
+ prefixes = config[:prefixes]
77
+ dirs = config[:dirs]
78
+ end
79
+
80
+ pkg = package_specification_with_semantics(version).new(prefixes, dirs)
81
+ pkg.parse_command_line if options[:parse_cmdline]
82
+ pkg.instance_eval(&instructions)
83
+
84
+ pkg.run_tasks if options[:run_tasks]
85
+
86
+ # pkg.install
87
+ pkg
88
+ end
89
+
90
+ def self.package_specification_with_semantics(version)
91
+ #XXX: implement the full x.y(.z)? semantics
92
+ r = SEMANTICS[version]
93
+ raise SpecificationError, "Unknown version #{version}." unless r
94
+ r
95
+ end
96
+
97
+
98
+ module Actions
99
+
100
+ class InstallFile
101
+
102
+ attr_reader :source, :destination, :mode
103
+
104
+ def initialize(source, destination, mode, options)
105
+ @source = source
106
+ @destination = destination
107
+ @mode = mode
108
+ @options = options
109
+ end
110
+
111
+ def install
112
+ FileUtils.install @source, File.join(@options.destdir, @destination),
113
+ {:verbose => @options.verbose,
114
+ :noop => @options.noop, :mode => @mode }
115
+ end
116
+
117
+ def hash
118
+ [@source.hash, @destination.hash].hash
119
+ end
120
+
121
+ def eql?(other)
122
+ self.class == other.class &&
123
+ @source == other.source &&
124
+ @destination == other.destination &&
125
+ @mode == other.mode
126
+ end
127
+
128
+ def <=>(other)
129
+ FULL_ORDER[self, other] || self.destination <=> other.destination
130
+ end
131
+ end
132
+
133
+ class MkDir
134
+
135
+ attr_reader :directory
136
+
137
+ def initialize(directory, options)
138
+ @directory = directory
139
+ @options = options
140
+ end
141
+
142
+ def install
143
+ FileUtils.mkdir_p File.join(@options.destdir, @directory),
144
+ {:verbose => @options.verbose,
145
+ :noop => @options.noop }
146
+ end
147
+
148
+ def <=>(other)
149
+ FULL_ORDER[self, other] || self.directory <=> other.directory
150
+ end
151
+ end
152
+
153
+ class FixShebang
154
+
155
+ attr_reader :destination
156
+
157
+ def initialize(destination, options)
158
+ @options = options
159
+ @destination = destination
160
+ end
161
+
162
+ def install
163
+ path = File.join(@options.destdir, @destination)
164
+ fix_shebang(path)
165
+ end
166
+
167
+ # taken from rpa-base, originally based on setup.rb's
168
+ # modify: #!/usr/bin/ruby
169
+ # modify: #! /usr/bin/ruby
170
+ # modify: #!ruby
171
+ # not modify: #!/usr/bin/env ruby
172
+ SHEBANG_RE = /\A\#!\s*\S*ruby\S*/
173
+
174
+ #TODO allow the ruby-prog to be placed in the shebang line to be passed as
175
+ # an option
176
+ def fix_shebang(path)
177
+ tmpfile = path + '.tmp'
178
+ begin
179
+ #XXX: needed at all?
180
+ # it seems that FileUtils doesn't expose its default output
181
+ # @fileutils_output = $stderr
182
+ # we might want to allow this to be redirected.
183
+ $stderr.puts "shebang:open #{tmpfile}" if @options.verbose
184
+ unless @options.noop
185
+ File.open(path) do |r|
186
+ File.open(tmpfile, 'w', 0755) do |w|
187
+ first = r.gets
188
+ return unless SHEBANG_RE =~ first
189
+ w.print first.sub(SHEBANG_RE, '#!' + Config::CONFIG['ruby-prog'])
190
+ w.write r.read
191
+ end
192
+ end
193
+ end
194
+ FileUtils.mv(tmpfile, path, :verbose => @options.verbose,
195
+ :noop => @options.noop)
196
+ ensure
197
+ FileUtils.rm_f(tmpfile, :verbose => @options.verbose,
198
+ :noop => @options.noop)
199
+ end
200
+ end
201
+
202
+ def <=>(other)
203
+ FULL_ORDER[self, other] || self.destination <=> other.destination
204
+ end
205
+
206
+ def hash
207
+ @destination.hash
208
+ end
209
+
210
+ def eql?(other)
211
+ self.class == other.class && self.destination == other.destination
212
+ end
213
+ end
214
+
215
+ order = [MkDir, InstallFile, FixShebang]
216
+ FULL_ORDER = lambda do |me, other|
217
+ a, b = order.index(me.class), order.index(other.class)
218
+ if a && b
219
+ (r = a - b) == 0 ? nil : r
220
+ else
221
+ -1 # arbitrary
222
+ end
223
+ end
224
+
225
+ class ActionList < Array
226
+
227
+ def directories!(options)
228
+ dirnames = []
229
+ map! { |d|
230
+ if d.kind_of?(InstallFile) && !dirnames.include?(File.dirname(d.destination))
231
+ dirnames << File.dirname(d.destination)
232
+ [MkDir.new(File.dirname(d.destination), options), d]
233
+ else
234
+ d
235
+ end
236
+ }
237
+ flatten!
238
+ end
239
+
240
+ def run(task)
241
+ each { |action| action.__send__ task }
242
+ end
243
+ end
244
+
245
+ end # module Actions
246
+
247
+ Options = Struct.new(:noop, :verbose, :destdir)
248
+
249
+ class PackageSpecification_1_0
250
+
251
+ TASKS = %w[config setup install test show]
252
+ # default options for translate(foo => bar)
253
+ TRANSLATE_DEFAULT_OPTIONS = { :inherit => true }
254
+
255
+ def self.declare_file_type(args, &handle_arg)
256
+ str_arr_p = lambda{|x| Array === x && x.all?{|y| String === y}}
257
+
258
+ # strict type checking --- we don't want this to be extended arbitrarily
259
+ unless args.size == 1 && Hash === args.first &&
260
+ args.first.all?{|f,r| [Proc, String, NilClass].include?(r.class) &&
261
+ (String === f || str_arr_p[f])} or
262
+ args.all?{|x| String === x || str_arr_p[x]}
263
+ raise SpecificationError,
264
+ "Unspecified semantics for the given arguments: #{args.inspect}"
265
+ end
266
+
267
+ if args.size == 1 && Hash === args.first
268
+ args.first.to_a.each do |file, rename_info|
269
+ if Array === file
270
+ # ignoring boring files
271
+ handle_arg.call(file, true, rename_info)
272
+ else
273
+ # we do want "boring" files given explicitly
274
+ handle_arg.call([file], false, rename_info)
275
+ end
276
+ end
277
+ else
278
+ args.each do |a|
279
+ if Array === a
280
+ a.each{|file| handle_arg.call(file, true, nil)}
281
+ else
282
+ handle_arg.call(a, false, nil)
283
+ end
284
+ end
285
+ end
286
+ end
287
+
288
+ #{{{ define the file tagging methods
289
+ KINDS.each { |kind|
290
+ define_method(kind) { |*args| # if this were 1.9 we could also take a block
291
+ bin_callback = lambda do |kind_, type, dest, options|
292
+ next if kind_ != :bin || type == :dir
293
+ @actions << Actions::FixShebang.new(dest, options)
294
+ end
295
+ #TODO: refactor
296
+ self.class.declare_file_type(args) do |files, ignore_p, opt_rename_info|
297
+ files.each do |file|
298
+ next if ignore_p && IGNORE_FILES.any?{|re| re.match(file)}
299
+ add_file(kind, file, opt_rename_info, &bin_callback)
300
+ end
301
+ end
302
+ }
303
+ }
304
+
305
+ def unit_test(*files)
306
+ @unit_tests.concat files.flatten
307
+ end
308
+
309
+ attr_accessor :actions, :options
310
+
311
+ def self.metadata(name)
312
+ define_method(name) { |*args|
313
+ if args.size == 1
314
+ @metadata[name] = args.first
315
+ end
316
+ @metadata[name]
317
+ }
318
+ end
319
+
320
+ metadata :name
321
+ metadata :version
322
+ metadata :author
323
+
324
+
325
+ def translate_dir(kind, dir)
326
+ replaced_dir_parts = dir.split(%r{/})
327
+ kept_dir_parts = []
328
+ loop do
329
+ replaced_path = replaced_dir_parts.join("/")
330
+ target, options = @translate[kind][replaced_path]
331
+ options ||= TRANSLATE_DEFAULT_OPTIONS
332
+ if target && (replaced_path == dir || options[:inherit])
333
+ dir = (target != '' ? File.join(target, *kept_dir_parts) :
334
+ File.join(*kept_dir_parts))
335
+ break
336
+ end
337
+ break if replaced_dir_parts.empty?
338
+ kept_dir_parts.unshift replaced_dir_parts.pop
339
+ end
340
+ dir
341
+ end
342
+
343
+ def add_file(kind, filename, new_filename_info, &callback)
344
+ #TODO: refactor!!!
345
+ if File.directory? filename #XXX setup.rb and rpa-base defined File.dir?
346
+ # to cope with some win32 issue
347
+ dir = filename.sub(/\A\.\//, "").sub(/\/\z/, "")
348
+ dest = File.join(@prefixes[kind], @dirs[kind], translate_dir(kind, dir))
349
+ @actions << Actions::MkDir.new(dest, @options)
350
+ callback.call(kind, :dir, dest, @options) if block_given?
351
+ else
352
+ if new_filename_info
353
+ case new_filename_info
354
+ when Proc
355
+ dest_name = new_filename_info.call(filename.dup)
356
+ else
357
+ dest_name = new_filename_info.dup
358
+ end
359
+ else
360
+ dest_name = filename.dup
361
+ end
362
+
363
+ dirname = File.dirname(dest_name)
364
+ dirname = "" if dirname == "."
365
+ dest_name = File.join(translate_dir(kind, dirname), File.basename(dest_name))
366
+
367
+ dest = File.join(@prefixes[kind], @dirs[kind], dest_name)
368
+ @actions << Actions::InstallFile.new(filename, dest, MODES[kind], @options)
369
+ callback.call(kind, :file, dest, @options) if block_given?
370
+ end
371
+ end
372
+
373
+ def initialize(prefixes = nil, dirs = nil)
374
+ @prefix = Config::CONFIG["prefix"].gsub(/\A\//, '')
375
+ @translate = {}
376
+ @prefixes = (prefixes || {}).dup
377
+ KINDS.each { |kind|
378
+ @prefixes[kind] = @prefix unless prefixes
379
+ @translate[kind] = {}
380
+ }
381
+
382
+ @dirs = (dirs || {}).dup
383
+ @dirs.update SITE_DIRS unless dirs
384
+
385
+ @actions = Actions::ActionList.new
386
+
387
+ @metadata = {}
388
+ @unit_tests = []
389
+
390
+ @options = Options.new
391
+ @options.verbose = true
392
+ @options.noop = false # XXX for testing
393
+ @options.destdir = ''
394
+
395
+ @tasks = []
396
+ end
397
+
398
+ def aoki
399
+ (KINDS - [:ext]).each { |kind|
400
+ translate(kind, kind.to_s => "", :inherit => true)
401
+ __send__ kind, Dir["#{kind}/**/*"]
402
+ }
403
+ translate(:ext, "ext/*" => "", :inherit => true)
404
+ ext Dir["ext/**/*.#{Config::CONFIG['DLEXT']}"]
405
+ end
406
+
407
+ def install
408
+ puts "Installing #{name || "unknown package"} #{version}..." if options.verbose
409
+
410
+ actions.uniq!
411
+ actions.sort!
412
+ actions.directories!(options)
413
+
414
+ #pp self
415
+
416
+ actions.run :install
417
+ end
418
+
419
+ def test
420
+ unless @unit_tests.empty?
421
+ puts "Testing #{name || "unknown package"} #{version}..." if options.verbose
422
+ require 'test/unit'
423
+ unless options.noop
424
+ t = Test::Unit::AutoRunner.new(true)
425
+ t.process_args(@unit_tests)
426
+ t.run
427
+ end
428
+ end
429
+ end
430
+
431
+ def config
432
+ File.open("config.save", "w") { |f|
433
+ YAML.dump({:prefixes => @prefixes, :dirs => @dirs}, f)
434
+ }
435
+ end
436
+
437
+ def show
438
+ KINDS.each { |kind|
439
+ puts "#{kind}\t#{File.join(options.destdir, @prefixes[kind], @dirs[kind])}"
440
+ }
441
+ end
442
+
443
+ def translate(kind, additional_translations)
444
+ default_opts = TRANSLATE_DEFAULT_OPTIONS.dup
445
+ key_val_pairs = additional_translations.to_a
446
+ option_pairs = key_val_pairs.select{|(k,v)| Symbol === k}
447
+ default_opts.update(Hash[*option_pairs.flatten])
448
+
449
+ (key_val_pairs - option_pairs).each do |key, val|
450
+ add_translation(kind, key, val, default_opts)
451
+ end
452
+ end
453
+
454
+ def add_translation(kind, src, dest, options)
455
+ if is_glob?(src)
456
+ dirs = expand_dir_glob(src)
457
+ else
458
+ dirs = [src]
459
+ end
460
+ dirs.each do |dirname|
461
+ dirname = dirname.sub(%r{\A\./}, "").sub(%r{/\z}, "")
462
+ @translate[kind].update({dirname => [dest, options]})
463
+ end
464
+ end
465
+
466
+ def is_glob?(x)
467
+ /(^|[^\\])[*?{\[]/.match(x)
468
+ end
469
+
470
+ def expand_dir_glob(src)
471
+ Dir[src].select{|x| File.directory?(x)}
472
+ end
473
+
474
+ def clean_path(path)
475
+ path.gsub(/\A\//, '').gsub(/\/+\Z/, '').squeeze("/")
476
+ end
477
+
478
+ def parse_command_line
479
+ opts = OptionParser.new(nil, 24, ' ') { |opts|
480
+ opts.banner = "Usage: setup.rb [options] [task]"
481
+
482
+ opts.separator ""
483
+ opts.separator "Tasks:"
484
+ opts.separator " config configures paths"
485
+ opts.separator " show shows paths"
486
+ opts.separator " setup compiles ruby extentions and others XXX"
487
+ opts.separator " install installs files"
488
+ opts.separator " test runs unit tests"
489
+
490
+
491
+ opts.separator ""
492
+ opts.separator "Specific options:"
493
+
494
+ opts.on "--prefix=PREFIX",
495
+ "path prefix of target environment [#@prefix]" do |prefix|
496
+ @prefix.replace clean_path(prefix) # Shared!
497
+ end
498
+
499
+ opts.separator ""
500
+
501
+ KINDS.each { |kind|
502
+ opts.on "--#{kind}prefix=PREFIX",
503
+ "path prefix for #{kind} files [#{@prefixes[kind]}]" do |prefix|
504
+ @prefixes[kind] = clean_path(prefix)
505
+ end
506
+ }
507
+
508
+ opts.separator ""
509
+
510
+ KINDS.each { |kind|
511
+ opts.on "--#{kind}dir=PREFIX",
512
+ "directory for #{kind} files [#{@dirs[kind]}]" do |prefix|
513
+ @dirs[kind] = clean_path(prefix)
514
+ end
515
+ }
516
+
517
+ opts.separator ""
518
+
519
+ KINDS.each { |kind|
520
+ opts.on "--#{kind}=PREFIX",
521
+ "absolute directory for #{kind} files [#{File.join(@prefixes[kind], @dirs[kind])}]" do |prefix|
522
+ @prefixes[kind] = clean_path(prefix)
523
+ end
524
+ }
525
+
526
+ opts.separator ""
527
+ opts.separator "Predefined path configurations:"
528
+ opts.on "--site", "install into site-local directories (default)" do
529
+ @dirs.update SITE_DIRS
530
+ end
531
+
532
+ opts.on "--vendor", "install into distribution directories (for packagers)" do
533
+ @dirs.update VENDOR_DIRS
534
+ end
535
+
536
+ opts.separator ""
537
+ opts.separator "General options:"
538
+
539
+ opts.on "--destdir=DESTDIR",
540
+ "install all files relative to DESTDIR (/)" do |destdir|
541
+ @options.destdir = destdir
542
+ end
543
+
544
+ opts.on "--dry-run", "only display what to do if given [#{@options.noop}]" do
545
+ @options.noop = true
546
+ end
547
+
548
+ opts.on "--no-harm", "only display what to do if given" do
549
+ @options.noop = true
550
+ end
551
+
552
+ opts.on "--[no-]verbose", "output messages verbosely [#{@options.verbose}]" do |verbose|
553
+ @options.verbose = verbose
554
+ end
555
+
556
+ opts.on_tail("-h", "--help", "Show this message") do
557
+ puts opts
558
+ exit
559
+ end
560
+ }
561
+
562
+ opts.parse! ARGV
563
+
564
+ if (ARGV - TASKS).empty? # Only existing tasks?
565
+ @tasks = ARGV
566
+ @tasks = ["install"] if @tasks.empty?
567
+ else
568
+ abort "Unknown task(s) #{(ARGV-TASKS).join ", "}."
569
+ end
570
+ end
571
+
572
+ def run_tasks
573
+ @tasks.each { |task| __send__ task }
574
+ end
575
+ end
576
+
577
+ end # module Package
578
+
579
+ #XXX incomplete setup.rb support for the hooks
580
+ require 'rbconfig'
581
+ def config(x)
582
+ Config::CONFIG[x]
583
+ end
584
+
585
+ #{{{ small example
586
+ if $0 == __FILE__
587
+ Package.setup("1.0") {
588
+ name "Crypt::ISAAC"
589
+
590
+ lib "crypt/ISAAC.rb"
591
+
592
+ unit_test Dir["test/TC*.rb"]
593
+ }
594
+ end
595
+
596
+ # vim: sw=2 sts=2 et ts=8