sow 0.4.0

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 (94) hide show
  1. data/COPYING +622 -0
  2. data/HISTORY +14 -0
  3. data/MANIFEST +138 -0
  4. data/NOTES +86 -0
  5. data/README +157 -0
  6. data/bin/sow +4 -0
  7. data/lib/sow.rb +12 -0
  8. data/lib/sow/command.rb +201 -0
  9. data/lib/sow/context.rb +29 -0
  10. data/lib/sow/core_ext.rb +47 -0
  11. data/lib/sow/generators/base.rb +321 -0
  12. data/lib/sow/generators/create.rb +111 -0
  13. data/lib/sow/generators/delete.rb +50 -0
  14. data/lib/sow/generators/update.rb +47 -0
  15. data/lib/sow/logger.rb +73 -0
  16. data/lib/sow/manager.rb +101 -0
  17. data/lib/sow/metadata.rb +115 -0
  18. data/lib/sow/plugin.rb +484 -0
  19. data/lib/sow/script.rb +186 -0
  20. data/lib/sow/session.rb +150 -0
  21. data/meta/authors +1 -0
  22. data/meta/contact +1 -0
  23. data/meta/description +1 -0
  24. data/meta/homepage +1 -0
  25. data/meta/loadpath +2 -0
  26. data/meta/package +1 -0
  27. data/meta/project +1 -0
  28. data/meta/repository +1 -0
  29. data/meta/requires +2 -0
  30. data/meta/ruby +2 -0
  31. data/meta/version +1 -0
  32. data/plug/sow/seeds/bin/.meta/created +1 -0
  33. data/plug/sow/seeds/bin/.meta/description +1 -0
  34. data/plug/sow/seeds/bin/.meta/license +1 -0
  35. data/plug/sow/seeds/bin/.meta/package +1 -0
  36. data/plug/sow/seeds/bin/.meta/requires +1 -0
  37. data/plug/sow/seeds/bin/.meta/title +1 -0
  38. data/plug/sow/seeds/bin/.meta/version +1 -0
  39. data/plug/sow/seeds/bin/SCRIPT.rb +22 -0
  40. data/plug/sow/seeds/bin/template/bin/command.rb +12 -0
  41. data/plug/sow/seeds/hoe/SCRIPT.rb +28 -0
  42. data/plug/sow/seeds/hoe/template/History.txt +7 -0
  43. data/plug/sow/seeds/hoe/template/Manifest.txt +8 -0
  44. data/plug/sow/seeds/hoe/template/README.txt +49 -0
  45. data/plug/sow/seeds/hoe/template/Rakefile +13 -0
  46. data/plug/sow/seeds/hoe/template/bin/__name__ +0 -0
  47. data/plug/sow/seeds/hoe/template/lib/__name__.rb +4 -0
  48. data/plug/sow/seeds/hoe/template/test/test___name__.rb +1 -0
  49. data/plug/sow/seeds/license/SCRIPT.rb +27 -0
  50. data/plug/sow/seeds/license/template/META/license +1 -0
  51. data/plug/sow/seeds/license/template/gpl/LICENSE +622 -0
  52. data/plug/sow/seeds/license/template/lgpl/LICENSE +789 -0
  53. data/plug/sow/seeds/license/template/mit/LICENSE +22 -0
  54. data/plug/sow/seeds/ruby/COPY.yml +14 -0
  55. data/plug/sow/seeds/ruby/DATA.yml +8 -0
  56. data/plug/sow/seeds/ruby/USAGE.txt +8 -0
  57. data/plug/sow/seeds/ruby/script.sow.rb +17 -0
  58. data/plug/sow/seeds/ruby/template/COPYING +622 -0
  59. data/plug/sow/seeds/ruby/template/History.rdoc +18 -0
  60. data/plug/sow/seeds/ruby/template/README.rdoc +43 -0
  61. data/plug/sow/seeds/ruby/template/README.rdoc.till +43 -0
  62. data/plug/sow/seeds/ruby/template/Rakefile +1 -0
  63. data/plug/sow/seeds/ruby/template/bin/__package__ +2 -0
  64. data/plug/sow/seeds/ruby/template/lib/__package__.rb +3 -0
  65. data/plug/sow/seeds/ruby/template/meta/created +1 -0
  66. data/plug/sow/seeds/ruby/template/meta/description +1 -0
  67. data/plug/sow/seeds/ruby/template/meta/license +1 -0
  68. data/plug/sow/seeds/ruby/template/meta/package +1 -0
  69. data/plug/sow/seeds/ruby/template/meta/requires +1 -0
  70. data/plug/sow/seeds/ruby/template/meta/title +1 -0
  71. data/plug/sow/seeds/ruby/template/meta/version +1 -0
  72. data/plug/sow/seeds/ruby/template/setup.rb +1467 -0
  73. data/plug/sow/seeds/ruby/template/test/template.rb +17 -0
  74. data/plug/sow/seeds/testunit/COPY.yml +12 -0
  75. data/plug/sow/seeds/testunit/DATA.yml +23 -0
  76. data/plug/sow/seeds/testunit/USAGE.txt +11 -0
  77. data/plug/sow/seeds/testunit/_SCRIPT.rb +42 -0
  78. data/plug/sow/seeds/testunit/template/form/testunit +24 -0
  79. data/plug/sow/seeds/testunit/template/test/test_template.rb +15 -0
  80. data/plug/sow/seeds/website/template/assets/styles/color.css +0 -0
  81. data/plug/sow/seeds/website/template/assets/styles/font.css +0 -0
  82. data/plug/sow/seeds/website/template/assets/styles/index.css +4 -0
  83. data/plug/sow/seeds/website/template/assets/styles/reset.css +0 -0
  84. data/plug/sow/seeds/website/template/assets/styles/struct.css +0 -0
  85. data/plug/sow/seeds/website/template/index.html +15 -0
  86. data/test/features/scaffold.feature +13 -0
  87. data/test/features/step_definitions/cli_steps.rb +0 -0
  88. data/test/features/step_definitions/fixture_steps.rb +72 -0
  89. data/test/features/support/env.rb +41 -0
  90. data/test/unit/fixtures/README +5 -0
  91. data/test/unit/helper.rb +23 -0
  92. data/test/unit/test_metadata.rb +17 -0
  93. data/test/unit/test_scaffold.rb +37 -0
  94. metadata +178 -0
@@ -0,0 +1,29 @@
1
+ module Sow
2
+
3
+ FIX = "FIXME"
4
+
5
+ # Erb templates are all rendered within the scope
6
+ # a context object. This limits access to only
7
+ # the those things that are pertinant. All metadata
8
+ # can be accessded by name, as this this object
9
+ # delegate missing methods to a Metadata instance.
10
+ #
11
+ class Context
12
+ instance_methods.each{ |m| private m unless m.to_s =~ /^__/ }
13
+
14
+ def initialize(metadata)
15
+ @metadata = metadata
16
+ end
17
+
18
+ def method_missing(s)
19
+ @metadata.__send__(s) || "#{FIX}: (#{s})"
20
+ end
21
+
22
+ # Processes file through erb.
23
+ def erb(file)
24
+ erb = ERB.new(File.read(file))
25
+ erb.result(binding)
26
+ end
27
+ end
28
+
29
+ end
@@ -0,0 +1,47 @@
1
+ require 'erb'
2
+ require 'fileutils'
3
+
4
+ # Facets Core
5
+ require 'facets/kernel/ask'
6
+ require 'facets/hash/rekey'
7
+ require 'facets/dir/multiglob'
8
+ require 'facets/file/rootname'
9
+ require 'facets/file/split_root'
10
+ require 'facets/module/basename'
11
+ require 'facets/string/tab'
12
+ require 'facets/string/pathize'
13
+ require 'facets/string/modulize'
14
+ require 'facets/string/methodize'
15
+
16
+ # Facets More
17
+ require 'facets/ostruct'
18
+ require 'facets/pathname'
19
+
20
+ # ARE THESE NEEDED?
21
+ #require 'facets/yaml' # for to_yamlfrag
22
+ #require 'facets/string/snakecase'
23
+ #require 'facets/string/camelcase'
24
+ #require 'sow/openext'
25
+
26
+ class String
27
+
28
+ def to_list
29
+ split(/[:;\n]/).collect{ |e| e.strip }
30
+ end
31
+
32
+ end
33
+
34
+ # NOTE: These are now in Facets.
35
+
36
+ =begin
37
+ module File
38
+
39
+ #
40
+ def split_root(path)
41
+ path_re = Regexp.new('[' + Regexp.escape(File::Separator + %q{\/}) + ']')
42
+ path.split(path_re, 2)
43
+ end
44
+
45
+ end
46
+ =end
47
+
@@ -0,0 +1,321 @@
1
+ require 'pathname'
2
+ require 'sow/core_ext'
3
+ require 'sow/plugin'
4
+ require 'sow/context'
5
+
6
+ module Sow
7
+
8
+ module Generators
9
+
10
+ # Base Class for the generators. This provides the
11
+ # backbone of Sow's operations. Essentially a plugin
12
+ # provides a copylist to the generator, which cleans
13
+ # it up and uses it for it's specific task,
14
+ # eg. create, update or delete.
15
+ #
16
+ class Base
17
+
18
+ attr :session
19
+ #attr :location
20
+ attr :copylist
21
+
22
+ attr :context
23
+ attr :logger
24
+
25
+ def initialize(session, copylist)
26
+ if session.debug?
27
+ puts "\n[copylist]"
28
+ copylist.each do |loc, tname, fname, opts|
29
+ puts "#{loc} #{tname} #{fname} #{opts.inspect}"
30
+ end
31
+ end
32
+
33
+ @session = session
34
+ #@location = location
35
+ @copylist = copylist
36
+
37
+ @logger = Logger.new(self)
38
+ @context = Context.new(metadata)
39
+ end
40
+
41
+ #
42
+ def metadata
43
+ session.metadata
44
+ end
45
+
46
+ # Where to find plugin files.
47
+ #alias_method :source, :location
48
+
49
+ # TODO: rename to 'destination'
50
+ def output
51
+ @output ||= (
52
+ #if session.create? && plugin.name #scaffold && session.scaffold?
53
+ # session.output + plugin.name
54
+ #else
55
+ session.destination
56
+ #end
57
+ )
58
+ end
59
+
60
+ #
61
+ def arguments
62
+ session.arguments
63
+ end
64
+
65
+ def trial? ; session.trial? ; end
66
+ def debug? ; session.debug? ; end
67
+ def quiet? ; session.quiet? ; end
68
+ def force? ; session.force? ; end
69
+ def prompt? ; session.prompt? ; end
70
+ def skip? ; session.skip? ; end
71
+
72
+ # Newuse of sow? In other words, is the destination empty?
73
+ def newproject?
74
+ session.new?
75
+ end
76
+
77
+ # Main command called to generate files.
78
+ #
79
+ def generate #(args, opts)
80
+ actionlist = actionlist(copylist)
81
+
82
+ if actionlist.empty?
83
+ logger.report_nothing_to_generate
84
+ return
85
+ end
86
+
87
+ source = '' # FIXME
88
+ logger.report_startup(source, output)
89
+ mkdir_p(output) #unless File.directory?(output)
90
+ Dir.chdir(output) do
91
+ actionlist.each do |action, loc, src, dest, opts|
92
+ atime = Time.now
93
+ result, fulldest = *__send__(action, loc, src, dest, opts)
94
+ logger.report_create(relative_to_output(dest), result, atime)
95
+ #logger.report_create(dest, result, atime)
96
+ end
97
+ end
98
+ logger.report_complete
99
+ logger.report_fixes #if session.newproject?
100
+ end
101
+
102
+ private
103
+
104
+ # Processes with erb.
105
+ def erb(file)
106
+ context.erb(file)
107
+ #metadata.erb(file)
108
+ end
109
+
110
+ #
111
+ def mark; 'copy'; end
112
+
113
+ def actionlist(list)
114
+ list = actionlist_sort(list)
115
+ list = actionlist_mark(list)
116
+ list = actionlist_safe(list)
117
+ list = actionlist_check(list)
118
+ list
119
+ end
120
+
121
+ def actionlist_sort(list)
122
+ list
123
+ end
124
+
125
+ # Add copy action.
126
+ def actionlist_mark(list)
127
+ list.map do |args|
128
+ [mark, *args]
129
+ end
130
+ end
131
+
132
+ # If in prompt mode, returns a list filtered of overwrites
133
+ # as selected by the user. If in skip mode, mark duplicates to
134
+ # skipped. If not in prompt or skip mode, simply return the
135
+ # current list.
136
+ #
137
+ def actionlist_safe(list)
138
+ return list unless (prompt? or skip?)
139
+ return list if list.empty?
140
+ safe = []
141
+ dups = []
142
+ list.each do |action, loc, tname, fname, opts|
143
+ dups << [action, loc, tname, fname, opts, (output + fname).file?]
144
+ end
145
+ puts "Select (y/n) which files to overwrite:\n" if prompt? unless quiet?
146
+ dups.each do |action, loc, tname, fname, opts, check|
147
+ if check
148
+ if skip?
149
+ safe << [:skip, loc, tname, fname, opts]
150
+ else
151
+ f = relative_to_output(fname)
152
+ case ans = ask(" #{f}? ").downcase.strip
153
+ when 'y', 'yes'
154
+ safe << [action, loc, tname, fname, opts]
155
+ else
156
+ safe << [:skip, loc, tname, fname, opts]
157
+ end
158
+ end
159
+ else
160
+ safe << [action, loc, tname, fname, opts]
161
+ end
162
+ end
163
+ puts
164
+ return safe
165
+ end
166
+
167
+ def actionlist_check(list)
168
+ check_conflicts(list) # TODO: should this come before or after prompt?
169
+ check_overwrite(list)
170
+ list
171
+ end
172
+
173
+ # Check for any overwrites. If generator allows overwrites
174
+ # this will be skipped, otherewise an error will be raised.
175
+ #
176
+ # TODO: Make this a list filter with check for "identical" files?
177
+ def check_overwrite(list)
178
+ return if force?
179
+ return if prompt?
180
+ return if skip?
181
+ #return if session.overwrite? # TODO: not so sure overwirte? option is a good idea.
182
+
183
+ if newproject? && !output.glob('**/*').empty? # FIXME?
184
+ abort "New project isn't empty. Use --force, --skip or --prompt."
185
+ end
186
+
187
+ clobbers = []
188
+ list.each do |action, loc, tname, fname, opts|
189
+ tpath = loc + tname
190
+ fpath = output + fname
191
+ if fpath.file? #fpath.exist?
192
+ clobbers << relative_to_output(fname)
193
+ end
194
+ end
195
+
196
+ if !clobbers.empty?
197
+ puts " " + clobbers.join("\n ")
198
+ abort "These files would be overwritten. Use --force, --skip or --prompt." # TODO: implement --skip
199
+ end
200
+ end
201
+
202
+ # Check for any clashing generations, ie. a directory that
203
+ # will overwrite a file or a file that will overwrite a
204
+ # directory. This will raise an error if any of these
205
+ # conditions are found, unless force? is set to true.
206
+ #
207
+ def check_conflicts(list)
208
+ #return if force?
209
+ list.each do |action, loc, tname, fname, opts|
210
+ tpath = loc + tname
211
+ fpath = output + fname
212
+ if File.exist?(fpath)
213
+ if tpath.directory?
214
+ if !fpath.directory?
215
+ raise "Directory to be created clashes with a pre-existent file -- #{fname}"
216
+ end
217
+ else
218
+ if fpath.directory?
219
+ raise "File to be created clashes with a pre-existent directory -- #{fname}"
220
+ end
221
+ end
222
+ end
223
+ end
224
+ end
225
+
226
+ #
227
+ def skip(loc, src, dest, opts)
228
+ return 'skip', dest
229
+ end
230
+
231
+ # Access to FileUtils
232
+ def fu
233
+ trial? ? FileUtils::DryRun : FileUtils
234
+ end
235
+
236
+ #
237
+ def cp(src, dest)
238
+ if trial?
239
+ s = src #relative_to_source(src)
240
+ d = relative_to_output(dest)
241
+ puts "cp #{s} #{d}"
242
+ else
243
+ fu.cp(src, dest)
244
+ end
245
+ end
246
+
247
+ #
248
+ def mkdir_p(dir)
249
+ if trial?
250
+ d = relative_to_output(dir)
251
+ puts "mkdir_p #{d}"
252
+ else
253
+ fu.mkdir_p(dir)
254
+ end
255
+ end
256
+
257
+ #
258
+ def chmod(mode, file)
259
+ if trial?
260
+ f = relative_to_output(file)
261
+ puts "chmod #{f} #{mode}"
262
+ else
263
+ fu.chmod(mode, file)
264
+ end
265
+ end
266
+
267
+ # Write file.
268
+ def write(file, text)
269
+ if trial?
270
+ f = relative_to_output(file)
271
+ puts "write #{f}"
272
+ else
273
+ mkdir_p(File.dirname(file))
274
+ File.open(file, 'w'){ |f| f << text }
275
+ end
276
+ end
277
+
278
+ #
279
+ def rm(dest)
280
+ if File.directory?(dest)
281
+ if trial?
282
+ d = relative_to_output(dest)
283
+ puts "rmdir #{d}"
284
+ else
285
+ fu.rmdir(dest)
286
+ end
287
+ else
288
+ if trial?
289
+ d = relative_to_output(dest)
290
+ puts "rm #{d}"
291
+ else
292
+ fu.rm(dest)
293
+ end
294
+ end
295
+ end
296
+
297
+ # FIXME
298
+ #def relative_to_source(src)
299
+ # Pathname.new(src).relative_path_from(source)
300
+ #end
301
+
302
+ #
303
+ def relative_to_output(dest)
304
+ if dest =~ /^\//
305
+ Pathname.new(dest).relative_path_from(output)
306
+ else
307
+ dest
308
+ end
309
+ end
310
+
311
+ #
312
+ def inspect
313
+ "#<#{self.class} @session=#{@session.inspect}>"
314
+ end
315
+
316
+ end
317
+
318
+ end
319
+
320
+ end#module Sow
321
+
@@ -0,0 +1,111 @@
1
+ require 'sow/generators/base'
2
+
3
+ module Sow
4
+
5
+ module Generators
6
+
7
+ # = Create Generator
8
+ #
9
+ class Create < Base
10
+
11
+ #
12
+ def copy(loc, src, dest, opts)
13
+ tmp = File.join(loc, src)
14
+ if File.directory?(tmp)
15
+ copy_dir(loc, src, dest, opts)
16
+ else
17
+ copy_doc(loc, src, dest, opts)
18
+ end
19
+ end
20
+
21
+ #
22
+ def copy_dir(loc, src, dest, opts)
23
+ if File.exist?(dest) #&& src == dest
24
+ how = 'same'
25
+ else
26
+ mkdir_p(dest)
27
+ how = 'create'
28
+ end
29
+ return how, dest
30
+ end
31
+
32
+ # TODO: Can .stub be used to prevent erb?
33
+ def copy_doc(loc, src, dest, opts)
34
+ tmp = File.join(loc, src)
35
+ #ext = File.extname(src)
36
+ #case ext
37
+ #when '.erb'
38
+ if opts['verbatim']
39
+ how = (File.exist?(dest) ? 'update' : 'create')
40
+ #file = tmp_file.chomp('.stub')
41
+ cp(tmp, dest)
42
+ else
43
+ #file = tname.chomp('.erb') # old way
44
+ text = erb(tmp)
45
+ how = (File.exist?(dest) ? 'update' : 'create')
46
+ write(dest, text)
47
+ end
48
+ if opts['chmod']
49
+ chmod(opts['chmod'], dest)
50
+ end
51
+ return how, dest
52
+ end
53
+
54
+ #
55
+ #def erb(file)
56
+ # plugin.erb(file)
57
+ #end
58
+
59
+ =begin
60
+ ###
61
+ def erb(file)
62
+ text = nil
63
+ temp = Context.new(plugin)
64
+ begin
65
+ text = temp.erb(file)
66
+ rescue => e
67
+ if trace?
68
+ raise e
69
+ else
70
+ abort "template error -- #{file}"
71
+ end
72
+ end
73
+ return text
74
+ end
75
+
76
+
77
+ ### Copy a directory varbatim; wich means
78
+ ### just doing a mkdir.
79
+ def verbatim_dir(tname, fname)
80
+ if File.exist?(fname)
81
+ #logger.report_create(fname, 'identical')
82
+ 'identical'
83
+ else
84
+ #logger.report_create(fname, 'create')
85
+ mkdir_p(fname)
86
+ 'create'
87
+ end
88
+ end
89
+
90
+ ### Copy a file verbatim.
91
+ def verbatim_file(tname, fname)
92
+ #ext = File.extname(tname)
93
+ doc = File.join(source, tname)
94
+ if File.exist?(fname)
95
+ how = 'update'
96
+ else
97
+ how = 'create'
98
+ end
99
+ #file = tmp_file.chomp('.stub')
100
+ #file = file.sub('__name__', name)
101
+ cp(doc, fname)
102
+ return how
103
+ end
104
+ =end
105
+
106
+ end
107
+
108
+ end
109
+
110
+ end
111
+