roll 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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