31#define PHAROS_SOCKET SOCKET
32#define PHAROS_INVALID_SOCKET INVALID_SOCKET
33#define pharos_close_socket closesocket
34#define pharos_getcwd _getcwd
35#define pharos_access _access
36#define pharos_stat _stat
37#define pharos_mkdir(path, mode) _mkdir(path)
38#define pharos_unlink _unlink
39#define pharos_strdup _strdup
43static int win_gettimeofday(
struct timeval *tv,
void *tz) {
46 GetSystemTimeAsFileTime(&ft);
47 li.LowPart = ft.dwLowDateTime;
48 li.HighPart = ft.dwHighDateTime;
49 tv->tv_sec = (long)((li.QuadPart - 116444736000000000ULL) / 10000000ULL);
50 tv->tv_usec = (long)((li.QuadPart / 10ULL) % 1000000ULL);
53#define gettimeofday win_gettimeofday
57#include <netinet/in.h>
60#include <sys/socket.h>
69#define PHAROS_SOCKET int
70#define PHAROS_INVALID_SOCKET -1
71#define pharos_close_socket close
72#define pharos_getcwd getcwd
73#define pharos_access access
74#define pharos_stat stat
75#define pharos_mkdir mkdir
76#define pharos_unlink unlink
77#define pharos_strdup strdup
112#ifndef PHAROS_TARGET_ID
113#define PHAROS_TARGET_ID "source-bootstrap"
116#ifndef PHAROS_VERSION
117#define PHAROS_VERSION "0.7.23"
130#define PHAROS_NATIVE_DEFAULT_WORKER_COUNT 16
131#define PHAROS_NATIVE_MIN_WORKER_COUNT 1
132#define PHAROS_NATIVE_MAX_WORKER_COUNT 256
133#define PHAROS_NATIVE_MIN_WORK_QUEUE_CAPACITY 32
134#define PHAROS_NATIVE_MAX_WORK_QUEUE_CAPACITY 8192
135#define PHAROS_NATIVE_DEFAULT_WORK_QUEUE_CAPACITY 128
136#define PHAROS_NATIVE_WORK_QUEUE_BYTES_PER_SLOT (8ULL * 1024ULL * 1024ULL)
147 CRITICAL_SECTION
mutex;
290 (void)report_path_out;
291 (void)artifact_dir_out;
296 const char *app_root,
297 const char *build_dir_override,
298 const char *state_dir_override,
299 const char *state_path_override,
300 const char *base_path_override,
301 char **report_path_out,
302 char **artifact_dir_out
310 char *index_path = NULL;
311 char *report_path = NULL;
312 char *report_json = NULL;
314 const char *report_id =
"pharos-end-to-end-site-v1";
315 if (artifact_dir == NULL) {
318 index_path =
path_join(artifact_dir,
"index.html");
319 if (index_path == NULL) {
332 if (report_path == NULL) {
338 if (report_json == NULL) {
352 if (report_path_out != NULL) *report_path_out = report_path;
else free(report_path);
357 char *manifest_path = NULL;
358 char *manifest_text = NULL;
359 char *host_profile = NULL;
360 if (app_root == NULL) {
363 manifest_path =
path_join(app_root,
"pharos.app.json");
364 manifest_text = manifest_path != NULL ?
read_file_text(manifest_path) : NULL;
365 if (manifest_text != NULL) {
370 if (host_profile == NULL) {
407 const char *app_root,
409 const char *build_dir_override,
410 const char *state_dir_override,
411 const char *state_path_override,
412 const char *base_path_override,
413 char **report_path_out,
414 char **artifact_dir_out
416 char *build_dir = NULL;
418 if (report_path_out != NULL) {
419 *report_path_out = NULL;
421 if (artifact_dir_out != NULL) {
422 *artifact_dir_out = NULL;
424 if (app_root == NULL || app_id == NULL) {
428 if (build_dir == NULL) {
432 code =
build_app_from_root_native(app_root, build_dir, state_dir_override, state_path_override, base_path_override, report_path_out, artifact_dir_out);
438 return "<!DOCTYPE html>\n"
439 "<html lang=\"en\">\n"
441 "<meta charset=\"UTF-8\">\n"
442 "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n"
443 "<title>Pharos Docs</title>\n"
444 "<link rel=\"stylesheet\" href=\"/dev_docs/docs/assets/docs.css\">\n"
448 " <section class=\"banner\">\n"
449 " <img src=\"/dev_docs/docs/assets/pharos-framework-wordmark.svg\" alt=\"Pharos Framework\" class=\"wordmark\">\n"
451 " <section class=\"card\">\n"
452 " <h2>Primary entry points</h2>\n"
454 " <li><a href=\"/dev_docs/\">Home</a></li>\n"
455 " <li><a href=\"/dev_docs/docs/pharos_framework.html\">Framework overview</a></li>\n"
456 " <li><a href=\"/dev_docs/docs/how-to-use-pharos-cli.html\">CLI guide</a></li>\n"
457 " <li><a href=\"/dev_docs/docs/operations/runtime-operations.html\">Runtime operations</a></li>\n"
458 " <li><a href=\"/dev_docs/docs/spec.html\">Framework specification</a></li>\n"
459 " <li><a href=\"/dev_docs/docs/platform-vision.html\">Platform vision</a></li>\n"
460 " <li><a href=\"/dev_docs/docs/html/index.html\">Doxygen source reference</a></li>\n"
471 char *apps_root = NULL;
472 char *repo_root = NULL;
473 char *repo_docs = NULL;
474 char *repo_doxyfile = NULL;
475 char *target_docs = NULL;
476 char *target_docs_html = NULL;
477 char *target_docs_index = NULL;
478 char *generated_doxyfile = NULL;
479 char *markdown_renderer = NULL;
480 char *artifact_noindex = NULL;
481 char *target_docs_noindex = NULL;
482 char *target_docs_html_noindex = NULL;
483 char *doxyfile_text = NULL;
484 char *generated_doxyfile_text = NULL;
485 char *command = NULL;
490 if (app_root == NULL || artifact_dir == NULL) {
494 repo_root = apps_root != NULL ?
path_dirname(apps_root) : NULL;
495 repo_docs = repo_root != NULL ?
path_join(repo_root,
"docs") : NULL;
496 repo_doxyfile = repo_root != NULL ?
path_join(repo_root,
"Doxyfile") : NULL;
497 target_docs =
path_join(artifact_dir,
"docs");
498 target_docs_html = target_docs != NULL ?
path_join(target_docs,
"html") : NULL;
499 target_docs_index = target_docs != NULL ?
path_join(target_docs,
"index.html") : NULL;
500 generated_doxyfile =
path_join(artifact_dir,
"Doxyfile.dev_docs");
501 markdown_renderer =
path_join(artifact_dir,
"dev_docs_markdown_render.py");
502 artifact_noindex =
path_join(artifact_dir,
".metadata_never_index");
503 target_docs_noindex =
path_join(target_docs,
".metadata_never_index");
504 target_docs_html_noindex =
path_join(target_docs_html,
".metadata_never_index");
505 if (repo_root == NULL || repo_docs == NULL || repo_doxyfile == NULL || target_docs == NULL || target_docs_html == NULL || target_docs_index == NULL || generated_doxyfile == NULL || markdown_renderer == NULL || artifact_noindex == NULL || target_docs_noindex == NULL || target_docs_html_noindex == NULL) {
529 static const char *renderer_script =
530 "from pathlib import Path\n"
534 "ROOT = Path(sys.argv[1])\n"
535 "HTML_TEMPLATE = \"\"\"<!DOCTYPE html>\n"
536 "<html lang=\\\"en\\\">\n"
538 "<meta charset=\\\"UTF-8\\\">\n"
539 "<meta name=\\\"viewport\\\" content=\\\"width=device-width, initial-scale=1.0\\\">\n"
540 "<title>{title}</title>\n"
541 "<link rel=\"stylesheet\" href=\"{stylesheet_src}\">\n"
545 "<section class=\\\"banner\\\">\n"
546 "<img src=\\\"{wordmark_src}\\\" alt=\\\"Pharos Framework\\\" class=\\\"wordmark\\\">\n"
547 "<p class=\\\"backlink\\\"><a href=\\\"{back_href}\\\">← Back</a></p>\n"
554 "LINK_RE = re.compile(r'\\[([^\\]]+)\\]\\(([^)]+)\\)')\n"
555 "INLINE_CODE_RE = re.compile(r'`([^`]+)`')\n"
556 "BOLD_RE = re.compile(r'\\*\\*([^*]+)\\*\\*')\n"
557 "ITALIC_RE = re.compile(r'(?<!\\*)\\*([^*]+)\\*(?!\\*)')\n"
558 "def rewrite_href(target):\n"
559 " if target.endswith('.md'): return target[:-3] + '.html'\n"
560 " if '.md#' in target: return target.replace('.md#', '.html#')\n"
562 "def inline_markup(text):\n"
563 " escaped = html.escape(text)\n"
564 " escaped = LINK_RE.sub(lambda m: f'<a href=\\\"{html.escape(rewrite_href(m.group(2)), quote=True)}\\\">{m.group(1)}</a>', escaped)\n"
565 " escaped = INLINE_CODE_RE.sub(lambda m: f'<code>{m.group(1)}</code>', escaped)\n"
566 " escaped = BOLD_RE.sub(lambda m: f'<strong>{m.group(1)}</strong>', escaped)\n"
567 " escaped = ITALIC_RE.sub(lambda m: f'<em>{m.group(1)}</em>', escaped)\n"
569 "def render_markdown(text, rel_path):\n"
570 " lines = text.splitlines()\n"
575 " list_type = None\n"
576 " title = rel_path.stem.replace('-', ' ').replace('_', ' ').title()\n"
577 " def close_paragraph():\n"
580 " out.append(f\"<p>{inline_markup(' '.join(para).strip())}</p>\")\n"
582 " def close_list():\n"
583 " nonlocal list_type\n"
584 " if list_type is not None:\n"
585 " out.append(f'</{list_type}>')\n"
586 " list_type = None\n"
587 " for line in lines:\n"
588 " stripped = line.rstrip('\\n')\n"
589 " if stripped.startswith('```'):\n"
590 " close_paragraph(); close_list()\n"
592 " out.append('<pre><code>' + html.escape('\\n'.join(code_lines)) + '</code></pre>')\n"
599 " code_lines.append(stripped)\n"
601 " if not stripped.strip():\n"
602 " close_paragraph(); close_list(); continue\n"
603 " heading_match = re.match(r'^(#{1,6})\\s+(.*)$', stripped)\n"
604 " if heading_match:\n"
605 " close_paragraph(); close_list()\n"
606 " level = len(heading_match.group(1))\n"
607 " heading_text = heading_match.group(2).strip()\n"
608 " if level == 1: title = heading_text\n"
609 " out.append(f'<h{level}>{inline_markup(heading_text)}</h{level}>')\n"
611 " unordered_match = re.match(r'^\\s*[-*]\\s+(.*)$', stripped)\n"
612 " ordered_match = re.match(r'^\\s*\\d+\\.\\s+(.*)$', stripped)\n"
613 " if unordered_match or ordered_match:\n"
614 " close_paragraph()\n"
615 " next_type = 'ul' if unordered_match else 'ol'\n"
616 " item_text = unordered_match.group(1) if unordered_match else ordered_match.group(1)\n"
617 " if list_type != next_type:\n"
619 " list_type = next_type\n"
620 " out.append(f'<{list_type}>')\n"
621 " out.append(f'<li>{inline_markup(item_text.strip())}</li>')\n"
623 " para.append(stripped.strip())\n"
624 " close_paragraph(); close_list()\n"
626 " out.append('<pre><code>' + html.escape('\\n'.join(code_lines)) + '</code></pre>')\n"
627 " prefix = '' if rel_path.parent == Path('.') else '../' * len(rel_path.parent.parts)\n"
628 " back_href = 'index.html' if rel_path.parent == Path('.') else prefix + 'index.html'\n"
629 " wordmark_src = prefix + 'assets/pharos-framework-wordmark.svg'\n"
630 " stylesheet_src = prefix + 'assets/docs.css'\n"
631 " return HTML_TEMPLATE.format(title=html.escape(title), back_href=html.escape(back_href, quote=True), wordmark_src=html.escape(wordmark_src, quote=True), stylesheet_src=html.escape(stylesheet_src, quote=True), body='\\n'.join(out))\n"
632 "def rewrite_html_links(path):\n"
633 " text = path.read_text(encoding='utf-8')\n"
634 " text = text.replace('.md#', '.html#')\n"
635 " text = re.sub(r'([\"\\\'])((?:[^\"\\\']+/)?[^\"\\\']+\\.md)(#[^\"\\\']*)?\\1', lambda m: f'{m.group(1)}{rewrite_href(m.group(2))}{m.group(3) or \"\"}{m.group(1)}', text)\n"
636 " path.write_text(text, encoding='utf-8')\n"
637 "markdown_files = sorted(ROOT.rglob('*.md'))\n"
638 "for md_path in markdown_files:\n"
639 " rel = md_path.relative_to(ROOT)\n"
640 " html_path = md_path.with_suffix('.html')\n"
641 " html_path.write_text(render_markdown(md_path.read_text(encoding='utf-8'), rel), encoding='utf-8')\n"
642 "for html_path in sorted(ROOT.rglob('*.html')):\n"
643 " rewrite_html_links(html_path)\n"
644 "for md_path in markdown_files:\n"
645 " md_path.unlink()\n";
650 needed = strlen(markdown_renderer) + strlen(target_docs) + 32;
651 command = (
char *)malloc(needed);
652 if (command == NULL) {
656 snprintf(command, needed,
"python3 %s %s", markdown_renderer, target_docs);
657 argv_list[0] =
"/bin/sh";
659 argv_list[2] = command;
675 if (doxyfile_text == NULL) {
679 needed = strlen(doxyfile_text) + strlen(target_docs) + 96;
680 generated_doxyfile_text = (
char *)malloc(needed);
681 if (generated_doxyfile_text == NULL) {
685 snprintf(generated_doxyfile_text, needed,
"%s\nOUTPUT_DIRECTORY = %s\nHTML_OUTPUT = html\n", doxyfile_text, target_docs);
690 needed = strlen(repo_root) + strlen(generated_doxyfile) + 32;
691 command = (
char *)malloc(needed);
692 if (command == NULL) {
696 snprintf(command, needed,
"cd %s && doxygen %s", repo_root, generated_doxyfile);
697 argv_list[0] =
"/bin/sh";
699 argv_list[2] = command;
702 if (code != 0 && output != NULL && output[0] !=
'\0') {
703 fprintf(stderr,
"%s", output);
708 if (noindex_code != 0) {
714 if (generated_doxyfile != NULL &&
path_exists(generated_doxyfile)) {
717 if (markdown_renderer != NULL &&
path_exists(markdown_renderer)) {
725 free(target_docs_html);
726 free(target_docs_index);
727 free(generated_doxyfile);
728 free(markdown_renderer);
729 free(artifact_noindex);
730 free(target_docs_noindex);
731 free(target_docs_html_noindex);
733 free(generated_doxyfile_text);
745 const char *app_root,
746 const char *build_dir_override,
747 const char *state_dir_override,
748 const char *state_path_override,
749 const char *base_path_override,
750 char **report_path_out,
751 char **artifact_dir_out
753 char *manifest_path =
path_join(app_root,
"pharos.app.json");
754 char *manifest_text = NULL;
756 char *compiled_entrypoint = NULL;
757 char *host_profile = NULL;
758 char *state_path = NULL;
759 char *base_path = NULL;
760 char *payload_dir_rel = NULL;
761 char *static_dir_rel = NULL;
762 char *media_dir_rel = NULL;
763 char *log_path = NULL;
764 char *log_format = NULL;
765 char *error_report_path = NULL;
767 char *route_fixture_rel = NULL;
768 char *surface_fixture_rel = NULL;
769 char *workflow_fixture_rel = NULL;
770 char *form_fixture_rel = NULL;
771 char *policy_fixture_rel = NULL;
772 char *entity_fixture_rel = NULL;
773 char *query_fixture_rel = NULL;
774 char *migration_fixture_rel = NULL;
775 char *seed_sources_text = NULL;
776 char *preferred_backend = NULL;
777 char *development_backend = NULL;
778 char *testing_backend = NULL;
779 char *build_dir = NULL;
780 char *artifact_dir = NULL;
781 char *report_path = NULL;
782 char *index_path = NULL;
783 char *build_dir_noindex = NULL;
785 char *payload_dir = NULL;
786 char *static_dir = NULL;
787 char *media_dir = NULL;
788 char *templates_dir = NULL;
789 char *data_dir = NULL;
790 char *fixtures_dir = NULL;
791 char *app_manifest_source_path = NULL;
792 char *app_conf_source_path = NULL;
793 char *pharos_conf_source_path = NULL;
794 char *start_script_source_path = NULL;
795 char *app_manifest_target_path = NULL;
796 char *app_conf_target_path = NULL;
797 char *start_script_target_path = NULL;
798 char *target_static = NULL;
799 char *target_media = NULL;
801 char *index_html = NULL;
802 char *artifact_local_app_manifest_json = NULL;
804 char *route_fixture = NULL;
805 char *surface_fixture = NULL;
806 char *workflow_fixture = NULL;
807 char *form_fixture = NULL;
808 char *policy_fixture = NULL;
809 char *entity_fixture = NULL;
810 char *query_fixture = NULL;
811 char *migration_fixture = NULL;
812 char *route_fixture_text = NULL;
813 char *surface_fixture_text = NULL;
814 char *workflow_fixture_text = NULL;
816 int surface_count = 0;
817 int workflow_count = 0;
819 if (manifest_path == NULL || !
path_exists(manifest_path)) {
824 if (manifest_text == NULL) {
846 if (app_id == NULL) {
852 payload_dir = payload_dir_rel != NULL ?
path_join(app_root, payload_dir_rel) : NULL;
853 static_dir = static_dir_rel != NULL ?
path_join(app_root, static_dir_rel) : NULL;
854 media_dir = media_dir_rel != NULL ?
path_join(app_root, media_dir_rel) : NULL;
855 templates_dir =
path_join(app_root,
"templates");
857 fixtures_dir =
path_join(app_root,
"fixtures");
858 app_manifest_source_path =
path_join(app_root,
"pharos.app.json");
859 app_conf_source_path =
path_join(app_root,
"app.conf");
860 pharos_conf_source_path =
path_join(app_root,
"pharos.conf");
861 start_script_source_path =
path_join(app_root,
"start.sh");
862 app_manifest_target_path =
path_join(artifact_dir,
"pharos.app.json");
863 app_conf_target_path =
path_join(artifact_dir,
"app.conf");
864 start_script_target_path =
path_join(artifact_dir,
"start.sh");
865 target_static =
path_join(artifact_dir,
"static");
866 target_media =
path_join(artifact_dir,
"media");
867 index_path =
path_join(artifact_dir,
"index.html");
869 build_dir_noindex =
path_join(build_dir,
".metadata_never_index");
870 if (build_dir == NULL || artifact_dir == NULL || target_static == NULL || target_media == NULL || index_path == NULL || report_path == NULL || build_dir_noindex == NULL || app_manifest_source_path == NULL || app_manifest_target_path == NULL || app_conf_target_path == NULL || start_script_source_path == NULL || start_script_target_path == NULL) {
888 if (code != 0)
goto cleanup;
891 if (code != 0)
goto cleanup;
894 code =
copy_file_binary(start_script_source_path, start_script_target_path);
895 if (code != 0)
goto cleanup;
898 char *target_data =
path_join(artifact_dir,
"data");
899 if (target_data == NULL) {
905 if (code != 0)
goto cleanup;
908 char *target_fixtures =
path_join(artifact_dir,
"fixtures");
909 if (target_fixtures == NULL) {
914 free(target_fixtures);
915 if (code != 0)
goto cleanup;
919 if (code != 0)
goto cleanup;
923 if (code != 0)
goto cleanup;
927 if (code != 0)
goto cleanup;
930 char *target_templates =
path_join(artifact_dir,
"templates");
931 if (target_templates == NULL) {
936 free(target_templates);
937 if (code != 0)
goto cleanup;
939 if (
streq(app_id,
"dev_docs")) {
941 if (code != 0)
goto cleanup;
943 route_fixture = route_fixture_rel != NULL ?
path_join(app_root, route_fixture_rel) : NULL;
944 surface_fixture = surface_fixture_rel != NULL ?
path_join(app_root, surface_fixture_rel) : NULL;
945 workflow_fixture = workflow_fixture_rel != NULL ?
path_join(app_root, workflow_fixture_rel) : NULL;
946 form_fixture = form_fixture_rel != NULL ?
path_join(app_root, form_fixture_rel) : NULL;
947 policy_fixture = policy_fixture_rel != NULL ?
path_join(app_root, policy_fixture_rel) : NULL;
948 entity_fixture = entity_fixture_rel != NULL ?
path_join(app_root, entity_fixture_rel) : NULL;
949 query_fixture = query_fixture_rel != NULL ?
path_join(app_root, query_fixture_rel) : NULL;
950 migration_fixture = migration_fixture_rel != NULL ?
path_join(app_root, migration_fixture_rel) : NULL;
951 route_fixture_text = route_fixture != NULL ?
read_file_text(route_fixture) : NULL;
952 surface_fixture_text = surface_fixture != NULL ?
read_file_text(surface_fixture) : NULL;
953 workflow_fixture_text = workflow_fixture != NULL ?
read_file_text(workflow_fixture) : NULL;
963 if (compiled_entrypoint != NULL && compiled_entrypoint[0] !=
'\0' && (
965 !(strlen(compiled_entrypoint) > 2 && compiled_entrypoint[1] ==
':') &&
967 compiled_entrypoint[0] !=
'/'
969 char *resolved =
path_join(app_root, compiled_entrypoint);
970 free(compiled_entrypoint);
971 compiled_entrypoint = resolved;
976 "pharos-native-runtime",
988 if (index_html == NULL || artifact_local_app_manifest_json == NULL) {
995 if (code == 0) code =
write_text_file(app_manifest_target_path, artifact_local_app_manifest_json);
997 char *report_json =
build_native_app_build_report_json(artifact_dir, app_id, state_path, base_path, log_path, log_format, error_report_path, debug, host_profile, compiled_entrypoint);
998 if (report_json == NULL) {
1006 free(manifest_path);
1007 free(manifest_text);
1009 free(compiled_entrypoint);
1015 free(error_report_path);
1017 free(payload_dir_rel);
1018 free(static_dir_rel);
1019 free(media_dir_rel);
1020 free(route_fixture_rel);
1021 free(surface_fixture_rel);
1022 free(workflow_fixture_rel);
1023 free(form_fixture_rel);
1024 free(policy_fixture_rel);
1025 free(entity_fixture_rel);
1026 free(query_fixture_rel);
1027 free(migration_fixture_rel);
1028 free(seed_sources_text);
1029 free(preferred_backend);
1030 free(development_backend);
1031 free(testing_backend);
1034 free(build_dir_noindex);
1038 free(templates_dir);
1041 free(app_manifest_source_path);
1042 free(app_conf_source_path);
1043 free(pharos_conf_source_path);
1044 free(start_script_source_path);
1045 free(app_manifest_target_path);
1046 free(app_conf_target_path);
1047 free(start_script_target_path);
1048 free(target_static);
1052 free(artifact_local_app_manifest_json);
1053 free(route_fixture);
1054 free(surface_fixture);
1055 free(workflow_fixture);
1057 free(policy_fixture);
1058 free(entity_fixture);
1059 free(query_fixture);
1060 free(migration_fixture);
1061 free(route_fixture_text);
1062 free(surface_fixture_text);
1063 free(workflow_fixture_text);
1069 if (report_path_out != NULL) *report_path_out = report_path;
else free(report_path);
1070 if (artifact_dir_out != NULL) *artifact_dir_out = artifact_dir;
else free(artifact_dir);
1078 char *app_id = NULL;
1079 char *build_dir = NULL;
1080 char *artifact_dir = NULL;
1085 if (app_id_hint != NULL && app_id_hint[0] !=
'\0') {
1088 char *manifest_path =
path_join(app_root,
"pharos.app.json");
1089 char *manifest_text = manifest_path != NULL ?
read_file_text(manifest_path) : NULL;
1090 if (manifest_text != NULL) {
1093 free(manifest_path);
1094 free(manifest_text);
1096 if (app_id == NULL) {
1100 if (build_dir == NULL) {
1111 if (load_existing_code == 0) {
1125 if (artifact_dir != NULL) {
1127 if (load_existing_code == 0) {
1142 artifact_dir = NULL;
1146 if (prepare_code != 0) {
1152 if (artifact_dir == NULL) {
1159 if (load_code == 0) {
1185 if (argv0 == NULL) {
1190 (strlen(argv0) > 2 && argv0[1] ==
':') ||
1192 argv0[0] ==
'/' || argv0[0] ==
'.'
1209 while (search_dir != NULL) {
1210 char *scripts =
path_join(search_dir,
"scripts/pharos_runtime.sh");
1211 char *nested =
path_join(search_dir,
"pharos/scripts/pharos_runtime.sh");
1220 char *repo =
path_join(search_dir,
"pharos");
1226 return canonical_repo;
1230 if (
streq(search_dir,
"/") ||
streq(search_dir,
".") || strlen(search_dir) <= 1) {
1234 if (strlen(search_dir) == 3 && search_dir[1] ==
':' && (search_dir[2] ==
'\\' || search_dir[2] ==
'/')) {
1240 if (parent == NULL ||
streq(parent, search_dir)) {
1245 search_dir = parent;
1250 while (search_dir != NULL) {
1251 char *scripts =
path_join(search_dir,
"scripts/pharos_runtime.sh");
1252 char *nested =
path_join(search_dir,
"pharos/scripts/pharos_runtime.sh");
1261 char *repo =
path_join(search_dir,
"pharos");
1267 return canonical_repo;
1271 if (
streq(search_dir,
"/") ||
streq(search_dir,
".") || strlen(search_dir) <= 1) {
1275 if (strlen(search_dir) == 3 && search_dir[1] ==
':' && (search_dir[2] ==
'\\' || search_dir[2] ==
'/')) {
1281 if (parent == NULL ||
streq(parent, search_dir)) {
1286 search_dir = parent;
1294 if (value == NULL || value[0] ==
'\0') {
1301 char *manifest_path = NULL;
1303 if (app_root == NULL || app_root[0] ==
'\0') {
1306 manifest_path =
path_join(app_root,
"pharos.app.json");
1307 if (manifest_path != NULL &&
path_exists(manifest_path)) {
1310 free(manifest_path);
1315 char *socket_value = NULL;
1316 char *resolved_socket_path = NULL;
1317 if (config != NULL && config->
socket_path != NULL) {
1320 if (runtime_conf_path == NULL) {
1324 if (socket_value == NULL) {
1329 return resolved_socket_path;
1333 char *content = NULL;
1334 if (file_path == NULL) {
1338 if (content == NULL) {
1341 fputs(content, stdout);
1347 char *host_profile = NULL;
1348 char *manifest_path = NULL;
1349 char *manifest_text = NULL;
1350 char *seed_entrypoint = NULL;
1351 if (app_root == NULL || target_id == NULL) {
1360 if (host_profile != NULL &&
streq(host_profile,
"static-pages")) {
1365 manifest_path =
path_join(app_root,
"pharos.app.json");
1366 manifest_text = manifest_path != NULL ?
read_file_text(manifest_path) : NULL;
1367 free(manifest_path);
1368 if (manifest_text != NULL) {
1370 free(manifest_text);
1372 if (seed_entrypoint == NULL || seed_entrypoint[0] ==
'\0') {
1374 free(seed_entrypoint);
1375 snprintf(buffer,
sizeof(buffer),
"%s/runtime/%s_native_host", app_root, target_id);
1378 if (seed_entrypoint[0] ==
'/') {
1379 return seed_entrypoint;
1382 char *resolved_seed =
path_join(app_root, seed_entrypoint);
1383 free(seed_entrypoint);
1384 return resolved_seed;
1389 char *seed_entrypoint;
1390 char *resolved_state;
1391 char *resolved_base;
1392 char *build_dir = NULL;
1393 char *pharos_bin_path = NULL;
1395 const char *env_keys[2];
1396 const char *env_values[2];
1397 size_t env_count = 0;
1398 char *output = NULL;
1401 if (config == NULL || app_root == NULL || app_id == NULL || app_id[0] ==
'\0' || (!config->
seed_state && !force_seed)) {
1406 if (seed_entrypoint == NULL || !
path_exists(seed_entrypoint)) {
1408 free(seed_entrypoint);
1413 build_dir != NULL ? build_dir :
"dist",
1419 argv_list[argc++] = seed_entrypoint;
1420 argv_list[argc++] =
"--build-dir";
1421 argv_list[argc++] = build_dir != NULL ? build_dir :
"dist";
1422 argv_list[argc++] =
"--state-path";
1423 argv_list[argc++] = resolved_state != NULL ? resolved_state :
"";
1424 argv_list[argc++] =
"--base-path";
1425 argv_list[argc++] = resolved_base != NULL ? resolved_base :
"/";
1426 argv_list[argc++] =
"--seed-state";
1427 argv_list[argc] = NULL;
1430 if (pharos_bin_path != NULL &&
path_exists(pharos_bin_path)) {
1431 env_keys[env_count] =
"PHAROS_BIN";
1432 env_values[env_count] = pharos_bin_path;
1437 env_keys[env_count] =
"PHAROS_RUNTIME_CONF_PATH";
1438 env_values[env_count] = config->
conf_path;
1442 if (code != 0 && output != NULL && output[0] !=
'\0') {
1443 fprintf(stderr,
"%s", output);
1446 free(pharos_bin_path);
1448 free(resolved_state);
1449 free(resolved_base);
1450 free(seed_entrypoint);
1455 char *app_root = NULL;
1456 char *artifact_dir_native = NULL;
1457 char *status_output = NULL;
1462 char *direct_manifest_text = direct_manifest != NULL ?
read_file_text(direct_manifest) : NULL;
1463 char *direct_app_id = direct_manifest_text != NULL ?
json_find_string(direct_manifest_text,
"app_id") : NULL;
1464 char *direct_build_artifact_dir = direct_manifest_text != NULL ?
json_find_string_in_section(direct_manifest_text,
"runtime",
"build_artifact_dir") : NULL;
1465 if (direct_app_id != NULL &&
streq(direct_app_id, config->
target_id) && direct_build_artifact_dir != NULL &&
streq(direct_build_artifact_dir,
".")) {
1467 char *direct_build_dir = NULL;
1468 if (direct_root == NULL) {
1471 if (direct_root != NULL) {
1474 if (direct_root != NULL && direct_build_dir != NULL) {
1478 free(direct_build_artifact_dir);
1479 free(direct_app_id);
1480 free(direct_manifest_text);
1481 free(direct_manifest);
1482 free(direct_build_dir);
1489 free(direct_build_dir);
1491 }
else if (direct_app_id != NULL &&
streq(direct_app_id, config->
target_id)) {
1493 if (app_root == NULL) {
1497 free(direct_build_artifact_dir);
1498 free(direct_app_id);
1499 free(direct_manifest_text);
1500 free(direct_manifest);
1502 if (app_root == NULL) {
1505 if (app_root != NULL) {
1508 int packaged_artifact_mode = 0;
1509 memset(&local_config, 0,
sizeof(local_config));
1510 if (build_dir == NULL) {
1516 packaged_artifact_mode = 1;
1520 if (packaged_artifact_mode) {
1539 if (code == 0 && artifact_dir_native != NULL) {
1541 free(artifact_dir_native);
1542 artifact_dir_native = NULL;
1560 fprintf(stderr,
"%s", status_output != NULL ? status_output :
"failed to build/status Pharos app\n");
1561 free(status_output);
1565 free(status_output);
1566 if (artifact_dir == NULL) {
1582 char *temp_body_path = NULL;
1584 const char *env_keys[2];
1585 const char *env_values[2];
1586 size_t env_count = 0;
1589 if (stderr_text != NULL) {
1590 *stderr_text = NULL;
1592 if (stderr_len != NULL) {
1597 if (temp_body_path == NULL) {
1600 }
else if (request->
body_len > 0) {
1623 env_keys[env_count] =
"PHAROS_RUNTIME_CONF_PATH";
1628 static char pharos_bin_path[4096];
1630 snprintf(pharos_bin_path,
sizeof(pharos_bin_path),
"%s\\pharos.exe",
global_binary_dir);
1632 snprintf(pharos_bin_path,
sizeof(pharos_bin_path),
"%s/pharos",
global_binary_dir);
1634 env_keys[env_count] =
"PHAROS_BIN";
1635 env_values[env_count] = pharos_bin_path;
1655 char *native_artifact_dir = NULL;
1656 char *status_output = NULL;
1657 char *artifact_dir = NULL;
1661 return native_artifact_dir;
1665 fprintf(stderr,
"%s", status_output != NULL ? status_output :
"failed to build/status Pharos website\n");
1666 free(status_output);
1670 free(status_output);
1671 return artifact_dir;
1675 char *runtime_conf_path = NULL;
1676 char *runtime_conf_dir = NULL;
1677 char *apps_dir_value = NULL;
1678 char *build_dir_value = NULL;
1679 char *state_dir_value = NULL;
1680 char *state_path_value = NULL;
1681 char *base_path_value = NULL;
1682 char *resolved_build_dir = NULL;
1683 char *resolved_state_dir = NULL;
1684 char *resolved_state_path = NULL;
1686 memset(stack, 0,
sizeof(*stack));
1687 memset(&effective_config, 0,
sizeof(effective_config));
1688 if (config != NULL) {
1689 effective_config = *config;
1697 resolved_build_dir = build_dir_value != NULL ?
resolve_relative_to(runtime_conf_dir, build_dir_value) : NULL;
1698 effective_config.
build_dir = resolved_build_dir;
1702 resolved_state_dir = state_dir_value != NULL ?
resolve_relative_to(runtime_conf_dir, state_dir_value) : NULL;
1703 effective_config.
state_dir = resolved_state_dir;
1707 resolved_state_path = state_path_value != NULL ?
resolve_relative_to(runtime_conf_dir, state_path_value) : NULL;
1708 effective_config.
state_path = resolved_state_path;
1712 effective_config.
base_path = base_path_value;
1717 free(apps_dir_value);
1722 DIR *dir = opendir(apps_dir);
1723 struct dirent *entry;
1726 free(runtime_conf_path);
1727 free(runtime_conf_dir);
1731 char *root_manifest =
path_join(apps_dir,
"pharos.app.json");
1732 char *root_manifest_text = root_manifest != NULL ?
read_file_text(root_manifest) : NULL;
1733 char *root_app_id = root_manifest_text != NULL ?
json_find_string(root_manifest_text,
"app_id") : NULL;
1734 if (root_app_id != NULL && root_app_id[0] !=
'\0') {
1737 free(root_manifest);
1738 free(root_manifest_text);
1741 while ((entry = readdir(dir)) != NULL && stack->
count <
MAX_APPS) {
1743 char *app_manifest_path;
1744 char *app_manifest_text;
1746 if (
streq(entry->d_name,
".") ||
streq(entry->d_name,
"..")) {
1749 app_root =
path_join(apps_dir, entry->d_name);
1754 app_manifest_path =
path_join(app_root,
"pharos.app.json");
1757 free(app_manifest_path);
1761 free(app_manifest_path);
1762 if (app_manifest_text == NULL) {
1767 free(app_manifest_text);
1768 if (app_id == NULL) {
1780 free(runtime_conf_path);
1781 free(runtime_conf_dir);
1782 free(build_dir_value);
1783 free(state_dir_value);
1784 free(state_path_value);
1785 free(base_path_value);
1786 free(resolved_build_dir);
1787 free(resolved_state_dir);
1788 free(resolved_state_path);
1789 if (stack->
count == 0) {
1798 char *response = NULL;
1799 char *stderr_text = NULL;
1800 char *static_target = NULL;
1801 char *request_target = NULL;
1802 char *log_target = NULL;
1803 char *response_status = NULL;
1804 size_t response_len = 0;
1805 size_t stderr_len = 0;
1811 if (static_target == NULL) {
1820 log_target = request_target != NULL ?
pharos_strdup(request_target) : NULL;
1821 if (request_target != NULL) {
1822 dynamic_request.
target = request_target;
1825 if (dyn_status >= 200 && dyn_status < 400) {
1833 char dyn_detail[128];
1834 snprintf(dyn_detail,
sizeof(dyn_detail),
"native_dynamic_status=%d", dyn_status);
1841 dyn_status >= 200 && dyn_status < 300 ?
"200 OK" : (dyn_status == 404 ?
"404 Not Found" :
"500 Internal Server Error"),
1842 "native_dynamic_runtime",
1850 log_target = request_target != NULL ?
pharos_strdup(request_target) : NULL;
1851 if (request_target != NULL) {
1852 spawned_request.
target = request_target;
1854 int code =
spawn_app_request(&context->
app, &spawned_request, &response, &response_len, &stderr_text, &stderr_len);
1855 if (code != 0 || response == NULL || response_len == 0) {
1856 char exit_detail[512];
1857 if (response != NULL && response_len > 0) {
1860 sizeof(exit_detail),
1861 "host_exit_code=%d output_len=%zu entrypoint=%s",
1869 sizeof(exit_detail),
1870 "host_exit_code=%d no_output entrypoint=%s",
1887 if (stderr_text != NULL && stderr_len > 0) {
1903 if (stderr_text != NULL && stderr_len > 0) {
1910 response_status != NULL ? response_status :
"200 OK",
1916 if (response_status != NULL) {
1918 if (response_code >= 200 && response_code < 400) {
1941 free(response_status);
1943 free(request_target);
1944 free(static_target);
1955 if (context == NULL) {
1973 if (value < minimum) {
1976 if (value > maximum) {
1991 unsigned long long parsed;
1992 if (text == NULL || text[0] ==
'\0' || value_out == NULL) {
1996 parsed = strtoull(text, &end, 10);
1997 if (errno != 0 || end == text || end == NULL || *end !=
'\0' || parsed == 0ULL) {
2000 if (parsed > (
unsigned long long)SIZE_MAX) {
2003 *value_out = (size_t)parsed;
2016 char *raw_value = NULL;
2018 if (runtime_conf_path == NULL || runtime_conf_path[0] ==
'\0' || key == NULL || key[0] ==
'\0') {
2034 MEMORYSTATUSEX statex;
2035 memset(&statex, 0,
sizeof(statex));
2036 statex.dwLength =
sizeof(statex);
2037 if (GlobalMemoryStatusEx(&statex)) {
2038 return (
unsigned long long)statex.ullTotalPhys;
2042#ifdef _SC_PHYS_PAGES
2045 long pages = sysconf(_SC_PHYS_PAGES);
2046 long page_size = sysconf(_SC_PAGESIZE);
2047 if (pages > 0L && page_size > 0L) {
2048 return (
unsigned long long)pages * (
unsigned long long)page_size;
2064 SYSTEM_INFO system_info;
2065 GetSystemInfo(&system_info);
2066 if (system_info.dwNumberOfProcessors > 0U) {
2070#ifdef _SC_NPROCESSORS_ONLN
2072 long cpu_count = sysconf(_SC_NPROCESSORS_ONLN);
2073 if (cpu_count > 0L) {
2089 if (memory_bytes == 0ULL) {
2094 size_t bounded_slots;
2095 if (slots == 0ULL) {
2098 if (slots > (
unsigned long long)SIZE_MAX) {
2101 bounded_slots = (size_t)slots;
2118 size_t configured = 0;
2132 size_t configured = 0;
2149 if (context == NULL) {
2176 EnterCriticalSection(&pool->
mutex);
2178 SleepConditionVariableCS(&pool->
not_empty, &pool->
mutex, INFINITE);
2180 if (pool->
count > 0) {
2186 LeaveCriticalSection(&pool->
mutex);
2189 LeaveCriticalSection(&pool->
mutex);
2205 pthread_mutex_lock(&pool->
mutex);
2209 if (pool->
count > 0) {
2215 pthread_mutex_unlock(&pool->
mutex);
2218 pthread_mutex_unlock(&pool->
mutex);
2235 if (pool == NULL || worker_count == 0 || capacity == 0) {
2238 memset(pool, 0,
sizeof(*pool));
2240 if (pool->
items == NULL) {
2246 pool->
threads = (HANDLE *)calloc(worker_count,
sizeof(HANDLE));
2249 memset(pool, 0,
sizeof(*pool));
2252 InitializeCriticalSection(&pool->
mutex);
2253 InitializeConditionVariable(&pool->
not_empty);
2254 for (index = 0; index < worker_count; index++) {
2256 if (thread_handle == 0) {
2263 pool->
threads[index] = (HANDLE)thread_handle;
2266 pool->
threads = (pthread_t *)calloc(worker_count,
sizeof(pthread_t));
2269 memset(pool, 0,
sizeof(*pool));
2272 if (pthread_mutex_init(&pool->
mutex, NULL) != 0) {
2275 memset(pool, 0,
sizeof(*pool));
2278 if (pthread_cond_init(&pool->
not_empty, NULL) != 0) {
2279 pthread_mutex_destroy(&pool->
mutex);
2282 memset(pool, 0,
sizeof(*pool));
2285 for (index = 0; index < worker_count; index++) {
2307 if (pool == NULL || context == NULL) {
2311 EnterCriticalSection(&pool->
mutex);
2318 WakeConditionVariable(&pool->
not_empty);
2320 LeaveCriticalSection(&pool->
mutex);
2322 if (pthread_mutex_lock(&pool->
mutex) != 0) {
2333 pthread_mutex_unlock(&pool->
mutex);
2348 EnterCriticalSection(&pool->
mutex);
2350 WakeAllConditionVariable(&pool->
not_empty);
2351 LeaveCriticalSection(&pool->
mutex);
2353 if (pthread_mutex_lock(&pool->
mutex) != 0) {
2357 pthread_cond_broadcast(&pool->
not_empty);
2358 pthread_mutex_unlock(&pool->
mutex);
2369 if (pool == NULL || pool->
threads == NULL) {
2374 if (pool->
threads[index] != NULL) {
2375 WaitForSingleObject(pool->
threads[index], INFINITE);
2376 CloseHandle(pool->
threads[index]);
2382 pthread_join(pool->
threads[index], NULL);
2397 if (pool->
items != NULL) {
2398 for (index = 0; index < pool->
count; index++) {
2399 size_t item_index = (pool->
head + index) % pool->
capacity;
2404 DeleteCriticalSection(&pool->
mutex);
2407 pthread_mutex_destroy(&pool->
mutex);
2411 memset(pool, 0,
sizeof(*pool));
2417 struct dirent *entry;
2418 char *marker_path = NULL;
2420 if (root_path == NULL || root_path[0] ==
'\0' || !
path_is_directory(root_path)) {
2423 marker_path =
path_join(root_path,
".metadata_never_index");
2424 if (marker_path == NULL) {
2432 dir = opendir(root_path);
2436 while ((entry = readdir(dir)) != NULL) {
2438 if (
streq(entry->d_name,
".") ||
streq(entry->d_name,
"..")) {
2441 child_path =
path_join(root_path, entry->d_name);
2442 if (child_path == NULL) {
2467 printf(
"pharos runtime\n\n");
2468 printf(
"command families:\n");
2469 printf(
" targets bootstrap host target native json barcode\n");
2470 printf(
" migrate db jobs integrations backup restore deploy drift\n");
2471 printf(
" api admin build verify status run serve probe smoke doctor maintenance noindex\n\n");
2473 printf(
" pharos --help\n");
2474 printf(
" pharos --version\n");
2475 printf(
" pharos targets [text|json]\n");
2476 printf(
" pharos bootstrap build [out-dir]\n");
2477 printf(
" pharos bootstrap install [install-dir]\n");
2478 printf(
" pharos host detect\n");
2479 printf(
" pharos host build [source-bootstrap|native] [out-root]\n");
2480 printf(
" pharos target build-all [source-bootstrap|native] [out-root]\n");
2481 printf(
" pharos target build <target-id> [source-bootstrap|native] [out-root]\n");
2482 printf(
" pharos native build-target <target-id> [out-root]\n");
2483 printf(
" pharos native build-all [out-root]\n");
2484 printf(
" pharos native verify-target <target-id> [out-root]\n");
2485 printf(
" pharos native verify-all [out-root]\n");
2486 printf(
" pharos native smoke-target <target-id> [out-root]\n");
2487 printf(
" pharos native smoke-server <target-id> [out-root] [port] [site-root]\n");
2488 printf(
" pharos native package-release [out-root]\n");
2489 printf(
" pharos native verify-release-bundle [out-root]\n");
2490 printf(
" pharos native toolchain\n");
2491 printf(
" pharos json bundle manifest-slice-order --manifest PATH\n");
2492 printf(
" pharos json bundle manifest-layer-for-slice --manifest PATH --slice NAME\n");
2493 printf(
" pharos barcode decode IMAGE_PATH\n");
2494 printf(
" pharos noindex PATH\n");
2495 printf(
" pharos migrate <plan|status|seed|verify|apply|rollback> app <target-id> [--conf PATH] [--app-dir PATH] [--build-dir PATH] [--backend sqlite|postgresql] [--text]\n");
2496 printf(
" pharos db seed app <target-id> [--conf PATH] [--app-dir PATH] [--build-dir PATH] [--backend sqlite|postgresql] [--text]\n");
2497 printf(
" pharos jobs <inspect|run|replay> app <target-id> [--conf PATH] [--app-dir PATH] [--build-dir PATH] [--backend sqlite|postgresql] [--case CASE_ID] [--workflow WORKFLOW_ID] [--transition TRANSITION_ID] [--subject-id SUBJECT_ID] [--resource-id RESOURCE_ID] [--from-state STATE] [--idempotency-key KEY] [--trace-id TRACE_ID] [--execution-id ID] [--max-jobs N] [--retry-failed] [--requeue-stuck] [--text]\n");
2498 printf(
" pharos integrations <inspect|deliver> app <target-id> [--conf PATH] [--app-dir PATH] [--build-dir PATH] [--state-dir PATH|--state-path PATH] [--adapter-id ADAPTER_ID] [--delivery-id ID] [--event-kind KIND] [--resource-id RESOURCE_ID] [--tenant-id TENANT_ID] [--subject-id SUBJECT_ID] [--payload-json JSON] [--retry-failed] [--max-deliveries N] [--text]\n");
2499 printf(
" pharos backup app <target-id> [--conf PATH] [--build-dir PATH] [--backend sqlite|postgresql] [--output-dir PATH] [--text]\n");
2500 printf(
" pharos restore app <target-id> [--conf PATH] [--build-dir PATH] [--backend sqlite|postgresql] --input-dir PATH [--text]\n");
2501 printf(
" pharos deploy check app <target-id> [--conf PATH] [--build-dir PATH] [--backend sqlite|postgresql] [--text]\n");
2502 printf(
" pharos deploy package deb --binary PATH --target-id TARGET_ID [--output-dir PATH] [--text]\n");
2503 printf(
" pharos drift check app <target-id> [--conf PATH] [--build-dir PATH] [--backend sqlite|postgresql] [--text]\n");
2504 printf(
" pharos api <generate|schema> app <target-id> [--build-dir PATH] [--surface SURFACE_ID] [--text]\n");
2505 printf(
" pharos admin generate app <target-id> [--build-dir PATH] [--surface SURFACE_ID] [--text]\n");
2506 printf(
" pharos build runtime <runtime-id> --conf PATH [--text]\n");
2507 printf(
" pharos status runtime <runtime-id> --conf PATH [--text]\n");
2508 printf(
" pharos serve runtime <runtime-id> --conf PATH [--socket-path PATH]\n");
2509 printf(
" pharos build <website|app> <target-id> [--conf PATH] [--app-dir PATH] [--build-dir PATH] [--state-dir PATH|--state-path PATH] [--base-path PATH] [--log-path PATH] [--error-report-path PATH] [--debug BOOL] [--text]\n");
2510 printf(
" pharos verify <website|app> <target-id> [--conf PATH] [--app-dir PATH] [--build-dir PATH] [--state-dir PATH|--state-path PATH] [--base-path PATH] [--log-path PATH] [--error-report-path PATH] [--debug BOOL] [--text]\n");
2511 printf(
" pharos status <website|app> <target-id> [--conf PATH] [--app-dir PATH] [--build-dir PATH] [--state-dir PATH|--state-path PATH] [--base-path PATH] [--log-path PATH] [--error-report-path PATH] [--debug BOOL] [--text]\n");
2512 printf(
" pharos run <website|app> <target-id> [--conf PATH] [--app-dir PATH] [--build-dir PATH] [--state-dir PATH|--state-path PATH] [--base-path PATH] [--log-path PATH] [--error-report-path PATH] [--debug BOOL] [--text]\n");
2513 printf(
" pharos serve <website|app> <target-id> [--conf PATH] [--app-dir PATH] [--build-dir PATH] [--state-dir PATH|--state-path PATH] [--base-path PATH] [--log-path PATH] [--error-report-path PATH] [--debug BOOL] [--socket-path PATH] [--host HOST] [--port PORT]\n");
2514 printf(
" pharos probe app <target-id> [--conf PATH] [--app-dir PATH] [--build-dir PATH] [--text]\n");
2515 printf(
" pharos smoke app <target-id> [--conf PATH] [--app-dir PATH] [--build-dir PATH] [--text]\n");
2516 printf(
" pharos doctor app <target-id> [--conf PATH] [--app-dir PATH] [--build-dir PATH] [--text]\n");
2517 printf(
" pharos maintenance app <target-id> <action> [--conf PATH] [--app-dir PATH] [--build-dir PATH] [--state-dir PATH|--state-path PATH] [--base-path PATH] [--text]\n");
2523 switch (status_code) {
2525 return "Bad Request";
2527 return "Payload Too Large";
2529 return "URI Too Long";
2531 return "Request Header Fields Too Large";
2533 return "Not Implemented";
2535 return "Bad Request";
2540 switch (status_code) {
2542 return "request body exceeds native runtime limits\n";
2544 return "request target exceeds native runtime limits\n";
2546 return "request headers exceed native runtime limits\n";
2548 return "transfer encoding not supported\n";
2551 return "malformed request\n";
2558 if (accept_status == 0) {
2561 if (accept_status < 0) {
2565 if (parse_status != 0) {
2566 if (parse_status >= 400 && parse_status < 600) {
2582 if (worker == NULL) {
2589 memset(request, 0,
sizeof(*request));
2600 if (strcmp(request->
target,
"/health") == 0) {
2604 if (strcmp(request->
target,
"/version") != 0) {
2615 if (server_fd < 0) {
2616 fprintf(stderr,
"failed to open listener\n");
2627 if (request_status == 0) {
2630 if (request_status < 0) {
2633 if (strcmp(request.
method,
"GET") != 0 && strcmp(request.
method,
"HEAD") != 0 && !(strcmp(request.
method,
"POST") == 0 &&
starts_with(request.
target,
"/api/projects/"))) {
2656 size_t worker_count;
2657 size_t queue_capacity;
2660 memset(&pool, 0,
sizeof(pool));
2662 fprintf(stderr,
"failed to load Pharos app runtime for %s\n", config->
target_id);
2669 fprintf(stderr,
"failed to initialize native worker pool\n");
2673 if (server_fd < 0) {
2678 fprintf(stderr,
"failed to open listener\n");
2683 "pharos native app runtime listening on %s target=%s worker_pool=true workers=%zu queue_capacity=%zu\n",
2696 if (request_status == 0) {
2699 if (request_status < 0) {
2703 if (worker == NULL) {
2710 if (enqueue_status == 1) {
2715 if (enqueue_status != 0) {
2732 size_t worker_count;
2733 size_t queue_capacity;
2736 struct timeval load_started;
2737 struct timeval load_finished;
2738 char *apps_dir = NULL;
2739 char *fingerprint = NULL;
2740 memset(&pool, 0,
sizeof(pool));
2741 gettimeofday(&load_started, NULL);
2743 fprintf(stderr,
"failed to load Pharos runtime stack\n");
2746 gettimeofday(&load_finished, NULL);
2751 fprintf(stderr,
"failed to initialize native worker pool\n");
2755 if (server_fd < 0) {
2760 fprintf(stderr,
"failed to open listener\n");
2767 long startup_ms = (long)((load_finished.tv_sec - load_started.tv_sec) * 1000L + (load_finished.tv_usec - load_started.tv_usec) / 1000L);
2772 "pharos native runtime worker_pool=true workers=%zu queue_capacity=%zu\n",
2779 if (next_fingerprint != NULL && (fingerprint == NULL || strcmp(next_fingerprint, fingerprint) != 0)) {
2781 memset(&refreshed_stack, 0,
sizeof(refreshed_stack));
2784 stack = refreshed_stack;
2786 fingerprint = next_fingerprint;
2790 fprintf(stderr,
"failed to refresh Pharos runtime stack\n");
2791 free(next_fingerprint);
2794 free(next_fingerprint);
2804 if (request_status == 0) {
2807 if (request_status < 0) {
2815 if (matched == NULL) {
2822 if (worker == NULL) {
2829 if (enqueue_status == 1) {
2834 if (enqueue_status != 0) {
2854 if (artifact_root == NULL) {
2857 free(config_copy.
root);
2858 config_copy.
root = artifact_root;
2860 config_copy.
root = NULL;
2865 static const struct {
2874 for (index = 0; index <
sizeof(handler_map) /
sizeof(handler_map[0]); index++) {
2875 if (
streq(kind, handler_map[index].kind)) {
2876 return handler_map[index].handler;
2888 if (config.
kind == NULL) {
2889 if (config.
root == NULL) {
2899 fprintf(stderr,
"missing target id for serve %s\n", config.
kind);
2904 if (handler == NULL) {
2908 code = handler(&config);
2914 static const char *status_like_verbs[] = {
2915 "status",
"verify",
"run",
"probe",
"smoke",
"doctor",
"release",
2916 "restore",
"compare",
"snapshot",
"export",
"import",
"diff",
2920 if (
streq(verb,
"build")) {
2923 for (index = 0; index <
sizeof(status_like_verbs) /
sizeof(status_like_verbs[0]); index++) {
2924 if (
streq(verb, status_like_verbs[index])) {
2933 const char *target_kind;
2934 const char *target_id;
2935 const char *build_dir =
"dist";
2937 char *report_path = NULL;
2943 target_kind = argv[1];
2944 target_id = argv[2];
2948 for (index = 3; index < argc; index++) {
2949 if (
streq(argv[index],
"--build-dir") && index + 1 < argc) {
2950 build_dir = argv[index + 1];
2967 if (report_path != NULL) {
2969 if (content != NULL) {
2970 fputs(content, stdout);
2979 static const char *supported_verbs[] = {
2980 "build",
"status",
"verify",
"run",
"probe",
"smoke",
"doctor"
2983 for (index = 0; index <
sizeof(supported_verbs) /
sizeof(supported_verbs[0]); index++) {
2984 if (
streq(verb, supported_verbs[index])) {
2992 static const struct {
2994 const char *report_id;
2996 {
"status",
"pharos-status-v1" },
2997 {
"verify",
"pharos-local-app-build-v1" },
2998 {
"run",
"pharos-local-app-runtime-v1" },
2999 {
"probe",
"pharos-local-app-runtime-v1" },
3000 {
"smoke",
"pharos-local-app-runtime-v1" },
3001 {
"doctor",
"pharos-doctor-v1" }
3004 for (index = 0; index <
sizeof(report_map) /
sizeof(report_map[0]); index++) {
3005 if (
streq(verb, report_map[index].verb)) {
3006 return report_map[index].report_id;
3009 return "pharos-local-app-runtime-v1";
3014 char *app_root = NULL;
3015 char *artifact_dir = NULL;
3016 char *report_path = NULL;
3017 char *report_json = NULL;
3018 char *resolved_build_dir = NULL;
3019 char *build_dir_override = NULL;
3022 if (verb == NULL || config == NULL || config->
target_id == NULL) {
3031 if (app_root == NULL) {
3032 fprintf(stderr,
"unable to locate app root for app target: %s\n", config->
target_id);
3035 memset(&app, 0,
sizeof(app));
3048 free(build_dir_override);
3054 free(build_dir_override);
3062 free(build_dir_override);
3068 resolved_build_dir = build_dir_override;
3069 if (resolved_build_dir == NULL ||
3071 free(resolved_build_dir);
3078 free(resolved_build_dir);
3079 if (
streq(verb,
"build")) {
3092 if (report_json != NULL && report_path != NULL) {
3102 }
else if (
streq(verb,
"doctor")) {
3115 "native-host-target",
3124 if (report_json == NULL) {
3127 fputs(report_json, stdout);
3136 char *apps_dir = NULL;
3137 char *report_path = NULL;
3138 char *report_json = NULL;
3161 memset(&stack, 0,
sizeof(stack));
3173 if (report_path == NULL) {
3179 report_json =
streq(verb,
"build")
3182 if (report_json == NULL) {
3202 char *app_root = NULL;
3203 char *artifact_dir = NULL;
3204 char *report_path = NULL;
3205 char *resolved_build_dir = NULL;
3207 if (artifact_dir_out != NULL) {
3208 *artifact_dir_out = NULL;
3210 if (app_out == NULL || config == NULL || config->
target_id == NULL) {
3213 memset(app_out, 0,
sizeof(*app_out));
3215 if (app_root == NULL) {
3234 free(resolved_build_dir);
3241 free(resolved_build_dir);
3244 if (artifact_dir_out != NULL) {
3245 *artifact_dir_out = artifact_dir;
3254 for (index = 0; index < argc - 1; index++) {
3255 if ((first_name != NULL &&
streq(argv[index], first_name)) || (second_name != NULL &&
streq(argv[index], second_name))) {
3256 return argv[index + 1];
3269 if (option == NULL || value == NULL) {
3272 if (
streq(option,
"--binary")) {
3273 *binary_path = (
char *)value;
3276 if (
streq(option,
"--target-id")) {
3277 *target_id = (
char *)value;
3280 if (
streq(option,
"--output") ||
streq(option,
"--output-dir")) {
3281 *output_dir = (
char *)value;
3289 char *binary_path = NULL;
3290 char *target_id = NULL;
3291 char *output_dir = NULL;
3292 char *argv_list[17];
3293 char *output = NULL;
3294 char *package_path_json;
3297 char *report_json = NULL;
3301 if (argc < 3 || argv == NULL || script == NULL) {
3305 for (index = 3; index < argc; index++) {
3306 if (index + 1 >= argc) {
3319 if (binary_path == NULL || target_id == NULL) {
3323 argv_list[child_argc++] =
"/bin/sh";
3324 argv_list[child_argc++] = script;
3325 argv_list[child_argc++] =
"--binary";
3326 argv_list[child_argc++] = binary_path;
3327 argv_list[child_argc++] =
"--target-id";
3328 argv_list[child_argc++] = target_id;
3329 if (output_dir != NULL) {
3330 argv_list[child_argc++] =
"--output";
3331 argv_list[child_argc++] = output_dir;
3333 argv_list[child_argc] = NULL;
3336 if (output != NULL) {
3339 if (code != 0 || output == NULL || output[0] ==
'\0') {
3341 return code == 0 ? 69 : code;
3346 if (package_path_json != NULL && binary_json != NULL && target_json != NULL) {
3347 size_t needed = strlen(package_path_json) + strlen(binary_json) + strlen(target_json) + 192;
3348 report_json = (
char *)malloc(needed);
3349 if (report_json != NULL) {
3350 snprintf(report_json, needed,
"{\"report_id\":\"pharos-deploy-package-v1\",\"format\":\"deb\",\"target_id\":%s,\"binary\":%s,\"package_path\":%s,\"status\":\"packaged\"}", target_json, binary_json, package_path_json);
3354 free(package_path_json);
3357 if (report_json == NULL) {
3360 fputs(report_json, stdout);
3379 char **artifact_dir,
3394 if (report_json == NULL) {
3397 fputs(report_json, stdout);
3404 char *artifact_dir = NULL;
3405 char *report_json = NULL;
3406 char *backend_override;
3407 char *output_dir_override;
3409 char *error_text = NULL;
3418 report_json =
streq(argv[0],
"backup")
3424 if (report_json != NULL) {
3430 if (error_text != NULL && error_text[0] !=
'\0') {
3431 fprintf(stderr,
"%s\n", error_text);
3440 char *artifact_dir = NULL;
3441 char *report_json = NULL;
3450 if (report_json == NULL) {
3461 char *artifact_dir = NULL;
3462 char *report_json = NULL;
3477 if (report_json == NULL) {
3493 if (argc < min_argc || argv == NULL || argv[0] == NULL) {
3496 if (first != NULL && !
streq(argv[0], first)) {
3499 if (second != NULL && (argc < 2 || !
streq(argv[1], second))) {
3502 if (third != NULL && (argc < 3 || !
streq(argv[2], third))) {
3511 if (argc != 2 || argv == NULL || argv[0] == NULL || argv[1] == NULL || !
streq(argv[0],
"noindex")) {
3515 if (target_path == NULL) {
3518 if (target_path == NULL) {
3523 printf(
"marked noindex: %s\n", target_path);
3530 static const struct {
3535 int (*handler)(
int argc,
char **argv);
3536 } dispatch_table[] = {
3544 for (index = 0; index <
sizeof(dispatch_table) /
sizeof(dispatch_table[0]); index++) {
3548 dispatch_table[index].first,
3549 dispatch_table[index].second,
3550 dispatch_table[index].third,
3551 dispatch_table[index].min_argc
3553 return dispatch_table[index].handler(argc, argv);
3576 if (strcmp(argv[1],
"--help") == 0 || strcmp(argv[1],
"-h") == 0) {
3582 if (strcmp(argv[1],
"--version") == 0) {
3588 if (strcmp(argv[1],
"serve") == 0) {
3594 if (strcmp(argv[1],
"json") == 0) {
3602 if (barcode_code != 78) {
3605 return barcode_code;
3610 if (noindex_code != 78) {
3613 return noindex_code;
3617 if (ops_code != 78) {
3623 if (website_code != 78) {
3626 return website_code;
3629 if (runtime_code != 78) {
3632 return runtime_code;
3635 fprintf(stderr,
"unable to locate pharos repo root for launcher delegation\n");
3642 return website_code;
void free_app_local_config_native(AppLocalConfigNative *config)
Releases heap-owned fields in an app-local configuration record.
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.
int clone_app_runtime_native(const AppRuntime *source, AppRuntime *target)
Deep-copies one loaded app runtime into another record.
Declares helpers for cloning AppRuntime values.
int finalize_loaded_app_runtime_native(AppRuntime *app, const ServeConfig *config, const char *app_root_override, const char *build_dir_override)
Applies overrides and derived runtime paths to a loaded app runtime record.
Declares helpers that finalize loaded app runtime configuration.
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 * effective_app_debug_native(const char *app_root, const char *debug_override)
Resolves the effective 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 * 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 * effective_app_base_path_native(const char *app_root, const char *base_path_override)
Resolves the effective URL base path for an app.
Declares helpers for locating app roots and deriving runtime paths.
char * build_native_app_index_html(const char *app_id)
Builds the default index.html payload for a native app artifact.
char * native_website_artifact_dir(const char *build_dir, const char *target_id)
Builds the artifact directory path for a generated website target.
char * json_string_dup_native(const char *value)
Duplicates a string while escaping it for JSON string output.
char * native_website_report_path(const char *build_dir, const char *verb, const char *target_id)
Builds the report file path for a website build or status operation.
int count_substring_occurrences(const char *text, const char *needle)
Counts how many times a substring occurs in a string.
char * build_native_app_build_report_json(const char *artifact_dir, const char *app_id, const char *state_path, const char *base_path, const char *log_path, const char *log_format, const char *error_report_path, const char *debug, const char *host_profile, const char *compiled_entrypoint)
Builds a JSON report describing a native app build result.
char * build_artifact_local_app_manifest_json(const char *manifest_text, const char *artifact_generated_by, const char *state_path, const char *base_path, const char *log_path, const char *log_format, const char *error_report_path, const char *debug, const char *compiled_entrypoint, int route_count, int surface_count, int workflow_count)
Builds an artifact-localized copy of the app-owned manifest.
char * build_native_website_status_report_json(const char *report_id, const char *verb, const char *target_id, const char *artifact_dir)
Builds a JSON status report for a native website artifact.
Declares helpers that build native artifact and report payload strings.
char * build_native_restore_report_local_json(const ServeConfig *config, const AppRuntime *app, const char *backend_override, const char *input_dir, char **error_out)
Builds a JSON report describing a native app restore operation.
char * build_native_backup_report_local_json(const ServeConfig *config, const AppRuntime *app, const char *backend_override, const char *output_dir_override, char **error_out)
Builds a JSON report describing a native app backup operation.
Declares native backup and restore report builders.
int handle_native_barcode_command(int argc, char **argv)
int native_connection_close(NativeConnection *connection)
Closes a native connection and releases its owned metadata.
int native_connection_accept_next(int server_fd, volatile sig_atomic_t *shutdown_requested, NativeConnection *connection)
Accepts the next client connection and records its transport metadata.
int native_connection_write(NativeConnection *connection, const void *buffer, size_t len)
Writes bytes to a native connection.
void native_connection_init(NativeConnection *connection)
Initializes a native connection record to an empty state.
Declares the native connection abstraction and transport metadata helpers.
int native_dynamic_runtime_handle_request(const AppRuntime *app, const HttpRequest *request, NativeConnection *connection)
Serves one dynamic-app request entirely in-process.
In-process dynamic-app request handler for the Pharos native runtime.
int ensure_directory(const char *path)
Creates a directory path and any missing parent directories.
int write_text_file(const char *path, const char *content)
Writes a text buffer to a file path.
int remove_directory_recursive(const char *target_dir)
Recursively removes a directory tree.
int copy_directory_recursive(const char *source_dir, const char *target_dir)
Recursively copies one directory tree into another location.
int copy_file_binary(const char *source_path, const char *target_path)
Copies one file as binary data.
Declares native filesystem helper routines.
void native_write_access_log(const char *log_path, const HttpRequest *request, const char *request_path, int status_code)
Writes one access log entry for a completed HTTP request.
void native_write_error_log(const char *log_path, const char *error_report_path, const char *app_id, const HttpRequest *request, const char *request_path, const char *status_text, const char *reason, const char *resource_path, const char *detail_text)
Writes one structured error log entry and its paired JSONL error report.
Declares native access log and error log helpers.
char * http_status_line_from_response_native(const char *response)
Extracts the HTTP status line from a raw HTTP response payload.
int http_status_code_from_response_native(const char *response)
Extracts the numeric HTTP status code from a raw HTTP response payload.
Declares HTTP logging and response formatting helpers.
void free_http_request_native(HttpRequest *request)
Releases heap-owned fields in a parsed HTTP request record.
int parse_http_request_native(NativeConnection *connection, HttpRequest *request)
Parses an HTTP request from a native connection into a request record.
Declares the parsed HTTP request record and request parsing helpers.
void native_send_text_response(NativeConnection *connection, int status, const char *status_text, const char *body)
Sends a plain-text HTTP response with explicit content length.
Declares native HTTP response writing helpers.
char * conf_lookup_value(const char *path, const char *key)
Reads a Pharos conf file and looks up one key.
char * json_extract_array_in_section(const char *text, const char *section, const char *key)
Extracts the raw JSON array text for a key inside a named section.
char * json_find_string(const char *text, const char *key)
Finds the first JSON string value associated with a key.
char * json_find_string_in_section(const char *text, const char *section, const char *key)
Finds a JSON string value for a key inside a named section object.
Declares lightweight JSON and conf value lookup helpers.
int handle_native_json_command(int argc, char **argv)
const char * native_listener_endpoint(const ServeConfig *config)
Returns a printable endpoint string for the active listener configuration.
void native_listener_register_cleanup(NativeListenerState *state, const ServeConfig *config, int server_fd, volatile sig_atomic_t *shutdown_requested)
Registers the currently active listener for later cleanup.
void native_listener_cleanup_active(NativeListenerState *state)
Closes and unlinks the currently registered listener resources.
void native_listener_state_init(NativeListenerState *state)
Initializes listener cleanup state to an inactive value.
int native_listener_open(const ServeConfig *config)
Opens a listener socket using the supplied serve configuration.
Declares native listener state and socket lifecycle helpers.
char * build_native_app_drift_report_local_json(const char *repo_root, const ServeConfig *config, const AppRuntime *app)
Builds a JSON drift report for one app using native ops bridges.
char * build_native_app_doctor_report_local_json(const char *repo_root, const ServeConfig *config, const char *artifact_dir, const AppRuntime *app, const char *host_target)
Builds a JSON doctor report for one app using native ops bridges.
char * build_native_app_deploy_check_report_local_json(const char *repo_root, const ServeConfig *config, const char *artifact_dir, const AppRuntime *app, const char *host_target)
Builds a JSON deploy-check report for one app using native ops bridges.
Declares native bridge helpers for Pharos ops commands.
int run_process_capture_native(char *const argv[], char **output)
Executes a process and captures its combined output text.
int capture_execv_output_env_native(char *const argv[], const char *env_keys[], const char *env_values[], size_t env_count, char **output, size_t *output_len)
Executes a process with injected environment values and captures its output.
int capture_execv_output_native(char *const argv[], char **output, size_t *output_len)
Executes a process and captures its combined output.
int capture_execv_output_split_env_native(char *const argv[], const char *env_keys[], const char *env_values[], size_t env_count, char **stdout_output, size_t *stdout_len, char **stderr_output, size_t *stderr_len)
Executes a process with injected environment values and captures stdout and stderr separately.
Declares child-process capture helpers.
char * native_request_path_without_query(const char *target)
Removes the query string component from a request target.
char * native_request_target_for_mount(const char *mount_path, const char *target)
Remaps a request target so it is relative to an app mount path.
Declares request target normalization helpers.
void free_runtime_stack(RuntimeStack *stack)
Releases all loaded app runtimes and listener metadata in a runtime stack.
void free_app_runtime(AppRuntime *app)
Releases heap-owned fields in a loaded app runtime record.
Declares cleanup helpers for native runtime-owned data structures.
int load_app_runtime_from_artifact_native(const char *artifact_dir, AppRuntime *app)
Loads runtime metadata for one app from an emitted artifact directory.
Declares helpers for loading native runtime metadata from manifests.
char * build_native_app_runtime_report_json(const char *report_id, const char *verb, const char *host_target, const char *host_mode, const char *artifact_dir, const AppRuntime *app)
Builds a JSON runtime report for one app artifact and host surface.
char * build_native_runtime_status_report_json(const RuntimeStack *stack, const char *apps_dir)
Builds a JSON status report for a loaded runtime stack.
char * build_native_runtime_build_report_json(const char *target_id, const char *conf_path, const char *apps_dir, size_t app_count)
Builds a JSON report describing a native runtime build result.
Declares builders for native runtime report payloads.
char * runtime_apps_dir_native(const char *conf_path)
Resolves the apps directory configured for a runtime config file.
char * runtime_apps_fingerprint_native(const char *apps_dir)
Builds a fingerprint string describing the current runtime apps directory state.
void runtime_log_banner_native(const RuntimeStack *stack, const ServeConfig *config, long load_ms)
Emits a startup banner describing the loaded runtime stack.
AppRuntime * runtime_match_app_native(RuntimeStack *stack, const char *path)
Finds the loaded app runtime that should handle a request path.
Declares runtime stack helpers for app discovery, reload detection, and request matching.
Defines shared native runtime data structures used across the Pharos C runtime.
int parse_serve_config_native(int argc, char **argv, ServeConfig *config)
Parses native serve CLI arguments into a serve configuration record.
void apply_serve_config_defaults_from_conf_native(ServeConfig *config)
Applies runtime-config-derived default values to an already parsed serve config.
void free_serve_config_native(ServeConfig *config)
Releases heap-owned fields in a serve configuration record.
Declares helpers for parsing and normalizing native serve configuration.
int exec_runtime_script_native(const char *repo_root, int argc, char **argv)
Executes the shared Pharos runtime script with the supplied arguments.
int shell_status_or_build_native(const char *repo_root, const ServeConfig *config, int use_build, char **output)
Runs the shell-side status or build flow for one native serve target.
Declares bridge helpers for invoking Pharos shell command surfaces.
int build_native_app_request_argv(const AppRuntime *app, const char *request_method, const char *request_target, const char *request_cookie, const char *request_headers, const char *request_content_type, const char *request_body, int request_is_multipart, const char *temp_body_path, char *argv_list[], size_t argv_capacity, size_t *argc_out)
Builds the argv vector used to execute one compiled app request.
Declares argv construction helpers for spawned app requests.
#define PHAROS_APP_REQUEST_ARGV_CAPACITY
int write_native_temp_body_file(const char *body, size_t body_len, char **temp_body_path_out)
Writes a request body to a temporary file for multipart request execution.
void cleanup_native_temp_body_file(char **temp_body_path_io)
Removes a temporary request-body file and clears its stored path.
Declares temporary request-body file helpers.
int native_serve_static_file(NativeConnection *connection, const char *root, const char *path, const HttpRequest *request, const char *log_path)
Serves one static artifact response from a root directory.
Declares native static artifact serving helpers.
char * path_join(const char *left, const char *right)
Joins two path segments using the native path separator.
void trim_in_place(char *text)
Trims leading and trailing ASCII whitespace from a string in place.
char * path_canonicalize(const char *path)
Normalizes a path by collapsing redundant separators and dot segments.
char * current_working_directory(void)
Returns the current working directory.
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 * resolve_relative_to(const char *base_dir, const char *value)
Resolves a path value relative to a base directory when needed.
char * read_file_text(const char *path)
Reads an entire file into a newly allocated text buffer.
int starts_with(const char *value, const char *prefix)
Tests whether one string starts with another string.
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.
static int handle_static_root_builtin_request(NativeConnection *connection, const HttpRequest *request)
static void install_native_signal_handlers(void)
static int apply_deb_package_option_native(const char *option, const char *value, char **binary_path, char **target_id, char **output_dir)
static void handle_app_or_runtime_request(WorkerContext *context)
static void clear_listener_cleanup_registration(void)
static size_t native_resolved_work_queue_capacity(const char *runtime_conf_path)
Resolve the bounded queued-request capacity for one serve process.
static int handle_native_drift_check_ops_command(int argc, char **argv)
static int load_app_runtime_for_single_app(const ServeConfig *config, AppRuntime *app)
static int handle_serve(int argc, char **argv)
static int website_verb_mode_native(const char *verb)
static int build_known_website_native(const char *target_id, const char *build_dir, char **report_path_out, char **artifact_dir_out)
static int add_runtime_app_native(RuntimeStack *stack, const ServeConfig *config, const char *app_root, const char *app_id_hint)
static int parse_native_app_ops_config(int argc, char **argv, int skip_args, ServeConfig *config)
#define PHAROS_NATIVE_MIN_WORKER_COUNT
static void pharos_native_shutdown_signal_handler(int signum)
static int handle_native_deploy_check_ops_command(int argc, char **argv)
#define PHAROS_NATIVE_WORK_QUEUE_BYTES_PER_SLOT
static const char * native_http_parse_reason_phrase(int status_code)
static void native_send_worker_pool_overload_response(NativeConnection *connection)
Send the standard overload response for saturated native serving.
static void print_version(void)
#define PHAROS_NATIVE_MAX_WORKER_COUNT
static const char * dev_docs_directory_index_html_native(void)
static NativeServeHandlerFn find_serve_handler_native(const char *kind)
static void cleanup_active_listener(void)
#define PHAROS_NATIVE_DEFAULT_WORKER_COUNT
int main(int argc, char **argv)
Native Pharos CLI entrypoint.
static void native_worker_pool_request_shutdown(NativeWorkerPool *pool)
Ask the worker pool to stop after draining queued work.
static int runtime_verb_supported_native(const char *verb)
static int prepare_app_artifact_native(const char *app_root, const char *app_id, const char *build_dir_override, const char *state_dir_override, const char *state_path_override, const char *base_path_override, char **report_path_out, char **artifact_dir_out)
Prepares the artifact directory for an app at startup.
static int build_dev_docs_directory_native(const char *app_root, const char *artifact_dir)
static char * global_binary_dir
#define PHAROS_NATIVE_DEFAULT_WORK_QUEUE_CAPACITY
static int prepare_native_app_ops_runtime(int argc, char **argv, int skip_args, ServeConfig *config, char **artifact_dir, AppRuntime *app)
#define PHAROS_NATIVE_MAX_WORK_QUEUE_CAPACITY
static int handle_native_ops_command(int argc, char **argv)
static int emit_text_file_to_stdout_native(const char *file_path)
static void free_worker_context_native(WorkerContext *context)
Release a worker context and every owned request/runtime resource.
static size_t native_default_worker_count(void)
Resolve the default worker-thread count when config does not override it.
static int handle_native_runtime_command(int argc, char **argv)
static void process_worker_context_native(WorkerContext *context)
Execute one accepted request through the active runtime/app handler.
static int native_parse_positive_size_value(const char *text, size_t *value_out)
Parse one positive size_t from config text.
static char * native_option_value(int argc, char **argv, const char *first_name, const char *second_name)
static int serve_website_target(const ServeConfig *config)
static const char * native_app_runtime_report_id(const char *verb)
static char * resolve_website_root(const ServeConfig *config)
#define PHAROS_NATIVE_MIN_WORK_QUEUE_CAPACITY
static int native_known_website_supported(const char *target_id)
static int serve_single_app(const ServeConfig *config)
static int native_worker_pool_enqueue(NativeWorkerPool *pool, WorkerContext *context)
Submit accepted request work to the bounded worker pool.
static NativeListenerState global_listener_state
static int handle_native_backup_restore_ops_command(int argc, char **argv)
static void native_worker_pool_destroy(NativeWorkerPool *pool)
Destroy worker-pool resources after shutdown and join.
static int handle_native_noindex_command(int argc, char **argv)
static void native_worker_pool_join(NativeWorkerPool *pool)
Join all worker threads created for the pool.
int(* NativeServeHandlerFn)(const ServeConfig *config)
static const char * native_http_parse_error_body(int status_code)
static char * resolve_value_or_default(const char *value, const char *fallback)
static int emit_native_report_json(const char *report_json)
static size_t native_clamp_size_value(size_t value, size_t minimum, size_t maximum)
Clamp one size value into an inclusive range.
static unsigned long long native_detect_physical_memory_bytes(void)
Detect total physical memory visible to the current host.
static WorkerContext * build_worker_context_native(NativeConnection *connection, HttpRequest *request, const AppRuntime *source_app)
static size_t native_resolved_worker_count(const char *runtime_conf_path)
Resolve the fixed worker-thread count for one serve process.
static int serve_static_root(const ServeConfig *config)
static char * resolve_seed_entrypoint_native(const char *app_root, const char *target_id, const char *build_dir_override)
static int load_runtime_stack(const ServeConfig *config, RuntimeStack *stack)
static char * app_runtime_host_profile_native(const char *app_root)
static char * runtime_build_dir_override_native(const ServeConfig *config, const char *app_root)
static int prepare_finalized_app_from_config(const ServeConfig *config, char **artifact_dir_out, AppRuntime *app_out)
static int accept_http_request_native(int server_fd, NativeConnection *connection, HttpRequest *request)
static int native_conf_positive_size_value(const char *runtime_conf_path, const char *key, size_t *value_out)
Read the configured positive size value for one runtime key.
static int write_noindex_markers_recursive_native(const char *root_path)
Recursively write macOS no-index markers through a directory tree.
static char * find_repo_root(const char *argv0)
static void print_help(void)
static int match_native_ops_command(int argc, char **argv, const char *first, const char *second, const char *third, int min_argc)
static int handle_native_website_command(int argc, char **argv)
static void * native_worker_pool_thread_main(void *opaque)
Run queued request work items until the worker pool shuts down.
static int maybe_seed_app_state_native(const ServeConfig *config, const char *app_root, const char *app_id, int force_seed)
static int emit_website_status_native(const char *verb, const char *target_id, const char *build_dir, char **report_path_out)
static int spawn_app_request(const AppRuntime *app, const HttpRequest *request, char **response, size_t *response_len, char **stderr_text, size_t *stderr_len)
static char * global_repo_root
static int build_app_from_root_native(const char *app_root, const char *build_dir_override, const char *state_dir_override, const char *state_path_override, const char *base_path_override, char **report_path_out, char **artifact_dir_out)
static int handle_native_deploy_package_deb_command(int argc, char **argv)
static int serve_runtime_stack_native(const ServeConfig *config)
static size_t native_default_work_queue_capacity(void)
Resolve the default queue capacity from physical memory.
static void register_listener_cleanup(const ServeConfig *config, PHAROS_SOCKET server_fd)
static char * resolve_runtime_socket_path_native(const ServeConfig *config, const char *runtime_conf_path, const char *runtime_conf_dir)
static int app_root_has_finalized_artifact_native(const char *app_root)
static volatile sig_atomic_t global_shutdown_requested
static int native_worker_pool_init(NativeWorkerPool *pool, size_t worker_count, size_t capacity)
Initialize a bounded worker pool for native request serving.
static int handle_native_runtime_app_command(const char *verb, ServeConfig *config)
static char * executable_dir_from_argv0(const char *argv0)
App-local configuration values loaded from app-local config and manifest authority fields.
char * manifest_build_artifact_dir
Loaded runtime metadata for one Pharos app artifact.
char * compiled_entrypoint
Parsed HTTP request fields extracted from a native connection.
Accepted client connection and its resolved transport metadata.
Tracks the active listener descriptor and socket cleanup target.
In-memory collection of loaded app runtimes served by one listener.
AppRuntime apps[MAX_APPS]
Parsed native serve configuration used to bootstrap the runtime listener.
Per-request worker state used while routing either runtime or app traffic.
NativeConnection connection