abstract-ide 0.0.0.1__tar.gz
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.
- abstract_ide-0.0.0.1/PKG-INFO +36 -0
- abstract_ide-0.0.0.1/README.md +2 -0
- abstract_ide-0.0.0.1/pyproject.toml +3 -0
- abstract_ide-0.0.0.1/setup.cfg +4 -0
- abstract_ide-0.0.0.1/setup.py +39 -0
- abstract_ide-0.0.0.1/src/abstract_ide/__init__.py +1 -0
- abstract_ide-0.0.0.1/src/abstract_ide/imports/__init__.py +1 -0
- abstract_ide-0.0.0.1/src/abstract_ide/imports/imports.py +0 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/__init__.py +13 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/imports/__init__.py +1 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/imports/imports/__init__.py +2 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/imports/imports/constants.py +31 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/imports/imports/imports.py +18 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/imports/utils/__init__.py +2 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/imports/utils/file_utils.py +31 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/imports/utils/utils.py +184 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/managers/__init__.py +1 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/managers/imports/__init__.py +2 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/managers/imports/imports.py +1 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/managers/imports/widget_funcs.py +38 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/managers/utils/__init__.py +3 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/managers/utils/get_modules.py +436 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/managers/utils/importGraphWorker.py +29 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/managers/utils/imports.py +1 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/managers/utils/mainWindow/__init__.py +1 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/managers/utils/mainWindow/functions/__init__.py +2 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/managers/utils/mainWindow/functions/clickHandlers/__init__.py +1 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/managers/utils/mainWindow/functions/clickHandlers/clickHandlers.py +44 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/managers/utils/mainWindow/functions/clickHandlers/imports.py +1 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/managers/utils/mainWindow/functions/imports.py +1 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/managers/utils/mainWindow/functions/init_tabs/__init__.py +9 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/managers/utils/mainWindow/functions/init_tabs/apigui.py +270 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/managers/utils/mainWindow/functions/init_tabs/finder/__init__.py +1 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/managers/utils/mainWindow/functions/init_tabs/finder/clickfinder.py +266 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/managers/utils/mainWindow/functions/init_tabs/finder/finder.py +698 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/managers/utils/mainWindow/functions/init_tabs/finder/finder_back.py +266 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/managers/utils/mainWindow/functions/init_tabs/functions_page/__init__.py +1 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/managers/utils/mainWindow/functions/init_tabs/functions_page/functions_page.py +70 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/managers/utils/mainWindow/functions/init_tabs/imports.py +1 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/managers/utils/mainWindow/functions/init_tabs/initialize_init/__init__.py +1 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/managers/utils/mainWindow/functions/init_tabs/initialize_init/initialize_init.py +40 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/managers/utils/mainWindow/functions/init_tabs/runner/__init__.py +1 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/managers/utils/mainWindow/functions/init_tabs/runner/runner.py +59 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/managers/utils/mainWindow/imports.py +4 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/managers/utils/mainWindow/mainWindow.py +394 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/managers/utils/worker.py +70 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/widgets/__init__.py +1 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/widgets/imports/__init__.py +1 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/widgets/imports/imports.py +1 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/widgets/utils/__init__.py +1 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/widgets/utils/kwargs_utils.py +103 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/widgets/utils/utils.py +22 -0
- abstract_ide-0.0.0.1/src/abstract_ide/utils/widgets/utils/widgets.py +42 -0
- abstract_ide-0.0.0.1/src/abstract_ide.egg-info/PKG-INFO +36 -0
- abstract_ide-0.0.0.1/src/abstract_ide.egg-info/SOURCES.txt +57 -0
- abstract_ide-0.0.0.1/src/abstract_ide.egg-info/dependency_links.txt +1 -0
- abstract_ide-0.0.0.1/src/abstract_ide.egg-info/requires.txt +10 -0
- abstract_ide-0.0.0.1/src/abstract_ide.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: abstract_ide
|
|
3
|
+
Version: 0.0.0.1
|
|
4
|
+
Summary: abstract_ide
|
|
5
|
+
Home-page: https://github.com/AbstractEndeavors/abstract_ide
|
|
6
|
+
Author: putkoff
|
|
7
|
+
Author-email: partners@abstractendeavors.com
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Requires-Python: >=3.6
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
Requires-Dist: abstract_apis
|
|
16
|
+
Requires-Dist: PyQt5
|
|
17
|
+
Requires-Dist: abstract_webtools
|
|
18
|
+
Requires-Dist: abstract_utilities
|
|
19
|
+
Requires-Dist: abstract_gui
|
|
20
|
+
Requires-Dist: pydot
|
|
21
|
+
Requires-Dist: abstract_clipit
|
|
22
|
+
Requires-Dist: flask
|
|
23
|
+
Requires-Dist: abstract_paths
|
|
24
|
+
Requires-Dist: PyQt6
|
|
25
|
+
Dynamic: author
|
|
26
|
+
Dynamic: author-email
|
|
27
|
+
Dynamic: classifier
|
|
28
|
+
Dynamic: description
|
|
29
|
+
Dynamic: description-content-type
|
|
30
|
+
Dynamic: home-page
|
|
31
|
+
Dynamic: requires-dist
|
|
32
|
+
Dynamic: requires-python
|
|
33
|
+
Dynamic: summary
|
|
34
|
+
|
|
35
|
+
# abstract_ide
|
|
36
|
+
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from time import time
|
|
2
|
+
import setuptools
|
|
3
|
+
with open("README.md", "r", encoding="utf-8") as fh:
|
|
4
|
+
long_description = fh.read()
|
|
5
|
+
setuptools.setup(
|
|
6
|
+
name='abstract_ide',
|
|
7
|
+
version='0.0.0.001',
|
|
8
|
+
author='putkoff',
|
|
9
|
+
author_email='partners@abstractendeavors.com',
|
|
10
|
+
description='abstract_ide',
|
|
11
|
+
long_description=long_description,
|
|
12
|
+
long_description_content_type='text/markdown',
|
|
13
|
+
url='https://github.com/AbstractEndeavors/abstract_ide',
|
|
14
|
+
classifiers=[
|
|
15
|
+
'Development Status :: 3 - Alpha',
|
|
16
|
+
'Intended Audience :: Developers',
|
|
17
|
+
'License :: OSI Approved :: MIT License',
|
|
18
|
+
'Programming Language :: Python :: 3',
|
|
19
|
+
'Programming Language :: Python :: 3.11',
|
|
20
|
+
],
|
|
21
|
+
install_requires=[
|
|
22
|
+
'abstract_apis',
|
|
23
|
+
'PyQt5',
|
|
24
|
+
'abstract_webtools',
|
|
25
|
+
'abstract_utilities',
|
|
26
|
+
'abstract_gui',
|
|
27
|
+
'pydot',
|
|
28
|
+
'abstract_clipit',
|
|
29
|
+
'flask',
|
|
30
|
+
'abstract_paths',
|
|
31
|
+
'PyQt6'
|
|
32
|
+
]
|
|
33
|
+
,
|
|
34
|
+
package_dir={"": "src"},
|
|
35
|
+
packages=setuptools.find_packages(where="src"),
|
|
36
|
+
python_requires=">=3.6",
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .utils import *
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .imports import *
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .utils import *
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import re
|
|
2
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
3
|
+
# Command with markers (no log files on disk needed)
|
|
4
|
+
COMMAND = r"""
|
|
5
|
+
set -e
|
|
6
|
+
echo "__TSC_BEGIN__"
|
|
7
|
+
npx tsc --noEmit || true
|
|
8
|
+
echo "__TSC_END__"
|
|
9
|
+
echo "__BUILD_BEGIN__"
|
|
10
|
+
CI=true yarn build || true
|
|
11
|
+
echo "__BUILD_END__"
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
ANSI_RE = re.compile(r'\x1b\[[0-9;]*m')
|
|
15
|
+
FILE_REGEX = re.compile(r'([^\s:()]+\.(?:ts|tsx|js|jsx))\((\d+),(\d+)\)')
|
|
16
|
+
FILE_FILE_REGEX = re.compile(
|
|
17
|
+
r'(?P<file>[^\s:()]+\.(?:ts|tsx|js|jsx))'
|
|
18
|
+
r'(?:\((?P<l1>\d+),(?P<c1>\d+)\)|:(?P<l2>\d+):(?P<c2>\d+))'
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
GREP_REGEX = r"import\s+[^;]*\buse[^;]*from\s+['\"]react['\"]"
|
|
22
|
+
SEV_ERR = re.compile(r'(^|\b)(ERROR|error)\b|error TS\d+', re.IGNORECASE)
|
|
23
|
+
SEV_WRN = re.compile(r'(^|\b)(WARNING|warning)\b|warning TS\d+', re.IGNORECASE)
|
|
24
|
+
|
|
25
|
+
# Prefer targets left→right when hunting alternates
|
|
26
|
+
EXT_SWAP = {
|
|
27
|
+
".ts": [".tsx"],
|
|
28
|
+
".tsx": [".ts"],
|
|
29
|
+
".js": [".jsx"],
|
|
30
|
+
".jsx": [".js"],
|
|
31
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
import os,re,subprocess,sys,re,traceback,pydot
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from PyQt5.QtCore import (
|
|
5
|
+
QThread, pyqtSignal,
|
|
6
|
+
Qt
|
|
7
|
+
)
|
|
8
|
+
from PyQt5.QtGui import QTextCursor
|
|
9
|
+
from PyQt5.QtWidgets import (
|
|
10
|
+
QApplication, QVBoxLayout, QHBoxLayout,
|
|
11
|
+
QLabel, QLineEdit, QPushButton, QTextEdit,
|
|
12
|
+
QListWidgetItem, QMessageBox, QRadioButton,
|
|
13
|
+
QButtonGroup, QCheckBox,QWidget,QTabWidget,
|
|
14
|
+
QScrollArea, QGroupBox, QComboBox, QLayout,
|
|
15
|
+
QWidget, QVBoxLayout, QLabel, QListWidget
|
|
16
|
+
)
|
|
17
|
+
from abstract_utilities import make_list,safe_read_from_json,read_from_file,make_dirs
|
|
18
|
+
from abstract_paths import invert_to_function_map,start_analyzer
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from ..imports import start_analyzer,pydot,os,safe_read_from_json,make_dirs
|
|
2
|
+
BASE_DIRECTORY = '/var/www/html/clownworld/bolshevid'
|
|
3
|
+
DATA_DIR = make_dirs(BASE_DIRECTORY,"data")
|
|
4
|
+
IMPORT_MAP_DIR = make_dirs(DATA_DIR,"import_tools")
|
|
5
|
+
|
|
6
|
+
def get_dot_path():
|
|
7
|
+
return os.path.join(IMPORT_MAP_DIR,'graph.dot')
|
|
8
|
+
def get_import_graph_path():
|
|
9
|
+
return os.path.join(IMPORT_MAP_DIR,'import-graph.json')
|
|
10
|
+
def read_from_dot_file(path = None):
|
|
11
|
+
path = get_dot_path()
|
|
12
|
+
graphs, = pydot.graph_from_dot_file(path)
|
|
13
|
+
return graphs
|
|
14
|
+
def get_dot_data():
|
|
15
|
+
dot_path = get_dot_path()
|
|
16
|
+
ensure_import_creation(dot_path)
|
|
17
|
+
return read_from_dot_file()
|
|
18
|
+
def get_import_graph_data():
|
|
19
|
+
graph_path = get_import_graph_path()
|
|
20
|
+
ensure_import_creation(graph_path)
|
|
21
|
+
return safe_read_from_json(graph_path)
|
|
22
|
+
def ensure_import_creation(path):
|
|
23
|
+
if not os.path.isfile(path):
|
|
24
|
+
create_import_maps()
|
|
25
|
+
def create_import_maps():
|
|
26
|
+
root = BASE_DIRECTORY
|
|
27
|
+
directory = os.getcwd()
|
|
28
|
+
entries = 'index,main'
|
|
29
|
+
out = get_import_graph_path()
|
|
30
|
+
dot = get_dot_path()
|
|
31
|
+
start_analyzer(root=root,entries=entries,out=out,dot=dot)
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
from ..imports import *
|
|
2
|
+
def read_from_dot_file(path):
|
|
3
|
+
graphs, = pydot.graph_from_dot_file(path)
|
|
4
|
+
return graphs
|
|
5
|
+
|
|
6
|
+
def sh_quote(s: str) -> str:
|
|
7
|
+
return "'" + (s or "").replace("'", "'\\''") + "'"
|
|
8
|
+
|
|
9
|
+
def strip_ansi(text: str) -> str:
|
|
10
|
+
return ANSI_RE.sub('', text or "")
|
|
11
|
+
|
|
12
|
+
def get_trailing_number(file_path):
|
|
13
|
+
return_js = {"chars":'',"file_path":file_path}
|
|
14
|
+
for i in range(1,len(file_path)+1):
|
|
15
|
+
char = file_path[-i]
|
|
16
|
+
if is_number(char) or char == ':':
|
|
17
|
+
return_js["chars"] = str(char)+ str(chars)
|
|
18
|
+
else:
|
|
19
|
+
file_path = file_path[:-i]
|
|
20
|
+
return return_js
|
|
21
|
+
|
|
22
|
+
def resolve_alt_ext(path: str, project_root: str) -> str:
|
|
23
|
+
"""
|
|
24
|
+
If 'path' doesn't exist, try sibling files with alternate extensions
|
|
25
|
+
(ts<->tsx, js<->jsx). Also tries case-insensitive match and glob
|
|
26
|
+
for same basename with any extension in the same folder.
|
|
27
|
+
Returns the best existing path, or the original if none found.
|
|
28
|
+
"""
|
|
29
|
+
if not path:
|
|
30
|
+
return path
|
|
31
|
+
if os.path.exists(path):
|
|
32
|
+
return path
|
|
33
|
+
|
|
34
|
+
folder, base = os.path.dirname(path), os.path.basename(path)
|
|
35
|
+
stem, ext = os.path.splitext(base)
|
|
36
|
+
|
|
37
|
+
# 1) explicit swap candidates
|
|
38
|
+
for alt in EXT_SWAP.get(ext, []):
|
|
39
|
+
cand = os.path.join(folder, stem + alt)
|
|
40
|
+
if os.path.exists(cand):
|
|
41
|
+
return cand
|
|
42
|
+
|
|
43
|
+
# 2) case-insensitive lookup (useful on case-sensitive FS when log had case mismatch)
|
|
44
|
+
try:
|
|
45
|
+
for name in os.listdir(folder or "."):
|
|
46
|
+
if name.lower() == (stem + ext).lower():
|
|
47
|
+
cand = os.path.join(folder, name)
|
|
48
|
+
if os.path.exists(cand):
|
|
49
|
+
return cand
|
|
50
|
+
except Exception:
|
|
51
|
+
pass
|
|
52
|
+
|
|
53
|
+
# 3) any sibling with same stem (e.g., foo.*)
|
|
54
|
+
try:
|
|
55
|
+
for name in os.listdir(folder or "."):
|
|
56
|
+
nstem, next_ = os.path.splitext(name)
|
|
57
|
+
if nstem == stem and os.path.isfile(os.path.join(folder, name)):
|
|
58
|
+
# prefer our known alternates order
|
|
59
|
+
if next_ in sum(EXT_SWAP.values(), []):
|
|
60
|
+
return os.path.join(folder, name)
|
|
61
|
+
# fallback: first file with same stem
|
|
62
|
+
for name in os.listdir(folder or "."):
|
|
63
|
+
nstem, _ = os.path.splitext(name)
|
|
64
|
+
if nstem == stem:
|
|
65
|
+
return os.path.join(folder, name)
|
|
66
|
+
except Exception:
|
|
67
|
+
pass
|
|
68
|
+
|
|
69
|
+
return path
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
#split funcs
|
|
74
|
+
def split_sections(raw: str):
|
|
75
|
+
"""Return (tsc_text, build_text) from the full captured output."""
|
|
76
|
+
raw = strip_ansi(raw)
|
|
77
|
+
tsc = ""
|
|
78
|
+
build = ""
|
|
79
|
+
try:
|
|
80
|
+
tsc = raw.split("__TSC_BEGIN__", 1)[1].split("__TSC_END__", 1)[0]
|
|
81
|
+
except Exception:
|
|
82
|
+
pass
|
|
83
|
+
try:
|
|
84
|
+
build = raw.split("__BUILD_BEGIN__", 1)[1].split("__BUILD_END__", 1)[0]
|
|
85
|
+
except Exception:
|
|
86
|
+
pass
|
|
87
|
+
return tsc.strip(), build.strip()
|
|
88
|
+
|
|
89
|
+
def split_by_severity(text: str):
|
|
90
|
+
"""Return (errors_text, warnings_text) based on simple, robust heuristics."""
|
|
91
|
+
errs, warns = [], []
|
|
92
|
+
for ln in (text or "").splitlines():
|
|
93
|
+
# webpack/CRA often prints 'WARNING in ...' / 'ERROR in ...'
|
|
94
|
+
if ln.startswith('WARNING in '):
|
|
95
|
+
warns.append(ln)
|
|
96
|
+
continue
|
|
97
|
+
if ln.startswith('ERROR in '):
|
|
98
|
+
errs.append(ln)
|
|
99
|
+
continue
|
|
100
|
+
|
|
101
|
+
lnl = ln.lower()
|
|
102
|
+
if 'error' in lnl:
|
|
103
|
+
errs.append(ln)
|
|
104
|
+
elif 'warning' in lnl:
|
|
105
|
+
warns.append(ln)
|
|
106
|
+
return "\n".join(errs), "\n".join(warns)
|
|
107
|
+
|
|
108
|
+
#entries
|
|
109
|
+
def get_error_entries(log_text: str, project_path: str):
|
|
110
|
+
"""Find file(line,col) triplets."""
|
|
111
|
+
entries = []
|
|
112
|
+
if not log_text:
|
|
113
|
+
return entries
|
|
114
|
+
for match in FILE_REGEX.finditer(log_text):
|
|
115
|
+
rel, line, col = match.groups()
|
|
116
|
+
full = rel if os.path.isabs(rel) else os.path.normpath(os.path.join(project_path, rel))
|
|
117
|
+
try:
|
|
118
|
+
entries.append((full, int(line), int(col)))
|
|
119
|
+
except Exception:
|
|
120
|
+
continue
|
|
121
|
+
return entries
|
|
122
|
+
|
|
123
|
+
def get_file_error_entries(log_text: str, project_path: str):
|
|
124
|
+
entries = []
|
|
125
|
+
if not log_text:
|
|
126
|
+
return entries
|
|
127
|
+
for m in FILE_FILE_REGEX.finditer(log_text):
|
|
128
|
+
rel = m.group('file')
|
|
129
|
+
line = m.group('l1') or m.group('l2')
|
|
130
|
+
col = m.group('c1') or m.group('c2')
|
|
131
|
+
full = rel if os.path.isabs(rel) else os.path.normpath(os.path.join(project_path, rel))
|
|
132
|
+
try:
|
|
133
|
+
entries.append((full, int(line), int(col)))
|
|
134
|
+
except Exception:
|
|
135
|
+
continue
|
|
136
|
+
return entries
|
|
137
|
+
|
|
138
|
+
def get_entries_for(text: str, project_path: str):
|
|
139
|
+
"""Use file(line,col) extractor on a subset."""
|
|
140
|
+
return get_error_entries(text, project_path)
|
|
141
|
+
|
|
142
|
+
#imports
|
|
143
|
+
def grep_use_imports(project_path: str):
|
|
144
|
+
"""Fallback: grep for suspect 'use' imports in src. Returns list[(path,line,1)]."""
|
|
145
|
+
results = []
|
|
146
|
+
try:
|
|
147
|
+
proc = subprocess.run(
|
|
148
|
+
["grep", "-RnE", GREP_REGEX, "src"],
|
|
149
|
+
cwd=project_path,
|
|
150
|
+
capture_output=True, text=True
|
|
151
|
+
)
|
|
152
|
+
for ln in proc.stdout.splitlines():
|
|
153
|
+
try:
|
|
154
|
+
file, lineno, _ = ln.split(':', 2)
|
|
155
|
+
results.append((os.path.join(project_path, file), int(lineno), 1))
|
|
156
|
+
except Exception:
|
|
157
|
+
continue
|
|
158
|
+
except Exception:
|
|
159
|
+
pass
|
|
160
|
+
return results
|
|
161
|
+
|
|
162
|
+
#cmd utils
|
|
163
|
+
def run_ssh_cmd(user_at_host: str, cmd: str, path: str) -> str:
|
|
164
|
+
"""Run on remote via SSH and return stdout+stderr."""
|
|
165
|
+
try:
|
|
166
|
+
full = f"ssh {user_at_host} 'cd {path} && bash -lc {sh_quote(cmd)}'"
|
|
167
|
+
proc = subprocess.run(full, shell=True, capture_output=True, text=True)
|
|
168
|
+
return (proc.stdout or "") + (proc.stderr or "")
|
|
169
|
+
except Exception as e:
|
|
170
|
+
return f"❌ run_ssh_cmd error: {e}\n"
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def run_local_cmd(cmd: str, path: str) -> str:
|
|
174
|
+
"""Run locally in cwd=path and return stdout+stderr."""
|
|
175
|
+
try:
|
|
176
|
+
proc = subprocess.run(["bash", "-lc", cmd], cwd=path, capture_output=True, text=True)
|
|
177
|
+
return (proc.stdout or "") + (proc.stderr or "")
|
|
178
|
+
except Exception as e:
|
|
179
|
+
return f"❌ run_local_cmd error: {e}\n"
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .utils import *
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from ...widgets import *
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from ..imports import *
|
|
2
|
+
def get_args_kwargs(*args,**kwargs):
|
|
3
|
+
return args,kwargs
|
|
4
|
+
def addWidgets(layout,addFunc, *args, **kwargs):
|
|
5
|
+
addFunc = getattr(layout, addFunc)
|
|
6
|
+
for arg in args:
|
|
7
|
+
if isinstance(arg, tuple) and len(arg) == 2 and isinstance(arg[1], dict):
|
|
8
|
+
widget, options = arg
|
|
9
|
+
if isinstance(widget, str):
|
|
10
|
+
widget = QLabel(widget)
|
|
11
|
+
addFunc(widget, **options)
|
|
12
|
+
elif isinstance(arg, str):
|
|
13
|
+
widget = QLabel(arg)
|
|
14
|
+
addFunc(widget, **kwargs)
|
|
15
|
+
else:
|
|
16
|
+
addFunc(arg, **kwargs)
|
|
17
|
+
def createLayout(label,widgetFunc,addFunc,*args,**kwargs):
|
|
18
|
+
layout = widgetFunc()
|
|
19
|
+
label = QLabel(label)
|
|
20
|
+
args = (label,*args)
|
|
21
|
+
addWidgets(layout,addFunc,*args,**kwargs)
|
|
22
|
+
return layout
|
|
23
|
+
|
|
24
|
+
def createWidget(layout, label, widgetFunc, addFunc, getLayout, widgets, addSubFunc='addLayout'):
|
|
25
|
+
sublayout = createLayout(label, widgetFunc, addFunc, **getLayout)
|
|
26
|
+
addWidgets(sublayout, addFunc, *widgets)
|
|
27
|
+
if layout is not None:
|
|
28
|
+
add_sub_method = getattr(layout, addSubFunc)
|
|
29
|
+
add_sub_method(sublayout)
|
|
30
|
+
return sublayout
|
|
31
|
+
|
|
32
|
+
def add_func(tabs,addFunc,*args,**kwargs):
|
|
33
|
+
add_sub_method = getattr(tabs, addFunc)
|
|
34
|
+
add_sub_method(*args,**kwargs)
|
|
35
|
+
def add_tab(tabs,**kwargs):
|
|
36
|
+
tabs.addTab(**kwargs)
|
|
37
|
+
def add_layout(layout,*args,**kwargs):
|
|
38
|
+
add_func(layout,'addLayout',*args,**kwargs)
|