Azeez98 commited on
Commit
f67d201
·
verified ·
1 Parent(s): a20f7ac

Upload 3 files

Browse files
Files changed (3) hide show
  1. app.py +277 -479
  2. css/index.css +49 -0
  3. js/index.js +235 -0
app.py CHANGED
@@ -1,479 +1,277 @@
1
- import os
2
- import subprocess
3
- import tarfile
4
- from fastapi import FastAPI, HTTPException, Form, UploadFile, File, Depends, Query, Response
5
- from fastapi.responses import HTMLResponse, FileResponse, StreamingResponse
6
- from pydantic import BaseModel
7
- from tempfile import NamedTemporaryFile
8
- from typing import List
9
- from pydantic import BaseModel
10
-
11
- app = FastAPI()
12
-
13
- REQUIREMENTS_FILE = "requirements1.txt"
14
-
15
- class DockerImageParams(BaseModel):
16
- image_name: str
17
- tag: str = 'latest'
18
-
19
-
20
- @app.post("/download-dependencies")
21
- async def download_dependencies(requirements_file: UploadFile = File(...)):
22
- try:
23
- with NamedTemporaryFile(delete=False) as tmp:
24
- tmp.write(requirements_file.file.read())
25
- tmp_path = tmp.name
26
-
27
- # Ensure the directories exist
28
- os.makedirs("/tmp/dependencies", exist_ok=True)
29
-
30
- log_file_path = "/tmp/dependencies/download.log"
31
- with open(log_file_path, "w") as log_file:
32
- # Download dependencies
33
- result = subprocess.run(["pip", "download", "-r", tmp_path, "-d", "/tmp/dependencies"], stdout=log_file, stderr=log_file)
34
-
35
- if result.returncode != 0:
36
- raise HTTPException(status_code=500, detail="Error downloading dependencies. See log file for details.")
37
-
38
- # Create a tar file
39
- tar_path = "/tmp/dependencies.tar.gz"
40
- with tarfile.open(tar_path, "w:gz") as tar:
41
- for root, _, files in os.walk("/tmp/dependencies"):
42
- for file in files:
43
- file_path = os.path.join(root, file)
44
- tar.add(file_path, arcname=file)
45
- tar.add(log_file_path, arcname="download.log")
46
-
47
- # Serve the tar file
48
- return FileResponse(tar_path, filename='dependencies.tar.gz')
49
-
50
- except subprocess.CalledProcessError as e:
51
- raise HTTPException(status_code=500, detail=f"Error downloading dependencies: {str(e)}")
52
- except Exception as e:
53
- raise HTTPException(status_code=500, detail=str(e))
54
- finally:
55
- os.remove(tmp_path)
56
-
57
- class DockerImageParams(BaseModel):
58
- image_name: str
59
- tag: str = 'latest'
60
-
61
- def download_docker_image(image_name, tag='latest', destination='/tmp/docker-images'):
62
- try:
63
- os.makedirs(destination, exist_ok=True)
64
-
65
- tar_path = os.path.join(destination, f'{image_name.replace("/", "_")}.tar')
66
-
67
- # Remove the existing tar file if it exists
68
- if os.path.exists(tar_path):
69
- os.remove(tar_path)
70
-
71
- # Skopeo command to copy the image as a tar file
72
- command = [
73
- 'skopeo', 'copy',
74
- f'docker://{image_name}:{tag}',
75
- f'docker-archive:{tar_path}'
76
- ]
77
- subprocess.run(command, check=True)
78
- print(f"Image '{image_name}:{tag}' downloaded successfully to {destination}.")
79
- return tar_path
80
- except subprocess.CalledProcessError as e:
81
- print(f"Error downloading image: {str(e)}")
82
- raise HTTPException(status_code=500, detail=f"Error downloading Docker image: {str(e)}")
83
-
84
- @app.get("/", response_class=HTMLResponse)
85
- async def read_root():
86
- html_content = """
87
- <html>
88
- <head>
89
- <title>Welcome to FastAPI</title>
90
- <style>
91
- /* Style the tab */
92
- .tab {
93
- overflow: hidden;
94
- border: 1px solid #ccc;
95
- background-color: #f1f1f1;
96
- }
97
-
98
- /* Style the buttons inside the tab */
99
- .tab button {
100
- background-color: inherit;
101
- float: left;
102
- border: none;
103
- outline: none;
104
- cursor: pointer;
105
- padding: 14px 16px;
106
- transition: 0.3s;
107
- font-size: 17px;
108
- }
109
-
110
- /* Change background color of buttons on hover */
111
- .tab button:hover {
112
- background-color: #ddd;
113
- }
114
-
115
- /* Create an active/current tablink class */
116
- .tab button.active {
117
- background-color: #ccc;
118
- }
119
-
120
- /* Style the tab content */
121
- .tabcontent {
122
- display: none;
123
- padding: 6px 12px;
124
- border: 1px solid #ccc;
125
- border-top: none;
126
- }
127
-
128
- #progress-container {
129
- width: 100%;
130
- background-color: #f3f3f3;
131
- }
132
- #progress-bar {
133
- width: 0%;
134
- height: 30px;
135
- background-color: #4caf50;
136
- text-align: center;
137
- line-height: 30px;
138
- color: white;
139
- }
140
- </style>
141
- <script>
142
- function openTab(evt, tabName) {
143
- // Declare all variables
144
- var i, tabcontent, tablinks;
145
-
146
- // Get all elements with class="tabcontent" and hide them
147
- tabcontent = document.getElementsByClassName("tabcontent");
148
- for (i = 0; i < tabcontent.length; i++) {
149
- tabcontent[i].style.display = "none";
150
- }
151
-
152
- // Get all elements with class="tablinks" and remove the class "active"
153
- tablinks = document.getElementsByClassName("tablinks");
154
- for (i = 0; i < tablinks.length; i++) {
155
- tablinks[i].className = tablinks[i].className.replace(" active", "");
156
- }
157
-
158
- // Show the current tab, and add an "active" class to the button that opened the tab
159
- document.getElementById(tabName).style.display = "block";
160
- evt.currentTarget.className += " active";
161
- }
162
-
163
- async function handleDockerFormSubmit(event) {
164
- event.preventDefault(); // Prevent the form from submitting the traditional way
165
- const submitButton = document.getElementById('docker-submit-button');
166
- const messageDiv = document.getElementById('docker-message');
167
- const progressBar = document.getElementById('progress-bar');
168
- submitButton.disabled = true; // Disable the submit button
169
- messageDiv.textContent = "Downloading Docker image..."; // Show downloading message
170
- messageDiv.style.display = 'block';
171
-
172
- const form = event.target;
173
- const imageName = form.image_name.value;
174
- const tag = form.tag.value;
175
-
176
- try {
177
- const response = await fetch(`/download-docker-image?image_name=${imageName}&tag=${tag}`);
178
- if (response.ok) {
179
- const reader = response.body.getReader();
180
- const contentLength = response.headers.get('content-length');
181
- const total = parseInt(contentLength, 10);
182
- let loaded = 0;
183
-
184
- const stream = new ReadableStream({
185
- start(controller) {
186
- function push() {
187
- reader.read().then(({ done, value }) => {
188
- if (done) {
189
- controller.close();
190
- progressBar.style.width = '100%';
191
- messageDiv.textContent = "Download complete!";
192
- return;
193
- }
194
- loaded += value.length;
195
- const percent = Math.round((loaded / total) * 100);
196
- progressBar.style.width = `${percent}%`;
197
- progressBar.textContent = `${percent}%`;
198
- controller.enqueue(value);
199
- push();
200
- }).catch(error => {
201
- console.error('Error:', error);
202
- messageDiv.textContent = "Error downloading image.";
203
- });
204
- }
205
- push();
206
- }
207
- });
208
-
209
- const blob = await new Response(stream).blob();
210
- const url = window.URL.createObjectURL(blob);
211
- const a = document.createElement('a');
212
- a.style.display = 'none';
213
- a.href = url;
214
- a.download = `${imageName.replace("/", "_")}.tar`;
215
- document.body.appendChild(a);
216
- a.click();
217
- window.URL.revokeObjectURL(url);
218
- } else if (response.status === 404) {
219
- throw new Error('Image not found');
220
- } else {
221
- throw new Error('Download failed');
222
- }
223
- } catch (error) {
224
- console.error('Error:', error);
225
- if (error.message === 'Image not found') {
226
- messageDiv.textContent = "Error: Docker image not found."; // Show not found message
227
- } else {
228
- messageDiv.innerHTML = "Error downloading image.<br>Check the image name and tag."; // Show error message in two lines
229
- }
230
- } finally {
231
- submitButton.disabled = false; // Re-enable the submit button after download
232
- }
233
- }
234
-
235
- async function handlePipFormSubmit(event) {
236
- event.preventDefault(); // Prevent the form from submitting the traditional way
237
- const submitButton = document.getElementById('pip-submit-button');
238
- const messageDiv = document.getElementById('pip-message');
239
- submitButton.disabled = true; // Disable the submit button
240
- messageDiv.textContent = "Downloading dependencies..."; // Show downloading message
241
- messageDiv.style.display = 'block';
242
-
243
- const formData = new FormData(event.target);
244
- try {
245
- const response = await fetch('/download-dependencies', {
246
- method: 'POST',
247
- body: formData
248
- });
249
- if (response.ok) {
250
- const blob = await response.blob();
251
- const url = window.URL.createObjectURL(blob);
252
- const a = document.createElement('a');
253
- a.style.display = 'none';
254
- a.href = url;
255
- a.download = 'dependencies.tar.gz';
256
- document.body.appendChild(a);
257
- a.click();
258
- window.URL.revokeObjectURL(url);
259
- messageDiv.textContent = "Download complete!"; // Show download complete message
260
- } else {
261
- throw new Error('Download failed');
262
- }
263
- } catch (error) {
264
- console.error('Error:', error);
265
- messageDiv.innerHTML = "Error downloading dependencies.<br>Please try again."; // Show error message in two lines
266
- } finally {
267
- submitButton.disabled = false; // Re-enable the submit button after download
268
- }
269
- }
270
-
271
- async function handleDebFormSubmit(event) {
272
- event.preventDefault(); // Prevent the form from submitting the traditional way
273
- const submitButton = document.getElementById('deb-submit-button');
274
- const messageDiv = document.getElementById('deb-message');
275
- submitButton.disabled = true; // Disable the submit button
276
- messageDiv.textContent = "Downloading Debian packages..."; // Show downloading message
277
- messageDiv.style.display = 'block';
278
-
279
- const formData = new FormData(event.target);
280
- try {
281
- const response = await fetch('/download-deb-packages', {
282
- method: 'POST',
283
- body: formData
284
- });
285
- if (response.ok) {
286
- const blob = await response.blob();
287
- const url = window.URL.createObjectURL(blob);
288
- const a = document.createElement('a');
289
- a.style.display = 'none';
290
- a.href = url;
291
- a.download = 'deb-packages.tar.gz';
292
- document.body.appendChild(a);
293
- a.click();
294
- window.URL.revokeObjectURL(url);
295
- messageDiv.textContent = "Download complete!"; // Show download complete message
296
- } else {
297
- throw new Error('Download failed');
298
- }
299
- } catch (error) {
300
- console.error('Error:', error);
301
- messageDiv.innerHTML = "Error downloading Debian packages.<br>Please try again."; // Show error message in two lines
302
- } finally {
303
- submitButton.disabled = false; // Re-enable the submit button after download
304
- }
305
- }
306
- </script>
307
- </head>
308
- <body>
309
- <h1>Welcome to Azeez's Help Desk :)</h1>
310
-
311
- <div class="tab">
312
- <button class="tablinks" onclick="openTab(event, 'Docker')">Docker Image Download</button>
313
- <button class="tablinks" onclick="openTab(event, 'Pip')">Pip Dependencies Download</button>
314
- <button class="tablinks" onclick="openTab(event, 'Deb')">Debian Packages Download</button>
315
- </div>
316
-
317
- <div id="Docker" class="tabcontent">
318
- <h2>Docker Image Download</h2>
319
- <form onsubmit="handleDockerFormSubmit(event)">
320
- <label for="image_name">Docker Image Name:</label>
321
- <input type="text" id="image_name" name="image_name" required><br><br>
322
-
323
- <label for="tag">Docker Image Tag:</label>
324
- <input type="text" id="tag" name="tag" value="latest" required><br><br>
325
-
326
- <input type="submit" id="docker-submit-button" value="Download Docker Image">
327
- </form>
328
- <div id="docker-message" style="display: none; margin-top: 10px;"></div>
329
- <div id="progress-container">
330
- <div id="progress-bar">0%</div>
331
- </div>
332
- </div>
333
-
334
- <div id="Pip" class="tabcontent">
335
- <h2>Pip Dependencies Download</h2>
336
- <form onsubmit="handlePipFormSubmit(event)">
337
- <label for="requirements_file">Requirements File:</label>
338
- <input type="file" id="requirements_file" name="requirements_file" accept=".txt" required><br><br>
339
-
340
- <input type="submit" id="pip-submit-button" value="Download Dependencies">
341
- </form>
342
- <div id="pip-message" style="display: none; margin-top: 10px;"></div>
343
- </div>
344
-
345
- <div id="Deb" class="tabcontent">
346
- <h2>Debian Packages Download</h2>
347
- <form onsubmit="handleDebFormSubmit(event)">
348
- <label for="deb_packages">Debian Package Names (comma-separated):</label>
349
- <input type="text" id="deb_packages" name="deb_packages" required><br><br>
350
-
351
- <input type="submit" id="deb-submit-button" value="Download Debian Packages">
352
- </form>
353
- <div id="deb-message" style="display: none; margin-top: 10px;"></div>
354
- </div>
355
-
356
- </body>
357
- </html>
358
- """
359
- return HTMLResponse(content=html_content)
360
-
361
- @app.get("/download-docker-image")
362
- async def download_docker_image_endpoint(image_name: str = Query(...), tag: str = Query('latest')):
363
- tar_path = download_docker_image(image_name, tag)
364
- file_size = os.path.getsize(tar_path)
365
-
366
- def iterfile():
367
- with open(tar_path, 'rb') as file:
368
- while chunk := file.read(1024 * 1024): # Read in 1 MB chunks
369
- yield chunk
370
-
371
- headers = {
372
- "Content-Disposition": f'attachment; filename="{image_name.replace("/", "_")}.tar"',
373
- "Content-Length": str(file_size)
374
- }
375
-
376
- return StreamingResponse(iterfile(), media_type='application/x-tar', headers=headers)
377
-
378
- def create_tar_file(files_to_package: List[str], tar_filename: str, destination_dir: str):
379
- """
380
- Create a tar file containing specified files.
381
- Args:
382
- - files_to_package (list): List of paths to files to include in the tar file.
383
- - tar_filename (str): Name of the tar file to create.
384
- - destination_dir (str): Directory to save the tar file.
385
- """
386
- try:
387
- tar_path = os.path.join(destination_dir, tar_filename)
388
- with tarfile.open(tar_path, "w:gz") as tar:
389
- for file_path in files_to_package:
390
- tar.add(file_path, arcname=os.path.basename(file_path))
391
- print(f"Created tar file '{tar_filename}' successfully in '{destination_dir}'.")
392
- return tar_path
393
- except Exception as e:
394
- print(f"Error creating tar file: {e}")
395
- raise
396
-
397
- def download_deb_packages(package_names: List[str], destination_dir: str) -> List[str]:
398
- """
399
- Download Debian packages (`.deb`) and their dependencies using `apt-get download`.
400
- Args:
401
- - package_names (list): List of package names to download.
402
- - destination_dir (str): Directory to save downloaded packages.
403
- Returns:
404
- - List of paths to downloaded `.deb` packages.
405
- """
406
- try:
407
- # Create the destination directory if it doesn't exist
408
- os.makedirs(destination_dir, exist_ok=True)
409
-
410
- downloaded_packages = []
411
-
412
- # Download each package and its dependencies
413
- for package_name in package_names:
414
- # Run apt-get update to refresh package index
415
- # subprocess.run(['apt-get', 'update'], check=True)
416
- # Download the package to the destination directory
417
- subprocess.run(['apt-get', 'download', package_name, '-d', destination_dir], check=True)
418
- # Build the full path to the downloaded package
419
- deb_filename = f"{package_name}.deb"
420
- downloaded_packages.append(os.path.join(destination_dir, deb_filename))
421
-
422
- return downloaded_packages
423
-
424
- except subprocess.CalledProcessError as e:
425
- print(f"Error downloading packages: {e}")
426
- raise
427
-
428
- import subprocess
429
-
430
- def download_make_package(destination_dir):
431
- try:
432
- # Ensure the destination directory exists
433
- subprocess.run(['mkdir', '-p', destination_dir])
434
-
435
- # Download the make package
436
- result = subprocess.run(['apt-get', 'download', 'make', '-d', destination_dir], check=True)
437
-
438
- if result.returncode == 0:
439
- print(f"Downloaded make package and dependencies to {destination_dir} successfully.")
440
- else:
441
- print("Failed to download make package.")
442
-
443
- except subprocess.CalledProcessError as e:
444
- print(f"Error downloading packages: {e}")
445
-
446
- @app.post("/download-deb-packages")
447
- async def download_deb_packages_handler(deb_packages: str = Form(...)):
448
- try:
449
- destination_dir = '/tmp/downloaded_packages'
450
- subprocess.run(['mkdir', '-p', destination_dir]) # Ensure destination directory exists
451
-
452
- package_name='make'
453
-
454
- # Download the package using apt-get
455
- result = subprocess.run(['apt-get', 'install', package_name], check=True)
456
-
457
- # If download is successful, return the downloaded package
458
- if result.returncode == 0:
459
- tar_filename = f'{package_name}.tar.gz'
460
- tar_path = f'{destination_dir}/{tar_filename}'
461
- return FileResponse(tar_path, filename=tar_filename)
462
-
463
- # If download fails, raise HTTPException
464
- else:
465
- raise HTTPException(status_code=500, detail=f"Failed to download {package_name} package.")
466
-
467
- except subprocess.CalledProcessError as e:
468
- error_message = str(e.stderr)
469
- print(f"Error downloading packages: {error_message}")
470
- raise HTTPException(status_code=500, detail=f"Error downloading {package_name} package: {error_message}")
471
-
472
- except Exception as e:
473
- print(f"Error: {str(e)}")
474
- raise HTTPException(status_code=500, detail=f"Failed to download {package_name} package: {str(e)}")
475
-
476
-
477
- if __name__ == "__main__":
478
- import uvicorn
479
- uvicorn.run(app, host="0.0.0.0", port=5000)
 
1
+ import os
2
+ import subprocess
3
+ import tarfile
4
+ import asyncio
5
+ from fastapi import FastAPI, HTTPException, Form, UploadFile, File, Depends, Query, Response
6
+ from fastapi.responses import HTMLResponse, FileResponse, StreamingResponse
7
+ from pydantic import BaseModel
8
+ from tempfile import NamedTemporaryFile
9
+ from typing import List
10
+ from pydantic import BaseModel
11
+
12
+ app = FastAPI()
13
+
14
+ REQUIREMENTS_FILE = "requirements1.txt"
15
+
16
+ class DockerImageParams(BaseModel):
17
+ image_name: str
18
+ tag: str = 'latest'
19
+
20
+ app = FastAPI()
21
+
22
+ async def stream_log(file_path):
23
+ with open(file_path, 'r') as file:
24
+ while True:
25
+ line = file.readline()
26
+ if line:
27
+ yield line
28
+ else:
29
+ await asyncio.sleep(0.1)
30
+
31
+ @app.post("/download-dependencies")
32
+ async def download_dependencies(requirements_file: UploadFile = File(...)):
33
+ try:
34
+ with NamedTemporaryFile(delete=False) as tmp:
35
+ tmp.write(requirements_file.file.read())
36
+ tmp_path = tmp.name
37
+
38
+ # Ensure the directories exist
39
+ os.makedirs("/tmp/dependencies", exist_ok=True)
40
+
41
+ log_file_path = "/tmp/dependencies/download.log"
42
+ with open(log_file_path, "w") as log_file:
43
+ # Download dependencies
44
+ result = subprocess.run(
45
+ ["pip", "download", "-r", tmp_path, "-d", "/tmp/dependencies"],
46
+ stdout=log_file,
47
+ stderr=log_file
48
+ )
49
+
50
+ if result.returncode != 0:
51
+ raise HTTPException(status_code=500, detail="Error downloading dependencies. See log file for details.")
52
+
53
+ # Create a tar file
54
+ tar_path = "/tmp/dependencies.tar.gz"
55
+ with tarfile.open(tar_path, "w:gz") as tar:
56
+ for root, _, files in os.walk("/tmp/dependencies"):
57
+ for file in files:
58
+ file_path = os.path.join(root, file)
59
+ tar.add(file_path, arcname=file)
60
+ tar.add(log_file_path, arcname="download.log")
61
+
62
+ return StreamingResponse(stream_log(log_file_path), media_type="text/plain")
63
+
64
+ except subprocess.CalledProcessError as e:
65
+ raise HTTPException(status_code=500, detail=f"Error downloading dependencies: {str(e)}")
66
+ except Exception as e:
67
+ raise HTTPException(status_code=500, detail=str(e))
68
+ finally:
69
+ os.remove(tmp_path)
70
+
71
+ class DockerImageParams(BaseModel):
72
+ image_name: str
73
+ tag: str = 'latest'
74
+
75
+ def download_docker_image(image_name, tag='latest', destination='/tmp/docker-images'):
76
+ try:
77
+ os.makedirs(destination, exist_ok=True)
78
+
79
+ tar_path = os.path.join(destination, f'{image_name.replace("/", "_")}.tar')
80
+
81
+ # Remove the existing tar file if it exists
82
+ if os.path.exists(tar_path):
83
+ os.remove(tar_path)
84
+
85
+ # Skopeo command to copy the image as a tar file
86
+ command = [
87
+ 'skopeo', 'copy',
88
+ f'docker://{image_name}:{tag}',
89
+ f'docker-archive:{tar_path}'
90
+ ]
91
+ subprocess.run(command, check=True)
92
+ print(f"Image '{image_name}:{tag}' downloaded successfully to {destination}.")
93
+ return tar_path
94
+ except subprocess.CalledProcessError as e:
95
+ print(f"Error downloading image: {str(e)}")
96
+ raise HTTPException(status_code=500, detail=f"Error downloading Docker image: {str(e)}")
97
+
98
+ @app.get("/", response_class=HTMLResponse)
99
+ async def read_root():
100
+ html_content = """
101
+ <html>
102
+ <head>
103
+ <title>Azeez's Help Desk</title>
104
+ <link href src"/css/index.css" rel="stylesheet">
105
+ <script src="js/index.js></script>
106
+ </head>
107
+ <body>
108
+ <h1>Welcome to Azeez's Help Desk :)</h1>
109
+
110
+ <div class="tab">
111
+ <button class="tablink" onclick="openTab(event, 'Docker')" id="defaultOpen">Docker Image Download</button>
112
+ <button class="tablink" onclick="openTab(event, 'Pip')">Pip Dependencies Download</button>
113
+ <button class="tablink" onclick="openTab(event, 'Deb')">Debian Packages Download</button>
114
+ </div>
115
+
116
+ <div id="Docker" class="tabcontent">
117
+ <h2>Docker Image Download</h2>
118
+ <form onsubmit="handleDockerFormSubmit(event)">
119
+ <label for="image_name">Docker Image Name:</label>
120
+ <input type="text" id="image_name" name="image_name" required><br><br>
121
+
122
+ <label for="tag">Docker Image Tag:</label>
123
+ <input type="text" id="tag" name="tag" value="latest" required><br><br>
124
+
125
+ <input type="submit" id="docker-submit-button" value="Download Docker Image">
126
+ </form>
127
+ <div id="docker-message" style="display: none; margin-top: 10px;"></div>
128
+ </div>
129
+
130
+ <div id="Pip" class="tabcontent">
131
+ <h2>Pip Dependencies Download</h2>
132
+ <form onsubmit="handlePipFormSubmit(event)">
133
+ <label for="requirements_file">Requirements File:</label>
134
+ <input type="file" id="requirements_file" name="requirements_file" accept=".txt" required><br><br>
135
+
136
+ <input type="submit" id="pip-submit-button" value="Download Dependencies">
137
+ </form>
138
+ <div id="pip-message" style="display: none; margin-top: 10px;"></div>
139
+ </div>
140
+
141
+ <div id="Deb" class="tabcontent">
142
+ <h2>Debian Packages Download</h2>
143
+ <form onsubmit="handleDebFormSubmit(event)">
144
+ <label for="deb_packages">Debian Package Names (comma-separated):</label>
145
+ <input type="text" id="deb_packages" name="deb_packages" required><br><br>
146
+
147
+ <input type="submit" id="deb-submit-button" value="Download Debian Packages">
148
+ </form>
149
+ <div id="deb-message" style="display: none; margin-top: 10px;"></div>
150
+ </div>
151
+ <div id="progress-container">
152
+ <div id="progress-bar">0%</div>
153
+ </div>
154
+ </body>
155
+ </html>
156
+ """
157
+ return HTMLResponse(content=html_content)
158
+
159
+ @app.get("/download-docker-image")
160
+ async def download_docker_image_endpoint(image_name: str = Query(...), tag: str = Query('latest')):
161
+ tar_path = download_docker_image(image_name, tag)
162
+ file_size = os.path.getsize(tar_path)
163
+
164
+ def iterfile():
165
+ with open(tar_path, 'rb') as file:
166
+ while chunk := file.read(1024 * 1024): # Read in 1 MB chunks
167
+ yield chunk
168
+
169
+ headers = {
170
+ "Content-Disposition": f'attachment; filename="{image_name.replace("/", "_")}.tar"',
171
+ "Content-Length": str(file_size)
172
+ }
173
+
174
+ return StreamingResponse(iterfile(), media_type='application/x-tar', headers=headers)
175
+
176
+ def create_tar_file(files_to_package: List[str], tar_filename: str, destination_dir: str):
177
+ """
178
+ Create a tar file containing specified files.
179
+ Args:
180
+ - files_to_package (list): List of paths to files to include in the tar file.
181
+ - tar_filename (str): Name of the tar file to create.
182
+ - destination_dir (str): Directory to save the tar file.
183
+ """
184
+ try:
185
+ tar_path = os.path.join(destination_dir, tar_filename)
186
+ with tarfile.open(tar_path, "w:gz") as tar:
187
+ for file_path in files_to_package:
188
+ tar.add(file_path, arcname=os.path.basename(file_path))
189
+ print(f"Created tar file '{tar_filename}' successfully in '{destination_dir}'.")
190
+ return tar_path
191
+ except Exception as e:
192
+ print(f"Error creating tar file: {e}")
193
+ raise
194
+
195
+ def download_deb_packages(package_names: List[str], destination_dir: str) -> List[str]:
196
+ """
197
+ Download Debian packages (`.deb`) and their dependencies using `apt-get download`.
198
+ Args:
199
+ - package_names (list): List of package names to download.
200
+ - destination_dir (str): Directory to save downloaded packages.
201
+ Returns:
202
+ - List of paths to downloaded `.deb` packages.
203
+ """
204
+ try:
205
+ # Create the destination directory if it doesn't exist
206
+ os.makedirs(destination_dir, exist_ok=True)
207
+
208
+ downloaded_packages = []
209
+
210
+ # Download each package and its dependencies
211
+ for package_name in package_names:
212
+ # Run apt-get update to refresh package index
213
+ # subprocess.run(['apt-get', 'update'], check=True)
214
+ # Download the package to the destination directory
215
+ subprocess.run(['apt-get', 'download', package_name, '-d', destination_dir], check=True)
216
+ # Build the full path to the downloaded package
217
+ deb_filename = f"{package_name}.deb"
218
+ downloaded_packages.append(os.path.join(destination_dir, deb_filename))
219
+
220
+ return downloaded_packages
221
+
222
+ except subprocess.CalledProcessError as e:
223
+ print(f"Error downloading packages: {e}")
224
+ raise
225
+
226
+ import subprocess
227
+
228
+ def download_make_package(destination_dir):
229
+ try:
230
+ # Ensure the destination directory exists
231
+ subprocess.run(['mkdir', '-p', destination_dir])
232
+
233
+ # Download the make package
234
+ result = subprocess.run(['apt-get', 'download', 'make', '-d', destination_dir], check=True)
235
+
236
+ if result.returncode == 0:
237
+ print(f"Downloaded make package and dependencies to {destination_dir} successfully.")
238
+ else:
239
+ print("Failed to download make package.")
240
+
241
+ except subprocess.CalledProcessError as e:
242
+ print(f"Error downloading packages: {e}")
243
+
244
+ @app.post("/download-deb-packages")
245
+ async def download_deb_packages_handler(deb_packages: str = Form(...)):
246
+ try:
247
+ destination_dir = '/tmp/downloaded_packages'
248
+ subprocess.run(['mkdir', '-p', destination_dir]) # Ensure destination directory exists
249
+
250
+ package_name='make'
251
+
252
+ # Download the package using apt-get
253
+ result = subprocess.run(['apt-get', 'install', package_name], check=True)
254
+
255
+ # If download is successful, return the downloaded package
256
+ if result.returncode == 0:
257
+ tar_filename = f'{package_name}.tar.gz'
258
+ tar_path = f'{destination_dir}/{tar_filename}'
259
+ return FileResponse(tar_path, filename=tar_filename)
260
+
261
+ # If download fails, raise HTTPException
262
+ else:
263
+ raise HTTPException(status_code=500, detail=f"Failed to download {package_name} package.")
264
+
265
+ except subprocess.CalledProcessError as e:
266
+ error_message = str(e.stderr)
267
+ print(f"Error downloading packages: {error_message}")
268
+ raise HTTPException(status_code=500, detail=f"Error downloading {package_name} package: {error_message}")
269
+
270
+ except Exception as e:
271
+ print(f"Error: {str(e)}")
272
+ raise HTTPException(status_code=500, detail=f"Failed to download {package_name} package: {str(e)}")
273
+
274
+
275
+ if __name__ == "__main__":
276
+ import uvicorn
277
+ uvicorn.run(app, host="0.0.0.0", port=5000)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
css/index.css ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Style the tab */
2
+ .tab {
3
+ overflow: hidden;
4
+ border: 1px solid #ccc;
5
+ background-color: #f1f1f1;
6
+ }
7
+
8
+ /* Style the buttons inside the tab */
9
+ .tab button {
10
+ background-color: inherit;
11
+ float: left;
12
+ border: none;
13
+ outline: none;
14
+ cursor: pointer;
15
+ padding: 14px 16px;
16
+ transition: 0.3s;
17
+ font-size: 17px;
18
+ }
19
+
20
+ /* Change background color of buttons on hover */
21
+ .tab button:hover {
22
+ background-color: #ddd;
23
+ }
24
+
25
+ /* Create an active/current tablink class */
26
+ .tab button.active {
27
+ background-color: #ccc;
28
+ }
29
+
30
+ /* Style the tab content */
31
+ .tabcontent {
32
+ display: none;
33
+ padding: 6px 12px;
34
+ border: 1px solid #ccc;
35
+ border-top: none;
36
+ }
37
+
38
+ #progress-container {
39
+ width: 100%;
40
+ background-color: #f3f3f3;
41
+ }
42
+ #progress-bar {
43
+ width: 0%;
44
+ height: 30px;
45
+ background-color: #4caf50;
46
+ text-align: center;
47
+ line-height: 30px;
48
+ color: white;
49
+ }
js/index.js ADDED
@@ -0,0 +1,235 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ async function handleDockerFormSubmit(event) {
3
+ event.preventDefault(); // Prevent the form from submitting the traditional way
4
+ const submitButton = document.getElementById('docker-submit-button');
5
+ const messageDiv = document.getElementById('docker-message');
6
+ const progressBar = document.getElementById('progress-bar');
7
+ submitButton.disabled = true; // Disable the submit button
8
+ messageDiv.textContent = "Downloading Docker image..."; // Show downloading message
9
+ messageDiv.style.display = 'block';
10
+
11
+ const form = event.target;
12
+ const imageName = form.image_name.value;
13
+ const tag = form.tag.value;
14
+
15
+ try {
16
+ const response = await fetch(`/download-docker-image?image_name=${imageName}&tag=${tag}`);
17
+ if (response.ok) {
18
+ const reader = response.body.getReader();
19
+ const contentLength = response.headers.get('content-length');
20
+ const total = parseInt(contentLength, 10);
21
+ let loaded = 0;
22
+
23
+ const stream = new ReadableStream({
24
+ start(controller) {
25
+ function push() {
26
+ reader.read().then(({ done, value }) => {
27
+ if (done) {
28
+ controller.close();
29
+ updateProgress(progressBar, messageDiv, total, total);
30
+ return;
31
+ }
32
+ loaded += value.length;
33
+ updateProgress(progressBar, messageDiv, loaded, total);
34
+ controller.enqueue(value);
35
+ push();
36
+ }).catch(error => {
37
+ console.error('Error:', error);
38
+ messageDiv.textContent = "Error downloading image.";
39
+ });
40
+ }
41
+ push();
42
+ }
43
+ });
44
+
45
+ const blob = await new Response(stream).blob();
46
+ const url = window.URL.createObjectURL(blob);
47
+ const a = document.createElement('a');
48
+ a.style.display = 'none';
49
+ a.href = url;
50
+ a.download = `${imageName.replace("/", "_")}.tar`;
51
+ document.body.appendChild(a);
52
+ a.click();
53
+ window.URL.revokeObjectURL(url);
54
+ } else if (response.status === 404) {
55
+ throw new Error('Image not found');
56
+ } else {
57
+ throw new Error('Download failed');
58
+ }
59
+ } catch (error) {
60
+ console.error('Error:', error);
61
+ if (error.message === 'Image not found') {
62
+ messageDiv.textContent = "Error: Docker image not found."; // Show not found message
63
+ } else {
64
+ messageDiv.innerHTML = "Error downloading image.<br>Check the image name and tag."; // Show error message in two lines
65
+ }
66
+ } finally {
67
+ submitButton.disabled = false; // Re-enable the submit button after download
68
+ }
69
+ }
70
+
71
+ async function handlePipFormSubmit(event) {
72
+ event.preventDefault(); // Prevent the form from submitting the traditional way
73
+ const submitButton = document.getElementById('pip-submit-button');
74
+ const messageDiv = document.getElementById('pip-message');
75
+ submitButton.disabled = true; // Disable the submit button
76
+ messageDiv.textContent = "Downloading dependencies..."; // Show downloading message
77
+ messageDiv.style.display = 'block';
78
+
79
+ const formData = new FormData(event.target);
80
+ try {
81
+ const response = await fetch('/download-dependencies', {
82
+ method: 'POST',
83
+ body: formData
84
+ });
85
+ if (response.ok) {
86
+ const blob = await response.blob();
87
+ const url = window.URL.createObjectURL(blob);
88
+ const a = document.createElement('a');
89
+ a.style.display = 'none';
90
+ a.href = url;
91
+ a.download = 'dependencies.tar.gz';
92
+ document.body.appendChild(a);
93
+ a.click();
94
+ window.URL.revokeObjectURL(url);
95
+ messageDiv.textContent = "Download complete!"; // Show download complete message
96
+ } else {
97
+ throw new Error('Download failed');
98
+ }
99
+ } catch (error) {
100
+ console.error('Error:', error);
101
+ messageDiv.innerHTML = "Error downloading dependencies.<br>Please try again."; // Show error message in two lines
102
+ } finally {
103
+ submitButton.disabled = false; // Re-enable the submit button after download
104
+ }
105
+ }
106
+
107
+ async function handleDebFormSubmit(event) {
108
+ event.preventDefault(); // Prevent the form from submitting the traditional way
109
+ const submitButton = document.getElementById('deb-submit-button');
110
+ const messageDiv = document.getElementById('deb-message');
111
+ submitButton.disabled = true; // Disable the submit button
112
+ messageDiv.textContent = "Downloading Debian packages..."; // Show downloading message
113
+ messageDiv.style.display = 'block';
114
+
115
+ const formData = new FormData(event.target);
116
+ try {
117
+ const response = await fetch('/download-deb-packages', {
118
+ method: 'POST',
119
+ body: formData
120
+ });
121
+ if (response.ok) {
122
+ const blob = await response.blob();
123
+ const url = window.URL.createObjectURL(blob);
124
+ const a = document.createElement('a');
125
+ a.style.display = 'none';
126
+ a.href = url;
127
+ a.download = 'deb-packages.tar.gz';
128
+ document.body.appendChild(a);
129
+ a.click();
130
+ window.URL.revokeObjectURL(url);
131
+ messageDiv.textContent = "Download complete!"; // Show download complete message
132
+ } else {
133
+ throw new Error('Download failed');
134
+ }
135
+ } catch (error) {
136
+ console.error('Error:', error);
137
+ messageDiv.innerHTML = "Error downloading Debian packages.<br>Please try again."; // Show error message in two lines
138
+ } finally {
139
+ submitButton.disabled = false; // Re-enable the submit button after download
140
+ }
141
+ }
142
+
143
+ function updateProgress(progressBar, messageDiv, loaded, total) {
144
+ const percent = Math.round((loaded / total) * 100);
145
+ progressBar.style.width = `${percent}%`;
146
+ progressBar.textContent = `${percent}%`;
147
+ if (percent >= 100) {
148
+ messageDiv.textContent = "Download complete!";
149
+ messageDiv.style.display = 'block';
150
+ }
151
+ }
152
+
153
+ async function handlePipFormSubmit(event) {
154
+ event.preventDefault();
155
+ const submitButton = document.getElementById('pip-submit-button');
156
+ const messageDiv = document.getElementById('pip-message');
157
+ const progressBar = document.getElementById('progress-bar');
158
+ const progressContainer = document.getElementById('progress-container');
159
+ submitButton.disabled = true;
160
+ messageDiv.textContent = "Downloading dependencies...";
161
+ messageDiv.style.display = 'block';
162
+ progressContainer.style.display = 'block';
163
+ progressBar.style.width = '0%'; // Reset progress bar
164
+
165
+ const formData = new FormData(event.target);
166
+
167
+ try {
168
+ const response = await fetch('/download-dependencies', {
169
+ method: 'POST',
170
+ body: formData
171
+ });
172
+ if (response.ok) {
173
+ const reader = response.body.getReader();
174
+ const contentLength = response.headers.get('content-length');
175
+ const total = parseInt(contentLength, 10);
176
+ let loaded = 0;
177
+
178
+ const stream = new ReadableStream({
179
+ start(controller) {
180
+ function push() {
181
+ reader.read().then(({ done, value }) => {
182
+ if (done) {
183
+ controller.close();
184
+ updateProgress(progressBar, messageDiv, total, total);
185
+ return;
186
+ }
187
+ loaded += value.length;
188
+ updateProgress(progressBar, messageDiv, loaded, total);
189
+ controller.enqueue(value);
190
+ push();
191
+ }).catch(error => {
192
+ console.error('Error:', error);
193
+ messageDiv.textContent = "Error downloading dependencies.";
194
+ });
195
+ }
196
+ push();
197
+ }
198
+ });
199
+
200
+ const blob = await new Response(stream).blob();
201
+ const url = window.URL.createObjectURL(blob);
202
+ const a = document.createElement('a');
203
+ a.style.display = 'none';
204
+ a.href = url;
205
+ a.download = 'dependencies.tar.gz';
206
+ document.body.appendChild(a);
207
+ a.click();
208
+ window.URL.revokeObjectURL(url);
209
+ } else {
210
+ throw new Error('Download failed');
211
+ }
212
+ } catch (error) {
213
+ console.error('Error:', error);
214
+ messageDiv.innerHTML = "Error downloading dependencies.<br>Please try again.";
215
+ } finally {
216
+ submitButton.disabled = false;
217
+ }
218
+ }
219
+
220
+ function openTab(event, tabName) {
221
+ const tabContents = document.getElementsByClassName("tabcontent");
222
+ for (let i = 0; i < tabContents.length; i++) {
223
+ tabContents[i].style.display = "none";
224
+ }
225
+ const tabLinks = document.getElementsByClassName("tablink");
226
+ for (let i = 0; i < tabLinks.length; i++) {
227
+ tabLinks[i].className = tabLinks[i].className.replace(" active", "");
228
+ }
229
+ document.getElementById(tabName).style.display = "block";
230
+ event.currentTarget.className += " active";
231
+ }
232
+
233
+ window.onload = () => {
234
+ document.getElementById("defaultOpen").click(); // Open the default tab
235
+ };