1use std::path::PathBuf;
8
9use crate::session::SessionState;
10
11#[derive(Debug, thiserror::Error)]
20#[non_exhaustive]
21pub enum SessionError {
22 #[error("Session must be in {} state, current: {current}", format_expected(.expected))]
24 InvalidState {
25 expected: Vec<SessionState>,
26 current: SessionState,
27 },
28
29 #[error("Environment '{name}' {action} failed: {reason}")]
31 EnvironmentScriptFailed {
32 name: String,
33 action: String,
34 reason: String,
35 },
36
37 #[error("Failed to resolve {context}: {reason}")]
39 FormatString { context: String, reason: String },
40
41 #[error("Failed to write embedded file '{name}': {source}")]
43 EmbeddedFile {
44 name: String,
45 #[source]
46 source: std::io::Error,
47 },
48
49 #[error("Embedded file '{name}' has unsafe filename '{filename}': {reason}")]
57 EmbeddedFilePath {
58 name: String,
59 filename: String,
60 reason: String,
61 },
62
63 #[error("Failed to create working directory {path}: {source}")]
65 WorkingDirectory {
66 path: PathBuf,
67 #[source]
68 source: std::io::Error,
69 },
70
71 #[error("Failed to start subprocess '{command}': {source}")]
73 SubprocessStart {
74 command: String,
75 #[source]
76 source: std::io::Error,
77 },
78
79 #[error("Failed to create temp directory in {path}: {source}")]
81 TempDir {
82 path: PathBuf,
83 #[source]
84 source: std::io::Error,
85 },
86
87 #[error("{0}")]
89 Runtime(String),
90
91 #[error("Environment {id} has already been entered in this Session.")]
93 DuplicateEnvironment { id: String },
94
95 #[error("Unknown environment identifier: {identifier}")]
97 UnknownEnvironment { identifier: String },
98
99 #[error("Failed to set permissions on '{path}': {reason}")]
101 PathPermissions { path: String, reason: String },
102
103 #[error("Cross-user helper error: {0}")]
105 HelperCommunication(String),
106
107 #[error(
109 "Must exit the most recently entered environment first. Expected {expected}, got {got}"
110 )]
111 LifoViolation { expected: String, got: String },
112}
113
114fn format_expected(states: &[SessionState]) -> String {
115 match states {
116 [single] => single.to_string(),
117 _ => states
118 .iter()
119 .map(|s| s.to_string())
120 .collect::<Vec<_>>()
121 .join(" or "),
122 }
123}