origen 0.38.0 → 0.40.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/origen +1 -236
- data/config/application.rb +10 -1
- data/config/version.rb +1 -1
- data/lib/origen/{boot_api.rb → boot/api.rb} +2 -2
- data/lib/origen/boot/app.rb +324 -0
- data/lib/origen/boot.rb +287 -0
- data/lib/origen/commands/archive.rb +175 -0
- data/lib/origen/commands/extract.rb +43 -0
- data/lib/origen/commands/new.rb +33 -23
- data/lib/origen/commands.rb +4 -1
- data/lib/origen/commands_global.rb +3 -2
- data/lib/origen/operating_systems.rb +4 -0
- data/lib/origen/revision_control.rb +1 -1
- data/lib/origen/site_config.rb +4 -1
- data/lib/origen.rb +3 -2
- data/origen_app_generators/Gemfile +16 -0
- data/origen_app_generators/Gemfile.lock +147 -0
- data/origen_app_generators/LICENSE +21 -0
- data/origen_app_generators/README.md +368 -0
- data/origen_app_generators/Rakefile +10 -0
- data/origen_app_generators/bin/boot.rb +37 -0
- data/{bin → origen_app_generators/bin}/fix_my_workspace +0 -0
- data/origen_app_generators/config/application.rb +153 -0
- data/origen_app_generators/config/boot.rb +1 -0
- data/origen_app_generators/config/commands.rb +63 -0
- data/origen_app_generators/config/shared_commands.rb +172 -0
- data/origen_app_generators/config/version.rb +8 -0
- data/origen_app_generators/doc/history +213 -0
- data/origen_app_generators/lib/origen_app_generators/application.rb +62 -0
- data/origen_app_generators/lib/origen_app_generators/base.rb +231 -0
- data/origen_app_generators/lib/origen_app_generators/empty_application.rb +15 -0
- data/origen_app_generators/lib/origen_app_generators/empty_plugin.rb +15 -0
- data/origen_app_generators/lib/origen_app_generators/new.rb +162 -0
- data/origen_app_generators/lib/origen_app_generators/origen_infrastructure/app_generator_plugin.rb +109 -0
- data/origen_app_generators/lib/origen_app_generators/plugin.rb +58 -0
- data/origen_app_generators/lib/origen_app_generators/sub_block_parser.rb +81 -0
- data/origen_app_generators/lib/origen_app_generators/test_engineering/stand_alone_application.rb +236 -0
- data/origen_app_generators/lib/origen_app_generators/test_engineering/test_block.rb +162 -0
- data/origen_app_generators/lib/origen_app_generators.rb +123 -0
- data/origen_app_generators/lib/tasks/app_generators.rake +6 -0
- data/origen_app_generators/lib/tasks/new_app_tests.rake +8 -0
- data/origen_app_generators/origen_app_generators.gemspec +33 -0
- data/origen_app_generators/spec/spec_helper.rb +49 -0
- data/origen_app_generators/spec/sub_block_spec.rb +36 -0
- data/origen_app_generators/target/debug.rb +8 -0
- data/origen_app_generators/target/default.rb +8 -0
- data/origen_app_generators/target/production.rb +0 -0
- data/origen_app_generators/templates/app_generators/application/Gemfile +19 -0
- data/origen_app_generators/templates/app_generators/application/Rakefile +7 -0
- data/origen_app_generators/templates/app_generators/application/config/application.rb +125 -0
- data/origen_app_generators/templates/app_generators/application/config/boot.rb +4 -0
- data/origen_app_generators/templates/app_generators/application/config/commands.rb +79 -0
- data/origen_app_generators/templates/app_generators/application/config/maillist_dev.txt +4 -0
- data/origen_app_generators/templates/app_generators/application/config/maillist_prod.txt +3 -0
- data/origen_app_generators/templates/app_generators/application/config/version.rb +8 -0
- data/origen_app_generators/templates/app_generators/application/doc/history +0 -0
- data/origen_app_generators/templates/app_generators/application/dot_keep +0 -0
- data/origen_app_generators/templates/app_generators/application/lib/app.rake +6 -0
- data/origen_app_generators/templates/app_generators/application/lib/module.rb +22 -0
- data/origen_app_generators/templates/app_generators/application/lib/top_level.rb +12 -0
- data/origen_app_generators/templates/app_generators/application/origen_core_session +2 -0
- data/origen_app_generators/templates/app_generators/application/spec/spec_helper.rb +44 -0
- data/origen_app_generators/templates/app_generators/application/target/debug.rb +8 -0
- data/origen_app_generators/templates/app_generators/application/target/default.rb +1 -0
- data/origen_app_generators/templates/app_generators/application/target/production.rb +4 -0
- data/origen_app_generators/templates/app_generators/application/templates/web/index.md.erb +19 -0
- data/origen_app_generators/templates/app_generators/application/templates/web/layouts/_basic.html.erb +13 -0
- data/origen_app_generators/templates/app_generators/application/templates/web/partials/_navbar.html.erb +20 -0
- data/origen_app_generators/templates/app_generators/application/templates/web/release_notes.md.erb +5 -0
- data/origen_app_generators/templates/app_generators/new/generator.rb +102 -0
- data/origen_app_generators/templates/app_generators/new/info.md.erb +9 -0
- data/origen_app_generators/templates/app_generators/origen_infrastructure/app_generator_plugin/config/load_generators.rb +6 -0
- data/origen_app_generators/templates/app_generators/origen_infrastructure/app_generator_plugin/lib/application.rb +54 -0
- data/origen_app_generators/templates/app_generators/origen_infrastructure/app_generator_plugin/lib/base.rb +55 -0
- data/origen_app_generators/templates/app_generators/origen_infrastructure/app_generator_plugin/lib/module.rb +28 -0
- data/origen_app_generators/templates/app_generators/origen_infrastructure/app_generator_plugin/lib/plugin.rb +64 -0
- data/origen_app_generators/templates/app_generators/plugin/Gemfile +26 -0
- data/origen_app_generators/templates/app_generators/plugin/Rakefile +10 -0
- data/origen_app_generators/templates/app_generators/plugin/config/boot.rb +24 -0
- data/origen_app_generators/templates/app_generators/plugin/gemspec.rb +42 -0
- data/origen_app_generators/templates/app_generators/plugin/lib/README +4 -0
- data/origen_app_generators/templates/app_generators/plugin/lib_dev/README +5 -0
- data/origen_app_generators/templates/app_generators/plugin/templates/web/index.md.erb +37 -0
- data/origen_app_generators/templates/app_generators/plugin/templates/web/partials/_navbar_external.html.erb +20 -0
- data/origen_app_generators/templates/app_generators/plugin/templates/web/partials/_navbar_internal.html.erb +20 -0
- data/origen_app_generators/templates/app_generators/test_engineering/stand_alone_application/Gemfile +23 -0
- data/origen_app_generators/templates/app_generators/test_engineering/stand_alone_application/environment/j750.rb +1 -0
- data/origen_app_generators/templates/app_generators/test_engineering/stand_alone_application/environment/jlink.rb +1 -0
- data/origen_app_generators/templates/app_generators/test_engineering/stand_alone_application/environment/uflex.rb +1 -0
- data/origen_app_generators/templates/app_generators/test_engineering/stand_alone_application/environment/v93k.rb +1 -0
- data/origen_app_generators/templates/app_generators/test_engineering/stand_alone_application/lib/ip_block.rb +23 -0
- data/origen_app_generators/templates/app_generators/test_engineering/stand_alone_application/lib/ip_block_controller.rb +5 -0
- data/origen_app_generators/templates/app_generators/test_engineering/stand_alone_application/lib/top_level.rb +33 -0
- data/origen_app_generators/templates/app_generators/test_engineering/stand_alone_application/lib/top_level_controller.rb +21 -0
- data/origen_app_generators/templates/app_generators/test_engineering/stand_alone_application/pattern/example.rb +4 -0
- data/origen_app_generators/templates/app_generators/test_engineering/stand_alone_application/target/top_level.rb +4 -0
- data/origen_app_generators/templates/app_generators/test_engineering/test_block/environment/j750.rb +2 -0
- data/origen_app_generators/templates/app_generators/test_engineering/test_block/environment/ultraflex.rb +2 -0
- data/origen_app_generators/templates/app_generators/test_engineering/test_block/environment/v93k.rb +2 -0
- data/origen_app_generators/templates/app_generators/test_engineering/test_block/lib/controller.rb +12 -0
- data/origen_app_generators/templates/app_generators/test_engineering/test_block/lib/interface.rb +21 -0
- data/origen_app_generators/templates/app_generators/test_engineering/test_block/lib/model.rb +18 -0
- data/origen_app_generators/templates/app_generators/test_engineering/test_block/lib_dev/dut.rb +27 -0
- data/origen_app_generators/templates/app_generators/test_engineering/test_block/lib_dev/dut_controller.rb +26 -0
- data/origen_app_generators/templates/app_generators/test_engineering/test_block/pattern/example.rb +5 -0
- data/origen_app_generators/templates/app_generators/test_engineering/test_block/program/prb1.rb +11 -0
- data/origen_app_generators/templates/app_generators/test_engineering/test_block/target/default.rb +2 -0
- data/origen_site_config.yml +13 -2
- data/templates/git/gitignore.erb +0 -1
- metadata +99 -4
@@ -0,0 +1,231 @@
|
|
1
|
+
module OrigenAppGenerators
|
2
|
+
# This is the base generator used by all generators in this application
|
3
|
+
class Base < Origen::CodeGenerators::Base
|
4
|
+
include Origen::Utility::InputCapture
|
5
|
+
|
6
|
+
require 'gems'
|
7
|
+
|
8
|
+
def set_source_paths
|
9
|
+
# The base Origen generator puts the Origen core directory on the source path, in retrospect this
|
10
|
+
# was a bad idea and makes for hard to debug errors if an app generator resolves a template from
|
11
|
+
# outside of this app.
|
12
|
+
# So to keep things sane remove any inherited source paths.
|
13
|
+
self.class.source_paths.pop until self.class.source_paths.empty?
|
14
|
+
klass = self.class
|
15
|
+
|
16
|
+
until klass == OrigenAppGenerators::Base
|
17
|
+
if template_dir = OrigenAppGenerators.template_dirs[klass]
|
18
|
+
dir = []
|
19
|
+
last_class = nil
|
20
|
+
until klass.to_s =~ /^OrigenAppGenerators/
|
21
|
+
dir << "#{template_dir}/#{class_dir(klass)}"
|
22
|
+
last_class = klass
|
23
|
+
klass = klass.superclass
|
24
|
+
end
|
25
|
+
dir << "#{template_dir}/base"
|
26
|
+
klass = last_class
|
27
|
+
else
|
28
|
+
dir = "#{Origen.root!}/templates/app_generators/#{class_dir(klass)}"
|
29
|
+
end
|
30
|
+
Array(dir).each do |dir|
|
31
|
+
self.class.source_paths << dir if File.exist?(dir) && !self.class.source_paths.include?(dir)
|
32
|
+
end
|
33
|
+
klass = klass.superclass
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Just makes the type (:plugin or :application) available to all templates
|
38
|
+
def set_type
|
39
|
+
@type = type
|
40
|
+
end
|
41
|
+
|
42
|
+
def get_common_user_input
|
43
|
+
get_name_and_namespace
|
44
|
+
end
|
45
|
+
|
46
|
+
def get_lastest_origen_version
|
47
|
+
@latest_origen_version ||= begin
|
48
|
+
(Gems.info 'origen')['version']
|
49
|
+
rescue
|
50
|
+
# If the above fails, e.g. due to an SSL error in the runtime environment, try to fetch the
|
51
|
+
# latest Origen version from the Origen website, before finally falling back to the version
|
52
|
+
# we are currently running if all else fails
|
53
|
+
begin
|
54
|
+
require 'httparty'
|
55
|
+
response = HTTParty.get('http://origen-sdk.org/origen/release_notes/')
|
56
|
+
version = Origen::VersionString.new(response.body.match(/Tag: v(\d+\.\d+.\d+)</).to_a.last)
|
57
|
+
if version.valid?
|
58
|
+
version
|
59
|
+
else
|
60
|
+
fail "Can't get the latest version!"
|
61
|
+
end
|
62
|
+
rescue
|
63
|
+
Origen.version
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
protected
|
69
|
+
|
70
|
+
def class_dir(klass)
|
71
|
+
names = klass.to_s.split('::')
|
72
|
+
names.shift
|
73
|
+
names.map(&:underscore).join('/')
|
74
|
+
end
|
75
|
+
|
76
|
+
# def application_class?(klass)
|
77
|
+
# until klass == OrigenAppGenerators::Base
|
78
|
+
# end
|
79
|
+
|
80
|
+
def debugger
|
81
|
+
require 'byebug'
|
82
|
+
byebug # rubocop:disable Lint/Debugger
|
83
|
+
end
|
84
|
+
|
85
|
+
def plugin?
|
86
|
+
type == :plugin
|
87
|
+
end
|
88
|
+
|
89
|
+
def application?
|
90
|
+
!plugin?
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.title
|
94
|
+
desc.sub(/^An? /, '').titleize
|
95
|
+
end
|
96
|
+
|
97
|
+
# Calling this will compile all files in filelist against the current instance
|
98
|
+
# variable values
|
99
|
+
def build_filelist
|
100
|
+
symlink_cmds = []
|
101
|
+
self.destination_root = args.first
|
102
|
+
filelist.each do |_name, file|
|
103
|
+
if file[:type] == :symlink
|
104
|
+
if Origen.running_on_windows?
|
105
|
+
dest = Pathname.new("#{destination_root}/#{file[:dest]}")
|
106
|
+
source = dest.dirname.to_s + "/#{file[:source]}"
|
107
|
+
symlink_cmds << "call mklink /h #{dest.to_s.gsub('/', '\\')} #{source.to_s.gsub('/', '\\')}"
|
108
|
+
else
|
109
|
+
create_link file[:dest], file[:source]
|
110
|
+
end
|
111
|
+
elsif file[:type] == :dir || file[:type] == :directory
|
112
|
+
if file[:copy]
|
113
|
+
if (file.key? :dest) && (file.key? :source)
|
114
|
+
directory(file[:source], file[:dest])
|
115
|
+
else
|
116
|
+
directory(file[:dest] || file[:source])
|
117
|
+
end
|
118
|
+
elsif file[:nokeep]
|
119
|
+
empty_directory(file[:dest] || file[:source])
|
120
|
+
else
|
121
|
+
copy_file('dot_keep', "#{file[:dest]}/.keep")
|
122
|
+
end
|
123
|
+
else
|
124
|
+
dest = file[:dest] || file[:source]
|
125
|
+
if file[:copy] || dest =~ /.erb$/
|
126
|
+
copy_file(file[:source], dest)
|
127
|
+
else
|
128
|
+
@options = file[:options] || {}
|
129
|
+
template(file[:source], dest)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
symlink_cmds.each { |cmd| system(cmd) }
|
134
|
+
end
|
135
|
+
|
136
|
+
# Convenience method that is equivalent to calling get_name and then get_namespace
|
137
|
+
def get_name_and_namespace
|
138
|
+
get_name
|
139
|
+
get_namespace
|
140
|
+
end
|
141
|
+
|
142
|
+
# Prompts the user to confirm or enter the Ruby namespace to be used in the app.
|
143
|
+
#
|
144
|
+
# If @name is already defined a proposal will be generated from that, alternatively a proposal
|
145
|
+
# can be supplied. If not proposal is resolved the user will be prompted to input from scratch.
|
146
|
+
def get_namespace(proposal = nil)
|
147
|
+
puts
|
148
|
+
puts "SELECT YOUR #{type.to_s.upcase}'S NAMESPACE"
|
149
|
+
puts
|
150
|
+
puts "All #{type} code needs to reside in a unique namespace, this prevents naming collisions with 3rd party plugins."
|
151
|
+
puts 'By Ruby conventions, this must start with a capital letter and should ideally be CamelCased and not use underscores.'
|
152
|
+
# puts 'Some examples:: C40TFSNVMTester, CAPIOrigen, LS2080, ApacheOrigen'
|
153
|
+
[@namespace_advice].each { |l| puts l } if @namespace_advice
|
154
|
+
puts
|
155
|
+
if !proposal && @name
|
156
|
+
proposal = @name.to_s.camelize
|
157
|
+
end
|
158
|
+
proposal = nil if proposal.length < 3
|
159
|
+
|
160
|
+
valid = false
|
161
|
+
until valid
|
162
|
+
@namespace = get_text(single: true, default: proposal)
|
163
|
+
proposal = nil
|
164
|
+
unless @namespace.empty?
|
165
|
+
if @namespace.length >= 3
|
166
|
+
valid = valid_constant?(@namespace)
|
167
|
+
end
|
168
|
+
unless valid
|
169
|
+
puts 'That namespace is not valid :-('
|
170
|
+
puts
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
@namespace
|
175
|
+
end
|
176
|
+
|
177
|
+
# Returns true if the given string can be converted to a valid Ruby constant and one that
|
178
|
+
# does not already exist within the scope of this application and Origen Core
|
179
|
+
def valid_constant?(string)
|
180
|
+
valid = false
|
181
|
+
# Try and convert this to a constant to test for validity, this will also screen things
|
182
|
+
# like Origen since that will not trigger an error
|
183
|
+
begin
|
184
|
+
string.constantize
|
185
|
+
rescue NameError => e
|
186
|
+
if e.message =~ /^uninitialized constant/
|
187
|
+
valid = true
|
188
|
+
end
|
189
|
+
else
|
190
|
+
# Something else is wrong with it
|
191
|
+
end
|
192
|
+
valid
|
193
|
+
end
|
194
|
+
|
195
|
+
# Prompts the user to input a name for the new application, this will be screened to ensure
|
196
|
+
# that it can cleanly cast to a symbol for use in Origen.
|
197
|
+
#
|
198
|
+
# This should be unique within the whole Origen ecosystem, in future this method will be enhanced
|
199
|
+
# to check with the Origen server which will in future maintain a database of known app names.
|
200
|
+
#
|
201
|
+
# The final name is returned at the end and assigned to variable @name for use in templates.
|
202
|
+
def get_name
|
203
|
+
proposal = args.first.symbolize.to_s
|
204
|
+
proposal = nil if proposal.length < 3
|
205
|
+
puts
|
206
|
+
puts "WHAT DO YOU WANT TO CALL YOUR NEW #{type.to_s.upcase}?"
|
207
|
+
puts
|
208
|
+
puts "This should be lowercased and underscored and will be used to uniquely identify your #{type} within the Origen ecosystem."
|
209
|
+
[@name_advice].each { |l| puts l } if @name_advice
|
210
|
+
puts
|
211
|
+
valid = false
|
212
|
+
until valid
|
213
|
+
name = get_text(single: true, default: proposal)
|
214
|
+
proposal = nil
|
215
|
+
unless name.empty?
|
216
|
+
if name == name.symbolize.to_s
|
217
|
+
if name.symbolize.to_s.length >= 3
|
218
|
+
valid = true
|
219
|
+
@name = name
|
220
|
+
end
|
221
|
+
else
|
222
|
+
puts
|
223
|
+
puts 'That name is not valid, how about this?'
|
224
|
+
proposal = name.symbolize.to_s
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
@name
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module OrigenAppGenerators
|
2
|
+
# Generates a generic application shell
|
3
|
+
class EmptyApplication < Application
|
4
|
+
# Any methods that are not protected will get invoked in the order they are
|
5
|
+
# defined when the generator is run
|
6
|
+
|
7
|
+
def generate_files
|
8
|
+
build_filelist
|
9
|
+
end
|
10
|
+
|
11
|
+
def conclude
|
12
|
+
puts "New app created at: #{destination_root}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module OrigenAppGenerators
|
2
|
+
# Generates a generic plugin shell
|
3
|
+
class EmptyPlugin < Plugin
|
4
|
+
# Any methods that are not protected will get invoked in the order they are
|
5
|
+
# defined when the generator is run
|
6
|
+
|
7
|
+
def generate_files
|
8
|
+
build_filelist
|
9
|
+
end
|
10
|
+
|
11
|
+
def conclude
|
12
|
+
puts "New app created at: #{destination_root}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
module OrigenAppGenerators
|
2
|
+
class New < Base
|
3
|
+
include Origen::Utility::InputCapture
|
4
|
+
|
5
|
+
desc 'Creates a new application generator within this application'
|
6
|
+
|
7
|
+
# Naming of this method is important here to override the default user input which
|
8
|
+
# does not apply to this generator
|
9
|
+
def get_common_user_input
|
10
|
+
get_domain
|
11
|
+
get_name
|
12
|
+
get_type
|
13
|
+
get_summary
|
14
|
+
@namespace = Origen.app.namespace
|
15
|
+
end
|
16
|
+
|
17
|
+
def set_type
|
18
|
+
# Type not applicable in for this generator
|
19
|
+
end
|
20
|
+
|
21
|
+
def generate_files
|
22
|
+
build_filelist
|
23
|
+
end
|
24
|
+
|
25
|
+
def enable
|
26
|
+
available = Origen.app.namespace.constantize::AVAILABLE
|
27
|
+
test_inputs = Origen.app.namespace.constantize::TEST_INPUTS
|
28
|
+
|
29
|
+
# **** Add require line ****
|
30
|
+
module_declaration = /\nmodule #{Origen.app.namespace}/
|
31
|
+
inject_into_file "lib/#{Origen.app.name}.rb", "require '#{Origen.app.name}/#{@domain_namespace.underscore}/#{@classname.underscore}'\n",
|
32
|
+
before: module_declaration
|
33
|
+
|
34
|
+
# **** Add to the AVAILABLE hash ****
|
35
|
+
if available[@domain_summary]
|
36
|
+
existing_domain = /\s*('|")#{@domain_summary}('|") => \[\s*\n/
|
37
|
+
inject_into_file "lib/#{Origen.app.name}.rb", " #{Origen.app.namespace}::#{@domain_namespace}::#{@classname},\n",
|
38
|
+
after: existing_domain
|
39
|
+
else
|
40
|
+
new_domain = <<-END
|
41
|
+
'#{@domain_summary}' => [
|
42
|
+
#{Origen.app.namespace}::#{@domain_namespace}::#{@classname},
|
43
|
+
],
|
44
|
+
END
|
45
|
+
available_hash = /AVAILABLE = {\s*\n/
|
46
|
+
inject_into_file "lib/#{Origen.app.name}.rb", new_domain, after: available_hash
|
47
|
+
end
|
48
|
+
|
49
|
+
# **** Add a starter set of test inputs ****
|
50
|
+
# First work out what the selection numbers will be for the new generator
|
51
|
+
if available[@domain_summary]
|
52
|
+
first = available.size - available.find_index { |k, _| k == @domain_summary }
|
53
|
+
second = available[@domain_summary].size
|
54
|
+
else
|
55
|
+
first = available.size + 1
|
56
|
+
second = 0
|
57
|
+
end
|
58
|
+
inputs = "\n # #{test_inputs.size} - #{@domain_namespace}::#{@classname}\n"
|
59
|
+
if @parentclass == 'Plugin'
|
60
|
+
inputs += " ['#{first}', '#{second}', :default, :default, 'A cool plugin', 'yes', :default]"
|
61
|
+
else
|
62
|
+
inputs += " ['#{first}', '#{second}', :default, :default, :default]"
|
63
|
+
end
|
64
|
+
inputs = ",#{inputs}" unless test_inputs.empty?
|
65
|
+
end_of_test_inputs = /\n\s*\]\s*#\s*END_OF_TEST_INPUTS/
|
66
|
+
inject_into_file "lib/#{Origen.app.name}.rb", inputs, before: end_of_test_inputs
|
67
|
+
end
|
68
|
+
|
69
|
+
# Can't compile this as contains some final ERB, so substitute instead
|
70
|
+
# def customize_doc_page
|
71
|
+
# file = filelist[:doc_info][:dest]
|
72
|
+
# gsub_file file, 'TITLE_GOES_HERE', @title
|
73
|
+
# if @type == :plugin
|
74
|
+
# gsub_file file, 'INTRO_GOES_HERE', "This generates a customized version of the [Generic Plugin](<%= path 'origen_app_generators/plugin' %>)."
|
75
|
+
# else
|
76
|
+
# gsub_file file, 'INTRO_GOES_HERE', "This generates a customized version of the [Generic Application](<%= path 'origen_app_generators/application' %>)."
|
77
|
+
# end
|
78
|
+
# end
|
79
|
+
|
80
|
+
def conclude
|
81
|
+
system "origen lint #{Origen.root}/lib/#{Origen.app.name}.rb"
|
82
|
+
puts
|
83
|
+
puts "New generator created at: #{filelist[:generator][:dest]}"
|
84
|
+
puts
|
85
|
+
puts "Create any template files you need for this generator in: #{filelist[:templates_dir][:dest]}"
|
86
|
+
puts
|
87
|
+
# puts "Before you go add some documentation about what this generates to: templates/web/origen_app_generators/origen_app_generators/#{@domain_namespace.underscore}/#{@classname.underscore}.md.erb"
|
88
|
+
# puts
|
89
|
+
end
|
90
|
+
|
91
|
+
protected
|
92
|
+
|
93
|
+
def get_summary
|
94
|
+
puts
|
95
|
+
puts 'DESCRIBE YOUR NEW GENERATOR IN A FEW WORDS'
|
96
|
+
puts
|
97
|
+
@summary = get_text(single: true)
|
98
|
+
@title = @summary.sub(/^An? /, '').titleize
|
99
|
+
end
|
100
|
+
|
101
|
+
def get_type
|
102
|
+
puts
|
103
|
+
puts 'WILL YOUR TEMPLATE GENERATE A PLUGIN OR A TOP-LEVEL APPLICATION?'
|
104
|
+
puts
|
105
|
+
type = get_text(single: true, accept: %w(application plugin)).downcase
|
106
|
+
@parentclass = type.capitalize
|
107
|
+
end
|
108
|
+
|
109
|
+
def get_name
|
110
|
+
puts
|
111
|
+
puts 'GIVE YOUR NEW GENERATOR CLASS A NAME'
|
112
|
+
puts
|
113
|
+
puts 'Your new generator needs a class name, this should be reasonably descriptive although it will not be displayed to end users'
|
114
|
+
puts 'Some examples: GenericTestBlock, IPBlock, MPGBOMApp'
|
115
|
+
puts
|
116
|
+
valid = false
|
117
|
+
until valid
|
118
|
+
@classname = get_text(single: true).split('::').last
|
119
|
+
unless @classname.empty?
|
120
|
+
if @classname.length >= 3
|
121
|
+
valid = valid_constant?("#{Origen.app.namespace}::#{@domain_namespace}::#{@classname}")
|
122
|
+
end
|
123
|
+
unless valid
|
124
|
+
puts 'That class name is not valid :-('
|
125
|
+
puts
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
@classname
|
130
|
+
end
|
131
|
+
|
132
|
+
def get_domain
|
133
|
+
puts
|
134
|
+
puts 'WHAT APPLICATION DOMAIN WILL YOUR NEW APP TEMPLATE APPLY TO?'
|
135
|
+
puts
|
136
|
+
puts "Enter something like 'Test Engineering', 'Design', etc."
|
137
|
+
puts
|
138
|
+
domain = get_text(single: true)
|
139
|
+
domain = domain.split(' ').map do |word|
|
140
|
+
# Ensure all first letters capitalized, but make sure something like
|
141
|
+
# 'NVM' remains 'NVM' and not 'Nvm'
|
142
|
+
letters = word.split('')
|
143
|
+
letters.first.upcase!
|
144
|
+
letters.join
|
145
|
+
end.join(' ')
|
146
|
+
|
147
|
+
@domain_summary = domain
|
148
|
+
@domain_namespace = @domain_summary.gsub(' ', '')
|
149
|
+
end
|
150
|
+
|
151
|
+
def filelist
|
152
|
+
@filelist ||= {
|
153
|
+
generator: { source: 'generator.rb',
|
154
|
+
dest: "lib/#{Origen.app.name}/#{@domain_namespace.underscore}/#{@classname.underscore}.rb" },
|
155
|
+
templates_dir: { dest: "templates/app_generators/#{@domain_namespace.underscore}/#{@classname.underscore}",
|
156
|
+
type: :directory },
|
157
|
+
# doc_info: { source: 'info.md.erb',
|
158
|
+
# dest: "templates/web/#{Origen.app.name}/#{@domain_namespace.underscore}/#{@classname.underscore}.md.erb" }
|
159
|
+
}
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
data/origen_app_generators/lib/origen_app_generators/origen_infrastructure/app_generator_plugin.rb
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
module OrigenAppGenerators
|
2
|
+
module OrigenInfrastructure
|
3
|
+
# Generates a generic application shell
|
4
|
+
class AppGeneratorPlugin < Plugin
|
5
|
+
desc "A plugin to make your own application templates available through the 'origen new' command"
|
6
|
+
|
7
|
+
def initialize(*args)
|
8
|
+
@audience = :internal
|
9
|
+
@validate_release_tests = ['origen app_gen:test --regression']
|
10
|
+
super
|
11
|
+
end
|
12
|
+
|
13
|
+
# Any methods that are not protected will get invoked in the order that they are
|
14
|
+
# defined when the generator is run, method naming is irrelevant unless you want
|
15
|
+
# to override a method that is defined by the parent class
|
16
|
+
|
17
|
+
def get_user_input
|
18
|
+
# The methods to get the common user input that applies to all applications will
|
19
|
+
# get called at the start automatically, you have a chance here to ask any additional
|
20
|
+
# questions that are specific to the type of application being generated
|
21
|
+
end
|
22
|
+
|
23
|
+
def generate_files
|
24
|
+
@runtime_dependencies = [
|
25
|
+
['origen_app_generators', ">= #{Origen.app!.version}"]
|
26
|
+
]
|
27
|
+
@post_runtime_dependency_comments = [
|
28
|
+
'DO NOT ADD ANY ADDITIONAL RUNTIME DEPENDENCIES HERE, WHEN THESE GENERATORS',
|
29
|
+
'ARE INVOKED TO GENERATE A NEW APPLICATION IT WILL NOT BE LAUNCHED FROM WITHIN',
|
30
|
+
'A BUNDLED ENVIRONMENT.',
|
31
|
+
'',
|
32
|
+
'THEREFORE GENERATORS MUST NOT RELY ON ANY 3RD PARTY GEMS THAT ARE NOT',
|
33
|
+
'PRESENT AS PART OF A STANDARD ORIGEN INSTALLATION - I.E. YOU CAN ONLY RELY',
|
34
|
+
'ON THE GEMS THAT ORIGEN ITSELF DEPENDS ON.'
|
35
|
+
]
|
36
|
+
# Calling this will build all files, directories and symlinks contained in the
|
37
|
+
# hash returned by the filelist method
|
38
|
+
build_filelist
|
39
|
+
end
|
40
|
+
|
41
|
+
def modify_files
|
42
|
+
# If you want to modify any of the generated files you can do so now, you have access
|
43
|
+
# to all of the Thor Action methods described here:
|
44
|
+
# http://www.rubydoc.info/github/wycats/thor/Thor/Actions
|
45
|
+
# See the enable method in lib/app_generators/new.rb for some examples of using these.
|
46
|
+
end
|
47
|
+
|
48
|
+
def conclude
|
49
|
+
# Print out anything you think the user should know about their new application at the end
|
50
|
+
puts "New app created at: #{destination_root}"
|
51
|
+
puts
|
52
|
+
puts 'Create your first generator by running this command within your new app:'
|
53
|
+
puts ' origen app_gen:new'
|
54
|
+
puts
|
55
|
+
end
|
56
|
+
|
57
|
+
protected
|
58
|
+
|
59
|
+
# Defines the filelist for the generator, the default list is inherited from the
|
60
|
+
# parent class (Plugin).
|
61
|
+
# The filelist can contain references to generate files, directories or symlinks in the
|
62
|
+
# new application.
|
63
|
+
#
|
64
|
+
# Generally to make your generator more maintainable try and re-use as much as possible
|
65
|
+
# from the parent generator, this means that your generator will automatically stay up
|
66
|
+
# to date with the latest conventions
|
67
|
+
#
|
68
|
+
# The master templates live in templates/app_generators/plugin, but
|
69
|
+
# DO NOT MODIFY THESE FILES DIRECTLY.
|
70
|
+
# Either add or remove things post-generation in the modify_files method or copy the
|
71
|
+
# master file to the equivalent sub-directory of templates/app_generators/origen_infrastructure_engineering/app_generator_plugin
|
72
|
+
# which will override the version in the master directory.
|
73
|
+
#
|
74
|
+
# Additional files can be added or removed from the filelist as shown below.
|
75
|
+
def filelist
|
76
|
+
@filelist ||= begin
|
77
|
+
list = super # Always pick up the parent list
|
78
|
+
# Example of how to remove a file from the parent list
|
79
|
+
# list.delete(:web_doc_layout)
|
80
|
+
list.delete(:lib_readme)
|
81
|
+
list.delete(:lib_readme_dev)
|
82
|
+
list.delete(:templates_shared)
|
83
|
+
# Example of how to add a file, in this case the file will be compiled and copied to
|
84
|
+
# the same location in the new app
|
85
|
+
# list[:config_shared_commands] = { source: 'config/shared_commands.rb' }
|
86
|
+
list[:config_load_generators] = { source: 'config/load_generators.rb' }
|
87
|
+
list[:lib_base] = { source: 'lib/base.rb', dest: "lib/#{@name}/base.rb" }
|
88
|
+
list[:lib_plugin] = { source: 'lib/plugin.rb', dest: "lib/#{@name}/plugin.rb" }
|
89
|
+
list[:lib_application] = { source: 'lib/application.rb', dest: "lib/#{@name}/application.rb" }
|
90
|
+
# Alternatively specifying a different destination, typically you would do this when
|
91
|
+
# the final location is dynamic
|
92
|
+
# list[:gemspec] = { source: 'gemspec.rb', dest: "#{@name}.gemspec" }
|
93
|
+
# Example of how to create a directory
|
94
|
+
list[:templates_app] = { dest: 'templates/app_generators/application', type: :directory }
|
95
|
+
list[:templates_plugin] = { dest: 'templates/app_generators/plugin', type: :directory }
|
96
|
+
list[:templates_base] = { dest: 'templates/app_generators/base', type: :directory }
|
97
|
+
# By default, directories created in this way will contain a .keep file, to inhibit this:
|
98
|
+
# list[:pattern_dir] = { dest: "pattern", type: :directory, nokeep: true }
|
99
|
+
# Example of how to create a symlink
|
100
|
+
# list[:target_default] = { source: 'debug.rb', # Relative to the file being linked to
|
101
|
+
# dest: 'target/default.rb', # Relative to destination_root
|
102
|
+
# type: :symlink }
|
103
|
+
# Remember to return the final list
|
104
|
+
list
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module OrigenAppGenerators
|
2
|
+
# The base generator class that should be used by all plugin generators
|
3
|
+
class Plugin < Application
|
4
|
+
def get_common_user_input
|
5
|
+
get_name_and_namespace
|
6
|
+
get_summary
|
7
|
+
get_audience unless @audience
|
8
|
+
end
|
9
|
+
|
10
|
+
protected
|
11
|
+
|
12
|
+
# See Application#filelist for more details
|
13
|
+
def filelist
|
14
|
+
@filelist ||= begin
|
15
|
+
list = super
|
16
|
+
list.delete(:web_doc_layout)
|
17
|
+
list.delete(:web_references)
|
18
|
+
list.delete(:web_defintions)
|
19
|
+
list.delete(:web_installation)
|
20
|
+
list.delete(:web_introduction)
|
21
|
+
list[:gemspec] = { source: 'gemspec.rb', dest: "#{@name}.gemspec" }
|
22
|
+
list[:templates_shared] = { dest: 'templates/shared', type: :directory }
|
23
|
+
if @audience == :external
|
24
|
+
list[:travis] = { source: '.travis.yml' }
|
25
|
+
list[:web_navbar] = { source: 'templates/web/partials/_navbar_external.html.erb', dest: 'templates/web/partials/_navbar.html.erb' }
|
26
|
+
else
|
27
|
+
list[:web_navbar] = { source: 'templates/web/partials/_navbar_internal.html.erb', dest: 'templates/web/partials/_navbar.html.erb' }
|
28
|
+
end
|
29
|
+
list[:lib_readme] = { source: 'lib/README', dest: "lib/#{@name}/README" }
|
30
|
+
list[:lib_readme_dev] = { source: 'lib_dev/README', dest: "lib/#{@name}_dev/README" }
|
31
|
+
list
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def get_summary
|
36
|
+
puts
|
37
|
+
puts 'DESCRIBE YOUR NEW PLUGIN IN A FEW WORDS'
|
38
|
+
puts
|
39
|
+
@summary = get_text(single: true)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Prompts the user to say whether the new plugin is intended for an internal
|
43
|
+
# or external audience (meaning it will published to rubygems.org)
|
44
|
+
def get_audience(proposal = nil)
|
45
|
+
puts
|
46
|
+
puts 'IS THIS PLUGIN GOING TO BE RELEASED TO AN EXTERNAL AUDIENCE?'
|
47
|
+
puts
|
48
|
+
puts 'By answering yes, this plugin will be pushed to rubygems.org when it is released and it will be available outside of your company.'
|
49
|
+
puts
|
50
|
+
confirm_external = get_text(confirm: :return_boolean, default: 'no')
|
51
|
+
@audience = :external if confirm_external
|
52
|
+
end
|
53
|
+
|
54
|
+
def type
|
55
|
+
:plugin
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module OrigenAppGenerators
|
2
|
+
require 'strscan'
|
3
|
+
# Responsible for parsing something like this:
|
4
|
+
#
|
5
|
+
# "ram, osc, pll, atd(2), comms[ram(2), osc](3)"
|
6
|
+
#
|
7
|
+
# into this:
|
8
|
+
#
|
9
|
+
# {
|
10
|
+
# "RAM"=>{}, "Osc"=>{}, "PLL"=>{}, "ATD"=> {:instances=>2},
|
11
|
+
# "Comms"=>{:instances=>3, :children=>{"RAM"=>{:instances=>2}, "Osc"=>{}}}
|
12
|
+
# }
|
13
|
+
#
|
14
|
+
class SubBlockParser
|
15
|
+
def parse(str)
|
16
|
+
r = {}
|
17
|
+
split(str).each do |tag|
|
18
|
+
tag, i = extract_instances(tag)
|
19
|
+
name, children = extract_children(tag)
|
20
|
+
name = camelize(name)
|
21
|
+
r[name] = {}
|
22
|
+
r[name][:instances] = i if i
|
23
|
+
r[name][:children] = children if children
|
24
|
+
end
|
25
|
+
r
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
# Splits the given string by comma, but understands that nested
|
31
|
+
# commas should not be split on
|
32
|
+
def split(str)
|
33
|
+
r = []
|
34
|
+
str = StringScanner.new(str)
|
35
|
+
r << next_tag(str) until str.eos?
|
36
|
+
r
|
37
|
+
end
|
38
|
+
|
39
|
+
def next_tag(str)
|
40
|
+
v = str.scan_until(/,|\[|$/)
|
41
|
+
if v[-1] == ','
|
42
|
+
v.chop.strip
|
43
|
+
elsif v[-1] == '['
|
44
|
+
open = 1
|
45
|
+
while open > 0
|
46
|
+
v += str.scan_until(/\[|\]/)
|
47
|
+
if v[-1] == '['
|
48
|
+
open += 1
|
49
|
+
else
|
50
|
+
open -= 1
|
51
|
+
end
|
52
|
+
end
|
53
|
+
v += next_tag(str)
|
54
|
+
# End of line
|
55
|
+
else
|
56
|
+
v.strip
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def extract_children(tag)
|
61
|
+
# http://rubular.com/r/plGILY2e2U
|
62
|
+
if tag.strip =~ /([^\[]*)\[(.*)\]/
|
63
|
+
[Regexp.last_match(1), parse(Regexp.last_match(2))]
|
64
|
+
else
|
65
|
+
[tag.strip, nil]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def extract_instances(tag)
|
70
|
+
if tag.strip =~ /(.*)\((\d+)\)$/
|
71
|
+
[Regexp.last_match(1), Regexp.last_match(2).to_i]
|
72
|
+
else
|
73
|
+
[tag.strip, nil]
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def camelize(val)
|
78
|
+
val.strip.gsub(/\s+/, '_').camelize
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|