atomicshop 3.3.28__py3-none-any.whl → 3.10.0__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.

Potentially problematic release.


This version of atomicshop might be problematic. Click here for more details.

Files changed (99) hide show
  1. atomicshop/__init__.py +1 -1
  2. atomicshop/a_mains/get_local_tcp_ports.py +85 -0
  3. atomicshop/a_mains/install_ca_certificate.py +172 -0
  4. atomicshop/a_mains/process_from_port.py +119 -0
  5. atomicshop/a_mains/set_default_dns_gateway.py +90 -0
  6. atomicshop/basics/strings.py +1 -1
  7. atomicshop/certificates.py +2 -2
  8. atomicshop/dns.py +26 -28
  9. atomicshop/etws/traces/trace_tcp.py +1 -2
  10. atomicshop/mitm/centered_settings.py +133 -0
  11. atomicshop/mitm/config_static.py +18 -43
  12. atomicshop/mitm/connection_thread_worker.py +376 -162
  13. atomicshop/mitm/engines/__parent/recorder___parent.py +1 -1
  14. atomicshop/mitm/engines/__parent/requester___parent.py +1 -1
  15. atomicshop/mitm/engines/__parent/responder___parent.py +15 -2
  16. atomicshop/mitm/engines/create_module_template.py +1 -2
  17. atomicshop/mitm/import_config.py +79 -88
  18. atomicshop/mitm/initialize_engines.py +1 -2
  19. atomicshop/mitm/message.py +5 -4
  20. atomicshop/mitm/mitm_main.py +222 -121
  21. atomicshop/mitm/recs_files.py +61 -5
  22. atomicshop/mitm/ssh_tester.py +82 -0
  23. atomicshop/networks.py +108 -93
  24. atomicshop/package_mains_processor.py +84 -0
  25. atomicshop/permissions/ubuntu_permissions.py +47 -0
  26. atomicshop/print_api.py +3 -5
  27. atomicshop/python_functions.py +23 -108
  28. atomicshop/speech_recognize.py +8 -0
  29. atomicshop/ssh_remote.py +115 -51
  30. atomicshop/web.py +20 -7
  31. atomicshop/web_apis/google_llm.py +22 -14
  32. atomicshop/wrappers/ctyping/msi_windows_installer/cabs.py +2 -1
  33. atomicshop/wrappers/ctyping/msi_windows_installer/extract_msi_main.py +2 -1
  34. atomicshop/wrappers/dockerw/dockerw.py +2 -2
  35. atomicshop/wrappers/factw/install/pre_install_and_install_before_restart.py +5 -5
  36. atomicshop/wrappers/githubw.py +175 -63
  37. atomicshop/wrappers/loggingw/handlers.py +1 -1
  38. atomicshop/wrappers/loggingw/loggingw.py +17 -1
  39. atomicshop/wrappers/netshw.py +124 -3
  40. atomicshop/wrappers/playwrightw/scenarios.py +1 -1
  41. atomicshop/wrappers/powershell_networking.py +80 -0
  42. atomicshop/wrappers/psutilw/psutil_networks.py +9 -0
  43. atomicshop/wrappers/pywin32w/win_event_log/fetch.py +174 -0
  44. atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_create.py +3 -105
  45. atomicshop/wrappers/pywin32w/win_event_log/subscribes/process_terminate.py +3 -57
  46. atomicshop/wrappers/pywin32w/wmis/win32_networkadapterconfiguration.py +12 -27
  47. atomicshop/wrappers/pywin32w/wmis/win32networkadapter.py +15 -9
  48. atomicshop/wrappers/socketw/certificator.py +19 -9
  49. atomicshop/wrappers/socketw/creator.py +30 -7
  50. atomicshop/wrappers/socketw/dns_server.py +6 -6
  51. atomicshop/wrappers/socketw/exception_wrapper.py +3 -3
  52. atomicshop/wrappers/socketw/process_getter.py +86 -0
  53. atomicshop/wrappers/socketw/receiver.py +29 -9
  54. atomicshop/wrappers/socketw/sender.py +10 -9
  55. atomicshop/wrappers/socketw/sni.py +23 -6
  56. atomicshop/wrappers/socketw/{base.py → socket_base.py} +33 -1
  57. atomicshop/wrappers/socketw/socket_client.py +6 -8
  58. atomicshop/wrappers/socketw/socket_wrapper.py +82 -21
  59. atomicshop/wrappers/socketw/ssl_base.py +6 -2
  60. atomicshop/wrappers/win_auditw.py +189 -0
  61. {atomicshop-3.3.28.dist-info → atomicshop-3.10.0.dist-info}/METADATA +25 -30
  62. {atomicshop-3.3.28.dist-info → atomicshop-3.10.0.dist-info}/RECORD +74 -88
  63. atomicshop/_basics_temp.py +0 -101
  64. atomicshop/a_installs/ubuntu/docker_rootless.py +0 -11
  65. atomicshop/a_installs/ubuntu/docker_sudo.py +0 -11
  66. atomicshop/addons/a_setup_scripts/install_psycopg2_ubuntu.sh +0 -3
  67. atomicshop/addons/package_setup/CreateWheel.cmd +0 -7
  68. atomicshop/addons/package_setup/Setup in Edit mode.cmd +0 -6
  69. atomicshop/addons/package_setup/Setup.cmd +0 -7
  70. atomicshop/archiver/__init__.py +0 -0
  71. atomicshop/archiver/_search_in_zip.py +0 -189
  72. atomicshop/archiver/search_in_archive.py +0 -284
  73. atomicshop/archiver/sevenz_app_w.py +0 -86
  74. atomicshop/archiver/sevenzs.py +0 -73
  75. atomicshop/archiver/shutils.py +0 -34
  76. atomicshop/archiver/zips.py +0 -353
  77. atomicshop/file_types.py +0 -24
  78. atomicshop/pbtkmultifile_argparse.py +0 -88
  79. atomicshop/script_as_string_processor.py +0 -42
  80. atomicshop/ssh_scripts/process_from_ipv4.py +0 -37
  81. atomicshop/ssh_scripts/process_from_port.py +0 -27
  82. atomicshop/wrappers/_process_wrapper_curl.py +0 -27
  83. atomicshop/wrappers/_process_wrapper_tar.py +0 -21
  84. atomicshop/wrappers/dockerw/install_docker.py +0 -449
  85. atomicshop/wrappers/ffmpegw.py +0 -125
  86. atomicshop/wrappers/process_wrapper_pbtk.py +0 -16
  87. atomicshop/wrappers/socketw/get_process.py +0 -123
  88. /atomicshop/{addons → a_mains/addons}/PlayWrightCodegen.cmd +0 -0
  89. /atomicshop/{addons → a_mains/addons}/ScriptExecution.cmd +0 -0
  90. /atomicshop/{addons → a_mains/addons}/inits/init_to_import_all_modules.py +0 -0
  91. /atomicshop/{addons → a_mains/addons}/process_list/ReadMe.txt +0 -0
  92. /atomicshop/{addons → a_mains/addons}/process_list/compile.cmd +0 -0
  93. /atomicshop/{addons → a_mains/addons}/process_list/compiled/Win10x64/process_list.dll +0 -0
  94. /atomicshop/{addons → a_mains/addons}/process_list/compiled/Win10x64/process_list.exp +0 -0
  95. /atomicshop/{addons → a_mains/addons}/process_list/compiled/Win10x64/process_list.lib +0 -0
  96. /atomicshop/{addons → a_mains/addons}/process_list/process_list.cpp +0 -0
  97. {atomicshop-3.3.28.dist-info → atomicshop-3.10.0.dist-info}/WHEEL +0 -0
  98. {atomicshop-3.3.28.dist-info → atomicshop-3.10.0.dist-info}/licenses/LICENSE.txt +0 -0
  99. {atomicshop-3.3.28.dist-info → atomicshop-3.10.0.dist-info}/top_level.txt +0 -0
@@ -1,449 +0,0 @@
1
- import sys
2
- import os
3
- import subprocess
4
- import getpass
5
- import tempfile
6
- import textwrap
7
- from pathlib import Path
8
-
9
- from ... import process, filesystem
10
- from ...permissions import permissions, ubuntu_permissions
11
- from ...print_api import print_api
12
- from .. import ubuntu_terminal
13
-
14
-
15
- PREPARATION_OUTPUT_DIR: str = str(Path(__file__).parent / "offline-bundle")
16
- PREPARATION_OUTPUT_ZIP: str = f"{PREPARATION_OUTPUT_DIR}.zip"
17
- GET_DOCKER_URL: str = "https://get.docker.com"
18
-
19
-
20
- def is_docker_installed():
21
- """
22
- The function will check if docker is installed.
23
- :return: bool.
24
- """
25
-
26
- try:
27
- # Run the command 'docker --version'
28
- result = subprocess.run(['docker', '--version'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
29
-
30
- # Check if the command was successful
31
- if result.returncode == 0:
32
- message = f"Docker is installed. Version: {result.stdout.strip()}"
33
- print_api(message, color='green')
34
- return True
35
- else:
36
- print_api("Docker is not installed.")
37
- return False
38
- except FileNotFoundError:
39
- print_api("Docker command not found. Docker is not installed.")
40
- return False
41
-
42
-
43
- def add_current_user_to_docker_group(print_kwargs: dict = None):
44
- """
45
- The function will add the current user to the docker group.
46
-
47
- :param print_kwargs: dict, the print arguments.
48
- :return:
49
- """
50
- # Check if current user that executed the script is a sudo user. If not, use the current user.
51
- sudo_executer_username: str = ubuntu_permissions.get_sudo_executer_username()
52
- if sudo_executer_username:
53
- current_user = sudo_executer_username
54
- else:
55
- current_user = getpass.getuser()
56
-
57
- # Add the current user to the docker group.
58
- # subprocess.check_call(['sudo', 'usermod', '-aG', 'docker', current_user])
59
- command = f"sudo usermod -aG docker {current_user}"
60
- # Execute the command
61
- subprocess.run(command, shell=True, capture_output=True, text=True)
62
-
63
- # Check if the user was added to the docker group.
64
- result = subprocess.run(['groups', current_user], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
65
- if 'docker' in result.stdout:
66
- print_api(f"User {current_user} was added to the docker group.", color='green', **(print_kwargs or {}))
67
- return True
68
- else:
69
- print_api(f"User {current_user} was not added to the docker group. Try executing with sudo", color='red',
70
- **(print_kwargs or {}))
71
- return False
72
-
73
-
74
- def install_docker_ubuntu(
75
- use_docker_installer: bool = True,
76
- rootless: bool = False,
77
- add_current_user_to_docker_group_bool: bool = False
78
- ) -> int:
79
- """
80
- The function will install docker on ubuntu.
81
- Note: If you want to install docker in rootless mode, you need to run the script without sudo.
82
-
83
- :param rootless: bool, if True, the rootless installation will be performed.
84
- Meaning, you will be able to run the 'docker' command without sudo and you will not need to add the
85
- current user to the docker group.
86
- :param use_docker_installer: bool, if True, the docker installer will be used.
87
- If False, the docker will be installed using the apt package manager, custom repo and keyring.
88
- :param add_current_user_to_docker_group_bool: bool, if True, the current user will be added to the docker group.
89
- So the user will be able to run the 'docker' command without sudo. If you install docker in rootless mode
90
- this is not needed.
91
-
92
- Usage in main.py (run with sudo):
93
- import sys
94
- from atomicshop.wrappers.dockerw import install_docker
95
-
96
-
97
- def main():
98
- execution_result: int = install_docker.install_docker_ubuntu()
99
- return execution_result
100
-
101
-
102
- if __name__ == '__main__':
103
- sys.exit(main())
104
- """
105
-
106
- if rootless and permissions.is_admin():
107
- print_api('Rootless installation requires running the script without sudo.', color='red')
108
- sys.exit()
109
-
110
- if use_docker_installer:
111
- if not ubuntu_terminal.is_executable_exists('curl'):
112
- print_api('curl is not installed, installing...', color='yellow')
113
- ubuntu_terminal.update_system_packages()
114
- ubuntu_terminal.install_packages(['curl'])
115
-
116
- # Use the docker installer script.
117
- # The script will install docker and add the current user to the docker group.
118
- # The script will also install docker-compose and docker-buildx.
119
- # process.execute_script('curl -fsSL https://get.docker.com -o get-docker.sh && sh get-docker.sh', shell=True)
120
- process.execute_script('curl -fsSL https://get.docker.com | sh', shell=True)
121
- # subprocess.run("curl -fsSL https://get.docker.com | sh", shell=True, check=True)
122
- # process.execute_script('curl -fsSL https://get.docker.com -o get-docker.sh', shell=True)
123
- # process.execute_script('sh get-docker.sh', shell=True)
124
- # filesystem.remove_file('get-docker.sh')
125
- else:
126
- # Remove the existing keyrings, so we will not be asked to overwrite it if it exists.
127
- docker_keyring_file_path: str = "/etc/apt/keyrings/docker.gpg"
128
- filesystem.remove_file(docker_keyring_file_path)
129
-
130
- script = f"""
131
- # Step 1: Set up Docker's apt repository
132
- sudo apt-get update
133
- sudo apt-get install -y ca-certificates curl gnupg
134
- sudo install -m 0755 -d /etc/apt/keyrings
135
- curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
136
- sudo chmod a+r /etc/apt/keyrings/docker.gpg
137
-
138
- # Add the repository to Apt sources
139
- echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
140
- sudo apt-get update
141
-
142
- # Step 2: Install the Docker packages
143
- sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras
144
-
145
- # Step 3: Verify the installation
146
- # sudo docker run hello-world
147
-
148
- # Add Privileges to run docker without sudo. Add current user to Docker superuser group.
149
- # sudo usermod -aG docker $USER
150
- """
151
-
152
- process.execute_script(script, shell=True)
153
-
154
- if rootless:
155
- # Install uidmap package.
156
- if not ubuntu_terminal.is_package_installed('uidmap'):
157
- print_api('uidmap is not installed, installing...', color='yellow')
158
- ubuntu_terminal.update_system_packages()
159
- ubuntu_terminal.install_packages(['uidmap'])
160
-
161
- with ubuntu_permissions.temporary_regular_permissions():
162
- # After 'get-docker.sh' execution, we will install docker in rootless mode.
163
- # process.execute_script('dockerd-rootless-setuptool.sh install', shell=True, as_regular_user=True)
164
- process.execute_script(
165
- '/usr/bin/dockerd-rootless-setuptool.sh install',
166
- as_regular_user=True,
167
- shell=True,
168
- executable=None)
169
-
170
- # Start and enable the docker service in user mode.
171
- docker_start_command = ubuntu_terminal.get_command_execution_as_sudo_executer(
172
- 'systemctl --user start docker.service')
173
- docker_enable_command = ubuntu_terminal.get_command_execution_as_sudo_executer(
174
- 'systemctl --user enable docker.service')
175
- print_api('Starting and enabling the docker service in user mode...')
176
- process.execute_script(docker_start_command, shell=True, executable=None)
177
- process.execute_script(docker_enable_command, shell=True, executable=None)
178
-
179
- print_api('Executing "loginctl enable-linger" to enable Docker to run when the user is not logged in...')
180
- non_sudo_executer = ubuntu_permissions.get_sudo_executer_username()
181
- # Enable lingering so Docker runs when the user is not logged in
182
- process.execute_script(f'sudo loginctl enable-linger {non_sudo_executer}', shell=True)
183
-
184
- print_api('Adding $HOME/bin to your PATH...')
185
- # Add $HOME/bin to your PATH if it's not already there.
186
- with ubuntu_permissions.temporary_regular_permissions():
187
- ubuntu_terminal.add_path_to_bashrc(as_regular_user=True)
188
-
189
- # Add appropriate permissions to the docker socket, so the user can run docker commands without sudo in python.
190
- # with open('/etc/profile.d/docker_vars.sh', 'w') as file:
191
- # file.write('export DOCKER_HOST=unix:///run/user/1000/docker.sock')
192
-
193
- # Since we are installing the rootless mode, this script runs without sudo, so to add the DOCKER_HOST variable
194
- # to the environment, we need to add it to the /etc/profile.d/docker_vars.sh file with sudo.
195
- command = "echo 'export DOCKER_HOST=unix:///run/user/1000/docker.sock' | sudo tee /etc/profile.d/docker_vars.sh"
196
- subprocess.run(command, shell=True, check=True)
197
-
198
- # ubuntu_terminal.add_line_to_bashrc(
199
- # 'export DOCKER_HOST=unix:///run/user/1000/docker.sock', as_regular_user=True)
200
- # process.execute_script('export DOCKER_HOST=unix:///run/user/1000/docker.sock', shell=True)
201
- # Restart shell.
202
- # process.execute_script('source ~/.bashrc', shell=True)
203
-
204
- if add_current_user_to_docker_group_bool:
205
- # Check if current user that executed the script is a sudo user. If not, use the current user.
206
- # Add the current user to the docker group.
207
- add_current_user_to_docker_group()
208
-
209
- # Verify the installation.
210
- result: list = process.execute_with_live_output('sudo docker run hello-world')
211
- else:
212
- result: list = process.execute_with_live_output('docker run hello-world')
213
-
214
- print_api('\n'.join(result))
215
-
216
- if 'Hello from Docker!' in '\n'.join(result):
217
- print_api('Docker installed successfully.', color='green')
218
- return 0
219
- else:
220
- print_api('Docker installation failed.', color='red')
221
- print_api('Please check the logs above for more information.', color='red')
222
- return 1
223
-
224
-
225
- def prepare_offline_installation_bundle():
226
- # The Bash script in a single triple-quoted string - this is to easier copy-paste it if needed to run directly.
227
- bash_script = textwrap.dedent(r"""#!/usr/bin/env bash
228
- #
229
- # Build an offline-install bundle for Docker Engine on Ubuntu 24.04 LTS.
230
- # The package list is auto-discovered from `get.docker.com --dry-run`.
231
- #
232
- # sudo ./prepare_docker_offline.sh [/path/to/output_dir]
233
- #
234
- set -Eeuo pipefail
235
-
236
- ################################################################################
237
- # CLI PARAMETERS
238
- # $1 → OUTDIR (already supported: where to build the bundle)
239
- # $2 → GET_DOCKER_URL (defaults to https://get.docker.com)
240
- # $3 → OUTPUT_ZIP (defaults to "$OUTDIR.zip")
241
- ################################################################################
242
- OUTDIR="${1:-"$PWD/offline-bundle"}"
243
- GET_DOCKER_URL="${2:-https://get.docker.com}"
244
- OUTPUT_ZIP="${3:-$OUTDIR.zip}"
245
-
246
- die() { echo "ERROR: $*" >&2; exit 1; }
247
- need_root() { [[ $EUID -eq 0 ]] || die "Run as root (use sudo)"; }
248
- need_cmd() {
249
- local cmd=$1
250
- local pkg=${2:-$1} # default package == command
251
- if ! command -v "$cmd" &>/dev/null; then
252
- echo "[*] $cmd not found – installing $pkg ..."
253
- apt-get update -qq
254
- DEBIAN_FRONTEND=noninteractive \
255
- apt-get install -y --no-install-recommends "$pkg" || \
256
- die "Unable to install required package: $pkg"
257
- fi
258
- }
259
-
260
- need_root
261
- need_cmd curl
262
-
263
- echo "[*] Discovering package list via get.docker.com --dry-run ..."
264
- DRY_LOG=$(curl -fsSL "$GET_DOCKER_URL" | bash -s -- --dry-run)
265
-
266
- echo "[*] Determining package list via --dry-run ..."
267
- PKGS=$(printf '%s\n' "$DRY_LOG" | sed -n 's/.* install \(.*\) >\/dev\/null.*/\1/p')
268
-
269
- if ! grep -q '\S' <<< "$PKGS"; then
270
- echo "No packages detected in dry-run output – aborting." >&2
271
- exit 1
272
- fi
273
-
274
- echo "[*] Install Docker before preparing the offline bundle."
275
- curl -fsSL "$GET_DOCKER_URL" | sh
276
-
277
- mkdir -p "$OUTDIR"/packages
278
- echo "[*] Output directory: $OUTDIR"
279
-
280
- echo "Packages to install:"
281
- echo "$PKGS"
282
-
283
- echo "[*] Downloading packages and all dependencies …"
284
- apt-get update -qq
285
- apt-get clean
286
- mkdir -p /var/cache/apt/archives/partial
287
- apt-get -y --download-only --reinstall install $PKGS
288
- cp -v /var/cache/apt/archives/*.deb "$OUTDIR/packages/"
289
- echo "[*] $(ls "$OUTDIR/packages" | wc -l) .deb files written to packages/"
290
-
291
- echo "[*] Building local Packages.gz index …"
292
- pushd "$OUTDIR/packages" >/dev/null
293
- for deb in *.deb; do
294
- dpkg-deb -f "$deb" Package
295
- done | awk '{printf "%s\tmisc\toptional\n",$1}' > override
296
- apt-ftparchive packages . override | tee Packages | gzip -9c > Packages.gz
297
- popd >/dev/null
298
-
299
-
300
- echo ">> Checking for Docker ..."
301
- command -v docker >/dev/null 2>&1 || { echo "Docker not found."; exit 1; }
302
-
303
- # Pack final bundle
304
- echo "[*] Creating a zip archive ..."
305
- parent_dir=$(dirname "$OUTDIR")
306
- base_name=$(basename "$OUTDIR")
307
-
308
- # Create new shell, cd into the directory, and zip the contents. So that the zip file will not contain the full path.
309
- (
310
- cd "$parent_dir"
311
- zip -rq "$OUTPUT_ZIP" "$base_name"
312
- )
313
-
314
- rm -rf "$OUTDIR"
315
- echo "Docker offline bundle created at $OUTPUT_ZIP"
316
- echo
317
- echo "Copy the zip file and the offline installation python script to the target machine and execute."
318
- """)
319
-
320
- # Write it to a secure temporary file.
321
- with tempfile.NamedTemporaryFile('w', delete=False, suffix='.sh') as f:
322
- f.write(bash_script)
323
- temp_path = f.name
324
- os.chmod(temp_path, 0o755) # make it executable
325
-
326
- cmd = [
327
- "sudo", "bash", temp_path,
328
- PREPARATION_OUTPUT_DIR,
329
- GET_DOCKER_URL,
330
- PREPARATION_OUTPUT_ZIP,
331
- ]
332
-
333
- # Run it and stream output live.
334
- try:
335
- subprocess.run(cmd, check=True)
336
- finally:
337
- # 5. Clean up the temp file unless you want to inspect it.
338
- os.remove(temp_path)
339
-
340
-
341
- def install_offline_installation_bundle():
342
- bash_script = textwrap.dedent(r"""#!/usr/bin/env bash
343
- # Offline installer for the Docker bundle produced by prepare_docker_offline.sh
344
- set -euo pipefail
345
-
346
- die() { echo "ERROR: $*" >&2; exit 1; }
347
- need_root() { [[ $EUID -eq 0 ]] || die "Run as root (use sudo)"; }
348
-
349
- need_root
350
-
351
- # ------------------------------------------------------------------------------
352
- # Paths
353
- # ------------------------------------------------------------------------------
354
- BUNDLE_ZIP="${1:-"$PWD/offline-bundle.zip"}"
355
-
356
- BUNDLE_DIR="${BUNDLE_ZIP%.zip}" # remove .zip suffix
357
- REPO_DIR="$BUNDLE_DIR/packages" # contains *.deb + Packages
358
- OFFLINE_LIST="/etc/apt/sources.list.d/docker-offline.list"
359
-
360
- # Extract zip archive if it exists
361
- if [[ -f "$BUNDLE_ZIP" ]]; then
362
- echo "[*] Extracting offline bundle from $BUNDLE_ZIP ..."
363
- mkdir -p "$BUNDLE_DIR"
364
- unzip -q "$BUNDLE_ZIP" -d "."
365
- else
366
- die "Bundle zip file '$BUNDLE_ZIP' not found. Provide a valid path."
367
- fi
368
-
369
- TEMP_PARTS="$(mktemp -d)" # empty dir ⇒ no extra lists
370
-
371
- # ------------------------------------------------------------------------------
372
- # Helper to clean up even if the script aborts
373
- # ------------------------------------------------------------------------------
374
- cleanup() {
375
- sudo rm -f "$OFFLINE_LIST"
376
- sudo rm -rf "$TEMP_PARTS"
377
- }
378
- trap cleanup EXIT
379
-
380
- # ------------------------------------------------------------------------------
381
- # 1. Add the local repository (trusted) as the *only* source we will use
382
- # ------------------------------------------------------------------------------
383
- echo "[*] Adding temporary APT source for the offline bundle …"
384
- echo "deb [trusted=yes] file:$REPO_DIR ./" | sudo tee "$OFFLINE_LIST" >/dev/null
385
-
386
- # Ensure plain index exists (APT always understands the un-compressed form)
387
- if [[ ! -f "$REPO_DIR/Packages" && -f "$REPO_DIR/Packages.gz" ]]; then
388
- gunzip -c "$REPO_DIR/Packages.gz" > "$REPO_DIR/Packages"
389
- fi
390
-
391
- # ------------------------------------------------------------------------------
392
- # 2. Update metadata – but ONLY from our offline list
393
- # ------------------------------------------------------------------------------
394
- echo "[*] Updating APT metadata – offline only …"
395
- sudo apt-get -o Dir::Etc::sourcelist="$OFFLINE_LIST" \
396
- -o Dir::Etc::sourceparts="$TEMP_PARTS" \
397
- -o APT::Get::List-Cleanup="0" \
398
- update -qq
399
-
400
- # ------------------------------------------------------------------------------
401
- # 3. Figure out which packages are inside the bundle
402
- # ------------------------------------------------------------------------------
403
- PKGS=$(awk '/^Package: /{print $2}' "$REPO_DIR/Packages")
404
-
405
- echo "[*] Installing:"
406
- printf ' • %s\n' $PKGS
407
-
408
- # ------------------------------------------------------------------------------
409
- # 4. Install them, again restricting APT to the offline repo only
410
- # ------------------------------------------------------------------------------
411
- sudo apt-get -y \
412
- -o Dir::Etc::sourcelist="$OFFLINE_LIST" \
413
- -o Dir::Etc::sourceparts="$TEMP_PARTS" \
414
- install $PKGS
415
-
416
- echo "[✓] Docker installed completely offline!"
417
-
418
- usage() {
419
- echo "Usage: $0 <image-archive.tar.gz>"
420
- exit 1
421
- }
422
-
423
- echo ">> Checking for Docker ..."
424
- command -v docker >/dev/null 2>&1 || {
425
- echo "Docker is not installed; install Docker and try again."
426
- exit 1
427
- }
428
-
429
- echo "Removing extracted files..."
430
- rm -rf "$BUNDLE_DIR"
431
- """)
432
-
433
- # Write it to a secure temporary file.
434
- with tempfile.NamedTemporaryFile('w', delete=False, suffix='.sh') as f:
435
- f.write(bash_script)
436
- temp_path = f.name
437
- os.chmod(temp_path, 0o755) # make it executable
438
-
439
- cmd = [
440
- "sudo", "bash", temp_path,
441
- PREPARATION_OUTPUT_ZIP, # $1 BUNDLE_ZIP
442
- ]
443
-
444
- # 4. Run it and stream output live.
445
- try:
446
- subprocess.run(cmd, check=True)
447
- finally:
448
- # 5. Clean up the temp file unless you want to inspect it.
449
- os.remove(temp_path)
@@ -1,125 +0,0 @@
1
- import fnmatch
2
- import os
3
- import shlex
4
-
5
- from ..print_api import print_api
6
- from ..tempfiles import TempFile
7
- from .githubw import GitHubWrapper
8
- from ..process import execute_with_live_output
9
- from ..filesystem import create_directory
10
-
11
-
12
- class FFmpegWrapper:
13
- def __init__(self, working_directory: str = str(), ffmpeg_exe_path: str = str()):
14
- self.working_directory: str = working_directory
15
- self.ffmpeg_exe_path: str = ffmpeg_exe_path
16
- self.relative_path: str = 'bin'
17
- self.ffmpeg_exe_name: str = 'ffmpeg.exe'
18
-
19
- # Variables to download the latest release from GitHub in case execution fails.
20
- self.git_user: str = 'GyanD'
21
- self.git_repo: str = 'codexffmpeg'
22
- self.git_latest_release_pattern: str = '*full_build.zip'
23
-
24
- # ffmpeg Release directory name.
25
- self.ffmpeg_release_directory_name: str = \
26
- f"ffmpeg_{self.git_latest_release_pattern.replace('*', '').split('.')[0]}"
27
- self.ffmpeg_release_directory_path: str = str()
28
-
29
- # Execute functions.
30
- self.build_ffmpeg_exe_and_directory_path()
31
-
32
- def build_ffmpeg_exe_and_directory_path(self):
33
- # If working directory was specified, but not the full path to exe.
34
- if self.working_directory and not self.ffmpeg_exe_path:
35
- self.ffmpeg_release_directory_path = self.working_directory + os.sep + self.ffmpeg_release_directory_name
36
- self.ffmpeg_exe_path = \
37
- self.ffmpeg_release_directory_path + os.sep + self.relative_path + os.sep + self.ffmpeg_exe_name
38
- # If no working directory and no path to exe was specified.
39
- elif not self.working_directory and not self.ffmpeg_exe_path:
40
- # Use just 'ffmpeg.exe' as path to exe. Maybe it is already installed and is in environment PATH var.
41
- self.ffmpeg_exe_path = self.ffmpeg_exe_name
42
-
43
- def change_to_temp_directory(self):
44
- temp_file = TempFile()
45
- self.working_directory = temp_file.directory
46
- self.ffmpeg_exe_path = str()
47
- self.build_ffmpeg_exe_and_directory_path()
48
-
49
- def download_ffmpeg_and_extract(self):
50
- github_wrapper = GitHubWrapper(user_name=self.git_user, repo_name=self.git_repo)
51
- github_wrapper.build_links_from_user_and_repo()
52
- github_wrapper.download_and_extract_latest_release(
53
- target_directory=self.ffmpeg_release_directory_path, string_pattern=self.git_latest_release_pattern,
54
- archive_remove_first_directory=True)
55
-
56
- def execute_ffmpeg(self, cmd_list: list):
57
- continue_loop: bool = True
58
- while continue_loop:
59
- # If first entry contains 'ffmpeg.exe' and it is not 'self.ffmpeg_exe_path' already.
60
- if self.ffmpeg_exe_name in cmd_list[0] and cmd_list[0] != self.ffmpeg_exe_path:
61
- # We'll change it to the updated one.
62
- cmd_list[0] = self.ffmpeg_exe_path
63
- # If first entry doesn't contain 'ffmpeg.exe'.
64
- elif self.ffmpeg_exe_name not in cmd_list[0]:
65
- # We'll insert the current path into first entry.
66
- cmd_list.insert(0, self.ffmpeg_exe_path)
67
-
68
- output_strings: list = [
69
- 'Input',
70
- 'Output',
71
- 'video:'
72
- ]
73
-
74
- try:
75
- print(f'FFmpeg processing: {shlex.join(cmd_list)}')
76
- result_lines = execute_with_live_output(
77
- cmd=cmd_list, output_strings=output_strings, raise_exception=True, exit_on_error=False)
78
- # If 'ffmpeg.exe' is non-existent.
79
- except FileNotFoundError:
80
- # Check if full path to 'ffmpeg.exe' is just 'ffmpeg.exe'.
81
- if self.ffmpeg_exe_path == self.ffmpeg_exe_name:
82
- print_api('Will try temp folder...', raise_exception=False)
83
- # Change to temp folder and try executing again.
84
- self.change_to_temp_directory()
85
- continue
86
-
87
- print_api('Trying to download...', raise_exception=False)
88
- create_directory(self.ffmpeg_release_directory_path)
89
- self.download_ffmpeg_and_extract()
90
- continue
91
-
92
- # === At this point python exceptions are finished. ==========================
93
- # If 'Invalid argument' was returned by 'ffmpeg' in the last line.
94
- if 'Invalid argument' in result_lines[-1]:
95
- print_api(result_lines[-1], message_type_error=True, color="red", exit_on_error=True)
96
-
97
- # === Successful execution section ==========================================
98
- string_pattern = 'video:*audio:*subtitle*'
99
- # if 'video:' in result_lines[-1] and 'audio:' in result_lines[-1] and 'subtitle:' in result_lines[-1]:
100
- if fnmatch.fnmatch(result_lines[-1], string_pattern):
101
- print_api(f'FFmpeg finished successfully.', color="green")
102
-
103
- # Since exceptions are finished, we can stop the while loop.
104
- continue_loop = False
105
-
106
- def convert_file(self, source_file_path: str, dest_file_path: str, overwrite: bool = False) -> None:
107
- """
108
- The function converts source file to destination file. The source format is defined by the file extension
109
- as well as destination file format defined by the destination file extension.
110
-
111
- Example convert MP3 file to WAV:
112
- convert_file(source_file_path=some_music.mp3, dest_file_path=converted_file.wav)
113
-
114
- :param source_file_path: string, full file path to source file.
115
- :param dest_file_path: string, full file path to destination file.
116
- :param overwrite: boolean, set if destination file should be overwritten if it exists.
117
- :return: None.
118
- """
119
-
120
- cmd_list = ['-i', source_file_path, dest_file_path]
121
-
122
- if overwrite:
123
- cmd_list.append('-y')
124
-
125
- self.execute_ffmpeg(cmd_list)
@@ -1,16 +0,0 @@
1
- from atomicshop.process import execute_with_live_output
2
-
3
-
4
- def execute_pbtk(pbtk_path: str, file_path: str, target_directory: str) -> None:
5
- """
6
- The function receives file path and target filesystem directory to extract the files.
7
-
8
- :param pbtk_path: full path to pbtk file.
9
- :param file_path: full path to binary file.
10
- :param target_directory: The directory on the filesystem to extract files.
11
- """
12
-
13
- cmd: str = f'python "{pbtk_path}" "{file_path}" "{target_directory}"'
14
- print(f'Scanning: {file_path}')
15
-
16
- output_list = execute_with_live_output(cmd=cmd)