bubing 0.0.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 05a902c19d0555ec614c68bd6711d4a47fb4e8fe
4
+ data.tar.gz: 0c02b9af4fed83709f4f19612179c7bd7f142cb2
5
+ SHA512:
6
+ metadata.gz: 0c36fe6f2a4e9e8c898a645b98e49bedfa53a6ea4a63cf4916c1423b629c3788ed79ea2e82c91f7799395c733b2906e1f4a4e447b5a03648eb3a7f5a2af18acb
7
+ data.tar.gz: aade555ff9aff1256e69fe8dbfee3ce082ab120c887275148e331b0c74185920427487c989e8128fb85bd8e55f0a15dcd71980819fff3aa5e545f6bb2308751c
data/bin/bubing ADDED
@@ -0,0 +1,73 @@
1
+ #!/bin/env ruby
2
+
3
+ require 'optparse'
4
+ require 'bubing'
5
+
6
+ options = {}
7
+ options[:plugins] = []
8
+ options[:plugin_dirs] = []
9
+
10
+ options[:files] = []
11
+ options[:file_dirs] = []
12
+
13
+ options[:ld_paths] = []
14
+ options[:envs] = []
15
+
16
+ OptionParser.new do |opts|
17
+ opts.banner = 'Usage: bubing [options] BINARY DIRECTORY'
18
+
19
+ opts.on('-v', '--[no-]verbose', 'Run verbosely') do |v|
20
+ options[:verbose] = v
21
+ end
22
+
23
+ opts.on('-p', '--plugin LIBRARY',
24
+ 'Add not linked library, eg plugin') do |plugin|
25
+ options[:plugins] << plugin
26
+ end
27
+
28
+ opts.on('-P', '--plugin_directory PATH',
29
+ 'Add directory with additional libs, eg plugin directory') do |plugin_dir|
30
+ options[:plugin_dirs] << plugin_dir
31
+ end
32
+
33
+ opts.on('-f', '--file FILE=PATH',
34
+ 'Add additional file, eg config') do |file|
35
+ options[:files] << file
36
+ end
37
+
38
+ opts.on('-F', '--file_directory PATH=PATH',
39
+ 'Add directory with additional files, eg configs') do |file_dir|
40
+ options[:file_dirs] << file_dir
41
+ end
42
+
43
+ opts.on('-L', '--ld_path PATH',
44
+ 'Look dependencies in PATH') do |ld_path|
45
+ options[:ld_paths] << ld_path
46
+ end
47
+
48
+ opts.on('-e', '--env VAR=VAL',
49
+ 'Add environment variable to run.sh') do |env|
50
+ options[:envs] << env
51
+ end
52
+ end.parse!
53
+
54
+ if ARGV.count < 2
55
+ puts 'You must specify binary for bundling and output directory!'
56
+ exit(1)
57
+ end
58
+
59
+ directory = File.absolute_path(ARGV.pop)
60
+ filename = File.absolute_path(ARGV.pop)
61
+
62
+ unless File.exist?(filename)
63
+ puts "#{filename} does not exists!"
64
+ exit(1)
65
+ end
66
+
67
+ puts "Bundling #{filename} to #{directory}" if options[:verbose]
68
+
69
+ begin
70
+ Bubing::BundlerFactory.new.build(filename, directory, **options).bundle!
71
+ rescue Bubing::BundlingError
72
+ exit(1)
73
+ end
data/lib/bubing.rb ADDED
@@ -0,0 +1,8 @@
1
+ require 'bubing/binary_info'
2
+ require 'bubing/bundler.rb'
3
+ require 'bubing/executable_bundler'
4
+ require 'bubing/shared_object_bundler'
5
+ require 'bubing/bundler_factory'
6
+
7
+ module Bubing
8
+ end
@@ -0,0 +1,61 @@
1
+ module Bubing
2
+ class UnknownInterpreter < StandardError
3
+ end
4
+
5
+ class UnknownType < StandardError
6
+ end
7
+
8
+ class BinaryInfo
9
+ X86_32_RE = /ELF 32-bit/
10
+ X86_64_RE = /ELF 64-bit/
11
+
12
+ EXECUTABLE_RE = /LSB executable/
13
+ SHARED_OBJECT_RE = /LSB shared object/
14
+
15
+ X86_32_INTERPRETER = 'ld-linux.so'.freeze
16
+ X86_64_INTERPRETER = 'ld-linux-x86-64.so'.freeze
17
+
18
+ attr_reader :interpreter, :type
19
+
20
+ def initialize(binary)
21
+ @binary = binary
22
+ @file_output = `file #{@binary}`
23
+ @interpreter = detect_interpreter
24
+ @type = detect_type
25
+ end
26
+
27
+ private
28
+
29
+ def detect_type
30
+ case @file_output
31
+ when EXECUTABLE_RE
32
+ :executable
33
+ when SHARED_OBJECT_RE
34
+ :shared_object
35
+ else
36
+ raise Bubing::UnknownType
37
+ end
38
+ end
39
+
40
+ def detect_interpreter
41
+ case @file_output
42
+ when X86_32_RE
43
+ x86_32_interpreter
44
+ when X86_64_RE
45
+ x86_64_interpreter
46
+ else
47
+ raise Bubing::UnknownInterpreter
48
+ end
49
+ end
50
+
51
+ def x86_32_interpreter
52
+ libs = Dir['/lib/*']
53
+ libs.detect { |l| l.include?(X86_32_INTERPRETER) }
54
+ end
55
+
56
+ def x86_64_interpreter
57
+ libs = Dir['/lib/*']
58
+ libs.detect { |l| l.include?(X86_64_INTERPRETER) }
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,115 @@
1
+ require 'fileutils'
2
+
3
+ module Bubing
4
+ class DependencyNotFoundError < StandardError
5
+ end
6
+
7
+ class BundlingError < StandardError
8
+ end
9
+
10
+ class Bundler
11
+ PATH_RE = /=> (.+?(?=\())/
12
+
13
+ def initialize(binary, directory, interpreter:, plugins: [], plugin_dirs: [], files: [], file_dirs: [], ld_paths: [], envs: [], verbose: false)
14
+ @binary = binary
15
+ @directory = directory
16
+ @plugins = plugins
17
+ @plugin_dirs = plugin_dirs
18
+ @files = files
19
+ @file_dirs = file_dirs
20
+ @verbose = verbose
21
+ @interpreter = interpreter
22
+ @lib_dir = File.join(directory, 'lib')
23
+ @ld_paths = ld_paths
24
+
25
+ @copied = []
26
+ end
27
+
28
+ def bundle!
29
+ prepare_dir
30
+ log("Interpreter is #{@interpreter}")
31
+ copy_deps(@binary)
32
+ log('Copying plugins...')
33
+ log("Plugins to bundle #{@plugins.count}")
34
+ copy_plugins(@plugins)
35
+ log("Plugin dirs to bundle #{@plugin_dirs.count}")
36
+ copy_plugin_dirs
37
+ log('Copying files...')
38
+ log("Files to bundle #{@files.count}")
39
+ copy_files(@files)
40
+ log("File dirs to bundle #{@file_dirs.count}")
41
+ copy_files(@file_dirs)
42
+ rescue Bubing::DependencyNotFoundError => e
43
+ puts "#{e.message} not found!"
44
+ raise Bubing::BundlingError
45
+ end
46
+
47
+ protected
48
+
49
+ def prepare_dir
50
+ FileUtils.rm_rf(Dir.glob(File.join(@directory, '*')))
51
+ FileUtils.mkdir_p(@directory)
52
+ FileUtils.mkdir_p(@lib_dir)
53
+ end
54
+
55
+ def log(message)
56
+ puts message if @verbose
57
+ end
58
+
59
+ def extract_path(lib)
60
+ if lib.include?('not found')
61
+ raise DependencyNotFoundError.new(lib.split('=>')[0].strip)
62
+ end
63
+ File.absolute_path(PATH_RE.match(lib)[1].strip)
64
+ end
65
+
66
+ def get_deps(file)
67
+ ld_lib_path = if @ld_paths.any?
68
+ "LD_LIBRARY_PATH=#{@ld_paths.join(':')}"
69
+ else
70
+ ''
71
+ end
72
+ trace = `#{ld_lib_path} LD_TRACE_LOADED_OBJECTS=1 #{@interpreter} #{file}`
73
+ trace.split("\n").map(&:strip).select{|row| row.include?('=>')}.map{|dep| extract_path(dep)}
74
+ end
75
+
76
+ def copy_deps(binary)
77
+ log("Bundling #{binary}")
78
+ deps = get_deps(binary)
79
+ log("#{deps.count} dependencies found")
80
+ copy(deps, @lib_dir)
81
+ end
82
+
83
+ def copy(files, dst)
84
+ files = [files].flatten.select{|f| !@copied.include?(f)}
85
+ FileUtils.cp_r(files, dst)
86
+ @copied += files
87
+ @copied.flatten
88
+ end
89
+
90
+ def copy_plugins(plugins)
91
+ plugins.each do |plugin|
92
+ copy(plugin, @lib_dir)
93
+ copy_deps(plugin)
94
+ end
95
+ end
96
+
97
+ def copy_plugin_dirs
98
+ @plugin_dirs.each do |plugin_dir|
99
+ copy(plugin_dir, @lib_dir)
100
+ plugins = Dir[File.join(plugin_dir, '/**/*.so')]
101
+ copy_plugins(plugins)
102
+ end
103
+ end
104
+
105
+ def copy_files(files)
106
+ files.each do |file|
107
+ file, dst = file.split('=')
108
+ dst = File.join(@directory, dst)
109
+
110
+ FileUtils.mkdir_p(dst)
111
+ copy(file, dst)
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,14 @@
1
+ module Bubing
2
+ class BundlerFactory
3
+ def build(filename, directory, **options)
4
+ info = Bubing::BinaryInfo.new(filename)
5
+ options[:interpreter] = info.interpreter
6
+ case info.type
7
+ when :executable
8
+ Bubing::ExecutableBundler.new(filename, directory, **options)
9
+ when :shared_object
10
+ Bubing::SharedObjectBundler.new(filename, directory, **options)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,48 @@
1
+ module Bubing
2
+ class ExecutableBundler < Bubing::Bundler
3
+ RUN_TEMPLATE = '%{envs} ./lib/%{interpreter} ./bin/%{binary}'
4
+
5
+ def initialize(binary, directory, interpreter:, plugins: [], plugin_dirs: [], files: [], file_dirs: [], ld_paths: [], envs: [], verbose: false)
6
+ super
7
+ @bin_dir = File.join(@directory, 'bin')
8
+
9
+ @envs = envs.each_with_object({}) do |env, h|
10
+ k, v = env.split('=')
11
+ h[k] = v
12
+ end
13
+ if @envs['LD_LIBRARY_PATH'].nil?
14
+ @envs['LD_LIBRARY_PATH'] = './lib'
15
+ end
16
+ end
17
+
18
+ def bundle!
19
+ super
20
+ copy(@interpreter, @lib_dir)
21
+ copy(@binary, @bin_dir)
22
+ log('Preparing run.sh...')
23
+ run_file = make_run
24
+
25
+ FileUtils.chmod('+x', run_file)
26
+ end
27
+
28
+ def make_run
29
+ run_file = File.join(@directory, 'run.sh')
30
+ envs = @envs.each_with_object([]) do |(k, v), ary|
31
+ ary << "#{k}=#{v}"
32
+ end.join(' ')
33
+ run = RUN_TEMPLATE % {envs: envs, interpreter: File.basename(@interpreter), binary: File.basename(@binary)}
34
+ File.open(run_file, 'w') do |file|
35
+ file.write("#!/bin/bash\n")
36
+ file.write("#{run}\n")
37
+ end
38
+ run_file
39
+ end
40
+
41
+ protected
42
+
43
+ def prepare_dir
44
+ super
45
+ FileUtils.mkdir_p(@bin_dir)
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,8 @@
1
+ module Bubing
2
+ class SharedObjectBundler < Bubing::Bundler
3
+ def bundle!
4
+ super
5
+ copy(@binary, @lib_dir)
6
+ end
7
+ end
8
+ end
metadata ADDED
@@ -0,0 +1,50 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bubing
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Gleb Sinyavsky
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-05-07 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Script for bundling linux binaries
14
+ email: zhulik.gleb@gmail.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - bin/bubing
20
+ - lib/bubing.rb
21
+ - lib/bubing/binary_info.rb
22
+ - lib/bubing/bundler.rb
23
+ - lib/bubing/bundler_factory.rb
24
+ - lib/bubing/executable_bundler.rb
25
+ - lib/bubing/shared_object_bundler.rb
26
+ homepage: http://rubygems.org/gems/bubing
27
+ licenses:
28
+ - MIT
29
+ metadata: {}
30
+ post_install_message:
31
+ rdoc_options: []
32
+ require_paths:
33
+ - lib
34
+ required_ruby_version: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ">="
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ required_rubygems_version: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ requirements: []
45
+ rubyforge_project:
46
+ rubygems_version: 2.4.8
47
+ signing_key:
48
+ specification_version: 4
49
+ summary: Script for bundling linux binaries
50
+ test_files: []