vortex-cli 3.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- vortex/__init__.py +0 -0
- vortex/__main__.py +6 -0
- vortex/colour.py +18 -0
- vortex/commands/__init__.py +0 -0
- vortex/commands/clean.py +21 -0
- vortex/commands/clone.py +219 -0
- vortex/commands/code.py +22 -0
- vortex/commands/config.py +34 -0
- vortex/commands/copy.py +158 -0
- vortex/commands/delete.py +84 -0
- vortex/commands/find.py +46 -0
- vortex/commands/grep.py +68 -0
- vortex/commands/list.py +72 -0
- vortex/commands/log.py +32 -0
- vortex/commands/new.py +126 -0
- vortex/commands/watch.py +339 -0
- vortex/constants.py +6 -0
- vortex/main.py +483 -0
- vortex/models.py +529 -0
- vortex/puakma/lib/XmlSchema-1.4.2.jar +0 -0
- vortex/puakma/lib/activation-1.1.jar +0 -0
- vortex/puakma/lib/annogen-0.1.0.jar +0 -0
- vortex/puakma/lib/axiom-api-1.2.7.jar +0 -0
- vortex/puakma/lib/axiom-dom-1.2.7.jar +0 -0
- vortex/puakma/lib/axiom-impl-1.2.7.jar +0 -0
- vortex/puakma/lib/axis2-adb-1.4.1.jar +0 -0
- vortex/puakma/lib/axis2-adb-codegen-1.4.1.jar +0 -0
- vortex/puakma/lib/axis2-ant-plugin-1.4.1.jar +0 -0
- vortex/puakma/lib/axis2-clustering-1.4.1.jar +0 -0
- vortex/puakma/lib/axis2-codegen-1.4.1.jar +0 -0
- vortex/puakma/lib/axis2-corba-1.4.1.jar +0 -0
- vortex/puakma/lib/axis2-fastinfoset-1.4.1.jar +0 -0
- vortex/puakma/lib/axis2-java2wsdl-1.4.1.jar +0 -0
- vortex/puakma/lib/axis2-jaxbri-1.4.1.jar +0 -0
- vortex/puakma/lib/axis2-jaxws-1.4.1.jar +0 -0
- vortex/puakma/lib/axis2-jaxws-api-1.4.1.jar +0 -0
- vortex/puakma/lib/axis2-jibx-1.4.1.jar +0 -0
- vortex/puakma/lib/axis2-json-1.4.1.jar +0 -0
- vortex/puakma/lib/axis2-jws-api-1.4.1.jar +0 -0
- vortex/puakma/lib/axis2-kernel-1.4.1.jar +0 -0
- vortex/puakma/lib/axis2-metadata-1.4.1.jar +0 -0
- vortex/puakma/lib/axis2-mtompolicy-1.4.1.jar +0 -0
- vortex/puakma/lib/axis2-saaj-1.4.1.jar +0 -0
- vortex/puakma/lib/axis2-saaj-api-1.4.1.jar +0 -0
- vortex/puakma/lib/axis2-spring-1.4.1.jar +0 -0
- vortex/puakma/lib/axis2-xmlbeans-1.4.1.jar +0 -0
- vortex/puakma/lib/backport-util-concurrent-3.1.jar +0 -0
- vortex/puakma/lib/bcprov-jdk14-131.jar +0 -0
- vortex/puakma/lib/commons-codec-1.10.jar +0 -0
- vortex/puakma/lib/commons-codec-1.3.jar +0 -0
- vortex/puakma/lib/commons-collections4-4.1.jar +0 -0
- vortex/puakma/lib/commons-fileupload-1.2.jar +0 -0
- vortex/puakma/lib/commons-httpclient-3.1.jar +0 -0
- vortex/puakma/lib/commons-io-1.4.jar +0 -0
- vortex/puakma/lib/commons-logging-1.1.1.jar +0 -0
- vortex/puakma/lib/commons-logging-1.2.jar +0 -0
- vortex/puakma/lib/curvesapi-1.04.jar +0 -0
- vortex/puakma/lib/dom4j-1.6.1.jar +0 -0
- vortex/puakma/lib/geronimo-annotation_1.0_spec-1.1.jar +0 -0
- vortex/puakma/lib/geronimo-stax-api_1.0_spec-1.0.1.jar +0 -0
- vortex/puakma/lib/httpcore-4.0-beta1.jar +0 -0
- vortex/puakma/lib/httpcore-nio-4.0-beta1.jar +0 -0
- vortex/puakma/lib/iText-rtf-2.1.3.jar +0 -0
- vortex/puakma/lib/itext-2.1.7.jar +0 -0
- vortex/puakma/lib/itext-pdfa-5.5.1-javadoc.jar +0 -0
- vortex/puakma/lib/itext-pdfa-5.5.1-sources.jar +0 -0
- vortex/puakma/lib/itext-pdfa-5.5.1.jar +0 -0
- vortex/puakma/lib/itext-xtra-5.5.1-javadoc.jar +0 -0
- vortex/puakma/lib/itext-xtra-5.5.1-sources.jar +0 -0
- vortex/puakma/lib/itext-xtra-5.5.1.jar +0 -0
- vortex/puakma/lib/itextpdf-5.5.1-javadoc.jar +0 -0
- vortex/puakma/lib/itextpdf-5.5.1-sources.jar +0 -0
- vortex/puakma/lib/itextpdf-5.5.1.jar +0 -0
- vortex/puakma/lib/jalopy-1.5rc3.jar +0 -0
- vortex/puakma/lib/jaxb-api-2.1.jar +0 -0
- vortex/puakma/lib/jaxb-impl-2.1.6.jar +0 -0
- vortex/puakma/lib/jaxb-xjc-2.1.6.jar +0 -0
- vortex/puakma/lib/jaxen-1.1.1.jar +0 -0
- vortex/puakma/lib/jcifs-1.2.13.jar +0 -0
- vortex/puakma/lib/jcifs-1.3.3.jar +0 -0
- vortex/puakma/lib/jcifs-ext-0.9.4.jar +0 -0
- vortex/puakma/lib/jcommon-1.0.12.jar +0 -0
- vortex/puakma/lib/jettison-1.0-RC2.jar +0 -0
- vortex/puakma/lib/jfreechart-1.0.13.jar +0 -0
- vortex/puakma/lib/jfreechart-1.0.17.jar +0 -0
- vortex/puakma/lib/jibx-bind-1.1.5.jar +0 -0
- vortex/puakma/lib/jibx-run-1.1.5.jar +0 -0
- vortex/puakma/lib/json-20101028.jar +0 -0
- vortex/puakma/lib/json-20110712.jar +0 -0
- vortex/puakma/lib/junit-4.12.jar +0 -0
- vortex/puakma/lib/log4j-1.2.15.jar +0 -0
- vortex/puakma/lib/log4j-1.2.17.jar +0 -0
- vortex/puakma/lib/mail-1.4.jar +0 -0
- vortex/puakma/lib/mex-1.4.1.jar +0 -0
- vortex/puakma/lib/neethi-2.0.4.jar +0 -0
- vortex/puakma/lib/poi_3.10.1/poi-3.10.1-20140818.jar +0 -0
- vortex/puakma/lib/poi_3.10.1/poi-examples-3.10.1-20140818.jar +0 -0
- vortex/puakma/lib/poi_3.10.1/poi-excelant-3.10.1-20140818.jar +0 -0
- vortex/puakma/lib/poi_3.10.1/poi-ooxml-3.10.1-20140818.jar +0 -0
- vortex/puakma/lib/poi_3.10.1/poi-ooxml-schemas-3.10.1-20140818.jar +0 -0
- vortex/puakma/lib/poi_3.10.1/poi-scratchpad-3.10.1-20140818.jar +0 -0
- vortex/puakma/lib/poi_3.17/poi-3.17.jar +0 -0
- vortex/puakma/lib/poi_3.17/poi-examples-3.17.jar +0 -0
- vortex/puakma/lib/poi_3.17/poi-excelant-3.17.jar +0 -0
- vortex/puakma/lib/poi_3.17/poi-ooxml-3.17.jar +0 -0
- vortex/puakma/lib/poi_3.17/poi-ooxml-schemas-3.17.jar +0 -0
- vortex/puakma/lib/poi_3.17/poi-scratchpad-3.17.jar +0 -0
- vortex/puakma/lib/shaj-0.5.jar +0 -0
- vortex/puakma/lib/soapmonitor-1.4.1.jar +0 -0
- vortex/puakma/lib/stax-api-1.0.1.jar +0 -0
- vortex/puakma/lib/woden-api-1.0M8.jar +0 -0
- vortex/puakma/lib/woden-impl-dom-1.0M8.jar +0 -0
- vortex/puakma/lib/wsdl4j-1.6.2.jar +0 -0
- vortex/puakma/lib/wstx-asl-3.2.4.jar +0 -0
- vortex/puakma/lib/xalan-2.7.0.jar +0 -0
- vortex/puakma/lib/xercesImpl-2.8.1.jar +0 -0
- vortex/puakma/lib/xml-apis-1.3.04.jar +0 -0
- vortex/puakma/lib/xml-resolver-1.2.jar +0 -0
- vortex/puakma/lib/xmlbeans-2.3.0.jar +0 -0
- vortex/puakma/lib/xmlbeans-2.6.0.jar +0 -0
- vortex/puakma/lib-int/puakma.jar +0 -0
- vortex/puakma/lib-int/puakma.vortex.wst_1.1.0.jar +0 -0
- vortex/puakma/lib-int/retroweaver-rt-1.2.4.jar +0 -0
- vortex/puakma/lib-int/velocity-1.5.jar +0 -0
- vortex/soap.py +332 -0
- vortex/spinner.py +53 -0
- vortex/util.py +192 -0
- vortex/workspace.py +271 -0
- vortex_cli-3.0.0.dist-info/LICENSE +21 -0
- vortex_cli-3.0.0.dist-info/METADATA +179 -0
- vortex_cli-3.0.0.dist-info/RECORD +134 -0
- vortex_cli-3.0.0.dist-info/WHEEL +5 -0
- vortex_cli-3.0.0.dist-info/entry_points.txt +2 -0
- vortex_cli-3.0.0.dist-info/top_level.txt +1 -0
vortex/__init__.py
ADDED
|
File without changes
|
vortex/__main__.py
ADDED
vortex/colour.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from enum import Enum
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Colour(Enum):
|
|
7
|
+
NORMAL = "\033[m"
|
|
8
|
+
RED = "\033[41m"
|
|
9
|
+
BOLD = "\033[1m"
|
|
10
|
+
GREEN = "\033[42m"
|
|
11
|
+
YELLOW = "\033[43;30m"
|
|
12
|
+
|
|
13
|
+
@staticmethod
|
|
14
|
+
def highlight(text: str, colour: Colour, replace_in: str | None = None) -> str:
|
|
15
|
+
highlighted_txt = f"{colour.value}{text}{Colour.NORMAL.value}"
|
|
16
|
+
if replace_in:
|
|
17
|
+
highlighted_txt = replace_in.replace(text, highlighted_txt)
|
|
18
|
+
return highlighted_txt
|
|
File without changes
|
vortex/commands/clean.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import shutil
|
|
5
|
+
|
|
6
|
+
from vortex.workspace import Workspace
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
logger = logging.getLogger("vortex")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def clean(workspace: Workspace) -> int:
|
|
13
|
+
app_dirs = workspace.listdir(strict=False)
|
|
14
|
+
ret = 0
|
|
15
|
+
if app_dirs:
|
|
16
|
+
with workspace.exclusive_lock():
|
|
17
|
+
for app_dir in app_dirs:
|
|
18
|
+
shutil.rmtree(app_dir)
|
|
19
|
+
logger.info(f"Deleted directory '{app_dir}'")
|
|
20
|
+
ret = workspace.update_vscode_settings()
|
|
21
|
+
return ret
|
vortex/commands/clone.py
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import binascii
|
|
5
|
+
import logging
|
|
6
|
+
import xml.etree.ElementTree as ET
|
|
7
|
+
import zlib
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from vortex import util
|
|
12
|
+
from vortex.models import DesignObject
|
|
13
|
+
from vortex.models import DesignType
|
|
14
|
+
from vortex.models import JavaClassVersion
|
|
15
|
+
from vortex.models import PuakmaApplication
|
|
16
|
+
from vortex.models import PuakmaServer
|
|
17
|
+
from vortex.spinner import Spinner
|
|
18
|
+
from vortex.workspace import Workspace
|
|
19
|
+
|
|
20
|
+
logger = logging.getLogger("vortex")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def clone(
|
|
24
|
+
workspace: Workspace,
|
|
25
|
+
server: PuakmaServer,
|
|
26
|
+
app_ids: list[int],
|
|
27
|
+
*,
|
|
28
|
+
get_resources: bool = False,
|
|
29
|
+
open_urls: bool = False,
|
|
30
|
+
reclone: bool = False,
|
|
31
|
+
) -> int:
|
|
32
|
+
if reclone:
|
|
33
|
+
app_ids.extend(app.id for app in workspace.listapps(server))
|
|
34
|
+
|
|
35
|
+
with (
|
|
36
|
+
workspace.exclusive_lock(),
|
|
37
|
+
Spinner(f"Cloning {app_ids}..."),
|
|
38
|
+
):
|
|
39
|
+
return asyncio.run(
|
|
40
|
+
_aclone_apps(workspace, server, app_ids, get_resources, open_urls)
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
async def _aclone_apps(
|
|
45
|
+
workspace: Workspace,
|
|
46
|
+
server: PuakmaServer,
|
|
47
|
+
app_ids: list[int],
|
|
48
|
+
get_resources: bool,
|
|
49
|
+
open_urls: bool,
|
|
50
|
+
) -> int:
|
|
51
|
+
tasks = []
|
|
52
|
+
async with server as s:
|
|
53
|
+
await s.server_designer.ainitiate_connection()
|
|
54
|
+
logger.info(f"Connected to {s.host}")
|
|
55
|
+
|
|
56
|
+
for app_id in app_ids:
|
|
57
|
+
task = asyncio.create_task(_aclone_app(workspace, s, app_id, get_resources))
|
|
58
|
+
tasks.append(task)
|
|
59
|
+
|
|
60
|
+
ret = 0
|
|
61
|
+
for done in asyncio.as_completed(tasks):
|
|
62
|
+
try:
|
|
63
|
+
app, _ret = await done
|
|
64
|
+
if open_urls and app:
|
|
65
|
+
util.open_app_urls(app)
|
|
66
|
+
ret |= _ret
|
|
67
|
+
except (KeyboardInterrupt, Exception) as e:
|
|
68
|
+
for task in tasks:
|
|
69
|
+
task.cancel()
|
|
70
|
+
raise e
|
|
71
|
+
except asyncio.CancelledError:
|
|
72
|
+
logger.error("Operation Cancelled")
|
|
73
|
+
for task in tasks:
|
|
74
|
+
task.cancel()
|
|
75
|
+
ret = 1
|
|
76
|
+
break
|
|
77
|
+
else:
|
|
78
|
+
ret |= workspace.update_vscode_settings()
|
|
79
|
+
return ret
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
async def _aclone_app(
|
|
83
|
+
workspace: Workspace,
|
|
84
|
+
server: PuakmaServer,
|
|
85
|
+
app_id: int,
|
|
86
|
+
get_resources: bool,
|
|
87
|
+
) -> tuple[PuakmaApplication | None, int]:
|
|
88
|
+
"""Clone a Puakma Application into a newly created directory"""
|
|
89
|
+
|
|
90
|
+
logger.info(f"Cloning [{app_id}] from {server.host}...")
|
|
91
|
+
|
|
92
|
+
app_xml, _obj_rows = await asyncio.gather(
|
|
93
|
+
server.app_designer.aget_application_xml(app_id),
|
|
94
|
+
PuakmaApplication.afetch_design_objects(server, app_id, get_resources),
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
try:
|
|
98
|
+
app, app_ele = _parse_app_xml(server, app_xml, app_id)
|
|
99
|
+
except (ValueError, KeyError) as e:
|
|
100
|
+
logger.error(e)
|
|
101
|
+
return None, 1
|
|
102
|
+
|
|
103
|
+
eles = app_ele.findall("designElement", namespaces=None)
|
|
104
|
+
objs = _aparse_design_objs(_obj_rows, app)
|
|
105
|
+
_match_and_validate_design_objs(objs, eles)
|
|
106
|
+
|
|
107
|
+
app.design_objects = objs
|
|
108
|
+
app_dir = workspace.mkdir(app, True)
|
|
109
|
+
try:
|
|
110
|
+
logger.info(f"Saving {len(objs)} ({len(eles)}) Design Objects [{app_id}]...")
|
|
111
|
+
await asyncio.to_thread(_save_objs, workspace, objs)
|
|
112
|
+
except asyncio.CancelledError:
|
|
113
|
+
util.rmtree(app_dir)
|
|
114
|
+
return None, 1
|
|
115
|
+
|
|
116
|
+
logger.info(f"Successfully cloned {app} into '{app_dir.name}'")
|
|
117
|
+
|
|
118
|
+
return app, 0
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def _save_objs(workspace: Workspace, objs: list[DesignObject]) -> None:
|
|
122
|
+
for obj in objs:
|
|
123
|
+
obj.save(workspace)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def _aparse_design_objs(
|
|
127
|
+
objs: list[dict[str, Any]], app: PuakmaApplication
|
|
128
|
+
) -> list[DesignObject]:
|
|
129
|
+
ret: list[DesignObject] = []
|
|
130
|
+
for obj in objs:
|
|
131
|
+
design_type_id = int(obj["type"])
|
|
132
|
+
name = obj["name"]
|
|
133
|
+
id_ = int(obj["id"])
|
|
134
|
+
try:
|
|
135
|
+
type_ = DesignType(design_type_id)
|
|
136
|
+
except ValueError:
|
|
137
|
+
logger.debug(
|
|
138
|
+
f"Skipped Design Object '{name}' [{obj['id']}]: "
|
|
139
|
+
f"Invalid Design Type [{design_type_id}]"
|
|
140
|
+
)
|
|
141
|
+
continue
|
|
142
|
+
ret.append(
|
|
143
|
+
DesignObject(
|
|
144
|
+
id_,
|
|
145
|
+
name,
|
|
146
|
+
app,
|
|
147
|
+
type_,
|
|
148
|
+
obj["ctype"],
|
|
149
|
+
obj["data"],
|
|
150
|
+
obj["src"],
|
|
151
|
+
)
|
|
152
|
+
)
|
|
153
|
+
return ret
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def _parse_app_xml(
|
|
157
|
+
server: PuakmaServer, app_xml: ET.Element, app_id: int
|
|
158
|
+
) -> tuple[PuakmaApplication, ET.Element]:
|
|
159
|
+
app_ele = app_xml.find("puakmaApplication", namespaces=None)
|
|
160
|
+
if not app_ele:
|
|
161
|
+
raise ValueError(f"Application [{app_id}] does not exist")
|
|
162
|
+
|
|
163
|
+
java_version_ele = app_xml.find('.//sysProp[@name="java.class.version"]')
|
|
164
|
+
if java_version_ele is None or java_version_ele.text is None:
|
|
165
|
+
raise ValueError("Java class version not specified")
|
|
166
|
+
major, minor = (int(v) for v in java_version_ele.text.split(".", maxsplit=1))
|
|
167
|
+
version: JavaClassVersion = (major, minor)
|
|
168
|
+
app = PuakmaApplication(
|
|
169
|
+
id=int(app_ele.attrib["id"]),
|
|
170
|
+
name=app_ele.attrib["name"],
|
|
171
|
+
group=app_ele.attrib["group"],
|
|
172
|
+
inherit_from=app_ele.attrib["inherit"],
|
|
173
|
+
template_name=app_ele.attrib["template"],
|
|
174
|
+
java_class_version=version,
|
|
175
|
+
host=server.host,
|
|
176
|
+
)
|
|
177
|
+
return app, app_ele
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def _validate_crc32_checksum(obj: DesignObject, ele: dict[str, str]) -> bool:
|
|
181
|
+
data = obj.design_source if obj.do_save_source else obj.design_data
|
|
182
|
+
crc32_xml_key = "sourceCrc32" if obj.do_save_source else "dataCrc32"
|
|
183
|
+
crc32_checksum = int(ele.get(crc32_xml_key, 0))
|
|
184
|
+
try:
|
|
185
|
+
return crc32_checksum == zlib.crc32(data)
|
|
186
|
+
except (TypeError, binascii.Error):
|
|
187
|
+
return False
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def _match_and_validate_design_objs(
|
|
191
|
+
design_objs: list[DesignObject],
|
|
192
|
+
design_elements: list[ET.Element],
|
|
193
|
+
) -> None:
|
|
194
|
+
design_objs_eles = {int(ele.attrib["id"]): ele for ele in design_elements}
|
|
195
|
+
for obj in reversed(design_objs):
|
|
196
|
+
ele = design_objs_eles.get(obj.id)
|
|
197
|
+
if ele is not None:
|
|
198
|
+
obj.is_jar_library = ele.attrib.get("library", "false") == "true"
|
|
199
|
+
|
|
200
|
+
package = ele.attrib.get("package", None)
|
|
201
|
+
obj.package_dir = Path(*package.split(".")) if package else None
|
|
202
|
+
|
|
203
|
+
open_action_param_ele = ele.find('.//designParam[@name="OpenAction"]')
|
|
204
|
+
if open_action_param_ele is not None:
|
|
205
|
+
obj.open_action = open_action_param_ele.attrib["value"]
|
|
206
|
+
|
|
207
|
+
save_action_param_ele = ele.find('.//designParam[@name="SaveAction"]')
|
|
208
|
+
if save_action_param_ele is not None:
|
|
209
|
+
obj.save_action = save_action_param_ele.attrib["value"]
|
|
210
|
+
|
|
211
|
+
parent_page_param_ele = ele.find('.//designParam[@name="ParentPage"]')
|
|
212
|
+
if parent_page_param_ele is not None:
|
|
213
|
+
obj.parent_page = parent_page_param_ele.attrib["value"]
|
|
214
|
+
|
|
215
|
+
if ele is None or not _validate_crc32_checksum(obj, ele.attrib):
|
|
216
|
+
design_objs.remove(obj)
|
|
217
|
+
logger.warning(
|
|
218
|
+
f"Unable to validate Design Object {obj}. It will not be saved."
|
|
219
|
+
)
|
vortex/commands/code.py
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
|
|
5
|
+
from vortex import util
|
|
6
|
+
from vortex.workspace import Workspace
|
|
7
|
+
|
|
8
|
+
logger = logging.getLogger("vortex")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def code(workspace: Workspace, args: list[str]) -> int:
|
|
12
|
+
if not workspace.code_workspace_file.exists() and "--help" not in args:
|
|
13
|
+
logger.error(f"{workspace.code_workspace_file} does not exist")
|
|
14
|
+
return 1
|
|
15
|
+
|
|
16
|
+
args.insert(0, str(workspace.code_workspace_file))
|
|
17
|
+
cmd = "code"
|
|
18
|
+
try:
|
|
19
|
+
return util.execute_cmd(cmd, args)
|
|
20
|
+
except FileNotFoundError:
|
|
21
|
+
logger.error(f"VSCode '{cmd}' command not found. Check system PATH.")
|
|
22
|
+
return 1
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from vortex import util
|
|
4
|
+
from vortex.workspace import SAMPLE_CONFIG
|
|
5
|
+
from vortex.workspace import Workspace
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def config(
|
|
9
|
+
workspace: Workspace,
|
|
10
|
+
server_name: str | None,
|
|
11
|
+
*,
|
|
12
|
+
init: bool = False,
|
|
13
|
+
print_sample: bool = False,
|
|
14
|
+
update_vscode_settings: bool = False,
|
|
15
|
+
reset_vscode_settings: bool = False,
|
|
16
|
+
output_config_path: bool = False,
|
|
17
|
+
output_workspace_path: bool = False,
|
|
18
|
+
) -> int:
|
|
19
|
+
if print_sample:
|
|
20
|
+
print(SAMPLE_CONFIG, end="")
|
|
21
|
+
return 0
|
|
22
|
+
if update_vscode_settings or reset_vscode_settings:
|
|
23
|
+
return workspace.update_vscode_settings(reset_vscode_settings)
|
|
24
|
+
if output_config_path:
|
|
25
|
+
print(workspace.config_file)
|
|
26
|
+
return 0
|
|
27
|
+
if output_workspace_path:
|
|
28
|
+
print(workspace.path)
|
|
29
|
+
return 0
|
|
30
|
+
if not init:
|
|
31
|
+
workspace.print_info()
|
|
32
|
+
util.print_row_break(" Server Info ")
|
|
33
|
+
workspace.print_server_config_info(server_name)
|
|
34
|
+
return 0
|
vortex/commands/copy.py
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import logging
|
|
5
|
+
|
|
6
|
+
from vortex.models import DesignObject
|
|
7
|
+
from vortex.models import DesignObjectAmbiguousError
|
|
8
|
+
from vortex.models import DesignObjectNotFound
|
|
9
|
+
from vortex.models import PuakmaApplication
|
|
10
|
+
from vortex.models import PuakmaServer
|
|
11
|
+
from vortex.spinner import Spinner
|
|
12
|
+
from vortex.util import render_objects
|
|
13
|
+
from vortex.workspace import Workspace
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
logger = logging.getLogger("vortex")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def copy(
|
|
20
|
+
workspace: Workspace,
|
|
21
|
+
server: PuakmaServer,
|
|
22
|
+
obj_ids: list[int],
|
|
23
|
+
to_app_ids: list[int],
|
|
24
|
+
copy_params: bool,
|
|
25
|
+
) -> int:
|
|
26
|
+
workspace_apps = workspace.listapps(server)
|
|
27
|
+
to_apps = [app for app in workspace_apps if app.id in to_app_ids]
|
|
28
|
+
if not to_apps:
|
|
29
|
+
logger.error(f"No cloned application found with ID {to_app_ids}")
|
|
30
|
+
return 1
|
|
31
|
+
matches = [
|
|
32
|
+
obj for app in workspace_apps for obj in app.design_objects if obj.id in obj_ids
|
|
33
|
+
]
|
|
34
|
+
if not matches or len(matches) != len(obj_ids):
|
|
35
|
+
logger.error(
|
|
36
|
+
f"Unable to match Design Objects {obj_ids} in {[o.id for o in matches]}"
|
|
37
|
+
)
|
|
38
|
+
return 1
|
|
39
|
+
|
|
40
|
+
print(f"The following Objects will be copied to {[str(app) for app in to_apps]}:\n")
|
|
41
|
+
render_objects(matches, show_params=copy_params)
|
|
42
|
+
if input("\n[Y/y] to continue:") not in ["Y", "y"]:
|
|
43
|
+
return 1
|
|
44
|
+
|
|
45
|
+
with (
|
|
46
|
+
workspace.exclusive_lock(),
|
|
47
|
+
Spinner("Copying..."),
|
|
48
|
+
):
|
|
49
|
+
return asyncio.run(
|
|
50
|
+
_acopy_objects(workspace, server, to_apps, matches, copy_params)
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
async def _acopy_objects(
|
|
55
|
+
workspace: Workspace,
|
|
56
|
+
server: PuakmaServer,
|
|
57
|
+
to_apps: list[PuakmaApplication],
|
|
58
|
+
objs_to_copy: list[DesignObject],
|
|
59
|
+
copy_params: bool,
|
|
60
|
+
) -> int:
|
|
61
|
+
async with server:
|
|
62
|
+
await server.server_designer.ainitiate_connection()
|
|
63
|
+
logger.info(f"Connected to {server.host}")
|
|
64
|
+
ret = 0
|
|
65
|
+
tasks = []
|
|
66
|
+
|
|
67
|
+
for to_app in to_apps:
|
|
68
|
+
for obj_to_copy in objs_to_copy:
|
|
69
|
+
if to_app.id == obj_to_copy.app.id:
|
|
70
|
+
_err = f"Failed to copy {obj_to_copy} to {to_app}: "
|
|
71
|
+
logger.error(f"{_err} {obj_to_copy} already belongs to {to_app}")
|
|
72
|
+
ret |= 1
|
|
73
|
+
continue
|
|
74
|
+
|
|
75
|
+
obj_to_copy.app = to_app
|
|
76
|
+
|
|
77
|
+
task = asyncio.create_task(
|
|
78
|
+
_acopy_obj(workspace, server, obj_to_copy, copy_params)
|
|
79
|
+
)
|
|
80
|
+
tasks.append(task)
|
|
81
|
+
|
|
82
|
+
for result in asyncio.as_completed(tasks):
|
|
83
|
+
try:
|
|
84
|
+
ret |= await result
|
|
85
|
+
except (Exception, asyncio.CancelledError) as e:
|
|
86
|
+
logger.error(f"Operation Cancelled: {e}")
|
|
87
|
+
for task in tasks:
|
|
88
|
+
task.cancel()
|
|
89
|
+
ret = 1
|
|
90
|
+
break
|
|
91
|
+
|
|
92
|
+
for app in to_apps:
|
|
93
|
+
workspace.mkdir(app)
|
|
94
|
+
|
|
95
|
+
return ret
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
async def _acopy_obj(
|
|
99
|
+
workspace: Workspace,
|
|
100
|
+
server: PuakmaServer,
|
|
101
|
+
obj: DesignObject,
|
|
102
|
+
copy_params: bool,
|
|
103
|
+
) -> int:
|
|
104
|
+
_err_msg = f"Failed to copy {obj} to {obj.app.id}:"
|
|
105
|
+
|
|
106
|
+
try:
|
|
107
|
+
indx, existing_obj = obj.app.lookup_design_obj(obj.name)
|
|
108
|
+
except DesignObjectNotFound:
|
|
109
|
+
# Create a new object
|
|
110
|
+
obj.id = -1
|
|
111
|
+
ok = await obj.acreate(server.app_designer)
|
|
112
|
+
if not ok:
|
|
113
|
+
logger.error(f"{_err_msg} Unable to create Design Object {obj}")
|
|
114
|
+
return 1
|
|
115
|
+
|
|
116
|
+
if copy_params:
|
|
117
|
+
await obj.acreate_params(server.app_designer)
|
|
118
|
+
|
|
119
|
+
obj.app.design_objects.append(obj)
|
|
120
|
+
except DesignObjectAmbiguousError as e:
|
|
121
|
+
logger.error(f"{_err_msg } {e}")
|
|
122
|
+
return 1
|
|
123
|
+
else:
|
|
124
|
+
# Update the existing object
|
|
125
|
+
logger.info(
|
|
126
|
+
f"Design Object {obj} already exists in {obj.app}. "
|
|
127
|
+
"Only the Design data/source will be updated."
|
|
128
|
+
)
|
|
129
|
+
obj.id = existing_obj.id
|
|
130
|
+
obj.app.design_objects[indx].design_data = obj.design_data
|
|
131
|
+
obj.app.design_objects[indx].design_source = obj.design_source
|
|
132
|
+
|
|
133
|
+
tasks = []
|
|
134
|
+
if obj.do_save_source:
|
|
135
|
+
upload_src_task = asyncio.create_task(
|
|
136
|
+
obj.aupload(server.download_designer, True)
|
|
137
|
+
)
|
|
138
|
+
tasks.append(upload_src_task)
|
|
139
|
+
upload_data_task = asyncio.create_task(obj.aupload(server.download_designer))
|
|
140
|
+
tasks.append(upload_data_task)
|
|
141
|
+
|
|
142
|
+
ret = 0
|
|
143
|
+
for result in asyncio.as_completed(tasks):
|
|
144
|
+
try:
|
|
145
|
+
ok = await result
|
|
146
|
+
ret |= 0 if ok else 1
|
|
147
|
+
except (Exception, asyncio.CancelledError) as e:
|
|
148
|
+
for task in tasks:
|
|
149
|
+
task.cancel()
|
|
150
|
+
raise e
|
|
151
|
+
|
|
152
|
+
try:
|
|
153
|
+
await asyncio.to_thread(obj.save, workspace)
|
|
154
|
+
except OSError as e:
|
|
155
|
+
logger.error(e.strerror)
|
|
156
|
+
ret = 1
|
|
157
|
+
|
|
158
|
+
return ret
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import logging
|
|
5
|
+
|
|
6
|
+
from vortex.colour import Colour
|
|
7
|
+
from vortex.models import DesignObject
|
|
8
|
+
from vortex.models import PuakmaServer
|
|
9
|
+
from vortex.soap import AppDesigner
|
|
10
|
+
from vortex.util import render_objects
|
|
11
|
+
from vortex.workspace import Workspace
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger("vortex")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def delete(
|
|
17
|
+
workspace: Workspace,
|
|
18
|
+
server: PuakmaServer,
|
|
19
|
+
obj_ids: list[int],
|
|
20
|
+
) -> int:
|
|
21
|
+
objs = []
|
|
22
|
+
apps = []
|
|
23
|
+
for app in workspace.listapps(server):
|
|
24
|
+
for obj in app.design_objects:
|
|
25
|
+
if obj.id in obj_ids:
|
|
26
|
+
objs.append(obj)
|
|
27
|
+
apps.append(app)
|
|
28
|
+
|
|
29
|
+
if not objs:
|
|
30
|
+
logger.error(f"No cloned Design Object found with ID {obj_ids}")
|
|
31
|
+
return 1
|
|
32
|
+
|
|
33
|
+
_deleted = Colour.highlight("deleted", Colour.RED)
|
|
34
|
+
print(f"The following Design Objects will be {_deleted}:\n")
|
|
35
|
+
render_objects(objs)
|
|
36
|
+
if input("\n[Y/y] to continue:") not in ["Y", "y"]:
|
|
37
|
+
return 1
|
|
38
|
+
|
|
39
|
+
with workspace.exclusive_lock():
|
|
40
|
+
ret = asyncio.run(_adelete_objs(workspace, server, objs))
|
|
41
|
+
for app in apps:
|
|
42
|
+
workspace.mkdir(app)
|
|
43
|
+
return ret
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
async def _adelete_objs(
|
|
47
|
+
workspace: Workspace, server: PuakmaServer, objs: list[DesignObject]
|
|
48
|
+
) -> int:
|
|
49
|
+
async with server as s:
|
|
50
|
+
await s.server_designer.ainitiate_connection()
|
|
51
|
+
logger.info(f"Connected to {s.host}")
|
|
52
|
+
tasks = []
|
|
53
|
+
for obj in objs:
|
|
54
|
+
task = asyncio.create_task(_adelete(workspace, s.app_designer, obj))
|
|
55
|
+
tasks.append(task)
|
|
56
|
+
ret = 0
|
|
57
|
+
for done in asyncio.as_completed(tasks):
|
|
58
|
+
try:
|
|
59
|
+
ret |= await done
|
|
60
|
+
except (asyncio.CancelledError, Exception) as e:
|
|
61
|
+
for task in tasks:
|
|
62
|
+
task.cancel()
|
|
63
|
+
raise e
|
|
64
|
+
return ret
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
async def _adelete(
|
|
68
|
+
workspace: Workspace,
|
|
69
|
+
app_designer: AppDesigner,
|
|
70
|
+
obj: DesignObject,
|
|
71
|
+
) -> int:
|
|
72
|
+
await obj.adelete(app_designer)
|
|
73
|
+
obj.app.design_objects.remove(obj)
|
|
74
|
+
path = obj.design_path(workspace).path
|
|
75
|
+
try:
|
|
76
|
+
path.unlink()
|
|
77
|
+
logger.info(f"Deleted Local File: {path}")
|
|
78
|
+
except FileNotFoundError as e:
|
|
79
|
+
err = (
|
|
80
|
+
f"Unable to delete local file because it does not exist: {path}\n"
|
|
81
|
+
"Hint: It may have already been deleted or saved without file extension."
|
|
82
|
+
)
|
|
83
|
+
logger.warning(f"{e}: {err}")
|
|
84
|
+
return 0
|
vortex/commands/find.py
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from vortex.models import DesignType
|
|
4
|
+
from vortex.models import PuakmaServer
|
|
5
|
+
from vortex.util import render_objects
|
|
6
|
+
from vortex.workspace import Workspace
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def find(
|
|
10
|
+
workspace: Workspace,
|
|
11
|
+
server: PuakmaServer,
|
|
12
|
+
name: str,
|
|
13
|
+
*,
|
|
14
|
+
app_ids: list[int] | None = None,
|
|
15
|
+
design_types: list[DesignType] | None = None,
|
|
16
|
+
exclude_resources: bool = True,
|
|
17
|
+
show_params: bool = False,
|
|
18
|
+
show_ids_only: bool = False,
|
|
19
|
+
fuzzy_search: bool = True,
|
|
20
|
+
) -> int:
|
|
21
|
+
apps = (
|
|
22
|
+
app
|
|
23
|
+
for app in workspace.listapps(server)
|
|
24
|
+
if (not app_ids or (app.id in app_ids))
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
if exclude_resources:
|
|
28
|
+
design_types = [t for t in DesignType if t != DesignType.RESOURCE]
|
|
29
|
+
|
|
30
|
+
matches = (
|
|
31
|
+
obj
|
|
32
|
+
for app in apps
|
|
33
|
+
for obj in app.design_objects
|
|
34
|
+
if (
|
|
35
|
+
(fuzzy_search and name.lower() in obj.name.lower())
|
|
36
|
+
or (name.lower() == obj.name.lower())
|
|
37
|
+
)
|
|
38
|
+
and (not design_types or obj.design_type in design_types)
|
|
39
|
+
)
|
|
40
|
+
if show_ids_only:
|
|
41
|
+
for obj in matches:
|
|
42
|
+
print(obj.id)
|
|
43
|
+
else:
|
|
44
|
+
render_objects(matches, show_params=show_params)
|
|
45
|
+
|
|
46
|
+
return 0
|
vortex/commands/grep.py
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import functools
|
|
4
|
+
import re
|
|
5
|
+
|
|
6
|
+
from vortex.colour import Colour
|
|
7
|
+
from vortex.models import DesignObject
|
|
8
|
+
from vortex.models import DesignType
|
|
9
|
+
from vortex.models import PuakmaServer
|
|
10
|
+
from vortex.workspace import Workspace
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def grep(
|
|
14
|
+
workspace: Workspace,
|
|
15
|
+
server: PuakmaServer,
|
|
16
|
+
pattern: str,
|
|
17
|
+
*,
|
|
18
|
+
app_ids: list[int] | None = None,
|
|
19
|
+
design_types: list[DesignType] | None = None,
|
|
20
|
+
output_paths: bool = False,
|
|
21
|
+
exclude_resources: bool = True,
|
|
22
|
+
) -> int:
|
|
23
|
+
if exclude_resources:
|
|
24
|
+
design_types = [t for t in DesignType if t != DesignType.RESOURCE]
|
|
25
|
+
|
|
26
|
+
regex = re.compile(pattern.encode())
|
|
27
|
+
apps = (
|
|
28
|
+
app for app in workspace.listapps(server) if (not app_ids or app.id in app_ids)
|
|
29
|
+
)
|
|
30
|
+
objs = [
|
|
31
|
+
obj
|
|
32
|
+
for app in apps
|
|
33
|
+
for obj in app.design_objects
|
|
34
|
+
if (not obj.is_jar_library)
|
|
35
|
+
and (not design_types or obj.design_type in design_types)
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
_output_match = functools.partial(_output, workspace, output_path=output_paths)
|
|
39
|
+
|
|
40
|
+
for obj in sorted(objs, key=lambda obj: obj.name):
|
|
41
|
+
bytes_to_search = obj.design_source if obj.do_save_source else obj.design_data
|
|
42
|
+
match = re.search(regex, bytes_to_search)
|
|
43
|
+
_output_match(match, obj) if match else None
|
|
44
|
+
|
|
45
|
+
return 0
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _output(
|
|
49
|
+
workspace: Workspace,
|
|
50
|
+
match: re.Match[bytes],
|
|
51
|
+
obj: DesignObject,
|
|
52
|
+
*,
|
|
53
|
+
output_path: bool,
|
|
54
|
+
) -> None:
|
|
55
|
+
try:
|
|
56
|
+
text = match.string.decode()
|
|
57
|
+
except UnicodeDecodeError:
|
|
58
|
+
# Found a binary resource or jar library etc., skip
|
|
59
|
+
return
|
|
60
|
+
line_indx = text.count("\n", 0, match.start())
|
|
61
|
+
line_no = line_indx + 1
|
|
62
|
+
if output_path:
|
|
63
|
+
print(f"{obj.design_path(workspace)}:{line_no}")
|
|
64
|
+
else:
|
|
65
|
+
matched_text = match.group().decode()
|
|
66
|
+
line = text.splitlines()[line_indx].strip()
|
|
67
|
+
new_text = Colour.highlight(matched_text, Colour.RED, line)
|
|
68
|
+
print(f"{Colour.highlight(obj.file_name, Colour.BOLD)}:{line_no}:{new_text}")
|