| 1 |
package core |
| 2 |
|
| 3 |
/* Revision represents a single commit in the repository. |
| 4 |
* Uses SVN-style sequential numbering (r1, r2, ...) with global counter. |
| 5 |
* Supports branching with global revision numbers across all branches. */ |
| 6 |
|
| 7 |
type Revision struct { |
| 8 |
Number int64 `json:"number"` // r1, r2, etc. - globally unique |
| 9 |
Timestamp int64 `json:"timestamp"` // Unix timestamp |
| 10 |
Author string `json:"author"` // username |
| 11 |
Message string `json:"message"` // commit message |
| 12 |
Branch string `json:"branch"` // "port", "feature/foo" |
| 13 |
Parent int64 `json:"parent"` // parent revision number (0 for initial) |
| 14 |
MergeParent int64 `json:"merge_parent"` // second parent for merges (0 if none) |
| 15 |
TreeHash string `json:"tree_hash"` // hash of tree manifest |
| 16 |
} |
| 17 |
|
| 18 |
// EntryKind represents the type of a tree entry |
| 19 |
type EntryKind uint8 |
| 20 |
|
| 21 |
const ( |
| 22 |
EntryKindFile EntryKind = iota // regular file |
| 23 |
EntryKindDir // directory |
| 24 |
EntryKindSymlink // symbolic link |
| 25 |
) |
| 26 |
|
| 27 |
func (k EntryKind) String() string { |
| 28 |
switch k { |
| 29 |
case EntryKindFile: |
| 30 |
return "file" |
| 31 |
case EntryKindDir: |
| 32 |
return "dir" |
| 33 |
case EntryKindSymlink: |
| 34 |
return "symlink" |
| 35 |
default: |
| 36 |
return "unknown" |
| 37 |
} |
| 38 |
} |
| 39 |
|
| 40 |
/* TreeEntry represents a single file/directory in a tree manifest. |
| 41 |
* BlobHash uses xxhash64 for speed (16 hex chars). */ |
| 42 |
|
| 43 |
type TreeEntry struct { |
| 44 |
Path string `json:"path"` // relative path from repo root |
| 45 |
Mode uint32 `json:"mode"` // file permissions (unix mode) |
| 46 |
Size int64 `json:"size"` // file size in bytes |
| 47 |
BlobHash string `json:"blob_hash"` // content hash (xxhash64) |
| 48 |
Kind EntryKind `json:"kind"` // file, directory, symlink |
| 49 |
} |
| 50 |
|
| 51 |
/* Tree is a snapshot of the directory structure at a specific revision. |
| 52 |
* Hash is xxhash64 of the serialized entries. */ |
| 53 |
|
| 54 |
type Tree struct { |
| 55 |
Hash string `json:"hash"` |
| 56 |
Entries []TreeEntry `json:"entries"` |
| 57 |
} |
| 58 |
|
| 59 |
// NewTree creates a new tree and computes its hash |
| 60 |
func NewTree(entries []TreeEntry, computeHash func([]byte) string) (*Tree, error) { |
| 61 |
t := &Tree{Entries: entries} |
| 62 |
|
| 63 |
/* NOTE(kroot): hash is computed from JSON serialization of entries |
| 64 |
* this ensures consistent hashing across different runs */ |
| 65 |
return t, nil |
| 66 |
} |
| 67 |
|
| 68 |
// ChangeType represents the type of change between two trees |
| 69 |
type ChangeType uint8 |
| 70 |
|
| 71 |
const ( |
| 72 |
ChangeAdded ChangeType = iota // new file |
| 73 |
ChangeModified // file content changed |
| 74 |
ChangeDeleted // file removed |
| 75 |
ChangeModeOnly // only permissions changed |
| 76 |
) |
| 77 |
|
| 78 |
func (c ChangeType) String() string { |
| 79 |
switch c { |
| 80 |
case ChangeAdded: |
| 81 |
return "added" |
| 82 |
case ChangeModified: |
| 83 |
return "modified" |
| 84 |
case ChangeDeleted: |
| 85 |
return "deleted" |
| 86 |
case ChangeModeOnly: |
| 87 |
return "mode" |
| 88 |
default: |
| 89 |
return "unknown" |
| 90 |
} |
| 91 |
} |
| 92 |
|
| 93 |
// Change represents a single file change between revisions |
| 94 |
type Change struct { |
| 95 |
Path string `json:"path"` |
| 96 |
Type ChangeType `json:"type"` |
| 97 |
OldRef *TreeEntry `json:"old_ref,omitempty"` // nil for added |
| 98 |
NewRef *TreeEntry `json:"new_ref,omitempty"` // nil for deleted |
| 99 |
} |
| 100 |
|