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,580 @@
1
+ require "json"
2
+
3
+ module Baltix::Spec::Rpm::SpecCore
4
+ URL_MATCHER = {
5
+ /(?<proto>https?:\/\/)?(?<user>[^\.]+).github.io\/(?<page>[^\/]+)/ => ->(m) do
6
+ "https://github.com/#{m["user"]}/#{m["page"]}.git"
7
+ end,
8
+ /(?<proto>https?:\/\/)?github.com\/(?<user>[^\/]+)\/(?<page>[^\/]+)/ => ->(m) do
9
+ "https://github.com/#{m["user"]}/#{m["page"]}.git"
10
+ end
11
+ }
12
+
13
+ def of_source name
14
+ source.send(name) || nil
15
+ rescue NameError
16
+ nil
17
+ end
18
+
19
+ def of_state name
20
+ state[name.to_s] || state[name.to_sym]
21
+ end
22
+
23
+ def of_options name
24
+ options[name]
25
+ end
26
+
27
+ def of_space name
28
+ space.respond_to?(name) ? space.send(name) : nil
29
+ end
30
+
31
+ def of_default name
32
+ default = self.class::STATE[name][:default]
33
+
34
+ default.is_a?(Proc) ? default[self] : default
35
+ end
36
+
37
+ def [] name
38
+ instance_variable_get(:"@#{name}")
39
+ end
40
+
41
+ def []= name, value
42
+ instance_variable_set(:"@#{name}", value)
43
+ end
44
+
45
+ def read_attribute name, seq = nil
46
+ aa = (seq || self.class::STATE[name][:seq]).reduce(nil) do |value_in, func|
47
+ # binding.pry if name == :context
48
+ if func[0] == "_"
49
+ send(func, value_in)
50
+ elsif value_in.blank?
51
+ send(func, name)
52
+ else
53
+ value_in
54
+ end
55
+ end
56
+ # binding.pry if name == :context
57
+ aa
58
+ end
59
+
60
+ def options= options
61
+ @options = options.to_os
62
+ end
63
+
64
+ def options
65
+ @options ||= {}.to_os
66
+ end
67
+
68
+ def state
69
+ @state ||= {}.to_os
70
+ end
71
+
72
+ def state= value
73
+ if value.name
74
+ @name = name.merge(value.name)
75
+ end
76
+
77
+ @state = value.to_os
78
+ end
79
+
80
+ def evr
81
+ "#{epoch ? "#{epoch}:" : ""}#{version}-#{release}"
82
+ end
83
+
84
+ def summary
85
+ summaries[Baltix::I18n.default_locale]
86
+ end
87
+
88
+ # +executable_name+ returns a name of the executable package, based on
89
+ # the all the sources executables.
90
+ #
91
+ # spec.executable_name # => foo
92
+ #
93
+ def executable_name
94
+ # TODO make smart selection of executable name
95
+ @executable_name =
96
+ if executables.size > 1
97
+ max = executables.map { |x| x.size }.max
98
+ exec_map = executables.map {|exec| (exec + " " * (max - exec.size)).unpack("U*") }
99
+ filter = [45, 46, 95]
100
+
101
+ exec_map.transpose.reverse.reduce([]) do |r, chars|
102
+ if (chars | filter).size == chars.size || ([ chars.first ] | chars).size == 1
103
+ r.concat([ chars.first ])
104
+ else
105
+ []
106
+ end
107
+ end.reverse.pack("U*")
108
+ else
109
+ executables.first&.gsub(/[_\.]/, '-') || ""
110
+ end
111
+ end
112
+
113
+ def prefix
114
+ name.class.default_prefix
115
+ end
116
+
117
+ protected
118
+
119
+ def _name value_in
120
+ return value_in if value_in.is_a?(Baltix::Spec::Rpm::Name)
121
+
122
+ (name, aliases) =
123
+ if is_exec? && executable_name.size >= 3
124
+ [ executable_name, executables ]
125
+ elsif executable_name.size < 3
126
+ [ value_in, executables ]
127
+ else
128
+ [ value_in, [] ]
129
+ end
130
+
131
+ Baltix::Spec::Rpm::Name.parse(name, kind: kind, prefix: options[:name_prefix], aliases: aliases)
132
+ end
133
+
134
+ def _local_rename value_in
135
+ # if name.support_name.blank? # || name.support_name == name
136
+ # if is_spec?
137
+
138
+ # setup support name if any host
139
+ value_in.support_name = host.name if host
140
+
141
+ if host&.source&.kind_of?(Baltix::Source::Gem) && !is_exec?
142
+ value_in.class.parse(value_in, prefix: value_in.class.default_prefix, support_name: value_in.support_name)
143
+ elsif host && (host.source.kind_of?(Baltix::Source::Gemfile) || host.source.kind_of?(Baltix::Source::Rakefile))
144
+ value_in.class.parse(value_in, support_name: value_in.support_name, name: value_in.support_name.original_fullname)
145
+ else
146
+ value_in
147
+ end
148
+ end
149
+
150
+ # returns list of depencecies and devel sources without dep to itself
151
+ def _devel _in = nil
152
+ dependencies.reject { |x| x.name === source.name } | devel_sources
153
+ end
154
+
155
+ def _devel_sources _in = nil
156
+ files.grep(/.*\.h(pp)?$/)
157
+ end
158
+
159
+ def _docs _in = nil
160
+ of_source(:docs) || of_default(:docs)
161
+ end
162
+
163
+ def _summaries value_in
164
+ source_name = source&.name
165
+ summaries_in = @host && host.summaries || of_source(:summaries) || {}.to_os
166
+
167
+ Baltix::I18n.locales.map do |locale_in|
168
+ locale = locale_in.blank? && Baltix::I18n.default_locale || locale_in
169
+ summary_pre = !%i(lib app).include?(self.kind) && summaries_in[locale_in] || value_in[locale] || value_in[locale_in] || nil
170
+ summary = summary_pre&.match("(.*?)[\-\.,_\s]*?$")&.[](1)
171
+
172
+ [ locale_in, Baltix::I18n.t(:"spec.rpm.#{self.kind}.summary", locale: locale, binding: binding) ]
173
+ end.to_os.compact
174
+ end
175
+
176
+ def _devel_requires value_in
177
+ value_tmp = value_in || source&.dependencies(:development) || []
178
+ deps_versioned = replace_versioning(value_tmp)
179
+
180
+ render_deps(append_versioning(deps_versioned))
181
+ end
182
+
183
+ def _devel_conflicts value_in
184
+ value_tmp = value_in || source&.dependencies(:development) || []
185
+ deps_versioned = replace_versioning(value_tmp)
186
+
187
+ render_deps(append_versioning(deps_versioned), :negate)
188
+ end
189
+
190
+ def _files _in
191
+ source&.spec&.files || []
192
+ rescue
193
+ []
194
+ end
195
+
196
+ def _proceed_description value_in
197
+ value_in.map { |_locale, desc| desc.is_a?(Array) ? desc.join("\n") : desc }
198
+ end
199
+
200
+ def _descriptions value_in
201
+ source_name = of_source(:name)
202
+ summary = of_source(:summary)&.match("(.*?)[\.,-_\s]+$")&.[](1) # NOTE required for eval
203
+ summaries_in = @host && summaries || { Baltix::I18n.default_locale => summary }
204
+ descriptions_in = @host && host.descriptions || of_source(:descriptions) || of_source(:summaries) || {}.to_os
205
+
206
+ Baltix::I18n.locales.map do |locale|
207
+ sum = Baltix::I18n.t(:"spec.rpm.#{self.kind}.description", locale: locale, binding: binding)
208
+
209
+ [ locale, sum ]
210
+ end.to_os.map do |locale_in, summary_in|
211
+ if locale_in.to_s == Baltix::I18n.default_locale
212
+ if !%i(lib app).include?(self.kind)
213
+ summary_in = summaries_in[locale_in]
214
+ first = summary_in && (summary_in + ".")
215
+ rest_in = descriptions_in[locale_in]
216
+ /(?<re>.*)\.$/ =~ rest_in
217
+ rest = first&.include?(re || rest_in || "") ? nil : rest_in
218
+ [ first, rest ].compact.join("\n\n")
219
+ else
220
+ value_in[locale_in] || descriptions_in[locale_in]
221
+ end
222
+ else
223
+ summary_in = summaries_in[locale_in]
224
+ /(?<s>.+)\.?$/ =~ summary_in && s && "#{s}." || value_in[locale_in]
225
+ end
226
+ end.compact
227
+ end
228
+
229
+ def _format_descriptions value_in
230
+ value_in.map do |name, desc|
231
+ tdesc = desc.gsub(/\n{2,}/, "\x1F\x1F").gsub(/\n([\*\-])/, "\x1F\\1").gsub(/\n/, "\s")
232
+ new_desc =
233
+ tdesc.split(/ +/).reduce([]) do |res, token|
234
+ line = res.last
235
+ uptoken = token.gsub(/(\n[^\-\*])/, "\n\\1").strip
236
+ temp = [ line, uptoken ].reject { |x| x.blank? }.join(" ")
237
+
238
+ if temp.size > 80 || !line
239
+ res << uptoken
240
+ else
241
+ line.replace(temp)
242
+ end
243
+
244
+ postline = res.last.split(/\x1F/, -1)
245
+ if postline.size > 1
246
+ res.last.replace(postline[0].strip)
247
+ res.concat(postline[1..-1].map(&:strip))
248
+ end
249
+
250
+ res
251
+ end.join("\n")
252
+
253
+ new_desc
254
+ end
255
+ end
256
+
257
+ def _version value_in
258
+ reversion = gem_versionings.select {|n,v| name.eql?(n, true) }.to_h.values.first
259
+ value = reversion || value_in
260
+
261
+ v=
262
+ case value
263
+ when Gem::Version
264
+ value
265
+ when Gem::Dependency
266
+ value.requirement.requirements.first.last
267
+ when Array
268
+ Gem::Version.new(value.first.to_s)
269
+ else
270
+ Gem::Version.new(value.to_s)
271
+ end
272
+
273
+ # TODO move reversion to space/sources
274
+ # here is a workaround only
275
+ # reversion to support newer ones
276
+ if name.support_name.blank? # || name.support_name == name
277
+ if is_spec?
278
+ (count, (version, sources_tmp)) =
279
+ sources.group_by do |s|
280
+ s.version ? Gem::Version.new(s.version) : v
281
+ end.map do |(x, y)|
282
+ [y.count, [x, y]]
283
+ end.sort do |(x1, (v1, _)), (x2, (v2, _))|
284
+ s = x1 <=> x2
285
+
286
+ s == 0 ? v1 <=> v2 : s
287
+ end.last
288
+
289
+ version = reversion.requirement.requirements.first.last if reversion && (sources_tmp.map(&:name) & [reversion.name]).any?
290
+
291
+ #binding.pry
292
+ sources.count <= count * 2 ? version : v
293
+ elsif source.respond_to?(:spec)
294
+ #binding.pry
295
+ source.spec.version
296
+ elsif spec
297
+ #binding.pry
298
+ spec.version # TODO как отличить?
299
+ end
300
+ elsif host
301
+ host.version
302
+ else
303
+ v
304
+ end
305
+ end
306
+
307
+ def is_spec?
308
+ self.respond_to?(:space)
309
+ end
310
+
311
+ def is_host?
312
+ !self.respond_to?(:host)
313
+ end
314
+
315
+ def _readme _in
316
+ files.grep(/(readme|чтимя).*/i).group_by {|x| File.basename(x) }.map {|(name, a)| a.first }.join(" ")
317
+ end
318
+
319
+ def _requires_plain_only value_in
320
+ @requires_plain_only ||= value_in&.reject {|dep| dep.match(/gem\((.*)\) ([>=<]+) ([\w\d\.\-]+)/) }
321
+ end
322
+
323
+ def _conflicts_plain_only value_in
324
+ @conflicts_plain_only ||= value_in&.reject {|dep| dep.match(/gem\((.*)\) ([>=<]+) ([\w\d\.\-]+)/) }
325
+ end
326
+
327
+ def _pre_name value_in
328
+ return value_in if value_in.is_a?(Baltix::Spec::Rpm::Name)
329
+
330
+ name = @name ||
331
+ of_options(:name) ||
332
+ of_state(:name) ||
333
+ rootdir && rootdir.split("/").last ||
334
+ value_in
335
+
336
+ if name.is_a?(Baltix::Spec::Rpm::Name)
337
+ name
338
+ else
339
+ Baltix::Spec::Rpm::Name.parse(name, prefix: options[:name_prefix])
340
+ end
341
+ end
342
+
343
+ def _requires value_in
344
+ deps_pre =
345
+ if %i(lib app).include?(self.kind)
346
+ source&.dependencies(:runtime) || []
347
+ else
348
+ reqs = self.kind == :devel && devel_requires || []
349
+
350
+ [ host.is_app? ? "#{host.name} = #{host.evr}" : provide_dep ].compact | reqs
351
+ end
352
+
353
+ deps = replace_versioning(deps_pre | value_in)
354
+
355
+ render_deps(deps)
356
+ end
357
+
358
+ def _conflicts value_in
359
+ deps_pre =
360
+ if %i(lib app).include?(self.kind)
361
+ source&.dependencies(:runtime) || []
362
+ else
363
+ reqs = self.kind == :devel && devel_conflicts || []
364
+ end
365
+
366
+ deps = replace_versioning(deps_pre | value_in)
367
+
368
+ render_deps(deps, :negate)
369
+ end
370
+
371
+ # +replace_versioning+ replaces version of the +external+ libraties to align the any requires.
372
+ # It is not affects to an in-sourced gem/lib versions
373
+ def replace_versioning deps_in
374
+ versioning_list = available_gem_ranges # NOTE removed merge with gem_versionings
375
+ # versioning_list = available_gem_ranges.merge(gem_versionings)
376
+
377
+ deps_in.map do |dep_in|
378
+ if dep_in.is_a?(Gem::Dependency) && provide_dep&.name != dep_in.name
379
+ dep = versioning_list[dep_in.name]
380
+
381
+ if dep
382
+ combine_deps(dep_in, dep)
383
+ else
384
+ dep_in
385
+ end
386
+ else
387
+ dep_in
388
+ end
389
+ end
390
+ end
391
+
392
+ # +combine_deps+ method combines dependenies' requirements passed with arguments +base_dep+, and +dep+ base on
393
+ # the operators in +base_dep+
394
+ # Example:
395
+ # combine_deps(base_dep, dep)
396
+ #
397
+ def combine_deps base_dep, dep
398
+ dep_ver = Gem::Dependency.new(base_dep.name, base_dep.requirement | dep.requirement)
399
+ ops = base_dep.requirement.requirements.map {|x| x.first }.join(" ").gsub(/\A(~>|=)\z/, ">= < =").split(" ").uniq
400
+ reqs = dep_ver.requirement.requirements.select {|x| ops.include?(x[0]) }
401
+
402
+ dep_ver.requirement.requirements.replace(reqs)
403
+
404
+ dep_ver
405
+ end
406
+
407
+ def append_versioning deps_in
408
+ gem_versionings.reduce(deps_in) do |deps, name, dep|
409
+ index = deps.index { |dep_in| dep_in.is_a?(Gem::Dependency) && dep_in.name == name.to_s }
410
+
411
+ #binding.pry
412
+ index && deps || deps | [ dep ]
413
+ end
414
+ end
415
+
416
+ def variables
417
+ @variables ||= context.__macros || {}.to_os
418
+ end
419
+
420
+ def render_deps deps_in, mode = :debound
421
+ func = mode == :debound ? :lower_to_rpm : :upper_negate_to_rpm
422
+
423
+ deps_in.reduce([]) do |deps, dep|
424
+ deps |
425
+ if dep.is_a?(Gem::Dependency)
426
+ deph = Baltix::Deps.send(func, dep.requirement)
427
+
428
+ deph.blank? ? [] : ["#{prefix}(#{dep.name}) #{deph.first} #{deph.last}"]
429
+ else
430
+ name = Baltix::Spec::Rpm::Name.parse(dep)
431
+ deps_in.find do |dep_in|
432
+ if dep_in.is_a?(Gem::Dependency)
433
+ dep_in.name == name.name
434
+ end
435
+ end && [] || [ dep ]
436
+ end
437
+ end
438
+ end
439
+
440
+ def provide_dep
441
+ return @provide_dep if @provide_dep
442
+
443
+ name_tmp = source ? Baltix::Spec::Rpm::Name.parse(source.provide.name) : name
444
+ provide_dep_pre = gem_versionings.select {|n,v| name_tmp.eql?(n, true) }.to_h.values.first || source&.provide || space.name
445
+ @provide_dep = Gem::Dependency.new(provide_dep_pre.name, version)
446
+ end
447
+
448
+ def _provides value_in
449
+ stated_name = of_state(:name)
450
+ #binding.pry
451
+
452
+ provides =
453
+ if stated_name && stated_name.prefix != name.prefix && stated_name.original_fullname != name.fullname && %i(lib app).include?(self.kind)
454
+ # TODO optionalize defaults
455
+ [[ stated_name.prefix, stated_name.name ].compact.join("-") + " = %EVR"]
456
+ else
457
+ []
458
+ end | value_in
459
+
460
+ provides |
461
+ case self.kind
462
+ when :lib
463
+ render_deps([provide_dep].compact)
464
+ else
465
+ []
466
+ end
467
+ end
468
+
469
+ def _obsoletes value_in
470
+ obsoletes = value_in.dup
471
+ stated_name = of_state(:name)
472
+
473
+ if stated_name && stated_name.prefix != name.prefix && stated_name.original_fullname != name.fullname && %i(lib app).include?(self.kind)
474
+ # TODO optionalize defaults
475
+ obsoletes.unshift([ stated_name.prefix, stated_name.name ].compact.join("-") + " < %EVR")
476
+ end
477
+
478
+ obsoletes
479
+ end
480
+
481
+ def _available_gem_list value_in
482
+ value_in || options.available_gem_list || of_default(:available_gem_list)
483
+ end
484
+
485
+ def _available_gem_ranges value_in
486
+ available_gem_list.reduce({}.to_os) do |res, (name, version_in)|
487
+ low = [ version_in ].flatten.map {|v| Gem::Version.new(v) }.min
488
+ bottom = [ version_in ].flatten.map {|v| Gem::Version.new(v.split(".")[0..1].join(".")).bump }.max
489
+ reqs = [ ">= #{low}", "< #{bottom}" ]
490
+
491
+ res[name] = Gem::Dependency.new(name, Gem::Requirement.new(reqs))
492
+
493
+ res
494
+ end
495
+ end
496
+
497
+ def _filter_out_obsolete value_in
498
+ value_in.reject do |value|
499
+ !use_gem_obsolete_list.[](value.match(/^(?<name>[^\s]+)/)[:name]).nil?
500
+ end
501
+ end
502
+
503
+ def dep_list_merge first_in, second_in
504
+ first = first_in || {}.to_os
505
+ second = second_in || {}.to_os
506
+ a=
507
+ first.reduce(second) do |r, name, req|
508
+ if r[name]
509
+ r[name] = r[name].merge(req)
510
+
511
+ r
512
+ else
513
+ r.merge({ name => req }.to_os)
514
+ end
515
+ end
516
+ #binding.pry
517
+ a
518
+ end
519
+
520
+ def dep_list_intersect *lists_in
521
+ lists = lists_in.map {|list| list.to_os }
522
+
523
+ lists.reduce do |r_list, list|
524
+ list.reduce(r_list) do |r, name, req|
525
+ if r[name]
526
+ r[name] = Gem::Dependency.new("rake", req.requirement | r[name].requirement)
527
+
528
+ r
529
+ else
530
+ r.merge({ name => req }.to_os)
531
+ end
532
+ end
533
+ end
534
+ end
535
+
536
+ def _gem_versionings value_in
537
+ pre_vers =
538
+ [ variables.gem_replace_version ].flatten.compact.reduce({}.to_os) do |res, gemver|
539
+ /^(?<name>[^\s]+)(?:\s(?<rel>[<=>~]+)\s(?<version>[^\s]+))?/ =~ gemver
540
+
541
+ if res[name]
542
+ res[name].requirement.requirements << [rel, Gem::Version.new(version)]
543
+ else
544
+ res[name] = Gem::Dependency.new(name, Gem::Requirement.new(["#{rel} #{version}"]))
545
+ end
546
+
547
+ res
548
+ end
549
+
550
+ dep_list_merge(value_in, pre_vers)
551
+ end
552
+
553
+ # def parse_options options_in
554
+ # options_in&.each do |name, value_in|
555
+ # value =
556
+ # if name == "secondaries"
557
+ # value_in.map { |_name, sec| Secondary.new(spec: self, options: sec) }
558
+ # else
559
+ # ::JSON.parse value_in.to_json, object_class: OpenStruct
560
+ # end
561
+ #
562
+ # instance_variable_set(:"@#{name}", value)
563
+ # end
564
+ # end
565
+
566
+ class << self
567
+ def included obj
568
+ obj::STATE.each do |name, opts|
569
+ obj.define_method(name) { self[name] ||= read_attribute(name, opts[:seq]) || of_default(name) }
570
+ #obj.define_method("_#{name}") { of_state[name] }
571
+ obj.define_method("has_#{name}?") { !read_attribute(name, opts["seq"]).blank? }
572
+
573
+ end
574
+
575
+ %w(lib exec doc devel app).each do |name|
576
+ obj.define_method("is_#{name}?") { self.kind.to_s == name }
577
+ end
578
+ end
579
+ end
580
+ end