@@ -12,3 +12,4 @@ anyhow = "1"
|
||||
clap = { version = "4", features = ["derive"] }
|
||||
packie = { path = "../" }
|
||||
rust-i18n = "4"
|
||||
indicatif = "0.18"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use anyhow::anyhow;
|
||||
use clap::Parser;
|
||||
use indicatif::ProgressBar;
|
||||
use packie::repo::RepoServeDir;
|
||||
use std::path::PathBuf;
|
||||
|
||||
@@ -11,9 +12,26 @@ pub struct Cli {
|
||||
/// Add package(s) to the repository
|
||||
#[arg(long, short)]
|
||||
add_package: Option<Vec<PathBuf>>,
|
||||
|
||||
/// Clone or pull remote repository
|
||||
#[arg(long, short)]
|
||||
clone: Option<String>,
|
||||
}
|
||||
|
||||
pub fn main(cli: Cli) -> anyhow::Result<()> {
|
||||
if let Some(clone) = cli.clone {
|
||||
let progress_bar = ProgressBar::new(0);
|
||||
RepoServeDir::clone(&clone.parse()?, &cli.repo, |pkg, url, sum, total| {
|
||||
progress_bar.set_length(total);
|
||||
progress_bar.set_position(sum);
|
||||
if let Some(pkg) = pkg {
|
||||
progress_bar.set_prefix(pkg);
|
||||
}
|
||||
progress_bar.set_message(url.to_string());
|
||||
})
|
||||
.map_err(|x| anyhow!("{x}"))?;
|
||||
}
|
||||
|
||||
let mut repo = RepoServeDir::open(cli.repo)?;
|
||||
|
||||
for add_package in cli.add_package.into_iter().flatten() {
|
||||
|
||||
@@ -83,6 +83,10 @@ pub struct PkgManifest {
|
||||
#[serde(default)]
|
||||
pub dependencies: Vec<PkgSpec>,
|
||||
|
||||
/// Package provisions.
|
||||
#[serde(default)]
|
||||
pub provides: Vec<String>,
|
||||
|
||||
/// Links.
|
||||
#[serde(default)]
|
||||
pub links: Vec<LinkDescription>,
|
||||
|
||||
+30
-4
@@ -121,7 +121,32 @@ impl RepoDb {
|
||||
)?.query_one(params![pkg_ident.name, pkg_ident.version.to_string(), pkg_ident.arch], map_repo_package)
|
||||
}
|
||||
|
||||
pub fn select_package_by_pkgname(&mut self) {}
|
||||
pub fn select_package_by_pkgname(
|
||||
&mut self,
|
||||
pkgname: &str,
|
||||
) -> rusqlite::Result<Vec<RepoPackage>> {
|
||||
let mut stmt = self
|
||||
.0
|
||||
.prepare_cached(r#"SELECT * FROM "package" WHERE "pkg_name" = ?1"#)?;
|
||||
let mapped_rows = stmt.query_map(params![pkgname], map_repo_package)?;
|
||||
let mut ret = Vec::with_capacity(16);
|
||||
for mr in mapped_rows {
|
||||
ret.push(mr?);
|
||||
}
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
pub fn for_each_package<E: From<rusqlite::Error>>(
|
||||
&mut self,
|
||||
mut f: impl FnMut(RepoPackage) -> Result<(), E>,
|
||||
) -> Result<(), E> {
|
||||
let mut stmt = self.0.prepare_cached("SELECT * FROM \"package\"")?;
|
||||
let mapped_rows = stmt.query_map(params![], map_repo_package)?;
|
||||
for mr in mapped_rows {
|
||||
f(mr?)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn insert_package(&mut self, package: &RepoPackage) -> rusqlite::Result<()> {
|
||||
let pkg_manifest = serde_json::to_string(&package.pkg_manifest)
|
||||
@@ -131,9 +156,9 @@ impl RepoDb {
|
||||
r#"
|
||||
INSERT INTO "package"(
|
||||
"pkg_name", "pkg_version", "pkg_arch", "pkg_manifest",
|
||||
"download_size", "installed_size"
|
||||
"download_size", "installed_size", "checksum"
|
||||
)
|
||||
VALUES(?1, ?2, ?3, ?4, ?5, ?6)
|
||||
VALUES(?1, ?2, ?3, ?4, ?5, ?6, ?7)
|
||||
"#,
|
||||
)?
|
||||
.execute(params![
|
||||
@@ -142,7 +167,8 @@ impl RepoDb {
|
||||
package.pkg_manifest.arch,
|
||||
pkg_manifest,
|
||||
package.download_size as i64,
|
||||
package.installed_size as i64
|
||||
package.installed_size as i64,
|
||||
package.checksum
|
||||
])
|
||||
.map(|_| ())
|
||||
}
|
||||
|
||||
+41
-2
@@ -1,9 +1,10 @@
|
||||
use crate::{
|
||||
common::checksum::DEFAULT_HASHER,
|
||||
package::Package,
|
||||
repo::{RepoDb, RepoPackage},
|
||||
repo::{RepoDb, RepoPackage, download::Download},
|
||||
};
|
||||
use std::path::{Path, PathBuf};
|
||||
use url::Url;
|
||||
|
||||
/// A helper type to deal with repository serve directories.
|
||||
#[derive(Debug)]
|
||||
@@ -16,11 +17,49 @@ impl RepoServeDir {
|
||||
pub fn open<P: Into<PathBuf>>(path: P) -> rusqlite::Result<Self> {
|
||||
let path = path.into();
|
||||
Ok(Self {
|
||||
db: RepoDb::open_rw(&path)?,
|
||||
db: RepoDb::open_rw(path.join(RepoDb::FILENAME))?,
|
||||
path,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn clone<P: Into<PathBuf>>(
|
||||
url: &Url,
|
||||
path: P,
|
||||
mut on_event: impl FnMut(Option<String>, Url, u64, u64),
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
let path = path.into();
|
||||
std::fs::create_dir_all(&path)?;
|
||||
|
||||
let repo_db_url = url.join(RepoDb::FILENAME)?;
|
||||
Download::new(repo_db_url.to_string(), path.join(RepoDb::FILENAME))
|
||||
.on_progress(|sum, total| on_event(None, repo_db_url.clone(), sum, total))
|
||||
.run()?;
|
||||
|
||||
let mut db = RepoDb::open_ro(path.join(RepoDb::FILENAME))?;
|
||||
db.for_each_package::<Box<dyn std::error::Error + Send + Sync>>(|pkg| {
|
||||
let pkg_ident = pkg.pkg_manifest.pkg_ident();
|
||||
let standard_filename = format!("{}.pkg", pkg_ident.to_string());
|
||||
let pkgfile_url = url.join(&standard_filename)?;
|
||||
let pkgfile_path = path.join(&standard_filename);
|
||||
if crate::common::checksum::verify_file(&pkgfile_path, &pkg.checksum)
|
||||
.unwrap_or_default()
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
Download::new(pkgfile_url.to_string(), pkgfile_path)
|
||||
.on_progress(|sum, total| {
|
||||
on_event(Some(pkg_ident.to_string()), pkgfile_url.clone(), sum, total)
|
||||
})
|
||||
.run()
|
||||
.map_err::<Box<dyn std::error::Error + Send + Sync>, _>(|e| {
|
||||
Box::from(format!("failed to download \"{pkgfile_url}\": {e}"))
|
||||
})?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Add a package to the repository.
|
||||
pub fn add_package<P: AsRef<Path>>(
|
||||
&mut self,
|
||||
|
||||
Reference in New Issue
Block a user