-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcreate-deployment
executable file
·152 lines (110 loc) · 4.85 KB
/
create-deployment
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import absolute_import, print_function
import argparse
import logging
import os
import re
import shutil
import subprocess
import tempfile
WHITESPACE = re.compile(r'\s+', re.I)
SHARED_LIBRARY = re.compile(r'so(\.\d+)*$')
LOGGING_HANDLER = logging.StreamHandler()
LOGGING_HANDLER.setFormatter(logging.Formatter('%(asctime)s [%(levelname)-5s] %(name)s: %(message)s'))
root = logging.getLogger()
root.addHandler(LOGGING_HANDLER)
logger = logging.getLogger('deploy')
class SharedLibrary(object):
def __init__(self, path):
self.logger = logging.getLogger('deploy.sharedlib')
self.basename = os.path.basename(path)
self.path = os.path.realpath(path)
def __eq__(self, other):
return self.path == other.path
def __hash__(self):
return hash(self.path)
def __repr__(self):
return "SharedLibrary({})".format(self.basename)
def __str__(self):
return self.path
def dependencies(self):
result = set()
for line in subprocess.check_output(['ldd', self.path]).splitlines():
contents = WHITESPACE.split(line)
# if we don't have a fourth field, or it is a system link, continue
if len(contents) < 4 or contents[3][0] == '(':
continue
# found a library
library = SharedLibrary(contents[3])
# if it isn't present, insert it and its dependencies
if not library in result:
result.add(library)
result.union(library.dependencies())
return result
def main():
parser = argparse.ArgumentParser(description="Find and relocate linked shared libraries for a so.")
parser.add_argument('--verbose', '-v', action='count', help="Set logging verbosity. By default, it is set to WARN, "
"Passing this once will yield INFO, twice will yield DEBUG.")
parser.add_argument('library', type=argparse.FileType('r'), help="The shared library to source dependencies from.")
parser.add_argument('output_dir', help="The output directory to create the distribution in.")
args = parser.parse_args()
# setup logging
if args.verbose in (0, None):
root.setLevel(logging.WARNING)
elif args.verbose == 1:
root.setLevel(logging.INFO)
else:
root.setLevel(logging.DEBUG)
# create the output directory
if not os.path.isdir(args.output_dir):
os.makedirs(args.output_dir)
# output file
output_file = os.path.join(args.output_dir, "lambda.zip")
# create the temporory directory
workdir = tempfile.mkdtemp()
workdir_lib = os.path.join(workdir, 'lib')
os.mkdir(workdir_lib)
logger.debug("created temporary work directory: %s", workdir)
# copy the source library into the temporary directory
shutil.copy(args.library.name, workdir)
library = os.path.join(workdir, os.path.basename(args.library.name))
library_basename = os.path.basename(library)
# find, dereference, copy linked libraries
for linked_lib in SharedLibrary(library).dependencies():
# parse each linked library
logger.debug("found linked library: %s", linked_lib.path)
# copy the shared library file
logger.debug('copying linked library: %s', linked_lib.basename)
shutil.copyfile(linked_lib.path, os.path.join(workdir_lib, linked_lib.basename))
# strip the shared library file
logger.debug('stripping linked library: %s', linked_lib.basename)
subprocess.check_call(['strip', os.path.join(workdir_lib, linked_lib.basename)])
# strip the target
logger.debug('stripping %s', library_basename)
subprocess.check_call(['strip', library])
package_files = list([library_basename] + [os.path.join('lib', f) for f in os.listdir(workdir_lib)])
# create zip deployment
logger.debug("removing previous deployment zip...")
if os.path.isfile(output_file):
os.remove(os.path.abspath(output_file))
logger.debug("zipping shared libraries: %s", ', '.join(package_files))
p = subprocess.Popen(['zip', os.path.abspath(output_file)] + package_files,
cwd=workdir, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
stdout, _ = p.communicate()
logger.debug('zip output: \n%s', stdout)
# display debugging linking info
env = os.environ.copy()
env.update(LD_LIBRARY_PATH=workdir_lib)
p = subprocess.Popen(['ldd', library], env=env, stdout=subprocess.PIPE)
stdout, _ = p.communicate()
logger.debug("linking info: \n%s", stdout)
if not p.returncode == 0:
logger.error('Unable to create deployment package: %s', stdout)
else:
logger.info("Built deployment package to: %s", output_file)
# remove temporary directory
logger.debug("cleaning temporary directory: %s", workdir)
shutil.rmtree(workdir)
if __name__ == "__main__":
main()