1
0
Fork 0
mirror of https://codeberg.org/icewind/haze.git synced 2026-06-03 09:04:12 +02:00

edit command

This commit is contained in:
Robin Appelman 2025-09-03 18:37:33 +02:00
commit 43481a5960
5 changed files with 70 additions and 9 deletions

View file

@ -215,6 +215,12 @@ This is indented to run a local
haze update haze update
``` ```
#### Edit a file in an instance with the local $EDITOR
```bash
haze [match] edit <path>
```
## Federation ## Federation
Multiple instances can reach each other by using their instance name as domain Multiple instances can reach each other by using their instance name as domain

View file

@ -77,6 +77,10 @@ pub enum HazeArgs {
command: Option<HazeCommand>, command: Option<HazeCommand>,
}, },
Version, Version,
Edit {
filter: Option<String>,
path: String,
},
} }
#[derive(Debug, Clone, Eq, PartialEq)] #[derive(Debug, Clone, Eq, PartialEq)]
@ -282,6 +286,13 @@ impl HazeArgs {
Ok(HazeArgs::Help { command }) Ok(HazeArgs::Help { command })
} }
HazeCommand::Version => Ok(HazeArgs::Version), HazeCommand::Version => Ok(HazeArgs::Version),
HazeCommand::Edit => Ok(HazeArgs::Edit {
filter,
path: args
.next()
.ok_or_else(|| Report::msg("No path provided"))?
.into(),
}),
} }
} }
} }
@ -368,6 +379,9 @@ pub enum HazeCommand {
/// Show version number /// Show version number
#[strum(serialize = "--version", to_string = "version")] #[strum(serialize = "--version", to_string = "version")]
Version, Version,
/// Edit a file in the instance with $EDITOR on the host
#[strum(props(Args = "[path] file to edit"))]
Edit,
} }
impl HazeCommand { impl HazeCommand {
@ -384,6 +398,7 @@ impl HazeCommand {
| HazeCommand::Pin | HazeCommand::Pin
| HazeCommand::Unpin | HazeCommand::Unpin
| HazeCommand::Env | HazeCommand::Env
| HazeCommand::Edit
) )
} }
} }

View file

@ -15,6 +15,7 @@ use futures_util::future::try_join_all;
use miette::{IntoDiagnostic, Report, Result, WrapErr}; use miette::{IntoDiagnostic, Report, Result, WrapErr};
use petname::petname; use petname::petname;
use serde_json::Value; use serde_json::Value;
use std::borrow::Cow;
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt::Display; use std::fmt::Display;
use std::fs; use std::fs;
@ -767,4 +768,28 @@ impl Cloud {
pub fn php(&self) -> &PhpVersion { pub fn php(&self) -> &PhpVersion {
&self.options.php &self.options.php
} }
pub fn get_local_path(&self, config: &HazeConfig, path: &str) -> Option<Utf8PathBuf> {
let path = if path.starts_with('/') {
Cow::Borrowed(path)
} else {
format!("/var/www/html/{path}").into()
};
let mut mappings = config
.volume
.iter()
.map(Mapping::from)
.chain(default_mappings())
.collect::<Vec<_>>();
mappings.sort_by_key(|mapping| usize::MAX - mapping.target.as_str().len());
for mapping in mappings {
if let Some(rel_path) = path.strip_prefix(mapping.target.as_str()) {
let rel_path = rel_path.trim_matches('/');
return Some(mapping.source(&self.id, config).join(rel_path));
}
}
None
}
} }

View file

@ -16,7 +16,7 @@ use crate::service::{RedisTls, Service};
use bollard::Docker; use bollard::Docker;
use itertools::Itertools; use itertools::Itertools;
use miette::{IntoDiagnostic, Report, Result, WrapErr}; use miette::{IntoDiagnostic, Report, Result, WrapErr};
use std::env::vars; use std::env::{var, vars};
use std::fs::{create_dir_all, write}; use std::fs::{create_dir_all, write};
use std::io::stdout; use std::io::stdout;
use std::os::unix::process::CommandExt; use std::os::unix::process::CommandExt;
@ -452,6 +452,17 @@ async fn main() -> Result<ExitCode> {
HazeArgs::Help { command } => { HazeArgs::Help { command } => {
help(command); help(command);
} }
HazeArgs::Edit { filter, path } => {
let cloud = Cloud::get_by_filter(&docker, filter, &config).await?;
let path = cloud
.get_local_path(&config, &path)
.ok_or_else(|| Report::msg(format!("{path} not found on the instance")))?;
let editor = var("EDITOR").map_err(|_| Report::msg("$EDITOR not set"))?;
let err = Command::new(editor).arg(path).exec(); // this never exists without error
return Err(err)
.into_diagnostic()
.wrap_err("Failed to start $EDITOR");
}
}; };
Ok(ExitCode::SUCCESS) Ok(ExitCode::SUCCESS)

View file

@ -1,5 +1,5 @@
use crate::config::{HazeConfig, HazeVolumeConfig}; use crate::config::{HazeConfig, HazeVolumeConfig};
use camino::Utf8Path; use camino::{Utf8Path, Utf8PathBuf};
use miette::{IntoDiagnostic, Result}; use miette::{IntoDiagnostic, Result};
use tokio::fs::{create_dir_all, write}; use tokio::fs::{create_dir_all, write};
@ -7,7 +7,7 @@ use tokio::fs::{create_dir_all, write};
pub struct Mapping<'a> { pub struct Mapping<'a> {
source_type: MappingSourceType, source_type: MappingSourceType,
pub source: &'a Utf8Path, pub source: &'a Utf8Path,
target: &'a Utf8Path, pub target: &'a Utf8Path,
mapping_type: MappingType, mapping_type: MappingType,
read_only: bool, read_only: bool,
map: bool, map: bool,
@ -78,16 +78,20 @@ impl<'a> Mapping<'a> {
Ok(()) Ok(())
} }
pub fn get_volume_arg(&self, id: &str, config: &HazeConfig) -> Option<String> { pub fn source(&self, id: &str, config: &HazeConfig) -> Utf8PathBuf {
if !self.map { match self.source_type {
return None;
}
let source = match self.source_type {
MappingSourceType::WorkDir => config.work_dir.join(id).join(self.source), MappingSourceType::WorkDir => config.work_dir.join(id).join(self.source),
MappingSourceType::GlobalWorkDir => config.work_dir.join(self.source), MappingSourceType::GlobalWorkDir => config.work_dir.join(self.source),
MappingSourceType::Sources => config.sources_root.join(self.source), MappingSourceType::Sources => config.sources_root.join(self.source),
MappingSourceType::Absolute => self.source.into(), MappingSourceType::Absolute => self.source.into(),
}; }
}
pub fn get_volume_arg(&self, id: &str, config: &HazeConfig) -> Option<String> {
if !self.map {
return None;
}
let source = self.source(id, config);
Some(if self.read_only { Some(if self.read_only {
format!("{}:{}:ro", source, self.target) format!("{}:{}:ro", source, self.target)
} else { } else {