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,139 @@
1
+ module Baltix::Loader::Mast
2
+ PROPS = {
3
+ name: :name,
4
+ version: :version,
5
+ date: :date,
6
+ authors: :authors,
7
+ email: ->(this) do
8
+ /(?<email>[^\s<]+@[^\s>]+)/ =~ this["contact"]
9
+ email
10
+ end,
11
+ summary: :summary,
12
+ description: :description,
13
+ homepage: :"resources.home", #->(this) { this["resources"]["home"] }
14
+ "metadata.homepage_uri": [
15
+ :"resources.code",
16
+ ->(this) { this['resources'].select {|x| x['type'] == 'home'}.first['uri'] if this['resources'].is_a?(Array) }
17
+ ],
18
+ "metadata.allowed_push_host": "https://rubygems.org",
19
+ "metadata.source_code_uri": [
20
+ :"resources.repo",
21
+ ->(this) { this['resources'].select {|x| x['type'] == 'code'}.first['uri'] if this['resources'].is_a?(Array) }
22
+ ],
23
+ files: ->(this) { this["manifest"].grep(/^[^#]/) },
24
+ bindir: "bin",
25
+ executables: ->(this) { this["manifest"].grep(/^bin\//).map {|b| b.split("/").last } },
26
+ require_paths: ["lib"],
27
+ extra_rdoc_files: ->(this) { this["manifest"].grep(/\.(rdoc|md)$/) },
28
+ licenses: ->(this) do
29
+ if license = this["manifest"].grep(/LICENSE/).first
30
+ lic = IO.read(license).split("\n")
31
+ if type = lic.reduce(nil) { |r, l| r || /(?<type>Apache|MIT)/ =~ l && type }
32
+ version = lic.reduce(nil) { |r, l| r || /Version (?<version>[\d\.]+)/ =~ l && version }
33
+ [[ type, version ].compact.join("-") ]
34
+ end
35
+ end
36
+ end,
37
+ test_files: ->(this) { this["manifest"].grep(/^(test|spec|feature)\//) },
38
+ required_ruby_version: nil,
39
+ _add_development_dependency: ->(this) do
40
+ if this['requires']
41
+ this["requires"].map { |line| [/^(?<req>[^\s(]+)/.match(line)["req"]] }
42
+ end
43
+ end,
44
+ _add_dependency_with_type: ->(this) do
45
+ if this['requirements']
46
+ this["requirements"].map do |dep|
47
+ [dep['name'], dep['development'] ? :development : :runtime, [transform_version(dep['version'])].compact]
48
+ end
49
+ end
50
+ end
51
+ }
52
+
53
+ def value_for value_in, data_in
54
+ case value_in
55
+ when Symbol
56
+ value_in.to_s.split(".").reduce(data_in) {|r, n| r.is_a?(Hash) || r.is_a?(Array) && n.is_a?(Integer) ? r[n] : nil }
57
+ when Proc
58
+ value_in[data_in]
59
+ when NilClass
60
+ when Array
61
+ value_in.reduce(nil) { |r, v| r || value_for(v, data_in) }
62
+ else
63
+ value_in
64
+ end
65
+ end
66
+
67
+ def manifest file_in
68
+ spec = nil
69
+ dir = File.dirname(file_in)
70
+ file1 = File.join(dir, "meta", "package")
71
+ file2 = File.join(dir, "meta", "profile")
72
+ file3 = File.join(dir, ".index")
73
+
74
+ if File.file?(file1) && File.file?(file2) || File.file?(file3)
75
+ spec=
76
+ Dir.chdir(dir) do
77
+ Gem::Specification.new do |s|
78
+ data =
79
+ if File.file?(file1) && File.file?(file2)
80
+ Kernel.yaml_load(IO.read(file1)).merge(
81
+ Kernel.yaml_load(IO.read(file2))).merge(
82
+ "manifest" => IO.read(file_in).split("\n"))
83
+ else
84
+ Kernel.yaml_load(IO.read(file3)).merge(
85
+ "manifest" => IO.read(file_in).split("\n"))
86
+ end
87
+
88
+ PROPS.each do |name, value_in|
89
+ if value = value_for(value_in, data)
90
+ method_name = /^(?:_(?<mname>[^\.]+)|(?<subname>[^\.]+\..+)|.*)/ =~ name.to_s
91
+ if mname
92
+ if value.is_a?(Array)
93
+ value.each { |v| s.send(mname, *v) }
94
+ else
95
+ s.send(mname, value)
96
+ end
97
+ elsif subname
98
+ path = subname.split(".")
99
+ path[0..-2].reduce(s) {|r, n| r.send(n) }.send(:[]=, path[-1], value)
100
+ else
101
+ s.send("#{name}=", value)
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
107
+
108
+ file = Tempfile.new(spec.name)
109
+ file.puts(spec.to_ruby)
110
+ file.close
111
+ res = app_file(file.path)
112
+ file.unlink
113
+ res
114
+ end
115
+ rescue Exception => e
116
+ $stderr.puts "WARN [#{e.class}]: #{e.message}"
117
+ end
118
+
119
+ class << self
120
+ def transform_version version
121
+ if version
122
+ /(?<number>[\d]+)(?<approx>[~><=])?/ =~ version
123
+ part1 =
124
+ case approx
125
+ when '~'
126
+ '~> '
127
+ when '>'
128
+ '>= '
129
+ when '<'
130
+ '<= '
131
+ when '='
132
+ '= '
133
+ end
134
+
135
+ [part1, number].join(' ')
136
+ end
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,27 @@
1
+ # POM xml based valid gemspec environment generation module
2
+ # example: "ovirt-engine-sdk" gem
3
+ # requires "xmllint" to work
4
+ #
5
+ module Baltix::Loader::Pom
6
+ def pom propfile
7
+ dir = File.dirname(propfile)
8
+
9
+ specfile = Dir.glob(File.join(dir, '*.gemspec')).first
10
+
11
+ re = /require.*?(?<version_file>[^"']+version[^"']*)/
12
+ version_line = Dir.glob(File.join(dir, '**', '*.rb')).map { |x| IO.read(x).split("\n").grep(re).first }.compact.first
13
+ return nil if !version_line or !specfile
14
+ version_file = re.match(version_line)[:version_file]
15
+ re_V = /(?<klass>[^\"\'\(\s]+)::VERSION/
16
+ match = re_V.match(IO.read(specfile).split("\n").grep(re_V).first.to_s)
17
+ if match
18
+ klass = match[:klass]
19
+ version = `xmllint pom.xml --xpath "/*[name()='project']/*[name()='version']/text()"`.strip
20
+ if version != ""
21
+ modtext = "module #{klass};VERSION = '#{version}';end"
22
+ File.open(File.join(dir, "lib", version_file), "w+") {|f| f.puts(modtext) }
23
+ end
24
+ end
25
+ rescue Errno::ENOENT
26
+ end
27
+ end
@@ -0,0 +1,26 @@
1
+ # Rookbook based gemspec detection module
2
+ #
3
+ module Baltix::Loader::Rookbook
4
+ def rookbook propfile
5
+ dir = File.dirname(propfile)
6
+
7
+ props = IO.read(propfile)
8
+ .split("\n")
9
+ .map do |line|
10
+ /^(?<key>[^:]+):\s*(?<value>.*)$/ =~ line
11
+ [ key, value ]
12
+ end
13
+ .to_h
14
+
15
+ specfile = Dir.glob(File.join(dir, '**', '*.gemspec')).first
16
+
17
+ # fix specfile
18
+ oldspec = IO.read(specfile)
19
+ newspec = oldspec.split("\n").map do |x|
20
+ props.reduce(x) { |x, (key, value)| x.gsub(/\$#{key}[: ]*\$/i, value) }
21
+ end
22
+ if oldspec != newspec
23
+ File.open(specfile, 'w+') {|file| file.puts newspec }
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,18 @@
1
+ # yaml gemspec generator based
2
+ # example: "lemon" gem
3
+ #
4
+ module Baltix::Loader::Yaml
5
+ def yaml file
6
+ spec = Gem::Specification.from_yaml(IO.read(file))
7
+
8
+ file = Tempfile.new(spec.name)
9
+ file.puts(spec.to_ruby)
10
+ file.close
11
+ res = app_file(file.path)
12
+ file.unlink
13
+ res
14
+ rescue => e
15
+ nil
16
+ end
17
+ end
18
+
@@ -0,0 +1,192 @@
1
+ require 'rake'
2
+
3
+ require 'baltix'
4
+ require 'baltix/log'
5
+
6
+ module Baltix::Loader
7
+ include Baltix::Log
8
+
9
+ module Certain
10
+ include Baltix::Log
11
+ include Rake::DSL
12
+
13
+ attr_reader :object_hash, :object_ids
14
+
15
+ alias_method :require_orig, :require
16
+
17
+ def require *args
18
+ require_orig(*args)
19
+ rescue LoadError
20
+ true
21
+ end
22
+
23
+ def store_object_hash type_hash
24
+ object_hash =
25
+ type_hash.map do |(klass, types)|
26
+ objects = types.split(',').map do |type|
27
+ begin
28
+ ObjectSpace.each_object(type.constantize).map { |h| h }
29
+ rescue NameError
30
+ []
31
+ end
32
+ end.flatten
33
+
34
+ [klass, objects]
35
+ end.to_h
36
+
37
+ if @object_hash
38
+ @object_ids = object_hash.map do |(k, oh)|
39
+ [k, oh.map {|h| h.__id__ } - @object_hash[k].map {|h| h.__id__ }]
40
+ end.to_h
41
+ end
42
+
43
+ @object_hash = object_hash
44
+ end
45
+
46
+ def load_file file, type_hash
47
+ # NOTE this forces not to share namespace but avoid exception when calling
48
+ # main space methods, see Rakefile of racc gem
49
+ # also named module is required instead of anonymous one to allow root level defined methods access
50
+ store_object_hash(type_hash)
51
+ value = nil
52
+
53
+ begin
54
+ push
55
+ Dir.chdir(File.dirname(file)) do
56
+ _file = File.basename(file).untaint
57
+ code = File.read(file, mode: 'r:UTF-8:-')
58
+ code.untaint
59
+
60
+ value =
61
+ begin
62
+ # evaluation required not to lost loaded object,
63
+ # the instance_eval is used in favor of eval to avoid lost predefined vars
64
+ # like for chef-utils gem
65
+ instance_eval(code, _file)
66
+ rescue Exception
67
+ # thrown for setup gem
68
+ load(File.basename(file), true)
69
+ end
70
+ end
71
+ rescue Exception => e
72
+ raise e
73
+ ensure
74
+ debug("value: #{value.inspect}")
75
+ pop
76
+ store_object_hash(type_hash)
77
+ end
78
+
79
+ self
80
+ rescue Exception => e
81
+ debug("[#{e.class}]: #{e.message}\n\t#{e.backtrace.join("\n\t")}")
82
+
83
+ self
84
+ end
85
+
86
+ def push
87
+ @paths = $:.dup
88
+ debug("Stored paths are: " + @paths.join("\n\t"))
89
+ end
90
+
91
+ def pop
92
+ debug("Subtract paths: " + ($: - @paths).join("\n\t"))
93
+ # NOTE this sequency of merging is required to correct loading libs leads
94
+ # to show warning and break building rdoc documentation
95
+ $:.replace(@paths | $:)
96
+ debug("Replaced paths with: " + $:.join("\n\t"))
97
+ end
98
+ end
99
+
100
+ def self.extended_list
101
+ @extended_list ||= []
102
+ end
103
+
104
+ def self.extended kls
105
+ extended_list << kls
106
+ end
107
+
108
+ def type_hash
109
+ @type_hash ||=
110
+ Baltix::Loader.extended_list.map do |kls|
111
+ type =
112
+ begin
113
+ kls.const_get('TYPE')
114
+ rescue
115
+ nil
116
+ end
117
+
118
+ [kls, type]
119
+ end.select {|(_, type)| type }.to_h
120
+ end
121
+
122
+ def pre_loaders
123
+ @pre_loaders ||=
124
+ Baltix::Loader.extended_list.map do |kls|
125
+ begin
126
+ kls.const_get('PRELOAD_MATCHER')&.map do |k, v|
127
+ [k, v.is_a?(Symbol) && kls.singleton_method(v) || v]
128
+ end.to_h || {}
129
+ rescue
130
+ {}
131
+ end
132
+ end.reduce {|res, hash| res.merge(hash) }
133
+ end
134
+
135
+ def mods
136
+ @@mods ||= {}
137
+ end
138
+
139
+ def load_file file
140
+ debug("Loading file: #{file}")
141
+ stdout = $stdout
142
+ stderr = $stderr
143
+ $stdout = $stderr = Tempfile.new('loader')
144
+
145
+ pre_loaders.each do |(m, preload_method)|
146
+ if file =~ m
147
+ args = [file][0...preload_method.arity]
148
+ preload_method[*args]
149
+ end
150
+ end
151
+
152
+ module_name = "M" + Random.srand.to_s
153
+ mod_code = <<-END
154
+ module #{module_name}
155
+ extend(::Baltix::Loader::Certain)
156
+ end
157
+ END
158
+
159
+ mod = module_eval(mod_code)
160
+ mod.load_file(file, type_hash)
161
+ $stdout.rewind
162
+ $stderr.rewind
163
+ log = $stdout.readlines
164
+ errlog = $stderr.readlines
165
+
166
+ OpenStruct.new(mod: mod, log: log, errlog: errlog, object_hash: mod.object_hash, diff_ids: mod.object_ids)
167
+ rescue Exception => e
168
+ warn(e.message)
169
+
170
+ OpenStruct.new(mod: mod, object_hash: {}, log: log, errlog: errlog, diff_ids: [])
171
+ ensure
172
+ $stderr = stderr
173
+ $stdout = stdout
174
+ end
175
+
176
+ def app_file file, &block
177
+ mods[file] ||= load_file(file)
178
+
179
+ mod = mods[file].dup
180
+ objects = mod.diff_ids[self]&.map {|id| ObjectSpace._id2ref(id) }
181
+
182
+ debug("Object ids for '#{file}' are: #{mod.diff_ids[self].inspect}")
183
+ debug("Objects for '#{file}' are: #{objects.inspect}")
184
+
185
+ if block_given?
186
+ objects = [yield(objects)].flatten.compact
187
+ end
188
+ mod.objects = objects || []
189
+
190
+ mod
191
+ end
192
+ end
data/lib/baltix/log.rb ADDED
@@ -0,0 +1,73 @@
1
+ module Baltix::Log
2
+ DEFAULT_IO_NAMES = {
3
+ none: nil,
4
+ error: 'stderr',
5
+ warn: 'stderr',
6
+ info: 'stderr',
7
+ debug: 'stderr',
8
+ }
9
+
10
+ DEFAULT_IO_NAMES.keys.each do |key|
11
+ define_method(key) {|message| log(key, message) if level_match(key) }
12
+ end
13
+
14
+ def log kind, message
15
+ Baltix::Log.ios[kind].puts("#{Baltix::Log.prefix[kind]}#{message}")
16
+ end
17
+
18
+ def level_match kind
19
+ Baltix::Log.ios[kind] && Baltix::Log.ios.keys.index(kind) <= Baltix::Log.ios.keys.index(Baltix::Log.level)
20
+ end
21
+
22
+ class << self
23
+ def prefix_for kind, prefix
24
+ @@prefix[kind] = prefix
25
+ end
26
+
27
+ def prefix
28
+ @@prefix ||= default_prefix(ios)
29
+ end
30
+
31
+ def default_prefix ios
32
+ ios.keys.map {|kind| [kind, "[baltix][#{kind.upcase}]> " ] }.to_h
33
+ end
34
+
35
+ def setup_kind kind, io
36
+ ios[kind] = io
37
+ end
38
+
39
+ def ios
40
+ @@ios ||= io_name_parse(DEFAULT_IO_NAMES)
41
+ end
42
+
43
+ def level
44
+ @@level ||= :info
45
+ end
46
+
47
+ def setup level = :info, io_names = DEFAULT_IO_NAMES, prefix = nil
48
+ @@ios = io_name_parse(io_names)
49
+ @@level = level
50
+ @@prefix = prefix || default_prefix(ios)
51
+ end
52
+
53
+ def io_name_parse io_names
54
+ io_names.map do |(kind, io_name)|
55
+ io =
56
+ case io_name
57
+ when '-', 'stdout'
58
+ $stdout
59
+ when '--', 'stderr'
60
+ $stderr
61
+ when '', nil
62
+ nil
63
+ else
64
+ File.open(io_name, 'a+')
65
+ end
66
+
67
+ [kind, io]
68
+ end.to_h
69
+ end
70
+
71
+ at_exit { (@@ios rescue {}).values.each {|v| v.close if v.is_a?(File) } }
72
+ end
73
+ end
@@ -0,0 +1,57 @@
1
+ # used in digest-crc gem as an extension compiler
2
+ #
3
+ require 'baltix/loader'
4
+
5
+ class Baltix::Rake
6
+ extend ::Baltix::Loader
7
+
8
+ class InvalidRakefileError < StandardError; end
9
+
10
+ TYPE = 'Rake::Application'
11
+ PRELOAD_MATCHER = { /\/rakefile(.rb)?$/i => :preload }
12
+
13
+ attr_reader :app, :rakefile, :options
14
+
15
+ def blank?
16
+ !@app
17
+ end
18
+
19
+ def present?
20
+ !!@app
21
+ end
22
+
23
+ def tasks
24
+ @tasks ||= @app&.tasks || []
25
+ end
26
+
27
+ def run_task task_name
28
+ if @app
29
+ Rake.instance_variable_set(:@application, @app)
30
+
31
+ Dir.chdir(@app.original_dir) do
32
+ @app.invoke_task(task_name)
33
+ end
34
+ end
35
+ rescue Exception => e
36
+ warn "#{e.class}: #{e.message}\n\t#{e.backtrace.join("\n\t")}"
37
+ end
38
+
39
+ def initialize rakefile, options = {}
40
+ raise InvalidRakefileError unless File.file?(rakefile)
41
+
42
+ @rakefile = rakefile
43
+ @options = options
44
+ @app = self.class.load(rakefile).objects.first
45
+ end
46
+
47
+ class << self
48
+ # preload callback
49
+ def preload
50
+ Rake.instance_variable_set(:@application, nil)
51
+ end
52
+
53
+ def load rakefile
54
+ app_file(rakefile)
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,20 @@
1
+ ---
2
+ - match: \.so$
3
+ proc:
4
+ - context:
5
+ source_dir: <%= File.join(target.source.root, dir) %>
6
+ target_dir: <%= target.dldir %>
7
+ target_prefix: <%= File.expand_path(config.install_prefix) %>
8
+ file: <%= file %>
9
+ actor: copy
10
+ - context:
11
+ source_dir: <%= target.dldir %>
12
+ target_dir: <%= File.join(target.require_libdir) %>
13
+ target_prefix: <%= File.expand_path(config.install_prefix) %>
14
+ file: <%= file %>
15
+ actor: link
16
+ - context:
17
+ target_dir: <%= target.dldir %>
18
+ target_prefix: <%= File.expand_path(config.install_prefix) %>
19
+ file: <%= File.join(File.dirname(file), 'gem.build_complete') %>
20
+ actor: touch