Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: router paths + cli error reporting #3

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions volts-back/src/router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ pub fn build_router() -> Router<AppState> {
let plugins_routes = Router::with_state(state.clone())
.route("/", get(plugin::search))
.route("/new", put(plugin::publish))
.route("/:name/:version/yank", post(plugin::yank))
.route("/:name/:version/unyank", post(plugin::unyank))
.route("/:author/:name/:version", get(plugin::meta))
.route("/:author/:name/:version/yank", post(plugin::yank))
.route("/:author/:name/:version/unyank", post(plugin::unyank))
.route("/:author/:name/:version/download", get(plugin::download))
.route("/:author/:name/:version/readme", get(plugin::readme))
.route("/:author/:name/:version/icon", get(plugin::icon));
Expand Down
1 change: 1 addition & 0 deletions volts-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
anyhow = "1.0"
reqwest = { version = "0.11.12", features = ["blocking"] }
lapce-rpc = "0.2.1"
tempfile = "3.3.0"
Expand Down
96 changes: 47 additions & 49 deletions volts-cli/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::{
path::PathBuf,
};

use anyhow::{anyhow, Result};
use lapce_rpc::plugin::VoltMetadata;
use reqwest::{Method, StatusCode};
use tar::Builder;
Expand All @@ -12,76 +13,68 @@ use zstd::Encoder;

use crate::{auth_token, Cli, IconTheme};

pub(crate) fn publish(cli: &Cli) {
pub(crate) fn publish(cli: &Cli) -> Result<()> {
let token = auth_token(cli);

let temp_dir = tempfile::tempdir().unwrap();
let temp_dir = tempfile::tempdir()?;
let archive_path = temp_dir.path().join("plugin.volt");

{
let archive = File::create(&archive_path).unwrap();
let encoder = Encoder::new(archive, 0).unwrap();
let archive = File::create(&archive_path)?;
let encoder = Encoder::new(archive, 0)?;
let mut tar = Builder::new(encoder);

let volt_path = PathBuf::from("volt.toml");
if !volt_path.exists() {
eprintln!("volt.toml doesn't exist");
return;
return Err(anyhow!("volt.toml doesn't exist"));
}

let s = fs::read_to_string(&volt_path).unwrap();
let s = fs::read_to_string(&volt_path)?;
let volt: VoltMetadata = match toml::from_str(&s) {
Ok(volt) => volt,
Err(e) => {
eprintln!("volt.toml format invalid: {e}");
return;
return Err(anyhow!("volt.toml format invalid: {e}"));
}
};

tar.append_path(&volt_path).unwrap();
tar.append_path(&volt_path)?;

if let Some(wasm) = volt.wasm.as_ref() {
let wasm_path = PathBuf::from(wasm);
if !wasm_path.exists() {
eprintln!("wasm {wasm} not found");
return;
return Err(anyhow!("wasm {wasm} not found"));
}

tar.append_path(&wasm_path).unwrap();
tar.append_path(&wasm_path)?;
} else if let Some(themes) = volt.color_themes.as_ref() {
if themes.is_empty() {
eprintln!("no color theme provided");
return;
return Err(anyhow!("no color theme provided"));
}
for theme in themes {
let theme_path = PathBuf::from(theme);
if !theme_path.exists() {
eprintln!("color theme {theme} not found");
return;
return Err(anyhow!("color theme {theme} not found"));
}

tar.append_path(&theme_path).unwrap();
tar.append_path(&theme_path)?;
}
} else if let Some(themes) = volt.icon_themes.as_ref() {
if themes.is_empty() {
eprintln!("no icon theme provided");
return;
return Err(anyhow!("no icon theme provided"));
}
for theme in themes {
let theme_path = PathBuf::from(theme);
if !theme_path.exists() {
eprintln!("icon theme {theme} not found");
return;
return Err(anyhow!("icon theme {theme} not found"));
}

tar.append_path(&theme_path).unwrap();
tar.append_path(&theme_path)?;

let s = fs::read_to_string(&theme_path).unwrap();
let s = fs::read_to_string(&theme_path)?;
let theme_config: IconTheme = match toml::from_str(&s) {
Ok(config) => config,
Err(_) => {
eprintln!("icon theme {theme} format invalid");
return;
return Err(anyhow!("icon theme {theme} format invalid"));
}
};

Expand All @@ -96,31 +89,28 @@ pub(crate) fn publish(cli: &Cli) {
for icon in icons {
let icon_path = theme_path.parent().unwrap_or(&cwd).join(icon);
if !icon_path.exists() {
eprintln!("icon {icon} not found");
return;
return Err(anyhow!("icon {icon} not found"));
}
tar.append_path(&icon_path).unwrap();
tar.append_path(&icon_path)?;
}
}
} else {
eprintln!("not a valid plugin");
return;
return Err(anyhow!("not a valid plugin"));
}

let readme_path = PathBuf::from("README.md");
if readme_path.exists() {
tar.append_path(&readme_path).unwrap();
tar.append_path(&readme_path)?;
}

if let Some(icon) = volt.icon.as_ref() {
let icon_path = PathBuf::from(icon);
if !icon_path.exists() {
eprintln!("icon not found at the specified path");
return;
return Err(anyhow!("icon not found at the specified path"));
}
tar.append_path(&icon_path).unwrap();
tar.append_path(&icon_path)?;
}
tar.finish().unwrap();
tar.finish()?;
}

let resp = reqwest::blocking::Client::new()
Expand All @@ -130,17 +120,17 @@ pub(crate) fn publish(cli: &Cli) {
)
.bearer_auth(token.trim())
.body(File::open(&archive_path).unwrap())
.send()
.unwrap();
.send()?;
if resp.status() == StatusCode::OK {
println!("plugin published successfully");
return;
return Err(anyhow!("plugin published successfully"));
}

eprintln!("{}", resp.text().unwrap());
eprintln!("{}", resp.text()?);

Ok(())
}

pub(crate) fn yank(cli: &Cli, name: &String, version: &String) {
pub(crate) fn yank(cli: &Cli, author: &String, name: &String, version: &String) -> Result<()> {
let token = auth_token(cli);

let resp = reqwest::blocking::Client::new()
Expand All @@ -149,16 +139,20 @@ pub(crate) fn yank(cli: &Cli, name: &String, version: &String) {
format!("https://plugins.lapce.dev/api/v1/me/plugins/{name}/{version}/yank"),
)
.bearer_auth(token.trim())
.send()
.unwrap();
.send()?;
if resp.status() == StatusCode::OK {
println!("plugin version yanked successfully");
} else {
eprintln!("failed to yank plugin version: {}", resp.text().unwrap());
return Err(anyhow!(
"failed to yank plugin version: {}",
resp.text().unwrap()
));
}

Ok(())
}

pub(crate) fn unyank(cli: &Cli, name: &String, version: &String) {
pub(crate) fn unyank(cli: &Cli, author: &String, name: &String, version: &String) -> Result<()> {
let token = auth_token(cli);

let resp = reqwest::blocking::Client::new()
Expand All @@ -167,11 +161,15 @@ pub(crate) fn unyank(cli: &Cli, name: &String, version: &String) {
format!("https://plugins.lapce.dev/api/v1/me/plugins/{name}/{version}/unyank"),
)
.bearer_auth(token.trim())
.send()
.unwrap();
.send()?;
if resp.status() == StatusCode::OK {
println!("plugin version yanked successfully");
} else {
eprintln!("failed to yank plugin version: {}", resp.text().unwrap());
return Err(anyhow!(
"failed to unyank plugin version: {}",
resp.text().unwrap()
));
}

Ok(())
}
67 changes: 61 additions & 6 deletions volts-cli/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
mod commands;

use std::{collections::HashMap, io::stdin};
use std::{collections::HashMap, io::stdin, ops::Deref};

use anyhow::{Result, anyhow};
use clap::{Parser, Subcommand};
use lapce_rpc::plugin::VoltMetadata;
use serde::{Deserialize, Serialize};
use toml_edit::easy as toml;

#[derive(Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
Expand Down Expand Up @@ -35,21 +38,73 @@ enum Commands {
/// Publish plugin to registry
Publish {},
/// Yank version from registry
Yank { name: String, version: String },
Yank {
author: Option<String>,
name: Option<String>,
version: String,
},
/// Undo yanking version from registry
Unyank { name: String, version: String },
Unyank {
author: Option<String>,
name: Option<String>,
version: String,
},
}

pub fn cli() {
let cli = Cli::parse();

match &cli.command {
if let Err(e) = match &cli.command {
Commands::Publish {} => commands::publish(&cli),
Commands::Yank { name, version } => commands::yank(&cli, name, version),
Commands::Unyank { name, version } => commands::unyank(&cli, name, version),
Commands::Yank {
author,
name,
version,
} => {
if author.is_none() || name.is_none() {
let volt = read_volt();
commands::yank(&cli, volt.author, volt.name, version)
} else {
commands::yank(&cli, &author.unwrap(), &name.unwrap(), version)
}
},
Commands::Unyank {
author,
name,
version,
} => commands::unyank(&cli, author, name, version),
} {
eprintln!("Error: {e}");
std::process::exit(1);
}
}

const VOLT_MANIFEST: &str = "volt.toml";

fn read_volt() -> Result<VoltMetadata> {
let workdir = std::env::current_dir()?;
let volt_path = workdir.join(VOLT_MANIFEST);
if !volt_path.exists() {
return Err(anyhow!("{VOLT_MANIFEST} doesn't exist"));
}

let s = std::fs::read_to_string(&volt_path)?;
let volt = match toml::from_str::<VoltMetadata>(&s) {
Ok(mut volt) => {
volt
}
Err(_) => {
return Err(anyhow!("{VOLT_MANIFEST} format invalid"));
}
};

if semver::Version::parse(&volt.version).is_err() {
return Err(anyhow!("version isn't valid"));
}

Ok(volt)
}

fn auth_token(cli: &Cli) -> String {
let api_credential = keyring::Entry::new("lapce-volts", "registry-api");

Expand Down