mirror of
https://github.com/asciinema/asciinema.git
synced 2025-12-16 03:38:03 +01:00
Unify config
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
use crate::{config::Config, util};
|
||||
use crate::config::Config;
|
||||
use anyhow::{anyhow, Result};
|
||||
use clap::Args;
|
||||
use reqwest::Url;
|
||||
@@ -8,8 +8,9 @@ pub struct Cli {}
|
||||
|
||||
impl Cli {
|
||||
pub fn run(self, config: &Config) -> Result<()> {
|
||||
let auth_url = auth_url(config.server_url())?;
|
||||
let server_hostname = auth_url.host().ok_or(anyhow!("invalid server URL"))?;
|
||||
let server_url = config.get_server_url()?;
|
||||
let server_hostname = server_url.host().ok_or(anyhow!("invalid server URL"))?;
|
||||
let auth_url = auth_url(&server_url, &config.get_install_id()?);
|
||||
|
||||
println!("Open the following URL in a web browser to authenticate this asciinema CLI with your {server_hostname} user account:\n");
|
||||
println!("{}\n", auth_url);
|
||||
@@ -19,9 +20,9 @@ impl Cli {
|
||||
}
|
||||
}
|
||||
|
||||
fn auth_url(server_url: Option<&String>) -> Result<Url> {
|
||||
let mut url = util::get_server_url(server_url)?;
|
||||
url.set_path(&format!("connect/{}", util::get_install_id()?));
|
||||
fn auth_url(server_url: &Url, install_id: &str) -> Url {
|
||||
let mut url = server_url.clone();
|
||||
url.set_path(&format!("connect/{install_id}"));
|
||||
|
||||
Ok(url)
|
||||
url
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use crate::config::Config;
|
||||
use crate::util;
|
||||
use anyhow::{anyhow, Result};
|
||||
use clap::Args;
|
||||
use reqwest::{
|
||||
@@ -27,9 +26,9 @@ impl Cli {
|
||||
let form = Form::new().file("asciicast", self.filename)?;
|
||||
|
||||
let response = client
|
||||
.post(api_url(config.server_url())?)
|
||||
.post(api_url(&config.get_server_url()?))
|
||||
.multipart(form)
|
||||
.basic_auth(get_username(), Some(util::get_install_id()?))
|
||||
.basic_auth(get_username(), Some(config.get_install_id()?))
|
||||
.header(header::USER_AGENT, build_user_agent())
|
||||
.header(header::ACCEPT, "application/json")
|
||||
.send()?;
|
||||
@@ -57,11 +56,11 @@ impl Cli {
|
||||
}
|
||||
}
|
||||
|
||||
fn api_url(server_url: Option<&String>) -> Result<Url> {
|
||||
let mut url = util::get_server_url(server_url)?;
|
||||
fn api_url(server_url: &Url) -> Url {
|
||||
let mut url = server_url.clone();
|
||||
url.set_path("api/asciicasts");
|
||||
|
||||
Ok(url)
|
||||
url
|
||||
}
|
||||
|
||||
fn get_username() -> String {
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
use anyhow::{anyhow, Result};
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use reqwest::Url;
|
||||
use serde::Deserialize;
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::io::ErrorKind;
|
||||
use std::path::{Path, PathBuf};
|
||||
use uuid::Uuid;
|
||||
|
||||
const DEFAULT_SERVER_URL: &str = "https://asciinema.org";
|
||||
const INSTALL_ID_FILENAME: &str = "install-id";
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[allow(unused)]
|
||||
@@ -80,12 +86,46 @@ impl Config {
|
||||
Ok(config.build()?.try_deserialize()?)
|
||||
}
|
||||
|
||||
pub fn server_url(&self) -> Option<&String> {
|
||||
self.server.url.as_ref().or(self.api.url.as_ref())
|
||||
pub fn get_server_url(&self) -> Result<Url> {
|
||||
match self.server.url.as_ref() {
|
||||
Some(url) => Ok(Url::parse(url)?),
|
||||
|
||||
None => {
|
||||
let url = Url::parse(&ask_for_server_url()?)?;
|
||||
save_default_server_url(url.as_ref())?;
|
||||
|
||||
Ok(url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_install_id(&self) -> Result<String> {
|
||||
let path = install_id_path()?;
|
||||
|
||||
if let Some(id) = read_install_id(&path)? {
|
||||
Ok(id)
|
||||
} else {
|
||||
let id = create_install_id();
|
||||
save_install_id(&path, &id)?;
|
||||
|
||||
Ok(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn save_default_server_url(url: &str) -> Result<()> {
|
||||
fn ask_for_server_url() -> Result<String> {
|
||||
println!("No asciinema server configured for this CLI.");
|
||||
let mut rl = rustyline::DefaultEditor::new()?;
|
||||
let url = rl.readline_with_initial(
|
||||
"Enter the server URL to use by default: ",
|
||||
(DEFAULT_SERVER_URL, ""),
|
||||
)?;
|
||||
println!();
|
||||
|
||||
Ok(url)
|
||||
}
|
||||
|
||||
fn save_default_server_url(url: &str) -> Result<()> {
|
||||
let path = user_defaults_path()?;
|
||||
|
||||
if let Some(dir) = path.parent() {
|
||||
@@ -97,12 +137,32 @@ pub fn save_default_server_url(url: &str) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn home() -> Result<PathBuf> {
|
||||
env::var("ASCIINEMA_CONFIG_HOME")
|
||||
.map(PathBuf::from)
|
||||
.or(env::var("XDG_CONFIG_HOME").map(|home| Path::new(&home).join("asciinema")))
|
||||
.or(env::var("HOME").map(|home| Path::new(&home).join(".config").join("asciinema")))
|
||||
.map_err(|_| anyhow!("need $HOME or $XDG_CONFIG_HOME or $ASCIINEMA_CONFIG_HOME"))
|
||||
fn read_install_id(path: &PathBuf) -> Result<Option<String>> {
|
||||
match fs::read_to_string(path) {
|
||||
Ok(s) => Ok(Some(s.trim().to_string())),
|
||||
|
||||
Err(e) => {
|
||||
if e.kind() == ErrorKind::NotFound {
|
||||
Ok(None)
|
||||
} else {
|
||||
bail!(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn create_install_id() -> String {
|
||||
Uuid::new_v4().to_string()
|
||||
}
|
||||
|
||||
fn save_install_id(path: &PathBuf, id: &str) -> Result<()> {
|
||||
if let Some(dir) = path.parent() {
|
||||
fs::create_dir_all(dir)?;
|
||||
}
|
||||
|
||||
fs::write(path, &id)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn user_config_path() -> Result<PathBuf> {
|
||||
@@ -112,3 +172,15 @@ fn user_config_path() -> Result<PathBuf> {
|
||||
fn user_defaults_path() -> Result<PathBuf> {
|
||||
Ok(home()?.join("defaults.toml"))
|
||||
}
|
||||
|
||||
fn install_id_path() -> Result<PathBuf> {
|
||||
Ok(home()?.join(INSTALL_ID_FILENAME))
|
||||
}
|
||||
|
||||
fn home() -> Result<PathBuf> {
|
||||
env::var("ASCIINEMA_CONFIG_HOME")
|
||||
.map(PathBuf::from)
|
||||
.or(env::var("XDG_CONFIG_HOME").map(|home| Path::new(&home).join("asciinema")))
|
||||
.or(env::var("HOME").map(|home| Path::new(&home).join(".config").join("asciinema")))
|
||||
.map_err(|_| anyhow!("need $HOME or $XDG_CONFIG_HOME or $ASCIINEMA_CONFIG_HOME"))
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ mod format;
|
||||
mod locale;
|
||||
mod pty;
|
||||
mod recorder;
|
||||
mod util;
|
||||
use crate::config::Config;
|
||||
use anyhow::Result;
|
||||
use clap::{Parser, Subcommand};
|
||||
|
||||
111
src/util.rs
111
src/util.rs
@@ -1,111 +0,0 @@
|
||||
use crate::config;
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use reqwest::Url;
|
||||
use std::{env, fs, io::ErrorKind, path::Path, path::PathBuf};
|
||||
use uuid::Uuid;
|
||||
|
||||
const DEFAULT_SERVER_URL: &str = "https://asciinema.org";
|
||||
const INSTALL_ID_FILENAME: &str = "install-id";
|
||||
|
||||
pub fn get_install_id() -> Result<String> {
|
||||
if let Some(install_id) = read_install_id()? {
|
||||
Ok(install_id)
|
||||
} else if let Some(install_id) = read_legacy_install_id()? {
|
||||
Ok(install_id)
|
||||
} else {
|
||||
create_install_id()
|
||||
}
|
||||
}
|
||||
|
||||
fn read_install_id() -> Result<Option<String>> {
|
||||
read_state_file(INSTALL_ID_FILENAME)
|
||||
}
|
||||
|
||||
fn create_install_id() -> Result<String> {
|
||||
let id = Uuid::new_v4().to_string();
|
||||
write_state_file(INSTALL_ID_FILENAME, &id)?;
|
||||
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
fn read_legacy_install_id() -> Result<Option<String>> {
|
||||
let path = config::home()?.join(INSTALL_ID_FILENAME);
|
||||
|
||||
match fs::read_to_string(path) {
|
||||
Ok(s) => Ok(Some(s.trim().to_string())),
|
||||
|
||||
Err(e) => {
|
||||
if e.kind() == ErrorKind::NotFound {
|
||||
Ok(None)
|
||||
} else {
|
||||
bail!(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_server_url(server_url: Option<&String>) -> Result<Url> {
|
||||
match server_url {
|
||||
Some(url) => Ok(Url::parse(&url)?),
|
||||
|
||||
None => {
|
||||
let url = Url::parse(&ask_for_server_url()?)?;
|
||||
config::save_default_server_url(url.as_ref())?;
|
||||
|
||||
Ok(url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn ask_for_server_url() -> Result<String> {
|
||||
println!("No asciinema server configured for this CLI.");
|
||||
let mut rl = rustyline::DefaultEditor::new()?;
|
||||
let url = rl.readline_with_initial(
|
||||
"Enter the server URL to use by default: ",
|
||||
(DEFAULT_SERVER_URL, ""),
|
||||
)?;
|
||||
println!();
|
||||
|
||||
Ok(url)
|
||||
}
|
||||
|
||||
fn read_state_file(filename: &str) -> Result<Option<String>> {
|
||||
let path = state_home()?.join(filename);
|
||||
|
||||
match fs::read_to_string(path) {
|
||||
Ok(s) => Ok(Some(s.trim().to_string())),
|
||||
|
||||
Err(e) => {
|
||||
if e.kind() == ErrorKind::NotFound {
|
||||
Ok(None)
|
||||
} else {
|
||||
bail!(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn write_state_file(filename: &str, contents: &str) -> Result<()> {
|
||||
let path = state_home()?.join(filename);
|
||||
|
||||
if let Some(dir) = path.parent() {
|
||||
fs::create_dir_all(dir)?;
|
||||
}
|
||||
|
||||
fs::write(path, contents)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn state_home() -> Result<PathBuf> {
|
||||
env::var("ASCIINEMA_STATE_HOME")
|
||||
.map(PathBuf::from)
|
||||
.or(env::var("XDG_STATE_HOME").map(|home| Path::new(&home).join("asciinema")))
|
||||
.or(env::var("HOME").map(|home| {
|
||||
Path::new(&home)
|
||||
.join(".local")
|
||||
.join("state")
|
||||
.join("asciinema")
|
||||
}))
|
||||
.map_err(|_| anyhow!("need $HOME or $XDG_STATE_HOME or $ASCIINEMA_STATE_HOME"))
|
||||
}
|
||||
Reference in New Issue
Block a user