sow 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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,50 @@
1
+ require 'sow/generators/base'
2
+
3
+ module Sow
4
+
5
+ module Generators
6
+
7
+ # = Delete Generator
8
+ #
9
+ #--
10
+ # TODO: should force option be require to do this?
11
+ # And without force it just reports what would be deleted?
12
+ #++
13
+ class Delete < Base
14
+
15
+ def mark; 'delete'; end
16
+
17
+ #
18
+ def actionlist_check(list)
19
+ list
20
+ end
21
+
22
+ # Sort the manifest files before directory.
23
+ # This is opposite of Construct::Create.
24
+ def actionlist_sort(list)
25
+ list.reverse
26
+ #dirs, files = *list.partition{ |src, dest, opts| (source + src).directory? }
27
+ #files.sort{|a,b| a[1]<=>b[1]} + dirs.sort{|a,b| a[1]<=>b[1]}
28
+ end
29
+
30
+ # Delete template file.
31
+ def delete(loc, src, dest, opts)
32
+ if File.exist?(dest)
33
+ how = 'delete'
34
+ begin
35
+ rm(dest)
36
+ rescue Errno::ENOTEMPTY
37
+ how = 'skip'
38
+ end
39
+ else
40
+ how = 'missing'
41
+ end
42
+ return how, dest
43
+ end
44
+
45
+ end#class Delete
46
+
47
+ end#module Generators
48
+
49
+ end#module Sow
50
+
@@ -0,0 +1,47 @@
1
+ require 'sow/generators/create'
2
+
3
+ #--
4
+ # TODO: Could we use an "environment" settings file to specify environment variables to check for template variables?
5
+ #++
6
+
7
+ module Sow
8
+
9
+ module Generators
10
+
11
+ # = Update Generator
12
+ #
13
+ # Update is the same as the Create Generator with the exception
14
+ # that it pulls all metadata from the destination.
15
+ #
16
+ class Update < Create
17
+
18
+ =begin
19
+ ### Copy the file, processing it with ERB if
20
+ ### it has an .erb extension. Unlike Create's
21
+ ### this will skip pre-existant non-erb files.
22
+ def copy_doc(src, dest)
23
+ tmp = File.join(source, src)
24
+ ext = File.extname(src)
25
+ case ext
26
+ when '.erb'
27
+ text = erb(tmp)
28
+ how = (File.exist?(dest) ? 'update' : 'create')
29
+ write(dest, text)
30
+ else
31
+ if File.exist?(dest)
32
+ how = 'skip'
33
+ else
34
+ how = 'create'
35
+ cp(tmp, dest)
36
+ end
37
+ end
38
+ return how, dest
39
+ end
40
+ =end
41
+
42
+ end
43
+
44
+ end
45
+
46
+ end
47
+
data/lib/sow/logger.rb ADDED
@@ -0,0 +1,73 @@
1
+ module Sow
2
+
3
+ # The Logger class routes output to the console.
4
+ #
5
+ class Logger
6
+
7
+ #
8
+ attr :generator
9
+
10
+ #
11
+ def initialize(generator)
12
+ @generator = generator
13
+ end
14
+
15
+ # If there is nothing to generate this will be called
16
+ # to display a message to the effect.
17
+ def report_nothing_to_generate
18
+ report "Nothing to generate."
19
+ end
20
+
21
+ # Output to provide on startup of generation.
22
+ def report_startup(source, output) # FIXME: pass what info?
23
+ @time = Time.now
24
+ dir = File.basename(source) #File.basename(File.dirname(source))
25
+ report "Generating #{dir} in #{File.basename(output)}:\n\n"
26
+ end
27
+
28
+ # Output to provide when generation is complete.
29
+ def report_complete
30
+ report "\nFinished in %.3f seconds." % [Time.now - @time]
31
+ end
32
+
33
+ # Output to provide as generation is progressing.
34
+ def report_create(file, how, atime)
35
+ report "%10s [%.4fs] %s" % [how, (Time.now - atime), file]
36
+ end
37
+
38
+ # Use this to report any "templating" that needs
39
+ # to done by hand.
40
+ def report_fixes(marker='FIXME:')
41
+ glist = check_for_fixes(marker)
42
+ unless glist.empty?
43
+ puts "\nYou need to fix the occurances of '#{marker}' in the following files:\n\n"
44
+ glist.each do |file|
45
+ puts " #{file}"
46
+ end
47
+ puts
48
+ end
49
+ end
50
+
51
+ # TODO: don't use grep
52
+ def check_for_fixes(marker)
53
+ g = `grep -R #{marker} .` # FIXME Use ruby code instead
54
+ glist = []
55
+ g.each_line do |line|
56
+ line = line.gsub('./','')
57
+ indx = line.index(':')
58
+ file, *desc = *line.split(':')
59
+ glist << file
60
+ end
61
+ glist.uniq
62
+ end
63
+
64
+ private
65
+
66
+ def report(message)
67
+ puts message unless generator.quiet? or generator.trial?
68
+ end
69
+
70
+ end
71
+
72
+ end
73
+
@@ -0,0 +1,101 @@
1
+ require 'sow/plugin'
2
+ require 'facets/plugin_manager'
3
+
4
+ module Sow
5
+
6
+ # The Manager class locates sow plugins.
7
+ #
8
+ class Manager
9
+
10
+ #
11
+ PLUGIN_DIRECTORY = "sow/seeds"
12
+
13
+ def initialize
14
+ end
15
+
16
+ # Plugins
17
+ #--
18
+ # Note that order of paths is important here.
19
+ #++
20
+ def plugin_locations
21
+ @plugin_locations ||= (
22
+ pl = {}
23
+ pa = []
24
+ pa |= plugins_from_packages
25
+ #pa |= plugins_core)
26
+ #pa |= plugins_user
27
+ pa.each do |d|
28
+ pl[File.basename(d)] = d
29
+ end
30
+ pl
31
+ )
32
+ end
33
+
34
+ def plugins
35
+ @plugins ||= plugin_locations.keys
36
+ end
37
+
38
+ def plugin(session, name, options)
39
+ location = plugin_locations[name]
40
+ raise "unknown scaffolding -- #{name}" unless location
41
+ Plugin.new(session, location, options)
42
+ end
43
+
44
+ # Convert path into plugin.
45
+ #def plugin(path)
46
+ # path = Pathname.new(path) unless path.is_a?(Pathname)
47
+ # Plugin.new(:location => path, :project => project, :command => cli)
48
+ #end
49
+
50
+ # This routine searches for seeds (sow plugins),
51
+ #
52
+ def plugins_from_packages
53
+ match = File.join(PLUGIN_DIRECTORY, '*/')
54
+ PluginManager.find(match).map do |path|
55
+ path.chomp('/')
56
+ end
57
+ end
58
+
59
+ =begin
60
+ # Plugins installed in other packages.
61
+ # This routine searches through the $LOAD_PATH
62
+ # looking for directories with a MANIFEST.sow file.
63
+ #
64
+ def plugins_from_packages
65
+ plugins = []
66
+ # Standard $LOAD_PATH
67
+ $LOAD_PATH.uniq.each do |path|
68
+ dirs = Dir.glob(File.join(path, PLUGIN_DIRECTORY, '*/'))
69
+ #dirs = dirs.select{ |d| File.directory?(d) }
70
+ dirs = dirs.map{ |d| d.chomp('/') }
71
+ plugins.concat(dirs)
72
+ end
73
+ # ROLL (load latest versions only)
74
+ if defined?(::Roll)
75
+ ::Roll::Library.ledger.each do |name, lib|
76
+ lib = lib.sort.first if Array===lib
77
+ lib.load_path.each do |path|
78
+ path = File.join(lib.location, path)
79
+ dirs = Dir.glob(File.join(path, PLUGIN_DIRECTORY, '*/'))
80
+ #dirs = dirs.select{ |d| File.directory?(d) }
81
+ dirs = dirs.map{ |d| d.chomp('/') }
82
+ plugins.concat(dirs)
83
+ end
84
+ end
85
+ end
86
+ # RubyGems (load latest versions only)
87
+ if defined?(::Gem)
88
+ Gem.latest_load_paths do |path|
89
+ dirs = Dir.glob(File.join(path, PLUGIN_DIRECTORY, '*/'))
90
+ dirs = dirs.map{ |d| d.chomp('/') }
91
+ plugins.concat(dirs)
92
+ end
93
+ end
94
+ plugins
95
+ end
96
+ =end
97
+
98
+ end
99
+
100
+ end #module Sow
101
+
@@ -0,0 +1,115 @@
1
+ module Sow
2
+
3
+ # Metadata located in destination.
4
+ #
5
+ # This can be used to "prefill" template variables in some
6
+ # types of scaffolding.
7
+ #
8
+ #--
9
+ # TODO: Use POM::Metadata instead?
10
+ #
11
+ # TODO: Should this only be used when updating?
12
+ #
13
+ # TODO: If we copy meta/ first then it can be reused. ?
14
+ #++
15
+ class Metadata
16
+ alias :__id__ :object_id
17
+
18
+ instance_methods.each{ |m| private m unless m.to_s =~ /^__/ }
19
+
20
+ #
21
+ def initialize(destination)
22
+ @dir = destination
23
+ @cache = {}
24
+ end
25
+
26
+ # Is there a metadata directory located in the destination directory?
27
+ def exist?
28
+ @exist ||= Dir.glob(File.join(@dir, '{.meta,meta}/')).first
29
+ end
30
+
31
+ # If method is missing, lookup metdata value by that name.
32
+ def method_missing(s, *a, &b)
33
+ s = s.to_s
34
+ if s =~ /=$/
35
+ s = s.chomp('=')
36
+ self[s] = a[0]
37
+ else
38
+ s = s.chomp('?')
39
+ self[s]
40
+ end
41
+ end
42
+
43
+ # Metadata has given +entry+?
44
+ def respond_to?(entry)
45
+ self[entry] ? true : false
46
+ end
47
+
48
+ # Get a metadata value directly from the metadata cache.
49
+ def __get__(entry)
50
+ @cache[entry.to_s]
51
+ end
52
+
53
+ # Get a metadata value. If not found in the cache,
54
+ # attempt to load it from the path store.
55
+ def [](s)
56
+ s = s.to_s
57
+ if @cache.key?(s)
58
+ @cache[s]
59
+ else
60
+ #@cache[s] = HOLE + " (#{s})"
61
+ @cache[s] = load_value(s) #|| HOLE + " (#{s})"
62
+ end
63
+ end
64
+
65
+ # Set a metadate value.
66
+ def []=(k,v)
67
+ @cache[k.to_s] = v
68
+ end
69
+
70
+ private
71
+
72
+ # Load metadata value.
73
+ #
74
+ # In update mode, metadata is looked for in the receiving end.
75
+ #
76
+ def load_value(name)
77
+ #val = read_value_from_commandline(name)
78
+ #return val if val
79
+
80
+ #if @plugin.update?
81
+ # val = load_value_from_destination(name)
82
+ # return val if val
83
+ #end
84
+
85
+ # See if the metadata is defined in the destination.
86
+
87
+ file = Dir[File.join(@dir, '{meta,.meta}', name)].first
88
+
89
+ if file && File.file?(file)
90
+ File.read(file).strip # erb?
91
+ else
92
+ nil
93
+ end
94
+ end
95
+
96
+ #def load_template_metadata
97
+ # Dir[File.join(metasrc, '*')].each do |f|
98
+ # @metadata_source[File.basename(f)] = erb(f).strip
99
+ # end
100
+ #end
101
+
102
+ # Processes with erb.
103
+ def erb(file)
104
+ erb = ERB.new(File.read(file))
105
+ erb.result(binding!)
106
+ end
107
+
108
+ def binding!
109
+ binding
110
+ end
111
+
112
+ end
113
+
114
+ end
115
+
data/lib/sow/plugin.rb ADDED
@@ -0,0 +1,484 @@
1
+ require 'sow/core_ext'
2
+ require 'sow/session'
3
+ require 'sow/logger'
4
+ require 'sow/script'
5
+ require 'sow/generators/create'
6
+ require 'sow/generators/update'
7
+ require 'sow/generators/delete'
8
+
9
+ require 'facets/erb'
10
+ require 'facets/ostruct'
11
+ require 'facets/kernel/instance_class'
12
+
13
+ module Sow
14
+
15
+ # Plugin encapsulates information about a sow plugin.
16
+ #
17
+ class Plugin
18
+ # Name of template directory.
19
+ TEMPLATE_NAME = 'template/'
20
+ # Name of plugin script file.
21
+ SCRIPT_NAME = 'SCRIPT{,.rb}'
22
+ # Name of usage document.
23
+ USAGE_NAME = 'USAGE{,.txt}'
24
+ # Name of metadata file.
25
+ DATA_NAME = 'DATA{,.yml,.yaml}'
26
+ # Name of copy file.
27
+ COPY_NAME = 'COPY{,.yml,.yaml}'
28
+
29
+ # Instanance of Session.
30
+ attr :session
31
+ # Location of plugin.
32
+ attr :location
33
+ # Argmuent
34
+ attr :argument
35
+ # Options
36
+ attr :options
37
+ # Desitnation pathname
38
+ attr :destination
39
+
40
+ #
41
+ def initialize(session, location, options)
42
+ @session = session
43
+ @options = options.to_ostruct
44
+
45
+ @location = Pathname.new(location)
46
+
47
+ @copy = []
48
+ end
49
+
50
+ # Metadata from scaffold destination.
51
+ def metadata
52
+ session.metadata
53
+ end
54
+
55
+ # Destination for scaffolding.
56
+ def destination
57
+ session.destination
58
+ end
59
+
60
+ # Argument for main command option.
61
+ def argument
62
+ options.argument
63
+ end
64
+
65
+ # Directory with template files.
66
+ def template_dir
67
+ @template_dir ||= grab(TEMPLATE_NAME)
68
+ end
69
+
70
+ # File containing usage text.
71
+ def usage_file
72
+ @usage_file ||= grab(USAGE_NAME)
73
+ end
74
+
75
+ # Metadata file.
76
+ def meta_file
77
+ @meta_file ||= grab(DATA_NAME)
78
+ end
79
+
80
+ # Transfer file.
81
+ def seed_file
82
+ @seed_file ||= grab(COPY_NAME)
83
+ end
84
+
85
+ # Traditional alternative to the meta & seed file.
86
+ def script_file
87
+ @script_file ||= grab(SCRIPT_NAME)
88
+ end
89
+
90
+ # Usage text.
91
+ def usage
92
+ @usage ||= (
93
+ if usage_file
94
+ Usage.new(usage_file)
95
+ else
96
+ "Generate #{self.class.name} scaffolding."
97
+ end
98
+ )
99
+ end
100
+
101
+ # Plugin's special metadata. These entries are
102
+ # converted to methods for rendering of the
103
+ # transfer list.
104
+ def meta
105
+ @meta ||= (
106
+ if meta_file
107
+ YAML.load(File.new(meta_file))
108
+ else
109
+ {}
110
+ end
111
+ )
112
+ end
113
+
114
+ # Plugin's transfer list.
115
+ def seed
116
+ @seed ||= (
117
+ if seed_file
118
+ res = template.erb_result(File.read(seed_file))
119
+ YAML.load(res)
120
+ else
121
+ [{'from' => '**/*'}]
122
+ end
123
+ )
124
+ end
125
+
126
+ private
127
+
128
+ # Grab the first instance of a mathcing glob as a Pathname object.
129
+ def grab(glob)
130
+ file = Dir.glob(File.join(location, glob), File::FNM_CASEFOLD).first
131
+ file ? Pathname.new(file) : nil
132
+ end
133
+
134
+ # Erb OpenTemplate
135
+ def template
136
+ @template ||= (
137
+ ERB::OpenTemplate.new(options, session, :options => options, :metadata=>metadata)
138
+ )
139
+ end
140
+
141
+ =begin
142
+ # Setup up the option parsing for the specific plugin.
143
+ # This method takes an instance of OptionParser.
144
+ def setup_options(parser)
145
+ txt = []
146
+ txt << "Usage: sow " + script[:usage] if script[:usage]
147
+ txt << script[:help] if script[:help]
148
+ parser.banner = txt.join("\n")
149
+ script[:options].each do |name, desc, valid|
150
+ if valid.arity == 0
151
+ parser.on("--#{name}", desc, &valid)
152
+ else
153
+ parser.on("--#{name} [VALUE]", desc, &valid)
154
+ end
155
+ end
156
+ end
157
+ =end
158
+
159
+ public
160
+
161
+ # Prepare for scaffolding procedure. If a script.rb file
162
+ # was provided then uses the class defined within it
163
+ # to build the proper copylist.
164
+ #
165
+ # IMPORTANT: The class name must have the same as the
166
+ # plugin directory it is within.
167
+ #
168
+ # If not using a script.rb, but rather a seed.yml and/or
169
+ # a meta.yml file, this reads and prepares those instead.
170
+
171
+ def setup
172
+ if script_file
173
+ require(File.expand_path(script_file))
174
+ scriptClass = Script.registry[location.basename.to_s]
175
+ @script = scriptClass.new(session, options)
176
+ @script.setup
177
+ @script.manifest
178
+ @copy = @script.copylist
179
+ else
180
+ prepare_meta
181
+ prepare_seed
182
+ prepare_data
183
+ end
184
+ end
185
+
186
+ #setup_arguments #(arguments)
187
+ #setup_metadata
188
+ #setup_script #(session)
189
+ #init
190
+ #parse
191
+
192
+ # Any arguments defined in the script get there assigments
193
+ # defined as singleton methods via the script[]= call.
194
+ #def setup_arguments #(a)
195
+ # #h = {}
196
+ # a = script[:values]
197
+ # script[:arguments].each_with_index do |(name, desc, valid), i|
198
+ # if valid
199
+ # script[name] = valid.call(a[i])
200
+ # else
201
+ # script[name] = a[i]
202
+ # end
203
+ # end
204
+ # #@args = h #TODO: where?
205
+ #end
206
+
207
+ # Collect any metadata settings that may have been made
208
+ # in the initial script evaluation.
209
+ #def setup_metadata
210
+ # script.metadata.each do |k,v|
211
+ # metadata[k] = v
212
+ # end
213
+ #end
214
+
215
+ # Setup the plugin with information about current operation.
216
+ #
217
+ # TODO: This seems wrong. Need to figure a better way!
218
+ #
219
+ #def setup_script
220
+ # script.instance_variable_set("@session", session)
221
+ # script.instance_variable_set("@metadata", metadata)
222
+ # #script[:values].each do |v|
223
+ # #end
224
+ #end
225
+
226
+ # Define metadata entries as singleton methods of the Erb template.
227
+ def prepare_meta
228
+ meta.each do |m,c|
229
+ template.instance_class do
230
+ eval %{
231
+ def #{m}
232
+ #{c}
233
+ end
234
+ }
235
+ end
236
+ end
237
+ # validate
238
+ template.validate if meta['validate']
239
+ end
240
+
241
+ #
242
+ def prepare_seed
243
+ seed.each do |opts|
244
+ opts.rekey!(&:to_s)
245
+ from = opts.delete('from')
246
+ to = opts.delete('to') || '.'
247
+ cond = opts.delete('if')
248
+ next unless template.instance_eval(cond) if cond
249
+ @copy << [from, to, opts]
250
+ end
251
+ end
252
+
253
+ #
254
+ def prepare_data
255
+ meta.each do |m,c|
256
+ metadata[m] = template.__send__(m)
257
+ end
258
+ end
259
+
260
+ # Designate a copying action.
261
+ #
262
+ #def copy(*from_to_opts)
263
+ # opts = Hash===from_to_opts.last ? from_to_opts.pop : {}
264
+ # from, to = *from_to_opts
265
+ # to = to || '.'
266
+ # @copylist << [from, to, opts]
267
+ #end
268
+
269
+ # Expanded copy list.
270
+ def copylist
271
+ @copylist ||= copylist_sort(copylist_glob(@copy)) #redest(list)
272
+ end
273
+
274
+ # Raw copylist as defined in the script.
275
+ #def script_copylist
276
+ # @script_copylist ||= (
277
+ # script[:copytemp].each{|s| s.call}
278
+ # script[:copylist]
279
+ # )
280
+ #end
281
+
282
+ # Does the script define a package name.
283
+ #def name
284
+ # script[:name]
285
+ #end
286
+
287
+ # Expand copylist by globbing entries.
288
+
289
+ def copylist_glob(copylist)
290
+ list = []
291
+ dotpaths = ['.', '..']
292
+
293
+ copylist.each do |from, into, opts|
294
+ cdir = opts['cd'] || '.'
295
+ srcs = []
296
+
297
+ Dir.chdir(template_dir + cdir) do
298
+ less = opts['less'] ? Dir.multiglob_r(opts['less']) : []
299
+ srcs = Dir.glob(from, File::FNM_DOTMATCH)
300
+ srcs = srcs - less
301
+ srcs = srcs.reject{ |d| File.basename(d) =~ /^[.]{1,2}$/ }
302
+ end
303
+
304
+ # remove +less+ option, not needed any more
305
+ opts.delete('less')
306
+ #srcs = filter_paths(srcs)
307
+ srcs.each do |src|
308
+ case into
309
+ when /\/$/
310
+ dest = File.join(into, File.basename(src))
311
+ when '.'
312
+ dest = src
313
+ else
314
+ dest = into
315
+ end
316
+ source = (cdir == '.' ? src : File.join(cdir, src))
317
+ list << [template_dir, source, template_to_filename(dest), opts] #dest
318
+ end
319
+ end
320
+ list = uniq(list)
321
+ list
322
+ end
323
+
324
+ # Reduce copylist to uniq transfers. If transfers are the same
325
+ # the later transfere takes precedence. Transfire options are
326
+ # not considered in determining uniquness.
327
+
328
+ def uniq(list)
329
+ h = {}
330
+ list.each do |dir, src, dest, opts|
331
+ h[[dir,src,dest]] = opts
332
+ end
333
+ h.inject([]){ |a,x| a << x.flatten; a }
334
+ end
335
+
336
+ =begin
337
+ # Filter out special paths from copylist.
338
+ #
339
+ def filter_paths(paths)
340
+ filter.each do |re|
341
+ paths = paths.reject do |pn|
342
+ case re
343
+ when Regexp
344
+ re =~ pn.to_s
345
+ else
346
+ re == pn.to_s
347
+ end
348
+ end
349
+ end
350
+ paths
351
+ end
352
+ =end
353
+
354
+ # Convert a template pathname into a destination pathname.
355
+ # This allows for substitution in the pathnames themselves
356
+ # by using '__name__' notation.
357
+ #
358
+ def template_to_filename(path)
359
+ name = path.dup #chomp('.erb')
360
+ name = name.gsub(/__(.*?)__/) do |md|
361
+ metadata.__get__($1) || 'FIXME' # TODO: raise error?
362
+ end
363
+ #if md =~ /^(.*?)[-]$/
364
+ # name = metadata[md[1]] || plugin.metadata(md[1]) || name
365
+ #end
366
+ name
367
+ end
368
+
369
+ # Sort the list, directory before files and in alphabetical order.
370
+ def copylist_sort(list)
371
+ dirs, files = *copylist_partition(list)
372
+ dirs.sort{|a,b| a[2]<=>b[2]} + files.sort{|a,b| a[2]<=>b[2]}
373
+ end
374
+
375
+ # Partition the list between directories and files.
376
+ def copylist_partition(list)
377
+ list.partition{ |loc, src, dest, opts| (loc + src).directory? }
378
+ end
379
+
380
+ # Complete destination.
381
+ #def copylist_dest(list)
382
+ # list.collect do |src, dest|
383
+ # case dest
384
+ # when nil
385
+ # dest = src
386
+ # when '/.'
387
+ # dest = src
388
+ # when /\/[.]$/
389
+ # dest = File.join(dest.chomp('/.'), src)
390
+ # when '/', '.'
391
+ # dest = File.basename(src)
392
+ # when /\/$/
393
+ # #dest = File.join(dest, template_to_filename(File.basename(src)))
394
+ # dest = File.join(dest, File.basename(src))
395
+ # #else
396
+ # # dest = dest
397
+ # end
398
+ # dest = template_to_filename(dest)
399
+ # [src, dest]
400
+ # end
401
+ #end
402
+
403
+ ###
404
+ #def erb(file)
405
+ # text = nil
406
+ # temp = Context.new(plugin)
407
+ # begin
408
+ # text = temp.erb(file)
409
+ # rescue => e
410
+ # if trace?
411
+ # raise e
412
+ # else
413
+ # abort "template error -- #{file}"
414
+ # end
415
+ # end
416
+ # return text
417
+ #end
418
+
419
+ end
420
+
421
+ end#module Sow
422
+
423
+
424
+
425
+
426
+
427
+ =begin
428
+ #
429
+ def create(arguments, options={})
430
+ setup_for(:create, arguments, options)
431
+
432
+ #setup_arguments #(arguments)
433
+ #session.mode = :create
434
+
435
+ # collect metadata settings
436
+ #plugin.script.metadata.each do |k,v|
437
+ # metadata[k] = v
438
+ #end
439
+
440
+ # this is kind of odd here
441
+ #plugin.script_setup(session)
442
+
443
+ #session = Session.new(arguments, options)
444
+ generator = Generators::Create.new(session, location, copylist)
445
+ generator.generate
446
+ end
447
+
448
+ #
449
+ def update(arguments, options={})
450
+ setup_for(:update, arguments, options)
451
+ #setup_arguments #(arguments)
452
+ #session.mode = :update
453
+
454
+ #session = Session.new(arguments, options)
455
+ generator = Generators::Update.new(session, location, copylist)
456
+ generator.generate
457
+ end
458
+
459
+ #
460
+ def delete(arguments, options={})
461
+ setup_for(:delete, arguments, options)
462
+ #setup_arguments #(arguments)
463
+ #session.mode = :delete
464
+ #session = Session.new(arguments, options)
465
+ generator = Generators::Delete.new(session, location, copylist)
466
+ generator.generate
467
+ end
468
+
469
+ # No specific operation mode given, select one
470
+ # based on plugin and state of current location.
471
+ def select(arguments, options={})
472
+ #setup_arguments #(arguments) # FIXME
473
+ #session = Session.new(arguments, options)
474
+ if name && session.sowed? #FIXME name?
475
+ setup_for(:update, arguments, options)
476
+ generator = Generators::Update.new(session, location, copylist)
477
+ generator.generate
478
+ else
479
+ setup_for(:create, arguments, options)
480
+ generator = Generators::Create.new(session, location, copylist)
481
+ generator.generate
482
+ end
483
+ end
484
+ =end