Skip to content
This repository was archived by the owner on Feb 25, 2026. It is now read-only.

Commit fd4cc0f

Browse files
authored
Merge pull request #23 from ekala-project/dependency-finalization
feat: finalize dependency management
2 parents 8a01e76 + 0ae5a69 commit fd4cc0f

42 files changed

Lines changed: 2007 additions & 955 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Cargo.lock

Lines changed: 32 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ strip = true
1515

1616
anyhow.workspace = true
1717
clap.workspace = true
18+
either.workspace = true
1819
gix.workspace = true
1920
semver.workspace = true
2021
tempfile.workspace = true
@@ -30,6 +31,7 @@ atom.path = "crates/atom"
3031

3132
[workspace.dependencies]
3233
anyhow = "^1"
34+
lazy-regex = "3.4.1"
3335
tempfile = "^3.13"
3436
thiserror = "^1"
3537
tracing = "^0.1"
@@ -41,6 +43,7 @@ clap = { version = "^4", features = [
4143
"wrap_help",
4244
"unstable-markdown",
4345
] }
46+
either = { version = "1.15.0", features = ["serde"] }
4447
insta = { version = "^1", features = ["yaml"] }
4548
semver = { version = "^1", features = ["serde"] }
4649
serde = { version = "^1", features = ["derive"] }

adrs/0008-lockfile-refactor.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# 8. Lockfile Data Model and Synchronization Refactor
2+
3+
- **Status:** Proposed
4+
- **Deciders:** eka-devs
5+
- **Date:** 2025-10-13
6+
7+
## Context and Problem Statement
8+
9+
The initial implementation of the ADR#7 manifest and lockfile format has revealed several areas of unnecessary complexity and inefficiency in the underlying data models. The primary issues are:
10+
11+
1. **Redundant Identity Types:** The `lock.rs` module defines an `AtomDigest` struct to represent an atom's cryptographic ID, which is conceptually redundant with the `IdHash` struct defined in the canonical `id` module. This creates a confusing and error-prone translation layer.
12+
2. **Inefficient In-Memory Lockfile Structure:** The lockfile is currently deserialized into a `BTreeSet`, which requires inefficient linear scans for lookups and updates. This data structure will not scale and makes implementing future features, like transitive dependency resolution, overly complex.
13+
3. **Complex Synchronization Logic:** The existing synchronization logic is difficult to implement and maintain due to the inefficient data structures and redundant types.
14+
15+
This ADR proposes a refactoring of the core data models to address these issues, creating a more elegant, efficient, and robust system for managing lockfiles.
16+
17+
## Decision
18+
19+
We will refactor the core identity types and the in-memory representation of the lockfile. The implementation will be conducted in three phases.
20+
21+
### Phase 1: Refactor Core Identity Types
22+
23+
The goal of this phase is to create a single, canonical representation for an atom's cryptographic ID.
24+
25+
- **Step 1.1:** In `crates/atom/src/id/mod.rs`, the ephemeral `IdHash` struct will be renamed to `IdHashView` to clarify its purpose as a temporary, referenced view of a hash.
26+
- **Step 1.2:** A new public, storable struct, `pub struct Id([u8; 32]);`, will be created in `crates/atom/src/id/mod.rs`. This will become the canonical, owned type for an atom's cryptographic ID.
27+
- **Step 1.3:** The `AtomId::compute_hash()` method will be modified to return this new `id::Id` struct.
28+
- **Step 1.4:** The redundant `AtomDigest` struct will be completely removed from `crates/atom/src/lock.rs`.
29+
- **Step 1.5:** The `AtomDep` struct in `crates/atom/src/lock.rs` will be updated to use the new `id::Id` for its `id` field.
30+
31+
### Phase 2: Redesign In-Memory Lockfile Structure
32+
33+
This phase will optimize the in-memory data structure for the lockfile for efficient lookups.
34+
35+
- **Step 2.1:** The `Lockfile` struct in `crates/atom/src/lock.rs` will be modified. The `DepMap` (a `BTreeSet`) will be replaced with separate `BTreeMap` collections for each major dependency type.
36+
- **Step 2.2:** The primary map will be `atoms: BTreeMap<id::Id, AtomDep>`, providing efficient O(log n) lookups. Similar maps will be added for Nix dependencies, keyed by their `Name`.
37+
- **Step 2.3:** Custom `Serialize` and `Deserialize` implementations for the `Lockfile` struct will be created to handle the conversion between the efficient in-memory `BTreeMap` representation and the readable on-disk flat list of `[[input]]` tables.
38+
39+
### Phase 3: Implement the New Synchronization Algorithm
40+
41+
With the new data models in place, we will implement a clear and robust synchronization algorithm.
42+
43+
- **Step 3.1:** Implement the loading logic to parse `atom.toml` and deserialize `atom.lock` into the new `BTreeMap`-based `Lockfile` structure.
44+
- **Step 3.2:** Implement the reconciliation logic. This will iterate through manifest dependencies, compute the expected `id::Id` for each, and use the `BTreeMap` for efficient lookups to add, update, or verify entries against the loaded lockfile.
45+
- **Step 3.3:** Implement pruning logic to remove any stale entries from the lockfile that are no longer present in the manifest.
46+
- **Step 3.4:** Implement the final write logic that serializes the in-memory `Lockfile` back to the `atom.lock` on-disk format.
47+
48+
## Consequences
49+
50+
- **Positive:**
51+
52+
- **Reduced Complexity:** Eliminates redundant types and simplifies the conceptual model.
53+
- **Improved Performance:** The `BTreeMap` structure provides efficient lookups, making the system more scalable.
54+
- **Increased Robustness:** A clearer data model and algorithm will be less prone to bugs and easier to maintain.
55+
- **Future-Proofing:** Provides a solid foundation for future features like transitive dependency resolution.
56+
57+
- **Negative:**
58+
- **Implementation Effort:** This is a significant refactoring that will require careful implementation and testing.

crates/atom/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ nom = "^7"
1212
path-clean = "^1"
1313
unic-ucd-category = "^0.9"
1414

15+
either.workspace = true
16+
lazy-regex.workspace = true
1517
prodash.workspace = true
1618
semver.workspace = true
1719
serde.workspace = true

crates/atom/src/core.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,24 @@
44
//! file system structure. These types form the foundation of the atom format
55
//! and are used throughout the crate.
66
7+
use std::collections::HashMap;
78
use std::path::{Path, PathBuf};
89

910
use semver::Version;
1011
use serde::{Deserialize, Serialize};
1112

12-
use super::id::AtomTag;
13+
use super::id::{AtomTag, Name};
14+
use crate::manifest::AtomSets;
15+
16+
//================================================================================================
17+
// Types
18+
//================================================================================================
1319

1420
/// Represents the deserialized form of an Atom, directly constructed from the TOML manifest.
1521
///
1622
/// This struct contains the basic metadata of an Atom but lacks the context-specific
1723
/// [`crate::AtomId`], which must be constructed separately.
18-
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
24+
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
1925
#[serde(deny_unknown_fields)]
2026
pub struct Atom {
2127
/// The verified, human-readable Unicode identifier for the Atom.
@@ -27,6 +33,10 @@ pub struct Atom {
2733
/// An optional description of the Atom.
2834
#[serde(skip_serializing_if = "Option::is_none")]
2935
pub description: Option<String>,
36+
37+
/// A table of named atom sets, defining the sources for resolving atom dependencies.
38+
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
39+
pub sets: HashMap<Name, AtomSets>,
3040
}
3141

3242
/// Represents the file system paths associated with an atom.
@@ -45,6 +55,10 @@ where
4555
content: P,
4656
}
4757

58+
//================================================================================================
59+
// Impls
60+
//================================================================================================
61+
4862
impl AtomPaths<PathBuf> {
4963
/// Creates a new `AtomPaths` instance from a given path.
5064
///

0 commit comments

Comments
 (0)