bcpkgfox 0.15.30__py3-none-any.whl → 0.17.7__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.
- bcpkgfox/__init__.py +79 -26
- bcpkgfox/clean.py +257 -0
- bcpkgfox/cli.py +465 -138
- bcpkgfox/find_elements.py +33 -8
- bcpkgfox/get_driver.py +33 -14
- bcpkgfox/invoke_api.py +386 -88
- bcpkgfox/system.py +42 -9
- {bcpkgfox-0.15.30.dist-info → bcpkgfox-0.17.7.dist-info}/METADATA +20 -4
- bcpkgfox-0.17.7.dist-info/RECORD +12 -0
- {bcpkgfox-0.15.30.dist-info → bcpkgfox-0.17.7.dist-info}/WHEEL +1 -1
- bcpkgfox-0.17.7.dist-info/entry_points.txt +22 -0
- bcpkgfox/cli 2.py +0 -536
- bcpkgfox/cli copy 2.py +0 -237
- bcpkgfox/cli copy.py +0 -306
- bcpkgfox/cli2.py +0 -303
- bcpkgfox/dasdad.py +0 -68
- bcpkgfox/exec_file copy 2.py +0 -100
- bcpkgfox/exec_file copy.py +0 -99
- bcpkgfox/exec_file.py +0 -100
- bcpkgfox-0.15.30.dist-info/RECORD +0 -19
- bcpkgfox-0.15.30.dist-info/entry_points.txt +0 -2
- {bcpkgfox-0.15.30.dist-info → bcpkgfox-0.17.7.dist-info}/top_level.txt +0 -0
bcpkgfox/cli.py
CHANGED
|
@@ -8,53 +8,114 @@ import sys
|
|
|
8
8
|
import re
|
|
9
9
|
import os
|
|
10
10
|
|
|
11
|
+
def main(): cli().main()
|
|
12
|
+
|
|
11
13
|
class cli:
|
|
12
14
|
def __init__(self):
|
|
13
15
|
self.current_dir = os.getcwd()
|
|
16
|
+
self.file = None
|
|
17
|
+
self.args = None
|
|
14
18
|
|
|
15
19
|
self.visuals = self.visual(self)
|
|
16
20
|
self.exec_gen = self.exec_gen_(self)
|
|
17
21
|
self.find_imports = self.find_import(self)
|
|
18
|
-
self.
|
|
22
|
+
self.venv_manager = self.venv_mangt(self)
|
|
19
23
|
|
|
20
24
|
self.parser = argparse.ArgumentParser(
|
|
21
|
-
add_help=False
|
|
25
|
+
add_help=False,
|
|
26
|
+
description=f"{self.visuals.bold}{self.visuals.DK_ORANGE} BCFOX Library \n You can use the arguments in any order you want.\n\n Most flags are independent, you can use it alone or combine them in a single command interacting with each other when applicable.{self.visuals.RESET}",
|
|
27
|
+
formatter_class=argparse.ArgumentDefaultsHelpFormatter
|
|
28
|
+
# formatter_class=argparse.RawTextHelpFormatter # Formats the 'help' text manually
|
|
22
29
|
)
|
|
23
|
-
|
|
24
|
-
self.file = args.filename
|
|
30
|
+
|
|
25
31
|
self._setup_arguments()
|
|
26
32
|
|
|
27
33
|
def _setup_arguments(self):
|
|
28
34
|
"""Configure all CLI arguments"""
|
|
29
|
-
venv_group = self.parser.add_argument_group('
|
|
35
|
+
venv_group = self.parser.add_argument_group(f'{self.visuals.ORANGE}{self.visuals.bold} Virtual Environment Options{self.visuals.RESET}')
|
|
30
36
|
venv_group.add_argument(
|
|
31
37
|
'-v', '--venv',
|
|
32
38
|
action='store_true',
|
|
33
|
-
help="Creates a virtual environment with all dependencies installed"
|
|
39
|
+
help="Creates a new virtual environment with all dependencies installed\n"
|
|
34
40
|
)
|
|
35
41
|
|
|
36
42
|
venv_group.add_argument(
|
|
37
43
|
'-vc', '--venv-clean',
|
|
38
44
|
action='store_true',
|
|
39
|
-
help="Creates a virtual environment without dependencies"
|
|
45
|
+
help="Creates a virtual environment without dependencies\n"
|
|
40
46
|
)
|
|
41
47
|
|
|
42
48
|
venv_group.add_argument(
|
|
43
49
|
'-rv', '--recreate-venv',
|
|
44
50
|
action='store_true',
|
|
45
|
-
help="Recreates venv (without dependencies)"
|
|
51
|
+
help="Recreates venv (without dependencies)\n"
|
|
46
52
|
)
|
|
47
53
|
|
|
48
54
|
venv_group.add_argument(
|
|
49
55
|
'-dv', '--delete-venv',
|
|
50
56
|
action='store_true',
|
|
51
|
-
help="Deletes venv"
|
|
57
|
+
help="Deletes venv\n"
|
|
52
58
|
)
|
|
53
59
|
|
|
54
|
-
|
|
60
|
+
venv_group.add_argument(
|
|
61
|
+
'-r', '--requirements',
|
|
62
|
+
action='store_true',
|
|
63
|
+
# nargs='?',
|
|
64
|
+
# action=self.venv_manager.custom_action_requirements,
|
|
65
|
+
# default=False,
|
|
66
|
+
help="Create a requirements\n"
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
exe_group = self.parser.add_argument_group(f'{self.visuals.ORANGE}{self.visuals.bold} Exe options{self.visuals.RESET}')
|
|
70
|
+
exe_group.add_argument(
|
|
71
|
+
'-e', '--exe',
|
|
72
|
+
action='store_true',
|
|
73
|
+
help="Creates a .exe of the file\n"
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
exe_group.add_argument(
|
|
77
|
+
'-nc', '--no-console',
|
|
78
|
+
action='store_true',
|
|
79
|
+
help="The exe don't open the console when started\n"
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
exe_group.add_argument(
|
|
83
|
+
'-z', '--zip',
|
|
84
|
+
action='store_true',
|
|
85
|
+
help="Make a zip of the 'dist' and rename it to the name of the file\n"
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
exe_group.add_argument(
|
|
89
|
+
'-ic', '--icon',
|
|
90
|
+
type=str,
|
|
91
|
+
nargs='+',
|
|
92
|
+
help="Change the exe icon (put .ico path)\n"
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
exe_group.add_argument(
|
|
96
|
+
'-ad', '--add-data',
|
|
97
|
+
type=str,
|
|
98
|
+
nargs='+',
|
|
99
|
+
help="Add data(s) to .exe (similar of pyinstaller)\n"
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
file_group = self.parser.add_argument_group(f'{self.visuals.ORANGE}{self.visuals.bold} File Options{self.visuals.RESET}')
|
|
103
|
+
file_group.add_argument(
|
|
55
104
|
'-fi', '--find-imports',
|
|
56
105
|
action='store_true',
|
|
57
|
-
help="Finds all imports necessary for the lib to work"
|
|
106
|
+
help="Finds all imports necessary for the lib to work\n"
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
file_group.add_argument(
|
|
110
|
+
'-vi', '--verify-imports',
|
|
111
|
+
action='store_true',
|
|
112
|
+
help="Shows imports that were not installed automatically\n"
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
file_group.add_argument(
|
|
116
|
+
'-i', '--install-imports',
|
|
117
|
+
action='store_true',
|
|
118
|
+
help="Installs all imports necessary for the lib to work\n"
|
|
58
119
|
)
|
|
59
120
|
|
|
60
121
|
self.parser.add_argument(
|
|
@@ -68,36 +129,77 @@ class cli:
|
|
|
68
129
|
'-h', '--help',
|
|
69
130
|
action='help',
|
|
70
131
|
default=argparse.SUPPRESS,
|
|
71
|
-
help="
|
|
132
|
+
help="If you need more help contact guilherme"
|
|
72
133
|
)
|
|
73
134
|
|
|
74
135
|
def main(self):
|
|
75
|
-
args = self.parser.parse_args()
|
|
136
|
+
self.args = self.parser.parse_args()
|
|
137
|
+
self.file = self.args.filename
|
|
138
|
+
|
|
139
|
+
self.data_dict = []
|
|
140
|
+
if self.args.exe:
|
|
141
|
+
if self.args.add_data:
|
|
142
|
+
for data in self.args.add_data:
|
|
143
|
+
self.data_dict.append(data)
|
|
144
|
+
|
|
145
|
+
# Icon check
|
|
146
|
+
if self.args.icon:
|
|
147
|
+
if len(self.args.icon) > 1:
|
|
148
|
+
raise ValueError("Put only one PATH in 'icon' argument.")
|
|
149
|
+
|
|
150
|
+
if not os.path.exists(os.path.join(self.current_dir, self.args.icon[0])):
|
|
151
|
+
raise ValueError(f"The path '{self.args.icon[0]}' not exists")
|
|
76
152
|
|
|
77
|
-
|
|
153
|
+
# Venv
|
|
154
|
+
if self.args.venv:
|
|
78
155
|
self.venv_manager.main()
|
|
79
|
-
elif args.venv_clean:
|
|
156
|
+
elif self.args.venv_clean:
|
|
80
157
|
self.venv_manager.create_venv()
|
|
81
|
-
elif args.recreate_venv:
|
|
158
|
+
elif self.args.recreate_venv:
|
|
82
159
|
self.venv_manager.recreate_venv()
|
|
83
|
-
elif args.delete_venv:
|
|
160
|
+
elif self.args.delete_venv:
|
|
84
161
|
self.venv_manager.delete_venv()
|
|
85
162
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
self.
|
|
163
|
+
# Imports
|
|
164
|
+
if self.args.find_imports:
|
|
165
|
+
self.find_imports.main()
|
|
166
|
+
elif self.args.install_imports:
|
|
167
|
+
self.venv_manager.install_imports()
|
|
168
|
+
|
|
169
|
+
# EXEC
|
|
170
|
+
elif self.args.exe:
|
|
171
|
+
self.exec_gen.main()
|
|
172
|
+
|
|
173
|
+
if self.args.zip:
|
|
174
|
+
self.exec_gen.zip_file()
|
|
175
|
+
|
|
176
|
+
# LOG - Verify imports
|
|
177
|
+
if self.args.verify_imports:
|
|
178
|
+
if self.args.find_imports \
|
|
179
|
+
or self.args.install_imports \
|
|
180
|
+
or self.args.venv \
|
|
181
|
+
or self.args.recreate_venv \
|
|
182
|
+
or self.args.exe:
|
|
183
|
+
self.find_imports.verify_imports()
|
|
184
|
+
else:
|
|
185
|
+
print(f"{self.visuals.bold}{self.visuals.RD} > Error: You need to use one function that installs imports before verifying them{self.visuals.RESET}")
|
|
186
|
+
print("\033[J", end='', flush=True)
|
|
187
|
+
|
|
188
|
+
# Requirements
|
|
189
|
+
if self.args.requirements:
|
|
190
|
+
self.venv_manager.requirements()
|
|
191
|
+
|
|
192
|
+
self.clean_terminal()
|
|
91
193
|
|
|
92
194
|
def clean_terminal(self):
|
|
93
195
|
if self.exec_gen.error == 1 \
|
|
94
196
|
or self.find_imports.error == 1 \
|
|
95
|
-
or self.
|
|
197
|
+
or self.venv_manager.error == 1:
|
|
96
198
|
print("\033[J", end='', flush=True)
|
|
97
199
|
|
|
98
200
|
if self.exec_gen.descerror: print(f"\n {self.visuals.DK_ORANGE}>{self.visuals.RESET} {self.exec_gen.descerror}")
|
|
99
201
|
if self.find_imports.descerror: print(f"\n {self.visuals.DK_ORANGE}>{self.visuals.RESET} {self.find_imports.descerror}")
|
|
100
|
-
if self.
|
|
202
|
+
if self.venv_manager.descerror: print(f"\n {self.visuals.DK_ORANGE}>{self.visuals.RESET} {self.venv_manager.descerror}")
|
|
101
203
|
|
|
102
204
|
class visual:
|
|
103
205
|
def __init__(self, self_cli):
|
|
@@ -105,6 +207,7 @@ class cli:
|
|
|
105
207
|
|
|
106
208
|
self.DK_ORANGE = "\033[38;5;130m"
|
|
107
209
|
self.ORANGE = "\033[38;5;214m"
|
|
210
|
+
self.YL = "\033[38;5;226m"
|
|
108
211
|
self.RD = "\033[38;5;196m"
|
|
109
212
|
self.GR = "\033[38;5;34m"
|
|
110
213
|
self.RESET = "\033[0m"
|
|
@@ -136,6 +239,53 @@ class cli:
|
|
|
136
239
|
time.sleep(delay)
|
|
137
240
|
return f" \033[1m{self.rgb_text(text, r, g, b)}\033[0m"
|
|
138
241
|
|
|
242
|
+
class animation:
|
|
243
|
+
def __init__(self, self_cli):
|
|
244
|
+
self.cli = self_cli
|
|
245
|
+
self.text = None
|
|
246
|
+
self.braille_spinner = [
|
|
247
|
+
'\u280B',
|
|
248
|
+
'\u2809',
|
|
249
|
+
'\u2839',
|
|
250
|
+
'\u2838',
|
|
251
|
+
'\u283C',
|
|
252
|
+
'\u2834',
|
|
253
|
+
'\u2826',
|
|
254
|
+
'\u2827',
|
|
255
|
+
'\u2807',
|
|
256
|
+
'\u280F'
|
|
257
|
+
]
|
|
258
|
+
|
|
259
|
+
self.retro_computer_style = [
|
|
260
|
+
'\u23BA', # ⎺
|
|
261
|
+
'\u23BB', # ⎻
|
|
262
|
+
'\u23BC', # ⎼
|
|
263
|
+
'\u23BD', # ⎽
|
|
264
|
+
]
|
|
265
|
+
|
|
266
|
+
self.footer_thread = None
|
|
267
|
+
self.process_finished = False
|
|
268
|
+
|
|
269
|
+
def print_footer(self):
|
|
270
|
+
s = 0
|
|
271
|
+
n = 0
|
|
272
|
+
while not self.process_finished:
|
|
273
|
+
if s % 10 == 0: n += 1
|
|
274
|
+
if n == len(self.retro_computer_style): n = 0
|
|
275
|
+
|
|
276
|
+
sys.stdout.write(f"\r \033[F\r\033[K\033[E {self.cli.visuals.animate_rgb_text(f" {self.cli.visuals.bold} {self.retro_computer_style[n]} {self.text} {self.retro_computer_style[n]} {self.cli.visuals.RESET}")} \033[0J\n\033[F")
|
|
277
|
+
sys.stdout.flush()
|
|
278
|
+
s += 1
|
|
279
|
+
|
|
280
|
+
def start(self, text):
|
|
281
|
+
self.text = text
|
|
282
|
+
self.footer_thread = threading.Thread(target=self.print_footer)
|
|
283
|
+
self.footer_thread.start()
|
|
284
|
+
|
|
285
|
+
def finish(self):
|
|
286
|
+
self.process_finished = True
|
|
287
|
+
self.footer_thread.join()
|
|
288
|
+
|
|
139
289
|
class exec_gen_:
|
|
140
290
|
def __init__(self, self_cli):
|
|
141
291
|
self.cli = self_cli
|
|
@@ -144,17 +294,11 @@ class cli:
|
|
|
144
294
|
self.error = 0
|
|
145
295
|
self.descerror = ""
|
|
146
296
|
self.visuals = self.cli.visuals
|
|
297
|
+
self.ultimate_error = None
|
|
147
298
|
|
|
148
299
|
def preparations(self):
|
|
149
300
|
self.current_dir = os.getcwd()
|
|
150
|
-
|
|
151
|
-
parser = argparse.ArgumentParser(description="Script to generate .exe and preventing bugs")
|
|
152
|
-
parser.add_argument("file", type=str, help="Put the name of file after the command (with the extension '.py')")
|
|
153
|
-
|
|
154
|
-
# args = parser.parse_args() #TODO
|
|
155
|
-
# self.file_name = args.file #TODO
|
|
156
|
-
self.target_file = os.path.join(self.current_dir, self.file_name) #TODO
|
|
157
|
-
# self.target_file = self.cli.file #FIX
|
|
301
|
+
self.target_file = os.path.join(self.current_dir, self.cli.file) #TODO
|
|
158
302
|
|
|
159
303
|
if not os.path.exists(self.target_file):
|
|
160
304
|
self.descerror = f"Error: File '{self.target_file}' does not exist."
|
|
@@ -165,23 +309,23 @@ class cli:
|
|
|
165
309
|
global process_finished
|
|
166
310
|
|
|
167
311
|
braille_spinner = [
|
|
168
|
-
'\u280B',
|
|
169
|
-
'\u2809',
|
|
170
|
-
'\u2839',
|
|
171
|
-
'\u2838',
|
|
172
|
-
'\u283C',
|
|
173
|
-
'\u2834',
|
|
174
|
-
'\u2826',
|
|
175
|
-
'\u2827',
|
|
176
|
-
'\u2807',
|
|
177
|
-
'\u280F'
|
|
312
|
+
'\u280B',
|
|
313
|
+
'\u2809',
|
|
314
|
+
'\u2839',
|
|
315
|
+
'\u2838',
|
|
316
|
+
'\u283C',
|
|
317
|
+
'\u2834',
|
|
318
|
+
'\u2826',
|
|
319
|
+
'\u2827',
|
|
320
|
+
'\u2807',
|
|
321
|
+
'\u280F'
|
|
178
322
|
]
|
|
179
323
|
|
|
180
324
|
retro_computer_style = [
|
|
181
|
-
'\u23BA',
|
|
182
|
-
'\u23BB',
|
|
183
|
-
'\u23BC',
|
|
184
|
-
'\u23BD',
|
|
325
|
+
'\u23BA',
|
|
326
|
+
'\u23BB',
|
|
327
|
+
'\u23BC',
|
|
328
|
+
'\u23BD',
|
|
185
329
|
]
|
|
186
330
|
|
|
187
331
|
def print_footer():
|
|
@@ -191,34 +335,123 @@ class cli:
|
|
|
191
335
|
if s % 10 == 0: n += 1
|
|
192
336
|
if n == len(braille_spinner): n = 0
|
|
193
337
|
|
|
194
|
-
sys.stdout.write(f"\r \033[F\r\033[K\033[E {self.visuals.animate_rgb_text(f" {self.visuals.bold} {braille_spinner[n]} Gerando executável do '{self.
|
|
338
|
+
sys.stdout.write(f"\r \033[F\r\033[K\033[E {self.visuals.animate_rgb_text(f" {self.visuals.bold} {braille_spinner[n]} Gerando executável do '{self.cli.file}', aguarde finalização. {braille_spinner[n]} {self.visuals.RESET}")} \033[0J\n\033[F")
|
|
195
339
|
sys.stdout.flush()
|
|
196
340
|
s += 1
|
|
341
|
+
print("\033[1A \r\033[K \033[1B \r\033[K") #\033[1B \r\033[K\033[1B \r\033[K\033[1B \r\033[K")
|
|
197
342
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
command,
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
343
|
+
try:
|
|
344
|
+
process_finished = False
|
|
345
|
+
python_executable = os.path.join(".venv", 'Scripts' if os.name == 'nt' else 'bin', 'python')
|
|
346
|
+
command = [python_executable, "-m", "PyInstaller", "--onefile", "--clean"]
|
|
347
|
+
if self.cli.data_dict:
|
|
348
|
+
for data in self.cli.data_dict:
|
|
349
|
+
if ":" in data or ";" in data: command.extend(["--add-data", data])
|
|
350
|
+
else: command.extend(["--add-data", f"{data}:{data}"])
|
|
351
|
+
|
|
352
|
+
if self.cli.args.no_console:
|
|
353
|
+
command.append("--noconsole")
|
|
354
|
+
|
|
355
|
+
if self.cli.args.icon:
|
|
356
|
+
command.extend(["--icon", f"{self.cli.args.icon[0]}"])
|
|
357
|
+
|
|
358
|
+
command.append(self.target_file)
|
|
359
|
+
|
|
360
|
+
process = subprocess.Popen(
|
|
361
|
+
command,
|
|
362
|
+
stdout=subprocess.PIPE,
|
|
363
|
+
stderr=subprocess.STDOUT,
|
|
364
|
+
universal_newlines=True,
|
|
365
|
+
bufsize=1
|
|
366
|
+
)
|
|
367
|
+
footer_thread = threading.Thread(target=print_footer)
|
|
368
|
+
footer_thread.start()
|
|
369
|
+
|
|
370
|
+
while True:
|
|
371
|
+
output = process.stdout.readline()
|
|
372
|
+
if output == '' and process.poll() is not None: break
|
|
373
|
+
if output:
|
|
374
|
+
sys.stdout.write(f"\033[F\r\033[K{output.strip()}\033[K\n\n")
|
|
375
|
+
sys.stdout.flush()
|
|
209
376
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
if output == '' and process.poll() is not None:
|
|
213
|
-
break
|
|
214
|
-
if output:
|
|
215
|
-
sys.stdout.write(f"\033[F\r\033[K{output.strip()}\033[K\n\n")
|
|
216
|
-
sys.stdout.flush()
|
|
377
|
+
process_finished = True
|
|
378
|
+
footer_thread.join()
|
|
217
379
|
|
|
218
|
-
|
|
219
|
-
|
|
380
|
+
except Exception as e:
|
|
381
|
+
process_finished = True
|
|
382
|
+
self.descerror = e
|
|
383
|
+
self.error = 1
|
|
384
|
+
finally: process_finished = True
|
|
385
|
+
|
|
386
|
+
rows = os.get_terminal_size().lines
|
|
387
|
+
print(f"\033[F\033[K\033[f\033[K\033[f\033[K{self.visuals.bold}{self.visuals.GR}\033[{rows};1H > Executável gerado com sucesso!\n{self.visuals.RESET} \033[0J")
|
|
388
|
+
|
|
389
|
+
def zip_file(self):
|
|
390
|
+
|
|
391
|
+
animation = self.visuals.animation(self.cli)
|
|
392
|
+
animation.start(text='Creating zip file')
|
|
393
|
+
zip_log = False
|
|
394
|
+
|
|
395
|
+
try:
|
|
396
|
+
name_dir = self.current_dir.split("\\")
|
|
397
|
+
print(name_dir)
|
|
398
|
+
|
|
399
|
+
name_dir = [part for part in name_dir if part]
|
|
400
|
+
|
|
401
|
+
target_name = name_dir[-1]
|
|
402
|
+
|
|
403
|
+
dist_path = os.path.join(self.current_dir, "dist")
|
|
404
|
+
temp_path = os.path.join(self.current_dir, f"{target_name}_temp")
|
|
405
|
+
inner_path = os.path.join(temp_path, target_name)
|
|
406
|
+
|
|
407
|
+
if os.path.isfile(os.path.join(self.current_dir, f"{target_name}.zip")):
|
|
408
|
+
os.remove(os.path.join(self.current_dir, f"{target_name}.zip"))
|
|
409
|
+
|
|
410
|
+
if os.path.exists(os.path.join(self.current_dir, f"{target_name}")):
|
|
411
|
+
shutil.rmtree(os.path.join(self.current_dir, f"{target_name}"))
|
|
412
|
+
|
|
413
|
+
if os.path.exists(dist_path):
|
|
414
|
+
if os.path.exists(temp_path):
|
|
415
|
+
shutil.rmtree(temp_path)
|
|
416
|
+
os.mkdir(temp_path)
|
|
417
|
+
shutil.move(dist_path, inner_path)
|
|
418
|
+
else:
|
|
419
|
+
raise FileNotFoundError(f"{self.visuals.bold}{self.visuals.RD}Error: 'dist' directory not found!{self.visuals.RESET}")
|
|
420
|
+
|
|
421
|
+
zip_path = shutil.make_archive(
|
|
422
|
+
os.path.join(self.current_dir, target_name),
|
|
423
|
+
'zip',
|
|
424
|
+
root_dir=temp_path,
|
|
425
|
+
base_dir=target_name
|
|
426
|
+
)
|
|
427
|
+
|
|
428
|
+
# Espera o sistema liberar o zip
|
|
429
|
+
wait = 0
|
|
430
|
+
while True:
|
|
431
|
+
try:
|
|
432
|
+
with open(zip_path, 'rb'):
|
|
433
|
+
break
|
|
434
|
+
except (PermissionError, OSError):
|
|
435
|
+
time.sleep(0.1)
|
|
436
|
+
wait += 1
|
|
437
|
+
if wait >= 600:
|
|
438
|
+
raise TimeoutError("Timeout while waiting for zip file to be accessible.")
|
|
439
|
+
|
|
440
|
+
shutil.rmtree(temp_path)
|
|
441
|
+
zip_log = True
|
|
220
442
|
|
|
221
|
-
|
|
443
|
+
except Exception as e:
|
|
444
|
+
self.ultimate_error = e
|
|
445
|
+
|
|
446
|
+
finally:
|
|
447
|
+
animation.finish()
|
|
448
|
+
|
|
449
|
+
if zip_log:
|
|
450
|
+
print(f"{self.visuals.bold}{self.visuals.GR} > Zip file created successfully {self.visuals.RESET}\033[J\n\033[J")
|
|
451
|
+
else:
|
|
452
|
+
print(f"{self.visuals.bold}{self.visuals.RD} > Error creating zip file:\033[J")
|
|
453
|
+
print(f"{self.ultimate_error}{self.visuals.RESET}")
|
|
454
|
+
sys.exit(1)
|
|
222
455
|
|
|
223
456
|
def main(self):
|
|
224
457
|
script = self.cli.exec_gen
|
|
@@ -234,6 +467,7 @@ class cli:
|
|
|
234
467
|
self.descerror = ""
|
|
235
468
|
|
|
236
469
|
self.imports = None
|
|
470
|
+
self.error_libs = []
|
|
237
471
|
|
|
238
472
|
def hsl_to_rgb(self, h, s, l):
|
|
239
473
|
h = h % 360
|
|
@@ -269,19 +503,22 @@ class cli:
|
|
|
269
503
|
hue = (hue + 1) % 360
|
|
270
504
|
time.sleep(delay)
|
|
271
505
|
|
|
506
|
+
def verify_imports(self):
|
|
507
|
+
if self.error_libs:
|
|
508
|
+
print(f"{self.visuals.bold}{self.visuals.YL} WARNING: \n The libraries below can't be installed. This is not necessarily an error, just an alert.{self.visuals.RESET}")
|
|
509
|
+
for lib in self.error_libs:
|
|
510
|
+
print(f" {self.visuals.bold}{self.visuals.YL} - {lib} {self.visuals.RESET}")
|
|
511
|
+
|
|
272
512
|
def main(self, return_=False):
|
|
273
|
-
|
|
274
|
-
parser.add_argument("file", type=str, help="The target .py file to process")
|
|
513
|
+
self.target_file = self.cli.file
|
|
275
514
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
self.target_file = self.cli.file #FIX
|
|
515
|
+
if not self.target_file:
|
|
516
|
+
print(f"{self.visuals.bold}{self.visuals.RD} > Error: Please pass your 'target_file' to detect the libraries.{self.visuals.RESET}")
|
|
517
|
+
sys.exit(1)
|
|
280
518
|
|
|
281
519
|
if not os.path.exists(self.target_file):
|
|
282
|
-
self.
|
|
283
|
-
|
|
284
|
-
return
|
|
520
|
+
print(f"{self.visuals.bold}{self.visuals.RD} > Error: Your 'target_file' does not exist or can't be accessed.{self.visuals.RESET}")
|
|
521
|
+
sys.exit(1)
|
|
285
522
|
|
|
286
523
|
try:
|
|
287
524
|
with open(self.target_file, "r", encoding="utf-8", errors="replace") as file:
|
|
@@ -294,25 +531,38 @@ class cli:
|
|
|
294
531
|
print(f"Erro: Não foi possível ler o arquivo '{self.target_file}' com nenhuma codificação testada.")
|
|
295
532
|
return
|
|
296
533
|
|
|
297
|
-
self.imports = []
|
|
534
|
+
self.imports = ["bcpkgfox"]
|
|
298
535
|
import_data = {
|
|
299
536
|
"extract_pdf": "PyMuPDF",
|
|
300
537
|
"import requests": "requests",
|
|
301
538
|
"import pyautogui": "pyautogui",
|
|
302
539
|
"import cv2": "opencv-python",
|
|
540
|
+
"fitz": "PyMuPDF",
|
|
303
541
|
"from PIL": "Pillow",
|
|
304
542
|
"from reportlab.lib import utils": "reportlab",
|
|
305
543
|
"from PyPDF2 import PdfMerger": "PyPDF2",
|
|
544
|
+
"PdfWriter": "pypdf",
|
|
306
545
|
"import PyPDF2": "PyPDF2",
|
|
307
546
|
"invoke_api_": "requests",
|
|
547
|
+
"login_2fac": "pyautogui",
|
|
308
548
|
"wait_for": "pygetwindow",
|
|
309
549
|
"from selenium_stealth import stealth": "selenium-stealth",
|
|
550
|
+
"capmonstercloudclient": "bcpkgfox[capmonstercloudclient]",
|
|
551
|
+
"capmonstercloud_client": "bcpkgfox[capmonstercloudclient]",
|
|
310
552
|
"import undetected_chromedriver": "undetected-chromedriver",
|
|
311
|
-
"
|
|
553
|
+
"webdriver_manager": "webdriver-manager",
|
|
312
554
|
"move_to_image": ["pyscreeze", "pyautogui", "Pillow", "opencv-python"],
|
|
313
555
|
"move_mouse_smoothly": ["pyscreeze", "pyautogui", "Pillow"],
|
|
314
556
|
"initialize_driver": ["webdriver-manager", "undetected-chromedriver", "pyautogui", "psutil"],
|
|
315
|
-
"stealth max": ["webdriver-manager", "undetected-chromedriver",
|
|
557
|
+
"stealth max": ["webdriver-manager", "undetected-chromedriver"],
|
|
558
|
+
"bs4": "beautifulsoup4", "beautifulsoup":"beautifulsoup4",
|
|
559
|
+
"psutil": "bcpkgfox[psutil]",
|
|
560
|
+
"screeninfo": "bcpkgfox[screeninfo]", "get_monitors": "bcpkgfox[screeninfo]",
|
|
561
|
+
"pynput": "bcpkgfox[pynput]", "pynput.mouse": "bcpkgfox[pynput]",
|
|
562
|
+
"pynput.keyboard": "bcpkgfox[pynput]",
|
|
563
|
+
"pywinauto": "bcpkgfox[pywinauto]",
|
|
564
|
+
"pdfplumber": "pdfplumber",
|
|
565
|
+
"twocaptcha": "bcpkgfox[twocaptcha]", "TwoCaptcha": "bcpkgfox[twocaptcha]",
|
|
316
566
|
}
|
|
317
567
|
|
|
318
568
|
for name, import_name in import_data.items():
|
|
@@ -321,6 +571,14 @@ class cli:
|
|
|
321
571
|
self.imports.extend(import_name)
|
|
322
572
|
else: self.imports.append(import_name)
|
|
323
573
|
|
|
574
|
+
IMPORT_PATTERN = re.compile(r'^(?:from|import)\s+([A-Za-z0-9_\.]+)', re.MULTILINE)
|
|
575
|
+
|
|
576
|
+
# Encontra outras libs por regex
|
|
577
|
+
for match in IMPORT_PATTERN.finditer(file_content):
|
|
578
|
+
módulo = match.group(1).split('.')[0] # pega o pacote raiz
|
|
579
|
+
if módulo not in self.imports:
|
|
580
|
+
self.imports.append(módulo)
|
|
581
|
+
|
|
324
582
|
self.imports = list(set(self.imports))
|
|
325
583
|
import pyperclip
|
|
326
584
|
|
|
@@ -339,8 +597,6 @@ class cli:
|
|
|
339
597
|
else: return self.imports
|
|
340
598
|
else: print("No libraries from the list were found in the script.")
|
|
341
599
|
|
|
342
|
-
|
|
343
|
-
|
|
344
600
|
class venv_mangt:
|
|
345
601
|
def __init__(self, self_cli):
|
|
346
602
|
self.cli = self_cli
|
|
@@ -380,24 +636,31 @@ class cli:
|
|
|
380
636
|
if s % 10 == 0: n += 1
|
|
381
637
|
if n == len(braille_spinner): n = 0
|
|
382
638
|
|
|
383
|
-
sys.stdout.write(f"\r \033[F\r\033[K\033[E {self.visuals.animate_rgb_text(f" {self.visuals.bold} {braille_spinner[n]} Deleting virtual environment {braille_spinner[n]} {self.visuals.RESET}")} \n\033[F")
|
|
639
|
+
sys.stdout.write(f"\r \033[F\r\033[K\033[E {self.visuals.animate_rgb_text(f" {self.visuals.bold} {braille_spinner[n]} Deleting virtual environment {braille_spinner[n]} {self.visuals.RESET}")} \033[0J\n\033[F")
|
|
384
640
|
sys.stdout.flush()
|
|
385
641
|
s += 1
|
|
386
642
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
print(f"{self.visuals.bold}{self.visuals.GR} > Oldest virtual environment deleted with sucessfuly {self.visuals.RESET}\n")
|
|
643
|
+
try:
|
|
644
|
+
footer_thread = threading.Thread(target=print_footer)
|
|
645
|
+
footer_thread.start()
|
|
646
|
+
|
|
647
|
+
if os.path.exists(os.path.join(self.current_dir, ".venv")):
|
|
648
|
+
try:
|
|
649
|
+
shutil.rmtree(".venv")
|
|
650
|
+
except Exception as e:
|
|
651
|
+
print(f"{self.visuals.RD} > Failed to remove venv: {e} {self.visuals.RESET}")
|
|
652
|
+
return False
|
|
653
|
+
process_finished = True
|
|
654
|
+
footer_thread.join()
|
|
400
655
|
|
|
656
|
+
print(f"{self.visuals.bold}{self.visuals.GR} > Oldest virtual environment deleted with sucessfuly {self.visuals.RESET}\n")
|
|
657
|
+
except Exception as e:
|
|
658
|
+
process_finished = True
|
|
659
|
+
self.descerror = e
|
|
660
|
+
self.error = 1
|
|
661
|
+
sys.exit()
|
|
662
|
+
raise SystemExit()
|
|
663
|
+
finally: process_finished = True
|
|
401
664
|
|
|
402
665
|
def create_venv(self):
|
|
403
666
|
|
|
@@ -429,34 +692,40 @@ class cli:
|
|
|
429
692
|
if s % 10 == 0: n += 1
|
|
430
693
|
if n == len(braille_spinner): n = 0
|
|
431
694
|
|
|
432
|
-
sys.stdout.write(f"\r \033[F\r\033[K\033[E {self.visuals.animate_rgb_text(f" {self.visuals.bold} {braille_spinner[n]} Generating virtual environment {braille_spinner[n]} {self.visuals.RESET}")} \n\033[F")
|
|
695
|
+
sys.stdout.write(f"\r \033[F\r\033[K\033[E {self.visuals.animate_rgb_text(f" {self.visuals.bold} {braille_spinner[n]} Generating virtual environment {braille_spinner[n]} {self.visuals.RESET}")} \033[0J\n\033[F")
|
|
433
696
|
sys.stdout.flush()
|
|
434
697
|
s += 1
|
|
435
698
|
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
699
|
+
try:
|
|
700
|
+
process_finished = False
|
|
701
|
+
command = [sys.executable, '-m', 'venv', ".venv"]
|
|
702
|
+
process = subprocess.Popen(
|
|
703
|
+
command,
|
|
704
|
+
stdout=subprocess.PIPE,
|
|
705
|
+
stderr=subprocess.STDOUT,
|
|
706
|
+
universal_newlines=True,
|
|
707
|
+
bufsize=1
|
|
708
|
+
)
|
|
709
|
+
footer_thread = threading.Thread(target=print_footer)
|
|
710
|
+
footer_thread.start()
|
|
711
|
+
|
|
712
|
+
while True:
|
|
713
|
+
output = process.stdout.readline()
|
|
714
|
+
if output == '' and process.poll() is not None:
|
|
715
|
+
break
|
|
716
|
+
if output:
|
|
717
|
+
sys.stdout.write(f"\033[F\r\033[K{output.strip()}\033[K\n\n")
|
|
718
|
+
sys.stdout.flush()
|
|
455
719
|
|
|
456
|
-
|
|
457
|
-
|
|
720
|
+
process_finished = True
|
|
721
|
+
footer_thread.join()
|
|
458
722
|
|
|
459
|
-
|
|
723
|
+
print(f"{self.visuals.bold}{self.visuals.GR} > Virtual environment created successfully {self.visuals.RESET}\n")
|
|
724
|
+
except Exception as e:
|
|
725
|
+
process_finished = True
|
|
726
|
+
self.descerror = e
|
|
727
|
+
self.error = 1
|
|
728
|
+
finally: process_finished = True
|
|
460
729
|
|
|
461
730
|
def install_imports(self):
|
|
462
731
|
pip_path = os.path.join(".venv", 'Scripts' if os.name == 'nt' else 'bin', 'pip')
|
|
@@ -490,47 +759,105 @@ class cli:
|
|
|
490
759
|
if s % 10 == 0: n += 1
|
|
491
760
|
if n == len(braille_spinner): n = 0
|
|
492
761
|
|
|
493
|
-
sys.stdout.write(f"\r \033[F\r\033[K\033[E {self.visuals.animate_rgb_text(f" {self.visuals.bold} {braille_spinner[n]} Installing all dependencies {braille_spinner[n]} {self.visuals.RESET}")} \n\033[F")
|
|
762
|
+
sys.stdout.write(f"\r \033[F\r\033[K\033[E {self.visuals.animate_rgb_text(f" {self.visuals.bold} {braille_spinner[n]} Installing all dependencies {braille_spinner[n]} {self.visuals.RESET}")} \033[0J\n\033[F")
|
|
494
763
|
sys.stdout.flush()
|
|
495
764
|
s += 1
|
|
496
765
|
|
|
497
|
-
log_animation = threading.Thread(target=print_footer)
|
|
498
|
-
log_animation.start()
|
|
499
|
-
|
|
500
|
-
process_finished = False
|
|
501
766
|
try:
|
|
767
|
+
log_animation = threading.Thread(target=print_footer)
|
|
768
|
+
log_animation.start()
|
|
769
|
+
|
|
770
|
+
process_finished = False
|
|
502
771
|
for lib in librarys:
|
|
503
772
|
result = subprocess.run(
|
|
504
773
|
[pip_path, 'install', lib],
|
|
505
|
-
check=True,
|
|
774
|
+
# check=True,
|
|
506
775
|
stdout=subprocess.PIPE,
|
|
507
776
|
stderr=subprocess.PIPE,
|
|
508
777
|
text=True
|
|
509
778
|
)
|
|
510
779
|
|
|
780
|
+
if result.returncode != 0:
|
|
781
|
+
if isinstance(lib, list):
|
|
782
|
+
self.cli.find_imports.error_libs.extend(lib)
|
|
783
|
+
else: self.cli.find_imports.error_libs.append(lib)
|
|
784
|
+
continue
|
|
785
|
+
|
|
511
786
|
|
|
512
|
-
|
|
787
|
+
elif result.stdout:
|
|
513
788
|
print(f"\033[0J{result.stdout.strip()}\033[0J")
|
|
514
789
|
|
|
515
|
-
except subprocess.CalledProcessError as e:
|
|
516
|
-
print(f"{self.visuals.bold}{self.visuals.RD} Failed to install {lib}: {e.stderr.strip()}{self.visuals.RESET}", end="\r")
|
|
517
|
-
return False
|
|
518
|
-
finally:
|
|
519
790
|
process_finished = True
|
|
520
791
|
log_animation.join()
|
|
521
|
-
|
|
792
|
+
print(f" {self.visuals.bold}{self.visuals.GR} > All packages installed successfully {self.visuals.RESET}\n\n")
|
|
793
|
+
|
|
794
|
+
except Exception as e:
|
|
795
|
+
process_finished = True
|
|
796
|
+
self.descerror = e
|
|
797
|
+
self.error = 1
|
|
798
|
+
print(e)
|
|
799
|
+
sys.exit()
|
|
522
800
|
|
|
523
801
|
def recreate_venv(self):
|
|
524
802
|
self.delete_venv()
|
|
525
803
|
self.create_venv()
|
|
526
804
|
|
|
805
|
+
class custom_action_requirements(argparse.Action):
|
|
806
|
+
''' This is necessary to define a new action and the parser identifies it as valid '''
|
|
807
|
+
|
|
808
|
+
def __call__(self, parser, namespace, values, option_string=None):
|
|
809
|
+
if values is None:
|
|
810
|
+
setattr(namespace, self.dest, 'requirements.txt')
|
|
811
|
+
else:
|
|
812
|
+
setattr(namespace, self.dest, values)
|
|
813
|
+
|
|
814
|
+
def requirements(self):
|
|
815
|
+
|
|
816
|
+
# # Identifies endwish
|
|
817
|
+
# if '.' in self.cli.args.requirements:
|
|
818
|
+
# name = self.cli.args.requirements
|
|
819
|
+
# else:
|
|
820
|
+
# name = self.cli.args.requirements + '.txt'
|
|
821
|
+
|
|
822
|
+
# FIX: name is always 'requirements.txt'
|
|
823
|
+
name = 'requirements.txt'
|
|
824
|
+
|
|
825
|
+
# Attempt of recreate
|
|
826
|
+
try:
|
|
827
|
+
os.remove(os.path.join(self.current_dir, name))
|
|
828
|
+
except:
|
|
829
|
+
pass
|
|
830
|
+
|
|
831
|
+
# Creates a new one
|
|
832
|
+
subprocess.run(f"pip freeze > {name}", shell=True)
|
|
833
|
+
|
|
834
|
+
# Read
|
|
835
|
+
with open(f'{name}', 'r') as f:
|
|
836
|
+
lines = f.readlines()
|
|
837
|
+
|
|
838
|
+
# Re-write
|
|
839
|
+
add_list = []
|
|
840
|
+
imports = self.cli.find_imports.main(return_=True)
|
|
841
|
+
imports_lower = {imp.lower() for imp in imports}
|
|
842
|
+
with open(f'{name}', 'w') as f:
|
|
843
|
+
|
|
844
|
+
for line in lines:
|
|
845
|
+
|
|
846
|
+
# Formats
|
|
847
|
+
if '\n' in line:
|
|
848
|
+
line_for_print = line.replace('\n', '').strip()
|
|
849
|
+
|
|
850
|
+
# Compares
|
|
851
|
+
pkg = line.split('==')[0].strip().lower()
|
|
852
|
+
if pkg in imports_lower:
|
|
853
|
+
f.write(line)
|
|
854
|
+
add_list.append(line_for_print)
|
|
855
|
+
|
|
856
|
+
print(f"\n{self.visuals.bold}{self.visuals.GR} > Requirements created with sucessfuly {self.visuals.RESET}\n")
|
|
857
|
+
print(f"{self.visuals.bold}{self.visuals.YL} Libraries installed: {self.visuals.RESET}{self.visuals.YL}" + "".join(f"\n {lib}" for lib in add_list) + f"{self.visuals.RESET}")
|
|
527
858
|
|
|
528
859
|
def main(self):
|
|
529
|
-
self.delete_venv()
|
|
860
|
+
try: self.delete_venv()
|
|
861
|
+
except: pass
|
|
530
862
|
self.create_venv()
|
|
531
|
-
self.install_imports()
|
|
532
|
-
|
|
533
|
-
code = cli("bcpkgfox//cli.py")
|
|
534
|
-
code.exec_gen.main()
|
|
535
|
-
code.clean_terminal()
|
|
536
|
-
print()
|
|
863
|
+
self.install_imports()
|