origen 0.38.0 → 0.40.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. checksums.yaml +4 -4
  2. data/bin/origen +1 -236
  3. data/config/application.rb +10 -1
  4. data/config/version.rb +1 -1
  5. data/lib/origen/{boot_api.rb → boot/api.rb} +2 -2
  6. data/lib/origen/boot/app.rb +324 -0
  7. data/lib/origen/boot.rb +287 -0
  8. data/lib/origen/commands/archive.rb +175 -0
  9. data/lib/origen/commands/extract.rb +43 -0
  10. data/lib/origen/commands/new.rb +33 -23
  11. data/lib/origen/commands.rb +4 -1
  12. data/lib/origen/commands_global.rb +3 -2
  13. data/lib/origen/operating_systems.rb +4 -0
  14. data/lib/origen/revision_control.rb +1 -1
  15. data/lib/origen/site_config.rb +4 -1
  16. data/lib/origen.rb +3 -2
  17. data/origen_app_generators/Gemfile +16 -0
  18. data/origen_app_generators/Gemfile.lock +147 -0
  19. data/origen_app_generators/LICENSE +21 -0
  20. data/origen_app_generators/README.md +368 -0
  21. data/origen_app_generators/Rakefile +10 -0
  22. data/origen_app_generators/bin/boot.rb +37 -0
  23. data/{bin → origen_app_generators/bin}/fix_my_workspace +0 -0
  24. data/origen_app_generators/config/application.rb +153 -0
  25. data/origen_app_generators/config/boot.rb +1 -0
  26. data/origen_app_generators/config/commands.rb +63 -0
  27. data/origen_app_generators/config/shared_commands.rb +172 -0
  28. data/origen_app_generators/config/version.rb +8 -0
  29. data/origen_app_generators/doc/history +213 -0
  30. data/origen_app_generators/lib/origen_app_generators/application.rb +62 -0
  31. data/origen_app_generators/lib/origen_app_generators/base.rb +231 -0
  32. data/origen_app_generators/lib/origen_app_generators/empty_application.rb +15 -0
  33. data/origen_app_generators/lib/origen_app_generators/empty_plugin.rb +15 -0
  34. data/origen_app_generators/lib/origen_app_generators/new.rb +162 -0
  35. data/origen_app_generators/lib/origen_app_generators/origen_infrastructure/app_generator_plugin.rb +109 -0
  36. data/origen_app_generators/lib/origen_app_generators/plugin.rb +58 -0
  37. data/origen_app_generators/lib/origen_app_generators/sub_block_parser.rb +81 -0
  38. data/origen_app_generators/lib/origen_app_generators/test_engineering/stand_alone_application.rb +236 -0
  39. data/origen_app_generators/lib/origen_app_generators/test_engineering/test_block.rb +162 -0
  40. data/origen_app_generators/lib/origen_app_generators.rb +123 -0
  41. data/origen_app_generators/lib/tasks/app_generators.rake +6 -0
  42. data/origen_app_generators/lib/tasks/new_app_tests.rake +8 -0
  43. data/origen_app_generators/origen_app_generators.gemspec +33 -0
  44. data/origen_app_generators/spec/spec_helper.rb +49 -0
  45. data/origen_app_generators/spec/sub_block_spec.rb +36 -0
  46. data/origen_app_generators/target/debug.rb +8 -0
  47. data/origen_app_generators/target/default.rb +8 -0
  48. data/origen_app_generators/target/production.rb +0 -0
  49. data/origen_app_generators/templates/app_generators/application/Gemfile +19 -0
  50. data/origen_app_generators/templates/app_generators/application/Rakefile +7 -0
  51. data/origen_app_generators/templates/app_generators/application/config/application.rb +125 -0
  52. data/origen_app_generators/templates/app_generators/application/config/boot.rb +4 -0
  53. data/origen_app_generators/templates/app_generators/application/config/commands.rb +79 -0
  54. data/origen_app_generators/templates/app_generators/application/config/maillist_dev.txt +4 -0
  55. data/origen_app_generators/templates/app_generators/application/config/maillist_prod.txt +3 -0
  56. data/origen_app_generators/templates/app_generators/application/config/version.rb +8 -0
  57. data/origen_app_generators/templates/app_generators/application/doc/history +0 -0
  58. data/origen_app_generators/templates/app_generators/application/dot_keep +0 -0
  59. data/origen_app_generators/templates/app_generators/application/lib/app.rake +6 -0
  60. data/origen_app_generators/templates/app_generators/application/lib/module.rb +22 -0
  61. data/origen_app_generators/templates/app_generators/application/lib/top_level.rb +12 -0
  62. data/origen_app_generators/templates/app_generators/application/origen_core_session +2 -0
  63. data/origen_app_generators/templates/app_generators/application/spec/spec_helper.rb +44 -0
  64. data/origen_app_generators/templates/app_generators/application/target/debug.rb +8 -0
  65. data/origen_app_generators/templates/app_generators/application/target/default.rb +1 -0
  66. data/origen_app_generators/templates/app_generators/application/target/production.rb +4 -0
  67. data/origen_app_generators/templates/app_generators/application/templates/web/index.md.erb +19 -0
  68. data/origen_app_generators/templates/app_generators/application/templates/web/layouts/_basic.html.erb +13 -0
  69. data/origen_app_generators/templates/app_generators/application/templates/web/partials/_navbar.html.erb +20 -0
  70. data/origen_app_generators/templates/app_generators/application/templates/web/release_notes.md.erb +5 -0
  71. data/origen_app_generators/templates/app_generators/new/generator.rb +102 -0
  72. data/origen_app_generators/templates/app_generators/new/info.md.erb +9 -0
  73. data/origen_app_generators/templates/app_generators/origen_infrastructure/app_generator_plugin/config/load_generators.rb +6 -0
  74. data/origen_app_generators/templates/app_generators/origen_infrastructure/app_generator_plugin/lib/application.rb +54 -0
  75. data/origen_app_generators/templates/app_generators/origen_infrastructure/app_generator_plugin/lib/base.rb +55 -0
  76. data/origen_app_generators/templates/app_generators/origen_infrastructure/app_generator_plugin/lib/module.rb +28 -0
  77. data/origen_app_generators/templates/app_generators/origen_infrastructure/app_generator_plugin/lib/plugin.rb +64 -0
  78. data/origen_app_generators/templates/app_generators/plugin/Gemfile +26 -0
  79. data/origen_app_generators/templates/app_generators/plugin/Rakefile +10 -0
  80. data/origen_app_generators/templates/app_generators/plugin/config/boot.rb +24 -0
  81. data/origen_app_generators/templates/app_generators/plugin/gemspec.rb +42 -0
  82. data/origen_app_generators/templates/app_generators/plugin/lib/README +4 -0
  83. data/origen_app_generators/templates/app_generators/plugin/lib_dev/README +5 -0
  84. data/origen_app_generators/templates/app_generators/plugin/templates/web/index.md.erb +37 -0
  85. data/origen_app_generators/templates/app_generators/plugin/templates/web/partials/_navbar_external.html.erb +20 -0
  86. data/origen_app_generators/templates/app_generators/plugin/templates/web/partials/_navbar_internal.html.erb +20 -0
  87. data/origen_app_generators/templates/app_generators/test_engineering/stand_alone_application/Gemfile +23 -0
  88. data/origen_app_generators/templates/app_generators/test_engineering/stand_alone_application/environment/j750.rb +1 -0
  89. data/origen_app_generators/templates/app_generators/test_engineering/stand_alone_application/environment/jlink.rb +1 -0
  90. data/origen_app_generators/templates/app_generators/test_engineering/stand_alone_application/environment/uflex.rb +1 -0
  91. data/origen_app_generators/templates/app_generators/test_engineering/stand_alone_application/environment/v93k.rb +1 -0
  92. data/origen_app_generators/templates/app_generators/test_engineering/stand_alone_application/lib/ip_block.rb +23 -0
  93. data/origen_app_generators/templates/app_generators/test_engineering/stand_alone_application/lib/ip_block_controller.rb +5 -0
  94. data/origen_app_generators/templates/app_generators/test_engineering/stand_alone_application/lib/top_level.rb +33 -0
  95. data/origen_app_generators/templates/app_generators/test_engineering/stand_alone_application/lib/top_level_controller.rb +21 -0
  96. data/origen_app_generators/templates/app_generators/test_engineering/stand_alone_application/pattern/example.rb +4 -0
  97. data/origen_app_generators/templates/app_generators/test_engineering/stand_alone_application/target/top_level.rb +4 -0
  98. data/origen_app_generators/templates/app_generators/test_engineering/test_block/environment/j750.rb +2 -0
  99. data/origen_app_generators/templates/app_generators/test_engineering/test_block/environment/ultraflex.rb +2 -0
  100. data/origen_app_generators/templates/app_generators/test_engineering/test_block/environment/v93k.rb +2 -0
  101. data/origen_app_generators/templates/app_generators/test_engineering/test_block/lib/controller.rb +12 -0
  102. data/origen_app_generators/templates/app_generators/test_engineering/test_block/lib/interface.rb +21 -0
  103. data/origen_app_generators/templates/app_generators/test_engineering/test_block/lib/model.rb +18 -0
  104. data/origen_app_generators/templates/app_generators/test_engineering/test_block/lib_dev/dut.rb +27 -0
  105. data/origen_app_generators/templates/app_generators/test_engineering/test_block/lib_dev/dut_controller.rb +26 -0
  106. data/origen_app_generators/templates/app_generators/test_engineering/test_block/pattern/example.rb +5 -0
  107. data/origen_app_generators/templates/app_generators/test_engineering/test_block/program/prb1.rb +11 -0
  108. data/origen_app_generators/templates/app_generators/test_engineering/test_block/target/default.rb +2 -0
  109. data/origen_site_config.yml +13 -2
  110. data/templates/git/gitignore.erb +0 -1
  111. 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
@@ -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