Skip to content

Commit

Permalink
Merge pull request #167 from JoeHut/jh/api_impl
Browse files Browse the repository at this point in the history
Support releasing of api package from implementing repository
  • Loading branch information
JoeHut authored Nov 28, 2023
2 parents e1b79e1 + 66e321e commit cef7f1f
Show file tree
Hide file tree
Showing 47 changed files with 516 additions and 202 deletions.
4 changes: 2 additions & 2 deletions registry/proto/manifest.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

syntax = "proto3";

import "package.proto";
import "dependency.proto";
import "buffrs/package.proto";
import "buffrs/dependency.proto";

package buffrs.manifest;

Expand Down
2 changes: 1 addition & 1 deletion registry/proto/registry.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

syntax = "proto3";

import "package.proto";
import "buffrs/package.proto";

package buffrs.registry;

Expand Down
14 changes: 13 additions & 1 deletion src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,8 @@ pub async fn package(directory: impl AsRef<Path>, dry_run: bool) -> miette::Resu
let manifest = Manifest::read().await?;
let store = PackageStore::current().await?;

store.populate(&manifest).await?;

let package = store.release(manifest).await?;

if dry_run {
Expand Down Expand Up @@ -223,6 +225,8 @@ pub async fn publish(
let store = PackageStore::current().await?;
let artifactory = Artifactory::new(registry, &credentials)?;

store.populate(&manifest).await?;

let package = store.release(manifest).await?;

if dry_run {
Expand All @@ -240,6 +244,8 @@ pub async fn install() -> miette::Result<()> {
let store = PackageStore::current().await?;
let credentials = Credentials::load().await?;

store.populate(&manifest).await?;

let dependency_graph =
DependencyGraph::from_manifest(&manifest, &lockfile, &credentials.into())
.await
Expand Down Expand Up @@ -317,7 +323,11 @@ pub async fn uninstall() -> miette::Result<()> {
/// Lists all protobuf files managed by Buffrs to stdout
pub async fn list() -> miette::Result<()> {
let store = PackageStore::current().await?;
let protos = store.collect(&store.proto_path(), true).await;
let manifest = Manifest::read().await?;

store.populate(&manifest).await?;

let protos = store.collect(&store.proto_vendor_path()).await;

let cwd = {
let cwd = std::env::current_dir()
Expand Down Expand Up @@ -348,6 +358,8 @@ pub async fn lint() -> miette::Result<()> {
let manifest = Manifest::read().await?;
let store = PackageStore::current().await?;

store.populate(&manifest).await?;

let violations = store.validate(&manifest).await?;

violations
Expand Down
13 changes: 10 additions & 3 deletions src/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,12 @@ impl Generator {
std::env::set_var("PROTOC", protoc.clone());

let store = PackageStore::current().await?;
let protos = store.collect(&store.proto_path(), true).await;
let includes = &[store.proto_path()];
let manifest = Manifest::read().await?;

store.populate(&manifest).await?;

let protos = store.populated_files(&manifest).await;
let includes = &[store.proto_vendor_path()];

match self {
Generator::Tonic => {
Expand Down Expand Up @@ -124,8 +128,11 @@ impl Generator {
pub async fn generate(&self) -> miette::Result<()> {
let manifest = Manifest::read().await?;
let store = PackageStore::current().await?;

store.populate(&manifest).await?;

// Collect non-vendored protos
let protos = store.collect(&store.proto_path(), false).await;
let protos = store.populated_files(&manifest).await;

info!(":: initializing code generator");

Expand Down
77 changes: 64 additions & 13 deletions src/package/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ impl PackageStore {
}

/// Open given directory.
pub async fn open(path: &Path) -> miette::Result<Self> {
async fn open(path: &Path) -> miette::Result<Self> {
let store = Self::new(path.into());

if !store.exists().await? {
Expand All @@ -76,6 +76,12 @@ impl PackageStore {
self.root.join(Self::PROTO_VENDOR_PATH)
}

/// Path to where the package contents are populated.
pub fn populated_path(&self, manifest: &Manifest) -> PathBuf {
self.proto_vendor_path()
.join(manifest.package.name.to_string())
}

/// Creates the expected directory structure for `buffrs`
pub async fn create(path: PathBuf) -> miette::Result<Self> {
let store = PackageStore::new(path);
Expand Down Expand Up @@ -145,10 +151,10 @@ impl PackageStore {
&self,
manifest: &Manifest,
) -> miette::Result<crate::validation::Violations> {
let pkg_path = self.proto_path();
let source_files = self.collect(&pkg_path, false).await;
let root_path = self.proto_vendor_path();
let source_files = self.populated_files(manifest).await;

let mut parser = crate::validation::Validator::new(&pkg_path, &manifest.package.name);
let mut parser = crate::validation::Validator::new(&root_path, &manifest.package.name);

for file in &source_files {
parser.input(file);
Expand Down Expand Up @@ -182,7 +188,7 @@ impl PackageStore {
let pkg_path = self.proto_path();
let mut entries = BTreeMap::new();

for entry in self.collect(&pkg_path, false).await {
for entry in self.populated_files(&manifest).await {
let path = entry.strip_prefix(&pkg_path).into_diagnostic()?;
let contents = tokio::fs::read(&entry).await.unwrap();
entries.insert(path.into(), contents.into());
Expand All @@ -205,18 +211,11 @@ impl PackageStore {
}

/// Collect .proto files in a given path
pub async fn collect(&self, path: &Path, vendored: bool) -> Vec<PathBuf> {
pub async fn collect(&self, path: &Path) -> Vec<PathBuf> {
let mut paths: Vec<_> = WalkDir::new(path)
.into_iter()
.filter_map(Result::ok)
.map(|entry| entry.into_path())
.filter(|path| {
if vendored {
return true;
}

!path.starts_with(self.proto_vendor_path())
})
.filter(|path| {
let ext = path.extension().map(|s| s.to_str());

Expand All @@ -229,6 +228,58 @@ impl PackageStore {

paths
}

/// Sync this stores proto files to the vendor directory
pub async fn populate(&self, manifest: &Manifest) -> miette::Result<()> {
let source_path = self.proto_path();
let target_dir = self
.proto_vendor_path()
.join(manifest.package.name.to_string());

if tokio::fs::try_exists(&target_dir)
.await
.into_diagnostic()
.wrap_err(format!(
"Failed to check whether directory {} still exists",
target_dir.to_str().unwrap()
))?
{
tokio::fs::remove_dir_all(&target_dir)
.await
.into_diagnostic()
.wrap_err(format!(
"Failed to remove directory {} and its contents.",
target_dir.to_str().unwrap()
))?;
}

for entry in self.collect(&source_path).await {
if entry.starts_with(self.proto_vendor_path()) {
continue;
}

let file_name = entry.strip_prefix(&source_path).into_diagnostic()?;
let target_path = target_dir.join(file_name);
tokio::fs::create_dir_all(target_path.parent().unwrap())
.await
.into_diagnostic()
.wrap_err(format!(
"Failed to create directory {} and its parents.",
target_path.parent().unwrap().to_str().unwrap()
))?;

tokio::fs::copy(entry, target_path)
.await
.into_diagnostic()?;
}

Ok(())
}

/// Get the paths of all files under management after population
pub async fn populated_files(&self, manifest: &Manifest) -> Vec<PathBuf> {
self.collect(&self.populated_path(manifest)).await
}
}

#[test]
Expand Down
34 changes: 22 additions & 12 deletions src/validation/data/package.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ use super::*;
pub struct Package {
/// Name of the package.
pub name: String,
/// File path where this package is defined.
pub file: PathBuf,
/// File paths where this package is defined.
pub files: Vec<PathBuf>,
/// Entities defined in this package.
pub entities: BTreeMap<String, Entity>,
}
Expand All @@ -33,12 +33,12 @@ pub struct Package {
#[derive(Error, Debug, Diagnostic)]
#[allow(missing_docs)]
pub enum PackageError {
#[error("duplicate entity {entity} in file {file}")]
#[error("duplicate entity {entity} in package {package}")]
#[diagnostic(
help = "check to make sure your don't define two entities of the same name",
help = "check to make sure you don't define two entities of the same name",
code = "duplicate_entity"
)]
DuplicateEntity { file: PathBuf, entity: String },
DuplicateEntity { package: String, entity: String },

#[error("error parsing message {name}")]
Message {
Expand All @@ -61,13 +61,23 @@ impl Package {
/// Try to create a new one from a [`FileDescriptorProto`].
pub fn new(descriptor: &FileDescriptorProto) -> Result<Self, PackageError> {
let mut package = Self {
file: descriptor.name().into(),
files: vec![descriptor.name().into()],
name: descriptor.package().to_string(),
entities: Default::default(),
};

package.parse(descriptor)?;

Ok(package)
}

pub fn add(&mut self, descriptor: &FileDescriptorProto) {
self.parse(descriptor).unwrap();
}

fn parse(&mut self, descriptor: &FileDescriptorProto) -> Result<&Self, PackageError> {
for message in &descriptor.message_type {
package.add_entity(
self.add_entity(
message.name(),
Message::new(message).map_err(|error| PackageError::Message {
name: message.name().into(),
Expand All @@ -77,7 +87,7 @@ impl Package {
}

for entity in &descriptor.enum_type {
package.add_entity(
self.add_entity(
entity.name(),
Enum::new(entity).map_err(|error| PackageError::Enum {
name: entity.name().into(),
Expand All @@ -87,10 +97,10 @@ impl Package {
}

for entity in &descriptor.service {
package.add_entity(entity.name(), Service {})?;
self.add_entity(entity.name(), Service {})?;
}

Ok(package)
Ok(self)
}

/// Try to add an entity.
Expand All @@ -101,7 +111,7 @@ impl Package {
Ok(())
}
Entry::Occupied(_entry) => Err(PackageError::DuplicateEntity {
file: self.file.clone(),
package: self.name.clone(),
entity: name.into(),
}),
}
Expand All @@ -118,7 +128,7 @@ impl Package {
.flat_map(|(name, entity)| rules.check_entity(name, entity).into_iter()),
)
.map(|mut violation| {
violation.location.file = Some(self.file.display().to_string());
violation.location.file = Some(self.files.last().unwrap().display().to_string());
violation.location.package = Some(self.name.clone());
violation
})
Expand Down
28 changes: 6 additions & 22 deletions src/validation/data/packages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,6 @@ pub struct Packages {
#[derive(Error, Debug, Diagnostic)]
#[allow(missing_docs)]
pub enum PackagesError {
#[error("duplicate package {package}, defined in {previous} and {current}")]
#[diagnostic(
help = "check to make sure your files define different package names",
code = "duplicate_package"
)]
DuplicatePackage {
package: String,
current: PathBuf,
previous: PathBuf,
},

#[error("error parsing package {package} in {file}")]
Package {
package: String,
Expand All @@ -59,17 +48,12 @@ impl Packages {
file: descriptor.name().to_string(),
error,
})?;
match self.packages.entry(name) {
Entry::Vacant(entry) => {
entry.insert(package);
Ok(())
}
Entry::Occupied(entry) => Err(PackagesError::DuplicatePackage {
package: descriptor.package().to_string(),
previous: entry.get().file.clone(),
current: package.file.clone(),
}),
}
self.packages
.entry(name)
.and_modify(|package| package.add(descriptor))
.or_insert(package);

Ok(())
}

/// Run checks against this.
Expand Down
9 changes: 2 additions & 7 deletions src/validation/rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,10 @@ use crate::validation::{
violation::{self, *},
};

mod file_name;
mod ident_casing;
mod package_name;

pub use self::{file_name::*, ident_casing::*, package_name::*};
pub use self::{ident_casing::*, package_name::*};

/// Collection of rules.
pub type RuleSet = Vec<Box<dyn Rule>>;
Expand Down Expand Up @@ -102,9 +101,5 @@ impl Rule for RuleSet {

/// Get default rules for a given `buffrs` package name.
pub fn package_rules(name: &str) -> RuleSet {
vec![
Box::new(PackageName::new(name)),
Box::new(FileName),
Box::new(IdentCasing),
]
vec![Box::new(PackageName::new(name)), Box::new(IdentCasing)]
}
Loading

0 comments on commit cef7f1f

Please sign in to comment.