roll 0.8.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. data/{LICENSE → COPYING} +1 -1
  2. data/HISTORY +62 -0
  3. data/README.rdoc +169 -0
  4. data/TODO +4 -0
  5. data/bin/roll +3 -44
  6. data/lib/oll.rb +1 -2
  7. data/lib/roll.rb +87 -0
  8. data/lib/roll/command.rb +207 -0
  9. data/lib/roll/config.rb +80 -0
  10. data/lib/roll/environment.rb +317 -0
  11. data/lib/roll/errors.rb +13 -0
  12. data/lib/roll/kernel.rb +41 -0
  13. data/lib/roll/ledger.rb +299 -0
  14. data/lib/roll/library.rb +241 -558
  15. data/lib/roll/locals.rb +96 -0
  16. data/lib/roll/metadata.rb +112 -0
  17. data/lib/roll/original.rb +10 -0
  18. data/lib/roll/version.rb +91 -101
  19. data/meta/active +1 -0
  20. data/meta/authors +1 -0
  21. data/meta/contact +1 -0
  22. data/meta/created +1 -0
  23. data/meta/description +5 -0
  24. data/meta/homepage +1 -0
  25. data/meta/maintainer +1 -0
  26. data/meta/name +1 -0
  27. data/meta/repository +1 -0
  28. data/meta/ruby +2 -0
  29. data/meta/suite +1 -0
  30. data/meta/summary +1 -0
  31. data/meta/version +1 -0
  32. data/script/rdoc +4 -0
  33. data/script/setup +1344 -0
  34. data/script/test +23 -0
  35. data/test/benchmarks/vsgems.rb +11 -0
  36. data/test/benchmarks/vsgems_bm.rb +17 -0
  37. data/test/demonstrations/01_library.rdoc +33 -0
  38. data/test/demonstrations/04_version.rdoc +56 -0
  39. data/test/fixtures/env.list +1 -0
  40. data/{demo/sample → test/fixtures}/inspect.rb +0 -0
  41. data/test/fixtures/tryme/1.0/lib/tryme.rb +1 -0
  42. data/test/fixtures/tryme/1.0/meta/homepage +1 -0
  43. data/test/fixtures/tryme/1.0/meta/name +1 -0
  44. data/test/fixtures/tryme/1.0/meta/version +1 -0
  45. data/test/fixtures/tryme/1.1/lib/tryme.rb +1 -0
  46. data/test/fixtures/tryme/1.1/meta/homepage +1 -0
  47. data/test/fixtures/tryme/1.1/meta/name +1 -0
  48. data/test/fixtures/tryme/1.1/meta/version +1 -0
  49. data/test/{test_version.rb → unit/version_test.rb} +21 -21
  50. data/test/unitcases/version_case.rb +69 -0
  51. metadata +102 -65
  52. data/README +0 -17
  53. data/demo/bench/bench_load.rb +0 -7
  54. data/demo/sample/tryme/1.0/lib/tryme.rb +0 -1
  55. data/demo/sample/tryme/1.1/lib/tryme.rb +0 -1
  56. data/lib/roll/attributes.rb +0 -72
  57. data/lib/roll/package.rb +0 -300
  58. data/lib/roll/remote.rb +0 -37
  59. data/meta/ROLL-0.8.0.roll +0 -21
  60. data/task/rdoc +0 -9
  61. data/task/setup +0 -1616
  62. data/task/test +0 -5
  63. data/test/test_library.rb +0 -10
@@ -0,0 +1,299 @@
1
+ module Roll
2
+ require 'roll/original'
3
+ require 'roll/environment'
4
+ require 'roll/library'
5
+
6
+ # = Ledger class
7
+ #
8
+ class Ledger
9
+
10
+ include Enumerable
11
+
12
+ #
13
+ def initialize
14
+ @index = Hash.new{|h,k| h[k] = []}
15
+
16
+ @environment = Environment.new
17
+
18
+ @environment.each do |name, paths|
19
+ paths.each do |path|
20
+ unless File.directory?(path)
21
+ warn "roll: invalid path for #{name} -- #{path}"
22
+ next
23
+ end
24
+ lib = Library.new(path, name)
25
+ @index[name] << lib if lib.active?
26
+ end
27
+ end
28
+
29
+ @load_stack = []
30
+ @load_monitor = Hash.new{ |h,k| h[k]=[] }
31
+ end
32
+
33
+ #
34
+ def enironment
35
+ @environment
36
+ end
37
+
38
+ #
39
+ def [](name)
40
+ @index[name]
41
+ end
42
+
43
+ #
44
+ def []=(name, value)
45
+ @index[name] = value
46
+ end
47
+
48
+ #
49
+ def include?(name)
50
+ @index.include?(name)
51
+ end
52
+
53
+ #
54
+ def names
55
+ @index.keys
56
+ end
57
+
58
+ #
59
+ def each(&block)
60
+ @index.each(&block)
61
+ end
62
+
63
+ #
64
+ def size
65
+ @index.size
66
+ end
67
+
68
+ #
69
+ def load_stack
70
+ @load_stack
71
+ end
72
+
73
+ # NOTE: Not used yet.
74
+ def load_monitor
75
+ @load_monitor
76
+ end
77
+
78
+ #--
79
+ # TODO: Should Ruby's underlying require be tried first,
80
+ # then fallback to Rolls. Or vice-versa?
81
+ #++
82
+
83
+ #
84
+ def require(path)
85
+ #begin
86
+ # original_require(path)
87
+ #rescue LoadError => load_error
88
+ # lib, file = *match(path)
89
+ # if lib && file
90
+ # constrain(lib)
91
+ # lib.require_absolute(file)
92
+ # else
93
+ # raise clean_backtrace(load_error)
94
+ # end
95
+ #end
96
+ lib, file = *match(path)
97
+ if lib && file
98
+ constrain(lib)
99
+ lib.require_absolute(file)
100
+ else
101
+ begin
102
+ original_require(path)
103
+ rescue LoadError => load_error
104
+ raise clean_backtrace(load_error)
105
+ end
106
+ end
107
+
108
+ end
109
+
110
+ #
111
+ def load(path, wrap=nil)
112
+ lib, file = *match(path, false)
113
+ if lib && file
114
+ constrain(lib)
115
+ lib.load_absolute(file, wrap)
116
+ else
117
+ begin
118
+ original_load(path, wrap)
119
+ rescue LoadError => load_error
120
+ raise clean_backtrace(load_error)
121
+ end
122
+ end
123
+ end
124
+
125
+ # Use acquire to use Roll-style loading. This first
126
+ # looks for a specific library via ':'. If ':' is
127
+ # not present it then tries the current library.
128
+ # Failing that it fallsback to Ruby itself.
129
+ #
130
+ # acquire('facets:string/margin')
131
+ #
132
+ # To "load" the library, rather than "require" it set
133
+ # the +:load+ option to true.
134
+ #
135
+ # acquire('facets:string/margin', :load=>true)
136
+ #
137
+ def acquire(file, opts={})
138
+ if file.index(':') # a specific library
139
+ name, file = file.split(':')
140
+ lib = Library.open(name)
141
+ else # try the current library
142
+ cur = load_stack.last
143
+ if cur && cur.include?(file)
144
+ lib = cur
145
+ elsif !file.index('/') # is this a library name?
146
+ if cur = Library.instance(file)
147
+ lib = cur
148
+ file = lib.default # default file to load
149
+ end
150
+ end
151
+ end
152
+ if opts[:load]
153
+ lib ? lib.load(file) : original_load(file)
154
+ else
155
+ lib ? lib.require(file) : original_require(file)
156
+ end
157
+ end
158
+
159
+ #
160
+ def constrain(lib)
161
+ cmp = self[lib.name]
162
+ if Array === cmp
163
+ self[lib.name] = lib
164
+ else
165
+ if lib.version != cmp.version
166
+ raise VersionError
167
+ end
168
+ end
169
+ end
170
+
171
+ private
172
+
173
+ # Find require matches.
174
+ def match(path, suffix=true)
175
+ path = path.to_s
176
+
177
+ return nil if /^\// =~ path # absolute path
178
+
179
+ if path.index(':') # a specified library
180
+ name, path = path.split(':')
181
+ lib = Library.open(name)
182
+ if lib.active?
183
+ file = lib.find(path, suffix)
184
+ return lib, file
185
+ end
186
+ end
187
+
188
+ matches = []
189
+
190
+ # try the load stack first
191
+ load_stack.reverse_each do |lib|
192
+ if file = lib.find(path, suffix)
193
+ return [lib, file] unless $VERBOSE
194
+ matches << [lib, file]
195
+ end
196
+ end
197
+
198
+ # TODO: Perhaps the selected and unselected should be kept in separate lists?
199
+ unselected, selected = *@index.partition{ |name, libs| Array === libs }
200
+
201
+ selected.each do |(name, lib)|
202
+ if file = lib.find(path, suffix)
203
+ #matches << [lib, file]
204
+ #return matches.first unless $VERBOSE
205
+ return [lib, file] unless $VERBOSE
206
+ matches << [lib, file]
207
+ end
208
+ end
209
+
210
+ unselected.each do |(name, libs)|
211
+ pos = []
212
+ libs.each do |lib|
213
+ if file = lib.find(path, suffix)
214
+ pos << [lib, file]
215
+ end
216
+ end
217
+ unless pos.empty?
218
+ latest = pos.sort{ |a,b| b[0].version <=> a[0].version }.first
219
+ return latest unless $VERBOSE
220
+ matches << latest
221
+ #return matches.first unless $VERBOSE
222
+ end
223
+ end
224
+
225
+ matches.uniq!
226
+
227
+ if matches.size > 1
228
+ warn_multiples(path, matches)
229
+ end
230
+
231
+ matches.first
232
+ end
233
+
234
+ #
235
+ def warn_multiples(path, matches)
236
+ warn "multiple matches for same request -- #{path}"
237
+ matches.each do |lib, file|
238
+ warn " #{file}"
239
+ end
240
+ end
241
+
242
+ #
243
+ def clean_backtrace(error)
244
+ if $DEBUG
245
+ error
246
+ else
247
+ bt = error.backtrace
248
+ bt = bt.reject{ |e| /roll/ =~ e }
249
+ error.set_backtrace(bt)
250
+ error
251
+ end
252
+ end
253
+
254
+ end#class Ledger
255
+
256
+ #--
257
+ # Ledger augments the Library metaclass.
258
+ #++
259
+ class << Library
260
+
261
+ #
262
+ def ledger
263
+ @ledger ||= Ledger.new
264
+ end
265
+
266
+ # Current environment
267
+ def environment
268
+ ledger.environment
269
+ end
270
+
271
+ # List of library names.
272
+ def list
273
+ ledger.names
274
+ end
275
+
276
+ #
277
+ def require(path)
278
+ ledger.require(path)
279
+ end
280
+
281
+ #
282
+ def load(path, wrap=nil)
283
+ ledger.load(path, wrap)
284
+ end
285
+
286
+ #
287
+ def load_stack
288
+ ledger.load_stack
289
+ end
290
+
291
+ # NOTE: Not used yet.
292
+ def load_monitor
293
+ ledger.load_monitor
294
+ end
295
+
296
+ end
297
+
298
+ end#module Roll
299
+
@@ -1,635 +1,318 @@
1
- # TITLE:
2
- #
3
- # library.rb
4
- #
5
- # LICENSE:
6
- #
7
- # Copyright (c)2007 Thomas Sawyer, Ruby License
8
- #
9
- # TODO:
10
- #
11
- # - Commented out #import for now. Facets' module_require and module_load
12
- # are probably better. Implement those for Rolls instead. (Yes?)
13
- # - Maybe add autopackage install system?
14
- # - What about remotes? What about version tiers when remote requiring?
15
-
16
- require 'rbconfig'
17
- require 'fileutils'
18
- require 'roll/package'
1
+ #require 'rbconfig'
19
2
  require 'roll/version'
20
- #require 'roll/sign'
21
-
22
- # We need to hold a copy of the original $LOAD_PATH
23
- # for specified "ruby: ..." loads.
24
-
25
- $RUBY_PATH = $LOAD_PATH.dup
26
-
27
- # Locations of rolls-ready libraries.
28
- # # We could use the site_ruby locations instead, but that creates an odd sort of overlap in
29
- # # the load paths, and would also promote putting the information file in the lib/ dir. So
30
- # # I think it's better to use a separate location. (After all site_ruby may just fade away.)
31
- # $LOAD_SITE = $LOAD_PATH - Config::CONFIG.values_at('rubylibdir', 'archdir') - ['.']
32
-
33
- rolldir = 'ruby_library'
34
- sitedir = ::Config::CONFIG['sitedir']
35
- version = ::Config::CONFIG['ruby_version']
3
+ require 'roll/metadata'
4
+ require 'roll/errors'
36
5
 
37
- $LOAD_SITE = [File.join(File.dirname(sitedir), rolldir, version)] + ENV['ROLL_PATH'].to_s.split(':')
38
-
39
- # = Library Class
40
- #
41
- # The Library class serves as an objecified location in Ruby's load paths.
42
- #
43
- # The Library qua class also serves as the library manager, storing a ledger of
44
- # available libraries.
45
- #
46
- # A library is roll-ready when it supplies a {name}-{verison}.roll file in either its
47
- # base directory or in the base's meta/ directory. The roll file name is specifically
48
- # designed to make library lookup fast. There is no need for Rolls to open the roll
49
- # file until an actual version is used. It also gives the most flexability in repository
50
- # layout. Rolls searches up to three subdirs deep looking for roll files. This is
51
- # suitable to non-versioned libs, versioned libs, non-versioned subprojects and subprojects,
52
- # including typical Subversion repository layouts.
53
-
54
- class Library
55
-
56
- # Dynamic link extension.
57
- def self.dlext
58
- @dlext ||= '.' + ::Config::CONFIG['DLEXT']
59
- end
60
-
61
- # Location of rolls-ready libs.
62
- def self.load_site
63
- $LOAD_SITE
64
- end
6
+ module Roll
65
7
 
8
+ # = Library class
66
9
  #
67
- def self.load_path
68
- $LOAD_PATH
69
- end
10
+ class Library
70
11
 
71
- #
72
- def self.ruby_path
73
- $RUBY_PATH
74
- end
75
-
76
- # Name of library.
77
- attr_reader :name
78
-
79
- # Version of library. This is a VersionNumber object.
80
- attr_reader :version
12
+ # Dynamic link extension.
13
+ #DLEXT = '.' + ::Config::CONFIG['DLEXT']
81
14
 
82
- # Path to library.
83
- attr_reader :location
15
+ #
16
+ #SUFFIXES = ['', '.rb', '.rbw', '.so', '.bundle', '.dll', '.sl', '.jar']
17
+ SUFFIXES = ['', '.rb', '.rbw', '.so', '.bundle', '.dll', '.sl', '.jar']
84
18
 
85
- # New libray.
86
- def initialize(location, identity=nil) #name, version, location=nil)
87
- @location = location
88
-
89
- if identity
90
- @name = identity[:name]
91
- @version = identity[:version]
92
- @load_path = identity[:load_path] || identity[:load_paths]
93
- else
94
- identify(location)
95
- end
19
+ #
20
+ SUFFIX_PATTERN = "{#{SUFFIXES.join(',')}}"
96
21
 
97
- raise unless @name
98
- raise unless @version
22
+ # Get an instance of a library by name, or name and version.
23
+ # Libraries are singleton, so once loaded the same object is
24
+ # always returned.
99
25
 
100
- @identity = identity
26
+ def self.instance(name, constraint=nil)
27
+ name = name.to_s
28
+ #raise "no library -- #{name}" unless ledger.include?(name)
29
+ return nil unless ledger.include?(name)
101
30
 
102
- # TODO Version number needs to be more flexiable in handling non-numeric tuples.
103
- @version = VersionNumber.new(@version) unless VersionNumber === @version
104
- end
31
+ library = ledger[name]
105
32
 
106
- # Identify a library based on it's location.
107
- def identify(location)
108
- file = File.join(location,'{,meta/}*.roll')
109
- if file = Dir.glob(file).first
110
- @name, @version = file.chomp('.roll').split('-')
111
- end
112
- end
113
-
114
- # Inspection.
115
- def inspect
116
- if version
117
- "#<Library #{name}/#{version}>"
118
- else
119
- "#<Library #{name}>"
33
+ if Library===library
34
+ if constraint # TODO: it's okay if constraint fits current
35
+ raise VersionConflict, "previously selected version -- #{ledger[name].version}"
36
+ else
37
+ library
38
+ end
39
+ else # library is an array of versions
40
+ if constraint
41
+ compare = Version.constraint_lambda(constraint)
42
+ library = library.select(&compare).max
43
+ else
44
+ library = library.max
45
+ end
46
+ unless library
47
+ raise VersionError, "no library version -- #{name} #{constraint}"
48
+ end
49
+ #ledger[name] = library
50
+ #library.activate
51
+ return library
52
+ end
120
53
  end
121
- end
122
54
 
123
- def roll_file
124
- find = "{,meta/}*.roll" # "{,meta/}#{name}-#{version}.roll"
125
- file = Dir.glob(File.join(location, find), File::FNM_CASEFOLD).first
126
- end
55
+ # A shortcut for #instance.
127
56
 
128
- # Read roll file.
129
- def load_roll
130
- return unless location # NEED TO DO THIS BETTER. THIS IS HERE FOR THE ONE 'ruby' CASE.
131
- raise LoadError unless File.directory?(location)
132
- glob = File.join(location, "{,meta/}*.roll") # "{,meta/}#{name}-#{version}.roll"
133
- file = Dir.glob(glob, File::FNM_CASEFOLD).first
134
- if file
135
- @roll_file = file
136
- @roll = Roll::Package.open(file, :name=>name, :version=>version.to_s)
137
- else
138
- raise "THIS SHOULD NOT POSSIBLE!"
139
- #@roll = false #Roll::Package.new # THIS IN NO LONGER POSSIBLE
57
+ def self.[](name, constraint=nil)
58
+ instance(name, constraint)
140
59
  end
141
- #use #?
142
- return @roll
143
- end
144
-
145
- # Does this library have an roll file?
146
- #def rolled?
147
- # roll ? true : false
148
- #end
149
-
150
- # Does this library have a remote source?
151
-
152
- #def remote?
153
- # rolled? and source and pubkey
154
- #end
155
-
156
- # Meta information about the libray.
157
- def roll
158
- @roll = load_roll if @roll.nil? # If it's false, we don't have one.
159
- @roll
160
- end
161
- alias_method :info, :roll
162
60
 
163
- # Compare by version.
164
- def <=>(other)
165
- version <=> other.verison
166
- end
61
+ # Same as #instance but will raise and error if the library is
62
+ # not found. This can also take a block to yield on the library.
167
63
 
168
- # List of subdirectories that are searched when loading libs.
169
- # In general this should include all the libs internal load paths,
170
- # so long as there will be no name conflicts between directories.
171
- def lib_path
172
- return unless roll # NEED TO DO THIS BETTER. THIS IS HERE FOR THE ONE 'ruby' CASE.
173
- return @load_path if @load_path
174
- if roll.load_path
175
- @load_path = roll.load_path.collect{ |path| File.join(location, path) }
176
- else
177
- @load_path = ['lib'] # ["lib/#{name}"]
178
- end
179
- end
180
- alias_method :load_path, :lib_path
181
- alias_method :load_paths, :lib_path
182
-
183
- # List of subdirectories that are searched for binaries.
184
- #++
185
- # TODO I think it would be better just to make this a fix
186
- # convention that bin/ is always the place to put these.
187
- # (Unlike lib/ which needs to be more flexable.)
188
- #--
189
- def bin_path
190
- return @bin_path if @bin_path
191
- return [] unless location # NEED TO DO THIS BETTER.
192
- if roll.bin_path
193
- @bin_path = roll.bin_path.collect{ |path| File.join(location, path) }
194
- else
195
- if File.directory?(File.join(location, 'bin'))
196
- @bin_path = [File.join(location, 'bin')]
197
- else
198
- @bin_path = []
64
+ def self.open(name, constraint=nil) #:yield:
65
+ lib = instance(name, constraint)
66
+ unless lib
67
+ raise LoadError, "no library -- #{name}"
199
68
  end
69
+ yield(lib) if block_given?
70
+ lib
200
71
  end
201
- return @bin_path
202
- end
203
72
 
204
- # Return the path to the data directory associated with the given
205
- # package name. Normally this is just
206
- # "#{Config::CONFIG['datadir']}/#{package_name}", but may be
207
- # modified by packages like RubyGems and Rolls to handle
208
- # versioned data directories.
209
- def datadir(versionless=false)
210
- if version and not versionless
211
- File.join(Config::CONFIG['datadir'], name, version)
212
- else
213
- File.join(Config::CONFIG['datadir'], name)
73
+ #
74
+ def initialize(location, name=nil)
75
+ @location = location
76
+ @name = name
214
77
  end
215
- end
216
-
217
- # Return the path to the configuration directory.
218
- #--
219
- # Can or should configuration directories be versioned?
220
- #++
221
- def confdir
222
- File.join(location, 'data')
223
- #if version
224
- # File.join(Config::CONFIG['confdir'], name, version)
225
- #else
226
- # File.join(Config::CONFIG['datadir'], name)
227
- #end
228
- end
229
-
230
- # Require find.
231
- def require_find(file)
232
- file = roll.index_file if (file.nil? or file.empty?)
233
- glob = File.join('{' + load_path.join(',') + '}', file + "{.rb,#{Library.dlext},}")
234
- Dir.glob(glob).first
235
- end
236
-
237
- # Load find.
238
- def load_find(file)
239
- file = roll.index_file if (file.nil? or file.empty?)
240
- glob = File.join('{' + load_path.join(',') + '}', file)
241
- Dir.glob(glob).first
242
- end
243
78
 
244
- # Library specific #require.
245
- def require(file)
246
- if path = require_find(file)
247
- Kernel.require(path)
248
- else
249
- raise LoadError, "no such file to load -- #{name}:#{file}"
79
+ #
80
+ def location
81
+ @location
250
82
  end
251
- end
252
83
 
253
- # Library specific load.
254
- def load(file, wrap=nil)
255
- if path = load_find(file)
256
- Kernel.load(path, wrap)
257
- else
258
- raise LoadError, "no such file to load -- #{name}:#{file}"
84
+ #
85
+ def name
86
+ @name ||= metadata.name
259
87
  end
260
- end
261
88
 
262
- # Library specific autoload.
263
- def autoload(base, file)
264
- if path = require_find(file)
265
- Kernel.autoload(base, file)
266
- else
267
- raise LoadError, "no such file to autoload -- #{name}:#{file}"
89
+ #
90
+ def version
91
+ @version ||= metadata.version
268
92
  end
269
- end
270
93
 
271
- # Require into module.
272
- def module_require(mod, file)
273
- if path = require_find(file)
274
- mod.module_require(path) # FIXME
275
- else
276
- raise LoadError, "no such file to load -- #{name}:#{file}"
94
+ #
95
+ def active?
96
+ @active ||= metadata.active
277
97
  end
278
- end
279
98
 
280
- # Load into module.
281
- def module_load(mod, file)
282
- if path = load_find(file)
283
- mod.module_load(path) # FIXME
284
- else
285
- raise LoadError, "no such file to load -- #{name}:#{file}"
99
+ #
100
+ def loadpath
101
+ @loadpath ||= metadata.loadpath
286
102
  end
287
- end
288
103
 
289
- # Library specific autoload for module.
290
- def module_autoload(mod, base, file)
291
- if path = require_find(file)
292
- mod.autoload_without_roll(base, file)
293
- else
294
- raise LoadError, "no such file to autoload -- #{name}:#{file}"
104
+ #
105
+ def requires
106
+ @requires ||= metadata.requires
295
107
  end
296
- end
297
108
 
298
- # Put the libs load paths into the global lookup.
299
- #--
300
- # TODO Maybe call 'import' instead?
301
- #++
302
- def utilize
303
- lib_path.each do |path|
304
- Library.load_path.unshift(path)
109
+ #
110
+ def released
111
+ @released ||= metadata.released
305
112
  end
306
- Library.load_path.uniq!
307
- self
308
- end
309
-
310
- # Class instance variable @ledger stores the library references.
311
113
 
312
- @ledger = {}
313
-
314
- class << self
315
-
316
- # Scan the site locations for libraries.
317
- def scan
318
- # First we add Ruby core and standard libraries.
319
- @ledger['ruby'] = Library.new(nil, :name=>'ruby', :version=>VERSION, :load_path=>Library.ruby_path)
320
-
321
- scan_working() if $DEBUG
322
-
323
- projs1 = Dir.glob( '{' + $LOAD_SITE.join(',') + '}/*{/meta,}/*.roll', File::FNM_CASEFOLD )
324
- projs2 = Dir.glob( '{' + $LOAD_SITE.join(',') + '}/*/*{/meta,}/*.roll', File::FNM_CASEFOLD )
325
- projs3 = Dir.glob( '{' + $LOAD_SITE.join(',') + '}/*/*/*{/meta,}/*.roll', File::FNM_CASEFOLD )
326
-
327
- projs = projs1 + projs2 + projs3
328
-
329
- #dirs = projs.collect do |prj|
330
- # metafile = File.basename(prj)
331
- # dir = File.dirname(prj)
332
- # dir = File.dirname(dir) if dir =~ /meta$/
333
- # dir
334
- #end
335
-
336
- projs.uniq!
337
-
338
- #dirs -= $LOAD_SITE
114
+ #
115
+ def verify
116
+ requires.each do |(name, constraint)|
117
+ Library.open(name, constraint)
118
+ end
119
+ end
339
120
 
340
- projs.each do |proj|
341
- name, ver = *File.basename(proj).chomp('.roll').split('-')
342
- dir = File.dirname(proj)
343
- dir = File.dirname(dir) if File.basename(dir) == 'meta'
121
+ # Find first matching +file+.
344
122
 
345
- name = name.downcase
123
+ #def find(file, suffix=true)
124
+ # case File.extname(file)
125
+ # when *SUFFIXES
126
+ # find = File.join(lookup_glob, file)
127
+ # else
128
+ # find = File.join(lookup_glob, file + SUFFIX_PATTERN) #'{' + ".rb,#{DLEXT}" + '}')
129
+ # end
130
+ # Dir[find].first
131
+ #end
346
132
 
347
- #if versions.empty?
348
- # @ledger[name] ||= Library.new(dir, :name=>name, :version=>'0') #Version.new('0', dir)
349
- #else
350
- @ledger[name] ||= []
351
- @ledger[name] << Library.new(dir, :name=>name, :version=>ver)
352
- #end
133
+ # Standard loadpath search.
134
+ #
135
+ def find(file, suffix=true)
136
+ if suffix
137
+ SUFFIXES.each do |ext|
138
+ loadpath.each do |lpath|
139
+ f = File.join(location, lpath, file + ext)
140
+ return f if File.file?(f)
141
+ end
142
+ end
143
+ else
144
+ loadpath.each do |lpath|
145
+ f = File.join(location, lpath, file)
146
+ return f if File.file?(f)
147
+ end
353
148
  end
149
+ nil
354
150
  end
355
151
 
356
- # Scan current working location to see if there's
357
- # a library. This will ascend from the current
358
- # working directy to one level below root looking
359
- # for a lib/ directory.
360
- #--
361
- # TODO CHANGE TO LOOK FRO INDEX FILE.
362
- #++
363
- def scan_working
364
- paths = Dir.pwd.split('/')
365
- (paths.size-1).downto(1) do |n|
366
- dir = File.join( *(paths.slice(0..n) << 'lib') )
367
- if File.directory? dir
368
- $LOAD_SITE.unshift dir
152
+ # Does this library have a matching +file+? If so, the full-path
153
+ # of the file is returned.
154
+ #
155
+ # Unlike #find, this also matches within the library directory
156
+ # itself, eg. <tt>lib/foo/*</tt>. It is used by #aquire.
157
+ #
158
+ def include?(file, suffix=true)
159
+ if suffix
160
+ SUFFIXES.each do |ext|
161
+ loadpath.each do |lpath|
162
+ f = File.join(location, lpath, name, file + ext)
163
+ return f if File.file?(f)
164
+ f = File.join(location, lpath, file + ext)
165
+ return f if File.file?(f)
166
+ end
167
+ end
168
+ else
169
+ loadpath.each do |lpath|
170
+ f = File.join(location, lpath, name, file)
171
+ return f if File.file?(f)
172
+ f = File.join(location, lpath, file)
173
+ return f if File.file?(f)
369
174
  end
370
175
  end
176
+ nil
371
177
  end
372
178
 
373
- # Return a list of library names.
374
- def list
375
- @ledger.keys
376
- end
179
+ #def include?(file)
180
+ # case File.extname(file)
181
+ # when *SUFFIXES
182
+ # find = File.join(lookup_glob, "{#{name}/,}" + file)
183
+ # else
184
+ # find = File.join(lookup_glob, "{#{name}/,}" + file + SUFFIX_PATTERN) #'{' + ".rb,#{DLEXT}" + '}')
185
+ # end
186
+ # Dir[find].first
187
+ #end
377
188
 
378
- # Libraries are Singleton pattern.
379
- def instance(name, constraint=nil)
380
- name = name.to_s
381
- #raise "no library -- #{name}" unless @ledger.include?( name )
382
- return nil unless @ledger.include?(name)
383
- case lib = @ledger[name]
384
- when Library
385
- return lib unless constraint
386
- raise VersionConflict, "previously selected library version" # -- #{lib.version}"
387
- #when Version
388
- # @ledger[name] = new(lib.location, :name=>name, :version=>lib) #new(name, lib, lib.location)
389
- when Array
390
- if constraint
391
- compare = VersionNumber.constrant_lambda(constraint)
392
- version = lib.select(&compare).max
393
- else
394
- version = lib.max
395
- end
396
- unless version
397
- raise VersionError, "no library version -- #{name} #{constraint}"
398
- end
399
- @ledger[name] = version #new(version.location, :name=>name, :version=>version) #new(name, version, version.location)
189
+ #
190
+ def require(file)
191
+ if path = include?(file)
192
+ require_absolute(path)
400
193
  else
401
- raise "this should never happen"
194
+ load_error = LoadError.new("no such file to require -- #{name}:#{file}")
195
+ raise clean_backtrace(load_error)
402
196
  end
403
- @ledger[name].roll # Make sure the roll file is loaded.
404
- @ledger[name]
405
197
  end
406
198
 
407
- # A shortcut for #instance.
408
- alias_method :[], :instance
409
-
410
- # Same as #instance but will raise and error if the library is not found.
411
- def open(name, constraint=nil, &yld)
412
- lib = instance(name, constraint)
413
- unless lib
414
- raise LoadError, "no library -- #{name}"
199
+ # NOT SURE ABOUT USING THIS
200
+ def require_absolute(file)
201
+ #Library.load_monitor[file] << caller if $LOAD_MONITOR
202
+ Library.load_stack << self
203
+ begin
204
+ success = original_require(file)
205
+ #rescue LoadError => load_error
206
+ # raise clean_backtrace(load_error)
207
+ ensure
208
+ Library.load_stack.pop
415
209
  end
416
- yield(lib) if yld
417
- lib
210
+ success
418
211
  end
419
212
 
420
- end
421
-
422
- # VersionError is raised when a requested version cannot be found.
423
- class VersionError < ::RangeError # :nodoc:
424
- end
213
+ #
214
+ def load(file, wrap=nil)
215
+ if path = include?(file, false)
216
+ load_absolute(path, wrap)
217
+ else
218
+ load_error = LoadError.new("no such file to load -- #{name}:#{file}")
219
+ clean_backtrace(load_error)
220
+ end
221
+ end
425
222
 
426
- # VersionConflict is raised when selecting another version
427
- # of a library when a previous version has already been selected.
428
- class VersionConflict < ::LoadError # :nodoc:
429
- end
430
- end
223
+ #
224
+ def load_absolute(file, wrap=nil)
225
+ #Library.load_monitor[file] << caller if $LOAD_MONITOR
226
+ Library.load_stack << self
227
+ begin
228
+ success = original_load(file, wrap)
229
+ #rescue LoadError => load_error
230
+ # raise clean_backtrace(load_error)
231
+ ensure
232
+ Library.load_stack.pop
233
+ end
234
+ success
235
+ end
431
236
 
237
+ # Inspection.
238
+ def inspect
239
+ if @version
240
+ %[#<Library #{name}/#{@version} @location="#{location}">]
241
+ else
242
+ %[#<Library #{name} @location="#{location}">]
243
+ end
244
+ end
432
245
 
433
- module ::Config
434
- # Return the path to the data directory associated with the given
435
- # package name. Normally this is just
436
- # "#{Config::CONFIG['datadir']}/#{package_name}", but may be
437
- # modified by packages like RubyGems and Rolls to handle
438
- # versioned data directories.
439
- def self.datadir(name, versionless=false)
440
- if lib = Library.instance( name )
441
- lib.datadir( versionless )
442
- else
443
- File.join(CONFIG['datadir'], name)
246
+ def to_s
247
+ inspect
444
248
  end
445
- end
446
249
 
447
- # Return the path to the configuration directory.
448
- def self.confdir(name)
449
- if lib = Library.instance( name )
450
- lib.confdir
451
- else
452
- File.join(CONFIG['datadir'], name)
250
+ # Compare by version.
251
+ def <=>(other)
252
+ version <=> other.version
453
253
  end
454
- end
455
- end
456
254
 
255
+ # # List of subdirectories that are searched when loading.
256
+ # #--
257
+ # # This defualts to ['lib/{name}', 'lib']. The first entry is
258
+ # # usually proper location; the latter is added for default
259
+ # # compatability with the traditional require system.
260
+ # #++
261
+ # def libdir
262
+ # loadpath.map{ |path| File.join(location, path) }
263
+ # end
264
+ #
265
+ # # Does the library have any lib directories?
266
+ # def libdir?
267
+ # lib.any?{ |d| File.directory?(d) }
268
+ # end
457
269
 
458
- module ::Kernel
270
+ # Location of executable. This is alwasy bin/. This is a fixed
271
+ # convention, unlike lib/ which needs to be more flexable.
272
+ def bindir ; File.join(location, 'bin') ; end
459
273
 
460
- # Activate a library.
461
- def library(name, constraint=nil)
462
- Library.open(name, constraint)
463
- end
464
- module_function :library
465
-
466
- # Use library. This activates a library, and adds
467
- # it's load_path to the global $LOAD_PATH.
468
- #--
469
- # Maybe call #import instead ?
470
- #++
471
- def use(name, constraint=nil)
472
- Library.open(name, constraint).utilize
473
- end
274
+ # Is there a <tt>bin/</tt> location?
275
+ def bindir? ; File.exist?(bindir) ; end
474
276
 
277
+ # Location of library system configuration files.
278
+ # This is alwasy the <tt>etc/</tt> directory.
279
+ def confdir ; File.join(location, 'etc') ; end
475
280
 
476
- def self.parse_load_parameters(file)
477
- if must = file.index(':')
478
- name, path = file.split(':')
479
- else
480
- name, *rest = file.split('/')
481
- path = File.join(*rest)
482
- end
483
- name = nil if name == ''
484
- lib = name ? Library.instance(name) : nil
485
- raise LoadError, "no library found -- #{file}" if must && !lib
486
- return lib, path
487
- end
281
+ # Is there a <tt>etc/</tt> location?metadata.name
282
+ def confdir? ; File.exist?(confdir) ; end
488
283
 
489
- # Rolls requires a modification to #require and #load.
490
- # So that it is not neccessary to make the library() call
491
- # if you just want the latest version.
492
- #
493
- # This would be a bit simpler if we mandated the
494
- # use of the ':' notation when specifying the library
495
- # name. Use of the ':' is robust. But we cannot do this
496
- # w/o loosing backward-compatability. Using '/' in its
497
- # place has the potential for pathname clashing, albeit
498
- # the likelihood is small. There are two ways to bypass
499
- # the problem if it arises. Use 'ruby:{path}' if the
500
- # conflicting lib is a ruby core or standard library.
501
- # Use ':{path}' to bypass Roll system altogether.
502
-
503
- # # Require script.
504
- # def require(file)
505
- # if file.index(':')
506
- # name, file = file.split(':')
507
- # if name == ''
508
- # Kernel.require(file)
509
- # #if lib == 'ruby'
510
- # # Ruby.require(file)
511
- # elsif lib = Library.instance(name)
512
- # lib.require(file)
513
- # else
514
- # raise LoadError, "no library found -- #{name}"
515
- # end
516
- # else
517
- # name, *rest = file.split('/')
518
- # if lib = Library.instance(name)
519
- # lib.require(File.join(*rest))
520
- # else
521
- # Kernel.require(file)
522
- # end
523
- # end
524
- # end
525
-
526
- # Require script.
527
- def require(file)
528
- lib, path = *Kernel.parse_load_parameters(file)
529
- if lib
530
- lib.require(path)
531
- else
532
- Kernel.require(file)
533
- end
534
- end
284
+ # Location of library shared data directory.
285
+ # This is always the <tt>data/</tt> directory.
286
+ def datadir ; File.join(location, 'data') ; end
535
287
 
536
- # # Load script.
537
- # def load(file, wrap=nil)
538
- # if file.index(':')
539
- # name, file = file.split(':')
540
- # if name == ''
541
- # Kernel.require(file)
542
- # #if lib == 'ruby'
543
- # # Ruby.load(file, safe)
544
- # elsif lib = Library.instance(name)
545
- # lib.load(file, wrap)
546
- # else
547
- # raise LoadError, "no library found -- #{name}"
548
- # end
549
- # else
550
- # name, *rest = file.split('/')
551
- # if lib = Library.instance(name)
552
- # lib.load(File.join(*rest))
553
- # else
554
- # Kernel.load(file, wrap)
555
- # end
556
- # end
557
- # end
558
-
559
- # Require script.
560
- def load(file, wrap=false)
561
- lib, path = *Kernel.parse_load_parameters(file)
562
- if lib
563
- lib.load(path, wrap)
564
- else
565
- Kernel.load(file, wrap)
566
- end
567
- end
288
+ # Is there a <tt>data/</tt> location?
289
+ def datadir? ; File.exist?(datadir) ; end
568
290
 
569
- # #
570
- # def autoload(base, file)
571
- # if file.index(':')
572
- # name, file = file.split(':')
573
- # if name == ''
574
- # Kernel.autoload(base, file)
575
- # elsif lib = Library.instance(name)
576
- # lib.autoload(base, file)
577
- # else
578
- # raise LoadError, "no library found -- #{name}"
579
- # end
580
- # else
581
- # name, *rest = file.split('/')
582
- # if lib = Library.instance(name)
583
- # lib.autoload(base, File.join(*rest))
584
- # else
585
- # Kernel.autoload(base, file)
586
- # end
587
- # end
588
- # end
589
-
590
- =begin
591
- # Autoload script.
592
- def autoload(base, file)
593
- lib, path = *Kernel.parse_load_parameters(file)
594
- if lib
595
- lib.autoload(base, path)
596
- else
597
- Kernel.autoload(base, file)
291
+ # Access to secondary metadata.
292
+ def metadata
293
+ @metadata ||= Metadata.new(location)
598
294
  end
599
- end
600
- =end
601
295
 
602
- end
603
-
604
- # TODO
605
- class ::Module
296
+ private
606
297
 
607
- =begin
608
- alias_method :autoload_without_roll, :autoload
298
+ #
299
+ #def lookup_glob
300
+ # @lookup_glob ||= File.join(location, '{' + loadpath.join(',') + '}')
301
+ #end
609
302
 
610
- #
611
- def autoload(base, file)
612
- lib, path = *Kernel.parse_load_parameters(file)
613
- if lib
614
- lib.module_autoload(self, base, path)
615
- else
616
- autoload_without_roll(base, file)
303
+ #
304
+ def clean_backtrace(error)
305
+ if $DEBUG
306
+ error
307
+ else
308
+ bt = error.backtrace
309
+ bt = bt.reject{ |e| /roll/ =~ e } if bt
310
+ error.set_backtrace(bt)
311
+ error
312
+ end
617
313
  end
618
- end
619
- =end
620
-
621
- # TODO
622
314
 
623
- # Adds importing to Module class called against +self+ as default.
624
-
625
- # def module_require()
626
- # end
627
-
628
- # def module_load()
629
- # end
315
+ end
630
316
 
631
317
  end
632
318
 
633
- # Prime the library ledger.
634
- Library.scan
635
-