bubing 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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: []