Skip to content

Commit

Permalink
Add registry plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
tarkah committed Sep 18, 2023
1 parent c435489 commit 6c86143
Show file tree
Hide file tree
Showing 13 changed files with 409 additions and 114 deletions.
15 changes: 10 additions & 5 deletions moss/src/cli/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use std::path::PathBuf;

use clap::{ArgMatches, Command};
use futures::StreamExt;
use itertools::Itertools;
use thiserror::Error;

Expand All @@ -31,7 +32,7 @@ pub fn command() -> Command {
}

/// Handle listing by filter
pub fn handle(args: &ArgMatches) -> Result<(), Error> {
pub async fn handle(args: &ArgMatches) -> Result<(), Error> {
let root = args.get_one::<PathBuf>("root").unwrap().clone();

let filter_flags = match args.subcommand() {
Expand All @@ -41,15 +42,19 @@ pub fn handle(args: &ArgMatches) -> Result<(), Error> {
};

// Grab a client for the target, enumerate packages
let mut client = Client::new_for_root(root)?;
let pkgs = client.registry().list(filter_flags).collect_vec();
let client = Client::new_for_root(root).await?;
let pkgs = client.registry.list(filter_flags).collect::<Vec<_>>().await;

if pkgs.is_empty() {
return Err(Error::NoneFound);
}

// Print em
for pkg in pkgs {
println!(" - {:?}", pkg);
for pkg in pkgs
.into_iter()
.sorted_by_key(|pkg| pkg.meta.name.to_string())
{
println!(" - {} v{}", pkg.meta.name, pkg.meta.version_identifier);
}

Ok(())
Expand Down
2 changes: 1 addition & 1 deletion moss/src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ pub async fn process() -> Result<(), Error> {
version::print();
Ok(())
}
Some(("list", a)) => list::handle(a).map_err(Error::List),
Some(("list", a)) => list::handle(a).await.map_err(Error::List),
Some(("repo", a)) => repo::handle(a, root).await.map_err(Error::Repo),
_ => unreachable!(),
}
Expand Down
13 changes: 7 additions & 6 deletions moss/src/cli/repo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use std::path::Path;

use clap::{arg, Arg, ArgAction, ArgMatches, Command};
use itertools::Itertools;
use moss::{repository, Installation, Repository};
use thiserror::Error;
use url::Url;
Expand Down Expand Up @@ -86,7 +87,7 @@ async fn add(root: &Path, name: String, uri: Url, comment: String) -> Result<(),
Repository {
description: comment,
uri,
priority: 0,
priority: repository::Priority::new(0),
},
)
.await?;
Expand All @@ -101,15 +102,15 @@ async fn list(root: &Path) -> Result<(), Error> {
let installation = Installation::open(root);
let manager = repository::Manager::new(installation).await?;

let mut configured_repos = manager.list();
if configured_repos.is_empty() {
let configured_repos = manager.list();
if configured_repos.len() == 0 {
println!("No repositories have been configured yet");
return Ok(());
}

configured_repos.sort_by_key(|(_, repo)| repo.priority);

for (id, repo) in configured_repos {
for (id, repo) in
configured_repos.sorted_by(|(_, a), (_, b)| a.priority.cmp(&b.priority).reverse())
{
println!(" - {} = {} [{}]", id, repo.uri, repo.priority);
}

Expand Down
48 changes: 35 additions & 13 deletions moss/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,54 +7,76 @@ use std::path::PathBuf;
use thiserror::Error;

use crate::{
registry::plugin::{self, cobble},
Installation, Registry,
registry::plugin::{self, Plugin},
repository, Installation, Registry,
};

#[derive(Debug, Error)]
pub enum Error {
#[error("Root is invalid")]
RootInvalid,
#[error("repository: {0}")]
Repository(#[from] repository::manager::Error),
}

/// A Client is a connection to the underlying package management systems
pub struct Client {
/// Root that we operate on
installation: Installation,
registry: Registry,
repositories: repository::Manager,
pub registry: Registry,
}

impl Client {
/// Construct a new Client
pub fn new_for_root(root: impl Into<PathBuf>) -> Result<Client, Error> {
pub async fn new_for_root(root: impl Into<PathBuf>) -> Result<Client, Error> {
let root = root.into();

if !root.exists() || !root.is_dir() {
return Err(Error::RootInvalid);
}

let installation = Installation::open(root);
let mut registry = Registry::default();
// TODO: Seed with plugins for the Installation
let repositories = repository::Manager::new(installation.clone()).await?;

let cobble = cobble::Plugin::default();
registry.add_plugin(plugin::Plugin::Cobble(cobble));
let registry = build_registry(&repositories);

Ok(Client {
installation,
repositories,
registry,
})
}

/// Construct a new Client for the global installation
pub fn system() -> Result<Client, Error> {
Client::new_for_root("/")
pub async fn system() -> Result<Client, Error> {
Client::new_for_root("/").await
}

/// Borrow the registry
pub fn registry(&mut self) -> &Registry {
&self.registry
/// Reload all configured repositories and refreshes their index file, then update
/// registry with all active repositories.
pub async fn refresh_repositories(&mut self) -> Result<(), Error> {
// Reload manager and refresh all repositories
self.repositories = repository::Manager::new(self.installation.clone()).await?;
self.repositories.refresh_all().await?;

// Rebuild registry
self.registry = build_registry(&self.repositories);

Ok(())
}
}

fn build_registry(repositories: &repository::Manager) -> Registry {
let mut registry = Registry::default();

registry.add_plugin(Plugin::Cobble(plugin::Cobble::default()));

for repo in repositories.active() {
registry.add_plugin(Plugin::Repository(plugin::Repository::new(repo)));
}

registry
}

impl Drop for Client {
Expand Down
118 changes: 113 additions & 5 deletions moss/src/db/meta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,99 @@ impl Database {
Ok(())
}

// TODO: Replace with specialized query interfaces
pub async fn all(&self) -> Result<Vec<(package::Id, Meta)>, Error> {
let entry_query = sqlx::query_as::<_, encoding::Entry>(
"
SELECT package,
name,
version_identifier,
source_release,
build_release,
architecture,
summary,
description,
source_id,
homepage,
uri,
hash,
download_size
FROM meta;
",
);

let licenses_query = sqlx::query_as::<_, encoding::License>(
"
SELECT package, license
FROM meta_licenses;
",
);

let dependencies_query = sqlx::query_as::<_, encoding::Dependency>(
"
SELECT package, dependency
FROM meta_dependencies;
",
);

let providers_query = sqlx::query_as::<_, encoding::Provider>(
"
SELECT package, provider
FROM meta_providers;
",
);

let (entries, licenses, dependencies, providers) = futures::try_join!(
entry_query.fetch_all(&self.pool),
licenses_query.fetch_all(&self.pool),
dependencies_query.fetch_all(&self.pool),
providers_query.fetch_all(&self.pool),
)?;

Ok(entries
.into_iter()
.map(|entry| {
(
entry.id.0.clone(),
Meta {
name: entry.name.0,
version_identifier: entry.version_identifier,
source_release: entry.source_release as u64,
build_release: entry.build_release as u64,
architecture: entry.architecture,
summary: entry.summary,
description: entry.description,
source_id: entry.source_id,
homepage: entry.homepage,
licenses: licenses
.iter()
.filter(|l| l.id.0 == entry.id.0)
.map(|l| l.license.clone())
.collect(),
dependencies: dependencies
.iter()
.filter(|l| l.id.0 == entry.id.0)
.map(|d| d.dependency.0.clone())
.collect(),
providers: providers
.iter()
.filter(|l| l.id.0 == entry.id.0)
.map(|p| p.provider.0.clone())
.collect(),
uri: entry.uri,
hash: entry.hash,
download_size: entry.download_size.map(|i| i as u64),
},
)
})
.collect())
}

pub async fn get(&self, package: &package::Id) -> Result<Meta, Error> {
let entry_query = sqlx::query_as::<_, encoding::Entry>(
"
SELECT name,
SELECT package,
name,
version_identifier,
source_release,
build_release,
Expand All @@ -64,7 +153,7 @@ impl Database {

let licenses_query = sqlx::query_as::<_, encoding::License>(
"
SELECT license
SELECT package, license
FROM meta_licenses
WHERE package = ?;
",
Expand All @@ -73,7 +162,7 @@ impl Database {

let dependencies_query = sqlx::query_as::<_, encoding::Dependency>(
"
SELECT dependency
SELECT package, dependency
FROM meta_dependencies
WHERE package = ?;
",
Expand All @@ -82,7 +171,7 @@ impl Database {

let providers_query = sqlx::query_as::<_, encoding::Provider>(
"
SELECT provider
SELECT package, provider
FROM meta_providers
WHERE package = ?;
",
Expand Down Expand Up @@ -245,12 +334,23 @@ async fn remove(package: package::Id, connection: &mut SqliteConnection) -> Resu

#[derive(Debug, Error)]
pub enum Error {
#[error("row not found")]
RowNotFound,
#[error("database error: {0}")]
Sqlx(#[from] sqlx::Error),
Sqlx(sqlx::Error),
#[error("migration error: {0}")]
Migrate(#[from] sqlx::migrate::MigrateError),
}

impl From<sqlx::Error> for Error {
fn from(error: sqlx::Error) -> Self {
match error {
sqlx::Error::RowNotFound => Error::RowNotFound,
error => Error::Sqlx(error),
}
}
}

mod encoding {
use sqlx::FromRow;

Expand All @@ -259,6 +359,8 @@ mod encoding {

#[derive(FromRow)]
pub struct Entry {
#[sqlx(rename = "package")]
pub id: Decoder<package::Id>,
pub name: Decoder<package::Name>,
pub version_identifier: String,
pub source_release: i64,
Expand All @@ -275,16 +377,22 @@ mod encoding {

#[derive(FromRow)]
pub struct License {
#[sqlx(rename = "package")]
pub id: Decoder<package::Id>,
pub license: String,
}

#[derive(FromRow)]
pub struct Dependency {
#[sqlx(rename = "package")]
pub id: Decoder<package::Id>,
pub dependency: Decoder<crate::Dependency>,
}

#[derive(FromRow)]
pub struct Provider {
#[sqlx(rename = "package")]
pub id: Decoder<package::Id>,
pub provider: Decoder<crate::Provider>,
}

Expand Down
6 changes: 6 additions & 0 deletions moss/src/package/meta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ impl From<Name> for String {
}
}

impl fmt::Display for Name {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}

/// The metadata of a [`Package`]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Meta {
Expand Down
Loading

0 comments on commit 6c86143

Please sign in to comment.