Skip to content
Merged
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
2 changes: 1 addition & 1 deletion Cargo.lock

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

1 change: 1 addition & 0 deletions peeko-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ edition = "2024"
[dependencies]
peeko = { path = "../peeko", features = ["progress"] }
clap = { version = "4.4", features = ["derive"] }
dirs = "6"
inquire = "0.7"
indicatif = "0.18"
console = "0.15"
Expand Down
3 changes: 2 additions & 1 deletion peeko-cli/src/commands/cat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ use tokio::io::{self, AsyncWriteExt};
use indicatif::{ProgressBar, ProgressStyle};
use peeko::reader::build_image_reader;

use crate::config;
use crate::error::{PeekoCliError, Result};
use crate::utils;

pub async fn execute(image_with_tag: &str, path: &str) -> Result<()> {
match image_with_tag.rsplit_once(':') {
Some((image, tag)) => {
let image_path = peeko::config::get_peeko_dir().join(format!("{image}/{tag}"));
let image_path = config::get_peeko_dir().join(format!("{image}/{tag}"));
// Check if image exists
if !std::path::Path::new(&image_path).exists() {
utils::print_error(&format!("Image {image}:{tag} not found locally"));
Expand Down
3 changes: 1 addition & 2 deletions peeko-cli/src/commands/list.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use std::fs;
use tabled::{Table, Tabled};

use peeko::config;

use crate::config;
use crate::error::Result;
use crate::utils;

Expand Down
3 changes: 2 additions & 1 deletion peeko-cli/src/commands/ls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use indicatif::{ProgressBar, ProgressStyle};
use peeko::reader::{build_image_reader, vfs::FileEntry};
use tabled::{Table, Tabled, settings::Style};

use crate::config;
use crate::error::{PeekoCliError, Result};
use crate::utils;

Expand All @@ -20,7 +21,7 @@ struct FileInfo {
pub async fn execute(image_with_tag: &str, path: &str) -> Result<()> {
match image_with_tag.rsplit_once(':') {
Some((image, tag)) => {
let image_path = peeko::config::get_peeko_dir().join(format!("{image}/{tag}"));
let image_path = config::get_peeko_dir().join(format!("{image}/{tag}"));
// Check if image exists
if !std::path::Path::new(&image_path).exists() {
utils::print_warning(&format!("Image {image}:{tag} not found locally"));
Expand Down
3 changes: 3 additions & 0 deletions peeko-cli/src/commands/pull.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use console::style;
use peeko::registry::client::{PlatformParam, RegistryClient, RegistryError};

use crate::config;
use crate::error::{PeekoCliError, Result};
use crate::utils;

Expand All @@ -11,6 +12,8 @@ pub async fn execute(image_url: &str) -> Result<()> {
utils::print_header(&format!("Pulling {image}:{tag} from {registry_url}"));

let mut client = RegistryClient::new(&registry_url).enable_progress();
client.set_concurrent_downloads(config::get_concurrent_downloads());
client.set_downloads_dir(config::get_peeko_dir());

let platform = PlatformParam {
architecture: None,
Expand Down
3 changes: 2 additions & 1 deletion peeko-cli/src/commands/remove.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use crate::config;
use crate::error::{PeekoCliError, Result};
use crate::utils;

pub async fn execute(image_with_tag: &str) -> Result<()> {
match image_with_tag.rsplit_once(':') {
Some((image, tag)) => {
peeko::fs::delete_image(image, tag)?;
peeko::fs::delete_image(config::get_peeko_dir(), image, tag)?;
utils::print_success(&format!("Successfully removed {image_with_tag}"));
Ok(())
}
Expand Down
3 changes: 2 additions & 1 deletion peeko-cli/src/commands/tree.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use peeko::reader::build_image_reader;

use crate::config;
use crate::error::{PeekoCliError, Result};
use crate::utils;

Expand All @@ -8,7 +9,7 @@ pub async fn execute(image_with_tag: &str, depth: usize, path: Option<String>) -
Some((image, tag)) => {
utils::print_header(&format!("Filesystem Tree for {image}:{tag}"));

let image_path = peeko::config::get_peeko_dir().join(format!("{image}/{tag}"));
let image_path = config::get_peeko_dir().join(format!("{image}/{tag}"));

// Check if image exists
if !std::path::Path::new(&image_path).exists() {
Expand Down
2 changes: 0 additions & 2 deletions peeko/src/config.rs → peeko-cli/src/config.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
use std::env;
use std::path::PathBuf;

use dirs;

const DEFAULT_PEEKO_DIR: &str = "~/.peeko";
const DEFAULT_CONCURRENT_DOWNLOADS: &str = "4";

Expand Down
1 change: 1 addition & 0 deletions peeko-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::{
};

mod commands;
mod config;
mod error;
mod interactive;
mod utils;
Expand Down
1 change: 0 additions & 1 deletion peeko/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ futures-util = "0.3.31"
flate2 = "1.1.2"
tar = "0.4.44"
zstd = "0.13.3"
dirs = "6.0.0"
indicatif = { version = "0.18", optional = true }

[features]
Expand Down
29 changes: 6 additions & 23 deletions peeko/src/fs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,13 @@ use std::fs;
use std::io::Result;
use std::path::{Path, PathBuf};

use crate::config;

pub fn collect_images() -> Result<Vec<String>> {
let base_dir = config::get_peeko_dir();
collect_image_directories(&base_dir).map(|dirs| {
pub fn collect_images<P: AsRef<Path>>(oci_dir: P) -> Result<Vec<String>> {
let base_dir = oci_dir.as_ref();
collect_image_directories(base_dir).map(|dirs| {
dirs.into_iter()
.map(|dir| {
let mut relative_path = dir
.strip_prefix(&base_dir)
.strip_prefix(base_dir)
.expect("Must be a subdirectory of the peeko directory")
.to_string_lossy()
.to_string();
Expand Down Expand Up @@ -53,23 +51,8 @@ fn collect_image_directories_recursive(path: &Path, result: &mut Vec<PathBuf>) -
Ok(())
}

pub fn delete_image(image: &str, tag: &str) -> Result<()> {
let image_path = config::get_peeko_dir().join(format!("{image}/{tag}"));
pub fn delete_image<P: AsRef<Path>>(oci_dir: P, image: &str, tag: &str) -> Result<()> {
let image_path = oci_dir.as_ref().join(format!("{image}/{tag}"));
fs::remove_dir_all(&image_path)?;
Ok(())
}

#[cfg(test)]
mod tests {
use super::*;
use crate::config;

#[test]
fn test_collect_image_directories() {
let result = collect_image_directories(config::get_peeko_dir()).unwrap();
println!("{:?}", result);
let images = collect_images().unwrap();
println!("{:?}", images);
assert_eq!(result.len(), images.len());
}
}
1 change: 0 additions & 1 deletion peeko/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
pub mod config;
pub mod fs;
pub mod manifest;
pub mod reader;
Expand Down
58 changes: 42 additions & 16 deletions peeko/src/registry/client.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::path::Path;
use std::path::{Path, PathBuf};
use std::sync::Arc;

use futures_util::{StreamExt, TryStreamExt, stream};
Expand All @@ -9,7 +9,6 @@ use tokio::fs::{self, File};
use tokio::io::AsyncWriteExt;

use super::progress::{NoopProgress, ProgressTracker};
use crate::config;
use crate::manifest::{self, Descriptor, Manifest, ManifestList, PlatformManifest};

#[derive(Error, Debug)]
Expand Down Expand Up @@ -57,39 +56,67 @@ pub struct PlatformParam {
pub variant: Option<String>,
}

const DEFAULT_REGISTRY: &str = "https://registry-1.docker.io";
const DEFAULT_CONCURRENT_DOWNLOADS: usize = 3;

#[derive(Clone)]
pub struct RegistryClient {
http: reqwest::Client,
registry_url: String,
oci_dir: PathBuf,
concurrent_downloads: usize,
auth_token: Option<String>,
username: Option<String>,
password: Option<String>,
progress: Arc<dyn ProgressTracker>,
}

impl RegistryClient {
pub fn new(registry_url: &str) -> Self {
impl Default for RegistryClient {
fn default() -> Self {
Self {
http: reqwest::Client::new(),
registry_url: registry_url.to_string(),
registry_url: DEFAULT_REGISTRY.to_string(),
oci_dir: "./".into(),
concurrent_downloads: DEFAULT_CONCURRENT_DOWNLOADS,
auth_token: None,
username: None,
password: None,
progress: Arc::new(NoopProgress),
}
}
}

impl RegistryClient {
pub fn new(registry_url: &str) -> Self {
Self {
registry_url: registry_url.to_string(),
..Default::default()
}
}

pub fn with_credentials(registry_url: &str, username: &str, password: &str) -> Self {
let mut client = Self::new(registry_url);
client.username = Some(username.to_string());
client.password = Some(password.to_string());
client
Self {
registry_url: registry_url.to_string(),
username: Some(username.to_string()),
password: Some(password.to_string()),
..Default::default()
}
}

pub fn with_token(registry_url: &str, token: &str) -> Self {
let mut client = Self::new(registry_url);
client.auth_token = Some(token.to_string());
client
Self {
registry_url: registry_url.to_string(),
auth_token: Some(token.to_string()),
..Default::default()
}
}

pub fn set_downloads_dir<P: Into<PathBuf>>(&mut self, dir: P) {
self.oci_dir = dir.into();
}

pub fn set_concurrent_downloads(&mut self, concurrent: usize) {
self.concurrent_downloads = concurrent;
}

#[cfg(feature = "progress")]
Expand Down Expand Up @@ -249,9 +276,8 @@ impl RegistryClient {

let oci_manifest = image_manifest.ok_or_else(|| RegistryError::ManifestNotFound)?;

// create folder
let peeko_dir = config::get_peeko_dir();
let folder_path = peeko_dir.join(format!("{image}/{tag}"));
// create folder;
let folder_path = self.oci_dir.join(format!("{image}/{tag}"));
fs::create_dir_all(&folder_path).await?;

let manifest_path = folder_path.join("manifest.json");
Expand All @@ -268,7 +294,7 @@ impl RegistryClient {
.map(|layer| self.download(image, layer, &folder_path));

stream::iter(tasks)
.buffer_unordered(config::get_concurrent_downloads())
.buffer_unordered(self.concurrent_downloads)
.try_collect::<Vec<_>>()
.await?;

Expand Down