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/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.4'
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
@@ -1,6 +1,6 @@
1
1
  #
2
2
  # Dependency-checking and Installation Rake Tasks
3
- # $Id: dependencies.rb 43 2008-09-05 18:19:16Z deveiant $
3
+
4
4
  #
5
5
 
6
6
  require 'rubygems/dependency_installer'
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.collect {|part| part =~ /\s/ ? part.inspect : part} )
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 = $defout.sync
127
- $defout.sync = true
128
- require 'net/http'
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
- targetpath.open( File::WRONLY|File::TRUNC|File::CREAT, 0644 ) do |ofh|
135
-
136
- url = sourceuri.is_a?( URI ) ? sourceuri : URI( sourceuri )
137
- downloaded = false
138
- limit = 5
139
-
140
- until downloaded or limit.zero?
141
- Net::HTTP.start( url.host, url.port ) do |http|
142
- req = Net::HTTP::Get.new( url.path )
143
-
144
- http.request( req ) do |res|
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
- $defout.sync = oldsync
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
+