baltix 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/ci.yml +44 -0
  3. data/.gitignore +10 -0
  4. data/Gemfile +8 -0
  5. data/LICENSE +8 -0
  6. data/README.md +60 -0
  7. data/Rakefile +8 -0
  8. data/TODO +84 -0
  9. data/baltix.gemspec +39 -0
  10. data/bin/console +14 -0
  11. data/bin/setup +8 -0
  12. data/exe/baltix +4 -0
  13. data/lib/baltix/actor/copy.rb +19 -0
  14. data/lib/baltix/actor/link.rb +20 -0
  15. data/lib/baltix/actor/spec.rb +25 -0
  16. data/lib/baltix/actor/touch.rb +17 -0
  17. data/lib/baltix/actor.rb +75 -0
  18. data/lib/baltix/cli.rb +173 -0
  19. data/lib/baltix/deps.rb +280 -0
  20. data/lib/baltix/dsl.rb +311 -0
  21. data/lib/baltix/extensions.rb +536 -0
  22. data/lib/baltix/i18n.rb +64 -0
  23. data/lib/baltix/loader/cmake.rb +11 -0
  24. data/lib/baltix/loader/git-version-gen.rb +36 -0
  25. data/lib/baltix/loader/mast.rb +139 -0
  26. data/lib/baltix/loader/pom.rb +27 -0
  27. data/lib/baltix/loader/rookbook.rb +26 -0
  28. data/lib/baltix/loader/yaml.rb +18 -0
  29. data/lib/baltix/loader.rb +192 -0
  30. data/lib/baltix/log.rb +73 -0
  31. data/lib/baltix/rake.rb +57 -0
  32. data/lib/baltix/scheme.erb.yaml +20 -0
  33. data/lib/baltix/source/base.rb +438 -0
  34. data/lib/baltix/source/fake.rb +17 -0
  35. data/lib/baltix/source/gem.rb +407 -0
  36. data/lib/baltix/source/gemfile.rb +35 -0
  37. data/lib/baltix/source/rakefile.rb +24 -0
  38. data/lib/baltix/source.rb +57 -0
  39. data/lib/baltix/space/spec.rb +11 -0
  40. data/lib/baltix/space.rb +424 -0
  41. data/lib/baltix/spec/rpm/name.rb +155 -0
  42. data/lib/baltix/spec/rpm/parser.rb +412 -0
  43. data/lib/baltix/spec/rpm/secondary.rb +170 -0
  44. data/lib/baltix/spec/rpm/spec_core.rb +580 -0
  45. data/lib/baltix/spec/rpm.erb +188 -0
  46. data/lib/baltix/spec/rpm.rb +822 -0
  47. data/lib/baltix/spec.rb +48 -0
  48. data/lib/baltix/version.rb +3 -0
  49. data/lib/baltix.rb +19 -0
  50. data/locale/en_US.UTF-8.yaml +27 -0
  51. data/locale/ru_RU.UTF-8.yaml +23 -0
  52. metadata +216 -0
@@ -0,0 +1,280 @@
1
+ require 'baltix'
2
+
3
+ class Baltix::Deps
4
+ attr_reader :project
5
+
6
+ REQS = {
7
+ 'lib' => {
8
+ proc { |target| target.source.compilable? } => proc { |this| this.deps_ruby_version },
9
+ proc { |target| target.source.valid? } => proc { |this, target| this.deps_dyno(target.source, 'lib', :dsl) },
10
+ },
11
+ 'bin' => {
12
+ proc { |target| target.public_executables.any? } => proc { |this, target| this.deps_ruby_exec(target) },
13
+ proc { |target| target.source.exefiles.any? &&
14
+ target.source.is_a?(Baltix::Source::Gem) } => proc { |this, target| this.deps_dyno(target.source, 'bin', :dsl) },
15
+ },
16
+ 'doc' => {
17
+ proc { |target| target.source.is_a?(Baltix::Source::Gem) } => proc { |this, target| this.deps_dyno(target.source, 'doc') },
18
+ },
19
+ 'devel' => {
20
+ proc { |target|
21
+ target.source.is_a?(Baltix::Source::Gem) &&
22
+ (target.source.inctree.any? ||
23
+ target.source.dsl.original_deps.any?) } => proc { |this, target| this.deps_dyno(target.source, 'devel', :dsl) },
24
+ }
25
+ }
26
+
27
+ PROVS = {
28
+ 'lib' => {
29
+ proc { |target| target.source.is_a?(Baltix::Source::Gem) } => proc { |this, target| this.deps_gem_ext(target.source) },
30
+ },
31
+ 'bin' => {
32
+ proc { |target| target.public_executables.any? } => proc { |this, target| this.deps_execs(target) },
33
+ },
34
+ }
35
+
36
+ def targets
37
+ if name = project.config.current_package_name
38
+ project.targets.select { |target| target.source.has_name?(name) }
39
+ else
40
+ project.targets
41
+ end
42
+ end
43
+
44
+ def target_provs target, sets_in = nil
45
+ sets = sets_in && [ sets_in ].flatten || PROVS.keys
46
+
47
+ PROVS.select { |set, _| sets.include?(set) }.map do |set, data|
48
+ provs = data.map do |cond_in, prov_in|
49
+ cond = cond_in.is_a?(Proc) ? cond_in[target] : cond_in
50
+ cond && (prov_in.is_a?(Proc) && prov_in[self, target] || prov_in) || []
51
+ end.flatten
52
+
53
+ [ set, provs ]
54
+ end.to_h
55
+ end
56
+
57
+ def target_reqs target, sets_in = nil
58
+ sets = sets_in && [ sets_in ].flatten || REQS.keys
59
+
60
+ #require 'pry'; binding.pry
61
+ REQS.select { |set, _| sets.include?(set) }.map do |set, data|
62
+ reqs = data.map do |cond_in, req_in|
63
+ cond = cond_in.is_a?(Proc) ? cond_in[target] : cond_in
64
+ cond && (req_in.is_a?(Proc) && req_in[self, target] || req_in) || []
65
+ end.flatten
66
+
67
+ [ set, reqs.uniq ]
68
+ end.to_h
69
+ end
70
+
71
+ ## deps
72
+ def deps_gem_dsl dsl, set = 'lib'
73
+ deps =
74
+ case set
75
+ when 'bin'
76
+ dsl.runtime_deps(:gemfile)
77
+ when 'devel'
78
+ dsl.development_deps(:gemspec)
79
+ else
80
+ dsl.runtime_deps(:gemspec)
81
+ end
82
+
83
+ list = []
84
+
85
+ deps.each do |dep|
86
+ list << (["#{prefix}(#{dep.name})"] | self.class.lower_to_rpm(dep.requirement)).join(" ")
87
+ end
88
+
89
+ if /lib|bin/ =~ set
90
+ list |=
91
+ dsl.required_ruby_version.requirements.map do |(cond, ver)|
92
+ self.class.lower_to_rpm(Gem::Requirement.new("#{cond} #{ver}"))
93
+ end.reject {|x| x.blank? }.map do |req|
94
+ [dsl.required_ruby] | req
95
+ end.map {|x| x.join(" ") }
96
+ list << "rubygems #{dsl.required_rubygems_version}"
97
+ end
98
+
99
+ list
100
+ end
101
+
102
+ def deps_ruby_version
103
+ # TODO enable when fix for new version ruby rebuld
104
+ #"ruby(#{RbConfig::CONFIG['ruby_version']})"
105
+ ""
106
+ end
107
+
108
+ def deps_gem source
109
+ ["gem(#{source.name})", source.version].compact.join(' = ')
110
+ end
111
+
112
+ def deps_gem_ext source
113
+ %w(gem).map do |kind|
114
+ "#{kind}(#{source.name}) = #{source.version}"
115
+ end
116
+ end
117
+
118
+ def deps_dyno source, set, kind = nil
119
+ root = project.config.dep_sources[set]
120
+ name = (root[source.name] || root[nil]).first
121
+ if name == 'auto'
122
+ kind == :dsl && deps_gem_dsl(source.dsl, set) || deps_gem(source)
123
+ else
124
+ project.select_source(name).map do |source|
125
+ deps_gem_dsl(source.dsl)
126
+ end
127
+ end
128
+ end
129
+
130
+ def deps_ruby_exec target
131
+ target.public_executables.map do |file|
132
+ File.join(target.root, file)
133
+ end.map do |file|
134
+ if File.symlink?(file)
135
+ realfile = File.readlink(file)
136
+ IO.read(File.join(target.root, realfile), mode: 'rb').split("\n").first
137
+ elsif File.exist?(file)
138
+ IO.read(file, mode: 'rb').split("\n").first
139
+ end
140
+ end.compact.uniq.map do |line|
141
+ if match = /#!\s*(?<exec>\S+)/.match(line)
142
+ match[:exec]
143
+ else
144
+ $stderr.puts "Invalid shebang line '#{line}'"
145
+ nil
146
+ end
147
+ end.uniq
148
+ end
149
+
150
+ def deps_execs target
151
+ target.public_executables
152
+ end
153
+
154
+ # common
155
+ def deps type, set = nil
156
+ $stderr.puts "* #{type} ->"
157
+
158
+ method = method("target_#{type}")
159
+
160
+ deps = targets.map do |target|
161
+ $stderr.puts " - [#{target.source.name}]"
162
+
163
+ target_deps = method[target, set].each do |set, deps|
164
+ if !deps.empty?
165
+ $stderr.puts " [#{set}]:"
166
+ deps.each do |dep|
167
+ $stderr.puts " #{dep}"
168
+ end
169
+ end
170
+ end
171
+
172
+ [ target.source.name, target_deps ]
173
+ end.to_h
174
+ end
175
+
176
+ def reqs
177
+ deps 'reqs', project.config.current_set
178
+ end
179
+
180
+ def provs
181
+ deps 'provs', project.config.current_set
182
+ end
183
+
184
+ class << self
185
+ def lower_to_rpm req
186
+ req.requirements.reduce([]) do |res, r|
187
+ merge(res, debound(r))
188
+ end
189
+ end
190
+
191
+ def upper_negate_to_rpm req
192
+ req.requirements.reduce([]) do |res, r|
193
+ merge(res, negate(r))
194
+ end
195
+ end
196
+
197
+ # TODO for requirement
198
+ # +debound+ crop upper limitation bound from the requirement rule
199
+ #
200
+ def debound req
201
+ ver = Gem::Version.new("#{req[1]}".gsub(/x/, '0'))
202
+
203
+ case req[0]
204
+ when "~>"
205
+ ['>=', ver.release]
206
+ when ">=", ">", "="
207
+ [req[0], ver.release]
208
+ when "!="
209
+ ['>', ver.release]
210
+ else
211
+ nil
212
+ end
213
+ end
214
+
215
+ # TODO for requirement
216
+ # +negate+ megates requirement rule
217
+ #
218
+ def negate req
219
+ ver = Gem::Version.new("#{req[1]}".gsub(/x/, '0'))
220
+
221
+ case req[0]
222
+ when "~>"
223
+ ['>=', ver.bump]
224
+ when "<"
225
+ ['>=', ver.release]
226
+ when "<="
227
+ ['>', ver.release]
228
+ else
229
+ nil
230
+ end
231
+ end
232
+
233
+ # TODO for requirement
234
+ # +merge+ enstricts requirement
235
+ # >= 4 & >= 5 => >= 5
236
+ # > 5 ^ > 4 => > 5
237
+ #
238
+ # > 5 & >= 4 => > 5
239
+ # > 4 & >= 4 => > 4
240
+ # > 4 & >= 4.x => >= 4.x
241
+ #
242
+ # >= 4 & > 4 => > 4
243
+ # >= 4 & > 5 => > 5
244
+ # >= 5 & > 4 => >= 5
245
+ #
246
+ MERGE_CONDS = {
247
+ ">=" => {
248
+ code: -1,
249
+ }
250
+ }
251
+
252
+ def merge req1, req2
253
+ return req1 if req2.blank?
254
+ return req2 if req1.blank?
255
+
256
+ m = [req1[1], req2[1]].max
257
+
258
+ if req1[0] == req2[0]
259
+ [req1[0], m]
260
+ elsif req1[0] == ">="
261
+ req1[1] <= req2[1] ? [">", m] : [">=", m]
262
+ elsif req1[0] == ">"
263
+ req1[1] >= req2[1] ? [">", m] : [">=", m]
264
+ elsif %w(= < <=).include?(req1[0])
265
+ # unsupported
266
+ req2
267
+ else
268
+ # unsupported
269
+ req1
270
+ end
271
+ end
272
+ end
273
+
274
+ protected
275
+
276
+ def initialize project: raise, options: {}
277
+ @project = project
278
+ @options = options
279
+ end
280
+ end
data/lib/baltix/dsl.rb ADDED
@@ -0,0 +1,311 @@
1
+ require 'bundler'
2
+ require 'fileutils'
3
+ require 'tempfile'
4
+
5
+ require 'baltix'
6
+
7
+ # DSL service for baltix.
8
+ class Baltix::DSL
9
+ # group to kind mapping
10
+ GROUP_MAPPING = {
11
+ default: :development,
12
+ integration: :development,
13
+ development: :development,
14
+ test: :development,
15
+ debug: :development,
16
+ production: :runtime,
17
+ true => :runtime,
18
+ }.reduce(Hash.new(:development)) {|r,(k,v)| r.merge(k => v) }
19
+
20
+ # attributes
21
+ attr_reader :source_file, :replace_list, :skip_list, :append_list, :spec
22
+
23
+ def gemfiles
24
+ return @gemfiles if @gemfiles
25
+
26
+ gemfiles = dsl.instance_variable_get(:@gemfiles) || []
27
+
28
+ @gemfiles = gemfiles.map {|g| g.is_a?(Pathname) && g || Pathname.new(g) }
29
+ end
30
+
31
+ def gemfile
32
+ gemfiles.first || original_gemfile || fake_gemfile_path
33
+ end
34
+
35
+ def original_gemfile
36
+ @original_gemfile ||= is_source_gemfile && Pathname.new(source_file) || find_gemfile
37
+ end
38
+
39
+ def is_source_gemfile
40
+ source_file =~ /Gemfile$/i
41
+ end
42
+
43
+ def find_gemfile
44
+ gemfile = source_file && Dir[File.join(File.dirname(source_file), '{Gemfile,gemfile}')].first
45
+
46
+ gemfile && Pathname.new(gemfile) || nil
47
+ end
48
+
49
+ def fake_gemfile_path
50
+ if !@fake_gemfile && @fake_gemfile ||= Tempfile.create('Gemfile')
51
+ @fake_gemfile_path = @fake_gemfile.path
52
+
53
+ Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", @fake_gemfile_path
54
+ @fake_gemfile.close
55
+ end
56
+
57
+ @fake_gemfile_path
58
+ end
59
+
60
+ def fake_gemlock_path
61
+ if !@fake_gemlock && @fake_gemlock ||= Tempfile.create('Gemfile.lock')
62
+ @fake_gemlock_path = @fake_gemlock.path
63
+
64
+ Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", @fake_gemlock_path
65
+ @fake_gemlock.close
66
+ end
67
+
68
+ @fake_gemlock_path
69
+ end
70
+
71
+ def dsl
72
+ @dsl ||= (
73
+ begin
74
+ dsl =
75
+ Dir.chdir(File.dirname(source_file)) do
76
+ dsl = Bundler::Dsl.new
77
+ dsl.eval_gemfile(original_gemfile)
78
+ dsl
79
+ end
80
+ rescue LoadError,
81
+ TypeError,
82
+ Bundler::GemNotFound,
83
+ Bundler::GemfileNotFound,
84
+ Bundler::VersionConflict,
85
+ Bundler::Dsl::DSLError,
86
+ Errno::ENOENT,
87
+ ::Gem::InvalidSpecificationException => e
88
+
89
+ dsl = Bundler::Dsl.new
90
+ dsl.instance_variable_set(:@gemfiles, [Pathname.new(fake_gemfile_path)])
91
+ dsl.to_definition(fake_gemlock_path, {})
92
+ Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", nil
93
+
94
+ dsl
95
+ end)
96
+ end
97
+
98
+ def edsl
99
+ @edsl ||= (
100
+ begin
101
+ edsl = dsl.dup
102
+ edsl.dependencies = deps_but(dsl.dependencies)
103
+ edsl
104
+ end)
105
+ end
106
+
107
+ def definition
108
+ @definition ||=
109
+ Dir.mktmpdir do
110
+ FileUtils.touch("Gemfile")
111
+
112
+ edsl.to_definition("./Gemfile", {})
113
+ end
114
+ end
115
+
116
+ def original_deps_for kinds_in = nil
117
+ groups = defined_groups_for(kinds_in)
118
+
119
+ original_deps.select do |dep|
120
+ (dep.groups & groups).any? &&
121
+ dep.should_include? # &&
122
+ # (dep.autorequire || [ true ]).all? { |r| r }
123
+ end
124
+ end
125
+
126
+ def original_deps
127
+ @original_deps ||= definition.dependencies.map do |dep|
128
+ type = dep.groups.map {|g| GROUP_MAPPING[g]}.compact.uniq.sort.first || dep.type
129
+ dep.instance_variable_set(:@type, type)
130
+ valid = !dep.source.is_a?(Bundler::Source::Path)
131
+
132
+ valid && dep || nil
133
+ end.compact
134
+ end
135
+
136
+ def gemspecs
137
+ spec ? [spec] : dsl.gemspecs
138
+ end
139
+
140
+ def extracted_gemspec_deps
141
+ gemspecs.map { |gs| gs.dependencies }.flatten.uniq
142
+ end
143
+
144
+ def extracted_gemspec_runtime_deps
145
+ gemspecs.map do |gs|
146
+ gs.dependencies.select {|dep|dep.runtime?}
147
+ end.flatten.uniq
148
+ end
149
+
150
+ def runtime_deps kind = :gemspec
151
+ if kind == :gemspec
152
+ deps_but(extracted_gemspec_runtime_deps)
153
+ else
154
+ deps_but(original_deps_for(:runtime))
155
+ end
156
+ end
157
+
158
+ def development_deps kind = :gemspec
159
+ deps_but(original_deps_for(:development))
160
+ end
161
+
162
+ def defined_groups_for kinds_in = nil
163
+ no_groups =
164
+ [kinds_in].compact.flatten.map do |k|
165
+ GROUP_MAPPING.map do |(g, k_in)|
166
+ k_in != k && g || nil
167
+ end.compact
168
+ end.flatten
169
+
170
+ definition.groups - no_groups
171
+ end
172
+
173
+ class << self
174
+ def merge_dependencies *depses
175
+ depses.reduce({}) do |res, deps|
176
+ deps.reduce(res.dup) do |r, x|
177
+ r[x.name] =
178
+ if r[x.name]
179
+ req = r[x.name].requirement.merge(x.requirement)
180
+
181
+ r[x.name].class.new(x.name, req, "type" => r[x.name].type)
182
+ else
183
+ x
184
+ end
185
+
186
+ r
187
+ end
188
+ end.values
189
+ end
190
+
191
+ def filter_dependencies type, *depses
192
+ depses.map { |deps| deps.select {|x|x.type == type }}
193
+ end
194
+ end
195
+
196
+ def dependencies type = nil
197
+ if type
198
+ self.class.merge_dependencies(*self.class.filter_dependencies(type, definition.dependencies, spec.dependencies))
199
+ else
200
+ self.class.merge_dependencies(definition.dependencies, spec.dependencies)
201
+ end
202
+ end
203
+
204
+ def deps
205
+ deps_but(original_deps) | gemspec_deps
206
+ end
207
+
208
+ def gemspec_deps
209
+ gemspecs.map do |gs|
210
+ version = gs.version || Gem::Version.new(0)
211
+ Gem::Dependency.new(gs.name, Gem::Requirement.new(["= #{version}"]), :development)
212
+ end
213
+ end
214
+
215
+ def deps_for kinds_in = nil
216
+ deps_but(original_deps_for(kinds_in)) | gemspec_deps
217
+ end
218
+
219
+ def ruby
220
+ { type: required_ruby, version: required_ruby_version }
221
+ end
222
+
223
+ def rubygems
224
+ { version: required_rubygems_version }
225
+ end
226
+
227
+ def valid?
228
+ gemfiles.any? {|g| g.eql?(original_gemfile) }
229
+ end
230
+
231
+ def to_ruby
232
+ spec = self.spec.dup
233
+ deps_in = deps_but(extracted_gemspec_deps)
234
+ deps = spec.dependencies.map {|x| deps_in.find {|a| a.name == x.name }}.compact
235
+ spec.dependencies.replace(deps)
236
+ spec.to_ruby
237
+ end
238
+
239
+ def to_gemfile
240
+ deps_but(original_deps).group_by { |d| d.name }.map do |name, deps|
241
+ reqs = deps.map do |dep|
242
+ reqs = dep.requirement.requirements.map {|r| "'#{r[0]} #{r[1]}'" }.join(", ")
243
+ end.join(", ")
244
+
245
+ dep = deps.first
246
+ autoreq = dep.respond_to?(:autorequire) &&
247
+ dep.autorequire &&
248
+ "require: #{dep.autorequire.any? &&
249
+ "[" + dep.autorequire.map { |r| r.inspect }.join(', ') + "]" ||
250
+ "false"}" || nil
251
+ groups = dep.respond_to?(:groups) && dep.groups || []
252
+ g = groups - [ :default ]
253
+ group_list = g.any? && "group: %i(#{groups.join("\n")})" || nil
254
+
255
+ [ "gem '#{name}'", reqs, autoreq, group_list ].compact.join(', ')
256
+ end.join("\n")
257
+ end
258
+
259
+ def required_rubygems_version
260
+ ">= 0"
261
+ end
262
+
263
+ def required_ruby_version
264
+ @required_ruby_version ||= Gem::Requirement.new(dsl.instance_variable_get(:@ruby_version)&.engine_versions || ">= 0")
265
+ end
266
+
267
+ def required_ruby
268
+ @required_ruby ||= dsl.instance_variable_get(:@ruby_version)&.engine || "ruby"
269
+ end
270
+
271
+ def merge_in other_dsl
272
+ if original_gemfile.to_s != other_dsl.original_gemfile.to_s
273
+ hodeps = other_dsl.original_deps.map {|dep| [dep.name, dep] }.to_h
274
+ original_deps.map {|dep| [dep.name, dep] }.to_h.deep_merge(hodeps).values.map do |dep|
275
+ if dep.is_a?(Array)
276
+ dep.reduce { |res, dep_in| res.merge(dep_in) }
277
+ else
278
+ dep
279
+ end
280
+ end
281
+ end
282
+
283
+ self
284
+ end
285
+
286
+ protected
287
+
288
+ def deps_but deps
289
+ deps.map do |dep|
290
+ next if skip_list.include?(dep.name)
291
+
292
+ new_req = replace_list.reduce(nil) do |s, (name, req)|
293
+ s || name == dep.name && req
294
+ end
295
+
296
+ new_req && Bundler::Dependency.new(dep.name, Gem::Requirement.new([new_req]), "type" => dep.type) || dep
297
+ end.compact | append_list
298
+ end
299
+
300
+ #
301
+ def initialize source_file, options = {}
302
+ # TODO source_file is null for Fake source
303
+ # raise unless source_file && File.file?(source_file)
304
+
305
+ @source_file = source_file
306
+ @spec = options[:spec]
307
+ @replace_list = options[:replace_list] || {}
308
+ @skip_list = options[:skip_list] || []
309
+ @append_list = options[:append_list] || []
310
+ end
311
+ end