tap-gen 0.3.1 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History +4 -0
- data/MIT-LICENSE +1 -1
- data/README +1 -4
- data/lib/tap/generator/base.rb +99 -33
- data/lib/tap/generator/destroy.rb +20 -4
- data/lib/tap/generator/generate.rb +20 -4
- data/lib/tap/generator/generators/config.rb +5 -17
- data/lib/tap/generator/generators/env.rb +106 -0
- data/lib/tap/generator/generators/resource.rb +3 -3
- data/lib/tap/generator/generators/root.rb +25 -38
- data/lib/tap/generator/generators/tap.rb +49 -0
- data/lib/tap/generator/helpers.rb +49 -0
- data/lib/tap/generator/preview.rb +1 -1
- data/lib/tap/generator/version.rb +1 -1
- data/tap-gen.gemspec +67 -0
- data/templates/tap/generator/generators/generator/resource.erb +6 -3
- data/templates/tap/generator/generators/generator/test.erb +3 -3
- data/templates/tap/generator/generators/middleware/test.erb +2 -2
- data/templates/tap/generator/generators/root/README +1 -1
- data/templates/tap/generator/generators/root/gemspec +11 -11
- data/templates/tap/generator/generators/root/tap.yml +0 -0
- data/templates/tap/generator/generators/root/{Rakefile → tapfile} +28 -36
- data/templates/tap/generator/generators/root/test/{tap_test_helper.rb → test_helper.rb} +0 -0
- data/templates/tap/generator/generators/tap/profile.erb +9 -0
- data/templates/tap/generator/generators/tap/tap.erb +3 -0
- data/templates/tap/generator/generators/task/resource.erb +0 -1
- data/templates/tap/generator/generators/task/test.erb +2 -2
- metadata +43 -16
- data/cmd/destroy.rb +0 -27
- data/cmd/generate.rb +0 -27
- data/lib/tap/generator/generators/command.rb +0 -21
- data/templates/tap/generator/generators/command/command.erb +0 -30
- data/templates/tap/generator/generators/root/Rapfile +0 -11
data/History
CHANGED
data/MIT-LICENSE
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Copyright (c) 2009, Regents of the University of Colorado.
|
2
2
|
|
3
|
-
Copyright (c) 2009, Simon Chiang.
|
3
|
+
Copyright (c) 2009-2010, Simon Chiang.
|
4
4
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
data/README
CHANGED
@@ -8,9 +8,6 @@ Generators for Tap.
|
|
8
8
|
|
9
9
|
Provides generators for Tap. Generators are subclasses of Task are therefore
|
10
10
|
easy to configure, subclass, and distribute.
|
11
|
-
{Tap-Generator}[http://tap.rubyforge.org/tap-gen] is a part of the
|
12
|
-
{Tap-Suite}[http://tap.rubyforge.org/tap-suite]. Check out these links for
|
13
|
-
documentation, development, and bug tracking.
|
14
11
|
|
15
12
|
* Website[http://tap.rubyforge.org]
|
16
13
|
* Github[http://github.com/bahuvrihi/tap/tree/master]
|
@@ -23,7 +20,7 @@ Get started:
|
|
23
20
|
% tap generate root sample
|
24
21
|
% cd sample
|
25
22
|
% tap generate task goodnight
|
26
|
-
% tap
|
23
|
+
% tap goodnight moon
|
27
24
|
|
28
25
|
Get some help:
|
29
26
|
|
data/lib/tap/generator/base.rb
CHANGED
@@ -1,8 +1,11 @@
|
|
1
|
-
require 'tap'
|
1
|
+
require 'tap/task'
|
2
|
+
require 'tap/templater'
|
2
3
|
require 'tap/generator/manifest'
|
3
4
|
require 'tap/generator/arguments'
|
4
5
|
require 'tap/generator/generate'
|
5
6
|
require 'tap/generator/destroy'
|
7
|
+
require 'tap/generator/helpers'
|
8
|
+
require 'tap/tasks/list'
|
6
9
|
|
7
10
|
module Tap
|
8
11
|
module Generator
|
@@ -71,40 +74,82 @@ module Tap
|
|
71
74
|
#
|
72
75
|
# :startdoc:::+
|
73
76
|
class Base < Tap::Task
|
74
|
-
|
77
|
+
class << self
|
78
|
+
def parse_as(mixin, argv=ARGV, app=Tap::App.current, &block)
|
79
|
+
if argv.empty?
|
80
|
+
raise "no generator specified"
|
81
|
+
end
|
82
|
+
|
83
|
+
if argv[0] == '--help'
|
84
|
+
desc = mixin.desc
|
85
|
+
lines = ["#{mixin}#{desc.empty? ? '' : ' -- '}#{desc.to_s}"]
|
86
|
+
lines << '-' * 80
|
87
|
+
lines.concat desc.wrap(77, 2, nil).collect {|line| " #{line}"}
|
88
|
+
lines << '-' * 80
|
89
|
+
lines << "usage: tap #{mixin.to_s.underscore} generator *args"
|
90
|
+
lines << ''
|
91
|
+
lines.concat Tasks::List.new(:types => ['generator']).manifest
|
92
|
+
raise lines.join("\n")
|
93
|
+
end
|
94
|
+
|
95
|
+
argv = argv.dup
|
96
|
+
generator = argv.shift
|
97
|
+
argv.unshift mixin
|
98
|
+
app.env.constant(generator, 'generator').parse(argv, app, &block)
|
99
|
+
end
|
100
|
+
|
101
|
+
def build(spec={}, app=Tap::App.current)
|
102
|
+
obj = new(spec['config'] || {}, app)
|
103
|
+
|
104
|
+
if mixin = spec['mixin']
|
105
|
+
obj.extend app.env.constant(mixin)
|
106
|
+
end
|
107
|
+
|
108
|
+
obj
|
109
|
+
end
|
110
|
+
|
111
|
+
def convert_to_spec(parser, args)
|
112
|
+
{
|
113
|
+
'config' => parser.nested_config,
|
114
|
+
'mixin' => args.shift
|
115
|
+
}
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
extend Helpers
|
120
|
+
|
121
|
+
lazy_attr :desc, 'generator'
|
75
122
|
lazy_attr :args, :manifest
|
76
123
|
lazy_register :manifest, Arguments
|
77
124
|
|
78
|
-
|
125
|
+
config_attr :destination_root, nil, # The destination root directory
|
79
126
|
:long => :destination,
|
80
|
-
:short => :d
|
127
|
+
:short => :d do |root|
|
128
|
+
root ||= default_destination_root
|
129
|
+
@destination_root = root.kind_of?(Root) ? root : Root.new(root)
|
130
|
+
end
|
131
|
+
|
132
|
+
config_attr :template_root, nil, # The template root directory
|
133
|
+
:long => :template,
|
134
|
+
:short => :t do |root|
|
135
|
+
root ||= default_template_root
|
136
|
+
@template_root = root.kind_of?(Root) ? root : Root.new(root)
|
137
|
+
end
|
138
|
+
|
81
139
|
config :pretend, false, &c.flag # Run but rollback any changes.
|
82
140
|
config :force, false, &c.flag # Overwrite files that already exist.
|
83
141
|
config :skip, false, &c.flag # Skip files that already exist.
|
84
142
|
|
85
|
-
signal :set # Set this generator to generate or destroy
|
86
|
-
|
87
|
-
# The generator-specific templates directory. By default:
|
88
|
-
# 'templates/path/to/name' for 'lib/path/to/name.rb'
|
89
|
-
attr_accessor :template_dir
|
90
|
-
|
91
143
|
# The IO used to pull prompt inputs (default: $stdin)
|
92
144
|
attr_accessor :prompt_in
|
93
145
|
|
94
146
|
# The IO used to prompt users for input (default: $stdout)
|
95
147
|
attr_accessor :prompt_out
|
96
148
|
|
97
|
-
def initialize(config={}, app=Tap::App.
|
149
|
+
def initialize(config={}, app=Tap::App.current)
|
98
150
|
super
|
99
151
|
@prompt_in = $stdin
|
100
152
|
@prompt_out = $stdout
|
101
|
-
@template_dir = app.env.path(:templates, self.class.to_s.underscore) {|dir| File.directory?(dir) } || File.expand_path("templates/#{self.class.to_s.underscore}")
|
102
|
-
end
|
103
|
-
|
104
|
-
def set(mod)
|
105
|
-
mod = app.env[mod] unless mod.class == Module
|
106
|
-
extend(mod)
|
107
|
-
self
|
108
153
|
end
|
109
154
|
|
110
155
|
# Builds the manifest, then executes the actions of the manifest.
|
@@ -116,7 +161,7 @@ module Tap
|
|
116
161
|
|
117
162
|
iterate(actions) do |action, args, block|
|
118
163
|
send(action, *args, &block)
|
119
|
-
end
|
164
|
+
end.compact
|
120
165
|
end
|
121
166
|
|
122
167
|
# Overridden in subclasses to add actions to the input Manifest.
|
@@ -134,7 +179,7 @@ module Tap
|
|
134
179
|
|
135
180
|
# Constructs a path relative to destination_root.
|
136
181
|
def path(*paths)
|
137
|
-
|
182
|
+
destination_root.path(*paths)
|
138
183
|
end
|
139
184
|
|
140
185
|
# Peforms a directory action (ex generate or destroy). Must be
|
@@ -163,28 +208,28 @@ module Tap
|
|
163
208
|
|
164
209
|
# Makes (or destroys) the target by templating the source using
|
165
210
|
# the specified attributes. Source is expanded relative to
|
166
|
-
#
|
211
|
+
# template_root. Options are passed onto file.
|
167
212
|
def template(target, source, attributes={}, options={})
|
168
|
-
|
169
|
-
|
170
|
-
template_path = File.expand_path(source, template_dir)
|
213
|
+
template_path = template_root.path(source)
|
171
214
|
templater = Templater.new(File.read(template_path), attributes)
|
172
215
|
|
216
|
+
(options[:helpers] || self.class.helpers).each do |helper|
|
217
|
+
templater.extend(helper)
|
218
|
+
end
|
219
|
+
|
173
220
|
file(target, options) do |file|
|
174
221
|
file << templater.build(nil, template_path)
|
175
222
|
end
|
176
223
|
end
|
177
224
|
|
178
|
-
# Yields each source file under
|
179
|
-
# a target path of the source relative to
|
225
|
+
# Yields each source file under template_root to the block, with
|
226
|
+
# a target path of the source relative to template_root.
|
180
227
|
def template_files
|
181
|
-
raise "no template dir is set" unless template_dir
|
182
|
-
|
183
228
|
targets = []
|
184
|
-
|
229
|
+
template_root.glob('**/*').sort.each do |source|
|
185
230
|
next unless File.file?(source)
|
186
231
|
|
187
|
-
target =
|
232
|
+
target = template_root.relative_path(source)
|
188
233
|
yield(source, target)
|
189
234
|
targets << target
|
190
235
|
end
|
@@ -205,10 +250,31 @@ module Tap
|
|
205
250
|
raise NotImplementedError
|
206
251
|
end
|
207
252
|
|
208
|
-
# Logs the action with the relative filepath from
|
253
|
+
# Logs the action with the relative filepath from destination_root to path.
|
209
254
|
def log_relative(action, path)
|
210
|
-
relative_path =
|
211
|
-
log(action, relative_path || path)
|
255
|
+
relative_path = destination_root.relative_path(path)
|
256
|
+
app.log(action, relative_path || path)
|
257
|
+
end
|
258
|
+
|
259
|
+
protected
|
260
|
+
|
261
|
+
def default_destination_root
|
262
|
+
Root.new
|
263
|
+
end
|
264
|
+
|
265
|
+
def default_template_root
|
266
|
+
class_path = self.class.to_s.underscore
|
267
|
+
|
268
|
+
template_dir = nil
|
269
|
+
app.env.path(:templates).each do |dir|
|
270
|
+
path = File.join(dir, class_path)
|
271
|
+
if File.directory?(path)
|
272
|
+
template_dir = path
|
273
|
+
break
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
Root.new(template_dir || "templates/#{class_path}")
|
212
278
|
end
|
213
279
|
end
|
214
280
|
end
|
@@ -1,8 +1,18 @@
|
|
1
|
+
require 'tap/generator/base'
|
2
|
+
|
1
3
|
module Tap
|
2
4
|
module Generator
|
3
5
|
|
4
|
-
#
|
6
|
+
# ::mixin run generators in reverse
|
7
|
+
#
|
8
|
+
# A mixin defining how to run manifest actions in reverse.
|
5
9
|
module Destroy
|
10
|
+
extend Lazydoc::Attributes
|
11
|
+
lazy_attr(:desc, 'mixin')
|
12
|
+
|
13
|
+
def self.parse(argv=ARGV, app=Tap::App.current, &block)
|
14
|
+
Base.parse_as(self, argv, app, &block)
|
15
|
+
end
|
6
16
|
|
7
17
|
# Iterates over the actions in reverse, and collects the results.
|
8
18
|
def iterate(actions)
|
@@ -17,14 +27,15 @@ module Tap
|
|
17
27
|
#
|
18
28
|
# No options currently affect the behavior of this method.
|
19
29
|
def directory(target, options={})
|
20
|
-
target =
|
30
|
+
target = path(target)
|
21
31
|
|
22
32
|
case
|
23
33
|
when !File.exists?(target)
|
24
34
|
log_relative :missing, target
|
25
35
|
when !File.directory?(target)
|
26
36
|
log_relative 'not a directory', target
|
27
|
-
when
|
37
|
+
when target == Dir.pwd
|
38
|
+
when !Root.empty?(target)
|
28
39
|
log_relative 'not empty', target
|
29
40
|
else
|
30
41
|
log_relative :rm, target
|
@@ -40,7 +51,7 @@ module Tap
|
|
40
51
|
#
|
41
52
|
# No options currently affect the behavior of this method.
|
42
53
|
def file(target, options={})
|
43
|
-
target =
|
54
|
+
target = path(target)
|
44
55
|
|
45
56
|
case
|
46
57
|
when File.file?(target)
|
@@ -60,6 +71,11 @@ module Tap
|
|
60
71
|
:destroy
|
61
72
|
end
|
62
73
|
|
74
|
+
def to_spec
|
75
|
+
spec = super
|
76
|
+
spec['mixin'] = 'Tap::Generator::Destroy'
|
77
|
+
spec
|
78
|
+
end
|
63
79
|
end
|
64
80
|
end
|
65
81
|
end
|
@@ -1,19 +1,29 @@
|
|
1
1
|
require 'tempfile'
|
2
|
+
require 'tap/generator/base'
|
2
3
|
|
3
4
|
module Tap
|
4
5
|
module Generator
|
5
6
|
|
6
|
-
#
|
7
|
+
# ::mixin run generators
|
8
|
+
#
|
9
|
+
# A mixin defining how to run manifest actions.
|
7
10
|
module Generate
|
11
|
+
extend Lazydoc::Attributes
|
12
|
+
lazy_attr(:desc, 'mixin')
|
13
|
+
|
14
|
+
def self.parse(argv=ARGV, app=Tap::App.current, &block)
|
15
|
+
Base.parse_as(self, argv, app, &block)
|
16
|
+
end
|
8
17
|
|
9
18
|
# Creates the target directory if it doesn't exist. When pretend is
|
10
19
|
# true, creation is logged but does not actually happen.
|
11
20
|
#
|
12
21
|
# No options currently affect the behavior of this method.
|
13
22
|
def directory(target, options={})
|
14
|
-
target =
|
23
|
+
target = path(target)
|
15
24
|
|
16
25
|
case
|
26
|
+
when target == Dir.pwd
|
17
27
|
when File.exists?(target)
|
18
28
|
log_relative :exists, target
|
19
29
|
else
|
@@ -37,7 +47,7 @@ module Tap
|
|
37
47
|
source_file.close
|
38
48
|
|
39
49
|
source = source_file.path
|
40
|
-
target =
|
50
|
+
target = path(target)
|
41
51
|
|
42
52
|
copy_file = true
|
43
53
|
msg = case
|
@@ -67,6 +77,12 @@ module Tap
|
|
67
77
|
:generate
|
68
78
|
end
|
69
79
|
|
80
|
+
def to_spec
|
81
|
+
spec = super
|
82
|
+
spec['mixin'] = 'Tap::Generator::Generate'
|
83
|
+
spec
|
84
|
+
end
|
85
|
+
|
70
86
|
protected
|
71
87
|
|
72
88
|
# Ask the user interactively whether to force collision.
|
@@ -77,7 +93,7 @@ module Tap
|
|
77
93
|
prompt_out.print "overwrite #{target}? [Ynaiq] "
|
78
94
|
prompt_out.flush
|
79
95
|
case prompt_in.gets.strip
|
80
|
-
when /^y(es)?$/i
|
96
|
+
when /^y(es)?$/i, ''
|
81
97
|
true
|
82
98
|
when /^n(o)?$/i
|
83
99
|
false
|
@@ -72,36 +72,24 @@ module Tap::Generator::Generators
|
|
72
72
|
config :doc, true, &c.switch # Include documentation in the config
|
73
73
|
config :nest, false, &c.switch # Generate nested config files
|
74
74
|
config :blanks, true, &c.switch # Allow generation of empty config files
|
75
|
-
|
76
|
-
|
77
|
-
# Lookup the named resource. Lookup happens through the active Env
|
78
|
-
# instance, specifically using:
|
79
|
-
#
|
80
|
-
# Env.instance[type][name]
|
81
|
-
#
|
82
|
-
# Raises an error if the name cannot be resolved to a resource.
|
83
|
-
def lookup(name)
|
84
|
-
env = Tap::Env.instance
|
85
|
-
env[type][name] or raise "unknown #{type}: #{name}"
|
86
|
-
end
|
87
|
-
|
75
|
+
|
88
76
|
def manifest(m, name, config_name=nil)
|
89
77
|
# setup
|
90
|
-
|
91
|
-
config_name ||=
|
78
|
+
clas = app.env.constant(name)
|
79
|
+
config_name ||= clas.to_s.underscore
|
92
80
|
config_file = path('config', config_name)
|
93
81
|
config_file += ".yml" if File.extname(config_file).empty?
|
94
82
|
|
95
83
|
# generate the dumps
|
96
84
|
dumps = Configurable::Utils.dump_file(
|
97
|
-
|
85
|
+
clas.configurations,
|
98
86
|
config_file,
|
99
87
|
nest,
|
100
88
|
true,
|
101
89
|
&format_block)
|
102
90
|
|
103
91
|
# now put the dumps to the manifest
|
104
|
-
m.directory
|
92
|
+
m.directory 'config'
|
105
93
|
|
106
94
|
dumps.each do |path, content|
|
107
95
|
next if content.empty? && !blanks
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'tap/generator/base'
|
2
|
+
|
3
|
+
module Tap
|
4
|
+
module Generator
|
5
|
+
module Generators
|
6
|
+
# :startdoc::generator generate a tapenv file
|
7
|
+
class Env < Tap::Generator::Base
|
8
|
+
|
9
|
+
config :pattern, '**/*.rb', &c.string # the glob pattern under each path
|
10
|
+
config :lib, 'lib', &c.string # the lib dir
|
11
|
+
config :pathfile, 'tap.yml', &c.string # the pathfile
|
12
|
+
config :register, true, &c.switch # register resource paths
|
13
|
+
config :load_paths, true, &c.switch # set load paths
|
14
|
+
config :set, true, &c.switch # set constants
|
15
|
+
config :gems, [],
|
16
|
+
:long => :gem,
|
17
|
+
&c.list # gems to add
|
18
|
+
config :tapenv, 'tapenv', &c.string # the tapenv file name
|
19
|
+
config :use_organize, true,
|
20
|
+
:long => :organize,
|
21
|
+
&c.switch # organize results a bit
|
22
|
+
|
23
|
+
def manifest(m, *paths)
|
24
|
+
lines = []
|
25
|
+
paths.each do |path|
|
26
|
+
lines.concat Tap::Env.generate(options(path))
|
27
|
+
end
|
28
|
+
|
29
|
+
gem_options.each do |options|
|
30
|
+
lines.concat Tap::Env.generate(options)
|
31
|
+
end
|
32
|
+
|
33
|
+
lines.uniq!
|
34
|
+
|
35
|
+
if use_organize
|
36
|
+
lines = organize(lines)
|
37
|
+
end
|
38
|
+
|
39
|
+
m.file(tapenv) do |io|
|
40
|
+
lines.each {|line| io.puts line }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def options(path)
|
45
|
+
config.to_hash.merge(:dir => path)
|
46
|
+
end
|
47
|
+
|
48
|
+
def gem_options
|
49
|
+
specs = []
|
50
|
+
gems.each do |gem_name|
|
51
|
+
gem_name =~ /\A(.*?)([\s<>=~].+)?\z/
|
52
|
+
dependency = Gem::Dependency.new($1, $2)
|
53
|
+
collect_specs(dependency, specs)
|
54
|
+
end
|
55
|
+
|
56
|
+
most_recent_specs = {}
|
57
|
+
specs.sort_by do |spec|
|
58
|
+
spec.version
|
59
|
+
end.reverse_each do |spec|
|
60
|
+
most_recent_specs[spec.name] ||= spec
|
61
|
+
end
|
62
|
+
|
63
|
+
most_recent_specs.values.collect do |spec|
|
64
|
+
pathfile = File.join(spec.full_gem_path, 'tap.yml')
|
65
|
+
map = Tap::Env::Path.load(pathfile)
|
66
|
+
map.merge!('lib' => spec.require_paths)
|
67
|
+
|
68
|
+
{
|
69
|
+
:dir => spec.full_gem_path,
|
70
|
+
:lib => 'lib',
|
71
|
+
:map => map,
|
72
|
+
:set => File.exists?(pathfile)
|
73
|
+
}
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def organize(lines)
|
78
|
+
sets, everything_else = lines.partition {|line| line.index('set ') == 0 }
|
79
|
+
sets.collect! {|set| set.split(' ', 4) }
|
80
|
+
|
81
|
+
cmax = sets.collect {|set| set[1].length }.max
|
82
|
+
rmax = sets.collect {|set| set[2].length }.max
|
83
|
+
format = "%s %-#{cmax}s %-#{rmax}s %s"
|
84
|
+
sets.collect! {|set| format % set }
|
85
|
+
|
86
|
+
lines = everything_else + sets
|
87
|
+
lines.sort!
|
88
|
+
lines
|
89
|
+
end
|
90
|
+
|
91
|
+
protected
|
92
|
+
|
93
|
+
def collect_specs(dependency, specs) # :nodoc:
|
94
|
+
Gem.source_index.search(dependency).each do |spec|
|
95
|
+
unless specs.include?(spec)
|
96
|
+
specs << spec
|
97
|
+
spec.runtime_dependencies.each do |dep|
|
98
|
+
collect_specs(dep, specs)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|