kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

build.h (6684B)


      1 #ifndef KIT_BUILD_BUILD_H
      2 #define KIT_BUILD_BUILD_H
      3 
      4 #include <kit/cas.h>
      5 #include <kit/core.h>
      6 #include <stdarg.h>
      7 #include <stddef.h>
      8 #include <stdint.h>
      9 
     10 /*
     11  * Shared substrate for the content-addressed build coordinator
     12  * (`<kit/build_coord.h>`, `kit build`). See doc/BUILD_COORDINATOR.md.
     13  *
     14  * This layer sits *on top of* the public content store (`<kit/cas.h>`), the
     15  * digest surface (`<kit/hash.h>`), and the signed-package machinery
     16  * (`<kit/package.h>`). It deliberately does not reach into src/dist internals:
     17  * every id it computes is a plain BLAKE2b-256 of canonical bytes, which is
     18  * exactly a CAS blob id (`kit_blob_info`), so need-overlay maps, argv vectors,
     19  * and trace bodies content-address themselves through the ordinary CAS.
     20  *
     21  * Naming/result conventions mirror src/dist: internal modules return `int`
     22  * (BUILD_OK / BUILD_ERR), parse/emit modules also take a `char* err, size_t
     23  * errcap` sink, and the public composition layer (src/api/build.c) maps the
     24  * result to KitStatus and routes human-readable detail through ctx->diag. All
     25  * ids are lowercase hex on the wire and in every canonical text body.
     26  */
     27 
     28 /* All content ids are BLAKE2b-256, shared with the CAS. */
     29 #define BUILD_HASH_LEN KIT_CAS_HASH_LEN
     30 #define BUILD_HEX_LEN (2u * BUILD_HASH_LEN + 1u)
     31 
     32 /* Result convention for internal modules: 0 = ok, non-zero = error. */
     33 #define BUILD_OK 0
     34 #define BUILD_ERR 1
     35 
     36 /* Canonical text magics (version lines), in the `kit-tree 1` / `kit-package 3`
     37  * family: a version line, ordered scalar fields, then sorted sections. */
     38 #define BUILD_SHALLOW_MAGIC "kit-build-shallow 1"
     39 #define BUILD_DEEP_MAGIC "kit-build-deep 1"
     40 #define BUILD_TEST_SHALLOW_MAGIC "kit-build-test-shallow 1"
     41 #define BUILD_TEST_DEEP_MAGIC "kit-build-test-deep 1"
     42 #define BUILD_DEEPSET_MAGIC \
     43   "kit-build-deepset 1" /* one node of the transitive input-closure DAG */
     44 #define BUILD_RECORD_MAGIC "kit-build-record 1"
     45 #define BUILD_CONFIG_MAGIC                                               \
     46   "kit-build-config 1"                      /* serialized propagated map \
     47                                              */
     48 #define BUILD_ARGV_MAGIC "kit-build-argv 1" /* serialized local argv vector */
     49 #define BUILD_TRACES_MAGIC \
     50   "kit-build-traces 1"                 /* signed trace-bundle manifest */
     51 #define BUILD_DEFN_MAGIC "kit-build 1" /* build-definition file */
     52 
     53 /* The resolution identity of a build is the triple (target-name, config-id,
     54  * argv-id): config-id is the effective propagated config, argv-id the effective
     55  * local argv. Two requests for one target that differ in either are distinct
     56  * builds. Traces record all three and match on all three.
     57  *
     58  * Domain-separation prefix for the per-target index key:
     59  *   target-key = BLAKE2b("kit build target v1" || target-name).
     60  * The index key depends on the target NAME only — never config, argv, or
     61  * recipe-id — so a target's mutable record is a stable handle holding candidate
     62  * traces across every (config, argv) it was recently built under, while its
     63  * inputs churn. */
     64 #define BUILD_TARGET_KEY_DOMAIN "kit build target v1"
     65 #define BUILD_TEST_TARGET_KEY_DOMAIN "kit build test target v1"
     66 
     67 /* Fixed string capacities. A target name and config key/value are bounded; a
     68  * workspace/source path is bounded by BUILD_PATH_MAX. These cap a single
     69  * canonical row, never an aggregate. */
     70 #define BUILD_TARGET_MAX 256u  /* e.g. "//app:server" */
     71 #define BUILD_KEY_MAX 64u      /* config key name */
     72 #define BUILD_VAL_MAX 512u     /* config value */
     73 #define BUILD_PATH_MAX 1024u   /* workspace-relative or absolute fs path */
     74 #define BUILD_URL_MAX 1024u    /* one fetch URL hint */
     75 #define BUILD_PATTERN_MAX 256u /* glob pattern */
     76 
     77 /* Per-recipe trace section capacities. These are aggregate limits for one
     78  * recipe execution, not row-size limits. They need to fit real C-library
     79  * recipes that log one source leaf per compiled source/header while staying
     80  * fixed-size and VLA-free. */
     81 #define BUILD_RECIPE_CONFIG_CAP 256u
     82 #define BUILD_RECIPE_SOURCE_CAP 1024u
     83 #define BUILD_RECIPE_GLOB_CAP 256u
     84 #define BUILD_RECIPE_BLOB_CAP 256u
     85 #define BUILD_RECIPE_DEP_CAP 256u
     86 
     87 /* The two kinds of trace a build records. Written together on every real
     88  * build; resolution picks whichever fits the change it sees. */
     89 typedef enum BuildTraceKind {
     90   BUILD_TRACE_DEEP = 0,
     91   BUILD_TRACE_SHALLOW = 1,
     92 } BuildTraceKind;
     93 
     94 /* MRU window size of the mutable per-target record (each kind capped
     95  * independently). Older candidates age out and become GC-eligible. */
     96 #define KIT_BUILD_RECORD_CAP 8u
     97 
     98 /* The first two lowercase-hex chars of an id form its fan-out dir, as in
     99  * doc/DISTRIBUTE.md (`<pp>/<id>`). */
    100 #define BUILD_PP_LEN 2u
    101 
    102 /* Byte-exact id equality. */
    103 static inline int build_id_eq(const uint8_t a[BUILD_HASH_LEN],
    104                               const uint8_t b[BUILD_HASH_LEN]) {
    105   size_t i;
    106   for (i = 0; i < BUILD_HASH_LEN; ++i)
    107     if (a[i] != b[i]) return 0;
    108   return 1;
    109 }
    110 
    111 /* Compute target-key = BLAKE2b(BUILD_TARGET_KEY_DOMAIN || target-name). */
    112 int build_target_key(KitSlice target_name, uint8_t out[BUILD_HASH_LEN]);
    113 /* Compute test-target-key = BLAKE2b(BUILD_TEST_TARGET_KEY_DOMAIN || target-name).
    114  * Test and build records are intentionally disjoint for the same target. */
    115 int build_test_target_key(KitSlice target_name, uint8_t out[BUILD_HASH_LEN]);
    116 
    117 /* One (path, blob-id) pair in a glob's canonical match listing. Structurally a
    118  * source leaf, but defined at the foundation so the glob-result hash stays a
    119  * pure, separately-testable helper — it is the SOLE producer of the value the
    120  * deep/shallow traces store and match on under [glob], so coord (which expands
    121  * the glob) and any future consumer agree on its bytes by construction. */
    122 typedef struct BuildPathBlob {
    123   char path[BUILD_PATH_MAX];
    124   uint8_t blob[BUILD_HASH_LEN];
    125 } BuildPathBlob;
    126 
    127 /* glob-result-hash = BLAKE2b of the canonical listing of a glob's matches: one
    128  * "<path> <hex blob-id>\n" row per entry, entries pre-sorted by path and
    129  * deduped by the caller. One row thus covers the existence AND content of the
    130  * whole match set, so files read through a glob need no separate source rows.
    131  * Pure: emits the canonical bytes through a scratch writer off `heap`, then
    132  * hashes (kit_blob_info), so the result equals the BLAKE2b that would name the
    133  * listing as a CAS blob. */
    134 int build_glob_result_hash(KitHeap* heap, const BuildPathBlob* entries,
    135                            size_t n, uint8_t out[BUILD_HASH_LEN]);
    136 
    137 /* Emit a human-readable operational error through ctx->diag (no source
    138  * location), mirroring cas_diagf. No-op when ctx/diag is NULL. */
    139 void build_diagf(const KitContext* ctx, const char* fmt, ...);
    140 
    141 #endif