1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
|
#!/usr/bin/env ruby
# The tasks associated with building Reductive Labs projects
require 'rbconfig'
require 'rake'
require 'rake/tasklib'
require 'rake/clean'
require 'rake/testtask'
$features = {}
begin
require 'rubygems'
require 'rake/gempackagetask'
$features[:gem] = true
rescue Exception
$features[:gem] = false
$stderr.puts "No Gems; skipping"
nil
end
begin
require 'rdoc/rdoc'
$features[:rdoc] = true
rescue => detail
$features[:rdoc] = false
puts "No rdoc: %s" % detail
end
if $features[:rdoc]
require 'rake/rdoctask'
end
# Create all of the standard targets for a Reductive Labs project.
# NOTE: The reason so many of the rake tasks are generated, rather than being
# declared directly, is that they need information from the project instance.
# Any rake task with an instance variable (e.g., @name or @version) needs
# to have that variable assigned *before* the task is defined. Suckage.
class Rake::RedLabProject < Rake::TaskLib
# The project name.
attr_accessor :name
# The project version.
attr_accessor :version
# The directory to which to publish packages and html and such.
attr_accessor :publishdir
# The package-specific publishing directory
attr_accessor :pkgpublishdir
# Create a Gem file.
attr_accessor :mkgem
# The hosts to run all of our tests on.
attr_accessor :testhosts
# The summary of this project.
attr_accessor :summary
# The description of this project.
attr_accessor :description
# The author of this project.
attr_accessor :author
# A Contact email address.
attr_accessor :email
# The URL for the project.
attr_accessor :url
# Where to get the source code.
attr_accessor :source
# Who the vendor is.
attr_accessor :vendor
# The copyright for this project
attr_accessor :copyright
# The RubyForge project.
attr_accessor :rfproject
# The list of files. Only used for gem tasks.
attr_writer :filelist
# The directory in which to store packages. Defaults to "pkg".
attr_accessor :package_dir
# The default task. Defaults to the 'alltests' task.
attr_accessor :defaulttask
# The defined requirements
attr_reader :requires
# The file containing the version string.
attr_accessor :versionfile
# Print messages on stdout
def announce(msg = nil)
puts msg
end
# Print messages on stderr
def warn(msg = nil)
$stderr.puts msg
end
def add_dependency(name, version)
@requires[name] = version
end
# Where we'll be putting the code.
def codedir
unless defined? @codedir
@codedir = File.join(self.package_dir, "#{@name}-#{@version}")
end
return @codedir
end
# Retrieve the current version from the code.
def currentversion
unless defined? @currentversion
ver = %x{ruby -Ilib ./bin/#{@name} --version}.chomp
if $? == 0 and ver != ""
@currentversion = ver
else
warn "Could not retrieve current version; using 0.0.0"
@currentversion = "0.0.0"
end
end
return @currentversion
end
# Define all of our package tasks. We just search through all of our
# defined methods and call anything that's listed as making tasks.
def define
self.methods.find_all { |method| method.to_s =~ /^mktask/ }.each { |method|
self.send(method)
}
end
def egrep(pattern)
Dir['**/*.rb'].each do |fn|
count = 0
open(fn) do |f|
while line = f.gets
count += 1
if line =~ pattern
puts "#{fn}:#{count}:#{line}"
end
end
end
end
end
# List all of the files.
def filelist
unless defined? @createdfilelist
# If they passed in a file list as an array, then create a FileList
# object out of it.
if defined? @filelist
unless @filelist.is_a? FileList
@filelist = FileList[@filelist]
end
else
# Use a default file list.
@filelist = FileList[
'install.rb',
'[A-Z]*',
'lib/**/*.rb',
'test/**/*.rb',
'bin/**/*',
'ext/**/*',
'examples/**/*',
'conf/**/*'
]
end
@filelist.delete_if {|item| item.include?(".git")}
@createdfilelist = true
end
@filelist
end
def has?(feature)
feature = feature.intern if feature.is_a? String
if $features.include?(feature)
return $features[feature]
else
return true
end
end
def initialize(name, version = nil)
@name = name
if ENV['REL']
@version = ENV['REL']
else
@version = version || self.currentversion
end
@defaulttask = :alltests
@publishdir = ENV['DOWNLOAD_DIR'] || "/opt/rl/docroots/reductivelabs.com/htdocs/downloads"
@pkgpublishdir = "#{@publishdir}/#{@name}"
@email = "dev@reductivelabs.com"
@url = "http://reductivelabs.com/projects/#{@name}"
@source = "http://reductivelabs.com/downloads/#{@name}/#{@name}-#{@version}.tgz"
@vendor = "Reductive Labs, LLC"
@copyright = "Copyright 2003-2008, Reductive Labs, LLC. Some Rights Reserved."
@rfproject = @name
@defaulttask = :package
@package_dir = "pkg"
@requires = {}
@versionfile = "lib/#{@name}.rb"
CLOBBER.include('doc/*')
yield self if block_given?
define if block_given?
end
def mktaskhtml
if $features[:rdoc]
Rake::RDocTask.new(:html) { |rdoc|
rdoc.rdoc_dir = 'html'
rdoc.template = 'html'
rdoc.title = @name.capitalize
rdoc.options << '--line-numbers' << '--inline-source' <<
'--main' << 'README'
rdoc.rdoc_files.include('README', 'COPYING', 'CHANGELOG')
rdoc.rdoc_files.include('lib/**/*.rb')
CLEAN.include("html")
}
# Publish the html.
task :publish => [:package, :html] do
puts Dir.getwd
apidocsdir = "#{@pkgpublishdir}/apidocs"
File.makedirs(apidocsdir)
sh %{cp -r html #{apidocsdir}}
end
else
warn "No rdoc; skipping html"
end
end
# Create a release task.
def mktaskrelease
desc "Make a new release"
task :release => [
:prerelease,
:clobber,
:update_version,
:commit_newversion,
:trac_version,
:tag, # tag everything before we make a bunch of extra dirs
:html,
:package,
:publish
] do
announce
announce "**************************************************************"
announce "* Release #{@version} Complete."
announce "* Packages ready to upload."
announce "**************************************************************"
announce
end
end
# Do any prerelease work.
def mktaskprerelease
# Validate that everything is ready to go for a release.
task :prerelease do
announce
announce "**************************************************************"
announce "* Making Release #{@version}"
announce "* (current version #{self.currentversion})"
announce "**************************************************************"
announce
# Is a release number supplied?
unless ENV['REL']
warn "You must provide a release number when releasing"
fail "Usage: rake release REL=x.y.z [REUSE=tag_suffix]"
end
# Is the release different than the current release.
# (or is REUSE set?)
if @version == self.currentversion && ! ENV['REUSE']
fail "Current version is #{@version}, must specify REUSE=tag_suffix to reuse version"
end
# Are all source files checked in?
if ENV['RELTEST']
announce "Release Task Testing, skipping checked-in file test"
else
announce "Checking for unchecked-in files..."
data = %x{git status}
unless data.include?("nothing to commit")
fail "git status is not clean ... do you have unchecked-in files?"
end
announce "No outstanding checkins found ... OK"
end
end
end
# Create the task to update versions.
def mktaskupdateversion
task :update_version => [:prerelease] do
if @version == self.currentversion
announce "No version change ... skipping version update"
else
announce "Updating #{@versionfile} version to #{@version}"
open(@versionfile) do |rakein|
open("#{@versionfile}.new", "w") do |rakeout|
rakein.each do |line|
if line =~ /^(\s*)#{@name.upcase}VERSION\s*=\s*/
rakeout.puts "#{$1}#{@name.upcase}VERSION = '#{@version}'"
else
rakeout.puts line
end
end
end
end
mv "#{@versionfile}.new", @versionfile
end
end
desc "Commit the new versions to SVN."
task :commit_newversion => [:update_version] do
if ENV['RELTEST']
announce "Release Task Testing, skipping commiting of new version"
else
sh %{git commit -m "Updated to version #{@version}" #{@versionfile}}
end
end
end
def mktasktrac_version
task :trac_version => [:update_version] do
tracpath = "/opt/rl/trac/#{@name}"
unless FileTest.exists?(tracpath)
announce "No Trac instance at %s" % tracpath
else
output = %x{sudo trac-admin #{tracpath} version list}.chomp.split("\n")
versions = {}
output[3..-1].each do |line|
name, time = line.chomp.split(/\s+/)
versions[name] = time
end
if versions.include?(@version)
announce "Version #{@version} already in Trac"
else
announce "Adding #{@name} version #{@version} to Trac"
date = [Time.now.year.to_s,
Time.now.month.to_s,
Time.now.day.to_s].join("-")
system("sudo trac-admin #{tracpath} version add #{@version} #{date}")
end
end
end
end
# Create the tag task.
def mktasktag
desc "Tag all the files with the latest release number (REL=x.y.z)"
task :tag => [:prerelease] do
reltag = @version
announce "Tagging with [#{reltag}]"
if ENV['RELTEST']
announce "Release Task Testing, skipping tagging"
else
sh %{git tag #{reltag}}
end
end
end
# Create the task for testing across all hosts.
def mktaskhosttest
desc "Test Puppet on each test host"
task :hosttest do
out = ""
TESTHOSTS.each { |host|
puts "testing %s" % host
cwd = Dir.getwd
file = "/tmp/#{@name}-#{host}test.out"
system("ssh #{host} 'cd git/#{@name}/test; sudo rake' 2>&1 >#{file}")
if $? != 0
puts "%s failed; output is in %s" % [host, file]
end
}
end
end
def mktaskri
# Create a task to build the RDOC documentation tree.
#Rake::RDocTask.new("ri") { |rdoc|
# #rdoc.rdoc_dir = 'html'
# #rdoc.template = 'html'
# rdoc.title = "Puppet"
# rdoc.options << '--ri' << '--line-numbers' << '--inline-source' << '--main' << 'README'
# rdoc.rdoc_files.include('README', 'COPYING', 'CHANGELOG')
# rdoc.rdoc_files.include('lib/**/*.rb', 'doc/**/*.rdoc')
#}
if $features[:rdoc]
task :ri do |ri|
files = ['README', 'COPYING', 'CHANGELOG'] + Dir.glob('lib/**/*.rb')
puts "files are \n%s" % files.join("\n")
begin
ri = RDoc::RDoc.new
ri.document(["--ri-site"] + files)
rescue RDoc::RDocError => detail
puts "Failed to build docs: %s" % detail
return nil
rescue LoadError
puts "Missing rdoc; cannot build documentation"
return nil
end
end
else
warn "No rdoc; skipping ri."
end
end
desc "Install the application using the standard install.rb script"
task :install do
ruby "install.rb"
end
def mktaskdefault
if dtask = self.defaulttask
desc "Default task"
task :default => dtask
end
end
desc "Run all unit tests."
task :alltests do
if FileTest.exists?("spec/Rakefile")
sh %{cd spec; rake}
else
Dir.chdir("spec") do
Dir.entries(".").find_all { |f| f =~ /\.rb/ }.each do |f|
sh %{ruby #{f}}
end
end
end
end
desc "List all ruby files"
task :rubyfiles do
puts Dir['**/*.rb'].reject { |fn| fn =~ /^pkg/ }
puts Dir['**/bin/*'].reject { |fn| fn =~ /svn|(~$)|(\.rb$)/ }
end
desc "Look for TODO and FIXME tags in the code"
task :todo do
egrep "/#.*(FIXME|TODO|TBD)/"
end
# This task requires extra information from the Rake file.
def mkgemtask
# ====================================================================
# Create a task that will package the Rake software into distributable
# tar, zip and gem files.
if ! defined?(Gem)
puts "Package Target requires RubyGEMs"
else
spec = Gem::Specification.new { |s|
#### Basic information.
s.name = self.name
s.version = self.version
s.summary = self.summary
s.description = self.description
s.platform = Gem::Platform::RUBY
#### Dependencies and requirements.
# I'd love to explicitly list all of the libraries that I need,
# but gems seem to only be able to handle dependencies on other
# gems, which is, um, stupid.
self.requires.each do |name, version|
s.add_dependency(name, ">= #{version}")
end
s.files = filelist.to_a
#### Signing key and cert chain
#s.signing_key = '/..../gem-private_key.pem'
#s.cert_chain = ['gem-public_cert.pem']
#### Author and project details.
s.author = [self.author]
s.email = self.email
s.homepage = self.url
s.rubyforge_project = self.rfproject
yield s
}
Rake::GemPackageTask.new(spec) { |pkg|
pkg.need_tar = true
}
desc "Copy the newly created package into the downloads directory"
task :publish => [:package] do
puts Dir.getwd
sh %{cp pkg/#{@name}-#{@version}.gem #{self.publishdir}/gems}
sh %{gem generate_index -d #{self.publishdir}}
sh %{cp pkg/#{@name}-#{@version}.tgz #{self.pkgpublishdir}}
sh %{ln -sf #{@name}-#{@version}.tgz #{self.pkgpublishdir}/#{@name}-latest.tgz}
end
CLEAN.include("pkg")
end
end
end
|