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,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