setup 4.2.0 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/HISTORY +47 -3
  2. data/MANIFEST +49 -16
  3. data/README.rdoc +148 -0
  4. data/bin/setup.rb +1 -5
  5. data/lib/setup.rb +2 -2
  6. data/lib/setup/base.rb +143 -0
  7. data/lib/setup/command.rb +218 -114
  8. data/lib/setup/compiler.rb +69 -0
  9. data/lib/setup/configuration.rb +822 -0
  10. data/lib/setup/constants.rb +12 -0
  11. data/lib/setup/{rubyver.rb → core_ext.rb} +0 -0
  12. data/lib/setup/documentor.rb +149 -0
  13. data/lib/setup/installer.rb +363 -0
  14. data/lib/setup/project.rb +68 -0
  15. data/lib/setup/rake.rb +44 -45
  16. data/lib/setup/session.rb +233 -0
  17. data/lib/setup/tester.rb +92 -0
  18. data/lib/setup/uninstaller.rb +76 -0
  19. data/meta/active +1 -0
  20. data/meta/collection +1 -0
  21. data/meta/{abstract → description} +0 -0
  22. data/meta/{package → name} +0 -0
  23. data/meta/repository +1 -0
  24. data/meta/ruby +3 -0
  25. data/meta/version +1 -1
  26. data/script/bstrap +5 -0
  27. data/script/bundle +64 -0
  28. data/script/setup +1338 -0
  29. data/script/test +3 -0
  30. data/test/cases/installer.rb +28 -0
  31. data/test/features/config.feature +16 -0
  32. data/test/features/document.feature +2 -0
  33. data/test/features/install.feature +72 -0
  34. data/test/features/make.feature +18 -0
  35. data/test/features/step_definitions/common_steps.rb +34 -0
  36. data/test/features/step_definitions/config_steps.rb +24 -0
  37. data/test/features/step_definitions/env.rb +37 -0
  38. data/test/features/step_definitions/install_steps.rb +75 -0
  39. data/test/features/step_definitions/setup_steps.rb +30 -0
  40. data/test/features/step_definitions/uninstall_steps.rb +8 -0
  41. data/test/features/test.feature +2 -0
  42. data/test/features/uninstall.feature +13 -0
  43. data/test/fixtures/faux-project/bin/faux +3 -0
  44. data/test/fixtures/faux-project/ext/faux/extconf.rb +12 -0
  45. data/test/fixtures/faux-project/ext/faux/faux.c +24 -0
  46. data/test/fixtures/faux-project/lib/faux.rb +1 -0
  47. metadata +58 -29
  48. data/README +0 -106
  49. data/RELEASE +0 -41
  50. data/lib/setup/build.rb +0 -2
  51. data/lib/setup/config.rb +0 -452
  52. data/lib/setup/error.rb +0 -4
  53. data/lib/setup/install.rb +0 -1007
  54. data/meta/setup/metaconfig.rb +0 -3
  55. data/test/test_installer.rb +0 -139
@@ -0,0 +1,12 @@
1
+ module Setup
2
+
3
+ #
4
+ META_EXTENSION_DIR = '.setup'
5
+
6
+ #
7
+ FILETYPES = %w( bin lib ext data etc man doc )
8
+
9
+ #
10
+ INSTALL_RECORD = 'InstalledFiles' #'.cache/setup/installedfiles'
11
+
12
+ end
File without changes
@@ -0,0 +1,149 @@
1
+ require 'setup/base'
2
+
3
+ module Setup
4
+
5
+ #
6
+ class Documentor < Base
7
+
8
+ #
9
+ def document
10
+ return if config.no_doc
11
+ exec_ri
12
+
13
+ #if file = DOCSCRIPT
14
+ # ruby(file)
15
+ #else
16
+ # exec_rdoc
17
+ #end
18
+ end
19
+
20
+ # Generate ri documentation.
21
+ #++
22
+ # TODO: call rdoc programmatically.
23
+ #--
24
+ def exec_ri
25
+ case config.type #installdirs
26
+ when 'std', 'ruby'
27
+ #output = "--ri-system" # no longer supported?
28
+ output = "--ri-site"
29
+ when 'site'
30
+ output = "--ri-site"
31
+ when 'home'
32
+ output = "--ri"
33
+ else
34
+ abort "bad config: should not be possible -- type=#{config.type}"
35
+ end
36
+
37
+ if File.exist?('.document')
38
+ files = File.read('.document').split("\n")
39
+ files.reject!{ |l| l =~ /^\s*[#]/ || l !~ /\S/ }
40
+ files.collect!{ |f| f.strip }
41
+ #elsif File.exist?('meta/loadpath')
42
+ else
43
+ files = []
44
+ files << 'lib' if File.directory?('lib')
45
+ files << 'ext' if File.directory?('ext')
46
+ end
47
+
48
+ opt = []
49
+ opt << "-U"
50
+ opt << "-q" #if quiet?
51
+ #opt << "-D" #if $DEBUG
52
+ opt << output
53
+ opt << files
54
+
55
+ opt = opt.flatten
56
+
57
+ cmd = "rdoc " + opt.join(' ')
58
+
59
+ if trial?
60
+ puts cmd
61
+ else
62
+ begin
63
+ success = system(cmd)
64
+ raise unless success
65
+ #require 'rdoc/rdoc'
66
+ #::RDoc::RDoc.new.document(opt)
67
+ io.puts "Ok ri." #unless quiet?
68
+ rescue Exception
69
+ $stderr.puts "ri generation failed"
70
+ $stderr.puts "command was: '#{cmd}'"
71
+ #$stderr.puts "proceeding with install..."
72
+ end
73
+
74
+ # Now in local directory
75
+ #opt = []
76
+ #opt << "-U"
77
+ #opt << "--ri --op 'doc/ri'"
78
+ #opt << files
79
+ #opt = opt.flatten
80
+ #::RDoc::RDoc.new.document(opt)
81
+ end
82
+ end
83
+
84
+ # Generate rdocs.
85
+ #
86
+ # Needs <tt>meta/name</tt> or <tt>.meta/name</tt>.
87
+ #
88
+ # NOTE: This is not being used. It's here in case we decide
89
+ # to add this feature, though it is quite possible that
90
+ # we may never do so.
91
+ #
92
+ def exec_rdoc
93
+ main = Dir.glob("README{,.*}", File::FNM_CASEFOLD).first
94
+
95
+ if File.exist?('.document')
96
+ files = File.read('.document').split("\n")
97
+ files.reject!{ |l| l =~ /^\s*[#]/ || l !~ /\S/ }
98
+ files.collect!{ |f| f.strip }
99
+ else
100
+ files = []
101
+ files << main if main
102
+ files << 'lib' if File.directory?('lib')
103
+ files << 'ext' if File.directory?('ext')
104
+ end
105
+
106
+ checkfiles = (files + files.map{ |f| Dir[File.join(f,'*','**')] }).flatten.uniq
107
+ if FileUtils.uptodate?('doc/rdoc', checkfiles)
108
+ puts "RDocs look current."
109
+ return
110
+ end
111
+
112
+ output = 'doc/rdoc'
113
+ title = (PACKAGE.capitalize + " API").strip if PACKAGE
114
+ template = config.doctemplate || 'html'
115
+
116
+ opt = []
117
+ opt << "-U"
118
+ opt << "-q" #if quiet?
119
+ opt << "--op=#{output}"
120
+ #opt << "--template=#{template}"
121
+ opt << "--title=#{title}"
122
+ opt << "--main=#{main}" if main
123
+ #opt << "--debug"
124
+ opt << files
125
+
126
+ opt = opt.flatten
127
+
128
+ cmd = "rdoc " + opt.join(' ')
129
+
130
+ if trial?
131
+ puts cmd
132
+ else
133
+ begin
134
+ system(cmd)
135
+ #require 'rdoc/rdoc'
136
+ #::RDoc::RDoc.new.document(opt)
137
+ puts "Ok rdoc." unless quiet?
138
+ rescue Exception
139
+ puts "Fail rdoc."
140
+ puts "Command was: '#{cmd}'"
141
+ puts "Proceeding with install anyway."
142
+ end
143
+ end
144
+ end
145
+
146
+ end
147
+
148
+ end
149
+
@@ -0,0 +1,363 @@
1
+ require 'setup/base'
2
+
3
+ module Setup
4
+
5
+ # Installer class handles the actual install procedure.
6
+ #
7
+ # NOTE: This new version does not support per-directory hooks.
8
+ #
9
+ class Installer < Base
10
+
11
+ #
12
+ def install_prefix
13
+ config.install_prefix
14
+ end
15
+ #attr_accessor :install_prefix
16
+
17
+ # Install package.
18
+ def install
19
+ Dir.chdir(rootdir) do
20
+ install_bin
21
+ install_ext
22
+ install_lib
23
+ install_data
24
+ install_man
25
+ install_doc
26
+ install_etc
27
+ prune_install_record
28
+ end
29
+ end
30
+
31
+ # Install binaries (executables).
32
+ def install_bin
33
+ return unless directory?('bin')
34
+ report_transfer('bin', config.bindir)
35
+ #io.puts "* bin -> #{config.bindir}" unless quiet?
36
+ files = files('bin')
37
+ install_files('bin', files, config.bindir, 0755)
38
+ #install_shebang(files, config.bindir)
39
+ end
40
+
41
+ # Install shared extension libraries.
42
+ def install_ext
43
+ return unless directory?('ext')
44
+ report_transfer('ext', config.sodir)
45
+ #io.puts "* ext -> #{config.sodir}" unless quiet?
46
+ files = files('ext')
47
+ files = select_dllext(files)
48
+ #install_files('ext', files, config.sodir, 0555)
49
+ files.each do |file|
50
+ name = File.join(File.dirname(File.dirname(file)), File.basename(file))
51
+ dest = destination(config.sodir, name)
52
+ install_file('ext', file, dest, 0555, install_prefix)
53
+ end
54
+ end
55
+
56
+ # Install library files.
57
+ def install_lib
58
+ return unless directory?('lib')
59
+ report_transfer('lib', config.rbdir)
60
+ #io.puts "* lib -> #{config.rbdir}" unless quiet?
61
+ files = files('lib')
62
+ install_files('lib', files, config.rbdir, 0644)
63
+ end
64
+
65
+ # Install shared data.
66
+ def install_data
67
+ return unless directory?('data')
68
+ report_transfer('data', config.datadir)
69
+ #io.puts "* data -> #{config.datadir}" unless quiet?
70
+ files = files('data')
71
+ install_files('data', files, config.datadir, 0644)
72
+ end
73
+
74
+ # Install configuration.
75
+ def install_etc
76
+ return unless directory?('etc')
77
+ report_transfer('etc', config.sysconfdir)
78
+ files = files('etc')
79
+ install_files('etc', files, config.sysconfdir, 0644)
80
+ end
81
+
82
+ # Install manpages.
83
+ def install_man
84
+ return unless directory?('man')
85
+ report_transfer('man', config.mandir)
86
+ files = files('man')
87
+ install_files('man', files, config.mandir, 0644)
88
+ end
89
+
90
+ # Install documentation.
91
+ #
92
+ # TODO: The use of the project name in the doc directory
93
+ # should be set during the config phase. Define a seperate
94
+ # config method for it.
95
+ def install_doc
96
+ return unless config.doc?
97
+ return unless directory?('doc')
98
+ return unless project.name
99
+ dir = File.join(config.docdir, "ruby-{project.name}")
100
+ report_transfer('doc', dir)
101
+ #io.puts "* doc -> #{dir}" unless quiet?
102
+ files = files('doc')
103
+ install_files('doc', files, dir, 0644)
104
+ end
105
+
106
+ private
107
+
108
+ # Display the file transfer taking place.
109
+ def report_transfer(source, directory)
110
+ unless quiet?
111
+ if install_prefix
112
+ out = File.join(install_prefix, directory)
113
+ else
114
+ out = directory
115
+ end
116
+ io.puts "* #{source} -> #{out}"
117
+ end
118
+ end
119
+
120
+ # Comfirm a +path+ is a directory and exists.
121
+ def directory?(path)
122
+ File.directory?(path)
123
+ end
124
+
125
+ # Get a list of project files given a project subdirectory.
126
+ def files(dir)
127
+ files = Dir["#{dir}/**/*"]
128
+ files = files.select{ |f| File.file?(f) }
129
+ files = files.map{ |f| f.sub("#{dir}/", '') }
130
+ files
131
+ end
132
+
133
+ # Extract dynamic link libraries from all ext files.
134
+ def select_dllext(files)
135
+ ents = files.select do |file|
136
+ File.extname(file) == ".#{dllext}"
137
+ end
138
+ if ents.empty? && !files.empty?
139
+ raise Error, "ruby extention not compiled: 'setup.rb setup' first"
140
+ end
141
+ ents
142
+ end
143
+
144
+ # Dynamic link library extension for this system.
145
+ def dllext
146
+ config.dlext
147
+ #Configuration::RBCONFIG['DLEXT']
148
+ end
149
+
150
+ # Install project files.
151
+ def install_files(dir, list, dest, mode)
152
+ #mkdir_p(dest) #, install_prefix)
153
+ list.each do |fname|
154
+ rdest = destination(dest, fname)
155
+ install_file(dir, fname, rdest, mode, install_prefix)
156
+ end
157
+ end
158
+
159
+ # Install a project file.
160
+ def install_file(dir, from, dest, mode, prefix=nil)
161
+ mkdir_p(File.dirname(dest))
162
+
163
+ if trace? or trial?
164
+ #to = prefix ? File.join(prefix, dir, from) : File.join(dir, from)
165
+ io.puts "install #{dir}/#{from} #{dest}"
166
+ end
167
+
168
+ return if trial?
169
+
170
+ str = binread(File.join(dir, from))
171
+
172
+ if diff?(str, dest)
173
+ trace_off {
174
+ rm_f(dest) if File.exist?(dest)
175
+ }
176
+ File.open(dest, 'wb'){ |f| f.write(str) }
177
+ File.chmod(mode, dest)
178
+ end
179
+
180
+ record_installation(dest) # record file as installed
181
+ end
182
+
183
+ # Install a directory.
184
+ #--
185
+ # TODO: Surely this can be simplified.
186
+ #++
187
+ def mkdir_p(dirname) #, prefix=nil)
188
+ #dirname = destination(dirname)
189
+ #dirname = File.join(prefix, File.expand_path(dirname)) if prefix
190
+ return if File.directory?(dirname)
191
+
192
+ io.puts "mkdir -p #{dirname}" if trace? or trial?
193
+
194
+ return if trial?
195
+
196
+ # Does not check '/', it's too abnormal.
197
+ dirs = File.expand_path(dirname).split(%r<(?=/)>)
198
+ if /\A[a-z]:\z/i =~ dirs[0]
199
+ disk = dirs.shift
200
+ dirs[0] = disk + dirs[0]
201
+ end
202
+ dirs.each_index do |idx|
203
+ path = dirs[0..idx].join('')
204
+ unless File.dir?(path)
205
+ Dir.mkdir(path)
206
+ end
207
+ record_installation(path) # record directories made
208
+ end
209
+ end
210
+
211
+ # Record that a file or directory was installed in the
212
+ # install record file.
213
+ def record_installation(path)
214
+ File.open(install_record, 'a') do |f|
215
+ f.puts(path)
216
+ end
217
+ #io.puts "installed #{path}" if trace?
218
+ end
219
+
220
+ # Remove duplicates from the install record.
221
+ def prune_install_record
222
+ entries = File.read(install_record).split("\n")
223
+ entries.uniq!
224
+ File.open(install_record, 'w') do |f|
225
+ f << entries.join("\n")
226
+ f << "\n"
227
+ end
228
+ end
229
+
230
+ # Get the install record file name, and ensure it's location
231
+ # is prepared (ie. make it's directory).
232
+ def install_record
233
+ @install_record ||= (
234
+ file = INSTALL_RECORD
235
+ dir = File.dirname(file)
236
+ unless File.directory?(dir)
237
+ FileUtils.mkdir_p(dir)
238
+ end
239
+ file
240
+ )
241
+ end
242
+
243
+ #realdest = prefix ? File.join(prefix, File.expand_path(dest)) : dest
244
+ #realdest = File.join(realdest, from) #if File.dir?(realdest) #File.basename(from)) if File.dir?(realdest)
245
+
246
+ # Determine actual destination including install_prefix.
247
+ def destination(dir, file)
248
+ dest = install_prefix ? File.join(install_prefix, File.expand_path(dir)) : dir
249
+ dest = File.join(dest, file) #if File.dir?(dest)
250
+ dest = File.expand_path(dest)
251
+ dest
252
+ end
253
+
254
+ # Is a current project file different from a previously
255
+ # installed file?
256
+ def diff?(new_content, path)
257
+ return true unless File.exist?(path)
258
+ new_content != binread(path)
259
+ end
260
+
261
+ # Binary read.
262
+ def binread(fname)
263
+ File.open(fname, 'rb') do |f|
264
+ return f.read
265
+ end
266
+ end
267
+
268
+ # TODO: The shebang updating needs some work.
269
+ #
270
+ # I beleive that on unix-based systems <tt>#!/usr/bin/env ruby</tt>
271
+ # is the appropriate shebang.
272
+
273
+ #
274
+ def install_shebang(files, dir)
275
+ files.each do |file|
276
+ path = File.join(dir, File.basename(file))
277
+ update_shebang_line(path)
278
+ end
279
+ end
280
+
281
+ #
282
+ def update_shebang_line(path)
283
+ return if trial?
284
+ return if config.shebang == 'never'
285
+ old = Shebang.load(path)
286
+ if old
287
+ if old.args.size > 1
288
+ $stderr.puts "warning: #{path}"
289
+ $stderr.puts "Shebang line has too many args."
290
+ $stderr.puts "It is not portable and your program may not work."
291
+ end
292
+ new = new_shebang(old)
293
+ return if new.to_s == old.to_s
294
+ else
295
+ return unless config.shebang == 'all'
296
+ new = Shebang.new(config.rubypath)
297
+ end
298
+ $stderr.puts "updating shebang: #{File.basename(path)}" if trace?
299
+ open_atomic_writer(path) do |output|
300
+ File.open(path, 'rb') do |f|
301
+ f.gets if old # discard
302
+ output.puts new.to_s
303
+ output.print f.read
304
+ end
305
+ end
306
+ end
307
+
308
+ #
309
+ def new_shebang(old)
310
+ if /\Aruby/ =~ File.basename(old.cmd)
311
+ Shebang.new(config.rubypath, old.args)
312
+ elsif File.basename(old.cmd) == 'env' and old.args.first == 'ruby'
313
+ Shebang.new(config.rubypath, old.args[1..-1])
314
+ else
315
+ return old unless config.shebang == 'all'
316
+ Shebang.new(config.rubypath)
317
+ end
318
+ end
319
+
320
+ #
321
+ def open_atomic_writer(path, &block)
322
+ tmpfile = File.basename(path) + '.tmp'
323
+ begin
324
+ File.open(tmpfile, 'wb', &block)
325
+ File.rename tmpfile, File.basename(path)
326
+ ensure
327
+ File.unlink tmpfile if File.exist?(tmpfile)
328
+ end
329
+ end
330
+
331
+ #
332
+ class Shebang
333
+ def Shebang.load(path)
334
+ line = nil
335
+ File.open(path) {|f|
336
+ line = f.gets
337
+ }
338
+ return nil unless /\A#!/ =~ line
339
+ parse(line)
340
+ end
341
+
342
+ def Shebang.parse(line)
343
+ cmd, *args = *line.strip.sub(/\A\#!/, '').split(' ')
344
+ new(cmd, args)
345
+ end
346
+
347
+ def initialize(cmd, args = [])
348
+ @cmd = cmd
349
+ @args = args
350
+ end
351
+
352
+ attr_reader :cmd
353
+ attr_reader :args
354
+
355
+ def to_s
356
+ "#! #{@cmd}" + (@args.empty? ? '' : " #{@args.join(' ')}")
357
+ end
358
+ end
359
+
360
+ end
361
+
362
+ end
363
+