baltix 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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