sysbuild 1.0.3
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.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/README.md +36 -0
- data/Rakefile +2 -0
- data/bin/sysbuild +6 -0
- data/doc/snippets +5 -0
- data/lib/change_detector.rb +107 -0
- data/lib/sysbuild.rb +680 -0
- data/lib/version.rb +3 -0
- data/sysbuild.gemspec +35 -0
- metadata +196 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1440cdd35744897e112ced48488483835498f109
|
4
|
+
data.tar.gz: bfb8141d839c9e29340f393819c6f04e56cd1359
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 13090879de8c29e72eaf41096fabc5dd3478d5c9443514ebce6086e091c3fb0980a861a5d7abf25798b0120a7c1dcccc05fb4ee6331d54f58ae8414698d3fb8d
|
7
|
+
data.tar.gz: 977341327f82505a222fb0d3ae66a84f943712cc8fd8514e55b66092358a6f960e84960aeb627d60d198527f9fc29a621f8f81fd23f8a2c4326a19037802f0a0
|
data/.gitignore
ADDED
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
sysbuild-dev
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.3.0
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# Sysbuild
|
2
|
+
|
3
|
+
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/sysbuild`. To experiment with that code, run `bin/console` for an interactive prompt.
|
4
|
+
|
5
|
+
TODO: Delete this and the text above, and describe your gem
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'sysbuild'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install sysbuild
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
TODO: Write usage instructions here
|
26
|
+
|
27
|
+
## Development
|
28
|
+
|
29
|
+
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
30
|
+
|
31
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
32
|
+
|
33
|
+
## Contributing
|
34
|
+
|
35
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/sysbuild.
|
36
|
+
|
data/Rakefile
ADDED
data/bin/sysbuild
ADDED
data/doc/snippets
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
module Constants
|
2
|
+
TYPE_BOTH = "both"
|
3
|
+
TYPE_POM = "pom"
|
4
|
+
TYPE_MVN = "mvn"
|
5
|
+
TYPE_MVN_18 = "mvn18"
|
6
|
+
|
7
|
+
HASH_FOLDER = '.sysbuild/hashes'
|
8
|
+
end
|
9
|
+
|
10
|
+
require 'fileutils'
|
11
|
+
require 'digest'
|
12
|
+
|
13
|
+
class ChangeDetector
|
14
|
+
|
15
|
+
|
16
|
+
def initialize(source:, type: Constants::TYPE_BOTH)
|
17
|
+
|
18
|
+
@source_directory = source
|
19
|
+
raise "Change type #{type} unknown." unless [Constants::TYPE_BOTH, Constants::TYPE_POM, Constants::TYPE_MVN, Constants::TYPE_MVN_18].include? type
|
20
|
+
@type = type
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
def changed?
|
25
|
+
|
26
|
+
begin
|
27
|
+
cwd = `pwd`.strip!
|
28
|
+
Dir.chdir @source_directory
|
29
|
+
|
30
|
+
changed = pom_check
|
31
|
+
|
32
|
+
# If there is still no change registered, the pom was okay - check the file system.
|
33
|
+
|
34
|
+
if (! @type.eql? Constants::TYPE_POM )
|
35
|
+
changed = fs_check unless changed
|
36
|
+
end
|
37
|
+
|
38
|
+
changed
|
39
|
+
ensure
|
40
|
+
Dir.chdir cwd
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def pom_check
|
45
|
+
# See if there's a hash for the pom. If not, create one.
|
46
|
+
|
47
|
+
changed = false
|
48
|
+
|
49
|
+
sha256 = Digest::SHA256.file 'pom.xml'
|
50
|
+
|
51
|
+
if !(File.exists?(Constants::HASH_FOLDER)) || !(File.exists?("#{Constants::HASH_FOLDER}/pom.xml.sha256"))
|
52
|
+
FileUtils::mkdir_p Constants::HASH_FOLDER
|
53
|
+
open("#{Constants::HASH_FOLDER}/pom.xml.sha256", 'w') {|f| f << sha256}
|
54
|
+
changed = true
|
55
|
+
else
|
56
|
+
|
57
|
+
loaded_hash = File.read("#{Constants::HASH_FOLDER}/pom.xml.sha256")
|
58
|
+
|
59
|
+
if (!(loaded_hash.to_s.eql? sha256.to_s))
|
60
|
+
open("#{Constants::HASH_FOLDER}/pom.xml.sha256", 'w') {|f| f << sha256}
|
61
|
+
changed = true
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
changed
|
66
|
+
end
|
67
|
+
|
68
|
+
def fs_check
|
69
|
+
return true if !File.exist?("target")
|
70
|
+
|
71
|
+
# get the newest file in the target folder
|
72
|
+
|
73
|
+
newest_target = nil
|
74
|
+
|
75
|
+
Find.find("target") do |path|
|
76
|
+
if (path.end_with?('jar')|| path.end_with?('zip'))
|
77
|
+
file = File.new(path)
|
78
|
+
newest_target = file if !newest_target
|
79
|
+
newest_target = file if file.mtime > newest_target.mtime
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
if !newest_target
|
84
|
+
return true
|
85
|
+
end
|
86
|
+
|
87
|
+
# puts "Newest target in #{Dir.pwd} is #{newest_target.path} => #{newest_target.mtime}"
|
88
|
+
|
89
|
+
#get the newest file in the source folder.
|
90
|
+
|
91
|
+
newest_source = nil
|
92
|
+
|
93
|
+
Find.find("src") do |path|
|
94
|
+
file = File.new(path)
|
95
|
+
newest_source = file if !newest_source
|
96
|
+
newest_source = file if file.mtime > newest_source.mtime
|
97
|
+
end
|
98
|
+
|
99
|
+
# puts "Newest source in #{Dir.pwd} is #{newest_source.path} => #{newest_source.mtime}"
|
100
|
+
# puts
|
101
|
+
|
102
|
+
newest_target.mtime < newest_source.mtime
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
end
|
data/lib/sysbuild.rb
ADDED
@@ -0,0 +1,680 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# vim: ts=2:sw=2
|
4
|
+
#
|
5
|
+
|
6
|
+
# Required Gems
|
7
|
+
# ruby-terminfo
|
8
|
+
# open4
|
9
|
+
# paint
|
10
|
+
# fileutils
|
11
|
+
#
|
12
|
+
# gem install ruby-terminfo open4 paint fileutils nokogiri text-table
|
13
|
+
|
14
|
+
# https://github.com/janlelis/paint
|
15
|
+
require 'paint'
|
16
|
+
|
17
|
+
# http://rubydoc.info/gems/ruby-terminfo/0.1.1/frames
|
18
|
+
require 'terminfo'
|
19
|
+
require 'yaml'
|
20
|
+
|
21
|
+
# https://github.com/ahoward/open4
|
22
|
+
require 'open4'
|
23
|
+
|
24
|
+
require 'fileutils'
|
25
|
+
require 'nokogiri'
|
26
|
+
require 'text-table'
|
27
|
+
require 'ruby-progressbar'
|
28
|
+
|
29
|
+
# BUILTINS
|
30
|
+
require 'optparse'
|
31
|
+
require 'pp'
|
32
|
+
require 'tempfile'
|
33
|
+
require 'find'
|
34
|
+
|
35
|
+
class Sysbuild_Main
|
36
|
+
|
37
|
+
|
38
|
+
# COLOUR CONSTANTS
|
39
|
+
|
40
|
+
COL_SEPARATOR = 'ivory'
|
41
|
+
COL_TITLE = 'ivory2'
|
42
|
+
COL_VERSION = 'tan'
|
43
|
+
COL_SUBTITLE = 'ivory3'
|
44
|
+
COL_OUTPUT = 'ivory3'
|
45
|
+
|
46
|
+
COL_NORMAL = 'RoyalBlue'
|
47
|
+
COL_ERROR = 'red'
|
48
|
+
COL_HARD_ERROR = 'firebrick4'
|
49
|
+
|
50
|
+
COL_WARN = "yellow"
|
51
|
+
|
52
|
+
COL_HEADER = "yellow"
|
53
|
+
|
54
|
+
JAVA_18 = "JAVA_HOME=#{`/usr/libexec/java_home -v 1.8`.strip} PATH=#{`/usr/libexec/java_home -v 1.8`.strip}/bin:$PATH"
|
55
|
+
JAVA_17 = "JAVA_HOME=#{`/usr/libexec/java_home -v 1.7`.strip} PATH=#{`/usr/libexec/java_home -v 1.7`.strip}/bin:$PATH"
|
56
|
+
|
57
|
+
|
58
|
+
# ===========================================================================
|
59
|
+
# Main methods
|
60
|
+
# ===========================================================================
|
61
|
+
|
62
|
+
def main
|
63
|
+
start_time = Time.now
|
64
|
+
|
65
|
+
trap "SIGINT" do
|
66
|
+
exit 130
|
67
|
+
end
|
68
|
+
|
69
|
+
@script_args = Array.new(ARGV) # copy this because they seem to be consumed by optparser
|
70
|
+
@script_name = $0
|
71
|
+
|
72
|
+
# Set up some constants
|
73
|
+
@width = TermInfo.screen_size[1]
|
74
|
+
@separator = '-' * @width
|
75
|
+
@progname = 'sysbuild - modular system builder'
|
76
|
+
|
77
|
+
@options = {}
|
78
|
+
@options[:operation] = 'build'
|
79
|
+
@options[:specfile] = 'sysbuild.yaml'
|
80
|
+
@options[:clean] = false
|
81
|
+
@options[:partial] = nil
|
82
|
+
@options[:quiet] = true
|
83
|
+
@options[:inhibit_stages] = false
|
84
|
+
|
85
|
+
@valid_operations = %w"build distro check scm scm2"
|
86
|
+
|
87
|
+
@local_repo = get_local_repo
|
88
|
+
|
89
|
+
banner
|
90
|
+
setup_optparser
|
91
|
+
load_spec
|
92
|
+
|
93
|
+
case @options[:operation]
|
94
|
+
when 'build'
|
95
|
+
do_build
|
96
|
+
when 'distro'
|
97
|
+
do_distro
|
98
|
+
when 'check'
|
99
|
+
do_check
|
100
|
+
when 'scm'
|
101
|
+
do_scm
|
102
|
+
when 'scm2'
|
103
|
+
do_scm2
|
104
|
+
end
|
105
|
+
|
106
|
+
puts
|
107
|
+
completion_message = "Build complete. Elapsed time: #{(Time.now - start_time).to_i}s";
|
108
|
+
puts Paint[completion_message, COL_NORMAL]
|
109
|
+
|
110
|
+
# If on Mac, and osascript is available, fire a desktop notification
|
111
|
+
if File.executable?("/usr/bin/osascript")
|
112
|
+
subtitle = "#{@script_name} #{@script_args.join(' ')}"
|
113
|
+
system "/usr/bin/osascript -e 'display notification \"#{completion_message}\" with title \"Sysbuild\" subtitle \"#{subtitle}\"'"
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
|
119
|
+
def load_spec
|
120
|
+
# attempt to load the spec from @options[:specfile]
|
121
|
+
#
|
122
|
+
unless File.exists?(@options[:specfile]) && File.readable?(@options[:specfile])
|
123
|
+
abort "Couldn't load the system specification file #{@options[:specfile]}"
|
124
|
+
end
|
125
|
+
|
126
|
+
|
127
|
+
@spec = YAML.load_file(@options[:specfile])
|
128
|
+
@base_location = File.dirname( File.absolute_path( @options[:specfile] ) )
|
129
|
+
|
130
|
+
# Find the build target for the deploy goal
|
131
|
+
@target_list ||= 'fusionreactor-agent'
|
132
|
+
end
|
133
|
+
|
134
|
+
|
135
|
+
def setup_optparser
|
136
|
+
@opt_parser = OptionParser.new do |opt|
|
137
|
+
opt.on('-p', '--partial [list]', 'Comma-separated list of partial build targets') do |list|
|
138
|
+
abort '-p: A list of build targets must be supplied.' unless list
|
139
|
+
@options[:partial] = list.split(',')
|
140
|
+
end
|
141
|
+
|
142
|
+
opt.on('-d', '--detect-changes [list]', 'Causes the script to attempt to identify projects with changes, and build those.') do |list|
|
143
|
+
@options[:detect] = true
|
144
|
+
@options[:clean] = true
|
145
|
+
@options[:always_build] = list.split(',') if list
|
146
|
+
end
|
147
|
+
|
148
|
+
opt.on('-c', '--clean', 'Clean build target areas before building') do
|
149
|
+
@options[:clean] = true
|
150
|
+
end
|
151
|
+
|
152
|
+
opt.on('-n', '--no-build-stages', 'Don\'t run pre and post build stages, if specified.') do
|
153
|
+
@options[:inhibit_stages] = true
|
154
|
+
end
|
155
|
+
|
156
|
+
opt.on('-s', '--systemspec [FILE]', 'A yaml file containing the system spec (default sysbuild.yaml)') do |spec|
|
157
|
+
abort '-s: A system spec file must be provided.' unless spec
|
158
|
+
@options[:specfile] = spec
|
159
|
+
end
|
160
|
+
|
161
|
+
opt.on('-o', '--operation [OPER]', 'An operation: build, distro, check, scm') do |oper|
|
162
|
+
abort '-o: An operation must be specified' unless oper
|
163
|
+
@options[:operation] = oper
|
164
|
+
abort "-o: Operation #{oper} is not valid" unless @valid_operations.include?(oper)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
@opt_parser.parse!
|
169
|
+
end
|
170
|
+
|
171
|
+
# ===========================================================================
|
172
|
+
# Command: Check
|
173
|
+
# ===========================================================================
|
174
|
+
|
175
|
+
|
176
|
+
def do_check
|
177
|
+
puts Paint['Checking structure.', COL_NORMAL]
|
178
|
+
|
179
|
+
@spec['modules'].each do |mod|
|
180
|
+
if !directory_exists?(mod.keys[0])
|
181
|
+
puts Paint[" Missing: #{mod.keys[0]}", COL_ERROR]
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
# ===========================================================================
|
187
|
+
# Command: SCM
|
188
|
+
# ===========================================================================
|
189
|
+
|
190
|
+
def do_scm
|
191
|
+
puts Paint['Performing SCM check.', COL_NORMAL]
|
192
|
+
|
193
|
+
@spec['modules'].each do |mod|
|
194
|
+
puts Paint["\n Checking: #{mod.keys[0]}", COL_NORMAL]
|
195
|
+
command = "svn status -u #{mod.keys[0]}"
|
196
|
+
pid, stdin, stdout, stderr = Open4::popen4 command
|
197
|
+
Process::waitpid2 pid
|
198
|
+
doc = stdout.read.strip
|
199
|
+
doc.lines do |line|
|
200
|
+
print Paint[" #{line}", COL_OUTPUT]
|
201
|
+
end
|
202
|
+
|
203
|
+
puts
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
|
208
|
+
# ===========================================================================
|
209
|
+
# Command: SCM2
|
210
|
+
# ===========================================================================
|
211
|
+
|
212
|
+
|
213
|
+
def do_scm2
|
214
|
+
puts Paint['Checking for SCM Changes.', COL_NORMAL]
|
215
|
+
puts
|
216
|
+
|
217
|
+
|
218
|
+
@spec['modules'].each do |mod|
|
219
|
+
|
220
|
+
result = `svn status --xml -u #{mod.keys[0]}`
|
221
|
+
|
222
|
+
doc = Nokogiri::XML(result)
|
223
|
+
doc.remove_namespaces!
|
224
|
+
|
225
|
+
change_entries = get_changes(doc)
|
226
|
+
|
227
|
+
if change_entries.length > 0
|
228
|
+
|
229
|
+
puts Paint["#{mod.keys[0]}", COL_NORMAL, :bright, :italic]
|
230
|
+
|
231
|
+
table = Text::Table.new :horizontal_padding => 1,
|
232
|
+
:vertical_boundary => '-',
|
233
|
+
:horizontal_boundary => '|',
|
234
|
+
:boundary_intersection => ' '
|
235
|
+
|
236
|
+
table.head = ['WC', 'Repo', 'Rev', 'Auth', 'Path']
|
237
|
+
|
238
|
+
change_entries.each do |entry|
|
239
|
+
path = entry.xpath('@path').to_s
|
240
|
+
path = path[path.index('/')..-1]
|
241
|
+
|
242
|
+
wc_status = entry.xpath('wc-status/@item').to_s
|
243
|
+
wc_revision = entry.xpath('wc-status/@revision').to_s
|
244
|
+
commit_revision = entry.xpath('wc-status/commit/@revision').to_s
|
245
|
+
commit_author = entry.xpath('wc-status/commit/author/text()').to_s
|
246
|
+
commit_date_s = entry.xpath('wc-status/commit/date/text()').to_s
|
247
|
+
|
248
|
+
repo_status_ns = entry.xpath('repos-status/@item')
|
249
|
+
repo_status = repo_status_ns.length > 0 ? repo_status_ns.to_s : "ok"
|
250
|
+
|
251
|
+
#puts " #{wc_status} #{wc_revision} (#{commit_author}) #{repo_status} #{path}"
|
252
|
+
#puts " #{status_to_symbol(wc_status)} #{wc_revision if repo_status != 'ok'} #{commit_author if repo_status != 'ok'} #{repo_status} #{path}"
|
253
|
+
|
254
|
+
# WC-STATUS # REPO STATUS #COMMIT-REV #COMMIT-AUTH #PATH
|
255
|
+
|
256
|
+
table.rows << [status_to_symbol(wc_status), status_to_symbol(repo_status), commit_revision, commit_author, path]
|
257
|
+
|
258
|
+
end
|
259
|
+
|
260
|
+
puts table.to_s
|
261
|
+
|
262
|
+
# abort
|
263
|
+
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
end
|
268
|
+
|
269
|
+
def get_changes(doc)
|
270
|
+
changes = doc.xpath('/status/target/entry')
|
271
|
+
clc = doc.xpath('/status/changelist/entry')
|
272
|
+
|
273
|
+
if clc.length > 0
|
274
|
+
clc.each do |c|
|
275
|
+
changes << c
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
changes.to_a.sort! do |a, b|
|
280
|
+
|
281
|
+
r_a = a.xpath('wc-status/commit/@revision').to_s.to_i
|
282
|
+
r_b = b.xpath('wc-status/commit/@revision').to_s.to_i
|
283
|
+
|
284
|
+
r_a <=> r_b
|
285
|
+
|
286
|
+
end
|
287
|
+
|
288
|
+
end
|
289
|
+
|
290
|
+
|
291
|
+
def status_to_symbol(status)
|
292
|
+
case status
|
293
|
+
when 'normal'
|
294
|
+
return ''
|
295
|
+
when 'none'
|
296
|
+
return '*'
|
297
|
+
when 'modified'
|
298
|
+
return 'M'
|
299
|
+
when 'ok'
|
300
|
+
return ''
|
301
|
+
when 'deleted'
|
302
|
+
return 'D'
|
303
|
+
when 'added'
|
304
|
+
return 'A'
|
305
|
+
when 'unversioned'
|
306
|
+
return 'X'
|
307
|
+
else
|
308
|
+
return "[#{status}]"
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
|
313
|
+
# ===========================================================================
|
314
|
+
# Command: Build and Change Detection
|
315
|
+
# ===========================================================================
|
316
|
+
|
317
|
+
def directory_exists?(directory)
|
318
|
+
File.directory?(directory)
|
319
|
+
end
|
320
|
+
|
321
|
+
|
322
|
+
def detect_changes
|
323
|
+
|
324
|
+
puts Paint["Detecting changes.", COL_NORMAL]
|
325
|
+
|
326
|
+
changed_projects = Array.new
|
327
|
+
|
328
|
+
@options[:partial] = changed_projects
|
329
|
+
|
330
|
+
progressbar = ProgressBar.create(:total => @spec['modules'].count,
|
331
|
+
:format => "%a %b\u{15E7}%i %p%% %e",
|
332
|
+
:progress_mark => ' ',
|
333
|
+
:remainder_mark => "\u{FF65}")
|
334
|
+
|
335
|
+
@spec['modules'].each do |mod|
|
336
|
+
|
337
|
+
progressbar.increment
|
338
|
+
|
339
|
+
name = mod.keys[0]
|
340
|
+
type = mod[name]
|
341
|
+
|
342
|
+
cd = ChangeDetector.new(source: name, type: type)
|
343
|
+
|
344
|
+
if cd.changed?
|
345
|
+
changed_projects << name
|
346
|
+
end
|
347
|
+
|
348
|
+
end
|
349
|
+
|
350
|
+
if changed_projects.length > 0
|
351
|
+
|
352
|
+
if (@options[:always_build])
|
353
|
+
|
354
|
+
@options[:always_build].each do |mod|
|
355
|
+
changed_projects << mod if !changed_projects.include?(mod)
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
return true
|
360
|
+
|
361
|
+
end
|
362
|
+
|
363
|
+
return false
|
364
|
+
end
|
365
|
+
|
366
|
+
|
367
|
+
def get_target_type(name)
|
368
|
+
|
369
|
+
pom = "#{name}/pom.xml"
|
370
|
+
|
371
|
+
doc = Nokogiri::XML(File.open(pom))
|
372
|
+
doc.remove_namespaces!
|
373
|
+
packaging = doc.xpath("/project/packaging/text()")
|
374
|
+
|
375
|
+
if !packaging || packaging.length == 0
|
376
|
+
packaging = 'jar'
|
377
|
+
end
|
378
|
+
|
379
|
+
packaging.to_s
|
380
|
+
end
|
381
|
+
|
382
|
+
|
383
|
+
def pom_requires_build?(name)
|
384
|
+
|
385
|
+
pom_file = File.new("#{name}/pom.xml")
|
386
|
+
|
387
|
+
# Generate effective pom - pom might have properties from super pom.
|
388
|
+
out = `cd #{name} && mvn help:effective-pom -Doutput=/tmp/ep.pom && cd ..`
|
389
|
+
pom_doc = File.open("/tmp/ep.pom") { |f| Nokogiri::XML(f) }
|
390
|
+
|
391
|
+
`rm /tmp/ep.pom`
|
392
|
+
|
393
|
+
pom_doc.remove_namespaces!
|
394
|
+
|
395
|
+
group_id = pom_doc.xpath("/project/groupId/text()").to_s
|
396
|
+
artifact_id = pom_doc.xpath("/project/artifactId/text()").to_s
|
397
|
+
version = pom_doc.xpath("/project/version/text()").to_s
|
398
|
+
|
399
|
+
repo_name = "#{artifact_id}-#{version}.pom"
|
400
|
+
|
401
|
+
candidate = "#{@local_repo}/#{group_id.tr('.', '/')}/#{artifact_id}/#{version}/#{repo_name}"
|
402
|
+
|
403
|
+
begin
|
404
|
+
repo_file = File.new(candidate)
|
405
|
+
# puts "#{repo_file.path} #{repo_file.mtime} <> #{pom_file.path} #{pom_file.mtime}"
|
406
|
+
return repo_file.mtime < pom_file.mtime
|
407
|
+
rescue Errno::ENOENT
|
408
|
+
# Not in local repo - needs building.
|
409
|
+
return true
|
410
|
+
rescue Exception => e
|
411
|
+
puts e.message
|
412
|
+
puts e.backtrace.inspect
|
413
|
+
return false
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
|
418
|
+
|
419
|
+
def do_build
|
420
|
+
|
421
|
+
current_dir = `pwd`.strip!
|
422
|
+
|
423
|
+
Dir.chdir(@base_location)
|
424
|
+
|
425
|
+
begin
|
426
|
+
if @options[:detect]
|
427
|
+
changes = detect_changes # puts changes into :partial
|
428
|
+
if !changes
|
429
|
+
puts Paint["No changes detected.", COL_NORMAL]
|
430
|
+
return
|
431
|
+
end
|
432
|
+
end
|
433
|
+
|
434
|
+
build_string = "Building #{@options[:partial] ? 'partial' : 'the full'} system."
|
435
|
+
|
436
|
+
do_stage(@spec['pre-build']) unless @options[:inhibit_stages]
|
437
|
+
|
438
|
+
puts Paint[build_string, COL_NORMAL]
|
439
|
+
|
440
|
+
if @options[:partial]
|
441
|
+
@options[:partial].each do |mod|
|
442
|
+
puts Paint[' ' << mod, COL_OUTPUT]
|
443
|
+
end
|
444
|
+
|
445
|
+
puts
|
446
|
+
|
447
|
+
@options[:partial].each do |mod|
|
448
|
+
build_single(mod)
|
449
|
+
end
|
450
|
+
else
|
451
|
+
# Build everything
|
452
|
+
puts
|
453
|
+
@spec['modules'].each do |modmap|
|
454
|
+
build_single(modmap)
|
455
|
+
end
|
456
|
+
end
|
457
|
+
|
458
|
+
do_stage(@spec['post-build']) unless @options[:inhibit_stages]
|
459
|
+
|
460
|
+
rescue Exception => e
|
461
|
+
|
462
|
+
puts e.message
|
463
|
+
puts e.backtrace.inspect
|
464
|
+
|
465
|
+
ensure
|
466
|
+
|
467
|
+
Dir.chdir( current_dir )
|
468
|
+
|
469
|
+
end
|
470
|
+
end
|
471
|
+
|
472
|
+
|
473
|
+
def build_single(something)
|
474
|
+
if something.kind_of?(String)
|
475
|
+
# look it up out of the spec.
|
476
|
+
modspec = lookup(something)
|
477
|
+
abort "Specified module \'#{something}\' not found in #{@options[:specfile]}" unless modspec
|
478
|
+
else
|
479
|
+
modspec = something
|
480
|
+
end
|
481
|
+
|
482
|
+
splits = modspec.values[0].split(' ')
|
483
|
+
buildtype = splits[0]
|
484
|
+
|
485
|
+
case buildtype
|
486
|
+
when 'mvn18'
|
487
|
+
build_maven(modspec.keys[0], JAVA_18)
|
488
|
+
when 'pom'
|
489
|
+
build_maven(modspec.keys[0], JAVA_17)
|
490
|
+
when 'mvn'
|
491
|
+
build_maven(modspec.keys[0], JAVA_17)
|
492
|
+
when 'gradle_libinstall'
|
493
|
+
build_gradle(modspec.keys[0], type: 'install')
|
494
|
+
when 'gradle'
|
495
|
+
build_gradle(modspec.keys[0])
|
496
|
+
else
|
497
|
+
abort "Build type #{buildtype} not supported."
|
498
|
+
end
|
499
|
+
end
|
500
|
+
|
501
|
+
def build_gradle(mod, type: 'build')
|
502
|
+
|
503
|
+
puts Paint["Gradle building #{mod}", COL_NORMAL]
|
504
|
+
|
505
|
+
if (type == 'build')
|
506
|
+
command = "cd #{mod} && gradle clean build -PuseLocalMavenRepo && cd .."
|
507
|
+
elsif (type == 'install')
|
508
|
+
command = "cd #{mod} && gradle clean install -PuseLocalMavenRepo && cd .."
|
509
|
+
end
|
510
|
+
|
511
|
+
pid, stdin, stdout, stderr = Open4::popen4 command
|
512
|
+
|
513
|
+
ignored, status = Process::waitpid2 pid
|
514
|
+
|
515
|
+
unless status.exitstatus == 0
|
516
|
+
abort ['Command returned nonzero status',
|
517
|
+
" command: #{command}",
|
518
|
+
" stdout: " << stdout.gets(sep=nil).to_s,
|
519
|
+
" stderr: " << stderr.gets(sep=nil).to_s]
|
520
|
+
end
|
521
|
+
|
522
|
+
end
|
523
|
+
|
524
|
+
|
525
|
+
def build_maven(mod, env='')
|
526
|
+
|
527
|
+
clean_flag = @options[:clean] ? '[clean]' : '[incremental]'
|
528
|
+
|
529
|
+
puts Paint["Maven building #{clean_flag} #{mod}", COL_NORMAL]
|
530
|
+
|
531
|
+
command = "cd #{mod} && #{env} mvn "
|
532
|
+
|
533
|
+
command << '-U ' if @options[:clean]
|
534
|
+
|
535
|
+
command << '-q ' if @options[:quiet]
|
536
|
+
command << '-DskipTests=true -Dskip.tests=true -Dmaven.test.skip -DskipITs '
|
537
|
+
command << 'clean ' if @options[:clean]
|
538
|
+
command << 'install'
|
539
|
+
|
540
|
+
command << ' && cd ..'
|
541
|
+
|
542
|
+
pid, stdin, stdout, stderr = Open4::popen4 command
|
543
|
+
|
544
|
+
ignored, status = Process::waitpid2 pid
|
545
|
+
|
546
|
+
unless status.exitstatus == 0
|
547
|
+
abort ['Command returned nonzero status',
|
548
|
+
" command: #{command}",
|
549
|
+
" stdout: " << stdout.gets(sep=nil).to_s,
|
550
|
+
" stderr: " << stderr.gets(sep=nil).to_s]
|
551
|
+
end
|
552
|
+
end
|
553
|
+
|
554
|
+
|
555
|
+
# ===========================================================================
|
556
|
+
# Build Stage
|
557
|
+
# ===========================================================================
|
558
|
+
|
559
|
+
|
560
|
+
def do_stage(text)
|
561
|
+
if text
|
562
|
+
file = Tempfile.new('sysbuild')
|
563
|
+
file.write text
|
564
|
+
file.close
|
565
|
+
FileUtils.chmod 0700, file.path
|
566
|
+
system(file.path)
|
567
|
+
file.unlink
|
568
|
+
end
|
569
|
+
end
|
570
|
+
|
571
|
+
# ===========================================================================
|
572
|
+
# Command: Distro
|
573
|
+
# ===========================================================================
|
574
|
+
|
575
|
+
def do_distro
|
576
|
+
|
577
|
+
puts Paint['Distributing build product', COL_NORMAL]
|
578
|
+
|
579
|
+
do_stage(@spec['pre-distro']) unless @options[:inhibit_stages]
|
580
|
+
|
581
|
+
# Load the distributions from the specfile.
|
582
|
+
|
583
|
+
@spec['distributions'].each do |map|
|
584
|
+
map.each do |location, type|
|
585
|
+
|
586
|
+
case type
|
587
|
+
when 'single'
|
588
|
+
distribute_single(location)
|
589
|
+
when 'multiple'
|
590
|
+
distribute_multiple(location)
|
591
|
+
end
|
592
|
+
end
|
593
|
+
end
|
594
|
+
|
595
|
+
do_stage(@spec['post-distro']) unless @options[:inhibit_stages]
|
596
|
+
end
|
597
|
+
|
598
|
+
|
599
|
+
# The build_product must be a list of files to distribute.
|
600
|
+
def distribute_single(location)
|
601
|
+
puts Paint[" Distribute to: #{location}", COL_NORMAL]
|
602
|
+
|
603
|
+
if !File.directory?(location)
|
604
|
+
puts Paint[" * Warning: location is not a directory - skipped.", COL_ERROR]
|
605
|
+
return
|
606
|
+
end
|
607
|
+
|
608
|
+
|
609
|
+
#Copy the build product to the location
|
610
|
+
|
611
|
+
unless File.exists?(location) && File.writable?(location)
|
612
|
+
abort "Couldn't find or write to the target area: #{location}"
|
613
|
+
end
|
614
|
+
|
615
|
+
@spec['products'].each do |product|
|
616
|
+
globpattern = Dir.glob(product)
|
617
|
+
FileUtils.cp(globpattern, location)
|
618
|
+
end
|
619
|
+
end
|
620
|
+
|
621
|
+
|
622
|
+
def distribute_multiple(location_stem)
|
623
|
+
#Copy the build product to all the directories listed in location_stem
|
624
|
+
|
625
|
+
Dir.glob(File.join(location_stem, "*")) do |folder|
|
626
|
+
distribute_single(folder)
|
627
|
+
end
|
628
|
+
end
|
629
|
+
|
630
|
+
# ===========================================================================
|
631
|
+
# Utils
|
632
|
+
# ===========================================================================
|
633
|
+
|
634
|
+
def banner
|
635
|
+
puts Paint[@separator, COL_SEPARATOR]
|
636
|
+
puts "#{Paint[@progname, COL_TITLE]} - r#{Paint[Sysbuild::VERSION, COL_VERSION]}"
|
637
|
+
puts Paint[@separator, COL_SEPARATOR]
|
638
|
+
puts
|
639
|
+
end
|
640
|
+
|
641
|
+
|
642
|
+
def abort(message = 'No message supplied.')
|
643
|
+
puts
|
644
|
+
puts Paint['SYSTEM BUILDER ABORT', COL_HARD_ERROR]
|
645
|
+
|
646
|
+
if message.kind_of?(Array)
|
647
|
+
message.each do |element|
|
648
|
+
puts Paint[' ' << element, COL_ERROR]
|
649
|
+
end
|
650
|
+
else
|
651
|
+
puts Paint[' ' << message, COL_ERROR]
|
652
|
+
end
|
653
|
+
|
654
|
+
Kernel.abort
|
655
|
+
end
|
656
|
+
|
657
|
+
|
658
|
+
def get_local_repo
|
659
|
+
|
660
|
+
system('mvn help:effective-settings -Doutput=/tmp/output.xml > /dev/null 2>&1 ')
|
661
|
+
doc = Nokogiri::XML(File.new("/tmp/output.xml"))
|
662
|
+
doc.remove_namespaces!
|
663
|
+
|
664
|
+
local_repo = doc.xpath('/settings/localRepository/text()').to_s
|
665
|
+
|
666
|
+
local_repo
|
667
|
+
end
|
668
|
+
|
669
|
+
|
670
|
+
def lookup(key)
|
671
|
+
# look up a module in the spec
|
672
|
+
@spec['modules'].each do |map|
|
673
|
+
if map.keys[0] == key
|
674
|
+
return map
|
675
|
+
end
|
676
|
+
end
|
677
|
+
|
678
|
+
nil
|
679
|
+
end
|
680
|
+
end
|
data/lib/version.rb
ADDED
data/sysbuild.gemspec
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "sysbuild"
|
8
|
+
spec.version = Sysbuild::VERSION
|
9
|
+
spec.authors = ["John Hawksley"]
|
10
|
+
spec.email = ["john.hawksley@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{Build a Maven non-reactor system}
|
13
|
+
spec.homepage = ""
|
14
|
+
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
17
|
+
f.match(%r{^(test|spec|features)/})
|
18
|
+
end
|
19
|
+
spec.bindir = "bin"
|
20
|
+
spec.executables = ['sysbuild']
|
21
|
+
spec.require_paths = ["lib"]
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.14"
|
24
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
25
|
+
spec.add_development_dependency "nexus", "~> 1.3.0"
|
26
|
+
|
27
|
+
spec.add_runtime_dependency 'require_all', '~> 1.3.3'
|
28
|
+
spec.add_runtime_dependency 'ruby-terminfo', '~> 0.1.1'
|
29
|
+
spec.add_runtime_dependency 'open4', '~> 1.3.4'
|
30
|
+
spec.add_runtime_dependency 'paint', '~> 2.0.0'
|
31
|
+
spec.add_runtime_dependency 'nokogiri', '~> 1.7.1'
|
32
|
+
spec.add_runtime_dependency 'text-table', '~> 1.2.4'
|
33
|
+
spec.add_runtime_dependency 'ruby-progressbar', '~> 1.8.1'
|
34
|
+
|
35
|
+
end
|
metadata
ADDED
@@ -0,0 +1,196 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sysbuild
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.3
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- John Hawksley
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-06-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.14'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.14'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: nexus
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 1.3.0
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.3.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: require_all
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.3.3
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 1.3.3
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: ruby-terminfo
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.1.1
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.1.1
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: open4
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 1.3.4
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 1.3.4
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: paint
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 2.0.0
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 2.0.0
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: nokogiri
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 1.7.1
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 1.7.1
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: text-table
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: 1.2.4
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: 1.2.4
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: ruby-progressbar
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - "~>"
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: 1.8.1
|
146
|
+
type: :runtime
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - "~>"
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: 1.8.1
|
153
|
+
description:
|
154
|
+
email:
|
155
|
+
- john.hawksley@gmail.com
|
156
|
+
executables:
|
157
|
+
- sysbuild
|
158
|
+
extensions: []
|
159
|
+
extra_rdoc_files: []
|
160
|
+
files:
|
161
|
+
- ".gitignore"
|
162
|
+
- ".ruby-gemset"
|
163
|
+
- ".ruby-version"
|
164
|
+
- Gemfile
|
165
|
+
- README.md
|
166
|
+
- Rakefile
|
167
|
+
- bin/sysbuild
|
168
|
+
- doc/snippets
|
169
|
+
- lib/change_detector.rb
|
170
|
+
- lib/sysbuild.rb
|
171
|
+
- lib/version.rb
|
172
|
+
- sysbuild.gemspec
|
173
|
+
homepage: ''
|
174
|
+
licenses: []
|
175
|
+
metadata: {}
|
176
|
+
post_install_message:
|
177
|
+
rdoc_options: []
|
178
|
+
require_paths:
|
179
|
+
- lib
|
180
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
181
|
+
requirements:
|
182
|
+
- - ">="
|
183
|
+
- !ruby/object:Gem::Version
|
184
|
+
version: '0'
|
185
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
186
|
+
requirements:
|
187
|
+
- - ">="
|
188
|
+
- !ruby/object:Gem::Version
|
189
|
+
version: '0'
|
190
|
+
requirements: []
|
191
|
+
rubyforge_project:
|
192
|
+
rubygems_version: 2.5.1
|
193
|
+
signing_key:
|
194
|
+
specification_version: 4
|
195
|
+
summary: Build a Maven non-reactor system
|
196
|
+
test_files: []
|