pluginfactory 1.0.4 → 1.0.5

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