Ghostty: run commands directly via base64 to avoid Gatekeeper prompts; translate README; anonymize examples
This commit is contained in:
parent
44ebb4054b
commit
1da2553b92
8 changed files with 79 additions and 76 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -759,6 +759,7 @@ dependencies = [
|
||||||
name = "lines"
|
name = "lines"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"base64",
|
||||||
"clap",
|
"clap",
|
||||||
"crossterm",
|
"crossterm",
|
||||||
"directories",
|
"directories",
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
base64 = "0.22.1"
|
||||||
clap = { version = "4.6.1", features = ["derive"] }
|
clap = { version = "4.6.1", features = ["derive"] }
|
||||||
crossterm = "0.29.0"
|
crossterm = "0.29.0"
|
||||||
directories = "6.0.0"
|
directories = "6.0.0"
|
||||||
|
|
|
||||||
82
README.md
82
README.md
|
|
@ -1,79 +1,79 @@
|
||||||
# lines
|
# lines
|
||||||
|
|
||||||
TUI aplikace pro rychlé spouštění často používaných příkazů — ideální pro SSH skripty, aktualizace a cokoliv, co pouštíš pravidelně z terminálu.
|
A TUI app for quickly running frequently used commands — ideal for SSH scripts, updates, and anything you run regularly from the terminal.
|
||||||
|
|
||||||
## Instalace
|
## Installation
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
brew install janvete/tools/lines
|
brew install janvete/tools/lines
|
||||||
```
|
```
|
||||||
|
|
||||||
## Použití
|
## Usage
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
lines # otevře TUI
|
lines # opens the TUI
|
||||||
lines --dir /cesta/k/datům # použije jinou datovou složku
|
lines --dir /path # use a different data directory
|
||||||
```
|
```
|
||||||
|
|
||||||
## Struktura dat
|
## Data structure
|
||||||
|
|
||||||
Data jsou běžné `.md` soubory ve složce `~/.lines`. Skupiny = podsložky.
|
Data is stored as plain `.md` files in `~/.lines`. Groups are subdirectories.
|
||||||
|
|
||||||
```
|
```
|
||||||
~/.lines
|
~/.lines
|
||||||
├── Synology
|
├── Servers
|
||||||
│ └── dsmview.md
|
│ └── web.md
|
||||||
└── Scripts
|
└── Scripts
|
||||||
└── update.md
|
└── update.md
|
||||||
```
|
```
|
||||||
|
|
||||||
### Konfigurace
|
### `.md` format
|
||||||
|
|
||||||
Vytvoř soubor `~/.lines/config.toml`:
|
Each section starts with `# Command name`. Command lines follow the heading.
|
||||||
|
|
||||||
```toml
|
|
||||||
terminal = "Ghostty" # možnosti: Terminal, Ghostty, iTerm
|
|
||||||
```
|
|
||||||
|
|
||||||
Výchozí terminál je `Terminal` (macOS Terminál.app).
|
|
||||||
|
|
||||||
## Formát `.md`
|
|
||||||
|
|
||||||
Každá sekce začíná nadpisem `# Název příkazu`. Pod ním následují řádky příkazů.
|
|
||||||
|
|
||||||
```markdown
|
```markdown
|
||||||
# Sysel DSM
|
# Web server
|
||||||
dsmview ssh root@192.168.40.15
|
ssh admin@web.example.com
|
||||||
|
|
||||||
# Johy DSM
|
# Database
|
||||||
dsmview ssh root@192.168.51.3
|
ssh admin@db.example.com
|
||||||
```
|
```
|
||||||
|
|
||||||
Sekce bez příkazů znamená "spustit všechny příkazy v tomto souboru".
|
A section without command lines means "run all commands in this file".
|
||||||
|
|
||||||
```markdown
|
```markdown
|
||||||
# Spustí vše
|
# Run all
|
||||||
|
|
||||||
# Docker update
|
# Docker update
|
||||||
ssh root@192.168.53.3 /opt/mealie/update.sh
|
ssh admin@host1.example.com /opt/app/update.sh
|
||||||
ssh root@192.168.53.5 /opt/yamtrack/update.sh
|
ssh admin@host2.example.com /opt/app/update.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
## Ovládání
|
## Configuration
|
||||||
|
|
||||||
| Klávesa | Akce |
|
Create `~/.lines/config.toml`:
|
||||||
|---------|------|
|
|
||||||
| `↑/↓` nebo `j/k` | pohyb v seznamu |
|
|
||||||
| `←/→` nebo `h/l` | přepínání panelů |
|
|
||||||
| `Enter` | spustí vybraný příkaz / všechny příkazy |
|
|
||||||
| `e` | otevře aktuální `.md` soubor v `$EDITOR` |
|
|
||||||
| `r` | znovu načte data ze složky |
|
|
||||||
| `q` nebo `Esc` | ukončí aplikaci |
|
|
||||||
|
|
||||||
## Zálohování
|
```toml
|
||||||
|
terminal = "Ghostty" # options: Terminal, Ghostty, iTerm
|
||||||
|
```
|
||||||
|
|
||||||
Celá datová složka `~/.lines` je obyčejný text — stačí ji zkopírovat na disk, do Gitu nebo iCloudu. Na novém Macu ji přeneseš a `lines` ji rovnou načte.
|
The default terminal is `Terminal` (macOS Terminal.app).
|
||||||
|
|
||||||
## Licence
|
## Controls
|
||||||
|
|
||||||
|
| Key | Action |
|
||||||
|
|-----|--------|
|
||||||
|
| `↑/↓` or `j/k` | move |
|
||||||
|
| `←/→` or `h/l` | switch panel |
|
||||||
|
| `Enter` | run selected command / all commands |
|
||||||
|
| `e` | open current `.md` file in `$EDITOR` |
|
||||||
|
| `r` | reload data |
|
||||||
|
| `q` / `Esc` | quit |
|
||||||
|
|
||||||
|
## Backup
|
||||||
|
|
||||||
|
The entire `~/.lines` folder is plain text. Copy it to a disk, Git repo, or iCloud. On a new Mac, move it to the same location and `lines` works immediately.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
MIT
|
MIT
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
# Spustí vše
|
# Run all
|
||||||
|
|
||||||
# Docker update
|
# Docker update
|
||||||
ssh root@192.168.53.3 /opt/mealie/update.sh
|
ssh admin@host1.example.com /opt/app/update.sh
|
||||||
ssh root@192.168.53.5 /opt/yamtrack/update.sh
|
ssh admin@host2.example.com /opt/app/update.sh
|
||||||
|
|
|
||||||
5
examples/Servers/web.md
Normal file
5
examples/Servers/web.md
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
# Main server
|
||||||
|
ssh admin@web.example.com
|
||||||
|
|
||||||
|
# Backup server
|
||||||
|
ssh admin@backup.example.com
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
# Sysel DSM
|
|
||||||
dsmview ssh root@192.168.40.15
|
|
||||||
|
|
||||||
# Johy DSM
|
|
||||||
dsmview ssh root@192.168.51.3
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::os::unix::fs::PermissionsExt;
|
use std::os::unix::fs::PermissionsExt;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::Path;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
|
use base64::{engine::general_purpose::STANDARD, Engine};
|
||||||
|
|
||||||
use crate::config::Terminal;
|
use crate::config::Terminal;
|
||||||
use crate::parser::{CommandFile, Section};
|
use crate::parser::{CommandFile, Section};
|
||||||
|
|
||||||
|
|
@ -22,20 +24,15 @@ pub fn run_section(section: &Section, file: &CommandFile, terminal: &Terminal, d
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let script = build_script(&commands);
|
match terminal {
|
||||||
execute_in_terminal(&script, terminal, data_dir);
|
Terminal::Ghostty => run_in_ghostty(&commands),
|
||||||
|
_ => run_via_script(&commands, terminal, data_dir),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_script(commands: &[String]) -> String {
|
fn run_via_script(commands: &[String], terminal: &Terminal, data_dir: &Path) {
|
||||||
commands.join("\n")
|
let script = commands.join("\n");
|
||||||
}
|
let run_dir = data_dir.join(".run");
|
||||||
|
|
||||||
fn script_dir(data_dir: &Path) -> PathBuf {
|
|
||||||
data_dir.join(".run")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn execute_in_terminal(script: &str, terminal: &Terminal, data_dir: &Path) {
|
|
||||||
let run_dir = script_dir(data_dir);
|
|
||||||
if fs::create_dir_all(&run_dir).is_err() {
|
if fs::create_dir_all(&run_dir).is_err() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -60,12 +57,28 @@ fn execute_in_terminal(script: &str, terminal: &Terminal, data_dir: &Path) {
|
||||||
let _ = fs::set_permissions(&script_path, fs::Permissions::from_mode(0o755));
|
let _ = fs::set_permissions(&script_path, fs::Permissions::from_mode(0o755));
|
||||||
|
|
||||||
match terminal {
|
match terminal {
|
||||||
Terminal::Ghostty => run_in_ghostty(&script_path),
|
|
||||||
Terminal::Iterm => run_in_iterm(&script_path),
|
Terminal::Iterm => run_in_iterm(&script_path),
|
||||||
Terminal::Builtin => run_in_terminal_app(&script_path),
|
Terminal::Builtin => run_in_terminal_app(&script_path),
|
||||||
|
Terminal::Ghostty => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn run_in_ghostty(commands: &[String]) {
|
||||||
|
let script = commands.join("\n");
|
||||||
|
let encoded = STANDARD.encode(script);
|
||||||
|
let shell_command = format!("echo {} | base64 -D | bash", encoded);
|
||||||
|
|
||||||
|
let _ = Command::new("open")
|
||||||
|
.arg("-na")
|
||||||
|
.arg("Ghostty")
|
||||||
|
.arg("--args")
|
||||||
|
.arg("-e")
|
||||||
|
.arg("bash")
|
||||||
|
.arg("-c")
|
||||||
|
.arg(shell_command)
|
||||||
|
.spawn();
|
||||||
|
}
|
||||||
|
|
||||||
fn run_in_terminal_app(script_path: &Path) {
|
fn run_in_terminal_app(script_path: &Path) {
|
||||||
let path_str = script_path.to_string_lossy();
|
let path_str = script_path.to_string_lossy();
|
||||||
let applescript = format!(
|
let applescript = format!(
|
||||||
|
|
@ -82,18 +95,6 @@ end tell"#,
|
||||||
.spawn();
|
.spawn();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_in_ghostty(script_path: &Path) {
|
|
||||||
let path_str = script_path.to_string_lossy();
|
|
||||||
let _ = Command::new("open")
|
|
||||||
.arg("-na")
|
|
||||||
.arg("Ghostty")
|
|
||||||
.arg("--args")
|
|
||||||
.arg("-e")
|
|
||||||
.arg("bash")
|
|
||||||
.arg(path_str.as_ref())
|
|
||||||
.spawn();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_in_iterm(script_path: &Path) {
|
fn run_in_iterm(script_path: &Path) {
|
||||||
let path_str = script_path.to_string_lossy();
|
let path_str = script_path.to_string_lossy();
|
||||||
let applescript = format!(
|
let applescript = format!(
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,6 @@ use std::path::PathBuf;
|
||||||
#[test]
|
#[test]
|
||||||
fn test_example_files_exist() {
|
fn test_example_files_exist() {
|
||||||
let examples = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("examples");
|
let examples = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("examples");
|
||||||
assert!(examples.join("Synology/dsmview.md").exists());
|
assert!(examples.join("Servers/web.md").exists());
|
||||||
assert!(examples.join("Scripts/update.md").exists());
|
assert!(examples.join("Scripts/update.md").exists());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue