roll 0.8.0

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.
@@ -0,0 +1,300 @@
1
+ require 'yaml'
2
+ require 'roll/attributes'
3
+
4
+ module Roll
5
+
6
+ class Package
7
+ include Attributes
8
+
9
+ # Read package information from a YAML file.
10
+ def self.open(file=nil, options={})
11
+ unless file
12
+ file = Dir.glob(filename, File::FNM_CASEFOLD).first
13
+ raise "Manifest file is required." unless file
14
+ end
15
+ data = YAML::load(File.open(file))
16
+ data.update(options)
17
+ data.update(:file => file)
18
+ new(data)
19
+ end
20
+
21
+ # Possible file name (was for Fileable).
22
+ def self.filename
23
+ '{,meta/}*.roll'
24
+ end
25
+
26
+ # New Package. Pass in a data hash to populate the object.
27
+ # TODO Support self setter block?
28
+ def initialize(data={}) #, &yld)
29
+ data.each do |k,v|
30
+ send( "#{k}=", v ) rescue nil
31
+ end
32
+ #if yld
33
+ # yld.to_h.each do |k,v|
34
+ # send( "#{k}=", v ) rescue nil
35
+ # end
36
+ #end
37
+
38
+ base = File.basename(file).chomp('.roll')
39
+ if base.index('-') # Just in case you want to load ir from a non-conforming file.
40
+ name, version = base.split('-')
41
+ name = name.downcase # TODO Is this too restrictive?
42
+ @name = name
43
+ @version = version
44
+ end
45
+
46
+ self
47
+ end
48
+
49
+ # Name of the package file (if used).
50
+ attr_accessor :file
51
+
52
+ # Path to the project file (if used).
53
+ def location
54
+ File.dirname(@file) if @file
55
+ end
56
+
57
+ # Indicates if this project information was read from a file.
58
+ # Returns the file's name if so.
59
+ def read? ; file ; end
60
+
61
+ #---------------------#
62
+ # GENERAL INFORMATION #
63
+ #---------------------#
64
+
65
+ # The title of the project (free-form, defaults to name).
66
+ attr_accessor :title
67
+
68
+ # One-line description of the package (Max 60 chars.)
69
+ attr_accessor :subtitle, :brief
70
+
71
+ # More detailed description of the package.
72
+ attr_accessor :description, :summary
73
+
74
+ # "Unix" name of the project.
75
+ attr_accessor :name, :project
76
+
77
+ # The date the project was started.
78
+ attr_accessor :created
79
+
80
+ # Copyright notice.
81
+ attr_accessor :copyright
82
+
83
+ # Distribution License.
84
+ attr_accessor :license
85
+
86
+ # Project slogan or "trademark" phrase.
87
+ attr_accessor :slogan
88
+
89
+ # General one-word software category.
90
+ attr_accessor :category
91
+
92
+ # Author(s) of this project.
93
+ # (Usually in "name <email>" format.)
94
+ attr_accessor :author
95
+
96
+ # Contact(s) (defaults to authors).
97
+ attr_accessor :contact
98
+
99
+ # Gerenal Email address (defaults to first contact's address, if given).
100
+ attr_accessor :email
101
+
102
+ # Official domain associated with this package.
103
+ attr_accessor :domain
104
+
105
+ # Project's homepage.
106
+ attr_accessor :homepage
107
+
108
+ # Project's development site.
109
+ attr_accessor :development, :devsite
110
+
111
+ # Internet address(es) to documentation pages.
112
+ attr_accessor :documentation, :docs
113
+
114
+ # Internet address(es) to downloadable packages.
115
+ attr_accessor :download
116
+
117
+ # Internet address for project wiki.
118
+ attr_accessor :wiki
119
+
120
+ # Project's mailing list or other contact email.
121
+ attr_accessor :list
122
+
123
+ # Generate documentation on installation?
124
+ attr_accessor :document
125
+
126
+ def name ; @name || project ; end
127
+ def title ; @title || project ; end
128
+ def contact ; @contact || author ; end
129
+ def email ; @email || contact ; end
130
+ def license ; @license || 'Ruby' ; end
131
+
132
+ # Subtitle is limited to 60 characters.
133
+ def subtitle ; @subtitle.to_s[0..59] ; end
134
+
135
+ # Returns a standard taguri id for the library and release.
136
+ def project_taguri
137
+ "tag:#{name}.#{domain},#{created}" # or released?
138
+ end
139
+
140
+ # Version Information
141
+
142
+ module Version
143
+ include Attributes
144
+
145
+ # Version number (eg. '1.0.0').
146
+ attr_accessor :version
147
+
148
+ # Status of this release: alpha, beta, RC1, etc.
149
+ attr_accessor :status
150
+
151
+ # Date of release (defaults to Time.now).
152
+ attr_accessor :released
153
+
154
+ # Build number (if true, defaults to a number based on current date-time).
155
+ attr_accessor :buildno
156
+
157
+ # Current release code name.
158
+ attr_accessor :codename
159
+
160
+ # If buildno is set to true, than returns a time stamp.
161
+ def buildno
162
+ bn = stamp.buildno if stamp
163
+ unless bn
164
+ if TrueClass === @buildno
165
+ bn = Time.now.strftime("%H*60+%M")
166
+ else
167
+ bn = @buildno
168
+ end
169
+ end
170
+ return bn
171
+ end
172
+ end
173
+
174
+ include Version
175
+
176
+ # Content Descriptions
177
+
178
+ module Contents
179
+ include Attributes
180
+
181
+ # Files in this package that are executables.
182
+ attr_accessor :executable, :executables
183
+
184
+ # Library files in this package that are *public*.
185
+ # This is akin to load_path but specifies specific files
186
+ # that can be loaded from the outside --where as those
187
+ # not listed are considerd *private*.
188
+ #
189
+ # NOTE: This is not enforced --and may never be. It
190
+ # complicates library loading. Ie. how to distinguish public
191
+ # loading from external loading. But it something that can be
192
+ # consider more carfully in the future. For now it can serve
193
+ # as an optional reference.
194
+ attr_accessor :library, :libraries
195
+
196
+ # Location(s) of executables.
197
+ attr_accessor :bin_path, :bin_paths
198
+
199
+ # Root location(s) of libraries (used by Rolls).
200
+ # If you plan to support Gems, this would be something like:
201
+ #
202
+ # 'lib/facets'
203
+ #
204
+ # If not, then the default ('lib') is nice b/c it means one less
205
+ # layer in your project heirarchy.
206
+ attr_accessor :lib_path, :lib_paths, :load_path, :load_paths
207
+
208
+ # Traditional load path (used by RubyGems).
209
+ # The default is 'lib', which is usually fine.
210
+ attr_accessor :gem_path, :gem_paths
211
+
212
+ # Default lib to load when requiring only on a package name. Eg.
213
+ #
214
+ # require 'facets'
215
+ #
216
+ attr_accessor :index_library
217
+
218
+ # Root location(s) of libraries.
219
+ #--
220
+ # TODO This is an intersting idea. Instead of fixed locations in
221
+ # the file system one could register "virtual locations" which map
222
+ # to real locations. Worth the added flexability?
223
+ #++
224
+ #attr_accessor :register
225
+
226
+ def executable ; [@executable || 'bin/**/*'].flatten ; end
227
+ def library ; [@library || 'lib/**/*'].flatten ; end
228
+
229
+ def gem_path ; [@gem_path || 'lib'].flatten ; end
230
+ def lib_path ; [@lib_path || 'lib'].flatten ; end
231
+
232
+ def index_library ; @index_library || 'index.rb' ; end
233
+
234
+ #def register ; @register || { name => 'lib' } ; end
235
+ end
236
+
237
+ include Contents
238
+
239
+ # Security Information
240
+
241
+ module Security
242
+ include Attributes
243
+
244
+ # Encryption digest type used.
245
+ # (md5, sha1, sha128, sha256, sha512).
246
+ attr_accessor :digest
247
+
248
+ # Public key file associated with this library. This is useful
249
+ # for security purposes especially remote loading. [pubkey.pem]
250
+ attr_accessor :public_key
251
+
252
+ # Private key file associated with this library. This is useful
253
+ # for security purposes especially remote loading. [_privkey.pem]
254
+ attr_accessor :private_key
255
+
256
+ def digest ; @digest || 'md5' ; end
257
+ def public_key ; @public_key || 'pubkey.pem' ; end
258
+ def private_key ; @private_key || '_privkey.pem' ; end
259
+ end
260
+
261
+ include Security
262
+
263
+ # Source Control Managment Information
264
+
265
+ module Control
266
+ include Attributes
267
+
268
+ # Specifices the type of revision control system used.
269
+ # darcs, svn, cvs, etc.
270
+ attr_accessor :scm
271
+
272
+ # Files that are tracked under revision control.
273
+ # Default is all less standard exceptions.
274
+ # '+' and '-' prefixes can be used to augment the list
275
+ # rather than fully override it.
276
+ attr_accessor :track, :scm_files
277
+
278
+ # Internet address to source code repository.
279
+ # (http://, ftp://, etc.)
280
+ attr_accessor :repository, :repo
281
+
282
+ # Changelog file.
283
+ attr_accessor :changelog
284
+ end
285
+
286
+ include Control
287
+
288
+ # Validation
289
+
290
+ validate "name is required" do
291
+ name
292
+ end
293
+
294
+ validate "version is required" do
295
+ version
296
+ end
297
+
298
+ end
299
+
300
+ end
@@ -0,0 +1,37 @@
1
+ module Roll
2
+
3
+ # Remote install cache (hmmm...should this be optional feature?)
4
+ REMOTE_CACHE = File.expand_path( '~/.lib/site_ruby/1.8/' )
5
+ FileUtils.mkdir_p REMOTE_CACHE unless File.directory? REMOTE_CACHE
6
+ $:.unshift REMOTE_CACHE
7
+
8
+ #
9
+
10
+ def remote_install(fname)
11
+ # Bit of a shortcoming here since it's not very efficient to
12
+ # be searching a remote location for multiple matches.
13
+ # .so suffix must be specified explicity on the remote end.
14
+ fname = fname + '.rb' unless fname =~ /\.rb$/ or fname =~ /\.so$/
15
+
16
+ # get signiture
17
+ url = File.join( source, 'meta', 'signitures', fname )
18
+ $stderr << "remote signiture -- " + url if $DEBUG
19
+ sig = URI.parse( url ).read
20
+
21
+ # get file
22
+ url = File.join( source, fname )
23
+ $stderr << "remote file -- " + url if $DEBUG
24
+ file = URI.parse( url ).read
25
+
26
+ # verify file and signiture
27
+ if Signer.verify?( pubkey, sig, file )
28
+ infile = File.join( REMOTE_CACHE, fname )
29
+ indir = File.dirname( infile )
30
+ FileUtils.mkdir_p indir
31
+ File.open( infile, 'w' ) { |f| f << file }
32
+ else
33
+ raise
34
+ end
35
+ end
36
+
37
+ end
@@ -0,0 +1,127 @@
1
+ # TITLE:
2
+ #
3
+ # VersionNumber
4
+ #
5
+ # DESCRIPTION:
6
+ #
7
+ # VersionNumber is a simplified form of a Tuple class
8
+ # desgined specifically for dealing with version numbers.
9
+ #
10
+ # AUTHOR:
11
+ #
12
+ # - Thomas Sawyer (7rans)
13
+ #
14
+ # LICENSE:
15
+ #
16
+ # Copyright (c) 2005 Thomas Sawyer
17
+ #
18
+ # Ruby License
19
+ #
20
+ # This module is free software. You may use, modify, and/or redistribute this
21
+ # software under the same terms as Ruby.
22
+ #
23
+ # This program is distributed in the hope that it will be useful, but WITHOUT
24
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
25
+ # FOR A PARTICULAR PURPOSE.
26
+ #
27
+ # TODO:
28
+ #
29
+ # - Maybe add Kernel method #version ?
30
+ #
31
+ # - If Tuple were standard part of Ruby this probably would
32
+ # not be needed or at least might be simple sublcass instead.
33
+
34
+
35
+ # = VersionNumber
36
+ #
37
+ # VersionNumber is a simplified form of a Tuple class
38
+ # desgined specifically for dealing with version numbers.
39
+ #
40
+ class VersionNumber #< Tuple
41
+
42
+ #include Enumerable
43
+ include Comparable
44
+
45
+ def initialize( *args )
46
+ args = args.join('.').split(/\W+/)
47
+ @self = args.collect { |i| i.to_i }
48
+ end
49
+
50
+ def to_s ; @self.join('.') ; end
51
+
52
+ # This is here only becuase File.join calls it instead of to_s.
53
+
54
+ def to_str ; @self.join('.') ; end
55
+
56
+ def inspect
57
+ @self.to_s
58
+ end
59
+
60
+ def [](i)
61
+ @self.fetch(i,0)
62
+ end
63
+
64
+ # "Spaceship" comparsion operator.
65
+
66
+ def <=>( other )
67
+ #other = other.to_t
68
+ [@self.size, other.size].max.times do |i|
69
+ c = @self[i] <=> other[i]
70
+ return c if c != 0
71
+ end
72
+ 0
73
+ end
74
+
75
+ # For pessimistic constraint (like '~>' in gems)
76
+
77
+ def =~( other )
78
+ #other = other.to_t
79
+ upver = other.dup
80
+ upver[0] += 1
81
+ @self >= other and @self < upver
82
+ end
83
+
84
+ # Major is the first number in the version series.
85
+
86
+ def major ; @self[0] ; end
87
+
88
+ # Minor is the second number in the version series.
89
+
90
+ def minor ; @self[1] || 0 ; end
91
+
92
+ # Teeny is third number in the version series.
93
+
94
+ def teeny ; @self[2] || 0 ; end
95
+
96
+ # Delegate to the array.
97
+
98
+ def method_missing( sym, *args, &blk )
99
+ @self.send(sym, *args, &blk ) rescue super
100
+ end
101
+
102
+ # Parses a string constraint returning the operation as a lambda.
103
+
104
+ def self.constraint_lambda( constraint )
105
+ op, val = *parse_constraint( constraint )
106
+ lambda { |t| t.send(op, val) }
107
+ end
108
+
109
+ def self.parse_constraint( constraint )
110
+ constraint = constraint.strip
111
+ re = %r{^(=~|~>|<=|>=|==|=|<|>)?\s*(\d+(:?[-.]\d+)*)$}
112
+ if md = re.match( constraint )
113
+ if op = md[1]
114
+ op = '=~' if op == '~>'
115
+ op = '==' if op == '='
116
+ val = new( *md[2].split(/\W+/) )
117
+ else
118
+ op = '=='
119
+ val = new( *constraint.split(/\W+/) )
120
+ end
121
+ else
122
+ raise ArgumentError, "invalid constraint"
123
+ end
124
+ return op, val
125
+ end
126
+
127
+ end