roll 0.8.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/{LICENSE → COPYING} +1 -1
- data/HISTORY +62 -0
- data/README.rdoc +169 -0
- data/TODO +4 -0
- data/bin/roll +3 -44
- data/lib/oll.rb +1 -2
- data/lib/roll.rb +87 -0
- data/lib/roll/command.rb +207 -0
- data/lib/roll/config.rb +80 -0
- data/lib/roll/environment.rb +317 -0
- data/lib/roll/errors.rb +13 -0
- data/lib/roll/kernel.rb +41 -0
- data/lib/roll/ledger.rb +299 -0
- data/lib/roll/library.rb +241 -558
- data/lib/roll/locals.rb +96 -0
- data/lib/roll/metadata.rb +112 -0
- data/lib/roll/original.rb +10 -0
- data/lib/roll/version.rb +91 -101
- data/meta/active +1 -0
- data/meta/authors +1 -0
- data/meta/contact +1 -0
- data/meta/created +1 -0
- data/meta/description +5 -0
- data/meta/homepage +1 -0
- data/meta/maintainer +1 -0
- data/meta/name +1 -0
- data/meta/repository +1 -0
- data/meta/ruby +2 -0
- data/meta/suite +1 -0
- data/meta/summary +1 -0
- data/meta/version +1 -0
- data/script/rdoc +4 -0
- data/script/setup +1344 -0
- data/script/test +23 -0
- data/test/benchmarks/vsgems.rb +11 -0
- data/test/benchmarks/vsgems_bm.rb +17 -0
- data/test/demonstrations/01_library.rdoc +33 -0
- data/test/demonstrations/04_version.rdoc +56 -0
- data/test/fixtures/env.list +1 -0
- data/{demo/sample → test/fixtures}/inspect.rb +0 -0
- data/test/fixtures/tryme/1.0/lib/tryme.rb +1 -0
- data/test/fixtures/tryme/1.0/meta/homepage +1 -0
- data/test/fixtures/tryme/1.0/meta/name +1 -0
- data/test/fixtures/tryme/1.0/meta/version +1 -0
- data/test/fixtures/tryme/1.1/lib/tryme.rb +1 -0
- data/test/fixtures/tryme/1.1/meta/homepage +1 -0
- data/test/fixtures/tryme/1.1/meta/name +1 -0
- data/test/fixtures/tryme/1.1/meta/version +1 -0
- data/test/{test_version.rb → unit/version_test.rb} +21 -21
- data/test/unitcases/version_case.rb +69 -0
- metadata +102 -65
- data/README +0 -17
- data/demo/bench/bench_load.rb +0 -7
- data/demo/sample/tryme/1.0/lib/tryme.rb +0 -1
- data/demo/sample/tryme/1.1/lib/tryme.rb +0 -1
- data/lib/roll/attributes.rb +0 -72
- data/lib/roll/package.rb +0 -300
- data/lib/roll/remote.rb +0 -37
- data/meta/ROLL-0.8.0.roll +0 -21
- data/task/rdoc +0 -9
- data/task/setup +0 -1616
- data/task/test +0 -5
- data/test/test_library.rb +0 -10
data/lib/roll/ledger.rb
ADDED
@@ -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
|
+
|
data/lib/roll/library.rb
CHANGED
@@ -1,635 +1,318 @@
|
|
1
|
-
#
|
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
|
-
|
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
|
-
|
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
|
-
|
68
|
-
$LOAD_PATH
|
69
|
-
end
|
10
|
+
class Library
|
70
11
|
|
71
|
-
|
72
|
-
|
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
|
-
|
83
|
-
|
15
|
+
#
|
16
|
+
#SUFFIXES = ['', '.rb', '.rbw', '.so', '.bundle', '.dll', '.sl', '.jar']
|
17
|
+
SUFFIXES = ['', '.rb', '.rbw', '.so', '.bundle', '.dll', '.sl', '.jar']
|
84
18
|
|
85
|
-
|
86
|
-
|
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
|
-
|
98
|
-
|
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
|
-
|
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
|
-
|
103
|
-
@version = VersionNumber.new(@version) unless VersionNumber === @version
|
104
|
-
end
|
31
|
+
library = ledger[name]
|
105
32
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
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
|
-
|
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
|
-
|
129
|
-
|
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
|
-
|
164
|
-
|
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
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
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
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
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
|
-
|
245
|
-
|
246
|
-
|
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
|
-
|
254
|
-
|
255
|
-
|
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
|
-
|
263
|
-
|
264
|
-
|
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
|
-
|
272
|
-
|
273
|
-
|
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
|
-
|
281
|
-
|
282
|
-
|
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
|
-
|
290
|
-
|
291
|
-
|
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
|
-
|
299
|
-
|
300
|
-
|
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
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
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
|
-
#
|
357
|
-
#
|
358
|
-
#
|
359
|
-
#
|
360
|
-
|
361
|
-
#
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
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
|
-
#
|
374
|
-
|
375
|
-
|
376
|
-
|
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
|
-
#
|
379
|
-
def
|
380
|
-
|
381
|
-
|
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
|
-
|
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
|
-
#
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
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
|
-
|
417
|
-
lib
|
210
|
+
success
|
418
211
|
end
|
419
212
|
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
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
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
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
|
-
|
434
|
-
|
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
|
-
|
448
|
-
|
449
|
-
|
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
|
-
|
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
|
-
|
461
|
-
|
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
|
-
|
477
|
-
|
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
|
-
|
490
|
-
|
491
|
-
|
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
|
-
#
|
537
|
-
|
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
|
-
|
571
|
-
|
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
|
-
|
603
|
-
|
604
|
-
# TODO
|
605
|
-
class ::Module
|
296
|
+
private
|
606
297
|
|
607
|
-
|
608
|
-
|
298
|
+
#
|
299
|
+
#def lookup_glob
|
300
|
+
# @lookup_glob ||= File.join(location, '{' + loadpath.join(',') + '}')
|
301
|
+
#end
|
609
302
|
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
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
|
-
|
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
|
-
|