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.
Files changed (134) hide show
  1. vortex/__init__.py +0 -0
  2. vortex/__main__.py +6 -0
  3. vortex/colour.py +18 -0
  4. vortex/commands/__init__.py +0 -0
  5. vortex/commands/clean.py +21 -0
  6. vortex/commands/clone.py +219 -0
  7. vortex/commands/code.py +22 -0
  8. vortex/commands/config.py +34 -0
  9. vortex/commands/copy.py +158 -0
  10. vortex/commands/delete.py +84 -0
  11. vortex/commands/find.py +46 -0
  12. vortex/commands/grep.py +68 -0
  13. vortex/commands/list.py +72 -0
  14. vortex/commands/log.py +32 -0
  15. vortex/commands/new.py +126 -0
  16. vortex/commands/watch.py +339 -0
  17. vortex/constants.py +6 -0
  18. vortex/main.py +483 -0
  19. vortex/models.py +529 -0
  20. vortex/puakma/lib/XmlSchema-1.4.2.jar +0 -0
  21. vortex/puakma/lib/activation-1.1.jar +0 -0
  22. vortex/puakma/lib/annogen-0.1.0.jar +0 -0
  23. vortex/puakma/lib/axiom-api-1.2.7.jar +0 -0
  24. vortex/puakma/lib/axiom-dom-1.2.7.jar +0 -0
  25. vortex/puakma/lib/axiom-impl-1.2.7.jar +0 -0
  26. vortex/puakma/lib/axis2-adb-1.4.1.jar +0 -0
  27. vortex/puakma/lib/axis2-adb-codegen-1.4.1.jar +0 -0
  28. vortex/puakma/lib/axis2-ant-plugin-1.4.1.jar +0 -0
  29. vortex/puakma/lib/axis2-clustering-1.4.1.jar +0 -0
  30. vortex/puakma/lib/axis2-codegen-1.4.1.jar +0 -0
  31. vortex/puakma/lib/axis2-corba-1.4.1.jar +0 -0
  32. vortex/puakma/lib/axis2-fastinfoset-1.4.1.jar +0 -0
  33. vortex/puakma/lib/axis2-java2wsdl-1.4.1.jar +0 -0
  34. vortex/puakma/lib/axis2-jaxbri-1.4.1.jar +0 -0
  35. vortex/puakma/lib/axis2-jaxws-1.4.1.jar +0 -0
  36. vortex/puakma/lib/axis2-jaxws-api-1.4.1.jar +0 -0
  37. vortex/puakma/lib/axis2-jibx-1.4.1.jar +0 -0
  38. vortex/puakma/lib/axis2-json-1.4.1.jar +0 -0
  39. vortex/puakma/lib/axis2-jws-api-1.4.1.jar +0 -0
  40. vortex/puakma/lib/axis2-kernel-1.4.1.jar +0 -0
  41. vortex/puakma/lib/axis2-metadata-1.4.1.jar +0 -0
  42. vortex/puakma/lib/axis2-mtompolicy-1.4.1.jar +0 -0
  43. vortex/puakma/lib/axis2-saaj-1.4.1.jar +0 -0
  44. vortex/puakma/lib/axis2-saaj-api-1.4.1.jar +0 -0
  45. vortex/puakma/lib/axis2-spring-1.4.1.jar +0 -0
  46. vortex/puakma/lib/axis2-xmlbeans-1.4.1.jar +0 -0
  47. vortex/puakma/lib/backport-util-concurrent-3.1.jar +0 -0
  48. vortex/puakma/lib/bcprov-jdk14-131.jar +0 -0
  49. vortex/puakma/lib/commons-codec-1.10.jar +0 -0
  50. vortex/puakma/lib/commons-codec-1.3.jar +0 -0
  51. vortex/puakma/lib/commons-collections4-4.1.jar +0 -0
  52. vortex/puakma/lib/commons-fileupload-1.2.jar +0 -0
  53. vortex/puakma/lib/commons-httpclient-3.1.jar +0 -0
  54. vortex/puakma/lib/commons-io-1.4.jar +0 -0
  55. vortex/puakma/lib/commons-logging-1.1.1.jar +0 -0
  56. vortex/puakma/lib/commons-logging-1.2.jar +0 -0
  57. vortex/puakma/lib/curvesapi-1.04.jar +0 -0
  58. vortex/puakma/lib/dom4j-1.6.1.jar +0 -0
  59. vortex/puakma/lib/geronimo-annotation_1.0_spec-1.1.jar +0 -0
  60. vortex/puakma/lib/geronimo-stax-api_1.0_spec-1.0.1.jar +0 -0
  61. vortex/puakma/lib/httpcore-4.0-beta1.jar +0 -0
  62. vortex/puakma/lib/httpcore-nio-4.0-beta1.jar +0 -0
  63. vortex/puakma/lib/iText-rtf-2.1.3.jar +0 -0
  64. vortex/puakma/lib/itext-2.1.7.jar +0 -0
  65. vortex/puakma/lib/itext-pdfa-5.5.1-javadoc.jar +0 -0
  66. vortex/puakma/lib/itext-pdfa-5.5.1-sources.jar +0 -0
  67. vortex/puakma/lib/itext-pdfa-5.5.1.jar +0 -0
  68. vortex/puakma/lib/itext-xtra-5.5.1-javadoc.jar +0 -0
  69. vortex/puakma/lib/itext-xtra-5.5.1-sources.jar +0 -0
  70. vortex/puakma/lib/itext-xtra-5.5.1.jar +0 -0
  71. vortex/puakma/lib/itextpdf-5.5.1-javadoc.jar +0 -0
  72. vortex/puakma/lib/itextpdf-5.5.1-sources.jar +0 -0
  73. vortex/puakma/lib/itextpdf-5.5.1.jar +0 -0
  74. vortex/puakma/lib/jalopy-1.5rc3.jar +0 -0
  75. vortex/puakma/lib/jaxb-api-2.1.jar +0 -0
  76. vortex/puakma/lib/jaxb-impl-2.1.6.jar +0 -0
  77. vortex/puakma/lib/jaxb-xjc-2.1.6.jar +0 -0
  78. vortex/puakma/lib/jaxen-1.1.1.jar +0 -0
  79. vortex/puakma/lib/jcifs-1.2.13.jar +0 -0
  80. vortex/puakma/lib/jcifs-1.3.3.jar +0 -0
  81. vortex/puakma/lib/jcifs-ext-0.9.4.jar +0 -0
  82. vortex/puakma/lib/jcommon-1.0.12.jar +0 -0
  83. vortex/puakma/lib/jettison-1.0-RC2.jar +0 -0
  84. vortex/puakma/lib/jfreechart-1.0.13.jar +0 -0
  85. vortex/puakma/lib/jfreechart-1.0.17.jar +0 -0
  86. vortex/puakma/lib/jibx-bind-1.1.5.jar +0 -0
  87. vortex/puakma/lib/jibx-run-1.1.5.jar +0 -0
  88. vortex/puakma/lib/json-20101028.jar +0 -0
  89. vortex/puakma/lib/json-20110712.jar +0 -0
  90. vortex/puakma/lib/junit-4.12.jar +0 -0
  91. vortex/puakma/lib/log4j-1.2.15.jar +0 -0
  92. vortex/puakma/lib/log4j-1.2.17.jar +0 -0
  93. vortex/puakma/lib/mail-1.4.jar +0 -0
  94. vortex/puakma/lib/mex-1.4.1.jar +0 -0
  95. vortex/puakma/lib/neethi-2.0.4.jar +0 -0
  96. vortex/puakma/lib/poi_3.10.1/poi-3.10.1-20140818.jar +0 -0
  97. vortex/puakma/lib/poi_3.10.1/poi-examples-3.10.1-20140818.jar +0 -0
  98. vortex/puakma/lib/poi_3.10.1/poi-excelant-3.10.1-20140818.jar +0 -0
  99. vortex/puakma/lib/poi_3.10.1/poi-ooxml-3.10.1-20140818.jar +0 -0
  100. vortex/puakma/lib/poi_3.10.1/poi-ooxml-schemas-3.10.1-20140818.jar +0 -0
  101. vortex/puakma/lib/poi_3.10.1/poi-scratchpad-3.10.1-20140818.jar +0 -0
  102. vortex/puakma/lib/poi_3.17/poi-3.17.jar +0 -0
  103. vortex/puakma/lib/poi_3.17/poi-examples-3.17.jar +0 -0
  104. vortex/puakma/lib/poi_3.17/poi-excelant-3.17.jar +0 -0
  105. vortex/puakma/lib/poi_3.17/poi-ooxml-3.17.jar +0 -0
  106. vortex/puakma/lib/poi_3.17/poi-ooxml-schemas-3.17.jar +0 -0
  107. vortex/puakma/lib/poi_3.17/poi-scratchpad-3.17.jar +0 -0
  108. vortex/puakma/lib/shaj-0.5.jar +0 -0
  109. vortex/puakma/lib/soapmonitor-1.4.1.jar +0 -0
  110. vortex/puakma/lib/stax-api-1.0.1.jar +0 -0
  111. vortex/puakma/lib/woden-api-1.0M8.jar +0 -0
  112. vortex/puakma/lib/woden-impl-dom-1.0M8.jar +0 -0
  113. vortex/puakma/lib/wsdl4j-1.6.2.jar +0 -0
  114. vortex/puakma/lib/wstx-asl-3.2.4.jar +0 -0
  115. vortex/puakma/lib/xalan-2.7.0.jar +0 -0
  116. vortex/puakma/lib/xercesImpl-2.8.1.jar +0 -0
  117. vortex/puakma/lib/xml-apis-1.3.04.jar +0 -0
  118. vortex/puakma/lib/xml-resolver-1.2.jar +0 -0
  119. vortex/puakma/lib/xmlbeans-2.3.0.jar +0 -0
  120. vortex/puakma/lib/xmlbeans-2.6.0.jar +0 -0
  121. vortex/puakma/lib-int/puakma.jar +0 -0
  122. vortex/puakma/lib-int/puakma.vortex.wst_1.1.0.jar +0 -0
  123. vortex/puakma/lib-int/retroweaver-rt-1.2.4.jar +0 -0
  124. vortex/puakma/lib-int/velocity-1.5.jar +0 -0
  125. vortex/soap.py +332 -0
  126. vortex/spinner.py +53 -0
  127. vortex/util.py +192 -0
  128. vortex/workspace.py +271 -0
  129. vortex_cli-3.0.0.dist-info/LICENSE +21 -0
  130. vortex_cli-3.0.0.dist-info/METADATA +179 -0
  131. vortex_cli-3.0.0.dist-info/RECORD +134 -0
  132. vortex_cli-3.0.0.dist-info/WHEEL +5 -0
  133. vortex_cli-3.0.0.dist-info/entry_points.txt +2 -0
  134. vortex_cli-3.0.0.dist-info/top_level.txt +1 -0
vortex/__init__.py ADDED
File without changes
vortex/__main__.py ADDED
@@ -0,0 +1,6 @@
1
+ from __future__ import annotations
2
+
3
+ from vortex.main import main
4
+
5
+ if __name__ == "__main__":
6
+ raise SystemExit(main())
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
@@ -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
@@ -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
+ )
@@ -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
@@ -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
@@ -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
@@ -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}")