onec-interactive-runtime-core 0.1.19__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 (87) hide show
  1. onec_interactive_runtime_core-0.1.19.dist-info/METADATA +12 -0
  2. onec_interactive_runtime_core-0.1.19.dist-info/RECORD +87 -0
  3. onec_interactive_runtime_core-0.1.19.dist-info/WHEEL +4 -0
  4. onec_interactive_runtime_core-0.1.19.dist-info/licenses/COPYRIGHT +9 -0
  5. onec_interactive_runtime_core-0.1.19.dist-info/licenses/LICENSE +232 -0
  6. onec_interactive_runtime_core-0.1.19.dist-info/licenses/THIRD_PARTY_NOTICES.txt +32 -0
  7. onec_runtime/AGENTS.md +7 -0
  8. onec_runtime/__init__.py +3 -0
  9. onec_runtime/artifacts.py +59 -0
  10. onec_runtime/bootstrap.py +310 -0
  11. onec_runtime/breakpoint_workspace.py +249 -0
  12. onec_runtime/bsl/__init__.py +139 -0
  13. onec_runtime/bsl/diagnostics.py +1046 -0
  14. onec_runtime/bsl/full_ast_worker_projection.py +522 -0
  15. onec_runtime/bsl/generated_semantic_parser.py +6322 -0
  16. onec_runtime/bsl/lexer.py +164 -0
  17. onec_runtime/bsl/module_catalog.py +420 -0
  18. onec_runtime/bsl/module_delta.py +1079 -0
  19. onec_runtime/bsl/module_universe.py +1877 -0
  20. onec_runtime/bsl/notebook_cells.py +232 -0
  21. onec_runtime/bsl/notebook_method_globals.py +74 -0
  22. onec_runtime/bsl/notebook_methods.py +175 -0
  23. onec_runtime/bsl/parser_artifact_identity.py +119 -0
  24. onec_runtime/bsl/parser_target.py +388 -0
  25. onec_runtime/bsl/preprocessor.py +16 -0
  26. onec_runtime/bsl/semantic_lowering.py +1539 -0
  27. onec_runtime/bsl/source_maps.py +2411 -0
  28. onec_runtime/bsl/worker_dependency_resolver.py +289 -0
  29. onec_runtime/bsl/worker_preprocessor.py +247 -0
  30. onec_runtime/bsl/worker_projection_model.py +137 -0
  31. onec_runtime/bsl/worker_reload_source_map.py +1697 -0
  32. onec_runtime/capture.py +113 -0
  33. onec_runtime/capture_source.py +453 -0
  34. onec_runtime/compact_table.py +376 -0
  35. onec_runtime/compact_table_backend.py +500 -0
  36. onec_runtime/config.py +198 -0
  37. onec_runtime/configurator_agent.py +520 -0
  38. onec_runtime/controller_worker.py +400 -0
  39. onec_runtime/credentials.py +18 -0
  40. onec_runtime/epf_container.py +196 -0
  41. onec_runtime/errors.py +205 -0
  42. onec_runtime/experiment.py +130 -0
  43. onec_runtime/extension_bundle.py +944 -0
  44. onec_runtime/extension_lifecycle.py +402 -0
  45. onec_runtime/extension_state.py +222 -0
  46. onec_runtime/fault_injection.py +30 -0
  47. onec_runtime/kernel.py +179 -0
  48. onec_runtime/lease.py +123 -0
  49. onec_runtime/observation.py +287 -0
  50. onec_runtime/performance_profile.py +245 -0
  51. onec_runtime/privacy.py +263 -0
  52. onec_runtime/processes.py +265 -0
  53. onec_runtime/prototype_runtime.py +2644 -0
  54. onec_runtime/rdbg/__init__.py +1 -0
  55. onec_runtime/rdbg/models.py +130 -0
  56. onec_runtime/rdbg/reconnect.py +59 -0
  57. onec_runtime/rdbg/session.py +913 -0
  58. onec_runtime/rdbg/transport.py +138 -0
  59. onec_runtime/rdbg/xml_codec.py +980 -0
  60. onec_runtime/recovery.py +106 -0
  61. onec_runtime/recovery_journal.py +79 -0
  62. onec_runtime/resources/extension/OnecInteractiveRuntime.cfe +0 -0
  63. onec_runtime/resources/extension/extension-manifest.json +108 -0
  64. onec_runtime/runtime_api.py +5272 -0
  65. onec_runtime/runtime_contracts.py +196 -0
  66. onec_runtime/server_worker.py +2034 -0
  67. onec_runtime/session.py +2123 -0
  68. onec_runtime/startup_diagnostics.py +45 -0
  69. onec_runtime/stop_routing.py +65 -0
  70. onec_runtime/supervised_processes.py +232 -0
  71. onec_runtime/supervised_runtime.py +512 -0
  72. onec_runtime/supervisor.py +363 -0
  73. onec_runtime/supervisor_model.py +148 -0
  74. onec_runtime/supervisor_protocol.py +77 -0
  75. onec_runtime/table_materialization.py +471 -0
  76. onec_runtime/table_transfer_backend.py +203 -0
  77. onec_runtime/table_value.py +311 -0
  78. onec_runtime/toolchain.py +730 -0
  79. onec_runtime/value_materialization.py +432 -0
  80. onec_runtime/value_transfer_backend.py +199 -0
  81. onec_runtime/worker_breakpoints.py +1431 -0
  82. onec_runtime/worker_epf.py +313 -0
  83. onec_runtime/worker_epf_template.py +53 -0
  84. onec_runtime/worker_stage_protocol.py +516 -0
  85. onec_runtime/worker_universe.py +3772 -0
  86. onec_runtime_build/__init__.py +1 -0
  87. onec_runtime_build/parser_target_development.py +116 -0
@@ -0,0 +1,730 @@
1
+ from __future__ import annotations
2
+
3
+ import shutil
4
+ import subprocess
5
+ from dataclasses import dataclass
6
+ from hashlib import sha256
7
+ from pathlib import Path
8
+
9
+ from onec_runtime.config import RuntimeConfig
10
+ from onec_runtime.credentials import redact_command
11
+ from onec_runtime.errors import ExtensionNotInstalled, ProcessStartError
12
+ from onec_runtime.extension_bundle import EXTENSION_NAME
13
+ from onec_runtime.startup_diagnostics import startup_log_hint
14
+
15
+ HEADLESS_ARGS = ["/DisableStartupDialogs", "/DisableStartupMessages"]
16
+ _MISSING_PRODUCT_EXTENSION_DIAGNOSTICS = (
17
+ "Операция не может быть выполнена, так как расширение конфигурации "
18
+ f"с указанным именем не найдено: {EXTENSION_NAME}",
19
+ "Cannot perform the operation because the following configuration extension "
20
+ f"is not found: {EXTENSION_NAME}",
21
+ )
22
+
23
+
24
+ @dataclass(frozen=True)
25
+ class ToolResult:
26
+ command: tuple[str, ...]
27
+ returncode: int
28
+ log_path: Path
29
+
30
+ def __post_init__(self) -> None:
31
+ object.__setattr__(self, "command", redact_command(self.command))
32
+
33
+
34
+ def create_file_infobase_at_command(
35
+ designer_exe: Path, infobase_dir: Path, log_path: Path
36
+ ) -> list[str]:
37
+ return [
38
+ str(designer_exe),
39
+ "CREATEINFOBASE",
40
+ f"File={infobase_dir};",
41
+ *HEADLESS_ARGS,
42
+ "/Out",
43
+ str(log_path),
44
+ ]
45
+
46
+
47
+ def load_product_extension_source_command(
48
+ designer_exe: Path,
49
+ infobase_dir: Path,
50
+ source_dir: Path,
51
+ log_path: Path,
52
+ ) -> list[str]:
53
+ return [
54
+ str(designer_exe),
55
+ "DESIGNER",
56
+ "/F",
57
+ str(infobase_dir),
58
+ "/LoadConfigFromFiles",
59
+ str(source_dir),
60
+ "-Extension",
61
+ EXTENSION_NAME,
62
+ "-updateConfigDumpInfo",
63
+ "-Format",
64
+ "Hierarchical",
65
+ *HEADLESS_ARGS,
66
+ "/Out",
67
+ str(log_path),
68
+ ]
69
+
70
+
71
+ def dump_product_extension_cfe_command(
72
+ designer_exe: Path,
73
+ infobase_dir: Path,
74
+ output_cfe: Path,
75
+ log_path: Path,
76
+ ) -> list[str]:
77
+ return [
78
+ str(designer_exe),
79
+ "DESIGNER",
80
+ "/F",
81
+ str(infobase_dir),
82
+ "/DumpCfg",
83
+ str(output_cfe),
84
+ "-Extension",
85
+ EXTENSION_NAME,
86
+ *HEADLESS_ARGS,
87
+ "/Out",
88
+ str(log_path),
89
+ ]
90
+
91
+
92
+ def _target_designer_command(config: RuntimeConfig) -> list[str]:
93
+ return [
94
+ str(config.designer_exe),
95
+ "DESIGNER",
96
+ *config.infobase_arguments,
97
+ "/N",
98
+ config.username,
99
+ "/P",
100
+ config.password,
101
+ ]
102
+
103
+
104
+ def dump_target_extension_files_command(
105
+ config: RuntimeConfig, output_dir: Path, log_path: Path
106
+ ) -> list[str]:
107
+ return [
108
+ *_target_designer_command(config),
109
+ "/DumpConfigToFiles",
110
+ str(output_dir),
111
+ "-Extension",
112
+ EXTENSION_NAME,
113
+ "-Format",
114
+ "Hierarchical",
115
+ *HEADLESS_ARGS,
116
+ "/Out",
117
+ str(log_path),
118
+ ]
119
+
120
+
121
+ def dump_target_extension_cfe_command(
122
+ config: RuntimeConfig, output_cfe: Path, log_path: Path
123
+ ) -> list[str]:
124
+ return [
125
+ *_target_designer_command(config),
126
+ "/DumpCfg",
127
+ str(output_cfe),
128
+ "-Extension",
129
+ EXTENSION_NAME,
130
+ *HEADLESS_ARGS,
131
+ "/Out",
132
+ str(log_path),
133
+ ]
134
+
135
+
136
+ def load_target_extension_cfe_command(
137
+ config: RuntimeConfig, input_cfe: Path, log_path: Path
138
+ ) -> list[str]:
139
+ return [
140
+ *_target_designer_command(config),
141
+ "/LoadCfg",
142
+ str(input_cfe),
143
+ "-Extension",
144
+ EXTENSION_NAME,
145
+ *HEADLESS_ARGS,
146
+ "/Out",
147
+ str(log_path),
148
+ ]
149
+
150
+
151
+ def apply_product_extension_command(config: RuntimeConfig, log_path: Path) -> list[str]:
152
+ dynamic_mode = "-Dynamic-" if config.uses_external_infobase else "-Dynamic+"
153
+ return [
154
+ *_target_designer_command(config),
155
+ "/UpdateDBCfg",
156
+ dynamic_mode,
157
+ "-Extension",
158
+ EXTENSION_NAME,
159
+ *HEADLESS_ARGS,
160
+ "/Out",
161
+ str(log_path),
162
+ ]
163
+
164
+
165
+ def create_infobase_command(config: RuntimeConfig) -> list[str]:
166
+ return _create_infobase_command(
167
+ config, config.infobase_dir, config.logs_dir / "create-infobase.log"
168
+ )
169
+
170
+
171
+ def create_build_infobase_command(config: RuntimeConfig) -> list[str]:
172
+ return _create_infobase_command(
173
+ config,
174
+ config.build_infobase_dir,
175
+ config.logs_dir / "create-build-infobase.log",
176
+ )
177
+
178
+
179
+ def _create_infobase_command(
180
+ config: RuntimeConfig, infobase_dir: Path, log_path: Path
181
+ ) -> list[str]:
182
+ return [
183
+ str(config.designer_exe),
184
+ "CREATEINFOBASE",
185
+ f"File={infobase_dir};",
186
+ *HEADLESS_ARGS,
187
+ "/Out",
188
+ str(log_path),
189
+ ]
190
+
191
+
192
+ def build_external_processor_command(config: RuntimeConfig) -> list[str]:
193
+ return build_external_processor_from_files_command(
194
+ config,
195
+ config.workspace / "onec" / "Kernel" / "Kernel.xml",
196
+ config.kernel_epf,
197
+ config.logs_dir / "build-kernel.log",
198
+ )
199
+
200
+
201
+ def build_worker_command(config: RuntimeConfig) -> list[str]:
202
+ return build_external_processor_from_files_command(
203
+ config,
204
+ config.workspace / "onec" / "Worker" / "Worker.xml",
205
+ config.worker_epf,
206
+ config.logs_dir / "build-worker.log",
207
+ )
208
+
209
+
210
+ def build_external_processor_from_files_command(
211
+ config: RuntimeConfig,
212
+ source_xml: Path,
213
+ output_epf: Path,
214
+ log_path: Path,
215
+ ) -> list[str]:
216
+ return [
217
+ str(config.designer_exe),
218
+ "DESIGNER",
219
+ "/F",
220
+ str(config.build_infobase_dir),
221
+ "/LoadExternalDataProcessorOrReportFromFiles",
222
+ str(source_xml),
223
+ str(output_epf),
224
+ *HEADLESS_ARGS,
225
+ "/Out",
226
+ str(log_path),
227
+ ]
228
+
229
+
230
+ def load_extension_source_command(
231
+ config: RuntimeConfig,
232
+ source_dir: Path,
233
+ ) -> list[str]:
234
+ return [
235
+ str(config.designer_exe),
236
+ "DESIGNER",
237
+ "/F",
238
+ str(config.build_infobase_dir),
239
+ "/LoadConfigFromFiles",
240
+ str(source_dir),
241
+ "-Extension",
242
+ EXTENSION_NAME,
243
+ "-updateConfigDumpInfo",
244
+ "-format",
245
+ "Hierarchical",
246
+ *HEADLESS_ARGS,
247
+ "/Out",
248
+ str(config.logs_dir / "load-extension-source.log"),
249
+ ]
250
+
251
+
252
+ def load_target_extension_source_command(
253
+ config: RuntimeConfig,
254
+ source_dir: Path,
255
+ ) -> list[str]:
256
+ return [
257
+ str(config.designer_exe),
258
+ "DESIGNER",
259
+ *config.infobase_arguments,
260
+ "/N",
261
+ config.username,
262
+ "/P",
263
+ config.password,
264
+ "/LoadConfigFromFiles",
265
+ str(source_dir),
266
+ "-Extension",
267
+ EXTENSION_NAME,
268
+ "-updateConfigDumpInfo",
269
+ "-format",
270
+ "Hierarchical",
271
+ *HEADLESS_ARGS,
272
+ "/Out",
273
+ str(config.logs_dir / "load-target-extension-source.log"),
274
+ ]
275
+
276
+
277
+ def dump_extension_command(
278
+ config: RuntimeConfig,
279
+ output_cfe: Path,
280
+ ) -> list[str]:
281
+ return [
282
+ str(config.designer_exe),
283
+ "DESIGNER",
284
+ "/F",
285
+ str(config.build_infobase_dir),
286
+ "/DumpCfg",
287
+ str(output_cfe),
288
+ "-Extension",
289
+ EXTENSION_NAME,
290
+ *HEADLESS_ARGS,
291
+ "/Out",
292
+ str(config.logs_dir / "dump-extension.log"),
293
+ ]
294
+
295
+
296
+ def deploy_extension_command(config: RuntimeConfig) -> list[str]:
297
+ return [
298
+ str(config.designer_exe),
299
+ "DESIGNER",
300
+ *config.infobase_arguments,
301
+ "/N",
302
+ config.username,
303
+ "/P",
304
+ config.password,
305
+ "/LoadCfg",
306
+ str(config.build_dir / f"{EXTENSION_NAME}.cfe"),
307
+ "-Extension",
308
+ EXTENSION_NAME,
309
+ *HEADLESS_ARGS,
310
+ "/Out",
311
+ str(config.logs_dir / "load-extension.log"),
312
+ ]
313
+
314
+
315
+ def update_extension_command(config: RuntimeConfig) -> list[str]:
316
+ command = [
317
+ str(config.designer_exe),
318
+ "DESIGNER",
319
+ *config.infobase_arguments,
320
+ "/N",
321
+ config.username,
322
+ "/P",
323
+ config.password,
324
+ "/UpdateDBCfg",
325
+ *HEADLESS_ARGS,
326
+ "-Extension",
327
+ EXTENSION_NAME,
328
+ "/Out",
329
+ str(config.logs_dir / "update-extension.log"),
330
+ ]
331
+ dynamic_mode = "-Dynamic-" if config.uses_external_infobase else "-Dynamic+"
332
+ command.insert(command.index("-Extension"), dynamic_mode)
333
+ return command
334
+
335
+
336
+ def apply_extension_command(config: RuntimeConfig) -> list[str]:
337
+ dynamic_mode = "-Dynamic-" if config.uses_external_infobase else "-Dynamic+"
338
+ return [
339
+ str(config.designer_exe),
340
+ "DESIGNER",
341
+ *config.infobase_arguments,
342
+ "/N",
343
+ config.username,
344
+ "/P",
345
+ config.password,
346
+ "/LoadCfg",
347
+ str(config.build_dir / f"{EXTENSION_NAME}.cfe"),
348
+ "-Extension",
349
+ EXTENSION_NAME,
350
+ "/UpdateDBCfg",
351
+ dynamic_mode,
352
+ *HEADLESS_ARGS,
353
+ "/Out",
354
+ str(config.logs_dir / "apply-extension.log"),
355
+ ]
356
+
357
+
358
+ def apply_target_extension_source_command(
359
+ config: RuntimeConfig,
360
+ source_dir: Path,
361
+ ) -> list[str]:
362
+ dynamic_mode = "-Dynamic-" if config.uses_external_infobase else "-Dynamic+"
363
+ return [
364
+ str(config.designer_exe),
365
+ "DESIGNER",
366
+ *config.infobase_arguments,
367
+ "/N",
368
+ config.username,
369
+ "/P",
370
+ config.password,
371
+ "/LoadConfigFromFiles",
372
+ str(source_dir),
373
+ "-Extension",
374
+ EXTENSION_NAME,
375
+ "-updateConfigDumpInfo",
376
+ "-format",
377
+ "Hierarchical",
378
+ "/UpdateDBCfg",
379
+ dynamic_mode,
380
+ *HEADLESS_ARGS,
381
+ "/Out",
382
+ str(config.logs_dir / "apply-extension-source.log"),
383
+ ]
384
+
385
+
386
+ def _prepare_runtime_directories(config: RuntimeConfig) -> None:
387
+ config.runtime_dir.mkdir(parents=True, exist_ok=True)
388
+ config.build_dir.mkdir(parents=True, exist_ok=True)
389
+ config.logs_dir.mkdir(parents=True, exist_ok=True)
390
+
391
+
392
+ def _run(command: list[str], log_path: Path) -> ToolResult:
393
+ try:
394
+ completed = subprocess.run(command, shell=False, check=False)
395
+ except OSError as error:
396
+ raise ProcessStartError(
397
+ f"Unable to start 1C tool (OS error {error.errno}); see {log_path}"
398
+ ) from None
399
+ result = ToolResult(tuple(command), completed.returncode, log_path)
400
+ if completed.returncode != 0:
401
+ raise ProcessStartError(
402
+ f"1C tool exited with code {completed.returncode}; see {log_path}"
403
+ )
404
+ return result
405
+
406
+
407
+ def run_tool_command(command: list[str], log_path: Path) -> ToolResult:
408
+ """Run one headless Designer command using the standard return-code policy."""
409
+ return _run(command, log_path)
410
+
411
+
412
+ def _prepare_designer_log(log_path: Path) -> None:
413
+ log_path.parent.mkdir(parents=True, exist_ok=True)
414
+ log_path.unlink(missing_ok=True)
415
+
416
+
417
+ def _clear_output(path: Path) -> None:
418
+ if path.is_dir():
419
+ shutil.rmtree(path)
420
+ else:
421
+ path.unlink(missing_ok=True)
422
+
423
+
424
+ def _require_non_empty_file(path: Path, label: str, log_path: Path) -> None:
425
+ if not path.is_file() or path.stat().st_size == 0:
426
+ raise ProcessStartError(
427
+ f"1C did not create non-empty {label}: {path}; see {log_path}"
428
+ )
429
+
430
+
431
+ def _require_non_empty_dump(output_dir: Path, log_path: Path) -> None:
432
+ if not output_dir.is_dir() or not any(
433
+ path.is_file() and path.stat().st_size > 0 for path in output_dir.rglob("*")
434
+ ):
435
+ raise ProcessStartError(
436
+ f"1C did not create a non-empty extension dump: {output_dir}; see {log_path}"
437
+ )
438
+
439
+
440
+ def _missing_product_extension(log_path: Path) -> bool:
441
+ try:
442
+ text = log_path.read_text(encoding="utf-8-sig")
443
+ except (OSError, UnicodeDecodeError):
444
+ return False
445
+ return any(
446
+ line.strip() in _MISSING_PRODUCT_EXTENSION_DIAGNOSTICS
447
+ for line in text.splitlines()
448
+ )
449
+
450
+
451
+ def _run_product_command(command: list[str], log_path: Path) -> ToolResult:
452
+ _prepare_designer_log(log_path)
453
+ try:
454
+ return run_tool_command(command, log_path)
455
+ except ProcessStartError as error:
456
+ if _missing_product_extension(log_path):
457
+ raise ExtensionNotInstalled(
458
+ f"The target infobase does not contain {EXTENSION_NAME}"
459
+ ) from error
460
+ hint = startup_log_hint(log_path)
461
+ if hint is not None:
462
+ raise ProcessStartError(
463
+ f"Конфигуратор 1С: {hint}; подробности: {log_path}"
464
+ ) from None
465
+ raise
466
+
467
+
468
+ def create_file_infobase_at(
469
+ designer_exe: Path, infobase_dir: Path, log_path: Path
470
+ ) -> ToolResult:
471
+ database_file = infobase_dir / "1Cv8.1CD"
472
+ if database_file.exists():
473
+ raise ProcessStartError(
474
+ f"Refusing to reuse the existing infobase at {infobase_dir}"
475
+ )
476
+ infobase_dir.parent.mkdir(parents=True, exist_ok=True)
477
+ result = _run_product_command(
478
+ create_file_infobase_at_command(designer_exe, infobase_dir, log_path),
479
+ log_path,
480
+ )
481
+ _require_non_empty_file(database_file, "1Cv8.1CD", log_path)
482
+ return result
483
+
484
+
485
+ def load_product_extension_source(
486
+ designer_exe: Path,
487
+ infobase_dir: Path,
488
+ source_dir: Path,
489
+ log_path: Path,
490
+ ) -> ToolResult:
491
+ return _run_product_command(
492
+ load_product_extension_source_command(
493
+ designer_exe, infobase_dir, source_dir, log_path
494
+ ),
495
+ log_path,
496
+ )
497
+
498
+
499
+ def dump_product_extension_cfe(
500
+ designer_exe: Path,
501
+ infobase_dir: Path,
502
+ output_cfe: Path,
503
+ log_path: Path,
504
+ ) -> ToolResult:
505
+ output_cfe.parent.mkdir(parents=True, exist_ok=True)
506
+ _clear_output(output_cfe)
507
+ result = _run_product_command(
508
+ dump_product_extension_cfe_command(
509
+ designer_exe, infobase_dir, output_cfe, log_path
510
+ ),
511
+ log_path,
512
+ )
513
+ _require_non_empty_file(output_cfe, "CFE", log_path)
514
+ return result
515
+
516
+
517
+ def dump_target_extension_files(
518
+ config: RuntimeConfig, output_dir: Path, log_path: Path
519
+ ) -> ToolResult:
520
+ output_dir.parent.mkdir(parents=True, exist_ok=True)
521
+ _clear_output(output_dir)
522
+ result = _run_product_command(
523
+ dump_target_extension_files_command(config, output_dir, log_path), log_path
524
+ )
525
+ _require_non_empty_dump(output_dir, log_path)
526
+ return result
527
+
528
+
529
+ def dump_target_extension_cfe(
530
+ config: RuntimeConfig, output_cfe: Path, log_path: Path
531
+ ) -> ToolResult:
532
+ output_cfe.parent.mkdir(parents=True, exist_ok=True)
533
+ _clear_output(output_cfe)
534
+ result = _run_product_command(
535
+ dump_target_extension_cfe_command(config, output_cfe, log_path), log_path
536
+ )
537
+ _require_non_empty_file(output_cfe, "CFE", log_path)
538
+ return result
539
+
540
+
541
+ def load_target_extension_cfe(
542
+ config: RuntimeConfig, input_cfe: Path, log_path: Path
543
+ ) -> ToolResult:
544
+ return _run_product_command(
545
+ load_target_extension_cfe_command(config, input_cfe, log_path), log_path
546
+ )
547
+
548
+
549
+ def apply_product_extension(config: RuntimeConfig, log_path: Path) -> ToolResult:
550
+ return _run_product_command(
551
+ apply_product_extension_command(config, log_path), log_path
552
+ )
553
+
554
+
555
+ def _create_empty_infobase(
556
+ config: RuntimeConfig,
557
+ infobase_dir: Path,
558
+ command: list[str],
559
+ log_path: Path,
560
+ *,
561
+ recreate: bool,
562
+ ) -> ToolResult:
563
+ _prepare_runtime_directories(config)
564
+ database_file = infobase_dir / "1Cv8.1CD"
565
+ if database_file.is_file():
566
+ if recreate:
567
+ raise ProcessStartError(
568
+ "Refusing to delete the existing infobase; move .runtime/infobase aside first"
569
+ )
570
+ return ToolResult(tuple(command), 0, log_path)
571
+
572
+ result = _run(command, log_path)
573
+ if not database_file.is_file() or database_file.stat().st_size == 0:
574
+ raise ProcessStartError(f"1C did not create {database_file}; see {log_path}")
575
+ return result
576
+
577
+
578
+ def create_empty_infobase(
579
+ config: RuntimeConfig, *, recreate: bool = False
580
+ ) -> ToolResult:
581
+ return _create_empty_infobase(
582
+ config,
583
+ config.infobase_dir,
584
+ create_infobase_command(config),
585
+ config.logs_dir / "create-infobase.log",
586
+ recreate=recreate,
587
+ )
588
+
589
+
590
+ def create_build_infobase(
591
+ config: RuntimeConfig, *, recreate: bool = False
592
+ ) -> ToolResult:
593
+ return _create_empty_infobase(
594
+ config,
595
+ config.build_infobase_dir,
596
+ create_build_infobase_command(config),
597
+ config.logs_dir / "create-build-infobase.log",
598
+ recreate=recreate,
599
+ )
600
+
601
+
602
+ def build_external_processor_from_files(
603
+ config: RuntimeConfig,
604
+ source_xml: Path,
605
+ output_epf: Path,
606
+ log_path: Path,
607
+ ) -> ToolResult:
608
+ _prepare_runtime_directories(config)
609
+ if not source_xml.is_file():
610
+ raise ProcessStartError(f"External processor source is missing: {source_xml}")
611
+ if not (config.build_infobase_dir / "1Cv8.1CD").is_file():
612
+ raise ProcessStartError("The dedicated build infobase has not been created")
613
+ output_epf.parent.mkdir(parents=True, exist_ok=True)
614
+ log_path.parent.mkdir(parents=True, exist_ok=True)
615
+ output_epf.unlink(missing_ok=True)
616
+ result = _run(
617
+ build_external_processor_from_files_command(
618
+ config, source_xml, output_epf, log_path
619
+ ),
620
+ log_path,
621
+ )
622
+ if not output_epf.is_file() or output_epf.stat().st_size == 0:
623
+ raise ProcessStartError(f"1C did not build {output_epf}; see {log_path}")
624
+ return result
625
+
626
+
627
+ def build_kernel(config: RuntimeConfig) -> ToolResult:
628
+ _prepare_runtime_directories(config)
629
+ source = config.workspace / "onec" / "Kernel" / "Kernel.xml"
630
+ if not source.is_file():
631
+ raise ProcessStartError(f"Kernel source is missing: {source}")
632
+ if not (config.build_infobase_dir / "1Cv8.1CD").is_file():
633
+ raise ProcessStartError("The dedicated build infobase has not been created")
634
+
635
+ command = build_external_processor_command(config)
636
+ log_path = config.logs_dir / "build-kernel.log"
637
+ result = _run(command, log_path)
638
+ if not config.kernel_epf.is_file() or config.kernel_epf.stat().st_size == 0:
639
+ raise ProcessStartError(f"1C did not build {config.kernel_epf}; see {log_path}")
640
+ return result
641
+
642
+
643
+ def build_worker(config: RuntimeConfig) -> ToolResult:
644
+ _prepare_runtime_directories(config)
645
+ source = config.workspace / "onec" / "Worker" / "Ext" / "ObjectModule.bsl"
646
+ if not source.is_file():
647
+ raise ProcessStartError(f"Worker source is missing: {source}")
648
+ from onec_runtime.worker_epf import build_worker_epf
649
+
650
+ source_text = source.read_text(encoding="utf-8-sig")
651
+ build_worker_epf(source_text, config.worker_epf)
652
+ command = (
653
+ "in-process-worker-epf",
654
+ str(source),
655
+ str(config.worker_epf),
656
+ )
657
+ log_path = config.logs_dir / "build-worker.log"
658
+ log_path.write_text(
659
+ "PASS\n"
660
+ f"source_sha256={sha256(source_text.encode('utf-8')).hexdigest()}\n"
661
+ f"artifact_sha256={sha256(config.worker_epf.read_bytes()).hexdigest()}\n",
662
+ encoding="utf-8",
663
+ newline="\n",
664
+ )
665
+ return ToolResult(command, 0, log_path)
666
+
667
+
668
+ def build_runtime_extension(
669
+ config: RuntimeConfig,
670
+ ) -> tuple[ToolResult, ToolResult]:
671
+ _prepare_runtime_directories(config)
672
+ source = config.workspace / "onec" / EXTENSION_NAME
673
+ if not (source / "Configuration.xml").is_file():
674
+ raise ProcessStartError(
675
+ f"Runtime extension source is missing: {source}"
676
+ )
677
+ if not (config.build_infobase_dir / "1Cv8.1CD").is_file():
678
+ raise ProcessStartError("The dedicated build infobase has not been created")
679
+ output_cfe = config.build_dir / f"{EXTENSION_NAME}.cfe"
680
+ output_cfe.unlink(missing_ok=True)
681
+ load_log = config.logs_dir / "load-extension-source.log"
682
+ loaded = _run(
683
+ load_extension_source_command(config, source),
684
+ load_log,
685
+ )
686
+ dump_log = config.logs_dir / "dump-extension.log"
687
+ dumped = _run(dump_extension_command(config, output_cfe), dump_log)
688
+ if not output_cfe.is_file() or output_cfe.stat().st_size == 0:
689
+ raise ProcessStartError(f"1C did not build {output_cfe}")
690
+ return loaded, dumped
691
+
692
+
693
+ def deploy_runtime_extension(
694
+ config: RuntimeConfig,
695
+ ) -> tuple[ToolResult, ToolResult]:
696
+ output_cfe = config.build_dir / f"{EXTENSION_NAME}.cfe"
697
+ if not output_cfe.is_file() or output_cfe.stat().st_size == 0:
698
+ raise ProcessStartError(f"{output_cfe.name} has not been built")
699
+ if not (config.infobase_dir / "1Cv8.1CD").is_file():
700
+ raise ProcessStartError("The dedicated runtime infobase has not been created")
701
+ loaded = _run(
702
+ deploy_extension_command(config),
703
+ config.logs_dir / "load-extension.log",
704
+ )
705
+ updated = _run(
706
+ apply_extension_command(config),
707
+ config.logs_dir / "apply-extension.log",
708
+ )
709
+ return loaded, updated
710
+
711
+
712
+ def deploy_runtime_extension_from_source(
713
+ config: RuntimeConfig,
714
+ ) -> tuple[ToolResult, ToolResult]:
715
+ source = config.workspace / "onec" / EXTENSION_NAME
716
+ if not (source / "Configuration.xml").is_file():
717
+ raise ProcessStartError(
718
+ f"Runtime extension source is missing: {source}"
719
+ )
720
+ if not (config.infobase_dir / "1Cv8.1CD").is_file():
721
+ raise ProcessStartError("The dedicated runtime infobase has not been created")
722
+ loaded = _run(
723
+ load_target_extension_source_command(config, source),
724
+ config.logs_dir / "load-target-extension-source.log",
725
+ )
726
+ updated = _run(
727
+ apply_target_extension_source_command(config, source),
728
+ config.logs_dir / "apply-extension-source.log",
729
+ )
730
+ return loaded, updated