implement download

This commit is contained in:
Cadey Ratio 2020-05-30 14:27:49 -04:00
parent e112253bf8
commit a316558140
7 changed files with 135 additions and 3 deletions

7
Cargo.lock generated
View File

@ -86,6 +86,12 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
[[package]]
name = "byte-unit"
version = "3.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55390dbbf21ce70683f3e926dace00a21da373e35e44a60cafd232e3e9bf2041"
[[package]] [[package]]
name = "byteorder" name = "byteorder"
version = "1.3.4" version = "1.3.4"
@ -323,6 +329,7 @@ name = "gitea-release"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"byte-unit",
"cli-table", "cli-table",
"comrak", "comrak",
"git2", "git2",

View File

@ -8,6 +8,7 @@ edition = "2018"
[dependencies] [dependencies]
anyhow = "1.0" anyhow = "1.0"
byte-unit = "3"
cli-table = "0.3" cli-table = "0.3"
comrak = "0.7" comrak = "0.7"
git2 = "0.13" git2 = "0.13"
@ -18,3 +19,6 @@ serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
structopt = { version = "0.3", default-features = false } structopt = { version = "0.3", default-features = false }
tokio = { version = "0.2", features = ["macros"] } tokio = { version = "0.2", features = ["macros"] }
[profile.release]
lto = true

View File

@ -3,7 +3,8 @@
* Commands * Commands
** DONE delete ** DONE delete
CLOSED: [2020-05-30 Sat 12:23] CLOSED: [2020-05-30 Sat 12:23]
** TODO download ** DONE download
CLOSED: [2020-05-30 Sat 14:27]
** TODO edit ** TODO edit
** DONE info ** DONE info
CLOSED: [2020-05-30 Sat 10:52] CLOSED: [2020-05-30 Sat 10:52]

68
src/cmd/download.rs Normal file
View File

@ -0,0 +1,68 @@
use crate::{gitea::*, *};
use anyhow::{anyhow, Result};
use cli_table::{Cell, Row, Table};
use std::fs::File;
use std::io::Write;
pub(crate) async fn run(common: Common, fname: Option<PathBuf>) -> Result<()> {
if common.tag.is_none() {
return Err(anyhow!("requires --tag"));
}
let cli = client(&common)?;
let release = get_release_by_tag(
&cli,
&common.server,
&common.owner,
&common.repo,
&common.tag.unwrap(),
)
.await?;
let attachments = get_attachments_for_release(
&cli,
&common.server,
&common.owner,
&common.repo,
&release.id,
)
.await?;
match fname {
None => {
let mut rows: Vec<Row> = vec![Row::new(vec![
Cell::new(&"name", Default::default()),
Cell::new(&"size", Default::default()),
Cell::new(&"url", Default::default()),
])];
for attachment in attachments {
rows.push(attachment.row())
}
let table = Table::new(rows, Default::default())?;
table.print_stdout()?;
Ok(())
}
Some(fname) => {
let mut url: Option<String> = None;
let fname = fname.into_os_string().into_string().unwrap();
for attachment in attachments {
if &fname == &attachment.name {
url = Some(attachment.browser_download_url);
}
}
if url.is_none() {
return Err(anyhow!("no attachment named {}", fname));
}
let data = &cli.get(url.unwrap().as_str()).send().await?.bytes().await?;
let mut fout = File::create(&fname)?;
fout.write(data)?;
Ok(())
}
}
}

View File

@ -1,2 +1,3 @@
pub(crate) mod delete; pub(crate) mod delete;
pub(crate) mod download;
pub(crate) mod info; pub(crate) mod info;

View File

@ -85,3 +85,53 @@ pub(crate) async fn get_release_by_tag(
Ok(release.unwrap()) Ok(release.unwrap())
} }
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Attachment {
pub id: i64,
pub name: String,
pub size: i64,
pub download_count: i64,
pub created_at: String,
pub uuid: String,
pub browser_download_url: String,
}
impl Attachment {
pub fn row(&self) -> Row {
let size = {
let bytes = byte_unit::Byte::from_bytes(self.size as u128);
let unit = bytes.get_appropriate_unit(false);
unit.to_string()
};
Row::new(vec![
Cell::new(&self.name, Default::default()),
Cell::new(&size, Default::default()),
Cell::new(&self.browser_download_url, Default::default()),
])
}
}
pub(crate) async fn get_attachments_for_release(
cli: &reqwest::Client,
server: &String,
owner: &String,
repo: &String,
id: &i64,
) -> Result<Vec<Attachment>> {
let attachments: Vec<Attachment> = cli
.get(
format!(
"{}/api/v1/repos/{}/{}/releases/{}/assets",
server, owner, repo, id
)
.as_str(),
)
.send()
.await?
.json()
.await?;
Ok(attachments)
}

View File

@ -29,7 +29,7 @@ pub(crate) struct Common {
} }
// Name your user agent after your app? // Name your user agent after your app?
static APP_USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"),); static APP_USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"));
pub(crate) fn client(c: &Common) -> Result<Client> { pub(crate) fn client(c: &Common) -> Result<Client> {
let mut headers = header::HeaderMap::new(); let mut headers = header::HeaderMap::new();
@ -69,7 +69,7 @@ pub(crate) enum Cmd {
common: Common, common: Common,
/// Folder to download release artifacts to /// Folder to download release artifacts to
#[structopt(short, long)] #[structopt(short, long)]
fname: PathBuf, fname: Option<PathBuf>,
}, },
/// Edits a release's description, name and other flags /// Edits a release's description, name and other flags
Edit { Edit {
@ -124,6 +124,7 @@ async fn main() -> Result<()> {
match cmd { match cmd {
Cmd::Delete { common } => cmd::delete::run(common).await, Cmd::Delete { common } => cmd::delete::run(common).await,
Cmd::Download { common, fname } => cmd::download::run(common, fname).await,
Cmd::Info { common, json } => cmd::info::run(common, json).await, Cmd::Info { common, json } => cmd::info::run(common, json).await,
_ => Err(anyhow!("not implemented yet")), _ => Err(anyhow!("not implemented yet")),