ratch 0.1

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.
Files changed (47) hide show
  1. data/LICENSE.txt +344 -0
  2. data/README.txt +10 -0
  3. data/bin/lt +4 -0
  4. data/bin/ludo +4 -0
  5. data/bin/ratch +8 -0
  6. data/data/mint/ratch/announce +224 -0
  7. data/data/mint/ratch/install +49 -0
  8. data/data/mint/ratch/notes +183 -0
  9. data/data/mint/ratch/publish +44 -0
  10. data/data/mint/ratch/rdoc +40 -0
  11. data/data/mint/ratch/setup +1616 -0
  12. data/data/mint/ratch/stats +138 -0
  13. data/demo/README +8 -0
  14. data/demo/doc/rdoc/created.rid +1 -0
  15. data/demo/doc/rdoc/files/README.html +112 -0
  16. data/demo/doc/rdoc/files/lib/foo/foo_rb.html +145 -0
  17. data/demo/doc/rdoc/fr_class_index.html +26 -0
  18. data/demo/doc/rdoc/fr_file_index.html +28 -0
  19. data/demo/doc/rdoc/fr_method_index.html +27 -0
  20. data/demo/doc/rdoc/index.html +24 -0
  21. data/demo/doc/rdoc/rdoc-style.css +208 -0
  22. data/demo/lib/foo/foo.rb +7 -0
  23. data/demo/util/conf/rdoc +4 -0
  24. data/demo/util/one +6 -0
  25. data/demo/util/rdoc +39 -0
  26. data/demo/util/tryme +10 -0
  27. data/dev/taskable-simple.rb +42 -0
  28. data/dev/taskable.rb +573 -0
  29. data/lib/ratch/batch.rb +43 -0
  30. data/lib/ratch/cli/lt.rb +56 -0
  31. data/lib/ratch/cli/ludo.rb +14 -0
  32. data/lib/ratch/cli/ratch.rb +47 -0
  33. data/lib/ratch/configutils.rb +100 -0
  34. data/lib/ratch/consoleutils.rb +88 -0
  35. data/lib/ratch/emailutils.rb +88 -0
  36. data/lib/ratch/fileutils.rb +173 -0
  37. data/lib/ratch/options.rb +57 -0
  38. data/lib/ratch/runnable.rb +117 -0
  39. data/lib/ratch/taskable.rb +105 -0
  40. data/lib/ratch/taskutils.rb +44 -0
  41. data/lib/ratch/uploadutils.rb +413 -0
  42. data/meta/manifest.txt +70 -0
  43. data/meta/project.yaml +24 -0
  44. data/misc/original.rb +308 -0
  45. data/task/setup +1616 -0
  46. data/task/stats +138 -0
  47. metadata +114 -0
@@ -0,0 +1,43 @@
1
+ #require 'shellwords'
2
+ require 'rbconfig' # replace with facets/rbsystem in future ?
3
+ require 'ratch/taskutils'
4
+
5
+ module Ratch
6
+
7
+ # Batch File class, is used as an executionm context for a
8
+ # ratch script.
9
+
10
+ class BatchFile < Module
11
+
12
+ include TaskUtils
13
+
14
+ # Quick start, equivalent to calling new.run(file).
15
+
16
+ #def self.start(file)
17
+ # new(file).call
18
+ #end
19
+
20
+ # New Batch File
21
+
22
+ def initialize(file)
23
+ abort "missing batch file -- #{file}" unless File.file?(file)
24
+ @file = file
25
+ end
26
+
27
+ # TODO What todo about arguments?
28
+
29
+ def call(arguments=nil)
30
+ script = File.read($0 = @file)
31
+ eval(script, binding, $0) #instance_eval(script)
32
+ @main.call if @main
33
+ end
34
+
35
+ end
36
+
37
+ end
38
+
39
+ # Load TaskUtils directly into to main runspace.
40
+
41
+ #class << self
42
+ # include TaskUtils
43
+ #end
@@ -0,0 +1,56 @@
1
+ #! /usr/bin/ruby1.8
2
+
3
+ # scan task scripts for descriptions
4
+
5
+ def script_desc( dir )
6
+ help = {}
7
+ files = Dir.glob( File.join( dir, '*' ) )
8
+ files.each do |fname|
9
+ next if FileTest.directory?( fname )
10
+ next unless FileTest.executable?( fname )
11
+ desc = ''
12
+ File.open(fname) do |f|
13
+ line = ''
14
+ until f.eof?
15
+ line = f.gets
16
+ case line
17
+ when /^(#!|\s*$)/
18
+ next
19
+ when /^\s*#(.*)/
20
+ desc = $1.strip; break
21
+ else
22
+ desc = nil; break
23
+ end
24
+ end
25
+ end
26
+ help[File.basename(fname)] = desc
27
+ end
28
+ help
29
+ end
30
+
31
+ def show( dir )
32
+ tasks = script_desc( dir )
33
+ max = tasks.keys.max{ |a,b| a.size <=> b.size }.size
34
+ if dir == ''
35
+ max += 4 + 2
36
+ else
37
+ max += dir.size + 2
38
+ end
39
+ tasks.each do |name, sum|
40
+ #sum = Sake.help_summary( type )
41
+ if dir == ''
42
+ cmd = "sake #{name}"
43
+ else
44
+ cmd = File.join( dir.chomp('/'), name )
45
+ end
46
+ puts "%-#{max}s # %s" % [cmd, sum]
47
+ end
48
+ end
49
+
50
+ dir = ARGV[0] || '.'
51
+
52
+ if File.directory?( dir )
53
+ show( dir )
54
+ else
55
+ puts "#{dir} is not a directory"
56
+ end
@@ -0,0 +1,14 @@
1
+ #! /usr/bin/ruby1.8
2
+
3
+ require 'facets/filetest'
4
+
5
+ name = ARGV[0]
6
+
7
+ if name
8
+ Dir.chdir '..' until FileTest.executable?(name) or FileTest.root?(Dir.pwd)
9
+ if FileTest.executable?( name )
10
+ system name
11
+ end
12
+ else
13
+ puts "Script #{name} not found."
14
+ end
@@ -0,0 +1,47 @@
1
+ #require 'shellwords'
2
+ require 'rbconfig' # replace with facets/rbsystem in future ?
3
+ require 'ratch/batch'
4
+
5
+ module Ratch
6
+
7
+ class RatchCommand
8
+
9
+ # Quick start.
10
+
11
+ def self.start(file)
12
+ new.run(file)
13
+ end
14
+
15
+ # Run task.
16
+
17
+ def run(file)
18
+ if file
19
+ BatchFile.new(file).call
20
+ else
21
+ help
22
+ end
23
+ end
24
+
25
+ # Dispaly help.
26
+
27
+ def help
28
+ help = <<-END
29
+ USAGE:
30
+
31
+ ratch [options] <taskfile>
32
+
33
+ OPTIONS:
34
+
35
+ --dryrun --nohram
36
+
37
+ --trace
38
+
39
+ --debug
40
+ END
41
+ puts help.gsub(/^\s+/, '')
42
+ end
43
+
44
+ end
45
+
46
+
47
+ end
@@ -0,0 +1,100 @@
1
+
2
+ module Ratch
3
+
4
+ module ConfigUtils
5
+
6
+ DEFAULT_CONFIG_FILE = 'config'
7
+
8
+ #
9
+
10
+ def configuration(file=nil)
11
+ @configuration ||= {}
12
+ if file = config_file(file)
13
+ @configuration[file] ||= config_read(file)
14
+ else
15
+ @configuration[file] ||= Hash.new{ |h,k| h[k] = {} }
16
+ end
17
+ end
18
+
19
+ #
20
+
21
+ def config_file(path=nil)
22
+ path ||= DEFAULT_CONFIG_FILE
23
+ find = "{#{utility_directory}/,}#{path}{.yaml,.yml,}"
24
+ file = Dir.glob(find)[0]
25
+ return file
26
+ end
27
+
28
+ # Load configuration data from a file. THe file will
29
+ # be looked for in the current script directory then
30
+ # from the project root.
31
+ #
32
+ # Since they are YAML files, they can optionally
33
+ # end with '.yaml' or '.yml'.
34
+
35
+ def config_read(path)
36
+ find = "{#{utility_directory}/,}#{path}{.yaml,.yml,}"
37
+ if file = Dir.glob(find)[0]
38
+ YAML::load(File.open(file))
39
+ else
40
+ raise LoadError, "Missing file -- #{path}"
41
+ end
42
+ end
43
+
44
+ # TODO Better name? Better definition? (Won't handle task subdirs well).
45
+
46
+ def utility_directory
47
+ File.dirname($0)
48
+ end
49
+
50
+ # Create an argument vector from a set of config options.
51
+ # TODO Deprecate in favor of Hash extension.
52
+
53
+ def config_vector(config, args_field=nil)
54
+ config.command_vector(args_field)
55
+ end
56
+
57
+ # # FIXME ProjectInfo, if available.
58
+ #
59
+ # def projectinfo
60
+ # require 'box/project'
61
+ # @projectinfo
62
+ #
63
+ # #begin
64
+ # # @projectinfo = ProjectInfo.open
65
+ # #rescue LoadError
66
+ # # @projectinfo = nil
67
+ # #end
68
+ # end
69
+
70
+ # def config_file
71
+ # @config_file ||= (
72
+ # dir = utility_directory
73
+ # name = Dir.basename(dir)
74
+ # Dir.glob("{#{dir},meta,info,}/{#{name},config}{.yaml,.yml}")
75
+ # )
76
+ # end
77
+
78
+ # # Load task configuration if any.
79
+ #
80
+ # def config_load(*names) #, defaults=nil)
81
+ #
82
+ # names.inject({}) do |memo, name|
83
+ # name = name.to_s
84
+ # #defaults = defaults || {}
85
+ #
86
+ # if file = config_file(name)
87
+ # config = YAML.load(File.open(file))
88
+ # elsif file = Dir.glob("#{utility_directory}/config{,.yaml,.yml}")[0]
89
+ # config = YAML.load(File.open(file))[name.to_s]
90
+ # else
91
+ # config = {}
92
+ # end
93
+ #
94
+ # config.update(memo)
95
+ # end
96
+ # #return defaults.update(config || {})
97
+ # end
98
+
99
+ end
100
+ end
@@ -0,0 +1,88 @@
1
+ module Ratch
2
+
3
+ module ConsoleUtils
4
+
5
+ # Convenient method to get simple console reply.
6
+
7
+ def ask(question, answers=nil)
8
+ print "#{question}"
9
+ print " [#{answers}] " if answers
10
+ until inp = $stdin.gets ; sleep 1 ; end
11
+ inp
12
+ end
13
+
14
+ # Ask for a password. (FIXME: only for unix so far)
15
+
16
+ def password(prompt=nil)
17
+ msg ||= "Enter Password: "
18
+ inp = ''
19
+
20
+ print "#{prompt} "
21
+
22
+ begin
23
+ system "stty -echo"
24
+ #inp = gets.chomp
25
+ until inp = $stdin.gets
26
+ sleep 1
27
+ end
28
+ ensure
29
+ system "stty echo"
30
+ end
31
+
32
+ return inp.chomp
33
+ end
34
+
35
+ end
36
+
37
+ end
38
+
39
+
40
+ class Array
41
+
42
+ # Convert an array into command line parameters.
43
+ # The array is accepted in the format of Ruby
44
+ # method arguments --ie. [arg1, arg2, ..., hash]
45
+
46
+ def to_params
47
+ flags = (Hash===last ? pop : {})
48
+ flags = flags.collect do |f,v|
49
+ m = f.to_s.size == 1 ? '-' : '--'
50
+ case v
51
+ when Array
52
+ v.collect{ |e| "#{m}#{f} '#{e}'" }.join(' ')
53
+ when true
54
+ "#{m}#{f}"
55
+ when false, nil
56
+ ''
57
+ else
58
+ "#{m}#{f} '#{v}'"
59
+ end
60
+ end
61
+ return (flags + self).join(" ")
62
+ end
63
+
64
+ # Not empty?
65
+
66
+ def not_empty?
67
+ !empty?
68
+ end
69
+
70
+ end
71
+
72
+
73
+ class Hash
74
+
75
+ # Setup a console arguments vector from a set of config options.
76
+
77
+ def command_vector(args_field=nil)
78
+ config = dup
79
+ if args_field
80
+ args = [config.delete(args_field)].flatten.compact
81
+ else
82
+ args = []
83
+ end
84
+ args << config
85
+ return args
86
+ end
87
+
88
+ end
@@ -0,0 +1,88 @@
1
+ begin
2
+ require 'facets/net/smtp_tls'
3
+ rescue LoadError
4
+ require 'net/smtp'
5
+ end
6
+
7
+
8
+ module Ratch
9
+
10
+ module EmailUtils
11
+
12
+ module_function
13
+
14
+ # Email function to easily send out an email.
15
+ #
16
+ # Settings:
17
+ #
18
+ # subject Subject of email message.
19
+ # from Message FROM address [email].
20
+ # to Email address to send announcemnt.
21
+ # server Email server to route message.
22
+ # port Email server's port.
23
+ # domain Email server's domain name.
24
+ # account Email account name.
25
+ # login Login type: plain, cram_md5 or login [plain].
26
+ # secure Uses TLS security, true or false? [false]
27
+ # message Mesage to send -or-
28
+ # file File that contains message.
29
+ #
30
+ # (Square brackets indicate defaults taken from Project information.
31
+ # if used via Project class.)
32
+
33
+ def email(message, settings)
34
+ server = settings['server']
35
+ account = settings['account']
36
+ login = settings['login'].to_sym
37
+ subject = settings['subject']
38
+ mail_to = settings['to'] || settings['mail_to']
39
+ mail_from = settings['from'] || settings['mail_from']
40
+ secure = settings['secure']
41
+ domain = settings['domain'] || server
42
+
43
+ port ||= (secure ? 465 : 25)
44
+ account ||= mail_from
45
+ login ||= :plain
46
+
47
+ #mail_to = nil if mail_to.empty?
48
+
49
+ raise ArgumentError, "missing email field -- server" unless server
50
+ raise ArgumentError, "missing email field -- account" unless account
51
+ raise ArgumentError, "missing email field -- subject" unless subject
52
+ raise ArgumentError, "missing email field -- to" unless mail_to
53
+ raise ArgumentError, "missing email field -- from" unless mail_from
54
+
55
+ passwd = password(account)
56
+
57
+ mail_to = [mail_to].flatten.compact
58
+
59
+ msg = ""
60
+ msg << "From: #{mail_from}\n"
61
+ msg << "To: #{mail_to.join(';')}\n"
62
+ msg << "Subject: #{subject}\n"
63
+ msg << ""
64
+ msg << message
65
+
66
+ begin
67
+ Net::SMTP.enable_tls if Net::SMTP.respond_to?(:enable_tls) and secure
68
+ Net::SMTP.start(server, port, domain, account, passwd, login) do |s|
69
+ s.send_message( msg, mail_from, mail_to )
70
+ end
71
+ puts "Email sent successfully to #{mail_to.join(';')}."
72
+ return true
73
+ rescue => e
74
+ if trace?
75
+ raise e
76
+ else
77
+ abort "Email delivery failed."
78
+ end
79
+ end
80
+ end
81
+
82
+ #def password( account )
83
+ # @password || ENV['PASSWORD'] || ask("Password for #{account}: ")
84
+ #end
85
+
86
+ end
87
+
88
+ end
@@ -0,0 +1,173 @@
1
+ require 'fileutils'
2
+
3
+
4
+ module Ratch
5
+
6
+ module FileUtils
7
+
8
+ # Glob files.
9
+
10
+ def glob(*args, &blk)
11
+ Dir.glob(*args, &blk)
12
+ end
13
+
14
+ # Read file.
15
+
16
+ def file_read(path)
17
+ File.read(path)
18
+ end
19
+
20
+ # Write file.
21
+
22
+ def file_write(path, text)
23
+ if dryrun?
24
+ puts "write #{path}"
25
+ else
26
+ File.open(path, 'w'){ |f| f << text }
27
+ end
28
+ end
29
+
30
+ ##########################
31
+ # Add FileUtils Features #
32
+ ##########################
33
+
34
+ ::FileUtils.private_instance_methods(false).each do |meth|
35
+ next if meth =~ /^fu_/
36
+ module_eval %{
37
+ def #{meth}(*a,&b)
38
+ fileutils.#{meth}(*a,&b)
39
+ end
40
+ }
41
+ end
42
+
43
+ # Delegate access to FileUtils.
44
+
45
+ def fileutils
46
+ dryrun? ? ::FileUtils::DryRun : ::FileUtils
47
+ end
48
+
49
+ # Bonus FileUtils features.
50
+
51
+ def cd(*a,&b)
52
+ puts "cd #{a}" if dryrun?
53
+ fileutils.chdir(*a,&b)
54
+ end
55
+
56
+
57
+ #########################
58
+ # Add FileTest Features #
59
+ #########################
60
+
61
+ FileTest.private_instance_methods(false).each do |meth|
62
+ next if meth =~ /^fu_/
63
+ module_eval %{
64
+ def #{meth}(*a,&b)
65
+ FileTest.#{meth}(*a,&b)
66
+ end
67
+ }
68
+ end
69
+
70
+ # Is a given path a regular file? If +path+ is a glob
71
+ # then checks to see if all matches are refular files.
72
+
73
+ def file?(path)
74
+ paths = Dir.glob(path)
75
+ paths.not_empty? && paths.all?{ |f| FileTest.file?(f) }
76
+ end
77
+
78
+ # Assert that a given path is a file.
79
+
80
+ def file!(*paths)
81
+ abort "file not found #{path}" unless paths.any?{|path| file?(path)}
82
+ end
83
+
84
+ # Is a given path a directory? If +path+ is a glob
85
+ # checks to see if all matches are directories.
86
+
87
+ def dir?(path)
88
+ paths = Dir.glob(path)
89
+ paths.not_empty? && paths.all?{ |f| FileTest.directory?(f) }
90
+ end
91
+ alias_method :directory?, :dir? ; module_function :directory?
92
+
93
+ # Assert that a given path is a directory.
94
+
95
+ def dir!(*paths)
96
+ paths.each do |path|
97
+ abort "Directory not found: '#{path}'." unless dir?(path)
98
+ end
99
+ end
100
+ alias_method :directory!, :dir! ; module_function :directory!
101
+
102
+ # # Okay, I'm being a dork, but 'fold' seems like a better word
103
+ # # then 'dir', 'folder', or 'directory'.
104
+ #
105
+ # def fold?(path)
106
+ # paths = Dir.glob(path)
107
+ # paths.not_empty? && paths.all?{ |f| FileTest.directory?(f) }
108
+ # end
109
+ #
110
+ # # Assert that a given path is a fold (ie. a folder).
111
+ #
112
+ # def fold!(*paths)
113
+ # abort "fold not found #{path}" unless paths.any?{|path| fold?(path)}
114
+ # end
115
+
116
+ # Assert that a path exists.
117
+
118
+ def exists?(path)
119
+ paths = Dir.glob(path)
120
+ paths.not_empty?
121
+ end
122
+ alias_method :exist?, :exists? ; module_function :exist?
123
+ alias_method :path?, :exists? ; module_function :path?
124
+
125
+ # Assert that a path exists.
126
+
127
+ def exists!(*paths)
128
+ abort "path not found #{path}" unless paths.any?{|path| exists?(path)}
129
+ end
130
+ alias_method :exist!, :exists! ; module_function :exist!
131
+ alias_method :path!, :exists! ; module_function :path!
132
+
133
+ # Is a file a task?
134
+
135
+ def task?(path)
136
+ task = File.dirname($0) + "/#{path}"
137
+ task.chomp!('!')
138
+ task if FileTest.file?(task) && FileTest.executable?(task)
139
+ end
140
+
141
+ # Is a file a command executable?
142
+ #
143
+ # TODO Probably needs to be fixed for Windows.
144
+
145
+ def bin?(path)
146
+ is_bin = command_paths.any? do |f|
147
+ FileTest.exist?(File.join(f, path))
148
+ end
149
+ is_bin ? File.basename(path) : false
150
+ end
151
+
152
+ # This is a support method of #bin?
153
+
154
+ def command_paths
155
+ @command_paths ||= ENV['PATH'].split(':')
156
+ end
157
+
158
+ # TODO Make more robust.
159
+
160
+ UNSAFE = [ '/', '/*', '/**/*' ]
161
+
162
+ # Is a path considered reasonably "safe"?
163
+
164
+ def safe?(path)
165
+ case path
166
+ when *UNSAFE
167
+ return false
168
+ end
169
+ true
170
+ end
171
+
172
+ end
173
+ end