Skip to content

Commit 97c41d0

Browse files
committed
Add: python static build
Fix: catch various cases where the static python was failing
1 parent aba1429 commit 97c41d0

15 files changed

+546
-120
lines changed

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ sdist/
3434
# Usually these files are written by a python script from a template
3535
# before PyInstaller builds the exe, so as to inject date/other infos into it.
3636
*.manifest
37-
*.spec
37+
#*.spec
3838

3939
# Installer logs
4040
pip-log.txt

opsbro/cluster.py

+10-1
Original file line numberDiff line numberDiff line change
@@ -1090,7 +1090,16 @@ def clean_old_events(self):
10901090

10911091

10921092
def do_memory_trim_thread(self):
1093-
import ctypes
1093+
try:
1094+
import ctypes
1095+
except ImportError: # like in static python
1096+
ctypes = None
1097+
1098+
if ctypes is None: # nop
1099+
while not stopper.interrupted:
1100+
time.sleep(10)
1101+
return
1102+
10941103
import gc
10951104

10961105
try:

opsbro/misc/monotonic.py

+118-111
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,11 @@
3838
limitations under the License.
3939
4040
"""
41-
import ctypes
42-
import ctypes.util
41+
try:
42+
import ctypes
43+
import ctypes.util
44+
except ImportError: # like in static python
45+
ctypes = None
4346
import os
4447
import sys
4548
import threading
@@ -50,126 +53,130 @@
5053
try:
5154
monotonic = time.monotonic
5255
except AttributeError:
53-
try:
54-
if sys.platform == 'darwin': # OS X, iOS
55-
# See Technical Q&A QA1398 of the Mac Developer Library:
56-
# <https://developer.apple.com/library/mac/qa/qa1398/>
57-
libc = ctypes.CDLL('/usr/lib/libc.dylib', use_errno=True)
58-
59-
60-
class mach_timebase_info_data_t(ctypes.Structure):
61-
"""System timebase info. Defined in <mach/mach_time.h>."""
62-
_fields_ = (('numer', ctypes.c_uint32),
63-
('denom', ctypes.c_uint32))
64-
65-
66-
mach_absolute_time = libc.mach_absolute_time
67-
mach_absolute_time.restype = ctypes.c_uint64
68-
69-
timebase = mach_timebase_info_data_t()
70-
libc.mach_timebase_info(ctypes.byref(timebase))
71-
ticks_per_second = timebase.numer / timebase.denom * 1.0e9
72-
73-
74-
def monotonic():
75-
"""Monotonic clock, cannot go backward."""
76-
return mach_absolute_time() / ticks_per_second
77-
78-
elif sys.platform.startswith('win32') or sys.platform.startswith('cygwin'):
79-
if sys.platform.startswith('cygwin'):
80-
# Note: cygwin implements clock_gettime (CLOCK_MONOTONIC = 4) since
81-
# version 1.7.6. Using raw WinAPI for maximum version compatibility.
56+
# if ctypes is not available, use the standard time, no luck here
57+
if ctypes is None:
58+
monotonic = time.time
59+
else:
60+
try:
61+
if sys.platform == 'darwin': # OS X, iOS
62+
# See Technical Q&A QA1398 of the Mac Developer Library:
63+
# <https://developer.apple.com/library/mac/qa/qa1398/>
64+
libc = ctypes.CDLL('/usr/lib/libc.dylib', use_errno=True)
8265

83-
# Ugly hack using the wrong calling convention (in 32-bit mode)
84-
# because ctypes has no windll under cygwin (and it also seems that
85-
# the code letting you select stdcall in _ctypes doesn't exist under
86-
# the preprocessor definitions relevant to cygwin).
87-
# This is 'safe' because:
88-
# 1. The ABI of GetTickCount and GetTickCount64 is identical for
89-
# both calling conventions because they both have no parameters.
90-
# 2. libffi masks the problem because after making the call it doesn't
91-
# touch anything through esp and epilogue code restores a correct
92-
# esp from ebp afterwards.
93-
try:
94-
kernel32 = ctypes.cdll.kernel32
95-
except OSError: # 'No such file or directory'
96-
kernel32 = ctypes.cdll.LoadLibrary('kernel32.dll')
97-
else:
98-
kernel32 = ctypes.windll.kernel32
99-
100-
GetTickCount64 = getattr(kernel32, 'GetTickCount64', None)
101-
if GetTickCount64:
102-
# Windows Vista / Windows Server 2008 or newer.
103-
GetTickCount64.restype = ctypes.c_ulonglong
66+
67+
class mach_timebase_info_data_t(ctypes.Structure):
68+
"""System timebase info. Defined in <mach/mach_time.h>."""
69+
_fields_ = (('numer', ctypes.c_uint32),
70+
('denom', ctypes.c_uint32))
71+
72+
73+
mach_absolute_time = libc.mach_absolute_time
74+
mach_absolute_time.restype = ctypes.c_uint64
75+
76+
timebase = mach_timebase_info_data_t()
77+
libc.mach_timebase_info(ctypes.byref(timebase))
78+
ticks_per_second = timebase.numer / timebase.denom * 1.0e9
10479

10580

10681
def monotonic():
10782
"""Monotonic clock, cannot go backward."""
108-
return GetTickCount64() / 1000.0
83+
return mach_absolute_time() / ticks_per_second
84+
85+
elif sys.platform.startswith('win32') or sys.platform.startswith('cygwin'):
86+
if sys.platform.startswith('cygwin'):
87+
# Note: cygwin implements clock_gettime (CLOCK_MONOTONIC = 4) since
88+
# version 1.7.6. Using raw WinAPI for maximum version compatibility.
89+
90+
# Ugly hack using the wrong calling convention (in 32-bit mode)
91+
# because ctypes has no windll under cygwin (and it also seems that
92+
# the code letting you select stdcall in _ctypes doesn't exist under
93+
# the preprocessor definitions relevant to cygwin).
94+
# This is 'safe' because:
95+
# 1. The ABI of GetTickCount and GetTickCount64 is identical for
96+
# both calling conventions because they both have no parameters.
97+
# 2. libffi masks the problem because after making the call it doesn't
98+
# touch anything through esp and epilogue code restores a correct
99+
# esp from ebp afterwards.
100+
try:
101+
kernel32 = ctypes.cdll.kernel32
102+
except OSError: # 'No such file or directory'
103+
kernel32 = ctypes.cdll.LoadLibrary('kernel32.dll')
104+
else:
105+
kernel32 = ctypes.windll.kernel32
106+
107+
GetTickCount64 = getattr(kernel32, 'GetTickCount64', None)
108+
if GetTickCount64:
109+
# Windows Vista / Windows Server 2008 or newer.
110+
GetTickCount64.restype = ctypes.c_ulonglong
111+
112+
113+
def monotonic():
114+
"""Monotonic clock, cannot go backward."""
115+
return GetTickCount64() / 1000.0
116+
117+
else:
118+
# Before Windows Vista.
119+
GetTickCount = kernel32.GetTickCount
120+
GetTickCount.restype = ctypes.c_uint32
121+
122+
get_tick_count_lock = threading.Lock()
123+
get_tick_count_last_sample = 0
124+
get_tick_count_wraparounds = 0
125+
126+
127+
def monotonic():
128+
"""Monotonic clock, cannot go backward."""
129+
global get_tick_count_last_sample
130+
global get_tick_count_wraparounds
131+
132+
with get_tick_count_lock:
133+
current_sample = GetTickCount()
134+
if current_sample < get_tick_count_last_sample:
135+
get_tick_count_wraparounds += 1
136+
get_tick_count_last_sample = current_sample
137+
138+
final_milliseconds = get_tick_count_wraparounds << 32
139+
final_milliseconds += get_tick_count_last_sample
140+
return final_milliseconds / 1000.0
109141

110142
else:
111-
# Before Windows Vista.
112-
GetTickCount = kernel32.GetTickCount
113-
GetTickCount.restype = ctypes.c_uint32
143+
try:
144+
# NOTE: on alpine linux 2.7, there is a issue with find(c) that is giving back
145+
# the full path instead of just the lib name, so use os.path.basename() to strip it
146+
clock_gettime = ctypes.CDLL(os.path.basename(ctypes.util.find_library('c')), use_errno=True).clock_gettime
147+
except AttributeError:
148+
clock_gettime = ctypes.CDLL(os.path.basename(ctypes.util.find_library('rt')), use_errno=True).clock_gettime
149+
150+
151+
class timespec(ctypes.Structure):
152+
"""Time specification, as described in clock_gettime(3)."""
153+
_fields_ = (('tv_sec', ctypes.c_long),
154+
('tv_nsec', ctypes.c_long))
114155

115-
get_tick_count_lock = threading.Lock()
116-
get_tick_count_last_sample = 0
117-
get_tick_count_wraparounds = 0
156+
157+
if sys.platform.startswith('linux'):
158+
CLOCK_MONOTONIC = 1
159+
elif sys.platform.startswith('freebsd'):
160+
CLOCK_MONOTONIC = 4
161+
elif sys.platform.startswith('sunos5'):
162+
CLOCK_MONOTONIC = 4
163+
elif 'bsd' in sys.platform:
164+
CLOCK_MONOTONIC = 3
165+
elif sys.platform.startswith('aix'):
166+
CLOCK_MONOTONIC = ctypes.c_longlong(10)
118167

119168

120169
def monotonic():
121170
"""Monotonic clock, cannot go backward."""
122-
global get_tick_count_last_sample
123-
global get_tick_count_wraparounds
124-
125-
with get_tick_count_lock:
126-
current_sample = GetTickCount()
127-
if current_sample < get_tick_count_last_sample:
128-
get_tick_count_wraparounds += 1
129-
get_tick_count_last_sample = current_sample
130-
131-
final_milliseconds = get_tick_count_wraparounds << 32
132-
final_milliseconds += get_tick_count_last_sample
133-
return final_milliseconds / 1000.0
134-
135-
else:
136-
try:
137-
# NOTE: on alpine linux 2.7, there is a issue with find(c) that is giving back
138-
# the full path instead of just the lib name, so use os.path.basename() to strip it
139-
clock_gettime = ctypes.CDLL(os.path.basename(ctypes.util.find_library('c')), use_errno=True).clock_gettime
140-
except AttributeError:
141-
clock_gettime = ctypes.CDLL(os.path.basename(ctypes.util.find_library('rt')), use_errno=True).clock_gettime
142-
143-
144-
class timespec(ctypes.Structure):
145-
"""Time specification, as described in clock_gettime(3)."""
146-
_fields_ = (('tv_sec', ctypes.c_long),
147-
('tv_nsec', ctypes.c_long))
148-
149-
150-
if sys.platform.startswith('linux'):
151-
CLOCK_MONOTONIC = 1
152-
elif sys.platform.startswith('freebsd'):
153-
CLOCK_MONOTONIC = 4
154-
elif sys.platform.startswith('sunos5'):
155-
CLOCK_MONOTONIC = 4
156-
elif 'bsd' in sys.platform:
157-
CLOCK_MONOTONIC = 3
158-
elif sys.platform.startswith('aix'):
159-
CLOCK_MONOTONIC = ctypes.c_longlong(10)
160-
171+
ts = timespec()
172+
if clock_gettime(CLOCK_MONOTONIC, ctypes.pointer(ts)):
173+
errno = ctypes.get_errno()
174+
raise OSError(errno, os.strerror(errno))
175+
return ts.tv_sec + ts.tv_nsec / 1.0e9
161176

162-
def monotonic():
163-
"""Monotonic clock, cannot go backward."""
164-
ts = timespec()
165-
if clock_gettime(CLOCK_MONOTONIC, ctypes.pointer(ts)):
166-
errno = ctypes.get_errno()
167-
raise OSError(errno, os.strerror(errno))
168-
return ts.tv_sec + ts.tv_nsec / 1.0e9
177+
# Perform a sanity-check.
178+
if monotonic() - monotonic() > 0:
179+
raise ValueError('monotonic() is not monotonic!')
169180

170-
# Perform a sanity-check.
171-
if monotonic() - monotonic() > 0:
172-
raise ValueError('monotonic() is not monotonic!')
173-
174-
except Exception:
175-
raise RuntimeError('no suitable implementation for this system')
181+
except Exception:
182+
raise RuntimeError('no suitable implementation for this system')

opsbro/misc/websocketserver.py

+8-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@
2424
import base64
2525
import socket
2626
import struct
27-
import ssl
27+
try:
28+
import ssl
29+
except ImportError: # like in static python
30+
ssl = None
2831
import time
2932
import errno
3033
import logging
@@ -606,9 +609,12 @@ def serveforever(self):
606609
del self.connections[fileno]
607610
self.listeners.remove(failed)
608611

612+
PROTOCOL_TLSv1 = None
613+
if ssl:
614+
PROTOCOL_TLSv1 = ssl.PROTOCOL_TLSv1
609615

610616
class SimpleSSLWebSocketServer(SimpleWebSocketServer):
611-
def __init__(self, host, port, websocketclass, certfile, keyfile, version=ssl.PROTOCOL_TLSv1):
617+
def __init__(self, host, port, websocketclass, certfile, keyfile, version=PROTOCOL_TLSv1):
612618
SimpleWebSocketServer.__init__(self, host, port, websocketclass)
613619

614620
self.cerfile = certfile

opsbro/threadmgr.py

+15-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import threading
2-
import ctypes
2+
try:
3+
import ctypes
4+
except ImportError: # on python static build for example
5+
ctypes = None
36
import sys
47
import os
58
import time
@@ -25,7 +28,11 @@
2528
# Hook threading to allow thread renaming
2629
if sys.platform.startswith("win"):
2730
def namer():
28-
import ctypes
31+
# If no ctypes, like in a static python build: exit
32+
try:
33+
import ctypes
34+
except ImportError:
35+
return
2936
import threading
3037
import time
3138
from ctypes import wintypes
@@ -87,8 +94,12 @@ def debugChecker():
8794
del namer
8895
elif sys.platform.startswith("linux"):
8996
def namer():
90-
import ctypes
91-
import ctypes.util
97+
# Return if python was build without ctypes (like in a static build)
98+
try:
99+
import ctypes
100+
import ctypes.util
101+
except ImportError:
102+
return
92103
import threading
93104
libpthread_path = ctypes.util.find_library("pthread")
94105
if not libpthread_path:

0 commit comments

Comments
 (0)