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,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