@tdk-landscape/tdk-cli-core 1.3.124 → 1.3.125

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.
@@ -0,0 +1,131 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { dirname, join, normalize } from "node:path";
3
+ import { formatCount } from "./formatting.js";
4
+ import { findProjectRoot } from "./paths.js";
5
+ export function findPrivateStarlarkLoadExports(content) {
6
+ const privateExports = new Set();
7
+ const loadCallPattern = /^load\s*\(([\s\S]*?)\)/gm;
8
+ for (const loadMatch of content.matchAll(loadCallPattern)) {
9
+ const args = loadMatch[1] ?? "";
10
+ const quotedValuePattern = /["']([^"']+)["']/g;
11
+ const quotedValues = Array.from(args.matchAll(quotedValuePattern), (match) => match[1]);
12
+ // First quoted arg is the module path. Later quoted args are exported names
13
+ // or alias targets, and Starlark refuses to export names beginning with "_".
14
+ for (const value of quotedValues.slice(1)) {
15
+ if (value.startsWith("_")) {
16
+ privateExports.add(value);
17
+ }
18
+ }
19
+ }
20
+ return Array.from(privateExports).sort();
21
+ }
22
+ export function resolveStarlarkLoadTarget(file, modulePath, projectRoot) {
23
+ if (modulePath === "ext://tdk-cli") {
24
+ return join(projectRoot, ".tdk", ".tdk-out", "tdk-cli-ext", "Tiltfile");
25
+ }
26
+ if (modulePath.startsWith(".") || (!modulePath.includes("://") && !modulePath.startsWith("@"))) {
27
+ return normalize(join(dirname(file), modulePath));
28
+ }
29
+ return null;
30
+ }
31
+ export function findMissingRelativeStarlarkLoads(file, content, projectRoot) {
32
+ const missing = [];
33
+ const loadCallPattern = /^load\s*\(([\s\S]*?)\)/gm;
34
+ for (const loadMatch of content.matchAll(loadCallPattern)) {
35
+ const args = loadMatch[1] ?? "";
36
+ const moduleMatch = args.match(/["']([^"']+)["']/);
37
+ const modulePath = moduleMatch?.[1];
38
+ if (!modulePath) {
39
+ continue;
40
+ }
41
+ const resolved = resolveStarlarkLoadTarget(file, modulePath, projectRoot);
42
+ if (!resolved) {
43
+ continue;
44
+ }
45
+ if (!existsSync(resolved)) {
46
+ missing.push(`${file}: ${modulePath} -> ${resolved}`);
47
+ }
48
+ }
49
+ return missing;
50
+ }
51
+ export function findRelativeStarlarkLoadTargets(file, content, projectRoot) {
52
+ const targets = [];
53
+ const loadCallPattern = /^load\s*\(([\s\S]*?)\)/gm;
54
+ for (const loadMatch of content.matchAll(loadCallPattern)) {
55
+ const args = loadMatch[1] ?? "";
56
+ const moduleMatch = args.match(/["']([^"']+)["']/);
57
+ const modulePath = moduleMatch?.[1];
58
+ if (modulePath) {
59
+ const target = resolveStarlarkLoadTarget(file, modulePath, projectRoot);
60
+ if (target) {
61
+ targets.push(target);
62
+ }
63
+ }
64
+ }
65
+ return targets;
66
+ }
67
+ export function collectReachableStarlarkFiles(entryFile, projectRoot) {
68
+ const visited = new Set();
69
+ const pending = [entryFile];
70
+ while (pending.length > 0) {
71
+ const file = pending.pop();
72
+ if (!file || visited.has(file) || !existsSync(file)) {
73
+ continue;
74
+ }
75
+ visited.add(file);
76
+ const content = readFileSync(file, "utf-8");
77
+ for (const target of findRelativeStarlarkLoadTargets(file, content, projectRoot)) {
78
+ if (!visited.has(target)) {
79
+ pending.push(target);
80
+ }
81
+ }
82
+ }
83
+ return Array.from(visited).sort();
84
+ }
85
+ export function checkStarlarkLoadExports() {
86
+ const projectRoot = findProjectRoot() ?? process.cwd();
87
+ const entryFile = join(projectRoot, ".tdk", ".tdk-out", "Tiltfile");
88
+ if (!existsSync(entryFile)) {
89
+ return {
90
+ name: "Starlark Load Exports",
91
+ didPass: true,
92
+ isSkipped: true,
93
+ message: "No generated Tiltfile to check",
94
+ };
95
+ }
96
+ const privateExportProblems = [];
97
+ const missingLoadProblems = [];
98
+ const reachableFiles = collectReachableStarlarkFiles(entryFile, projectRoot);
99
+ for (const file of reachableFiles) {
100
+ const content = readFileSync(file, "utf-8");
101
+ const privateExports = findPrivateStarlarkLoadExports(content);
102
+ if (privateExports.length > 0) {
103
+ privateExportProblems.push(`${file}: ${privateExports.join(", ")}`);
104
+ }
105
+ for (const missingLoad of findMissingRelativeStarlarkLoads(file, content, projectRoot)) {
106
+ missingLoadProblems.push(missingLoad);
107
+ }
108
+ }
109
+ if (privateExportProblems.length === 0 && missingLoadProblems.length === 0) {
110
+ const fileCount = formatCount(reachableFiles.length, "reachable Starlark file");
111
+ return {
112
+ name: "Starlark Load Exports",
113
+ didPass: true,
114
+ message: `${fileCount} ${reachableFiles.length === 1 ? "has" : "have"} valid load exports and paths`,
115
+ };
116
+ }
117
+ const sections = [];
118
+ if (privateExportProblems.length > 0) {
119
+ sections.push(`Private exported symbols:\n ${privateExportProblems.join("\n ")}`);
120
+ }
121
+ if (missingLoadProblems.length > 0) {
122
+ sections.push(`Missing relative load targets:\n ${missingLoadProblems.join("\n ")}`);
123
+ }
124
+ return {
125
+ name: "Starlark Load Exports",
126
+ didPass: false,
127
+ message: `Starlark load() issues will stop Tilt before services start:\n ${sections.join("\n\n ")}`,
128
+ fix: "Regenerate with a current TDK (`tdk config regenerate`). If the issue remains, rename loaded symbols without leading underscores and update stale load paths.",
129
+ };
130
+ }
131
+ //# sourceMappingURL=doctor-starlark.js.map
@@ -1,6 +1,7 @@
1
1
  import { randomBytes } from "node:crypto";
2
2
  import { existsSync, readFileSync, writeFileSync } from "node:fs";
3
3
  import { join } from "node:path";
4
+ import { writeTextFileAtomic } from "./atomic-write.js";
4
5
  const REQUIRED_ENV_VARS = [
5
6
  {
6
7
  name: "VERDACCIO_URL_DOCKER",
@@ -180,10 +181,26 @@ export function validateEnvFile(projectRoot) {
180
181
  return result;
181
182
  }
182
183
  /**
183
- * Appends the keys a newer CLI expects to an existing .env, without touching or rotating anything already there (an existing
184
- * DB_PASSWORD must survive, or the database volume stops accepting it). Creates the file when it is missing.
184
+ * Replaces the value in one parsed assignment while preserving its prefix, inline comment, and line ending.
185
+ * The caller only uses this for assignments whose parsed value is empty or whitespace.
186
+ */
187
+ function replaceEmptyEnvValue(line, name, value) {
188
+ const parsed = parseEnv(line);
189
+ if (!parsed.has(name))
190
+ return line;
191
+ const equalsIndex = line.indexOf("=");
192
+ if (equalsIndex < 0)
193
+ return line;
194
+ const rawValue = line.slice(equalsIndex + 1);
195
+ const commentIndex = rawValue.search(/\s#/);
196
+ const comment = commentIndex < 0 ? "" : rawValue.slice(commentIndex);
197
+ return line.slice(0, equalsIndex + 1) + value + comment;
198
+ }
199
+ /**
200
+ * Appends missing keys a newer CLI expects and fills empty generated keys in place.
201
+ * Non-empty values are not changed. Creates the file when it is missing.
185
202
  *
186
- * @returns the names that were added, empty when the file was already complete
203
+ * @returns the names that were added or filled in, empty when the file was already complete
187
204
  */
188
205
  export function completeEnvFile(projectRoot) {
189
206
  const envPath = join(projectRoot, ".env");
@@ -193,24 +210,49 @@ export function completeEnvFile(projectRoot) {
193
210
  }
194
211
  const existing = readFileSync(envPath, "utf-8");
195
212
  const env = parseEnv(existing);
196
- const toAdd = REQUIRED_ENV_VARS.filter((v) => v.complete && !env.has(v.name));
197
- if (toAdd.length === 0)
213
+ const toComplete = REQUIRED_ENV_VARS.filter((v) => {
214
+ if (!v.complete)
215
+ return false;
216
+ if (!env.has(v.name))
217
+ return true;
218
+ return !(env.get(v.name) ?? "").trim();
219
+ });
220
+ if (toComplete.length === 0)
198
221
  return [];
199
- // Anything generated from the password must use the project's existing one.
200
- const password = env.get("DB_PASSWORD") || generateDbPassword();
201
- const lines = [
202
- "",
203
- "# Added by TDK: keys this version expects. Existing values above were not changed.",
204
- "",
205
- ];
206
- for (const envVar of toAdd) {
207
- lines.push(...describe(envVar));
208
- lines.push(`${envVar.name}=${generatedValue(envVar.name, password)}`);
209
- lines.push("");
222
+ const toAdd = toComplete.filter((v) => !env.has(v.name));
223
+ const toRepair = toComplete.filter((v) => env.has(v.name));
224
+ // Anything generated from the password must use the project's existing non-empty value.
225
+ const existingPassword = env.get("DB_PASSWORD");
226
+ const password = existingPassword?.trim() ? existingPassword : generateDbPassword();
227
+ const lines = existing.split(/(\r\n|\n|\r)/);
228
+ for (const envVar of toRepair) {
229
+ let lineIndex = -1;
230
+ for (let index = 0; index < lines.length; index += 2) {
231
+ if (parseEnv(lines[index]).has(envVar.name))
232
+ lineIndex = index;
233
+ }
234
+ if (lineIndex < 0) {
235
+ throw new Error(`Could not locate empty .env assignment for ${envVar.name}`);
236
+ }
237
+ lines[lineIndex] = replaceEmptyEnvValue(lines[lineIndex], envVar.name, generatedValue(envVar.name, password));
238
+ }
239
+ let updated = lines.join("");
240
+ if (toAdd.length > 0) {
241
+ const addedLines = [
242
+ "",
243
+ "# Added by TDK: keys this version expects. Existing values above were not changed.",
244
+ "",
245
+ ];
246
+ for (const envVar of toAdd) {
247
+ addedLines.push(...describe(envVar));
248
+ addedLines.push(`${envVar.name}=${generatedValue(envVar.name, password)}`);
249
+ addedLines.push("");
250
+ }
251
+ const separator = updated.endsWith("\n") || updated.endsWith("\r") ? "" : "\n";
252
+ updated += separator + addedLines.join("\n");
210
253
  }
211
- const separator = existing.endsWith("\n") ? "" : "\n";
212
- writeFileSync(envPath, `${existing}${separator}${lines.join("\n")}`);
213
- return toAdd.map((v) => v.name);
254
+ writeTextFileAtomic(envPath, updated);
255
+ return toComplete.map((v) => v.name);
214
256
  }
215
257
  export function ensureEnvFile(projectRoot) {
216
258
  const envPath = join(projectRoot, ".env");
@@ -14,6 +14,7 @@ const DEPRECATED_FIELDS = {
14
14
  const KNOWN_SERVICE_FIELDS = new Set([
15
15
  "$schema",
16
16
  "apiBasePath",
17
+ "apiPath",
17
18
  "appName",
18
19
  "appType",
19
20
  "backendName",
@@ -49,6 +50,13 @@ const KNOWN_SERVICE_FIELDS = new Set([
49
50
  "traefik",
50
51
  "type",
51
52
  ]);
53
+ const SERVICE_ROUTE_PATH_FIELDS = ["apiPath", "basePath"];
54
+ export function getInvalidServiceRoutePathFields(value) {
55
+ if (!value || typeof value !== "object" || Array.isArray(value))
56
+ return [];
57
+ const manifest = value;
58
+ return SERVICE_ROUTE_PATH_FIELDS.filter((field) => field in manifest && typeof manifest[field] !== "string");
59
+ }
52
60
  export function validateServiceManifest(value, displayPath) {
53
61
  if (!value || typeof value !== "object" || Array.isArray(value)) {
54
62
  return { errors: [`${displayPath}: expected a JSON object`], warnings: [] };
@@ -67,6 +75,9 @@ export function validateServiceManifest(value, displayPath) {
67
75
  if ("schemaVersion" in manifest && manifest.schemaVersion !== SERVICE_MANIFEST_SCHEMA_VERSION) {
68
76
  errors.push(`${displayPath}.schemaVersion: unsupported version ${String(manifest.schemaVersion)} (supported: ${SERVICE_MANIFEST_SCHEMA_VERSION})`);
69
77
  }
78
+ for (const field of getInvalidServiceRoutePathFields(manifest)) {
79
+ errors.push(`${displayPath}.${field}: expected a string`);
80
+ }
70
81
  const dev = manifest.dev;
71
82
  const liveReload = dev && typeof dev === "object" && !Array.isArray(dev)
72
83
  ? dev.liveReload
@@ -5,7 +5,7 @@ import { AUTOGENERATED_FILE_PATTERNS, SKIP_DIRECTORIES } from "./constants.js";
5
5
  import { errorFactories } from "./errors.js";
6
6
  import { formatCount } from "./formatting.js";
7
7
  import { findProjectRoot } from "./paths.js";
8
- import { validateServiceManifest } from "./service-manifest.js";
8
+ import { getInvalidServiceRoutePathFields, validateServiceManifest } from "./service-manifest.js";
9
9
  import { deriveStackStatus } from "./stack-status.js";
10
10
  import { includes } from "./validation.js";
11
11
  const RESOURCE_JSON_FILENAME = "service.json";
@@ -79,6 +79,10 @@ function parseResource(serviceJsonPath) {
79
79
  if (!isValidResourceConfig(parsed)) {
80
80
  throw new InvalidServiceJsonError("missing required fields (appName, runtime or appType)");
81
81
  }
82
+ const invalidRoutePathFields = getInvalidServiceRoutePathFields(parsed);
83
+ if (invalidRoutePathFields.length > 0) {
84
+ throw new InvalidServiceJsonError(invalidRoutePathFields.map((field) => `${field}: expected a string`).join("; "));
85
+ }
82
86
  const parsedConfig = parsed;
83
87
  for (const warning of validateServiceManifest(parsed, serviceJsonPath).warnings) {
84
88
  // The warning names the file and field and says what is wrong (unknown, deprecated, ignored), so do not prefix it.
@@ -1,5 +1,6 @@
1
1
  import { spawn } from "node:child_process";
2
2
  import { join } from "node:path";
3
+ import { errorFactories } from "./errors.js";
3
4
  import { findProjectRoot } from "./paths.js";
4
5
  import { findOnPath } from "./which.js";
5
6
  export function runTilt(command, args = [], options = {}) {
@@ -49,7 +50,7 @@ export async function isTiltAvailable() {
49
50
  export function getTiltfilePath() {
50
51
  const projectRoot = findProjectRoot();
51
52
  if (!projectRoot) {
52
- throw new Error("Not in a TDK project (no .tdk/project.json found)");
53
+ throw errorFactories.notInProject();
53
54
  }
54
55
  return join(projectRoot, ".tdk", ".tdk-out", "Tiltfile");
55
56
  }
@@ -0,0 +1,118 @@
1
+ export const TABS = [
2
+ { id: "overview", label: "OVERVIEW", shortcut: "1" },
3
+ { id: "resources", label: "RESOURCES", shortcut: "2" },
4
+ { id: "events", label: "EVENTS", shortcut: "3" },
5
+ { id: "files", label: "FILES", shortcut: "4" },
6
+ { id: "config", label: "CONFIG", shortcut: "5" },
7
+ ];
8
+ const tabRange = `${TABS[0].shortcut}-${TABS[TABS.length - 1].shortcut}`;
9
+ const uiKeymap = [
10
+ {
11
+ id: "list-navigation",
12
+ keys: ["ArrowUp", "ArrowDown", "j", "k"],
13
+ label: "Navigate list items",
14
+ group: "Navigation",
15
+ display: { ascii: "UP/DOWN or k/j", unicode: "↑/↓ or k/j" },
16
+ },
17
+ {
18
+ id: "first-last",
19
+ keys: ["g", "G", "Home", "End"],
20
+ label: "First/last item",
21
+ group: "Navigation",
22
+ display: { ascii: "g/G or Home/End", unicode: "g/G or Home/End" },
23
+ },
24
+ {
25
+ id: "page-list",
26
+ keys: ["PageUp", "PageDown"],
27
+ label: "Move one page",
28
+ group: "Navigation",
29
+ display: { ascii: "PgUp/PgDn", unicode: "PgUp/PgDn" },
30
+ },
31
+ {
32
+ id: "select",
33
+ keys: ["Enter", "Space"],
34
+ label: "Select item / Open detail",
35
+ group: "Navigation",
36
+ display: { ascii: "Enter or Space", unicode: "Enter or Space" },
37
+ },
38
+ {
39
+ id: "cycle-tabs",
40
+ keys: ["Tab", "Shift+Tab"],
41
+ label: "Next / previous tab",
42
+ group: "Navigation",
43
+ display: { ascii: "Tab/Shift+Tab", unicode: "Tab/Shift+Tab" },
44
+ },
45
+ {
46
+ id: "direct-tabs",
47
+ keys: TABS.map((tab) => tab.shortcut),
48
+ label: "Direct tab access",
49
+ group: "Navigation",
50
+ display: { ascii: tabRange, unicode: tabRange },
51
+ },
52
+ {
53
+ id: "toggle-mouse",
54
+ keys: ["m"],
55
+ label: "Toggle mouse support",
56
+ group: "Actions",
57
+ },
58
+ {
59
+ id: "toggle-tooltips",
60
+ keys: ["t"],
61
+ label: "Toggle tooltips",
62
+ group: "Actions",
63
+ },
64
+ {
65
+ id: "toggle-enabled",
66
+ keys: ["e"],
67
+ label: "Toggle enabled/disabled services",
68
+ group: "Actions",
69
+ },
70
+ {
71
+ id: "refresh",
72
+ keys: ["r"],
73
+ label: "Refresh data",
74
+ group: "Actions",
75
+ },
76
+ {
77
+ id: "search",
78
+ keys: ["/"],
79
+ label: "Search/filter",
80
+ group: "Actions",
81
+ },
82
+ {
83
+ id: "help",
84
+ keys: ["?"],
85
+ label: "Show this help",
86
+ group: "Actions",
87
+ },
88
+ {
89
+ id: "quit",
90
+ keys: ["q"],
91
+ label: "Quit",
92
+ group: "Actions",
93
+ },
94
+ {
95
+ id: "back",
96
+ keys: ["Esc"],
97
+ label: "Back",
98
+ group: "Actions",
99
+ },
100
+ ];
101
+ export const UI_KEYMAP = uiKeymap;
102
+ function getUiKeymapEntry(id) {
103
+ const entry = UI_KEYMAP.find((shortcut) => shortcut.id === id);
104
+ if (!entry) {
105
+ throw new Error(`Unknown TDK UI shortcut: ${id}`);
106
+ }
107
+ return entry;
108
+ }
109
+ export function formatUiKeyNames(id, ascii = false) {
110
+ const entry = getUiKeymapEntry(id);
111
+ const display = ascii ? entry.display?.ascii : entry.display?.unicode;
112
+ return display ?? entry.keys.join("/");
113
+ }
114
+ export function formatUiKeyHint(id, label, ascii = false) {
115
+ const entry = getUiKeymapEntry(id);
116
+ return `[${formatUiKeyNames(id, ascii)}] ${label ?? entry.label}`;
117
+ }
118
+ //# sourceMappingURL=ui-keymap.js.map
package/cli/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "tdk-cli-internal",
3
3
  "private": true,
4
- "version": "1.3.124",
4
+ "version": "1.3.125",
5
5
  "description": "TDK CLI — start services on your laptop.",
6
6
  "keywords": [
7
7
  "tdk",
@@ -318,11 +318,11 @@ def write_file_if_changed(file_path, content):
318
318
  existing = str(existing_blob).rstrip()
319
319
 
320
320
  if existing == expected:
321
- print("DEBUG WRITE: Skipping {} (no changes)".format(file_path))
321
+ debug_log("WRITE: Skipping {} (no changes)".format(file_path))
322
322
  else:
323
- print("DEBUG WRITE: Writing {} bytes to {}".format(len(expected), file_path))
323
+ debug_log("WRITE: Writing {} bytes to {}".format(len(expected), file_path))
324
324
  _write_generated_file(file_path, expected)
325
- print("DEBUG WRITE: Completed {}".format(file_path))
325
+ debug_log("WRITE: Completed {}".format(file_path))
326
326
 
327
327
  # Keep a generated-content snapshot beside the service outputs. `tdk config verify`
328
328
  # compares these snapshots with the files and the source manifest, detecting both
@@ -2,7 +2,7 @@
2
2
  # 🛠️ TILT SDK - DEBUG UTILITIES
3
3
  # =============================================================================
4
4
 
5
- DEBUG_MODE = os.environ.get('TILT_DEBUG', 'false').lower() in ['true', '1', 'yes']
5
+ DEBUG_MODE = (os.environ.get('TDK_DEBUG') or os.environ.get('TILT_DEBUG', 'false')).lower() in ['true', '1', 'yes']
6
6
 
7
7
 
8
8
  def debug_log(message, data=None):
@@ -3,6 +3,7 @@ OUTPUT = struct(AUTOGENERATED_FOLDER = ".autogenerated")
3
3
  # === END INLINED CONSTANTS ===
4
4
 
5
5
 
6
+ load("../../common/utils_debug.star", "debug_log")
6
7
  load("../../../../topologies/tilt/common/utils.star", "Utils")
7
8
  load("../../../../topologies/tilt/manifest/constants.star", "GENERATED_CONFIG_FILENAMES")
8
9
 
@@ -126,15 +127,12 @@ def generate_frontend_tsconfig(resource_path, write_fn, internal_deps=None, is_d
126
127
  }
127
128
  if is_docker:
128
129
  output_path = resource_path + '/' + OUTPUT.AUTOGENERATED_FOLDER + '/' + GENERATED_CONFIG_FILENAMES['tsconfig_docker']
129
- if is_verbose:
130
- print("📝 DEBUG: Writing Docker tsconfig to: {}".format(output_path))
130
+ debug_log("📝 Writing Docker tsconfig to: {}".format(output_path))
131
131
  write_fn(output_path, Utils.encode_json(content))
132
- if is_verbose:
133
- print("📝 DEBUG: Docker tsconfig write complete")
132
+ debug_log("📝 Docker tsconfig write complete")
134
133
  else:
135
134
  output_path = resource_path + '/' + OUTPUT.AUTOGENERATED_FOLDER + '/' + GENERATED_CONFIG_FILENAMES['tsconfig_local']
136
- if is_verbose:
137
- print("📝 DEBUG: Writing Local tsconfig to: {}".format(output_path))
135
+ debug_log("📝 Writing Local tsconfig to: {}".format(output_path))
138
136
  write_fn(output_path, Utils.encode_json(content))
139
137
 
140
138
  DEBUG = {}
@@ -18,6 +18,7 @@
18
18
  # Infra.load_all(should_enable_fn)
19
19
  # =============================================================================
20
20
 
21
+ load("../common/utils_debug.star", "debug_log")
21
22
  load("../../platform/docker/constants.star", "PlatformDockerConstants")
22
23
  load("../../platform/docker/compose/traefik_standalone.star", "generate_standalone_traefik_compose")
23
24
  load("../../platform/docker/networking/sablier_container_cycle.star", "sablier_middleware_suffix")
@@ -130,14 +131,14 @@ def _register_platform_postgres(should_enable, root_prefix="", env_file=None, wr
130
131
  """
131
132
  postgres_compose = _ensure_database_management_compose(root_prefix, write_fn)
132
133
  if _file_exists(postgres_compose):
133
- print("DEBUG INFRA: Loading postgres compose from {}".format(postgres_compose))
134
+ debug_log("INFRA: Loading postgres compose from {}".format(postgres_compose))
134
135
  _docker_compose(postgres_compose, env_file)
135
136
  dc_resource('postgres', labels=['infra.tools'], resource_deps=['init-networks'], auto_init=True)
136
137
  return
137
138
  message = "Shared platform Postgres compose was not materialized at {}".format(postgres_compose)
138
139
  if required:
139
140
  fail(message + " (write_fn present: {}). Refusing to register a postgres Tilt resource with no compose.".format(write_fn != None))
140
- print("DEBUG INFRA: Skipping postgres (compose file not found): {}".format(message))
141
+ debug_log("INFRA: Skipping postgres (compose file not found): {}".format(message))
141
142
 
142
143
 
143
144
  def force_start_platform_postgres(should_enable, root_prefix="", env_file=None, write_fn=None):
@@ -161,7 +162,7 @@ def force_start_platform_postgres(should_enable, root_prefix="", env_file=None,
161
162
  def _load_database_management(should_enable, root_prefix="", env_file=None, write_fn=None):
162
163
  """Load database and messaging infrastructure."""
163
164
  if not should_enable('database-management'):
164
- print("DEBUG INFRA: database-management not enabled")
165
+ debug_log("INFRA: database-management not enabled")
165
166
  return
166
167
 
167
168
  print("🗃️ Loading database management services...")
@@ -172,7 +173,7 @@ def _load_database_management(should_enable, root_prefix="", env_file=None, writ
172
173
  # Load messaging if compose file exists
173
174
  messaging_compose = root_prefix + 'services/platform/messaging/docker-compose.yml'
174
175
  if _file_exists(messaging_compose):
175
- print("DEBUG INFRA: Loading messaging compose from {}".format(messaging_compose))
176
+ debug_log("INFRA: Loading messaging compose from {}".format(messaging_compose))
176
177
  _docker_compose(messaging_compose, env_file)
177
178
  # Register only services present in the project compose file. Minimal
178
179
  # NATS-only examples should not need to add an unrelated Redis broker.
@@ -181,7 +182,7 @@ def _load_database_management(should_enable, root_prefix="", env_file=None, writ
181
182
  if _compose_has_service(messaging_compose, 'nats'):
182
183
  dc_resource('nats', labels=['infra.messaging'], auto_init=True)
183
184
  else:
184
- print("DEBUG INFRA: Skipping messaging (compose file not found)")
185
+ debug_log("INFRA: Skipping messaging (compose file not found)")
185
186
 
186
187
  # Only create kafka resources if debezium is enabled AND messaging exists
187
188
  cdc_enabled = should_enable('debezium')
@@ -211,7 +212,7 @@ def _load_infisical(should_enable, root_prefix="", env_file=None):
211
212
 
212
213
  compose_file = root_prefix + 'docker-compose.infisical.yml'
213
214
  if not _file_exists(compose_file):
214
- print("DEBUG INFRA: Skipping Infisical (compose file not found)")
215
+ debug_log("INFRA: Skipping Infisical (compose file not found)")
215
216
  return
216
217
 
217
218
  print("🔐 Loading Infisical...")
@@ -254,7 +255,7 @@ def _load_standalone_traefik(root_prefix, env_file, write_fn):
254
255
  def _load_proxy(should_enable, root_prefix="", env_file=None, write_fn=None):
255
256
  """Load Traefik reverse proxy with proper health check sequencing."""
256
257
  if not should_enable('proxy'):
257
- print("DEBUG INFRA: proxy not enabled")
258
+ debug_log("INFRA: proxy not enabled")
258
259
  return
259
260
 
260
261
  compose_files = [
@@ -266,7 +267,7 @@ def _load_proxy(should_enable, root_prefix="", env_file=None, write_fn=None):
266
267
  ]
267
268
  missing = [path for path in compose_files if not _file_exists(path)]
268
269
  if missing:
269
- print("DEBUG INFRA: Platform proxy compose missing ({}), using standalone Traefik".format(missing[0]))
270
+ debug_log("INFRA: Platform proxy compose missing ({}), using standalone Traefik".format(missing[0]))
270
271
  _load_standalone_traefik(root_prefix, env_file, write_fn)
271
272
  return
272
273
 
@@ -422,11 +423,11 @@ def load_all_infrastructure(should_enable, fix_docker_networks_fn=None, docker_p
422
423
  """
423
424
  # Initialize networks first
424
425
  if fix_docker_networks_fn:
425
- print("DEBUG INFRA: Initializing networks...")
426
+ debug_log("INFRA: Initializing networks...")
426
427
  _init_networks(fix_docker_networks_fn)
427
- print("DEBUG INFRA: Networks initialized")
428
+ debug_log("INFRA: Networks initialized")
428
429
  else:
429
- print("DEBUG INFRA: SKIPPING network initialization (no fix_docker_networks_fn)")
430
+ debug_log("INFRA: SKIPPING network initialization (no fix_docker_networks_fn)")
430
431
 
431
432
  # These stacks both define an `elasticsearch` resource (and host port 9200).
432
433
  # Running both at once causes compose/resource collisions and unstable startup.
@@ -4,6 +4,7 @@
4
4
  # Purpose: thin coordinator for service apply lifecycle.
5
5
  # =============================================================================
6
6
 
7
+ load("../../common/utils_debug.star", "debug_log")
7
8
  load('../databases.star', 'Database')
8
9
  load('./apply_runtime_flags.star', 'RuntimeFlags')
9
10
  load('./apply_resource_validation.star', 'ResourceValidation')
@@ -38,7 +39,7 @@ def apply_app_service(resource_config, ctx):
38
39
  for nested in resource_config.get('resources', []):
39
40
  nested_name = nested.get('name', '')
40
41
  if nested_name and should_enable(nested_name):
41
- print("DEBUG APPLY: stack '{}' not individually enabled, but nested service '{}' is - proceeding".format(resource_name, nested_name))
42
+ debug_log("APPLY: stack '{}' not individually enabled, but nested service '{}' is - proceeding".format(resource_name, nested_name))
42
43
  service_enabled = True
43
44
  break
44
45