dkinst 0.2.0__py3-none-any.whl → 0.4.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.
- dkinst/__init__.py +1 -1
- dkinst/installers/_base.py +0 -2
- dkinst/installers/helpers/infra/__init__.py +0 -0
- dkinst/installers/helpers/infra/msis.py +151 -0
- dkinst/installers/helpers/infra/system.py +25 -0
- dkinst/installers/helpers/modules/__init__.py +0 -0
- dkinst/installers/helpers/modules/nodejs_installer.py +419 -0
- dkinst/installers/helpers/modules/pycharm_installer.py +140 -0
- dkinst/installers/helpers/{tesseract_ocr_manager.py → modules/tesseract_ocr_manager.py} +1 -10
- dkinst/installers/nodejs.py +53 -0
- dkinst/installers/pycharm.py +36 -0
- dkinst/installers/robocorp.py +12 -14
- dkinst/installers/tesseract_ocr.py +1 -1
- {dkinst-0.2.0.dist-info → dkinst-0.4.1.dist-info}/METADATA +2 -1
- dkinst-0.4.1.dist-info/RECORD +24 -0
- dkinst-0.2.0.dist-info/RECORD +0 -16
- /dkinst/installers/helpers/{permissions.py → infra/permissions.py} +0 -0
- {dkinst-0.2.0.dist-info → dkinst-0.4.1.dist-info}/WHEEL +0 -0
- {dkinst-0.2.0.dist-info → dkinst-0.4.1.dist-info}/entry_points.txt +0 -0
- {dkinst-0.2.0.dist-info → dkinst-0.4.1.dist-info}/licenses/LICENSE +0 -0
- {dkinst-0.2.0.dist-info → dkinst-0.4.1.dist-info}/top_level.txt +0 -0
dkinst/__init__.py
CHANGED
dkinst/installers/_base.py
CHANGED
@@ -4,8 +4,6 @@ import tomllib
|
|
4
4
|
from pathlib import Path
|
5
5
|
from types import ModuleType
|
6
6
|
from typing import Literal
|
7
|
-
import os
|
8
|
-
import ctypes
|
9
7
|
|
10
8
|
|
11
9
|
INSTALLATION_PATH_PORTABLE_WINDOWS: str = "C:\\dkinst" # Installation path for portable files on Windows that don't have a default location.
|
File without changes
|
@@ -0,0 +1,151 @@
|
|
1
|
+
import subprocess
|
2
|
+
|
3
|
+
from rich.console import Console
|
4
|
+
|
5
|
+
from . import permissions
|
6
|
+
from atomicshop import get_process_list
|
7
|
+
from atomicshop.wrappers.psutilw import processes
|
8
|
+
|
9
|
+
|
10
|
+
console = Console()
|
11
|
+
|
12
|
+
|
13
|
+
ERROR_CODES = {
|
14
|
+
'1603': 'The App is already installed or Insufficient permissions',
|
15
|
+
'1619': 'This installation package could not be opened. Verify that the package exists and that you can '
|
16
|
+
'install it manually, also check the installation command line switches'
|
17
|
+
}
|
18
|
+
|
19
|
+
|
20
|
+
class MsiInstallationError(Exception):
|
21
|
+
pass
|
22
|
+
|
23
|
+
|
24
|
+
def get_current_msiexec_processes(msi_file_path: str = None) -> dict:
|
25
|
+
"""
|
26
|
+
Get the current msiexec processes.
|
27
|
+
:param msi_file_path: string, OPTIONAL path to the MSI file to check in the command line.
|
28
|
+
:return: list of dicts, each key represents a pid and its values are process name and cmdline.
|
29
|
+
"""
|
30
|
+
|
31
|
+
current_processes: dict = (
|
32
|
+
get_process_list.GetProcessList(get_method='pywin32', connect_on_init=True).get_processes())
|
33
|
+
|
34
|
+
current_msiexec_dict: dict = {}
|
35
|
+
for pid, process_info in current_processes.items():
|
36
|
+
if 'msiexec.exe' in process_info['name']:
|
37
|
+
if msi_file_path:
|
38
|
+
if msi_file_path in process_info['cmdline']:
|
39
|
+
current_msiexec_dict[pid] = process_info
|
40
|
+
else:
|
41
|
+
current_msiexec_dict[pid] = process_info
|
42
|
+
|
43
|
+
return current_msiexec_dict
|
44
|
+
|
45
|
+
|
46
|
+
def wait_for_msiexec_processes_to_finish(msi_file_path: str):
|
47
|
+
"""
|
48
|
+
Wait for the msiexec processes to finish.
|
49
|
+
:param msi_file_path: string, path to the MSI file.
|
50
|
+
:return:
|
51
|
+
"""
|
52
|
+
|
53
|
+
current_msiexec: dict = get_current_msiexec_processes(msi_file_path)
|
54
|
+
current_pid = list(current_msiexec.keys())[0]
|
55
|
+
|
56
|
+
result_code = processes.wait_for_process(current_pid)
|
57
|
+
if result_code != 0:
|
58
|
+
raise Exception(f"MSI Installation failed. Return code: {result_code}")
|
59
|
+
|
60
|
+
|
61
|
+
def install_msi(
|
62
|
+
msi_path,
|
63
|
+
silent_no_gui: bool = False,
|
64
|
+
silent_progress_bar: bool = False,
|
65
|
+
no_restart: bool = False,
|
66
|
+
terminate_required_processes: bool = False,
|
67
|
+
additional_args: str = None,
|
68
|
+
create_log_near_msi: bool = False,
|
69
|
+
log_file_path: str = None,
|
70
|
+
scan_log_for_errors: bool = False,
|
71
|
+
# as_admin=True
|
72
|
+
):
|
73
|
+
"""
|
74
|
+
Install an MSI file silently.
|
75
|
+
:param msi_path: str, path to the MSI file.
|
76
|
+
:param silent_no_gui: bool, whether to run the installation silently, without showing GUI.
|
77
|
+
:param silent_progress_bar: bool, whether to show a progress bar during silent installation.
|
78
|
+
:param no_restart: bool, whether to restart the computer after installation.
|
79
|
+
:param terminate_required_processes: bool, whether to terminate processes that are required by the installation.
|
80
|
+
:param additional_args: str, additional arguments to pass to the msiexec command.
|
81
|
+
:param create_log_near_msi: bool, whether to create a log file near the MSI file.
|
82
|
+
If the msi file located in 'c:\\path\\to\\file.msi', the log file will be created in 'c:\\path\\to\\file.log'.
|
83
|
+
The log options that will be used: /l*v c:\\path\\to\\file.log
|
84
|
+
:param log_file_path: str, path to the log file. Even if 'create_log_near_msi' is False, you can specify a custom
|
85
|
+
path for the log file, and it will be created.
|
86
|
+
The log options that will be used: /l*v c:\\path\\to\\file.log
|
87
|
+
:param scan_log_for_errors: bool, whether to scan the log file for errors in case of failure.
|
88
|
+
# :param as_admin: bool, whether to run the installation as administrator.
|
89
|
+
:return:
|
90
|
+
"""
|
91
|
+
|
92
|
+
if not permissions.is_admin():
|
93
|
+
raise PermissionError("This function requires administrator privileges.")
|
94
|
+
|
95
|
+
if silent_progress_bar and silent_no_gui:
|
96
|
+
raise ValueError("silent_progress_bar and silent_no_gui cannot be both True.")
|
97
|
+
|
98
|
+
if create_log_near_msi and log_file_path:
|
99
|
+
raise ValueError("create_log_near_msi and log_file_path cannot be both set.")
|
100
|
+
|
101
|
+
if create_log_near_msi:
|
102
|
+
log_file_path = msi_path.replace('.msi', '.log')
|
103
|
+
|
104
|
+
if scan_log_for_errors and not log_file_path:
|
105
|
+
raise ValueError("[scan_log_for_errors] is set, but [log_file_path] or [create_log_near_msi] is not set.")
|
106
|
+
|
107
|
+
# Define the msiexec command
|
108
|
+
command = f'msiexec /i "{msi_path}"'
|
109
|
+
|
110
|
+
if silent_no_gui:
|
111
|
+
command = f"{command} /qn"
|
112
|
+
if silent_progress_bar:
|
113
|
+
command = f"{command} /qb"
|
114
|
+
if no_restart:
|
115
|
+
command = f"{command} /norestart"
|
116
|
+
|
117
|
+
if log_file_path:
|
118
|
+
command = f"{command} /l*v {log_file_path}"
|
119
|
+
|
120
|
+
if terminate_required_processes:
|
121
|
+
command = f"{command} REBOOT=ReallySuppress"
|
122
|
+
|
123
|
+
if additional_args:
|
124
|
+
if additional_args.startswith(' '):
|
125
|
+
additional_args = additional_args[1:]
|
126
|
+
command = f"{command} {additional_args}"
|
127
|
+
|
128
|
+
# if as_admin:
|
129
|
+
# command = win_permissions.get_command_to_run_as_admin_windows(command)
|
130
|
+
|
131
|
+
# Run the command
|
132
|
+
result = subprocess.run(command, capture_output=True, text=True)
|
133
|
+
|
134
|
+
# Check the result
|
135
|
+
if result.returncode == 0:
|
136
|
+
console.print("MSI Installation completed.", style="green")
|
137
|
+
else:
|
138
|
+
message = (f"Installation failed. Return code: {result.returncode}\n{ERROR_CODES.get(str(result.returncode), '')}\n"
|
139
|
+
f"MSI path: {msi_path}\nCommand: {command}\nOutput: {result.stdout}\nError: {result.stderr}")
|
140
|
+
|
141
|
+
if scan_log_for_errors:
|
142
|
+
with open(log_file_path, 'r', encoding='utf-16 le') as f:
|
143
|
+
log_content = f.read()
|
144
|
+
if 'error' in log_content.lower():
|
145
|
+
# Get the error text of the lines that contain 'error'.
|
146
|
+
error_lines = [line for line in log_content.split('\n') if 'error' in line.lower()]
|
147
|
+
for line in error_lines:
|
148
|
+
message += f"\n{line}"
|
149
|
+
|
150
|
+
console.print(message, style="red")
|
151
|
+
raise MsiInstallationError("MSI Installation Failed.")
|
@@ -0,0 +1,25 @@
|
|
1
|
+
import os
|
2
|
+
import platform
|
3
|
+
|
4
|
+
|
5
|
+
def get_platform() -> str:
|
6
|
+
"""Return the current platform as a string."""
|
7
|
+
current_platform = platform.system().lower()
|
8
|
+
if current_platform == "windows":
|
9
|
+
return "windows"
|
10
|
+
elif current_platform == "linux":
|
11
|
+
if is_debian():
|
12
|
+
return "debian"
|
13
|
+
else:
|
14
|
+
return "linux unknown"
|
15
|
+
else:
|
16
|
+
return ""
|
17
|
+
|
18
|
+
|
19
|
+
def is_debian() -> bool:
|
20
|
+
"""Check if the current Linux distribution is Debian-based."""
|
21
|
+
if os.path.exists("/etc/os-release"):
|
22
|
+
with open("/etc/os-release") as f:
|
23
|
+
data = f.read().lower()
|
24
|
+
return "debian" in data
|
25
|
+
return False
|
File without changes
|
@@ -0,0 +1,419 @@
|
|
1
|
+
import sys
|
2
|
+
import subprocess
|
3
|
+
import requests
|
4
|
+
import argparse
|
5
|
+
|
6
|
+
from rich.console import Console
|
7
|
+
|
8
|
+
from atomicshop.wrappers import githubw
|
9
|
+
|
10
|
+
from ..infra import system
|
11
|
+
|
12
|
+
|
13
|
+
console = Console()
|
14
|
+
|
15
|
+
|
16
|
+
VERSION: str = "1.0.0"
|
17
|
+
|
18
|
+
|
19
|
+
# === WINDOWS FUNCTIONS ================================================================================================
|
20
|
+
import os
|
21
|
+
import time
|
22
|
+
import tempfile
|
23
|
+
|
24
|
+
from atomicshop import web
|
25
|
+
|
26
|
+
from ..infra import permissions, msis
|
27
|
+
|
28
|
+
|
29
|
+
WINDOWS_X64_SUFFIX: str = "x64.msi"
|
30
|
+
|
31
|
+
|
32
|
+
class NodeJSWindowsInstallerNoVersionsFound(Exception):
|
33
|
+
pass
|
34
|
+
|
35
|
+
|
36
|
+
class NodeJSWindowsInstallerMoreThanOneVersionFound(Exception):
|
37
|
+
pass
|
38
|
+
|
39
|
+
|
40
|
+
class NodeJSWindowsInstallerFailedToExtractFileNameFromString(Exception):
|
41
|
+
pass
|
42
|
+
|
43
|
+
|
44
|
+
class NodeJSWindowsInstallerFailedToExtractVersionInString(Exception):
|
45
|
+
pass
|
46
|
+
|
47
|
+
|
48
|
+
def is_nodejs_installed_win() -> bool:
|
49
|
+
"""
|
50
|
+
Check if Node.js is installed by trying to run 'node -v'.
|
51
|
+
"""
|
52
|
+
print("Checking if Node.js is installed...")
|
53
|
+
try:
|
54
|
+
try:
|
55
|
+
node_version = subprocess.check_output(["node", "-v"], text=True)
|
56
|
+
except FileNotFoundError:
|
57
|
+
console.print(f"node.exe is not found.", style="red")
|
58
|
+
raise
|
59
|
+
|
60
|
+
node_version = node_version.replace("\n", "")
|
61
|
+
console.print(f"node.exe is found. Version: {node_version}", style="green")
|
62
|
+
|
63
|
+
try:
|
64
|
+
npm_version = subprocess.check_output(["npm.cmd", "-v"], text=True).strip()
|
65
|
+
except FileNotFoundError:
|
66
|
+
console.print(f"npm.cmd is not found.", style="red")
|
67
|
+
raise
|
68
|
+
|
69
|
+
npm_version = npm_version.replace("\n", "")
|
70
|
+
console.print(f"npm.cmd is found. Version: {npm_version}", style="green")
|
71
|
+
print("Node.js is installed.")
|
72
|
+
return True
|
73
|
+
except FileNotFoundError:
|
74
|
+
print("Node.js is not installed.")
|
75
|
+
return False
|
76
|
+
|
77
|
+
|
78
|
+
def add_nodejs_to_session_path_win():
|
79
|
+
"""
|
80
|
+
Add Node.js to the PATH for the current CMD session.
|
81
|
+
This is needed if the installation was done in the same session where
|
82
|
+
you want to use Node.js right after the installation without restarting the CMD session.
|
83
|
+
"""
|
84
|
+
|
85
|
+
print("Adding Node.js to the PATH for the current session...")
|
86
|
+
# Get the installation directory from the default Node.js install path
|
87
|
+
program_files = os.environ.get("ProgramFiles", "C:\\Program Files")
|
88
|
+
nodejs_path = os.path.join(program_files, "nodejs")
|
89
|
+
|
90
|
+
if os.path.exists(nodejs_path):
|
91
|
+
print(f"Node.js installation found at: {nodejs_path}")
|
92
|
+
current_path = os.environ.get("PATH", "")
|
93
|
+
if nodejs_path not in current_path:
|
94
|
+
# Add Node.js to the PATH for the current process
|
95
|
+
os.environ["PATH"] = f"{nodejs_path};{current_path}"
|
96
|
+
print("Node.js has been added to the PATH for this session.")
|
97
|
+
else:
|
98
|
+
print("Node.js is already in the current session PATH.")
|
99
|
+
else:
|
100
|
+
print("Node.js installation directory not found.")
|
101
|
+
|
102
|
+
|
103
|
+
def get_latest_nodejs_version_win() -> str | None:
|
104
|
+
"""
|
105
|
+
Fetch the latest Node.js version from the official Node.js website.
|
106
|
+
"""
|
107
|
+
print("Fetching the latest Node.js version...")
|
108
|
+
url = "https://nodejs.org/dist/latest/SHASUMS256.txt"
|
109
|
+
|
110
|
+
response = requests.get(url, timeout=10)
|
111
|
+
response.raise_for_status()
|
112
|
+
# Parse the file for the Node.js version
|
113
|
+
found_versions: list = []
|
114
|
+
for line in response.text.splitlines():
|
115
|
+
if line.endswith(WINDOWS_X64_SUFFIX):
|
116
|
+
found_versions.append(line)
|
117
|
+
|
118
|
+
if not found_versions:
|
119
|
+
raise NodeJSWindowsInstallerNoVersionsFound("No Node.js versions found in [https://nodejs.org/dist/latest/SHASUMS256.txt]")
|
120
|
+
elif len(found_versions) > 1:
|
121
|
+
raise NodeJSWindowsInstallerMoreThanOneVersionFound(f"More than one Node.js version found:\n"
|
122
|
+
f"{'\n'.join(found_versions)}")
|
123
|
+
|
124
|
+
try:
|
125
|
+
file_name = found_versions[0].split(" ")[-1]
|
126
|
+
except IndexError:
|
127
|
+
raise NodeJSWindowsInstallerFailedToExtractFileNameFromString("Failed to extract the file name from the string.")
|
128
|
+
|
129
|
+
try:
|
130
|
+
version = file_name.replace("node-v", "").replace(f"-{WINDOWS_X64_SUFFIX}", "")
|
131
|
+
except Exception:
|
132
|
+
raise NodeJSWindowsInstallerFailedToExtractVersionInString("Failed to extract the version from the string.")
|
133
|
+
|
134
|
+
print(f"Latest Node.js version: {version}")
|
135
|
+
return version
|
136
|
+
|
137
|
+
|
138
|
+
def download_nodejs_installer_win(version):
|
139
|
+
"""
|
140
|
+
Download the Node.js MSI installer for Windows.
|
141
|
+
"""
|
142
|
+
|
143
|
+
version = f"v{version}"
|
144
|
+
nodejs_base_url = f"https://nodejs.org/dist/{version}/"
|
145
|
+
file_name = f"node-{version}-x64.msi"
|
146
|
+
download_url = nodejs_base_url + file_name
|
147
|
+
print(f"Downloading Node.js installer from: {download_url}")
|
148
|
+
|
149
|
+
# Make temporary directory to store the installer
|
150
|
+
temp_dir = tempfile.gettempdir()
|
151
|
+
temp_file_path = web.download(download_url, temp_dir)
|
152
|
+
return temp_file_path
|
153
|
+
|
154
|
+
|
155
|
+
def clean_up_win(installer_path) -> None:
|
156
|
+
"""
|
157
|
+
Remove the installer file after installation.
|
158
|
+
"""
|
159
|
+
|
160
|
+
if os.path.exists(installer_path):
|
161
|
+
os.remove(installer_path)
|
162
|
+
print(f"Removed installer: {installer_path}")
|
163
|
+
|
164
|
+
|
165
|
+
def install_nodejs_win(
|
166
|
+
force: bool = False
|
167
|
+
) -> int:
|
168
|
+
"""
|
169
|
+
Install Node.js on Windows.
|
170
|
+
|
171
|
+
:param force: bool, if True, the function will install Node.js even if it is already installed.
|
172
|
+
:return: int, 0 if successful, 1 if failed.
|
173
|
+
"""
|
174
|
+
if not permissions.is_admin():
|
175
|
+
console.print("This script requires administrative privileges to install Node.js.", style="red")
|
176
|
+
return 1
|
177
|
+
|
178
|
+
if is_nodejs_installed_win() and not force:
|
179
|
+
console.print("Node.js is already installed. Use the [force] to install without prompt. Do you want to install anyway? [y/n]", style="yellow", markup=False)
|
180
|
+
if input().strip().lower() != 'y':
|
181
|
+
print("Exiting without installation.")
|
182
|
+
return 0
|
183
|
+
|
184
|
+
console.print("Starting Node.js installation process...", style="blue")
|
185
|
+
try:
|
186
|
+
version = get_latest_nodejs_version_win()
|
187
|
+
except Exception as e:
|
188
|
+
console.print(str(e), style="red")
|
189
|
+
return 1
|
190
|
+
if not version:
|
191
|
+
console.print("Exiting: Could not fetch the latest Node.js version.", style="red")
|
192
|
+
return 1
|
193
|
+
|
194
|
+
installer_path = download_nodejs_installer_win(version)
|
195
|
+
if not installer_path:
|
196
|
+
console.print("Exiting: Failed to download the Node.js installer.", style="red")
|
197
|
+
return 1
|
198
|
+
|
199
|
+
msis.install_msi(installer_path, silent_progress_bar=True)
|
200
|
+
time.sleep(5) # Wait a few seconds for the installation to complete
|
201
|
+
|
202
|
+
try:
|
203
|
+
clean_up_win(installer_path)
|
204
|
+
except Exception as e:
|
205
|
+
console.print(f"Failed to clean up the installer: {e}", style="red")
|
206
|
+
return 1
|
207
|
+
console.print("Installation process finished.", style="green")
|
208
|
+
|
209
|
+
# Add Node.js to the PATH for the current session, so we can verify the installation right away.
|
210
|
+
add_nodejs_to_session_path_win()
|
211
|
+
if not is_nodejs_installed_win():
|
212
|
+
console.print("Node.js installation verification failed.", style="red")
|
213
|
+
return 1
|
214
|
+
|
215
|
+
return 0
|
216
|
+
# === EOF WINDOWS FUNCTIONS ============================================================================================
|
217
|
+
|
218
|
+
|
219
|
+
# === UBUNTU FUNCTIONS =================================================================================================
|
220
|
+
def install_npm_package_ubuntu(package_name: str, sudo: bool = True):
|
221
|
+
"""
|
222
|
+
The function will install a npm package on Ubuntu.
|
223
|
+
:param package_name: str, the name of the package to install.
|
224
|
+
:param sudo: bool, if True, the function will use sudo.
|
225
|
+
NPM commands require sudo to install global packages.
|
226
|
+
:return:
|
227
|
+
"""
|
228
|
+
|
229
|
+
# Check if Node.js is installed.
|
230
|
+
if not is_nodejs_installed_ubuntu():
|
231
|
+
return
|
232
|
+
|
233
|
+
command = f"npm install -g {package_name}"
|
234
|
+
|
235
|
+
if sudo:
|
236
|
+
command = f"sudo {command}"
|
237
|
+
|
238
|
+
_ = subprocess.check_output(command, shell=True, stderr=subprocess.STDOUT)
|
239
|
+
|
240
|
+
|
241
|
+
def is_nodejs_installed_ubuntu():
|
242
|
+
"""
|
243
|
+
The function will check if Node.js is installed.
|
244
|
+
:return: bool.
|
245
|
+
"""
|
246
|
+
|
247
|
+
try:
|
248
|
+
# Run the command 'node -v'
|
249
|
+
result = subprocess.run(['node', '-v'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
250
|
+
|
251
|
+
# Check if the command was successful
|
252
|
+
if result.returncode == 0:
|
253
|
+
message = f"Node.js installed. Version: {result.stdout.strip()}"
|
254
|
+
console.print(message, style='green')
|
255
|
+
return True
|
256
|
+
else:
|
257
|
+
print("Node.js is not installed.")
|
258
|
+
return False
|
259
|
+
except FileNotFoundError:
|
260
|
+
print("Node command not found. Node.js is not installed.")
|
261
|
+
return False
|
262
|
+
|
263
|
+
|
264
|
+
def get_nodejs_latest_version_ubuntu(
|
265
|
+
by_github_api: bool = True,
|
266
|
+
_by_nodejs_website: bool = False,
|
267
|
+
get_major: bool = False
|
268
|
+
) -> str:
|
269
|
+
"""
|
270
|
+
The function will get the latest version number of Node.js.
|
271
|
+
:param by_github_api: bool, if True, the function will get the version number using the GitHub API.
|
272
|
+
Limitations: rate limits apply.
|
273
|
+
:param _by_nodejs_website: bool, if True, the function will get the version number using the Node.js website.
|
274
|
+
Limitations: the website structure can change and the json file is relatively large.
|
275
|
+
This is only for reference, it is not tested.
|
276
|
+
:param get_major: bool, if True, the function will return only the major version number string.
|
277
|
+
:return: str.
|
278
|
+
"""
|
279
|
+
|
280
|
+
if by_github_api and _by_nodejs_website:
|
281
|
+
raise ValueError("Only one of the arguments can be True.")
|
282
|
+
elif not by_github_api and not _by_nodejs_website:
|
283
|
+
raise ValueError("At least one of the arguments must be True.")
|
284
|
+
|
285
|
+
latest_version = ''
|
286
|
+
if by_github_api:
|
287
|
+
github_wrapper = githubw.GitHubWrapper('nodejs', 'node')
|
288
|
+
latest_version = github_wrapper.get_latest_release_version()
|
289
|
+
elif _by_nodejs_website:
|
290
|
+
url = "https://nodejs.org/dist/index.json"
|
291
|
+
response = requests.get(url)
|
292
|
+
versions = response.json()
|
293
|
+
latest_version = versions[0]['version'] # Assuming the first one is the latest.
|
294
|
+
|
295
|
+
if get_major:
|
296
|
+
latest_version = latest_version.replace('v', '')
|
297
|
+
latest_version = latest_version.split('.')[0]
|
298
|
+
|
299
|
+
return latest_version
|
300
|
+
|
301
|
+
|
302
|
+
def install_nodejs_ubuntu(
|
303
|
+
latest: bool = False,
|
304
|
+
lts: bool = True,
|
305
|
+
version: str = None,
|
306
|
+
force: bool = False
|
307
|
+
):
|
308
|
+
"""
|
309
|
+
The function will install Node.js on Ubuntu.
|
310
|
+
|
311
|
+
:param latest: bool, if True, the function will install the latest version of Node.js.
|
312
|
+
:param lts: bool, if True, the function will install the LTS version of Node.js.
|
313
|
+
:param version: str, the version number of Node.js to install.
|
314
|
+
:param force: bool, if True, the function will install Node.js even if it is already installed.
|
315
|
+
|
316
|
+
:return:
|
317
|
+
"""
|
318
|
+
|
319
|
+
if latest + lts + (version is not None) > 1:
|
320
|
+
raise ValueError("Only one of the arguments can be set to True or provided: latest, lts, version.")
|
321
|
+
if not latest and not lts and version is None:
|
322
|
+
raise ValueError("At least one of the arguments must be set to True or provided: latest, lts, version.")
|
323
|
+
|
324
|
+
# Check if Node.js is already installed.
|
325
|
+
if is_nodejs_installed_ubuntu():
|
326
|
+
if not force:
|
327
|
+
return
|
328
|
+
|
329
|
+
# NodeSource is listed as source under official Node.js GitHub repository:
|
330
|
+
# https://github.com/nodejs/node?tab=readme-ov-file#current-and-lts-releases
|
331
|
+
print("Adding NodeSource repository...")
|
332
|
+
|
333
|
+
# Fetch and execute the NodeSource repository setup script.
|
334
|
+
if latest:
|
335
|
+
version: str = get_nodejs_latest_version_ubuntu(get_major=True)
|
336
|
+
|
337
|
+
command: str = ''
|
338
|
+
if latest or version:
|
339
|
+
command = f"curl -fsSL https://deb.nodesource.com/setup_{version}.x | sudo -E bash -"
|
340
|
+
elif lts:
|
341
|
+
command = "curl -fsSL https://deb.nodesource.com/setup_current.x | sudo -E bash -"
|
342
|
+
|
343
|
+
_ = subprocess.check_output(command, shell=True, stderr=subprocess.STDOUT)
|
344
|
+
|
345
|
+
subprocess.check_call(['sudo', 'apt', 'update'])
|
346
|
+
subprocess.check_call(["sudo", "apt", "install", "-y", "nodejs"])
|
347
|
+
|
348
|
+
# Check if Node.js is installed.
|
349
|
+
is_nodejs_installed_ubuntu()
|
350
|
+
# === EOF UBUNTU FUNCTIONS =============================================================================================
|
351
|
+
|
352
|
+
|
353
|
+
def _make_parser():
|
354
|
+
parser = argparse.ArgumentParser(description="Install Node.js on Ubuntu.")
|
355
|
+
parser.add_argument(
|
356
|
+
'--latest',
|
357
|
+
action='store_true',
|
358
|
+
help="Install the latest version of Node.js."
|
359
|
+
)
|
360
|
+
parser.add_argument(
|
361
|
+
'--lts',
|
362
|
+
action='store_true',
|
363
|
+
help="Install the LTS version of Node.js. Available only for Ubuntu."
|
364
|
+
)
|
365
|
+
parser.add_argument(
|
366
|
+
'--version',
|
367
|
+
type=str,
|
368
|
+
help="Install a specific version of Node.js. Available only for Ubuntu."
|
369
|
+
)
|
370
|
+
parser.add_argument(
|
371
|
+
'--force',
|
372
|
+
action='store_true',
|
373
|
+
help="Force the installation of Node.js."
|
374
|
+
)
|
375
|
+
|
376
|
+
return parser
|
377
|
+
|
378
|
+
|
379
|
+
def main(
|
380
|
+
latest: bool = False,
|
381
|
+
lts: bool = False,
|
382
|
+
version: str = None,
|
383
|
+
force: bool = False
|
384
|
+
) -> int:
|
385
|
+
"""
|
386
|
+
The function will install Node.js on Ubuntu or Windows.
|
387
|
+
|
388
|
+
:param latest: bool, if True, the function will install the latest version of Node.js.
|
389
|
+
:param lts: bool, if True, the function will install the LTS version of Node.js.
|
390
|
+
:param version: str, the version number of Node.js to install.
|
391
|
+
:param force: bool, if True, the function will install Node.js even if it is already installed.
|
392
|
+
|
393
|
+
:return:
|
394
|
+
"""
|
395
|
+
|
396
|
+
if latest + lts + (version is not None) > 1:
|
397
|
+
raise ValueError("Only one of the arguments can be set to True or provided: latest, lts, version.")
|
398
|
+
if not latest and not lts and version is None:
|
399
|
+
raise ValueError("At least one of the arguments must be set to True or provided: latest, lts, version.")
|
400
|
+
|
401
|
+
current_platform: str = system.get_platform()
|
402
|
+
if current_platform == "debian":
|
403
|
+
install_nodejs_ubuntu(latest, lts, version, force)
|
404
|
+
elif current_platform == "windows":
|
405
|
+
if version or lts:
|
406
|
+
console.print("On Windows, only [latest] arguments is implemented; [version] and [lts] arguments aren't available.", style="red", markup=False)
|
407
|
+
return 1
|
408
|
+
install_nodejs_win(force)
|
409
|
+
else:
|
410
|
+
console.print(f"Node.js installation on {current_platform} is not implemented yet.", style="red")
|
411
|
+
return 1
|
412
|
+
|
413
|
+
return 0
|
414
|
+
|
415
|
+
|
416
|
+
if __name__ == '__main__':
|
417
|
+
nodejs_parser = _make_parser()
|
418
|
+
args = nodejs_parser.parse_args()
|
419
|
+
sys.exit(main(**vars(args)))
|
@@ -0,0 +1,140 @@
|
|
1
|
+
import sys
|
2
|
+
import os
|
3
|
+
import argparse
|
4
|
+
import requests
|
5
|
+
from bs4 import BeautifulSoup
|
6
|
+
import subprocess
|
7
|
+
|
8
|
+
from rich.console import Console
|
9
|
+
|
10
|
+
from atomicshop import process, web
|
11
|
+
|
12
|
+
from ..infra import system, permissions
|
13
|
+
|
14
|
+
|
15
|
+
console = Console()
|
16
|
+
|
17
|
+
|
18
|
+
VERSION: str = "1.0.1"
|
19
|
+
|
20
|
+
|
21
|
+
# === WINDOWS FUNCTIONS ================================================================================================
|
22
|
+
def install_win():
|
23
|
+
"""
|
24
|
+
Main function to download and install the latest PyCharm Community Edition.
|
25
|
+
"""
|
26
|
+
|
27
|
+
if not permissions.is_admin():
|
28
|
+
console.print("This script requires administrative privileges to run.", style="red")
|
29
|
+
return 1
|
30
|
+
|
31
|
+
def get_latest_pycharm_download_link():
|
32
|
+
url = "https://www.jetbrains.com/pycharm/download/"
|
33
|
+
headers = {
|
34
|
+
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
|
35
|
+
}
|
36
|
+
|
37
|
+
response = requests.get(url, headers=headers)
|
38
|
+
if response.status_code != 200:
|
39
|
+
raise Exception("Failed to load the download page")
|
40
|
+
|
41
|
+
soup = BeautifulSoup(response.text, 'html.parser')
|
42
|
+
download_link = None
|
43
|
+
|
44
|
+
# Find the Professional version download link
|
45
|
+
for a in soup.find_all('a', href=True):
|
46
|
+
if '/download?code=PCC&platform=windows' in a['href']:
|
47
|
+
download_link = a['href']
|
48
|
+
break
|
49
|
+
|
50
|
+
if not download_link:
|
51
|
+
raise Exception("Could not find the download link for the latest version of PyCharm Professional")
|
52
|
+
|
53
|
+
return f"https:{download_link}"
|
54
|
+
|
55
|
+
installer_path: str | None = None
|
56
|
+
try:
|
57
|
+
print("Fetching the latest PyCharm download link...")
|
58
|
+
download_url = get_latest_pycharm_download_link()
|
59
|
+
print(f"Download URL: {download_url}")
|
60
|
+
|
61
|
+
print("Starting the download...")
|
62
|
+
file_name = "pycharm-latest.exe"
|
63
|
+
# download_file(download_url, file_name)
|
64
|
+
installer_path = web.download(file_url=download_url, file_name=file_name, use_certifi_ca_repository=True)
|
65
|
+
console.print(f"Downloaded the latest version of PyCharm to: {file_name}", style='green')
|
66
|
+
except Exception as e:
|
67
|
+
print(f"An error occurred: {e}")
|
68
|
+
|
69
|
+
if not installer_path:
|
70
|
+
console.print("Failed to download the latest version of PyCharm", style='red')
|
71
|
+
return 1
|
72
|
+
|
73
|
+
# Install PyCharm
|
74
|
+
# Run the installer
|
75
|
+
print("Running the installer...")
|
76
|
+
subprocess.run([installer_path, '/S'], check=True) # /S for silent installation
|
77
|
+
console.print("Installation complete.", style='green')
|
78
|
+
|
79
|
+
# Remove the installer
|
80
|
+
os.remove(installer_path)
|
81
|
+
|
82
|
+
return 0
|
83
|
+
# === EOF WINDOWS FUNCTIONS ============================================================================================
|
84
|
+
|
85
|
+
|
86
|
+
# === UBUNTU FUNCTIONS =================================================================================================
|
87
|
+
def install_ubuntu(enable_sudo_execution: bool = False) -> int:
|
88
|
+
"""
|
89
|
+
Main function to install the latest PyCharm unified Edition.
|
90
|
+
"""
|
91
|
+
|
92
|
+
process.execute_script('sudo snap install pycharm-professional --classic', shell=True)
|
93
|
+
|
94
|
+
if enable_sudo_execution:
|
95
|
+
process.execute_script('xhost +SI:localuser:root', shell=True)
|
96
|
+
console.print('Run the following command to start PyCharm as root: [sudo snap run pycharm-professional]', style='blue', markup=False)
|
97
|
+
return 0
|
98
|
+
# === EOF UBUNTU FUNCTIONS =============================================================================================
|
99
|
+
|
100
|
+
|
101
|
+
def _make_parser():
|
102
|
+
"""
|
103
|
+
Parse command line arguments.
|
104
|
+
|
105
|
+
:return: Parsed arguments.
|
106
|
+
"""
|
107
|
+
parser = argparse.ArgumentParser(description='Install PyCharm Community Edition.')
|
108
|
+
parser.add_argument(
|
109
|
+
'--enable_sudo_execution', action='store_true',
|
110
|
+
help='There is a problem when trying to run snapd installed Pycharm as sudo, need to enable this.'
|
111
|
+
'This is not a good security practice to run GUI apps as root. Only if you know what you doing.')
|
112
|
+
|
113
|
+
return parser
|
114
|
+
|
115
|
+
|
116
|
+
def main(
|
117
|
+
enable_sudo_execution: bool = False
|
118
|
+
) -> int:
|
119
|
+
"""
|
120
|
+
The function will install Node.js on Ubuntu or Windows.
|
121
|
+
|
122
|
+
:param enable_sudo_execution: bool: Enable sudo execution for snapd installed PyCharm.
|
123
|
+
|
124
|
+
:return: int: 0 if success, 1 if error.
|
125
|
+
"""
|
126
|
+
|
127
|
+
current_platform: str = system.get_platform()
|
128
|
+
if current_platform == "debian":
|
129
|
+
return install_ubuntu(enable_sudo_execution)
|
130
|
+
elif current_platform == "windows":
|
131
|
+
return install_win()
|
132
|
+
else:
|
133
|
+
console.print(f"PyCharm installation on {current_platform} is not implemented yet.", style="red")
|
134
|
+
return 1
|
135
|
+
|
136
|
+
|
137
|
+
if __name__ == '__main__':
|
138
|
+
pycharm_parser = _make_parser()
|
139
|
+
args = pycharm_parser.parse_args()
|
140
|
+
sys.exit(main(**vars(args)))
|
@@ -399,13 +399,4 @@ def main(
|
|
399
399
|
if __name__ == '__main__':
|
400
400
|
parser = _make_parser()
|
401
401
|
args = parser.parse_args()
|
402
|
-
sys.exit(main(
|
403
|
-
installer_usage=args.installer_usage,
|
404
|
-
compile_portable=args.compile_portable,
|
405
|
-
installer_version_string_fetch=args.installer_version_string_fetch,
|
406
|
-
compile_version_string_fetch=args.compile_version_string_fetch,
|
407
|
-
get_path=args.get_path,
|
408
|
-
set_path=args.set_path,
|
409
|
-
force=args.force,
|
410
|
-
exe_path=args.exe_path
|
411
|
-
))
|
402
|
+
sys.exit(main(**vars(args)))
|
@@ -0,0 +1,53 @@
|
|
1
|
+
from pathlib import Path
|
2
|
+
from types import ModuleType
|
3
|
+
from typing import Literal
|
4
|
+
|
5
|
+
from rich.console import Console
|
6
|
+
|
7
|
+
from . import _base
|
8
|
+
from .helpers.modules import nodejs_installer
|
9
|
+
|
10
|
+
|
11
|
+
console = Console()
|
12
|
+
|
13
|
+
|
14
|
+
class NodeJS(_base.BaseInstaller):
|
15
|
+
def __init__(self):
|
16
|
+
super().__init__()
|
17
|
+
self.name: str = Path(__file__).stem
|
18
|
+
self.description: str = "NodeJS Installer"
|
19
|
+
self.version: str = nodejs_installer.VERSION
|
20
|
+
self.platforms: list = ["windows", "debian"]
|
21
|
+
self.helper: ModuleType | None = nodejs_installer
|
22
|
+
|
23
|
+
def install(
|
24
|
+
self,
|
25
|
+
force: bool = False
|
26
|
+
):
|
27
|
+
nodejs_installer.main(
|
28
|
+
latest=True,
|
29
|
+
force=force
|
30
|
+
)
|
31
|
+
|
32
|
+
def _show_help(
|
33
|
+
self,
|
34
|
+
method: Literal["install", "uninstall", "update"]
|
35
|
+
) -> None:
|
36
|
+
if method == "install":
|
37
|
+
method_help: str = (
|
38
|
+
"This method uses the [nodejs_installer.py] with the following arguments:\n"
|
39
|
+
" --latest - install the latest stable version.\n"
|
40
|
+
"\n"
|
41
|
+
" --force - force install on ubuntu.\n"
|
42
|
+
" This one is used only if you provide it explicitly to the 'install' command. Example:\n"
|
43
|
+
" dkinst install nodejs force\n"
|
44
|
+
"\n"
|
45
|
+
"You can also use the 'manual' method to provide custom arguments to the helper script.\n"
|
46
|
+
"Example:\n"
|
47
|
+
" dkinst manual nodejs help\n"
|
48
|
+
" dkinst manual nodejs --lts --force\n"
|
49
|
+
"\n"
|
50
|
+
)
|
51
|
+
print(method_help)
|
52
|
+
else:
|
53
|
+
raise ValueError(f"Unknown method '{method}'.")
|
@@ -0,0 +1,36 @@
|
|
1
|
+
from pathlib import Path
|
2
|
+
from types import ModuleType
|
3
|
+
from typing import Literal
|
4
|
+
|
5
|
+
from . import _base
|
6
|
+
from .helpers.modules import pycharm_installer
|
7
|
+
|
8
|
+
|
9
|
+
class PyCharm(_base.BaseInstaller):
|
10
|
+
def __init__(self):
|
11
|
+
super().__init__()
|
12
|
+
self.name: str = Path(__file__).stem
|
13
|
+
self.description: str = "PyCharm Installer"
|
14
|
+
self.version: str = pycharm_installer.VERSION
|
15
|
+
self.platforms: list = ["windows", "debian"]
|
16
|
+
self.helper: ModuleType | None = None
|
17
|
+
|
18
|
+
def install(
|
19
|
+
self,
|
20
|
+
force: bool = False
|
21
|
+
):
|
22
|
+
pycharm_installer.main()
|
23
|
+
|
24
|
+
def _show_help(
|
25
|
+
self,
|
26
|
+
method: Literal["install", "uninstall", "update"]
|
27
|
+
) -> None:
|
28
|
+
if method == "install":
|
29
|
+
method_help: str = (
|
30
|
+
"This method installs the latest version of PyCharm unified:\n"
|
31
|
+
"Windows: Downloads and installs PyCharm using the official installer from the Downloads section.\n"
|
32
|
+
"Debian: Installs using the snap package manager.\n"
|
33
|
+
)
|
34
|
+
print(method_help)
|
35
|
+
else:
|
36
|
+
raise ValueError(f"Unknown method '{method}'.")
|
dkinst/installers/robocorp.py
CHANGED
@@ -4,10 +4,8 @@ from typing import Literal
|
|
4
4
|
import subprocess
|
5
5
|
from rich.console import Console
|
6
6
|
|
7
|
-
from
|
8
|
-
|
9
|
-
from . import _base
|
10
|
-
from .helpers import permissions
|
7
|
+
from . import _base, tesseract_ocr, nodejs
|
8
|
+
from .helpers.infra import permissions
|
11
9
|
|
12
10
|
|
13
11
|
console = Console()
|
@@ -31,15 +29,12 @@ class Robocorp(_base.BaseInstaller):
|
|
31
29
|
return 1
|
32
30
|
|
33
31
|
console.print(f"Installing Tesseract OCR", style="blue")
|
34
|
-
|
32
|
+
tesseract_ocr_wrapper = tesseract_ocr.TesseractOCR()
|
33
|
+
tesseract_ocr_wrapper.install()
|
35
34
|
|
36
35
|
console.print("Installing NodeJS.", style="blue")
|
37
|
-
|
38
|
-
|
39
|
-
install_nodejs_windows.add_nodejs_to_path()
|
40
|
-
if not install_nodejs_windows.is_nodejs_installed():
|
41
|
-
console.print("Node.js installation failed.", style="red")
|
42
|
-
return 1
|
36
|
+
nodejs_wrapper = nodejs.NodeJS()
|
37
|
+
nodejs_wrapper.install(force=True)
|
43
38
|
|
44
39
|
console.print("PIP Installing Robocorp.", style="blue")
|
45
40
|
subprocess.check_call(["pip", "install", "--upgrade", "rpaframework"])
|
@@ -50,12 +45,13 @@ class Robocorp(_base.BaseInstaller):
|
|
50
45
|
console.print("PIP Installing Robocorp-Recognition.", style="blue")
|
51
46
|
subprocess.check_call(["pip", "install", "--upgrade", "rpaframework-recognition"])
|
52
47
|
|
53
|
-
console.print("Installing Playwright browsers.", style="blue")
|
54
|
-
subprocess.check_call(["playwright", "install"])
|
55
|
-
|
56
48
|
console.print("Initializing Robocorp Browser.", style="blue")
|
57
49
|
subprocess.check_call(["rfbrowser", "init"])
|
58
50
|
|
51
|
+
# Robocorp browser init already installs the browsers.
|
52
|
+
# console.print("Installing Playwright browsers.", style="blue")
|
53
|
+
# subprocess.check_call(["playwright", "install"])
|
54
|
+
|
59
55
|
console.print("Installing Additional modules.", style="blue")
|
60
56
|
subprocess.check_call(["pip", "install", "--upgrade", "matplotlib", "imagehash", "pynput"])
|
61
57
|
|
@@ -75,6 +71,8 @@ class Robocorp(_base.BaseInstaller):
|
|
75
71
|
with open(window_file_path, "w") as file:
|
76
72
|
file.write(file_content)
|
77
73
|
|
74
|
+
console.print("Robocorp Framework installation/update finished.", style="green")
|
75
|
+
|
78
76
|
return 0
|
79
77
|
|
80
78
|
def update(
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: dkinst
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.4.1
|
4
4
|
Summary: Den K Simple Installer
|
5
5
|
Author: Denis Kras
|
6
6
|
License-Expression: MIT
|
@@ -13,6 +13,7 @@ Description-Content-Type: text/markdown
|
|
13
13
|
License-File: LICENSE
|
14
14
|
Requires-Dist: wheel
|
15
15
|
Requires-Dist: rich==14.1.0
|
16
|
+
Requires-Dist: atomicshop
|
16
17
|
Dynamic: license-file
|
17
18
|
|
18
19
|
<h1 align="center">Den K Simple Installer - dkinst</h1>
|
@@ -0,0 +1,24 @@
|
|
1
|
+
dkinst/__init__.py,sha256=DJlBbVtolLsH24o0HeILaF4gxpl7DL0axOCiIu97aD8,78
|
2
|
+
dkinst/cli.py,sha256=4jLmbW73FInE21i1FXhuhM6eymWhA4Pvicl34H62K_4,9278
|
3
|
+
dkinst/config.toml,sha256=OaTuImf9xBIbTNCrC2MfAzpPLeuDdV2R5feIfT7xImA,48
|
4
|
+
dkinst/installers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
|
+
dkinst/installers/_base.py,sha256=2Ke4pQevOq3SRpCI1YKB9JrIwKIacPvAAMfjKn7IG20,10280
|
6
|
+
dkinst/installers/nodejs.py,sha256=34UObZLKjRIKcQt3Omslcqyuibm1m6u9nR6-W472gqY,1781
|
7
|
+
dkinst/installers/pycharm.py,sha256=GvH8uVCItaIjPSGPg2pyYl-7-LOkvh7gtubWmD2qvTM,1196
|
8
|
+
dkinst/installers/robocorp.py,sha256=yDBnA6sFjMSiOhwtyMRd59K-k6VC-42e5zVjeYZbmR4,4141
|
9
|
+
dkinst/installers/tesseract_ocr.py,sha256=iEW6S9CxzGRrhzYW0A0FMwgb6SxKXOOfCdiI1EAG5W0,2532
|
10
|
+
dkinst/installers/helpers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
11
|
+
dkinst/installers/helpers/infra/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
12
|
+
dkinst/installers/helpers/infra/msis.py,sha256=WQCTo3CsublO_xfyAgim5_HqlzMbjfhuYLM6zrqjAng,6036
|
13
|
+
dkinst/installers/helpers/infra/permissions.py,sha256=CYTDVOI0jh9ks0ZLnnOuPzppgCszFEc9-92DTkVTYi4,522
|
14
|
+
dkinst/installers/helpers/infra/system.py,sha256=CovoRRRz3TFEHKzHjuoSEJ2vrJGSbUETm3j5m-fjC2I,676
|
15
|
+
dkinst/installers/helpers/modules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
16
|
+
dkinst/installers/helpers/modules/nodejs_installer.py,sha256=crilyPMcFrydvpmgZjj5Q0evT5oQswY-pLmrt2BDr54,14966
|
17
|
+
dkinst/installers/helpers/modules/pycharm_installer.py,sha256=sRuRCvqFBoCxc9XDqb3E05x-M2LmFGV8c47FsXai8Xg,4914
|
18
|
+
dkinst/installers/helpers/modules/tesseract_ocr_manager.py,sha256=lJYVJDp5OTto4GHY1xkvJUkXCR1sgcOwj3UEUvfbPps,17369
|
19
|
+
dkinst-0.4.1.dist-info/licenses/LICENSE,sha256=ohlj1rmsTHdctr-wyqmP6kbFC6Sff8pJd29v3pruZ18,1088
|
20
|
+
dkinst-0.4.1.dist-info/METADATA,sha256=aevn_0EpnKKRwGhohQreBnCJXvp2mcZJRDupv72ZEVk,2045
|
21
|
+
dkinst-0.4.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
22
|
+
dkinst-0.4.1.dist-info/entry_points.txt,sha256=YNgO3GufKMdA_oRqWEGAVh6k00oIuPItqqChoUtU278,43
|
23
|
+
dkinst-0.4.1.dist-info/top_level.txt,sha256=_dGNrME6z6Ihv2sxGC4hfAlnVuhoDlKwx-97LZ2xtQ0,7
|
24
|
+
dkinst-0.4.1.dist-info/RECORD,,
|
dkinst-0.2.0.dist-info/RECORD
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
dkinst/__init__.py,sha256=S9yw_pl4J-PdSgFEDS7IQqPh-mDYidu8SUSUrDHBeYg,78
|
2
|
-
dkinst/cli.py,sha256=4jLmbW73FInE21i1FXhuhM6eymWhA4Pvicl34H62K_4,9278
|
3
|
-
dkinst/config.toml,sha256=OaTuImf9xBIbTNCrC2MfAzpPLeuDdV2R5feIfT7xImA,48
|
4
|
-
dkinst/installers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
|
-
dkinst/installers/_base.py,sha256=03KA1u23EKhArJV_SNlST3ss-Pvs6U6YPUEZxHYC_94,10306
|
6
|
-
dkinst/installers/robocorp.py,sha256=WAO8s9VZfQ29cPve1xMr1y5R74WaNZJf-BOOjPsC1VU,4232
|
7
|
-
dkinst/installers/tesseract_ocr.py,sha256=LqcOJCTQJU3xPz3wm_nQI5Bt6bB5dgDPzf7WykpSM6A,2524
|
8
|
-
dkinst/installers/helpers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
9
|
-
dkinst/installers/helpers/permissions.py,sha256=CYTDVOI0jh9ks0ZLnnOuPzppgCszFEc9-92DTkVTYi4,522
|
10
|
-
dkinst/installers/helpers/tesseract_ocr_manager.py,sha256=-Br9vHbqcQHRsNlDkakw5mLMxMBTydqXCblhpcBmp0A,17734
|
11
|
-
dkinst-0.2.0.dist-info/licenses/LICENSE,sha256=ohlj1rmsTHdctr-wyqmP6kbFC6Sff8pJd29v3pruZ18,1088
|
12
|
-
dkinst-0.2.0.dist-info/METADATA,sha256=t8sA7dOIwT_cOwOak7YTl4D-oarFbmfpbUnZ75n8SY4,2018
|
13
|
-
dkinst-0.2.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
14
|
-
dkinst-0.2.0.dist-info/entry_points.txt,sha256=YNgO3GufKMdA_oRqWEGAVh6k00oIuPItqqChoUtU278,43
|
15
|
-
dkinst-0.2.0.dist-info/top_level.txt,sha256=_dGNrME6z6Ihv2sxGC4hfAlnVuhoDlKwx-97LZ2xtQ0,7
|
16
|
-
dkinst-0.2.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|