Skip to main content

Module resources

Module resources 

Source
Expand description

Project-resource ZIP-member surgery (05-02) — the resource family re-pointed onto project-export zips, closing the Phase 3 cross-phase defect: the /projects/{p}/resources/** REST routes the family originally targeted DO NOT EXIST on real 8.3 gateways (openapi-evidenced twice — 575 paths, zero matches — plus the EAM probe and the gateway-scripting API audit; 05-RESEARCH). The native steer’s honest endpoint: export/import round-trip. These helpers are the surgery half.

PURE functions — no crate::client::GatewayApi surface, no I/O beyond the zip crate itself — so every mapping is unit-testable without a gateway. The orchestration (export → surgery → import) lives in actions::resources.

Zip layout of an 8.3 project export (05-RESEARCH, live-extracted): project.json at the root plus <collection>/resources/<rest> file members (collections are single-segment module ids — com.inductiveautomation.perspective, ignition, …). The user-facing path form — the Phase-3 UX-unchanged contract — is <collection>/<rest>: the resources/ segment is stripped on the way OUT and re-inserted on the way IN. A no-slash user path (a project-root file, e.g. perspective-properties.json) rides a module named after the path itself: <X><X>/resources/<X> (06-08, live-proven — the only adoptable shape for root-level files; see [member_path]). project.json is never a resource. Directory entries (when a writer emits them) are skipped on list and preserved verbatim on rewrite.

ResourceEntry keeps the Phase-3 list shape (path typed, passthrough extras) so the CLI’s rendering contract is untouched; surgery results carry no extras.

Structs§

DiffSummary
The four counts — the summary line and the JSON summary object.
MemberDiff
The member-level diff result: counts + one entry per resource member, sorted by path. The root project.json is EXCLUDED (it is not a resource; project_meta_delta surfaces it separately).
MemberDiffEntry
One row of the diff: the user path + its status.
ResourceEntry
One list item — the Phase-3 shape, unchanged: path typed (the human renderer prints one per line), unknown keys round-trip. Surgery-sourced entries carry no extras (the zip member list is the whole truth).

Enums§

MemberStatus
One member’s diff status — B-relative-to-A semantics (the LOCKED direction): added = in B only, removed = in A only.

Functions§

diff_members
THE compare primitive: B-relative-to-A member statuses over two export zips — added = path in B not A, removed = in A not B, changed = both with differing normalized hashes, same = both with equal ones. Entries ride path-sorted (the BTreeMap union iterates sorted). The root project.json never appears (the member_hashes walk skips it).
member_hashes
User path → FNV-1a digest for every resource member in the export zip. Members whose basename is resource.json hash their NORMALIZED form (normalize_descriptor); everything else hashes raw bytes. project.json, directory entries, and non-resources-shaped members carry no user path and are skipped (the same walk resource_members rides) — which is exactly how diff_members excludes the root project.json from resource entries.
normalize_descriptor
Normalize one resource.json descriptor for comparison: parse, strip the two live-evidenced volatility fields (attributes.lastModification and attributes.lastModificationSignature — keep every other attribute and all semantic keys), recursively sort object keys, re-serialize compact. None for non-JSON or a non-object root — the caller hashes the raw bytes instead (the descriptor is exotic or corrupt; content honesty over a false equality).
project_meta_delta
Compare the root project.json’s SEMANTIC fields — title, enabled, parent only — returning one (field, a_value, b_value) triple per differing field (stringified values; absent renders as null). Missing member or parse failure → empty vec: the diff is about resources, project meta rides separately.
read_member
THE read primitive: one member’s bytes, verbatim. A missing member is the existing not-found error shape (exit 6) — the REST family’s 404 semantics carried over the surgery transport.
remove_member
THE delete primitive: the zip minus the member. A missing member is the existing not-found error shape (exit 6).
replace_member
THE put primitive: replace the member’s content — or append it when absent (upsert: created if missing). Every other member, their order, and directory entries ride across untouched.
resource_members
THE list primitive: user-facing paths of every resource member in the export zip, in member order. project.json, directory entries, and non-resources-shaped members are skipped.