Skip to content
This repository was archived by the owner on Mar 27, 2026. It is now read-only.
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
15 changes: 15 additions & 0 deletions crates/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,20 @@ serde_json.workspace = true
thiserror.workspace = true
time.workspace = true
time-humanize.workspace = true
toml.workspace = true
tracing.workspace = true
tracing-subscriber.workspace = true

config = { version = "0.15", default-features = false, features = ["toml"] }
fs-err = { version = "3.1" }
indicatif = { version = "0.18" }
shellexpand = { version = "3.1" }

[dependencies.reqwest]
version = "0.12"
default-features = false
features = ["json", "rustls-tls-native-roots"]

[profile.dist]
inherits = "release"
lto = "thin"
61 changes: 61 additions & 0 deletions crates/cli/src/args.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
use std::path::PathBuf;

use clap::{builder::styling, Parser, Subcommand};

const VERSION: &str = env!("CARGO_PKG_VERSION");

static HELP_TEMPLATE: &str = "\
{before-help}{name} {version}
{about}

{usage-heading}
{usage}

{all-args}{after-help}";

pub mod host;
pub mod teams;
pub mod uploads;
pub mod download;
pub mod upload;

const STYLES: styling::Styles = styling::Styles::styled()
.header(styling::AnsiColor::Green.on_default().bold())
.usage(styling::AnsiColor::Green.on_default().bold())
.literal(styling::AnsiColor::Blue.on_default().bold())
.placeholder(styling::AnsiColor::Cyan.on_default());

/// CLI for Parcel file sharing service
#[derive(Debug, Parser)]
#[command(
name = "parcel",
version = VERSION,
help_template = HELP_TEMPLATE,
styles = STYLES,
)]
pub struct Args {
/// The location of the Parcel configuration file
#[arg(long)]
pub config: Option<PathBuf>,

/// The command to run
#[command(subcommand)]
command: ParcelCommand,
}

#[derive(Debug, Subcommand)]
pub enum ParcelCommand {
/// Manage Parcel hosts
#[command(subcommand)]
Host(host::HostCommand),
/// Access Parcel teams
#[command(subcommand)]
Teams(teams::TeamsCommand),
/// Manage uploads on Parcel
#[command(subcommand)]
Uploads(uploads::UploadsCommand),
/// Download from Parcel
Download(download::DownloadCommand),
/// Upload to Parcel
Upload(upload::UploadCommand),
}
4 changes: 4 additions & 0 deletions crates/cli/src/args/download.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
use clap::Parser;

#[derive(Debug, Parser)]
pub struct DownloadCommand {}
23 changes: 23 additions & 0 deletions crates/cli/src/args/host.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use clap::Subcommand;

pub mod add;
pub mod check;
pub mod list;
pub mod remove;
pub mod set;

#[derive(Debug, Subcommand)]
pub enum HostCommand {
/// Add a new host
Add(add::AddHostCommand),
/// Remove a host
Remove(remove::RemoveHostCommand),
/// List all hosts
List(list::ListHostsCommand),
/// Check all hosts
CheckAll,
/// Check a specific host
Check(check::CheckHostCommand),
/// Change host settings
Set(set::SetHostCommand),
}
27 changes: 27 additions & 0 deletions crates/cli/src/args/host/add.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use clap::Parser;

#[derive(Debug, Parser)]
pub struct AddHostCommand {
/// The alias for this host
///
/// Aliases are used to refer to hosts in commands. If not provided, the host can only be
/// referred to by its hostname/IP address. All aliases must be unique.
#[arg(long)]
pub alias: Option<String>,
/// Whether this is the default host
#[arg(long)]
pub default: bool,
/// The API key to use for this host
///
/// You can create an API key from your account settings in the Parcel web interface.
#[arg(long)]
pub key: String,
/// Whether to use HTTPS
#[arg(long, default_value_t = true)]
#[arg(num_args(0..=1), default_missing_value("true"))]
pub https: bool,
/// The hostname or IP address of the host to add
#[arg(long)]
pub host: String,
}

11 changes: 11 additions & 0 deletions crates/cli/src/args/host/check.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use clap::Parser;

#[derive(Debug, Parser)]
pub struct CheckHostCommand {
/// The alias or host of the host to check
///
/// This can be the alias you set when adding the host, or the actual hostname/IP address.
#[arg(long)]
pub host: String,
}

5 changes: 5 additions & 0 deletions crates/cli/src/args/host/list.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
use clap::Parser;

#[derive(Debug, Parser)]
pub struct ListHostsCommand {}

11 changes: 11 additions & 0 deletions crates/cli/src/args/host/remove.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use clap::Parser;

#[derive(Debug, Parser)]
pub struct RemoveHostCommand {
/// The alias or host of the host to remove
///
/// This can be the alias you set when adding the host, or the actual hostname/IP address.
#[arg(long)]
pub host: String,
}

35 changes: 35 additions & 0 deletions crates/cli/src/args/host/set.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
use clap::Parser;

#[derive(Debug, Parser)]
pub struct SetHostCommand {
/// The alias or host of the host to set
///
/// This can be the alias you set when adding the host, or the actual hostname/IP address.
#[arg(long)]
pub host: String,
/// The new alias for this host
///
/// This option will assign a new alias to the host. If not provided, the alias will not be
/// changed.
#[arg(long)]
pub alias: Option<String>,
/// Remove the alias from this host
#[arg(long)]
pub remove_alias: bool,
/// Set this host as the default host
///
/// This will set the host as the default host for all commands that require a host where one
/// is not specified. If a default host is already set, it will be replaced.
#[arg(long)]
pub default: bool,
/// The API key to use for this host
///
/// You can create an API key from your account settings in the Parcel web interface.
#[arg(long)]
pub key: Option<String>,
/// Whether to use HTTPS
#[arg(long)]
#[arg(num_args(0..=1), default_missing_value("true"))]
pub https: Option<bool>,
}

9 changes: 9 additions & 0 deletions crates/cli/src/args/teams.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use clap::Subcommand;

pub mod list;

#[derive(Debug, Subcommand)]
pub enum TeamsCommand {
/// List all teams you're a member of
List(list::ListTeamsCommand),
}
19 changes: 19 additions & 0 deletions crates/cli/src/args/teams/list.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use clap::Parser;

use crate::context::Context;

#[derive(Debug, Parser)]
pub struct ListTeamsCommand {
/// The host to list teams for
///
/// If not provided, the default host will be used. This can be the alias you set when
/// adding the host, or the actual hostname/IP address.
#[arg(long)]
pub host: Option<String>,
}

impl ListTeamsCommand {
pub async fn run(self, _context: Context) -> anyhow::Result<()> {
Ok(())
}
}
4 changes: 4 additions & 0 deletions crates/cli/src/args/upload.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
use clap::Parser;

#[derive(Debug, Parser)]
pub struct UploadCommand {}
26 changes: 26 additions & 0 deletions crates/cli/src/args/uploads.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use clap::Subcommand;

pub mod list;
pub mod show;
pub mod set;

#[derive(Debug, Subcommand)]
pub enum UploadsCommand {
/// List all uploads
///
/// This command will list all the uploads for your account, or for a specific team (so long as
/// you have access to that team). You can also specify filters to reduce the number of
/// uploads returned, such as by filename or uploader.
List(list::ListUploadsCommand),
/// Show information about a specific upload
///
/// This will show information about an upload, including its filename, slug, UUID,
/// uploader, and so on. This also includes the link for the upload.
Show(show::ShowUploadCommand),
/// Change the settings for an upload
///
/// This command allows you to change the settings for an upload, such as changing the
/// filename, adding a custom slug, making the upload public, or setting an expiry date.
Set(set::UploadSetCommand),
}

72 changes: 72 additions & 0 deletions crates/cli/src/args/uploads/list.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
use clap::{Parser, ValueEnum};

#[derive(Debug, Parser)]
pub struct ListUploadsCommand {
/// The host to list teams for.
///
/// If not provided, the default host will be used. This can be the alias you set when
/// adding the host, or the actual hostname/IP address.
#[arg(long)]
pub host: Option<String>,
/// The team to list uploads for.
///
/// This should be the slug of the team, or the team's UUID. If not provided, the
/// uplooads for the user will be listed.
#[arg(long)]
pub team: Option<String>,
/// How to sort the uploads.
#[arg(long, default_value = "uploaded-at")]
pub sort: UploadSort,
/// Change the ordering of the uploads.
#[arg(long, default_value = "asc")]
pub order: UploadOrder,
/// Filter the uploads by the given filename.
///
/// This is a case-insensitive filter that will match any uploads that contain the
/// given filename in their name.
#[arg(long)]
pub filename: Option<String>,
/// Filter the uploads by the given uploader.
///
/// This is only relevant if the `team` argument is not provided. This argument should
/// be the username of the uploader or their UUID.
#[arg(long)]
pub uploader: Option<String>,
/// Render as JSON instead of a table.
#[arg(long)]
pub json: bool,
/// The maximum number of uploads to return.
///
/// This is useful for pagination. If not provided, the server limits the number of uploads
/// returned via the API.
#[arg(long, default_value_t = 100)]
pub limit: usize,
/// The offset to start returning uploads from.
///
/// This is useful for pagination. If not provided, the server will return the first
/// `limit` uploads.
#[arg(long, default_value_t = 0)]
pub offset: usize,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
#[value(rename_all = "kebab-case")]
pub enum UploadSort {
/// Order by the upload filename.
Filename,
/// Order by the size of the uploads.
Size,
/// Order by the number of downloads.
Downloads,
/// Order by the date on which the public link will expire.
ExpiryDate,
/// Order by the date on which the upload was created.
UploadedAt,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
#[value(rename_all = "kebab-case")]
pub enum UploadOrder {
Asc,
Desc,
}
Loading