split module into smaller pieces
This commit is contained in:
parent
97fadf6c92
commit
11fd970400
117
src/cfg.rs
Normal file
117
src/cfg.rs
Normal file
|
@ -0,0 +1,117 @@
|
|||
use crate::{*,errors::*};
|
||||
|
||||
#[derive(ClapParser, Debug, Clone)]
|
||||
/// git-remote-k8s
|
||||
///
|
||||
/// This should usually be run by git. You can set git up to use it
|
||||
/// by running git remote add k k8s://default/ns/repo.
|
||||
///
|
||||
/// see https://git.strudelline.net/cascade/git-remote-k8s for more info
|
||||
pub struct Config {
|
||||
#[arg(
|
||||
short,
|
||||
long,
|
||||
env = "GIT_REMOTE_K8S_IMAGE",
|
||||
default_value = "alpine/git:latest"
|
||||
)]
|
||||
/// Docker image used for git Jobs
|
||||
pub image: String,
|
||||
|
||||
#[arg(index = 1)]
|
||||
/// remote name
|
||||
pub remote_name: String,
|
||||
|
||||
#[arg(index = 2)]
|
||||
/// remote URL
|
||||
pub remote_url: String,
|
||||
|
||||
#[arg(
|
||||
short,
|
||||
long,
|
||||
env = "GIT_REMOTE_K8S_DEBUG",
|
||||
action=ArgAction::Count,
|
||||
)]
|
||||
/// verbosity, may be specified more than once
|
||||
pub verbose: u8,
|
||||
|
||||
#[arg(
|
||||
long("storage-class-name"),
|
||||
env = "GIT_REMOTE_K8S_PVC_STORAGECLASSNAME"
|
||||
)]
|
||||
/// storageClassName to use for the backing PVC _if it is created_.
|
||||
///
|
||||
/// this will be used to create a new PVC but if a PVC already
|
||||
/// exists by the requested name, it will be used.
|
||||
pub storageclass: Option<String>,
|
||||
|
||||
#[arg(
|
||||
short('s'),
|
||||
long("initial-volume-size"),
|
||||
default_value("1Gi"),
|
||||
env = "GIT_REMOTE_K8S_INITIAL_VOLUME_SIZE"
|
||||
)]
|
||||
pub initial_size: String,
|
||||
}
|
||||
|
||||
|
||||
impl Config {
|
||||
/// parse and validate a k8s remote pvc short-URL into a triple of Strings of the form (context, namespace, pvc)
|
||||
///
|
||||
/// this utilizes a regex instead of url::Url to ensure that it returns sensible errors
|
||||
// TODO: find a way to memoize this cleanly. probably give it access to a memoizing context from AppContext.
|
||||
pub fn parse_and_validate(&self) -> Result<(String, String, String)> {
|
||||
let caps = REMOTE_PATTERN
|
||||
.captures(&self.remote_url)
|
||||
.ok_or(ConfigError::RemoteInvalid)?;
|
||||
let scheme = if caps.name("scheme_prefix").is_none() {
|
||||
SCHEME
|
||||
} else {
|
||||
caps.name("scheme")
|
||||
.ok_or(ConfigError::RemoteInvalidScheme)?
|
||||
.as_str()
|
||||
};
|
||||
if scheme != SCHEME {
|
||||
bail!(ConfigError::RemoteInvalidScheme);
|
||||
}
|
||||
let kctx = caps
|
||||
.name("context")
|
||||
.ok_or(ConfigError::RemoteNoContext)?
|
||||
.as_str();
|
||||
let ns = caps
|
||||
.name("namespace")
|
||||
.ok_or(ConfigError::RemoteNoNamespace)?
|
||||
.as_str();
|
||||
let pvc = caps.name("pvc").ok_or(ConfigError::RemoteNoPVC)?.as_str();
|
||||
// regex::Regex::find(REMOTE_PATTERN);
|
||||
if kctx == "" {
|
||||
bail!(ConfigError::RemoteNoContext);
|
||||
};
|
||||
if ns == "" {
|
||||
bail!(ConfigError::RemoteNoNamespace);
|
||||
};
|
||||
if pvc == "" {
|
||||
bail!(ConfigError::RemoteNoPVC);
|
||||
};
|
||||
if let Some(trailing) = caps.name("trailing") {
|
||||
if trailing.as_str() != "" {
|
||||
bail!(ConfigError::RemoteTrailingElements);
|
||||
}
|
||||
}
|
||||
Ok((kctx.to_owned(), ns.to_owned(), pvc.to_owned()))
|
||||
}
|
||||
|
||||
pub fn get_remote_context(&self) -> Result<String> {
|
||||
let (r, _, _) = self.parse_and_validate()?;
|
||||
Ok(r)
|
||||
}
|
||||
|
||||
pub fn get_remote_namespace(&self) -> Result<String> {
|
||||
let (_, r, _) = self.parse_and_validate()?;
|
||||
Ok(r)
|
||||
}
|
||||
|
||||
pub fn get_remote_pvc(&self) -> Result<String> {
|
||||
let (_, _, r) = self.parse_and_validate()?;
|
||||
Ok(r)
|
||||
}
|
||||
}
|
40
src/errors.rs
Normal file
40
src/errors.rs
Normal file
|
@ -0,0 +1,40 @@
|
|||
use crate::*;
|
||||
|
||||
#[derive(ThisError, Debug)]
|
||||
pub enum ApplicationError {
|
||||
/// cluster state problems
|
||||
#[error("cluster is in an inconsistent state")]
|
||||
RemoteClusterInconsistent,
|
||||
|
||||
/// pod state problems
|
||||
#[error("pod metadata doesn't contain a name")]
|
||||
PodNoName,
|
||||
#[error("pod metadata doesn't contain a namespace")]
|
||||
PodNoNamespace,
|
||||
#[error("couldn't open pod's stdin")]
|
||||
PodCouldNotOpenStdin,
|
||||
#[error("couldn't open pod's stdout")]
|
||||
PodCouldNotOpenStdout,
|
||||
#[error("couldn't open pod's stderr")]
|
||||
PodCouldNotOpenStderr,
|
||||
#[error("pod failed to start")]
|
||||
PodCouldNotStart,
|
||||
#[error("worker pod did not continue running")]
|
||||
PodDidNotWait,
|
||||
}
|
||||
|
||||
#[derive(ThisError, Debug)]
|
||||
pub enum ConfigError {
|
||||
#[error("no namespace present in remote URL")]
|
||||
RemoteNoNamespace,
|
||||
#[error("trailing elements after pvc in remote URL")]
|
||||
RemoteTrailingElements,
|
||||
#[error("no context present in remote URL")]
|
||||
RemoteNoContext,
|
||||
#[error("no PVC name present in remote URL")]
|
||||
RemoteNoPVC,
|
||||
#[error("invalid remote URL")]
|
||||
RemoteInvalid,
|
||||
#[error("remote URL has an invalid (or no) scheme")]
|
||||
RemoteInvalidScheme,
|
||||
}
|
155
src/main.rs
155
src/main.rs
|
@ -42,159 +42,10 @@ static REMOTE_PATTERN: Lazy<regex::Regex> = Lazy::new(|| {
|
|||
#[cfg(test)]
|
||||
mod test;
|
||||
|
||||
#[derive(ClapParser, Debug, Clone)]
|
||||
/// git-remote-k8s
|
||||
///
|
||||
/// This should usually be run by git. You can set git up to use it
|
||||
/// by running git remote add k k8s://default/ns/repo.
|
||||
///
|
||||
/// see https://git.strudelline.net/cascade/git-remote-k8s for more info
|
||||
struct Config {
|
||||
#[arg(
|
||||
short,
|
||||
long,
|
||||
env = "GIT_REMOTE_K8S_IMAGE",
|
||||
default_value = "alpine/git:latest"
|
||||
)]
|
||||
/// Docker image used for git Jobs
|
||||
image: String,
|
||||
mod cfg;
|
||||
mod errors;
|
||||
|
||||
#[arg(index = 1)]
|
||||
/// remote name
|
||||
remote_name: String,
|
||||
|
||||
#[arg(index = 2)]
|
||||
/// remote URL
|
||||
remote_url: String,
|
||||
|
||||
#[arg(
|
||||
short,
|
||||
long,
|
||||
env = "GIT_REMOTE_K8S_DEBUG",
|
||||
action=ArgAction::Count,
|
||||
)]
|
||||
/// verbosity, may be specified more than once
|
||||
verbose: u8,
|
||||
|
||||
#[arg(
|
||||
long("storage-class-name"),
|
||||
env = "GIT_REMOTE_K8S_PVC_STORAGECLASSNAME"
|
||||
)]
|
||||
/// storageClassName to use for the backing PVC _if it is created_.
|
||||
///
|
||||
/// this will be used to create a new PVC but if a PVC already
|
||||
/// exists by the requested name, it will be used.
|
||||
storageclass: Option<String>,
|
||||
|
||||
#[arg(
|
||||
short('s'),
|
||||
long("initial-volume-size"),
|
||||
default_value("1Gi"),
|
||||
env = "GIT_REMOTE_K8S_INITIAL_VOLUME_SIZE"
|
||||
)]
|
||||
initial_size: String,
|
||||
}
|
||||
|
||||
#[derive(ThisError, Debug)]
|
||||
pub enum ApplicationError {
|
||||
/// cluster state problems
|
||||
#[error("cluster is in an inconsistent state")]
|
||||
RemoteClusterInconsistent,
|
||||
|
||||
/// pod state problems
|
||||
#[error("pod metadata doesn't contain a name")]
|
||||
PodNoName,
|
||||
#[error("pod metadata doesn't contain a namespace")]
|
||||
PodNoNamespace,
|
||||
#[error("couldn't open pod's stdin")]
|
||||
PodCouldNotOpenStdin,
|
||||
#[error("couldn't open pod's stdout")]
|
||||
PodCouldNotOpenStdout,
|
||||
#[error("couldn't open pod's stderr")]
|
||||
PodCouldNotOpenStderr,
|
||||
#[error("pod failed to start")]
|
||||
PodCouldNotStart,
|
||||
#[error("worker pod did not continue running")]
|
||||
PodDidNotWait,
|
||||
}
|
||||
|
||||
#[derive(ThisError, Debug)]
|
||||
pub enum ConfigError {
|
||||
#[error("no namespace present in remote URL")]
|
||||
RemoteNoNamespace,
|
||||
#[error("trailing elements after pvc in remote URL")]
|
||||
RemoteTrailingElements,
|
||||
#[error("no context present in remote URL")]
|
||||
RemoteNoContext,
|
||||
#[error("no PVC name present in remote URL")]
|
||||
RemoteNoPVC,
|
||||
#[error("invalid remote URL")]
|
||||
RemoteInvalid,
|
||||
#[error("remote URL has an invalid (or no) scheme")]
|
||||
RemoteInvalidScheme,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
/// parse and validate a k8s remote pvc short-URL into a triple of Strings of the form (context, namespace, pvc)
|
||||
///
|
||||
/// this utilizes a regex instead of url::Url to ensure that it returns sensible errors
|
||||
// TODO: find a way to memoize this cleanly. probably give it access to a memoizing context from AppContext.
|
||||
fn parse_and_validate(&self) -> Result<(String, String, String)> {
|
||||
let caps = REMOTE_PATTERN
|
||||
.captures(&self.remote_url)
|
||||
.ok_or(ConfigError::RemoteInvalid)?;
|
||||
let scheme = if caps.name("scheme_prefix").is_none() {
|
||||
SCHEME
|
||||
} else {
|
||||
caps.name("scheme")
|
||||
.ok_or(ConfigError::RemoteInvalidScheme)?
|
||||
.as_str()
|
||||
};
|
||||
if scheme != SCHEME {
|
||||
bail!(ConfigError::RemoteInvalidScheme);
|
||||
}
|
||||
let kctx = caps
|
||||
.name("context")
|
||||
.ok_or(ConfigError::RemoteNoContext)?
|
||||
.as_str();
|
||||
let ns = caps
|
||||
.name("namespace")
|
||||
.ok_or(ConfigError::RemoteNoNamespace)?
|
||||
.as_str();
|
||||
let pvc = caps.name("pvc").ok_or(ConfigError::RemoteNoPVC)?.as_str();
|
||||
// regex::Regex::find(REMOTE_PATTERN);
|
||||
if kctx == "" {
|
||||
bail!(ConfigError::RemoteNoContext);
|
||||
};
|
||||
if ns == "" {
|
||||
bail!(ConfigError::RemoteNoNamespace);
|
||||
};
|
||||
if pvc == "" {
|
||||
bail!(ConfigError::RemoteNoPVC);
|
||||
};
|
||||
if let Some(trailing) = caps.name("trailing") {
|
||||
if trailing.as_str() != "" {
|
||||
bail!(ConfigError::RemoteTrailingElements);
|
||||
}
|
||||
}
|
||||
Ok((kctx.to_owned(), ns.to_owned(), pvc.to_owned()))
|
||||
}
|
||||
|
||||
fn get_remote_context(&self) -> Result<String> {
|
||||
let (r, _, _) = self.parse_and_validate()?;
|
||||
Ok(r)
|
||||
}
|
||||
|
||||
fn get_remote_namespace(&self) -> Result<String> {
|
||||
let (_, r, _) = self.parse_and_validate()?;
|
||||
Ok(r)
|
||||
}
|
||||
|
||||
fn get_remote_pvc(&self) -> Result<String> {
|
||||
let (_, _, r) = self.parse_and_validate()?;
|
||||
Ok(r)
|
||||
}
|
||||
}
|
||||
use crate::{cfg::*,errors::*};
|
||||
|
||||
struct AppContext {
|
||||
config: Arc<Config>,
|
||||
|
|
Loading…
Reference in New Issue
Block a user