1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
//! Error types for the VCS engine.
use std::fmt;
/// All errors produced by the VCS engine.
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum VcsError {
/// An object was not found in the store.
#[error("object not found: {id}")]
ObjectNotFound {
/// The missing object's ID.
id: crate::ObjectId,
},
/// A ref was not found.
#[error("ref not found: {name}")]
RefNotFound {
/// The missing ref name.
name: String,
},
/// HEAD is detached when a branch was expected.
#[error("HEAD is detached")]
DetachedHead,
/// Nothing is staged for commit.
#[error("nothing staged")]
NothingStaged,
/// Staging validation failed.
#[error("validation failed: {reasons:?}")]
ValidationFailed {
/// The validation errors.
reasons: Vec<String>,
},
/// Merge produced conflicts.
#[error("merge conflict: {count} conflict(s)")]
MergeConflicts {
/// The number of conflicts.
count: usize,
},
/// A branch already exists.
#[error("branch already exists: {name}")]
BranchExists {
/// The branch name.
name: String,
},
/// Not inside a panproto repository.
#[error("not a panproto repository")]
NotARepository,
/// An expected object had the wrong type.
#[error("expected {expected} object, found {found}")]
WrongObjectType {
/// The expected object type.
expected: &'static str,
/// The actual object type.
found: &'static str,
},
/// I/O error.
#[error("io error: {0}")]
Io(#[from] std::io::Error),
/// Serialization / deserialization error.
#[error("serialization error: {0}")]
Serialization(SerializationError),
/// Migration composition error.
#[error("compose error: {0}")]
Compose(#[from] panproto_mig::ComposeError),
/// No common ancestor found for merge.
#[error("no common ancestor found")]
NoCommonAncestor,
/// No path found between two commits.
#[error("no path found between commits")]
NoPath,
/// Branch is not fully merged into HEAD.
#[error("branch '{name}' is not fully merged")]
BranchNotMerged {
/// The branch name.
name: String,
},
/// A merge or cherry-pick is already in progress.
#[error("a {operation} is already in progress")]
OperationInProgress {
/// The operation type (e.g. "merge", "cherry-pick").
operation: String,
},
/// Feature is not yet implemented.
#[error("{feature} is not yet implemented")]
NotImplemented {
/// Description of the unimplemented feature.
feature: String,
},
/// Merge cannot fast-forward but --ff-only was requested.
#[error("cannot fast-forward; refusing to merge")]
FastForwardOnly,
/// Amend requested but no commits exist.
#[error("nothing to amend")]
NothingToAmend,
/// A tag already exists.
#[error("tag already exists: {name}")]
TagExists {
/// The tag name.
name: String,
},
/// Data migration failed.
#[error("data migration failed: {reason}")]
DataMigrationFailed {
/// Description of the failure.
reason: String,
},
/// An object had the wrong type (owned variant for runtime strings).
#[error("type mismatch: expected {expected}, got {got}")]
TypeMismatch {
/// The expected type name.
expected: String,
/// The actual type name.
got: String,
},
/// I/O error from a string description (for cases where
/// `std::io::Error` is not directly available).
#[error("io: {0}")]
IoError(String),
/// Two leaves were supplied at the same schema-tree path.
///
/// Returned by [`crate::tree::build_tree_from_leaves`] when the
/// same path appears twice. Surfacing the duplicate lets callers
/// decide how to dedupe rather than silently picking a winner.
#[error("duplicate schema-tree path: {path}")]
DuplicatePath {
/// The offending path, displayed with forward slashes.
path: String,
},
/// A leaf was supplied with an empty path.
///
/// Returned by [`crate::tree::build_tree_from_leaves`] when a path
/// has zero components. Empty paths cannot be placed in the
/// directory hierarchy and must not be silently dropped.
#[error("empty schema-tree path")]
EmptyPath,
/// A generic error described by a human-readable string.
#[error("{0}")]
Other(String),
}
/// Wrapper for serialization errors from rmp-serde.
#[derive(Debug)]
pub struct SerializationError(pub String);
impl fmt::Display for SerializationError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.0)
}
}
impl From<rmp_serde::encode::Error> for VcsError {
fn from(e: rmp_serde::encode::Error) -> Self {
Self::Serialization(SerializationError(e.to_string()))
}
}
impl From<rmp_serde::decode::Error> for VcsError {
fn from(e: rmp_serde::decode::Error) -> Self {
Self::Serialization(SerializationError(e.to_string()))
}
}