Skip to content

Commit

Permalink
feat(wkg-core): Adds new wkg-core crate with lockfile support
Browse files Browse the repository at this point in the history
This includes support for an optional config and tests for locking

Signed-off-by: Taylor Thomas <taylor@cosmonic.com>
  • Loading branch information
thomastaylor312 committed Sep 25, 2024
1 parent 4cfec08 commit 71631d3
Show file tree
Hide file tree
Showing 12 changed files with 1,018 additions and 50 deletions.
9 changes: 4 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,13 @@ name: CI
jobs:
run-ci:
name: Run CI
runs-on: ubuntu-latest
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- name: Install dependencies
run: |
ci/get-oras.sh
echo "/tmp/ci-bin" >> $GITHUB_PATH
- name: Run cargo test
run: cargo test --all --workspace
- name: Run cargo clippy
Expand Down
19 changes: 19 additions & 0 deletions Cargo.lock

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

11 changes: 11 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,25 @@ license = "Apache-2.0 WITH LLVM-exception"

[workspace.dependencies]
anyhow = "1"
base64 = "0.22.0"
bytes = "1.6.0"
dirs = "5.0.1"
docker_credential = "1.2.1"
futures-util = "0.3.30"
oci-client = { version = "0.12", default-features = false, features = [
"rustls-tls",
] }
oci-wasm = { version = "0.0.5", default-features = false, features = [
"rustls-tls",
] }
semver = "1.0.23"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1"
sha2 = "0.10"
tempfile = "3.10.1"
thiserror = "1.0"
tokio = "1.35.1"
toml = "0.8.13"
tracing = "0.1.40"
tracing-subscriber = { version = "0.3.18", default-features = false, features = [
"fmt",
Expand Down
15 changes: 0 additions & 15 deletions ci/get-oras.sh

This file was deleted.

20 changes: 10 additions & 10 deletions crates/wasm-pkg-client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,22 @@ readme = "../../README.md"
[dependencies]
anyhow = { workspace = true }
async-trait = "0.1.77"
base64 = "0.22.0"
bytes = "1.5.0"
dirs = "5.0.1"
base64 = { workspace = true }
bytes = { workspace = true }
dirs = { workspace = true }
docker_credential = { workspace = true }
futures-util = { version = "0.3.29", features = ["io"] }
futures-util = { workspace = true, features = ["io"] }
oci-client = { workspace = true }
oci-wasm = { workspace = true }
secrecy = { version = "0.8.0", features = ["serde"] }
serde = { version = "1.0.194", features = ["derive"] }
serde_json = "1.0.110"
sha2 = "0.10.8"
thiserror = "1.0.51"
serde = { workspace = true }
serde_json = { workspace = true }
sha2 = { workspace = true }
thiserror = { workspace = true }
tokio = { workspace = true, features = ["rt", "macros"] }
tokio-util = { version = "0.7.10", features = ["io", "io-util", "codec"] }
toml = "0.8.8"
tracing = "0.1.40"
toml = { workspace = true }
tracing = { workspace = true }
tracing-subscriber = { workspace = true }
url = "2.5.0"
warg-client = "0.9.0"
Expand Down
10 changes: 4 additions & 6 deletions crates/wasm-pkg-client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,19 +45,17 @@ use publisher::PackagePublisher;
use tokio::io::AsyncSeekExt;
use tokio::sync::RwLock;
use tokio_util::io::SyncIoBridge;

use wasm_pkg_common::metadata::RegistryMetadata;
use wit_component::DecodedWasm;

use crate::{loader::PackageLoader, local::LocalBackend, oci::OciBackend, warg::WargBackend};

pub use wasm_pkg_common::{
config::Config,
digest::ContentDigest,
metadata::RegistryMetadata,
package::{PackageRef, Version},
registry::Registry,
Error,
};
use wit_component::DecodedWasm;

use crate::{loader::PackageLoader, local::LocalBackend, oci::OciBackend, warg::WargBackend};

pub use release::{Release, VersionInfo};

Expand Down
20 changes: 10 additions & 10 deletions crates/wasm-pkg-common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ tokio = ["dep:tokio"]

[dependencies]
anyhow = { workspace = true }
bytes = "1.6.0"
dirs = "5.0.1"
futures-util = "0.3.30"
bytes = { workspace = true }
dirs = { workspace = true }
futures-util = { workspace = true }
http = "1.1.0"
reqwest = { version = "0.12.0", default-features = false, features = [
"rustls-tls",
Expand All @@ -25,14 +25,14 @@ reqwest = { version = "0.12.0", default-features = false, features = [
"macos-system-configuration",
"json",
], optional = true }
semver = "1.0.23"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
sha2 = "0.10.8"
semver = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
sha2 = { workspace = true }
tokio = { workspace = true, features = ["io-util", "fs"], optional = true }
toml = "0.8.13"
thiserror = "1.0"
tracing = "0.1"
toml = { workspace = true }
thiserror = { workspace = true }
tracing = { workspace = true }

[dev-dependencies]
tokio = { workspace = true, features = ["macros", "rt"] }
38 changes: 38 additions & 0 deletions crates/wkg-core/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
[package]
name = "wkg-core"
description = "Wasm Package Tools core libraries for wkg"
repository = "https://github.com/bytecodealliance/wasm-pkg-tools/tree/main/crates/wkg-core"
edition.workspace = true
version.workspace = true
authors.workspace = true
license.workspace = true

[dependencies]
anyhow = { workspace = true }
futures-util = { workspace = true }
semver = { workspace = true }
serde = { workspace = true }
tokio = { workspace = true, features = ["macros", "rt"] }
toml = { workspace = true }
tracing = { workspace = true }
wasm-pkg-common = { workspace = true }
wasm-pkg-client = { workspace = true }

[target.'cfg(unix)'.dependencies.libc]
version = "0.2.153"

[target.'cfg(windows)'.dependencies.windows-sys]
version = "0.52"
features = [
"Win32_Foundation",
"Win32_Storage",
"Win32_Storage_FileSystem",
"Win32_System",
"Win32_System_IO",
"Win32_Security",
"Win32_System_Console",
]

[dev-dependencies]
tempfile = { workspace = true }
sha2 = { workspace = true }
137 changes: 137 additions & 0 deletions crates/wkg-core/src/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
//! Type definitions and functions for working with `wkg.toml` files.

use std::{
collections::HashMap,
path::{Path, PathBuf},
};

use anyhow::{Context, Result};
use semver::VersionReq;
use serde::{Deserialize, Serialize};
use tokio::io::AsyncWriteExt;

/// The default name of the configuration file.
pub const CONFIG_FILE_NAME: &str = "wkg.toml";

/// The structure for a wkg.toml configuration file. This file is entirely optional and is used for
/// overriding and annotating wasm packages.
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
pub struct Config {
/// Overrides for various packages
#[serde(default, skip_serializing_if = "Option::is_none")]
pub overrides: Option<HashMap<String, Override>>,
/// Additional metadata about the package. This will override any metadata already set by other
/// tools.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub metadata: Option<Metadata>,
}

impl Config {
/// Loads a configuration file from the given path.
pub async fn load_from_path(path: impl AsRef<Path>) -> Result<Config> {
let contents = tokio::fs::read_to_string(path)
.await
.context("unable to load config from file")?;
let config: Config = toml::from_str(&contents).context("unable to parse config file")?;
Ok(config)
}

/// Attempts to load the configuration from the current directory. Most of the time, users of this
/// crate should use this function. Right now it just checks for a `wkg.toml` file in the current
/// directory, but we could add more resolution logic in the future. If the file is not found, a
/// default empty config is returned.
pub async fn load() -> Result<Config> {
let config_path = PathBuf::from(CONFIG_FILE_NAME);
if !tokio::fs::try_exists(&config_path).await? {
return Ok(Config::default());
}
Self::load_from_path(config_path).await
}

/// Serializes and writes the configuration to the given path.
pub async fn write(&self, path: impl AsRef<Path>) -> Result<()> {
let contents = toml::to_string_pretty(self)?;
let mut file = tokio::fs::File::create(path).await?;
file.write_all(contents.as_bytes())
.await
.context("unable to write config to path")
}
}

#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
pub struct Override {
/// A path to the package on disk. If this is set, the package will be loaded from the given
/// path. If this is not set, the package will be loaded from the registry.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub path: Option<PathBuf>,
/// Overrides the version of a package specified in a world file. This is for advanced use only
/// and may break things.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub version: Option<VersionReq>,
}

#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
pub struct Metadata {
/// The authors of the package.
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub authors: Vec<String>,
/// The categories of the package.
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub categories: Vec<String>,
/// The package description.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
/// The package license.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub license: Option<String>,
/// The package documentation URL.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub documentation: Option<String>,
/// The package homepage URL.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub homepage: Option<String>,
/// The package repository URL.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub repository: Option<String>,
}

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

#[tokio::test]
async fn test_roundtrip() {
let tempdir = tempfile::tempdir().unwrap();
let config_path = tempdir.path().join(CONFIG_FILE_NAME);
let config = Config {
overrides: Some(HashMap::from([(
"foo:bar".to_string(),
Override {
path: Some(PathBuf::from("bar")),
version: Some(VersionReq::parse("1.0.0").unwrap()),
},
)])),
metadata: Some(Metadata {
authors: vec!["foo".to_string(), "bar".to_string()],
categories: vec!["foo".to_string(), "bar".to_string()],
description: Some("foo".to_string()),
license: Some("foo".to_string()),
documentation: Some("foo".to_string()),
homepage: Some("foo".to_string()),
repository: Some("foo".to_string()),
}),
};

config
.write(&config_path)
.await
.expect("unable to write config");
let loaded_config = Config::load_from_path(config_path)
.await
.expect("unable to load config");
assert_eq!(
config, loaded_config,
"config loaded from file does not match original config"
);
}
}
6 changes: 6 additions & 0 deletions crates/wkg-core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
//! A library with reusable helpers and types for the `wkg` CLI. This is intended to be used by
//! other downstream CLI tools that may need to leverage some of the same functionality provided by
//! `wkg`.

pub mod config;
pub mod lock;
Loading

0 comments on commit 71631d3

Please sign in to comment.