dirac-lang 0.1.19 → 0.1.21
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.
- package/dist/{chunk-QMFCOZ5D.js → chunk-JRNDLSQJ.js} +1 -1
- package/dist/{chunk-GR6KWGCI.js → chunk-OS7DII2I.js} +58 -22
- package/dist/cli.js +3 -3
- package/dist/index.js +2 -2
- package/dist/{interpreter-JTOTDC46.js → interpreter-WSRBK3KI.js} +1 -1
- package/dist/test-runner.js +1 -1
- package/package.json +1 -1
- package/src/tags/defvar.ts +4 -3
- package/src/tags/output.ts +33 -3
- package/src/tags/system.ts +25 -2
- package/tests/generate-dirac.test.di +22 -0
- package/tests/output-file.test.di +19 -0
- package/tests/system-background.test.di +39 -0
|
@@ -138,7 +138,7 @@ function serializeToXml(children) {
|
|
|
138
138
|
xml += " />";
|
|
139
139
|
} else {
|
|
140
140
|
xml += ">";
|
|
141
|
-
if (child.text) {
|
|
141
|
+
if (child.text && child.children.length === 0) {
|
|
142
142
|
xml += escapeXml(child.text);
|
|
143
143
|
}
|
|
144
144
|
if (child.children.length > 0) {
|
|
@@ -196,7 +196,29 @@ function executeAssign(session, element) {
|
|
|
196
196
|
}
|
|
197
197
|
|
|
198
198
|
// src/tags/output.ts
|
|
199
|
+
import * as fs from "fs";
|
|
200
|
+
import * as path from "path";
|
|
199
201
|
async function executeOutput(session, element) {
|
|
202
|
+
const fileAttr = element.attributes?.file;
|
|
203
|
+
const filePath = fileAttr ? substituteAttribute(session, fileAttr) : null;
|
|
204
|
+
if (filePath) {
|
|
205
|
+
let content = "";
|
|
206
|
+
if (element.children && element.children.length > 0) {
|
|
207
|
+
const prevOutput = session.output;
|
|
208
|
+
session.output = [];
|
|
209
|
+
await integrateChildren(session, element);
|
|
210
|
+
content = session.output.join("");
|
|
211
|
+
session.output = prevOutput;
|
|
212
|
+
} else if (element.text) {
|
|
213
|
+
content = substituteVariables(session, element.text);
|
|
214
|
+
}
|
|
215
|
+
const dir = path.dirname(filePath);
|
|
216
|
+
if (dir !== "." && !fs.existsSync(dir)) {
|
|
217
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
218
|
+
}
|
|
219
|
+
fs.appendFileSync(filePath, content + "\n", "utf8");
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
200
222
|
if (element.children && element.children.length > 0) {
|
|
201
223
|
await integrateChildren(session, element);
|
|
202
224
|
return;
|
|
@@ -397,12 +419,12 @@ async function executeIf(session, element) {
|
|
|
397
419
|
const condition = await evaluatePredicate(session, conditionElement);
|
|
398
420
|
if (condition) {
|
|
399
421
|
if (thenElement) {
|
|
400
|
-
const { integrateChildren: integrateChildren2 } = await import("./interpreter-
|
|
422
|
+
const { integrateChildren: integrateChildren2 } = await import("./interpreter-WSRBK3KI.js");
|
|
401
423
|
await integrateChildren2(session, thenElement);
|
|
402
424
|
}
|
|
403
425
|
} else {
|
|
404
426
|
if (elseElement) {
|
|
405
|
-
const { integrateChildren: integrateChildren2 } = await import("./interpreter-
|
|
427
|
+
const { integrateChildren: integrateChildren2 } = await import("./interpreter-WSRBK3KI.js");
|
|
406
428
|
await integrateChildren2(session, elseElement);
|
|
407
429
|
}
|
|
408
430
|
}
|
|
@@ -415,7 +437,7 @@ async function evaluatePredicate(session, predicateElement) {
|
|
|
415
437
|
return await evaluateCondition(session, predicateElement);
|
|
416
438
|
}
|
|
417
439
|
const outputLengthBefore = session.output.length;
|
|
418
|
-
const { integrate: integrate2 } = await import("./interpreter-
|
|
440
|
+
const { integrate: integrate2 } = await import("./interpreter-WSRBK3KI.js");
|
|
419
441
|
await integrate2(session, predicateElement);
|
|
420
442
|
const newOutputChunks = session.output.slice(outputLengthBefore);
|
|
421
443
|
const result = newOutputChunks.join("").trim();
|
|
@@ -438,11 +460,11 @@ async function evaluateCondition(session, condElement) {
|
|
|
438
460
|
}
|
|
439
461
|
const outputLengthBefore = session.output.length;
|
|
440
462
|
const args = [];
|
|
441
|
-
const { integrate: integrate2 } = await import("./interpreter-
|
|
463
|
+
const { integrate: integrate2 } = await import("./interpreter-WSRBK3KI.js");
|
|
442
464
|
for (const child of condElement.children) {
|
|
443
465
|
if (child.tag.toLowerCase() === "arg") {
|
|
444
466
|
const argOutputStart = session.output.length;
|
|
445
|
-
const { integrateChildren: integrateChildren2 } = await import("./interpreter-
|
|
467
|
+
const { integrateChildren: integrateChildren2 } = await import("./interpreter-WSRBK3KI.js");
|
|
446
468
|
await integrateChildren2(session, child);
|
|
447
469
|
const newChunks = session.output.slice(argOutputStart);
|
|
448
470
|
const argValue = newChunks.join("");
|
|
@@ -857,11 +879,11 @@ ${expr}
|
|
|
857
879
|
for (const v of session.variables) {
|
|
858
880
|
context[v.name] = v.value;
|
|
859
881
|
}
|
|
860
|
-
const { default:
|
|
861
|
-
const { default:
|
|
882
|
+
const { default: fs3 } = await import("fs");
|
|
883
|
+
const { default: path2 } = await import("path");
|
|
862
884
|
const { fileURLToPath } = await import("url");
|
|
863
|
-
context.fs =
|
|
864
|
-
context.path =
|
|
885
|
+
context.fs = fs3;
|
|
886
|
+
context.path = path2;
|
|
865
887
|
context.__dirname = process.cwd();
|
|
866
888
|
context.getParams = () => {
|
|
867
889
|
const params = session.parameterStack[session.parameterStack.length - 1];
|
|
@@ -915,13 +937,13 @@ ${diracCode}
|
|
|
915
937
|
|
|
916
938
|
// src/tags/import.ts
|
|
917
939
|
import { readFileSync } from "fs";
|
|
918
|
-
import { resolve, dirname } from "path";
|
|
940
|
+
import { resolve, dirname as dirname2 } from "path";
|
|
919
941
|
async function executeImport(session, element) {
|
|
920
942
|
const src = element.attributes.src;
|
|
921
943
|
if (!src) {
|
|
922
944
|
throw new Error("<import> requires src attribute");
|
|
923
945
|
}
|
|
924
|
-
const currentDir = session.currentFile ?
|
|
946
|
+
const currentDir = session.currentFile ? dirname2(session.currentFile) : process.cwd();
|
|
925
947
|
const importPath = resolve(currentDir, src);
|
|
926
948
|
if (session.debug) {
|
|
927
949
|
console.error(`[IMPORT] Loading: ${importPath}`);
|
|
@@ -1046,7 +1068,7 @@ async function executeExpr(session, element) {
|
|
|
1046
1068
|
}
|
|
1047
1069
|
|
|
1048
1070
|
// src/tags/system.ts
|
|
1049
|
-
import { exec } from "child_process";
|
|
1071
|
+
import { exec, spawn } from "child_process";
|
|
1050
1072
|
import { promisify } from "util";
|
|
1051
1073
|
var execAsync = promisify(exec);
|
|
1052
1074
|
async function executeSystem(session, element) {
|
|
@@ -1068,8 +1090,22 @@ async function executeSystem(session, element) {
|
|
|
1068
1090
|
if (!command.trim()) {
|
|
1069
1091
|
return;
|
|
1070
1092
|
}
|
|
1093
|
+
const backgroundAttr = element.attributes?.background;
|
|
1094
|
+
const isBackground = backgroundAttr === "true";
|
|
1071
1095
|
if (session.debug) {
|
|
1072
|
-
console.error(`[SYSTEM] Executing: ${command}`);
|
|
1096
|
+
console.error(`[SYSTEM] Executing${isBackground ? " (background)" : ""}: ${command}`);
|
|
1097
|
+
}
|
|
1098
|
+
if (isBackground) {
|
|
1099
|
+
const child = spawn(command, {
|
|
1100
|
+
detached: true,
|
|
1101
|
+
stdio: "ignore",
|
|
1102
|
+
shell: true
|
|
1103
|
+
});
|
|
1104
|
+
child.unref();
|
|
1105
|
+
if (session.debug) {
|
|
1106
|
+
console.error(`[SYSTEM] Background process started with PID: ${child.pid}`);
|
|
1107
|
+
}
|
|
1108
|
+
return;
|
|
1073
1109
|
}
|
|
1074
1110
|
try {
|
|
1075
1111
|
const { stdout, stderr } = await execAsync(command, {
|
|
@@ -1103,13 +1139,13 @@ async function executeRequireModule(session, element) {
|
|
|
1103
1139
|
}
|
|
1104
1140
|
|
|
1105
1141
|
// src/tags/tag-check.ts
|
|
1106
|
-
import
|
|
1142
|
+
import fs2 from "fs";
|
|
1107
1143
|
import yaml from "js-yaml";
|
|
1108
1144
|
var SIMILARITY_CUTOFF = 0.75;
|
|
1109
1145
|
function getEmbeddingServerConfig() {
|
|
1110
1146
|
try {
|
|
1111
1147
|
const configPath = process.env.DIRAC_CONFIG || "config.yml";
|
|
1112
|
-
const config = yaml.load(
|
|
1148
|
+
const config = yaml.load(fs2.readFileSync(configPath, "utf8"));
|
|
1113
1149
|
const host = config.embeddingServer?.host || "localhost";
|
|
1114
1150
|
const port = config.embeddingServer?.port || 11434;
|
|
1115
1151
|
const model = config.embeddingServer?.model || "embeddinggemma";
|
|
@@ -1245,7 +1281,7 @@ async function executeTagCheck(session, element) {
|
|
|
1245
1281
|
const executeTag = correctedTag || tagName;
|
|
1246
1282
|
console.error(`[tag-check] Executing <${executeTag}/> as all checks passed and execute=true.`);
|
|
1247
1283
|
const elementToExecute = correctedTag ? { ...child, tag: correctedTag } : child;
|
|
1248
|
-
const { integrate: integrate2 } = await import("./interpreter-
|
|
1284
|
+
const { integrate: integrate2 } = await import("./interpreter-WSRBK3KI.js");
|
|
1249
1285
|
await integrate2(session, elementToExecute);
|
|
1250
1286
|
}
|
|
1251
1287
|
}
|
|
@@ -1254,7 +1290,7 @@ async function executeTagCheck(session, element) {
|
|
|
1254
1290
|
// src/tags/throw.ts
|
|
1255
1291
|
async function executeThrow(session, element) {
|
|
1256
1292
|
const exceptionName = element.attributes?.name || "exception";
|
|
1257
|
-
const { integrateChildren: integrateChildren2 } = await import("./interpreter-
|
|
1293
|
+
const { integrateChildren: integrateChildren2 } = await import("./interpreter-WSRBK3KI.js");
|
|
1258
1294
|
const exceptionDom = {
|
|
1259
1295
|
tag: "exception-content",
|
|
1260
1296
|
attributes: { name: exceptionName },
|
|
@@ -1267,7 +1303,7 @@ async function executeThrow(session, element) {
|
|
|
1267
1303
|
// src/tags/try.ts
|
|
1268
1304
|
async function executeTry(session, element) {
|
|
1269
1305
|
setExceptionBoundary(session);
|
|
1270
|
-
const { integrateChildren: integrateChildren2 } = await import("./interpreter-
|
|
1306
|
+
const { integrateChildren: integrateChildren2 } = await import("./interpreter-WSRBK3KI.js");
|
|
1271
1307
|
await integrateChildren2(session, element);
|
|
1272
1308
|
unsetExceptionBoundary(session);
|
|
1273
1309
|
}
|
|
@@ -1277,7 +1313,7 @@ async function executeCatch(session, element) {
|
|
|
1277
1313
|
const exceptionName = element.attributes?.name || "exception";
|
|
1278
1314
|
const caughtCount = lookupException(session, exceptionName);
|
|
1279
1315
|
if (caughtCount > 0) {
|
|
1280
|
-
const { integrateChildren: integrateChildren2 } = await import("./interpreter-
|
|
1316
|
+
const { integrateChildren: integrateChildren2 } = await import("./interpreter-WSRBK3KI.js");
|
|
1281
1317
|
await integrateChildren2(session, element);
|
|
1282
1318
|
}
|
|
1283
1319
|
flushCurrentException(session);
|
|
@@ -1286,7 +1322,7 @@ async function executeCatch(session, element) {
|
|
|
1286
1322
|
// src/tags/exception.ts
|
|
1287
1323
|
async function executeException(session, element) {
|
|
1288
1324
|
const exceptions = getCurrentExceptions(session);
|
|
1289
|
-
const { integrateChildren: integrateChildren2 } = await import("./interpreter-
|
|
1325
|
+
const { integrateChildren: integrateChildren2 } = await import("./interpreter-WSRBK3KI.js");
|
|
1290
1326
|
for (const exceptionDom of exceptions) {
|
|
1291
1327
|
await integrateChildren2(session, exceptionDom);
|
|
1292
1328
|
}
|
|
@@ -1426,7 +1462,7 @@ async function executeForeach(session, element) {
|
|
|
1426
1462
|
const parser2 = new DiracParser2();
|
|
1427
1463
|
try {
|
|
1428
1464
|
const fromElement = parser2.parse(fromAttr);
|
|
1429
|
-
const { integrate: integrate2 } = await import("./interpreter-
|
|
1465
|
+
const { integrate: integrate2 } = await import("./interpreter-WSRBK3KI.js");
|
|
1430
1466
|
await integrate2(session, fromElement);
|
|
1431
1467
|
} catch (e) {
|
|
1432
1468
|
session.output = savedOutput;
|
package/dist/cli.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
execute
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-JRNDLSQJ.js";
|
|
5
|
+
import "./chunk-OS7DII2I.js";
|
|
6
6
|
import "./chunk-HRHAMPOB.js";
|
|
7
7
|
import "./chunk-E7PWEMZA.js";
|
|
8
8
|
import "./chunk-52ED23DR.js";
|
|
@@ -13,7 +13,7 @@ import "dotenv/config";
|
|
|
13
13
|
// package.json
|
|
14
14
|
var package_default = {
|
|
15
15
|
name: "dirac-lang",
|
|
16
|
-
version: "0.1.
|
|
16
|
+
version: "0.1.21",
|
|
17
17
|
description: "LLM-Augmented Declarative Execution",
|
|
18
18
|
type: "module",
|
|
19
19
|
main: "dist/index.js",
|
package/dist/index.js
CHANGED
|
@@ -2,10 +2,10 @@ import {
|
|
|
2
2
|
createLLMAdapter,
|
|
3
3
|
execute,
|
|
4
4
|
executeUserCommand
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-JRNDLSQJ.js";
|
|
6
6
|
import {
|
|
7
7
|
integrate
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-OS7DII2I.js";
|
|
9
9
|
import {
|
|
10
10
|
DiracParser
|
|
11
11
|
} from "./chunk-HRHAMPOB.js";
|
package/dist/test-runner.js
CHANGED
package/package.json
CHANGED
package/src/tags/defvar.ts
CHANGED
|
@@ -86,12 +86,13 @@ function serializeToXml(children: DiracElement[]): string {
|
|
|
86
86
|
} else {
|
|
87
87
|
xml += '>';
|
|
88
88
|
|
|
89
|
-
//
|
|
90
|
-
if
|
|
89
|
+
// Only add text content if there are no children
|
|
90
|
+
// (if there are children, text is stored in text node children)
|
|
91
|
+
if (child.text && child.children.length === 0) {
|
|
91
92
|
xml += escapeXml(child.text);
|
|
92
93
|
}
|
|
93
94
|
|
|
94
|
-
// Add children
|
|
95
|
+
// Add children (which may include text nodes)
|
|
95
96
|
if (child.children.length > 0) {
|
|
96
97
|
xml += serializeToXml(child.children);
|
|
97
98
|
}
|
package/src/tags/output.ts
CHANGED
|
@@ -4,17 +4,47 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import type { DiracSession, DiracElement } from '../types/index.js';
|
|
7
|
-
import { emit, substituteVariables } from '../runtime/session.js';
|
|
7
|
+
import { emit, substituteVariables, substituteAttribute } from '../runtime/session.js';
|
|
8
8
|
import { integrateChildren } from '../runtime/interpreter.js';
|
|
9
|
+
import * as fs from 'fs';
|
|
10
|
+
import * as path from 'path';
|
|
9
11
|
|
|
10
12
|
export async function executeOutput(session: DiracSession, element: DiracElement): Promise<void> {
|
|
11
|
-
|
|
13
|
+
const fileAttr = element.attributes?.file;
|
|
14
|
+
const filePath = fileAttr ? substituteAttribute(session, fileAttr) : null;
|
|
15
|
+
|
|
16
|
+
// If writing to a file, collect content first
|
|
17
|
+
if (filePath) {
|
|
18
|
+
let content = '';
|
|
19
|
+
|
|
20
|
+
if (element.children && element.children.length > 0) {
|
|
21
|
+
// Capture output from children
|
|
22
|
+
const prevOutput = session.output;
|
|
23
|
+
session.output = [];
|
|
24
|
+
await integrateChildren(session, element);
|
|
25
|
+
content = session.output.join('');
|
|
26
|
+
session.output = prevOutput;
|
|
27
|
+
} else if (element.text) {
|
|
28
|
+
content = substituteVariables(session, element.text);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Ensure directory exists
|
|
32
|
+
const dir = path.dirname(filePath);
|
|
33
|
+
if (dir !== '.' && !fs.existsSync(dir)) {
|
|
34
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Append to file
|
|
38
|
+
fs.appendFileSync(filePath, content + '\n', 'utf8');
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Normal output to stdout
|
|
12
43
|
if (element.children && element.children.length > 0) {
|
|
13
44
|
await integrateChildren(session, element);
|
|
14
45
|
return;
|
|
15
46
|
}
|
|
16
47
|
|
|
17
|
-
// If only text content, use it (with variable substitution)
|
|
18
48
|
if (element.text) {
|
|
19
49
|
const content = substituteVariables(session, element.text);
|
|
20
50
|
emit(session, content);
|
package/src/tags/system.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import type { DiracSession, DiracElement } from '../types/index.js';
|
|
7
7
|
import { substituteVariables, emit } from '../runtime/session.js';
|
|
8
|
-
import { exec } from 'child_process';
|
|
8
|
+
import { exec, spawn } from 'child_process';
|
|
9
9
|
import { promisify } from 'util';
|
|
10
10
|
import { integrate } from '../runtime/interpreter.js';
|
|
11
11
|
|
|
@@ -43,10 +43,33 @@ export async function executeSystem(session: DiracSession, element: DiracElement
|
|
|
43
43
|
return;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
// Check for background attribute
|
|
47
|
+
const backgroundAttr = element.attributes?.background;
|
|
48
|
+
const isBackground = backgroundAttr === 'true';
|
|
49
|
+
|
|
46
50
|
if (session.debug) {
|
|
47
|
-
console.error(`[SYSTEM] Executing: ${command}`);
|
|
51
|
+
console.error(`[SYSTEM] Executing${isBackground ? ' (background)' : ''}: ${command}`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Background mode - spawn and don't wait
|
|
55
|
+
if (isBackground) {
|
|
56
|
+
const child = spawn(command, {
|
|
57
|
+
detached: true,
|
|
58
|
+
stdio: 'ignore',
|
|
59
|
+
shell: true,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// Unref so parent can exit without waiting
|
|
63
|
+
child.unref();
|
|
64
|
+
|
|
65
|
+
if (session.debug) {
|
|
66
|
+
console.error(`[SYSTEM] Background process started with PID: ${child.pid}`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return;
|
|
48
70
|
}
|
|
49
71
|
|
|
72
|
+
// Foreground mode - wait for completion (original behavior)
|
|
50
73
|
try {
|
|
51
74
|
const { stdout, stderr } = await execAsync(command, {
|
|
52
75
|
encoding: 'utf-8',
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<!-- TEST: generate_and_execute_dirac -->
|
|
2
|
+
<!-- EXPECT: Generated file executed
|
|
3
|
+
Result: 42 -->
|
|
4
|
+
<dirac>
|
|
5
|
+
<!-- Define a DIRAC script as literal -->
|
|
6
|
+
<defvar name="generated_script" literal="true" trim="false">
|
|
7
|
+
<dirac>
|
|
8
|
+
<defvar name="value">42</defvar>
|
|
9
|
+
<output>Result: <variable name="value" /></output>
|
|
10
|
+
</dirac>
|
|
11
|
+
</defvar>
|
|
12
|
+
|
|
13
|
+
<!-- Write to file -->
|
|
14
|
+
<output file="temp-generated.di"><variable name="generated_script" /></output>
|
|
15
|
+
|
|
16
|
+
<!-- Execute the generated script -->
|
|
17
|
+
<output>Generated file executed</output>
|
|
18
|
+
<system shell="bash">
|
|
19
|
+
node dist/cli.js temp-generated.di
|
|
20
|
+
rm temp-generated.di
|
|
21
|
+
</system>
|
|
22
|
+
</dirac>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<!-- TEST: output_file_basic -->
|
|
2
|
+
<!-- EXPECT: stdout output
|
|
3
|
+
File written -->
|
|
4
|
+
<dirac>
|
|
5
|
+
<!-- Write to file -->
|
|
6
|
+
<output file="output-test-temp.txt">File line 1</output>
|
|
7
|
+
<output file="output-test-temp.txt">File line 2</output>
|
|
8
|
+
|
|
9
|
+
<!-- Output to stdout to verify test runs -->
|
|
10
|
+
<output>stdout output</output>
|
|
11
|
+
|
|
12
|
+
<!-- Use system to verify file and clean up -->
|
|
13
|
+
<system shell="bash">
|
|
14
|
+
if [ -f output-test-temp.txt ]; then
|
|
15
|
+
echo "File written"
|
|
16
|
+
rm output-test-temp.txt
|
|
17
|
+
fi
|
|
18
|
+
</system>
|
|
19
|
+
</dirac>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<dirac>
|
|
2
|
+
<output>Testing background processes with loop...</output>
|
|
3
|
+
|
|
4
|
+
<!-- Setup: Clean up old test files -->
|
|
5
|
+
<system>rm -f /tmp/dirac-bg-counter.txt</system>
|
|
6
|
+
|
|
7
|
+
<!-- Start a background process that writes incrementing numbers -->
|
|
8
|
+
<system background="true">(for i in 1 2 3 4 5; do echo "Count: $i"; sleep 1; done > /tmp/dirac-bg-counter.txt) &</system>
|
|
9
|
+
<output>✓ Background counter started</output>
|
|
10
|
+
|
|
11
|
+
<!-- This executes immediately without waiting -->
|
|
12
|
+
<output>✓ DIRAC continuing without blocking</output>
|
|
13
|
+
|
|
14
|
+
<!-- Wait a moment for background process to start writing -->
|
|
15
|
+
<system>sleep 2</system>
|
|
16
|
+
|
|
17
|
+
<!-- Read the results in a loop (3 times, showing progressive output) -->
|
|
18
|
+
<loop count="3">
|
|
19
|
+
<system>wc -l /tmp/dirac-bg-counter.txt 2>/dev/null || echo "0"</system>
|
|
20
|
+
<output>Check: Background file now has lines</output>
|
|
21
|
+
<system>sleep 1</system>
|
|
22
|
+
</loop>
|
|
23
|
+
|
|
24
|
+
<!-- Give background process time to finish all 5 counts -->
|
|
25
|
+
<system>sleep 2</system>
|
|
26
|
+
|
|
27
|
+
<!-- Verify final result contains all 5 counts -->
|
|
28
|
+
<system>wc -l /tmp/dirac-bg-counter.txt</system>
|
|
29
|
+
<output>✓ Background process completed</output>
|
|
30
|
+
|
|
31
|
+
<!-- Verify content -->
|
|
32
|
+
<system>grep -c "Count:" /tmp/dirac-bg-counter.txt</system>
|
|
33
|
+
<output>✓ Found all count entries</output>
|
|
34
|
+
|
|
35
|
+
<!-- Cleanup -->
|
|
36
|
+
<system>rm -f /tmp/dirac-bg-counter.txt</system>
|
|
37
|
+
|
|
38
|
+
<output>✓ Background process with loop test passed</output>
|
|
39
|
+
</dirac>
|