pluginfactory 1.0.4 → 1.0.5
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.
- data/ChangeLog +70 -319
- data/LICENSE +1 -1
- data/README +0 -4
- data/Rakefile +90 -68
- data/lib/pluginfactory.rb +7 -11
- data/rake/dependencies.rb +1 -1
- data/rake/helpers.rb +75 -48
- data/rake/hg.rb +261 -0
- data/rake/manual.rb +74 -76
- data/rake/packaging.rb +40 -8
- data/rake/publishing.rb +70 -69
- data/rake/rdoc.rb +11 -26
- data/rake/style.rb +1 -1
- data/rake/svn.rb +582 -516
- data/rake/testing.rb +6 -21
- data/rake/win32.rb +119 -23
- data/spec/pluginfactory_spec.rb +112 -124
- metadata +18 -129
data/lib/pluginfactory.rb
CHANGED
@@ -63,10 +63,6 @@ class FactoryError < RuntimeError; end
|
|
63
63
|
# driver.class #=> MysqlDriver
|
64
64
|
# pgdriver = Driver.create( "PostGresDriver" )
|
65
65
|
#
|
66
|
-
# == Subversion ID
|
67
|
-
#
|
68
|
-
# $Id: pluginfactory.rb 57 2009-02-25 17:50:55Z deveiant $
|
69
|
-
#
|
70
66
|
# == Authors
|
71
67
|
#
|
72
68
|
# * Martin Chase <stillflame@FaerieMUD.org>
|
@@ -80,8 +76,8 @@ class FactoryError < RuntimeError; end
|
|
80
76
|
#
|
81
77
|
module PluginFactory
|
82
78
|
|
83
|
-
VERSION = '1.0.
|
84
|
-
|
79
|
+
VERSION = '1.0.5'
|
80
|
+
|
85
81
|
|
86
82
|
### Logging
|
87
83
|
@default_logger = Logger.new( $stderr )
|
@@ -93,7 +89,7 @@ module PluginFactory
|
|
93
89
|
class << self
|
94
90
|
# The logger that will be used when the logging subsystem is reset
|
95
91
|
attr_accessor :default_logger
|
96
|
-
|
92
|
+
|
97
93
|
# The logger that's currently in effect
|
98
94
|
attr_accessor :logger
|
99
95
|
alias_method :log, :logger
|
@@ -113,14 +109,14 @@ module PluginFactory
|
|
113
109
|
}
|
114
110
|
end
|
115
111
|
end
|
116
|
-
|
112
|
+
|
117
113
|
|
118
114
|
### Reset the global logger object to the default
|
119
115
|
def self::reset_logger
|
120
116
|
self.logger = self.default_logger
|
121
117
|
self.logger.level = Logger::WARN
|
122
118
|
end
|
123
|
-
|
119
|
+
|
124
120
|
|
125
121
|
### Returns +true+ if the global logger has not been set to something other than
|
126
122
|
### the default one.
|
@@ -181,7 +177,7 @@ module PluginFactory
|
|
181
177
|
end
|
182
178
|
alias_method :factoryType, :factory_type
|
183
179
|
|
184
|
-
|
180
|
+
|
185
181
|
### Inheritance callback -- Register subclasses in the derivatives hash
|
186
182
|
### so that ::create knows about them.
|
187
183
|
def inherited( subclass )
|
@@ -273,7 +269,7 @@ module PluginFactory
|
|
273
269
|
return self.derivatives[ class_name.downcase ]
|
274
270
|
end
|
275
271
|
alias_method :getSubclass, :get_subclass
|
276
|
-
|
272
|
+
|
277
273
|
|
278
274
|
### Calculates an appropriate filename for the derived class using the
|
279
275
|
### name of the base class and tries to load it via <tt>require</tt>. If
|
data/rake/dependencies.rb
CHANGED
data/rake/helpers.rb
CHANGED
@@ -5,6 +5,8 @@
|
|
5
5
|
|
6
6
|
|
7
7
|
require 'pathname'
|
8
|
+
require 'uri'
|
9
|
+
require 'open3'
|
8
10
|
|
9
11
|
begin
|
10
12
|
require 'readline'
|
@@ -66,17 +68,23 @@ def trace( *msg )
|
|
66
68
|
end
|
67
69
|
|
68
70
|
|
71
|
+
### Return the specified args as a string, quoting any that have a space.
|
72
|
+
def quotelist( *args )
|
73
|
+
return args.flatten.collect {|part| part =~ /\s/ ? part.inspect : part}
|
74
|
+
end
|
75
|
+
|
76
|
+
|
69
77
|
### Run the specified command +cmd+ with system(), failing if the execution
|
70
78
|
### fails.
|
71
79
|
def run( *cmd )
|
72
80
|
cmd.flatten!
|
73
81
|
|
74
82
|
if cmd.length > 1
|
75
|
-
trace( cmd
|
83
|
+
trace( quotelist(*cmd) )
|
76
84
|
else
|
77
85
|
trace( cmd )
|
78
86
|
end
|
79
|
-
|
87
|
+
|
80
88
|
if $dryrun
|
81
89
|
$stderr.puts "(dry run mode)"
|
82
90
|
else
|
@@ -88,6 +96,15 @@ def run( *cmd )
|
|
88
96
|
end
|
89
97
|
|
90
98
|
|
99
|
+
### Run the given +cmd+ with the specified +args+ without interpolation by the shell and
|
100
|
+
### return anything written to its STDOUT.
|
101
|
+
def read_command_output( cmd, *args )
|
102
|
+
trace "Reading output from: %s" % [ cmd, quotelist(cmd, *args) ]
|
103
|
+
output = IO.read( '|-' ) or exec cmd, *args
|
104
|
+
return output
|
105
|
+
end
|
106
|
+
|
107
|
+
|
91
108
|
### Run a subordinate Rake process with the same options and the specified +targets+.
|
92
109
|
def rake( *targets )
|
93
110
|
opts = ARGV.select {|arg| arg[0,1] == '-' }
|
@@ -106,7 +123,7 @@ def pipeto( *cmd )
|
|
106
123
|
$stderr.puts "(dry run mode)"
|
107
124
|
else
|
108
125
|
open( '|-', 'w+' ) do |io|
|
109
|
-
|
126
|
+
|
110
127
|
# Parent
|
111
128
|
if io
|
112
129
|
yield( io )
|
@@ -123,52 +140,35 @@ end
|
|
123
140
|
|
124
141
|
### Download the file at +sourceuri+ via HTTP and write it to +targetfile+.
|
125
142
|
def download( sourceuri, targetfile=nil )
|
126
|
-
oldsync = $
|
127
|
-
$
|
128
|
-
require '
|
129
|
-
require 'uri'
|
143
|
+
oldsync = $stdout.sync
|
144
|
+
$stdout.sync = true
|
145
|
+
require 'open-uri'
|
130
146
|
|
131
147
|
targetpath = Pathname.new( targetfile )
|
132
148
|
|
133
149
|
log "Downloading %s to %s" % [sourceuri, targetfile]
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
if res.is_a?( Net::HTTPSuccess )
|
146
|
-
log "Downloading..."
|
147
|
-
res.read_body do |buf|
|
148
|
-
ofh.print( buf )
|
149
|
-
end
|
150
|
-
downloaded = true
|
151
|
-
puts "done."
|
152
|
-
|
153
|
-
elsif res.is_a?( Net::HTTPRedirection )
|
154
|
-
url = URI( res['location'] )
|
155
|
-
log "...following redirection to: %s" % [ url ]
|
156
|
-
limit -= 1
|
157
|
-
sleep 0.2
|
158
|
-
next
|
159
|
-
|
160
|
-
else
|
161
|
-
res.error!
|
162
|
-
end
|
150
|
+
trace " connecting..."
|
151
|
+
ifh = open( sourceuri ) do |ifh|
|
152
|
+
trace " connected..."
|
153
|
+
targetpath.open( File::WRONLY|File::TRUNC|File::CREAT, 0644 ) do |ofh|
|
154
|
+
log "Downloading..."
|
155
|
+
buf = ''
|
156
|
+
|
157
|
+
while ifh.read( 16384, buf )
|
158
|
+
until buf.empty?
|
159
|
+
bytes = ofh.write( buf )
|
160
|
+
buf.slice!( 0, bytes )
|
163
161
|
end
|
164
162
|
end
|
163
|
+
|
164
|
+
log "Done."
|
165
165
|
end
|
166
|
-
|
166
|
+
|
167
167
|
end
|
168
|
-
|
168
|
+
|
169
169
|
return targetpath
|
170
170
|
ensure
|
171
|
-
$
|
171
|
+
$stdout.sync = oldsync
|
172
172
|
end
|
173
173
|
|
174
174
|
|
@@ -202,13 +202,13 @@ end
|
|
202
202
|
### line-endings, color reset, etc.
|
203
203
|
def colorize( *args )
|
204
204
|
string = ''
|
205
|
-
|
205
|
+
|
206
206
|
if block_given?
|
207
207
|
string = yield
|
208
208
|
else
|
209
209
|
string = args.shift
|
210
210
|
end
|
211
|
-
|
211
|
+
|
212
212
|
ending = string[/(\s)$/] || ''
|
213
213
|
string = string.rstrip
|
214
214
|
|
@@ -290,7 +290,7 @@ def prompt_for_multiple_values( label, default=nil )
|
|
290
290
|
|
291
291
|
results = []
|
292
292
|
result = nil
|
293
|
-
|
293
|
+
|
294
294
|
begin
|
295
295
|
result = readline( make_prompt_string("> ") )
|
296
296
|
if result.nil? || result.empty?
|
@@ -299,7 +299,7 @@ def prompt_for_multiple_values( label, default=nil )
|
|
299
299
|
results << result
|
300
300
|
end
|
301
301
|
end until result.nil? || result.empty?
|
302
|
-
|
302
|
+
|
303
303
|
return results.flatten
|
304
304
|
end
|
305
305
|
|
@@ -322,7 +322,7 @@ def noecho( masked=false )
|
|
322
322
|
ensure
|
323
323
|
Termios.tcsetattr( $stdin, Termios::TCSANOW, term )
|
324
324
|
end
|
325
|
-
|
325
|
+
|
326
326
|
return rval
|
327
327
|
end
|
328
328
|
|
@@ -365,7 +365,7 @@ alias :prompt_for_confirmation :ask_for_confirmation
|
|
365
365
|
### those will be returned in an Array, else the whole matching line is returned.
|
366
366
|
def find_pattern_in_file( regexp, file )
|
367
367
|
rval = nil
|
368
|
-
|
368
|
+
|
369
369
|
File.open( file, 'r' ).each do |line|
|
370
370
|
if (( match = regexp.match(line) ))
|
371
371
|
rval = match.captures.empty? ? match[0] : match.captures
|
@@ -377,12 +377,32 @@ def find_pattern_in_file( regexp, file )
|
|
377
377
|
end
|
378
378
|
|
379
379
|
|
380
|
+
### Search line-by-line in the output of the specified +cmd+ for the given +regexp+,
|
381
|
+
### returning the first match, or nil if no match was found. If the +regexp+ has any
|
382
|
+
### capture groups, those will be returned in an Array, else the whole matching line
|
383
|
+
### is returned.
|
384
|
+
def find_pattern_in_pipe( regexp, *cmd )
|
385
|
+
output = []
|
386
|
+
|
387
|
+
log( cmd.collect {|part| part =~ /\s/ ? part.inspect : part} )
|
388
|
+
Open3.popen3( *cmd ) do |stdin, stdout, stderr|
|
389
|
+
stdin.close
|
390
|
+
|
391
|
+
output << stdout.gets until stdout.eof?
|
392
|
+
output << stderr.gets until stderr.eof?
|
393
|
+
end
|
394
|
+
|
395
|
+
result = output.find { |line| regexp.match(line) }
|
396
|
+
return $1 || result
|
397
|
+
end
|
398
|
+
|
399
|
+
|
380
400
|
### Invoke the user's editor on the given +filename+ and return the exit code
|
381
401
|
### from doing so.
|
382
402
|
def edit( filename )
|
383
403
|
editor = ENV['EDITOR'] || ENV['VISUAL'] || DEFAULT_EDITOR
|
384
404
|
system editor, filename
|
385
|
-
unless $?.success?
|
405
|
+
unless $?.success? || editor =~ /vim/i
|
386
406
|
fail "Editor exited uncleanly."
|
387
407
|
end
|
388
408
|
end
|
@@ -398,10 +418,17 @@ end
|
|
398
418
|
### Log a subdirectory change, execute a block, and exit the subdirectory
|
399
419
|
def in_subdirectory( subdir )
|
400
420
|
block = Proc.new
|
401
|
-
|
421
|
+
|
402
422
|
log "Entering #{subdir}"
|
403
423
|
Dir.chdir( subdir, &block )
|
404
424
|
log "Leaving #{subdir}"
|
405
425
|
end
|
406
|
-
|
426
|
+
|
427
|
+
|
428
|
+
### Make an easily-comparable version vector out of +ver+ and return it.
|
429
|
+
def vvec( ver )
|
430
|
+
return ver.split('.').collect {|char| char.to_i }.pack('N*')
|
431
|
+
end
|
432
|
+
|
433
|
+
|
407
434
|
|
data/rake/hg.rb
ADDED
@@ -0,0 +1,261 @@
|
|
1
|
+
#
|
2
|
+
# Mercurial Rake Tasks
|
3
|
+
|
4
|
+
require 'enumerator'
|
5
|
+
|
6
|
+
#
|
7
|
+
# Authors:
|
8
|
+
# * Michael Granger <ged@FaerieMUD.org>
|
9
|
+
#
|
10
|
+
|
11
|
+
unless defined?( HG_DOTDIR )
|
12
|
+
|
13
|
+
# Mercurial constants
|
14
|
+
HG_DOTDIR = BASEDIR + '.hg'
|
15
|
+
HG_STORE = HG_DOTDIR + 'store'
|
16
|
+
|
17
|
+
IGNORE_FILE = BASEDIR + '.hgignore'
|
18
|
+
|
19
|
+
|
20
|
+
###
|
21
|
+
### Helpers
|
22
|
+
###
|
23
|
+
|
24
|
+
module MercurialHelpers
|
25
|
+
|
26
|
+
###############
|
27
|
+
module_function
|
28
|
+
###############
|
29
|
+
|
30
|
+
### Generate a commit log from a diff and return it as a String.
|
31
|
+
def make_commit_log
|
32
|
+
diff = read_command_output( 'hg', 'diff' )
|
33
|
+
fail "No differences." if diff.empty?
|
34
|
+
|
35
|
+
return diff
|
36
|
+
end
|
37
|
+
|
38
|
+
### Generate a commit log and invoke the user's editor on it.
|
39
|
+
def edit_commit_log
|
40
|
+
diff = make_commit_log()
|
41
|
+
|
42
|
+
File.open( COMMIT_MSG_FILE, File::WRONLY|File::TRUNC|File::CREAT ) do |fh|
|
43
|
+
fh.print( diff )
|
44
|
+
end
|
45
|
+
|
46
|
+
edit( COMMIT_MSG_FILE )
|
47
|
+
end
|
48
|
+
|
49
|
+
### Generate a changelog.
|
50
|
+
def make_changelog
|
51
|
+
log = read_command_output( 'hg', 'log', '--style', 'compact' )
|
52
|
+
return log
|
53
|
+
end
|
54
|
+
|
55
|
+
### Get the 'tip' info and return it as a Hash
|
56
|
+
def get_tip_info
|
57
|
+
data = read_command_output( 'hg', 'tip' )
|
58
|
+
return YAML.load( data )
|
59
|
+
end
|
60
|
+
|
61
|
+
### Return the ID for the current rev
|
62
|
+
def get_current_rev
|
63
|
+
id = read_command_output( 'hg', '-q', 'identify' )
|
64
|
+
return id.chomp
|
65
|
+
end
|
66
|
+
|
67
|
+
### Read the list of existing tags and return them as an Array
|
68
|
+
def get_tags
|
69
|
+
taglist = read_command_output( 'hg', 'tags' )
|
70
|
+
return taglist.split( /\n/ )
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
### Read any remote repo paths known by the current repo and return them as a hash.
|
75
|
+
def get_repo_paths
|
76
|
+
paths = {}
|
77
|
+
pathspec = read_command_output( 'hg', 'paths' )
|
78
|
+
pathspec.split.each_slice( 3 ) do |name, _, url|
|
79
|
+
paths[ name ] = url
|
80
|
+
end
|
81
|
+
return paths
|
82
|
+
end
|
83
|
+
|
84
|
+
### Return the list of files which are of status 'unknown'
|
85
|
+
def get_unknown_files
|
86
|
+
list = read_command_output( 'hg', 'status', '-un', '--no-color' )
|
87
|
+
list = list.split( /\n/ )
|
88
|
+
|
89
|
+
trace "New files: %p" % [ list ]
|
90
|
+
return list
|
91
|
+
end
|
92
|
+
|
93
|
+
### Returns a human-scannable file list by joining and truncating the list if it's too long.
|
94
|
+
def humanize_file_list( list, indent=FILE_INDENT )
|
95
|
+
listtext = list[0..5].join( "\n#{indent}" )
|
96
|
+
if list.length > 5
|
97
|
+
listtext << " (and %d other/s)" % [ list.length - 5 ]
|
98
|
+
end
|
99
|
+
|
100
|
+
return listtext
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
### Add the list of +pathnames+ to the .hgignore list.
|
105
|
+
def hg_ignore_files( *pathnames )
|
106
|
+
patterns = pathnames.flatten.collect do |path|
|
107
|
+
'^' + Regexp.escape(path) + '$'
|
108
|
+
end
|
109
|
+
trace "Ignoring %d files." % [ pathnames.length ]
|
110
|
+
|
111
|
+
IGNORE_FILE.open( File::CREAT|File::WRONLY|File::APPEND, 0644 ) do |fh|
|
112
|
+
fh.puts( patterns )
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
### Delete the files in the given +filelist+ after confirming with the user.
|
118
|
+
def delete_extra_files( filelist )
|
119
|
+
description = humanize_file_list( filelist, ' ' )
|
120
|
+
log "Files to delete:\n ", description
|
121
|
+
ask_for_confirmation( "Really delete them?", false ) do
|
122
|
+
filelist.each do |f|
|
123
|
+
rm_rf( f, :verbose => true )
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
end # module MercurialHelpers
|
129
|
+
|
130
|
+
|
131
|
+
### Rakefile support
|
132
|
+
def get_vcs_rev( dir='.' )
|
133
|
+
return MercurialHelpers.get_current_rev
|
134
|
+
end
|
135
|
+
def make_changelog
|
136
|
+
return MercurialHelpers.make_changelog
|
137
|
+
end
|
138
|
+
|
139
|
+
|
140
|
+
###
|
141
|
+
### Tasks
|
142
|
+
###
|
143
|
+
|
144
|
+
desc "Mercurial tasks"
|
145
|
+
namespace :hg do
|
146
|
+
include MercurialHelpers
|
147
|
+
|
148
|
+
desc "Prepare for a new release"
|
149
|
+
task :prep_release do
|
150
|
+
tags = get_tags()
|
151
|
+
rev = get_current_rev()
|
152
|
+
|
153
|
+
# Look for a tag for the current release version, and if it exists abort
|
154
|
+
if tags.include?( PKG_VERSION )
|
155
|
+
error "Version #{PKG_VERSION} already has a tag. Did you mean " +
|
156
|
+
"to increment the version in #{VERSION_FILE}?"
|
157
|
+
fail
|
158
|
+
end
|
159
|
+
|
160
|
+
# Sign the current rev
|
161
|
+
log "Signing rev #{rev}"
|
162
|
+
run 'hg', 'sign'
|
163
|
+
|
164
|
+
# Tag the current rev
|
165
|
+
log "Tagging rev #{rev} as #{PKG_VERSION}"
|
166
|
+
run 'hg', 'tag', PKG_VERSION
|
167
|
+
|
168
|
+
# Offer to push
|
169
|
+
Rake::Task['hg:push'].invoke
|
170
|
+
end
|
171
|
+
|
172
|
+
desc "Check for new files and offer to add/ignore/delete them."
|
173
|
+
task :newfiles do
|
174
|
+
log "Checking for new files..."
|
175
|
+
|
176
|
+
entries = get_unknown_files()
|
177
|
+
|
178
|
+
unless entries.empty?
|
179
|
+
files_to_add = []
|
180
|
+
files_to_ignore = []
|
181
|
+
files_to_delete = []
|
182
|
+
|
183
|
+
entries.each do |entry|
|
184
|
+
action = prompt_with_default( " #{entry}: (a)dd, (i)gnore, (s)kip (d)elete", 's' )
|
185
|
+
case action
|
186
|
+
when 'a'
|
187
|
+
files_to_add << entry
|
188
|
+
when 'i'
|
189
|
+
files_to_ignore << entry
|
190
|
+
when 'd'
|
191
|
+
files_to_delete << entry
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
unless files_to_add.empty?
|
196
|
+
run 'hg', 'add', *files_to_add
|
197
|
+
end
|
198
|
+
|
199
|
+
unless files_to_ignore.empty?
|
200
|
+
hg_ignore_files( *files_to_ignore )
|
201
|
+
end
|
202
|
+
|
203
|
+
unless files_to_delete.empty?
|
204
|
+
delete_extra_files( files_to_delete )
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
task :add => :newfiles
|
209
|
+
|
210
|
+
|
211
|
+
desc "Check the current code in if tests pass"
|
212
|
+
task :checkin => ['hg:newfiles', 'test', COMMIT_MSG_FILE] do
|
213
|
+
targets = get_target_args()
|
214
|
+
$stderr.puts '---', File.read( COMMIT_MSG_FILE ), '---'
|
215
|
+
ask_for_confirmation( "Continue with checkin?" ) do
|
216
|
+
run 'hg', 'ci', '-l', COMMIT_MSG_FILE, targets
|
217
|
+
rm_f COMMIT_MSG_FILE
|
218
|
+
end
|
219
|
+
Rake::Task['hg:push'].invoke
|
220
|
+
end
|
221
|
+
task :commit => :checkin
|
222
|
+
task :ci => :checkin
|
223
|
+
|
224
|
+
CLEAN.include( COMMIT_MSG_FILE )
|
225
|
+
|
226
|
+
desc "Push to the default origin repo (if there is one)"
|
227
|
+
task :push do
|
228
|
+
paths = get_repo_paths()
|
229
|
+
if origin_url = paths['default']
|
230
|
+
ask_for_confirmation( "Push to '#{origin_url}'?", false ) do
|
231
|
+
run 'hg', 'push'
|
232
|
+
end
|
233
|
+
else
|
234
|
+
trace "Skipping push: No 'default' path."
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
end
|
239
|
+
|
240
|
+
if HG_DOTDIR.exist?
|
241
|
+
trace "Defining mercurial VCS tasks"
|
242
|
+
|
243
|
+
desc "Check in all the changes in your current working copy"
|
244
|
+
task :ci => 'hg:ci'
|
245
|
+
desc "Check in all the changes in your current working copy"
|
246
|
+
task :checkin => 'hg:ci'
|
247
|
+
|
248
|
+
desc "Tag and sign revision before a release"
|
249
|
+
task :prep_release => 'hg:prep_release'
|
250
|
+
|
251
|
+
file COMMIT_MSG_FILE do
|
252
|
+
edit_commit_log()
|
253
|
+
end
|
254
|
+
|
255
|
+
else
|
256
|
+
trace "Not defining mercurial tasks: no #{HG_DOTDIR}"
|
257
|
+
end
|
258
|
+
|
259
|
+
end
|
260
|
+
|
261
|
+
|