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