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 +7 -0
- data/bin/bubing +73 -0
- data/lib/bubing.rb +8 -0
- data/lib/bubing/binary_info.rb +61 -0
- data/lib/bubing/bundler.rb +115 -0
- data/lib/bubing/bundler_factory.rb +14 -0
- data/lib/bubing/executable_bundler.rb +48 -0
- data/lib/bubing/shared_object_bundler.rb +8 -0
- metadata +50 -0
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,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
|
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: []
|