Pharos 0.7.23
Modern Web Framework & Web App Hosting Service.
Loading...
Searching...
No Matches
native_app_runtime_paths.c
Go to the documentation of this file.
1/**
2 * @file
3 * @brief Finds app roots and computes default or effective build, state, base, log, debug, and error-report paths.
4 */
5
7
8#include "native_app_config.h"
10#include "native_support.h"
11
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15
16#ifdef _WIN32
17#define pharos_app_runtime_paths_strdup _strdup
18#else
19#include <dirent.h>
20#define pharos_app_runtime_paths_strdup strdup
21#endif
22
23char *match_app_root_in_directory(const char *base_dir, const char *target_id) {
24 char *manifest_path = NULL;
25 char *manifest_text = NULL;
26 char *manifest_id = NULL;
27 char *matched = NULL;
28#ifndef _WIN32
29 DIR *dir = NULL;
30 struct dirent *entry;
31#endif
32 if (base_dir == NULL || target_id == NULL || base_dir[0] == '\0') {
33 return NULL;
34 }
35 manifest_path = path_join(base_dir, "pharos.app.json");
36 if (manifest_path != NULL && path_exists(manifest_path)) {
37 manifest_text = read_file_text(manifest_path);
38 if (manifest_text != NULL) {
39 manifest_id = json_find_string(manifest_text, "app_id");
40 if (manifest_id != NULL && streq(manifest_id, target_id)) {
41 matched = path_canonicalize(base_dir);
42 if (matched == NULL) {
43 matched = pharos_app_runtime_paths_strdup(base_dir);
44 }
45 }
46 }
47 }
48 free(manifest_id);
49 free(manifest_text);
50 free(manifest_path);
51 if (matched != NULL) {
52 return matched;
53 }
54#ifndef _WIN32
55 dir = opendir(base_dir);
56 if (dir == NULL) {
57 return NULL;
58 }
59 while ((entry = readdir(dir)) != NULL) {
60 char *child_root;
61 if (streq(entry->d_name, ".") || streq(entry->d_name, "..")) {
62 continue;
63 }
64 child_root = path_join(base_dir, entry->d_name);
65 if (child_root == NULL) {
66 continue;
67 }
68 if (path_is_directory(child_root)) {
69 manifest_path = path_join(child_root, "pharos.app.json");
70 if (manifest_path != NULL && path_exists(manifest_path)) {
71 manifest_text = read_file_text(manifest_path);
72 if (manifest_text != NULL) {
73 manifest_id = json_find_string(manifest_text, "app_id");
74 if (manifest_id != NULL && streq(manifest_id, target_id)) {
75 matched = path_canonicalize(child_root);
76 if (matched == NULL) {
77 matched = pharos_app_runtime_paths_strdup(child_root);
78 }
79 }
80 }
81 }
82 free(manifest_id);
83 manifest_id = NULL;
84 free(manifest_text);
85 manifest_text = NULL;
86 free(manifest_path);
87 manifest_path = NULL;
88 if (matched != NULL) {
89 free(child_root);
90 break;
91 }
92 }
93 free(child_root);
94 }
95 closedir(dir);
96#endif
97 return matched;
98}
99
100char *find_app_root_for_target(const char *target_id, const char *app_dir_hint, const char *repo_root, const char *binary_dir) {
101 char *matched;
102 if (app_dir_hint != NULL && app_dir_hint[0] != '\0') {
103 matched = match_app_root_in_directory(app_dir_hint, target_id);
104 if (matched != NULL) {
105 return matched;
106 }
107 }
108 if (repo_root != NULL && repo_root[0] != '\0') {
109 char *apps_dir = path_join(repo_root, "apps");
110 matched = match_app_root_in_directory(apps_dir, target_id);
111 free(apps_dir);
112 if (matched != NULL) {
113 return matched;
114 }
115 }
116 if (binary_dir != NULL && binary_dir[0] != '\0') {
117 char *apps_adj = path_join(binary_dir, "apps");
118 matched = match_app_root_in_directory(apps_adj, target_id);
119 free(apps_adj);
120 if (matched != NULL) {
121 return matched;
122 }
123 {
124 char *binary_parent = path_dirname(binary_dir);
125 if (binary_parent != NULL) {
126 char *apps_near = path_join(binary_parent, "apps");
127 matched = match_app_root_in_directory(apps_near, target_id);
128 free(apps_near);
129 free(binary_parent);
130 if (matched != NULL) {
131 return matched;
132 }
133 }
134 }
135 }
136 return NULL;
137}
138
139char *app_build_dir_local_native(const char *app_root) {
141 char *value = NULL;
142 char *result = NULL;
143 if (load_app_local_config_native(app_root, &config) == 0) {
144 if (config.build_dir != NULL && config.build_dir[0] != '\0') {
146 } else if (config.manifest_build_artifact_dir != NULL && config.manifest_build_artifact_dir[0] != '\0' && !streq(config.manifest_build_artifact_dir, "null")) {
147 if (streq(config.manifest_build_artifact_dir, ".")) {
148 value = path_dirname(app_root);
149 } else {
150 char *artifact_parent = path_dirname(config.manifest_build_artifact_dir);
151 if (artifact_parent != NULL) {
152 value = path_dirname(artifact_parent);
153 }
154 free(artifact_parent);
155 }
156 }
158 }
159 if (value != NULL && value[0] != '\0') {
160 return value;
161 }
162 free(value);
163 result = path_dirname(app_root);
164 if (result != NULL && result[0] != '\0') {
165 return result;
166 }
167 free(result);
168 return path_join(app_root, "dist");
169}
170
171char *effective_app_build_dir_native(const char *app_root, const char *build_dir_override) {
172 if (build_dir_override != NULL && build_dir_override[0] != '\0') {
173 return pharos_app_runtime_paths_strdup(build_dir_override);
174 }
175 return app_build_dir_local_native(app_root);
176}
177
178char *app_artifact_dir_from_build_dir_native(const char *build_dir, const char *app_id) {
179 char *apps_root = NULL;
180 char *artifact_dir = NULL;
181 size_t len;
182 if (build_dir == NULL || app_id == NULL) {
183 return NULL;
184 }
185 len = strlen(build_dir);
186 if ((len >= 5 && streq(build_dir + len - 5, "/apps")) || streq(build_dir, "apps")
187#ifdef _WIN32
188 || (len >= 5 && streq(build_dir + len - 5, "\\apps"))
189#endif
190 ) {
191 return path_join(build_dir, app_id);
192 }
193 apps_root = path_join(build_dir, "apps");
194 if (apps_root == NULL) {
195 return NULL;
196 }
197 artifact_dir = path_join(apps_root, app_id);
198 free(apps_root);
199 return artifact_dir;
200}
201
202char *effective_app_artifact_dir_native(const char *app_root, const char *build_dir, const char *app_id) {
204 char *artifact_dir = NULL;
205 if (load_app_local_config_native(app_root, &config) == 0) {
206 if (config.manifest_build_artifact_dir != NULL && config.manifest_build_artifact_dir[0] != '\0' && !streq(config.manifest_build_artifact_dir, "null")) {
207 if (streq(config.manifest_build_artifact_dir, ".")) {
208 artifact_dir = pharos_app_runtime_paths_strdup(app_root);
209 } else {
210#ifdef _WIN32
211 if ((strlen(config.manifest_build_artifact_dir) > 2 && config.manifest_build_artifact_dir[1] == ':') || config.manifest_build_artifact_dir[0] == '\\' || config.manifest_build_artifact_dir[0] == '/') {
213 } else if (build_dir != NULL && build_dir[0] != '\0') {
214 artifact_dir = path_join(build_dir, config.manifest_build_artifact_dir);
215 }
216#else
217 if (config.manifest_build_artifact_dir[0] == '/') {
219 } else if (build_dir != NULL && build_dir[0] != '\0') {
220 artifact_dir = path_join(build_dir, config.manifest_build_artifact_dir);
221 }
222#endif
223 }
224 }
226 }
227 if (artifact_dir != NULL) {
228 return artifact_dir;
229 }
230 return app_artifact_dir_from_build_dir_native(build_dir, app_id);
231}
232
233char *app_state_path_local_native(const char *app_root, const char *build_dir, const char *app_id) {
235 char *resolved = NULL;
236 if (load_app_local_config_native(app_root, &config) == 0) {
237 if (config.state_path != NULL && config.state_path[0] != '\0') {
240 return resolved;
241 }
242 if (config.state_dir != NULL && config.state_dir[0] != '\0') {
243 resolved = path_join(config.state_dir, app_id);
245 if (resolved == NULL) {
246 return NULL;
247 }
248 {
249 char *tmp = path_join(resolved, "runtime-state.json");
250 free(resolved);
251 return tmp;
252 }
253 }
254 if (config.manifest_state_path != NULL && config.manifest_state_path[0] != '\0' && !streq(config.manifest_state_path, "null")) {
255 if (
256#ifdef _WIN32
257 (strlen(config.manifest_state_path) > 2 && config.manifest_state_path[1] == ':') ||
258#endif
259 config.manifest_state_path[0] == '/'
260 ) {
262 } else {
263 resolved = path_join(app_root, config.manifest_state_path);
264 }
266 return resolved;
267 }
269 }
270 resolved = effective_app_artifact_dir_native(app_root, build_dir, app_id);
271 if (resolved == NULL) {
272 return NULL;
273 }
274 {
275 char *tmp = path_join(resolved, "runtime-state.json");
276 free(resolved);
277 return tmp;
278 }
279}
280
281char *effective_app_state_path_native(const char *app_root, const char *build_dir, const char *app_id, const char *state_path_override, const char *state_dir_override) {
282 char *resolved = NULL;
283 if (state_path_override != NULL && state_path_override[0] != '\0') {
284 return pharos_app_runtime_paths_strdup(state_path_override);
285 }
286 if (state_dir_override != NULL && state_dir_override[0] != '\0') {
287 resolved = path_join(state_dir_override, app_id);
288 if (resolved == NULL) {
289 return NULL;
290 }
291 {
292 char *tmp = path_join(resolved, "runtime-state.json");
293 free(resolved);
294 return tmp;
295 }
296 }
297 return app_state_path_local_native(app_root, build_dir, app_id);
298}
299
300char *app_base_path_local_native(const char *app_root) {
302 char *value = NULL;
303 char *normalized;
304 if (load_app_local_config_native(app_root, &config) == 0) {
305 if (config.base_path != NULL && config.base_path[0] != '\0') {
307 } else if (config.manifest_base_path != NULL) {
309 }
311 }
312 if (value == NULL) {
314 }
315 normalized = normalize_base_path_native(value);
316 free(value);
317 return normalized;
318}
319
320char *effective_app_base_path_native(const char *app_root, const char *base_path_override) {
321 if (base_path_override != NULL && base_path_override[0] != '\0') {
322 return normalize_base_path_native(base_path_override);
323 }
324 return app_base_path_local_native(app_root);
325}
326
327char *app_log_path_local_native(const char *app_root, const char *app_id) {
329 char *value = NULL;
330 if (load_app_local_config_native(app_root, &config) == 0) {
331 if (config.log_path != NULL && config.log_path[0] != '\0') {
333 }
335 }
336 if (value != NULL && value[0] != '\0') {
337 return value;
338 }
339 free(value);
340 {
341 size_t needed = strlen("/var/log/pharos/.log") + strlen(app_id) + 1;
342 char *log_path = (char *)malloc(needed);
343 if (log_path != NULL) {
344 snprintf(log_path, needed, "/var/log/pharos/%s.log", app_id);
345 }
346 return log_path;
347 }
348}
349
350char *effective_app_log_path_native(const char *app_root, const char *app_id, const char *log_path_override) {
351 if (log_path_override != NULL && log_path_override[0] != '\0') {
352 return pharos_app_runtime_paths_strdup(log_path_override);
353 }
354 return app_log_path_local_native(app_root, app_id);
355}
356
357char *app_log_format_local_native(const char *app_root) {
358 (void)app_root;
359 return pharos_app_runtime_paths_strdup("service");
360}
361
362char *effective_app_log_format_native(const char *app_root) {
363 return app_log_format_local_native(app_root);
364}
365
366char *app_error_report_path_local_native(const char *app_root) {
368 char *value = NULL;
369 if (load_app_local_config_native(app_root, &config) == 0) {
370 if (config.error_report_path != NULL && config.error_report_path[0] != '\0') {
372 }
374 }
375 if (value != NULL && value[0] != '\0') {
376 return value;
377 }
378 free(value);
380}
381
382char *effective_app_error_report_path_native(const char *app_root, const char *app_id) {
383 char *value = app_error_report_path_local_native(app_root);
384 if (value != NULL && value[0] != '\0') {
385 return value;
386 }
387 free(value);
388 {
389 size_t needed = strlen("/var/log/pharos/.error.jsonl") + strlen(app_id != NULL ? app_id : "app") + 1;
390 char *path = (char *)malloc(needed);
391 if (path != NULL) {
392 snprintf(path, needed, "/var/log/pharos/%s.error.jsonl", app_id != NULL && app_id[0] != '\0' ? app_id : "app");
393 }
394 return path;
395 }
396}
397
398char *app_debug_local_native(const char *app_root) {
400 char *value = NULL;
401 if (load_app_local_config_native(app_root, &config) == 0) {
402 if (config.debug != NULL && config.debug[0] != '\0') {
404 }
406 }
407 if (value != NULL && value[0] != '\0') {
408 return value;
409 }
410 free(value);
411 return pharos_app_runtime_paths_strdup("false");
412}
413
414char *effective_app_debug_native(const char *app_root, const char *debug_override) {
415 if (debug_override != NULL && debug_override[0] != '\0') {
416 return pharos_app_runtime_paths_strdup(debug_override);
417 }
418 return app_debug_local_native(app_root);
419}
void free_app_local_config_native(AppLocalConfigNative *config)
Releases heap-owned fields in an app-local configuration record.
char * normalize_base_path_native(const char *raw_value)
Normalizes a configured app base path into Pharos runtime form.
int load_app_local_config_native(const char *app_root, AppLocalConfigNative *config)
Loads app-local configuration and manifest-derived path hints into a config record.
Declares app-local runtime configuration helpers and the app-local configuration record.
char * app_build_dir_local_native(const char *app_root)
Builds the default local build directory path for an app.
char * effective_app_build_dir_native(const char *app_root, const char *build_dir_override)
Resolves the effective build directory for an app.
char * effective_app_log_path_native(const char *app_root, const char *app_id, const char *log_path_override)
Resolves the effective log file path for an app.
char * effective_app_log_format_native(const char *app_root)
Resolves the effective log format for an app.
char * app_artifact_dir_from_build_dir_native(const char *build_dir, const char *app_id)
Resolves the artifact directory for one app from a build root or deployed app parent.
char * effective_app_debug_native(const char *app_root, const char *debug_override)
Resolves the effective debug setting for an app.
char * app_debug_local_native(const char *app_root)
Builds the default local debug setting for an app.
char * find_app_root_for_target(const char *target_id, const char *app_dir_hint, const char *repo_root, const char *binary_dir)
Locates an app root for a target using explicit app-dir hints and canonical apps directories.
char * app_error_report_path_local_native(const char *app_root)
Builds the default local error report path for an app.
char * app_state_path_local_native(const char *app_root, const char *build_dir, const char *app_id)
Builds the default local state file path for an app.
char * effective_app_error_report_path_native(const char *app_root, const char *app_id)
Resolves the effective error report path for an app.
char * effective_app_state_path_native(const char *app_root, const char *build_dir, const char *app_id, const char *state_path_override, const char *state_dir_override)
Resolves the effective state file path for an app.
char * effective_app_artifact_dir_native(const char *app_root, const char *build_dir, const char *app_id)
Resolves the effective artifact directory for an app from framework build root plus app-owned contrac...
char * app_log_format_local_native(const char *app_root)
Builds the default local log format setting for an app.
char * effective_app_base_path_native(const char *app_root, const char *base_path_override)
Resolves the effective URL base path for an app.
#define pharos_app_runtime_paths_strdup
char * app_base_path_local_native(const char *app_root)
Builds the default local URL base path for an app.
char * match_app_root_in_directory(const char *base_dir, const char *target_id)
Searches one directory for an app root matching a target identifier.
char * app_log_path_local_native(const char *app_root, const char *app_id)
Builds the default local log file path for an app.
Declares helpers for locating app roots and deriving runtime paths.
char * json_find_string(const char *text, const char *key)
Finds the first JSON string value associated with a key.
Declares lightweight JSON and conf value lookup helpers.
char * path_join(const char *left, const char *right)
Joins two path segments using the native path separator.
char * path_canonicalize(const char *path)
Normalizes a path by collapsing redundant separators and dot segments.
int streq(const char *a, const char *b)
Tests whether two strings are exactly equal.
int path_is_directory(const char *path)
Tests whether a filesystem path refers to a directory.
char * path_dirname(const char *path)
Returns the parent directory component of a path.
char * read_file_text(const char *path)
Reads an entire file into a newly allocated text buffer.
int path_exists(const char *path)
Tests whether a filesystem path currently exists.
Declares shared low-level support helpers used across the Pharos native runtime.
App-local configuration values loaded from app-local config and manifest authority fields.
const char size_t len
Definition yyjson.h:8364