pywebexec 0.0.8__py3-none-any.whl → 0.1.1__py3-none-any.whl
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.
- pywebexec/pywebexec.py +7 -3
- pywebexec/templates/index.html +63 -6
- pywebexec/version.py +2 -2
- {pywebexec-0.0.8.dist-info → pywebexec-0.1.1.dist-info}/METADATA +3 -2
- {pywebexec-0.0.8.dist-info → pywebexec-0.1.1.dist-info}/RECORD +9 -9
- {pywebexec-0.0.8.dist-info → pywebexec-0.1.1.dist-info}/LICENSE +0 -0
- {pywebexec-0.0.8.dist-info → pywebexec-0.1.1.dist-info}/WHEEL +0 -0
- {pywebexec-0.0.8.dist-info → pywebexec-0.1.1.dist-info}/entry_points.txt +0 -0
- {pywebexec-0.0.8.dist-info → pywebexec-0.1.1.dist-info}/top_level.txt +0 -0
pywebexec/pywebexec.py
CHANGED
|
@@ -11,7 +11,7 @@ import random
|
|
|
11
11
|
import string
|
|
12
12
|
from datetime import datetime
|
|
13
13
|
import shlex
|
|
14
|
-
from gunicorn.app.base import
|
|
14
|
+
from gunicorn.app.base import Application
|
|
15
15
|
|
|
16
16
|
app = Flask(__name__)
|
|
17
17
|
auth = HTTPBasicAuth()
|
|
@@ -200,7 +200,7 @@ def run_script(script_name, params, script_id):
|
|
|
200
200
|
output_file_path = get_output_file_path(script_id)
|
|
201
201
|
with open(output_file_path, 'w') as output_file:
|
|
202
202
|
# Run the script with parameters and redirect stdout and stderr to the file
|
|
203
|
-
process = subprocess.Popen([script_name] + params, stdout=output_file, stderr=output_file, text=True)
|
|
203
|
+
process = subprocess.Popen([script_name] + params, stdout=output_file, stderr=output_file, bufsize=0) #text=True)
|
|
204
204
|
update_script_status(script_id, 'running', pid=process.pid)
|
|
205
205
|
processes[script_id] = process
|
|
206
206
|
process.wait()
|
|
@@ -311,7 +311,11 @@ def list_scripts():
|
|
|
311
311
|
script_id = filename[:-5]
|
|
312
312
|
status = read_script_status(script_id)
|
|
313
313
|
if status:
|
|
314
|
-
|
|
314
|
+
try:
|
|
315
|
+
params = shlex.join(status['params'])
|
|
316
|
+
except AttributeError:
|
|
317
|
+
params = " ".join([shlex.quote(p) if " " in p else p for p in status['params']])
|
|
318
|
+
command = status['script_name'] + ' ' + params
|
|
315
319
|
scripts.append({
|
|
316
320
|
'script_id': script_id,
|
|
317
321
|
'status': status['status'],
|
pywebexec/templates/index.html
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<title>pywebexec</title>
|
|
6
6
|
<style>
|
|
7
7
|
body { font-family: Arial, sans-serif; }
|
|
8
|
-
.table-container {
|
|
8
|
+
.table-container { height: 380px; overflow-y: auto; position: relative; }
|
|
9
9
|
table { width: 100%; border-collapse: collapse; }
|
|
10
10
|
th, td { padding: 8px; text-align: left; border-bottom: 1px solid #ddd; }
|
|
11
11
|
th { background-color: #f2f2f2; position: sticky; top: 0; z-index: 1; }
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
border: 1px solid #ccc;
|
|
17
17
|
font-family: monospace;
|
|
18
18
|
border-radius: 15px;
|
|
19
|
+
overflow-y: auto;
|
|
19
20
|
}
|
|
20
21
|
.copy-icon { cursor: pointer; }
|
|
21
22
|
.monospace { font-family: monospace; }
|
|
@@ -85,6 +86,20 @@
|
|
|
85
86
|
.currentscript {
|
|
86
87
|
background-color: #eef;
|
|
87
88
|
}
|
|
89
|
+
.resizer {
|
|
90
|
+
width: 100%;
|
|
91
|
+
height: 5px;
|
|
92
|
+
background: #aaa;
|
|
93
|
+
cursor: ns-resize;
|
|
94
|
+
position: absolute;
|
|
95
|
+
bottom: 0;
|
|
96
|
+
left: 0;
|
|
97
|
+
}
|
|
98
|
+
.resizer-container {
|
|
99
|
+
position: relative;
|
|
100
|
+
height: 5px;
|
|
101
|
+
margin-bottom: 10px;
|
|
102
|
+
}
|
|
88
103
|
</style>
|
|
89
104
|
</head>
|
|
90
105
|
<body>
|
|
@@ -96,7 +111,7 @@
|
|
|
96
111
|
<input type="text" id="params" name="params">
|
|
97
112
|
<button type="submit">Launch</button>
|
|
98
113
|
</form>
|
|
99
|
-
<div class="table-container">
|
|
114
|
+
<div class="table-container" id="tableContainer">
|
|
100
115
|
<table>
|
|
101
116
|
<thead>
|
|
102
117
|
<tr>
|
|
@@ -112,6 +127,9 @@
|
|
|
112
127
|
<tbody id="scripts"></tbody>
|
|
113
128
|
</table>
|
|
114
129
|
</div>
|
|
130
|
+
<div class="resizer-container">
|
|
131
|
+
<div class="resizer" id="resizer"></div>
|
|
132
|
+
</div>
|
|
115
133
|
<div id="output" class="output"></div>
|
|
116
134
|
|
|
117
135
|
<script>
|
|
@@ -131,7 +149,7 @@
|
|
|
131
149
|
});
|
|
132
150
|
const data = await response.json();
|
|
133
151
|
fetchScripts();
|
|
134
|
-
viewOutput(data.script_id)
|
|
152
|
+
viewOutput(data.script_id);
|
|
135
153
|
});
|
|
136
154
|
|
|
137
155
|
async function fetchScripts() {
|
|
@@ -184,13 +202,15 @@
|
|
|
184
202
|
clearInterval(outputInterval);
|
|
185
203
|
} else {
|
|
186
204
|
outputDiv.innerHTML = data.output;
|
|
205
|
+
outputDiv.scrollTop = outputDiv.scrollHeight;
|
|
187
206
|
if (data.status != 'running') {
|
|
188
|
-
clearInterval(outputInterval)
|
|
207
|
+
clearInterval(outputInterval);
|
|
189
208
|
}
|
|
190
209
|
}
|
|
191
210
|
}
|
|
192
211
|
|
|
193
212
|
async function viewOutput(script_id) {
|
|
213
|
+
adjustOutputHeight();
|
|
194
214
|
currentScriptId = script_id;
|
|
195
215
|
clearInterval(outputInterval);
|
|
196
216
|
const response = await fetch(`/script_status/${script_id}`);
|
|
@@ -223,7 +243,7 @@
|
|
|
223
243
|
});
|
|
224
244
|
const relaunchData = await relaunchResponse.json();
|
|
225
245
|
fetchScripts();
|
|
226
|
-
viewOutput(relaunchData.script_id)
|
|
246
|
+
viewOutput(relaunchData.script_id);
|
|
227
247
|
}
|
|
228
248
|
|
|
229
249
|
async function stopScript(script_id) {
|
|
@@ -258,13 +278,50 @@
|
|
|
258
278
|
|
|
259
279
|
function copyToClipboard(text, element) {
|
|
260
280
|
navigator.clipboard.writeText(text).then(() => {
|
|
261
|
-
element.classList.add('copy_clip_ok')
|
|
281
|
+
element.classList.add('copy_clip_ok');
|
|
262
282
|
setTimeout(() => {
|
|
263
283
|
element.classList.remove('copy_clip_ok');
|
|
264
284
|
}, 2000);
|
|
265
285
|
});
|
|
266
286
|
}
|
|
267
287
|
|
|
288
|
+
function adjustOutputHeight() {
|
|
289
|
+
const outputDiv = document.getElementById('output');
|
|
290
|
+
const windowHeight = window.innerHeight;
|
|
291
|
+
const outputTop = outputDiv.getBoundingClientRect().top;
|
|
292
|
+
const maxHeight = windowHeight - outputTop - 30; // 20px for padding/margin
|
|
293
|
+
outputDiv.style.maxHeight = `${maxHeight}px`;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
function initResizer() {
|
|
297
|
+
const resizer = document.getElementById('resizer');
|
|
298
|
+
const tableContainer = document.getElementById('tableContainer');
|
|
299
|
+
let startY, startHeight;
|
|
300
|
+
|
|
301
|
+
resizer.addEventListener('mousedown', (e) => {
|
|
302
|
+
startY = e.clientY;
|
|
303
|
+
startHeight = parseInt(document.defaultView.getComputedStyle(tableContainer).height, 10);
|
|
304
|
+
document.documentElement.addEventListener('mousemove', doDrag, false);
|
|
305
|
+
document.documentElement.addEventListener('mouseup', stopDrag, false);
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
function doDrag(e) {
|
|
309
|
+
tableContainer.style.height = `${startHeight + e.clientY - startY}px`;
|
|
310
|
+
adjustOutputHeight();
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
function stopDrag() {
|
|
314
|
+
document.documentElement.removeEventListener('mousemove', doDrag, false);
|
|
315
|
+
document.documentElement.removeEventListener('mouseup', stopDrag, false);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
window.addEventListener('resize', adjustOutputHeight);
|
|
320
|
+
window.addEventListener('load', () => {
|
|
321
|
+
adjustOutputHeight();
|
|
322
|
+
initResizer();
|
|
323
|
+
});
|
|
324
|
+
|
|
268
325
|
fetchScripts();
|
|
269
326
|
fetchExecutables();
|
|
270
327
|
setInterval(fetchScripts, 5000);
|
pywebexec/version.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: pywebexec
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.1.1
|
|
4
4
|
Summary: Simple Python HTTP Exec Server
|
|
5
5
|
Home-page: https://github.com/joknarf/pywebexec
|
|
6
6
|
Author: Franck Jouvanceau
|
|
@@ -55,8 +55,9 @@ Description-Content-Type: text/markdown
|
|
|
55
55
|
License-File: LICENSE
|
|
56
56
|
Requires-Dist: python-daemon>=2.3.2
|
|
57
57
|
Requires-Dist: cryptography>=40.0.2
|
|
58
|
-
Requires-Dist: Flask>=
|
|
58
|
+
Requires-Dist: Flask>=2.0.3
|
|
59
59
|
Requires-Dist: Flask-HTTPAuth>=4.8.0
|
|
60
|
+
Requires-Dist: gunicorn>=21.2.0
|
|
60
61
|
|
|
61
62
|
[](https://pypi.org/project/pywebexec/)
|
|
62
63
|

|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
pywebexec/__init__.py,sha256=4spIsVaF8RJt8S58AG_wWoORRNkws9Iwqprj27C3ljM,99
|
|
2
|
-
pywebexec/pywebexec.py,sha256=
|
|
3
|
-
pywebexec/version.py,sha256=
|
|
2
|
+
pywebexec/pywebexec.py,sha256=IyNVTDepd5UPfKBHqctIyNez9McNb7z9xN01rXGIK44,12928
|
|
3
|
+
pywebexec/version.py,sha256=PKIMyjdUACH4-ONvtunQCnYE2UhlMfp9su83e3HXl5E,411
|
|
4
4
|
pywebexec/static/images/aborted.svg,sha256=_mP43hU5QdRLFZIknBgjx-dIXrHgQG23-QV27ApXK2A,381
|
|
5
5
|
pywebexec/static/images/copy.svg,sha256=d9OwtGh5GzzZHzYcDrLfNxZYLth1Q64x7bRyYxu4Px0,622
|
|
6
6
|
pywebexec/static/images/copy_ok.svg,sha256=mEqUVUhSq8xaJK2msQkxRawnz_KwlCZ-tok8QS6hJ3g,451
|
|
@@ -8,10 +8,10 @@ pywebexec/static/images/failed.svg,sha256=ADZ7IKrUyOXtqpivnz3VcH0-Wru-I5MOi3OJAk
|
|
|
8
8
|
pywebexec/static/images/running.svg,sha256=vBpiG6ClNUNCArkwsyqK7O-qhIKJX1NI7MSjclNSp_8,1537
|
|
9
9
|
pywebexec/static/images/success.svg,sha256=PJDcCSTevJh7rkfSFLtc7P0pbeh8PVQBS8DaOLQemmc,489
|
|
10
10
|
pywebexec/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
|
-
pywebexec/templates/index.html,sha256=
|
|
12
|
-
pywebexec-0.
|
|
13
|
-
pywebexec-0.
|
|
14
|
-
pywebexec-0.
|
|
15
|
-
pywebexec-0.
|
|
16
|
-
pywebexec-0.
|
|
17
|
-
pywebexec-0.
|
|
11
|
+
pywebexec/templates/index.html,sha256=0628YJ1TIH7WPA-UJPfYqEjBo8joYn9685R9Zm5Zz30,12356
|
|
12
|
+
pywebexec-0.1.1.dist-info/LICENSE,sha256=gRJf0JPT_wsZJsUGlWPTS8Vypfl9vQ1qjp6sNbKykuA,1064
|
|
13
|
+
pywebexec-0.1.1.dist-info/METADATA,sha256=83vtZn2DbTfVaOFejyAiKhef_rYEiE6-ko_LMi8yPhg,4770
|
|
14
|
+
pywebexec-0.1.1.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
15
|
+
pywebexec-0.1.1.dist-info/entry_points.txt,sha256=l52GBkPCXRkmlHfEyoVauyfBdg8o-CAtC8qQpOIjJK0,55
|
|
16
|
+
pywebexec-0.1.1.dist-info/top_level.txt,sha256=vHoHyzngrfGdm_nM7Xn_5iLmaCrf10XO1EhldgNLEQ8,10
|
|
17
|
+
pywebexec-0.1.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|