cleepcli 1.43.10__tar.gz → 1.44.0__tar.gz
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.
- {cleepcli-1.43.10/cleepcli.egg-info → cleepcli-1.44.0}/PKG-INFO +1 -1
- {cleepcli-1.43.10 → cleepcli-1.44.0}/bin/ccli +19 -13
- {cleepcli-1.43.10 → cleepcli-1.44.0}/bin/cleep-cli +19 -13
- {cleepcli-1.43.10 → cleepcli-1.44.0}/cleepcli/ci.py +3 -1
- {cleepcli-1.43.10 → cleepcli-1.44.0}/cleepcli/cleepapi.py +158 -6
- {cleepcli-1.43.10 → cleepcli-1.44.0}/cleepcli/console.py +38 -48
- {cleepcli-1.43.10 → cleepcli-1.44.0}/cleepcli/file.py +10 -8
- {cleepcli-1.43.10 → cleepcli-1.44.0}/cleepcli/git.py +2 -2
- {cleepcli-1.43.10 → cleepcli-1.44.0}/cleepcli/module.py +1 -1
- {cleepcli-1.43.10 → cleepcli-1.44.0}/cleepcli/version.py +1 -1
- cleepcli-1.44.0/cleepcli/watch.py +481 -0
- {cleepcli-1.43.10 → cleepcli-1.44.0/cleepcli.egg-info}/PKG-INFO +1 -1
- {cleepcli-1.43.10 → cleepcli-1.44.0}/cleepcli.egg-info/SOURCES.txt +3 -1
- cleepcli-1.44.0/tests/test_console.py +51 -0
- cleepcli-1.44.0/tests/test_watch.py +208 -0
- cleepcli-1.43.10/cleepcli/watch.py +0 -375
- {cleepcli-1.43.10 → cleepcli-1.44.0}/LICENSE +0 -0
- {cleepcli-1.43.10 → cleepcli-1.44.0}/MANIFEST.in +0 -0
- {cleepcli-1.43.10 → cleepcli-1.44.0}/README.md +0 -0
- {cleepcli-1.43.10 → cleepcli-1.44.0}/cleepcli/__init__.py +0 -0
- {cleepcli-1.43.10 → cleepcli-1.44.0}/cleepcli/check.py +0 -0
- {cleepcli-1.43.10 → cleepcli-1.44.0}/cleepcli/config.py +0 -0
- {cleepcli-1.43.10 → cleepcli-1.44.0}/cleepcli/docs.py +0 -0
- {cleepcli-1.43.10 → cleepcli-1.44.0}/cleepcli/package.py +0 -0
- {cleepcli-1.43.10 → cleepcli-1.44.0}/cleepcli/test.py +0 -0
- {cleepcli-1.43.10 → cleepcli-1.44.0}/cleepcli/tools.py +0 -0
- {cleepcli-1.43.10 → cleepcli-1.44.0}/cleepcli.egg-info/dependency_links.txt +0 -0
- {cleepcli-1.43.10 → cleepcli-1.44.0}/cleepcli.egg-info/requires.txt +0 -0
- {cleepcli-1.43.10 → cleepcli-1.44.0}/cleepcli.egg-info/top_level.txt +0 -0
- {cleepcli-1.43.10 → cleepcli-1.44.0}/pyproject.toml +0 -0
- {cleepcli-1.43.10 → cleepcli-1.44.0}/requirements.txt +0 -0
- {cleepcli-1.43.10 → cleepcli-1.44.0}/setup.cfg +0 -0
- {cleepcli-1.43.10 → cleepcli-1.44.0}/setup.py +0 -0
|
@@ -90,7 +90,8 @@ def coreget():
|
|
|
90
90
|
|
|
91
91
|
# force coresync to synchronize installation with repo
|
|
92
92
|
f = File()
|
|
93
|
-
|
|
93
|
+
if not f.core_sync():
|
|
94
|
+
sys.exit(1)
|
|
94
95
|
|
|
95
96
|
# core modules
|
|
96
97
|
if not get_core_mods():
|
|
@@ -293,9 +294,10 @@ def modssync(run_scripts):
|
|
|
293
294
|
res = f.module_sync(module)
|
|
294
295
|
if not res:
|
|
295
296
|
sys.exit(1)
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
297
|
+
if run_scripts:
|
|
298
|
+
res = f.module_run_install_scripts(module)
|
|
299
|
+
if not res:
|
|
300
|
+
sys.exit(1)
|
|
299
301
|
|
|
300
302
|
logging.info('Done')
|
|
301
303
|
|
|
@@ -899,17 +901,21 @@ def cli():
|
|
|
899
901
|
|
|
900
902
|
|
|
901
903
|
if __name__ == '__main__':
|
|
902
|
-
def
|
|
903
|
-
if platform.system()!='Linux':
|
|
904
|
+
def is_raspberry_pi_os():
|
|
905
|
+
if platform.system() != 'Linux':
|
|
904
906
|
return False
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
907
|
+
try:
|
|
908
|
+
with open('/etc/os-release', 'r', encoding='utf-8') as handle:
|
|
909
|
+
content = handle.read().lower()
|
|
910
|
+
except OSError:
|
|
908
911
|
return False
|
|
909
|
-
return
|
|
912
|
+
return any(
|
|
913
|
+
token in content for token in ('raspbian', 'raspios', 'raspberry')
|
|
914
|
+
)
|
|
910
915
|
|
|
911
|
-
# execute only on
|
|
912
|
-
if
|
|
916
|
+
# execute only on Raspberry Pi OS
|
|
917
|
+
if is_raspberry_pi_os():
|
|
913
918
|
cli()
|
|
914
919
|
else:
|
|
915
|
-
click.echo('Cleep-cli runs only on
|
|
920
|
+
click.echo('Cleep-cli runs only on Raspberry Pi OS')
|
|
921
|
+
sys.exit(1)
|
|
@@ -90,7 +90,8 @@ def coreget():
|
|
|
90
90
|
|
|
91
91
|
# force coresync to synchronize installation with repo
|
|
92
92
|
f = File()
|
|
93
|
-
|
|
93
|
+
if not f.core_sync():
|
|
94
|
+
sys.exit(1)
|
|
94
95
|
|
|
95
96
|
# core modules
|
|
96
97
|
if not get_core_mods():
|
|
@@ -293,9 +294,10 @@ def modssync(run_scripts):
|
|
|
293
294
|
res = f.module_sync(module)
|
|
294
295
|
if not res:
|
|
295
296
|
sys.exit(1)
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
297
|
+
if run_scripts:
|
|
298
|
+
res = f.module_run_install_scripts(module)
|
|
299
|
+
if not res:
|
|
300
|
+
sys.exit(1)
|
|
299
301
|
|
|
300
302
|
logging.info('Done')
|
|
301
303
|
|
|
@@ -899,17 +901,21 @@ def cli():
|
|
|
899
901
|
|
|
900
902
|
|
|
901
903
|
if __name__ == '__main__':
|
|
902
|
-
def
|
|
903
|
-
if platform.system()!='Linux':
|
|
904
|
+
def is_raspberry_pi_os():
|
|
905
|
+
if platform.system() != 'Linux':
|
|
904
906
|
return False
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
907
|
+
try:
|
|
908
|
+
with open('/etc/os-release', 'r', encoding='utf-8') as handle:
|
|
909
|
+
content = handle.read().lower()
|
|
910
|
+
except OSError:
|
|
908
911
|
return False
|
|
909
|
-
return
|
|
912
|
+
return any(
|
|
913
|
+
token in content for token in ('raspbian', 'raspios', 'raspberry')
|
|
914
|
+
)
|
|
910
915
|
|
|
911
|
-
# execute only on
|
|
912
|
-
if
|
|
916
|
+
# execute only on Raspberry Pi OS
|
|
917
|
+
if is_raspberry_pi_os():
|
|
913
918
|
cli()
|
|
914
919
|
else:
|
|
915
|
-
click.echo('Cleep-cli runs only on
|
|
920
|
+
click.echo('Cleep-cli runs only on Raspberry Pi OS')
|
|
921
|
+
sys.exit(1)
|
|
@@ -12,7 +12,7 @@ import urllib.parse
|
|
|
12
12
|
from . import config
|
|
13
13
|
from .console import Console
|
|
14
14
|
from .check import Check
|
|
15
|
-
from .cleepapi import resolve_rpc_url
|
|
15
|
+
from .cleepapi import local_socket_available, request_over_local_socket, resolve_rpc_url
|
|
16
16
|
import subprocess
|
|
17
17
|
|
|
18
18
|
requests.packages.urllib3.disable_warnings()
|
|
@@ -284,6 +284,8 @@ class Ci:
|
|
|
284
284
|
"""
|
|
285
285
|
POST JSON to Cleep /command (self-signed TLS accepted).
|
|
286
286
|
"""
|
|
287
|
+
if local_socket_available():
|
|
288
|
+
return request_over_local_socket('POST', self.command_url, json_body=payload)
|
|
287
289
|
return requests.post(self.command_url, json=payload, verify=False)
|
|
288
290
|
|
|
289
291
|
def _rpc_get(self, url):
|
|
@@ -17,6 +17,9 @@ DEFAULT_RPC_URLS = (
|
|
|
17
17
|
'https://127.0.0.1:443',
|
|
18
18
|
'http://127.0.0.1:80',
|
|
19
19
|
)
|
|
20
|
+
# Local commands (frontend restart, docs, CI) use this socket so they
|
|
21
|
+
# stay available when TCP requires the Cleep password.
|
|
22
|
+
LOCAL_SOCKET_PATH = '/run/cleep/rpc.sock'
|
|
20
23
|
|
|
21
24
|
|
|
22
25
|
def resolve_rpc_url(urls=None, timeout=3.0):
|
|
@@ -54,6 +57,144 @@ def resolve_rpc_url(urls=None, timeout=3.0):
|
|
|
54
57
|
raise Exception('Unable to reach Cleep RPC (tried %s): %s' % (', '.join(candidates), last_error))
|
|
55
58
|
|
|
56
59
|
|
|
60
|
+
def local_socket_available(path=None):
|
|
61
|
+
"""
|
|
62
|
+
Return True when the local Cleep RPC socket exists.
|
|
63
|
+
"""
|
|
64
|
+
return os.path.exists(path or LOCAL_SOCKET_PATH)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _http_path(url):
|
|
68
|
+
"""
|
|
69
|
+
Return the path and query of an RPC URL.
|
|
70
|
+
"""
|
|
71
|
+
parts = urllib.parse.urlsplit(url)
|
|
72
|
+
path = parts.path or '/'
|
|
73
|
+
if parts.query:
|
|
74
|
+
path += '?' + parts.query
|
|
75
|
+
return path
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def _read_http_response(sock):
|
|
79
|
+
"""
|
|
80
|
+
Read one HTTP/1.1 response from a socket.
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
tuple: status code (int), body (bytes)
|
|
84
|
+
"""
|
|
85
|
+
data = b''
|
|
86
|
+
while b'\r\n\r\n' not in data:
|
|
87
|
+
chunk = sock.recv(4096)
|
|
88
|
+
if not chunk:
|
|
89
|
+
break
|
|
90
|
+
data += chunk
|
|
91
|
+
if b'\r\n\r\n' not in data:
|
|
92
|
+
raise Exception('Incomplete HTTP response from local socket')
|
|
93
|
+
|
|
94
|
+
header_blob, rest = data.split(b'\r\n\r\n', 1)
|
|
95
|
+
lines = header_blob.split(b'\r\n')
|
|
96
|
+
status_code = int(lines[0].split()[1])
|
|
97
|
+
headers = {}
|
|
98
|
+
for line in lines[1:]:
|
|
99
|
+
if b':' not in line:
|
|
100
|
+
continue
|
|
101
|
+
name, value = line.split(b':', 1)
|
|
102
|
+
headers[name.decode('ascii').lower()] = value.strip().decode('ascii')
|
|
103
|
+
|
|
104
|
+
if headers.get('transfer-encoding', '').lower() == 'chunked':
|
|
105
|
+
body = _read_chunked(sock, rest)
|
|
106
|
+
elif 'content-length' in headers:
|
|
107
|
+
length = int(headers['content-length'])
|
|
108
|
+
while len(rest) < length:
|
|
109
|
+
chunk = sock.recv(4096)
|
|
110
|
+
if not chunk:
|
|
111
|
+
break
|
|
112
|
+
rest += chunk
|
|
113
|
+
body = rest[:length]
|
|
114
|
+
else:
|
|
115
|
+
while True:
|
|
116
|
+
chunk = sock.recv(4096)
|
|
117
|
+
if not chunk:
|
|
118
|
+
break
|
|
119
|
+
rest += chunk
|
|
120
|
+
body = rest
|
|
121
|
+
return status_code, body
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def _read_chunked(sock, pending):
|
|
125
|
+
"""
|
|
126
|
+
Decode a chunked HTTP body.
|
|
127
|
+
"""
|
|
128
|
+
data = pending
|
|
129
|
+
body = b''
|
|
130
|
+
while True:
|
|
131
|
+
while b'\r\n' not in data:
|
|
132
|
+
chunk = sock.recv(4096)
|
|
133
|
+
if not chunk:
|
|
134
|
+
return body
|
|
135
|
+
data += chunk
|
|
136
|
+
size_line, data = data.split(b'\r\n', 1)
|
|
137
|
+
size = int(size_line.split(b';', 1)[0], 16)
|
|
138
|
+
if size == 0:
|
|
139
|
+
return body
|
|
140
|
+
while len(data) < size + 2:
|
|
141
|
+
chunk = sock.recv(4096)
|
|
142
|
+
if not chunk:
|
|
143
|
+
return body
|
|
144
|
+
data += chunk
|
|
145
|
+
body += data[:size]
|
|
146
|
+
data = data[size + 2:]
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def request_over_local_socket(method, url, json_body=None, timeout=30.0, path=None):
|
|
150
|
+
"""
|
|
151
|
+
Send one HTTP request through the local Cleep Unix socket.
|
|
152
|
+
|
|
153
|
+
Args:
|
|
154
|
+
method (str): HTTP method
|
|
155
|
+
url (str): request URL, used for the path when path is omitted
|
|
156
|
+
json_body (dict): JSON body for POST
|
|
157
|
+
timeout (float): socket timeout in seconds
|
|
158
|
+
path (str): socket path
|
|
159
|
+
|
|
160
|
+
Returns:
|
|
161
|
+
requests.Response
|
|
162
|
+
"""
|
|
163
|
+
import socket
|
|
164
|
+
from requests import Response
|
|
165
|
+
|
|
166
|
+
socket_path = path or LOCAL_SOCKET_PATH
|
|
167
|
+
http_path = _http_path(url)
|
|
168
|
+
body = b''
|
|
169
|
+
headers = [
|
|
170
|
+
'%s %s HTTP/1.1' % (method, http_path),
|
|
171
|
+
'Host: localhost',
|
|
172
|
+
'Accept: application/json',
|
|
173
|
+
'Connection: close',
|
|
174
|
+
]
|
|
175
|
+
if json_body is not None:
|
|
176
|
+
body = json.dumps(json_body).encode('utf-8')
|
|
177
|
+
headers.append('Content-Type: application/json')
|
|
178
|
+
headers.append('Content-Length: %s' % len(body))
|
|
179
|
+
raw = ('\r\n'.join(headers) + '\r\n\r\n').encode('ascii') + body
|
|
180
|
+
|
|
181
|
+
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
|
182
|
+
sock.settimeout(timeout)
|
|
183
|
+
try:
|
|
184
|
+
sock.connect(socket_path)
|
|
185
|
+
sock.sendall(raw)
|
|
186
|
+
status_code, payload = _read_http_response(sock)
|
|
187
|
+
finally:
|
|
188
|
+
sock.close()
|
|
189
|
+
|
|
190
|
+
response = Response()
|
|
191
|
+
response.status_code = status_code
|
|
192
|
+
response._content = payload
|
|
193
|
+
response.url = 'http://localhost' + http_path
|
|
194
|
+
response.encoding = 'utf-8'
|
|
195
|
+
return response
|
|
196
|
+
|
|
197
|
+
|
|
57
198
|
class CleepApi():
|
|
58
199
|
"""
|
|
59
200
|
Cleep api helper
|
|
@@ -81,9 +222,10 @@ class CleepApi():
|
|
|
81
222
|
|
|
82
223
|
cmd = '/bin/systemctl restart cleep'
|
|
83
224
|
c = Console()
|
|
84
|
-
|
|
225
|
+
# Maximum wait. systemctl returns as soon as the service has restarted.
|
|
226
|
+
resp = c.command(cmd, timeout=60)
|
|
85
227
|
self.logger.debug('Systemctl resp: %s' % resp)
|
|
86
|
-
if resp['
|
|
228
|
+
if resp['killed'] or resp['returncode'] != 0:
|
|
87
229
|
self.logger.error('Error restarting cleep backend')
|
|
88
230
|
return False
|
|
89
231
|
|
|
@@ -95,7 +237,11 @@ class CleepApi():
|
|
|
95
237
|
"""
|
|
96
238
|
self.logger.info('Restarting frontend')
|
|
97
239
|
data = {'to':'developer', 'command':'restart_frontend'}
|
|
98
|
-
self.__post(self.command_url, data)
|
|
240
|
+
result = self.__post(self.command_url, data)
|
|
241
|
+
if not result or result[0] != 200:
|
|
242
|
+
self.logger.error('Error restarting cleep frontend')
|
|
243
|
+
return False
|
|
244
|
+
return True
|
|
99
245
|
|
|
100
246
|
def get_documentation(self, module_name):
|
|
101
247
|
"""
|
|
@@ -132,7 +278,7 @@ class CleepApi():
|
|
|
132
278
|
(status_code, resp) = self.__get(url)
|
|
133
279
|
|
|
134
280
|
if status_code != 200:
|
|
135
|
-
raise Exception("Unable to call cleep %s endpoint"
|
|
281
|
+
raise Exception("Unable to call cleep %s endpoint" % url)
|
|
136
282
|
return resp
|
|
137
283
|
|
|
138
284
|
def __post(self, url, data):
|
|
@@ -152,7 +298,10 @@ class CleepApi():
|
|
|
152
298
|
"""
|
|
153
299
|
try:
|
|
154
300
|
self.logger.debug("POST url: %s", url)
|
|
155
|
-
|
|
301
|
+
if local_socket_available():
|
|
302
|
+
resp = request_over_local_socket('POST', url, json_body=data)
|
|
303
|
+
else:
|
|
304
|
+
resp = requests.post(url, json=data, verify=False)
|
|
156
305
|
resp_data = resp.json()
|
|
157
306
|
self.logger.debug('Response[%s]: %s', resp.status_code, resp_data)
|
|
158
307
|
return (resp.status_code, resp_data)
|
|
@@ -178,7 +327,10 @@ class CleepApi():
|
|
|
178
327
|
"""
|
|
179
328
|
try:
|
|
180
329
|
self.logger.debug("GET url: %s", url)
|
|
181
|
-
|
|
330
|
+
if local_socket_available():
|
|
331
|
+
resp = request_over_local_socket('GET', url)
|
|
332
|
+
else:
|
|
333
|
+
resp = requests.get(url, verify=False)
|
|
182
334
|
resp_data = resp.json()
|
|
183
335
|
self.logger.debug('Response[%s]: %s', resp.status_code, resp_data)
|
|
184
336
|
return (resp.status_code, resp_data)
|
|
@@ -14,6 +14,9 @@ import signal
|
|
|
14
14
|
import logging
|
|
15
15
|
import re
|
|
16
16
|
|
|
17
|
+
ON_POSIX = os.name == "posix"
|
|
18
|
+
|
|
19
|
+
|
|
17
20
|
class EndlessConsole(Thread):
|
|
18
21
|
"""
|
|
19
22
|
Helper class to execute long command line (system update...)
|
|
@@ -322,65 +325,52 @@ class Console():
|
|
|
322
325
|
stdout=subprocess.PIPE,
|
|
323
326
|
stderr=subprocess.PIPE,
|
|
324
327
|
close_fds=True,
|
|
325
|
-
preexec_fn=os.setsid
|
|
328
|
+
preexec_fn=os.setsid if ON_POSIX else None,
|
|
326
329
|
)
|
|
327
330
|
pid = proc.pid
|
|
328
|
-
|
|
329
|
-
# wait for end of command line
|
|
330
|
-
done = False
|
|
331
|
-
start = time.time()
|
|
332
331
|
killed = False
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
# read stds to avoid deadlocks
|
|
336
|
-
(stdout, stderr) = proc.communicate()
|
|
337
|
-
if stdout:
|
|
338
|
-
result['stdout'] += self.__process_lines(stdout.split(b'\n'))
|
|
339
|
-
if stderr:
|
|
340
|
-
result['stderr'] += self.__process_lines(stderr.split(b'\n'))
|
|
341
|
-
|
|
342
|
-
# check if command has finished
|
|
343
|
-
proc.poll()
|
|
344
|
-
if proc.returncode is not None:
|
|
345
|
-
# command terminated
|
|
346
|
-
self.logger.trace('Command terminated with returncode %s' % proc.returncode)
|
|
347
|
-
return_code = proc.returncode
|
|
348
|
-
self.last_return_code = return_code
|
|
349
|
-
done = True
|
|
350
|
-
break
|
|
351
|
-
|
|
352
|
-
# check timeout
|
|
353
|
-
if time.time() > (start + timeout):
|
|
354
|
-
# timeout is over, kill command
|
|
355
|
-
pgid = os.getpgid(pid)
|
|
356
|
-
self.logger.debug('Timeout over, kill command for PID=%s PGID=%s' % (pid, pgid))
|
|
357
|
-
try:
|
|
358
|
-
if ON_POSIX:
|
|
359
|
-
os.killpg(pgid, signal.SIGKILL)
|
|
360
|
-
else: # pragma: no cover
|
|
361
|
-
proc.kill()
|
|
362
|
-
except Exception: # pragma: no cover
|
|
363
|
-
pass
|
|
364
|
-
killed = True
|
|
365
|
-
break
|
|
332
|
+
stdout = b""
|
|
333
|
+
stderr = b""
|
|
366
334
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
335
|
+
try:
|
|
336
|
+
stdout, stderr = proc.communicate(timeout=timeout)
|
|
337
|
+
except subprocess.TimeoutExpired:
|
|
338
|
+
self.logger.debug("Timeout over, kill command for PID=%s" % pid)
|
|
339
|
+
try:
|
|
340
|
+
if ON_POSIX:
|
|
341
|
+
os.killpg(os.getpgid(pid), signal.SIGKILL)
|
|
342
|
+
else: # pragma: no cover
|
|
343
|
+
proc.kill()
|
|
344
|
+
except Exception: # pragma: no cover
|
|
345
|
+
pass
|
|
346
|
+
killed = True
|
|
347
|
+
try:
|
|
348
|
+
stdout, stderr = proc.communicate(timeout=1.0)
|
|
349
|
+
except Exception: # pragma: no cover
|
|
350
|
+
stdout, stderr = b"", b""
|
|
351
|
+
|
|
352
|
+
if stdout:
|
|
353
|
+
result["stdout"] = self.__process_lines(stdout.split(b"\n"))
|
|
354
|
+
if stderr:
|
|
355
|
+
result["stderr"] = self.__process_lines(stderr.split(b"\n"))
|
|
356
|
+
|
|
357
|
+
return_code = proc.returncode
|
|
358
|
+
self.last_return_code = return_code
|
|
359
|
+
result["returncode"] = return_code
|
|
360
|
+
result["killed"] = killed
|
|
361
|
+
# Prefer return code over stderr: tools like systemctl often write to stderr on success
|
|
362
|
+
result["error"] = killed or return_code not in (0, None)
|
|
363
|
+
self.logger.trace("Command terminated with returncode %s" % return_code)
|
|
364
|
+
self.logger.trace("Result: %s" % result)
|
|
375
365
|
|
|
376
366
|
# make sure all stds are closed
|
|
377
367
|
try:
|
|
378
368
|
proc.stdout.close()
|
|
379
|
-
except Exception:
|
|
369
|
+
except Exception: # pragma: no cover
|
|
380
370
|
pass
|
|
381
371
|
try:
|
|
382
372
|
proc.stderr.close()
|
|
383
|
-
except Exception:
|
|
373
|
+
except Exception: # pragma: no cover
|
|
384
374
|
pass
|
|
385
375
|
|
|
386
376
|
# trigger callback (used for delayed command)
|
|
@@ -32,6 +32,7 @@ class File():
|
|
|
32
32
|
'CONFIG_DIR': config.CONFIG_DIR,
|
|
33
33
|
}
|
|
34
34
|
cmd = """
|
|
35
|
+
set -e
|
|
35
36
|
mkdir -p "%(HTML_DST)s/"
|
|
36
37
|
mkdir -p "%(CORE_DST)s/modules"
|
|
37
38
|
mkdir -p "%(MEDIA_DST)s/modules"
|
|
@@ -42,11 +43,11 @@ rsync -av "%(REPO_DIR)s/bin/cleep" "%(BIN_DST)s/cleep"
|
|
|
42
43
|
rsync -av "%(REPO_DIR)s/medias/sounds" "%(MEDIA_DST)s/sounds/" --delete
|
|
43
44
|
""" % variables
|
|
44
45
|
self.logger.debug('Coresync cmd: %s' % cmd)
|
|
45
|
-
resp = c.command(cmd,
|
|
46
|
+
resp = c.command(cmd, 120)
|
|
46
47
|
self.logger.debug('Coresync stdout:\n%s' % '\n'.join(resp['stdout']))
|
|
47
48
|
if resp['stderr']:
|
|
48
49
|
self.logger.debug('Coresync stderr:\n%s' % '\n'.join(resp['stderr']))
|
|
49
|
-
if resp['
|
|
50
|
+
if resp['killed'] or resp['returncode'] != 0:
|
|
50
51
|
self.logger.error('Error occured while sync core content: %s' % ('killed' if resp['killed'] else resp['stderr']))
|
|
51
52
|
return False
|
|
52
53
|
|
|
@@ -71,7 +72,8 @@ rsync -av "%(REPO_DIR)s/medias/sounds" "%(MEDIA_DST)s/sounds/" --delete
|
|
|
71
72
|
mod_scripts_dst = os.path.join(config.MODULES_SCRIPTS_DST, module_name)
|
|
72
73
|
|
|
73
74
|
c = Console()
|
|
74
|
-
cmd = """
|
|
75
|
+
cmd = """
|
|
76
|
+
set -e
|
|
75
77
|
if [ -d "%(BACKEND_SRC)s" ]; then
|
|
76
78
|
/bin/mkdir -p "%(BACKEND_DST)s"
|
|
77
79
|
rsync -av "%(BACKEND_SRC)s" "%(BACKEND_DST)s" --delete --exclude "*.pyc" --exclude "*__pycache__*"
|
|
@@ -90,13 +92,13 @@ fi
|
|
|
90
92
|
'SCRIPTS_SRC': mod_scripts_src, 'SCRIPTS_DST': mod_scripts_dst
|
|
91
93
|
}
|
|
92
94
|
self.logger.debug('Modsync cmd: %s' % cmd)
|
|
93
|
-
resp = c.command(cmd,
|
|
95
|
+
resp = c.command(cmd, 120)
|
|
94
96
|
|
|
95
97
|
self.logger.debug('Modsync stdout:\n%s' % '\n'.join(resp['stdout']))
|
|
96
98
|
if resp['stderr']:
|
|
97
99
|
self.logger.debug('Modsync stderr:\n%s' % '\n'.join(resp['stderr']))
|
|
98
|
-
if resp['
|
|
99
|
-
self.logger.error(
|
|
100
|
+
if resp['killed'] or resp['returncode'] != 0:
|
|
101
|
+
self.logger.error('Error occured while sync module content: %s' % ('killed' if resp['killed'] else resp['stderr']))
|
|
100
102
|
return False
|
|
101
103
|
|
|
102
104
|
return True
|
|
@@ -116,14 +118,14 @@ fi
|
|
|
116
118
|
if os.path.exists(preinst_script):
|
|
117
119
|
self.logger.info('Running %s scripts', preinst_script)
|
|
118
120
|
resp = console.command(preinst_script, timeout=300)
|
|
119
|
-
if resp["returncode"] != 0:
|
|
121
|
+
if resp["killed"] or resp["returncode"] != 0:
|
|
120
122
|
self.logger.error('Error running %s [%s]: %s', preinst_script, resp["returncode"], ''.join(resp["stderr"]))
|
|
121
123
|
return False
|
|
122
124
|
|
|
123
125
|
if os.path.exists(postinst_script):
|
|
124
126
|
self.logger.info('Running %s scripts', postinst_script)
|
|
125
127
|
resp = console.command(postinst_script, timeout=300)
|
|
126
|
-
if resp["returncode"] != 0:
|
|
128
|
+
if resp["killed"] or resp["returncode"] != 0:
|
|
127
129
|
self.logger.error('Error running %s [%s]: %s', postinst_script, resp["returncode"], ''.join(resp["stderr"]))
|
|
128
130
|
return False
|
|
129
131
|
|
|
@@ -25,7 +25,7 @@ class Git():
|
|
|
25
25
|
self.logger.debug('cmd: %s' % cmd)
|
|
26
26
|
resp = c.command(cmd, 60)
|
|
27
27
|
self.logger.debug('Pull resp: %s' % resp)
|
|
28
|
-
if resp['
|
|
28
|
+
if resp['killed'] or resp['returncode'] != 0:
|
|
29
29
|
self.logger.error('Error occured while pulling repository: %s' % ('killed' if resp['killed'] else resp['stderr']))
|
|
30
30
|
return False
|
|
31
31
|
|
|
@@ -47,7 +47,7 @@ class Git():
|
|
|
47
47
|
self.logger.debug('cmd: %s' % cmd)
|
|
48
48
|
resp = c.command(cmd, 60)
|
|
49
49
|
self.logger.debug('Clone resp: %s' % resp)
|
|
50
|
-
if resp['
|
|
50
|
+
if resp['killed'] or resp['returncode'] != 0:
|
|
51
51
|
self.logger.error('Error occured while cloning repository: %s' % ('killed' if resp['killed'] else resp['stderr']))
|
|
52
52
|
return False
|
|
53
53
|
|
|
@@ -645,7 +645,7 @@ a:hover.icon.icon-home {
|
|
|
645
645
|
'CHANGELOG': templates['CHANGELOG'],
|
|
646
646
|
'GIT_IGNORE': templates['GIT_IGNORE'],
|
|
647
647
|
}, 10)
|
|
648
|
-
if resp['
|
|
648
|
+
if resp['killed'] or resp['returncode'] != 0:
|
|
649
649
|
self.logger.error('Error occured while creating application: %s' % ('killed' if resp['killed'] else resp['stderr']))
|
|
650
650
|
shutil.rmtree(path)
|
|
651
651
|
return False
|