refactor(registry): store index files as btreemaps

This commit is contained in:
daimond113 2024-03-16 22:34:39 +01:00
parent 118174d4ba
commit 7782a7537c
No known key found for this signature in database
GPG key ID: 3A8ECE51328B513C
5 changed files with 39 additions and 51 deletions

View file

@ -1,6 +1,6 @@
[package] [package]
name = "pesde-registry" name = "pesde-registry"
version = "0.4.0" version = "0.5.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
@ -28,4 +28,3 @@ pretty_env_logger = "0.5.0"
sentry = "0.32.2" sentry = "0.32.2"
sentry-log = "0.32.2" sentry-log = "0.32.2"
sentry-actix = "0.32.2" sentry-actix = "0.32.2"
chrono = "0.4.34"

View file

@ -1,6 +1,5 @@
use actix_multipart::form::{bytes::Bytes, MultipartForm}; use actix_multipart::form::{bytes::Bytes, MultipartForm};
use actix_web::{web, HttpResponse, Responder}; use actix_web::{web, HttpResponse, Responder};
use chrono::Utc;
use flate2::read::GzDecoder; use flate2::read::GzDecoder;
use log::error; use log::error;
use reqwest::StatusCode; use reqwest::StatusCode;
@ -80,7 +79,7 @@ pub async fn create_package(
let (scope, name) = manifest.name.parts(); let (scope, name) = manifest.name.parts();
{ let entry = {
let mut index = app_state.index.lock().unwrap(); let mut index = app_state.index.lock().unwrap();
let config = index.config()?; let config = index.config()?;
@ -103,9 +102,16 @@ pub async fn create_package(
}; };
} }
let success = index.create_package_version(&manifest, &user_id.0)?; match index.create_package_version(&manifest, &user_id.0)? {
Some(entry) => {
index.commit_and_push(
&format!("Add version {}@{}", manifest.name, manifest.version),
&commit_signature(),
)?;
if !success { entry
}
None => {
return Ok(HttpResponse::BadRequest().json(errors::ErrorResponse { return Ok(HttpResponse::BadRequest().json(errors::ErrorResponse {
error: format!( error: format!(
"Version {} of {} already exists", "Version {} of {} already exists",
@ -113,12 +119,8 @@ pub async fn create_package(
), ),
})); }));
} }
index.commit_and_push(
&format!("Add version {}@{}", manifest.name, manifest.version),
&commit_signature(),
)?;
} }
};
{ {
let mut search_writer = app_state.search_writer.lock().unwrap(); let mut search_writer = app_state.search_writer.lock().unwrap();
@ -135,7 +137,7 @@ pub async fn create_package(
name_field => manifest.name.to_string(), name_field => manifest.name.to_string(),
schema.get_field("version").unwrap() => manifest.version.to_string(), schema.get_field("version").unwrap() => manifest.version.to_string(),
schema.get_field("description").unwrap() => manifest.description.unwrap_or_default(), schema.get_field("description").unwrap() => manifest.description.unwrap_or_default(),
schema.get_field("published_at").unwrap() => DateTime::from_timestamp_secs(Utc::now().timestamp()), schema.get_field("published_at").unwrap() => DateTime::from_timestamp_secs(entry.published_at.timestamp())
) )
).unwrap(); ).unwrap();
@ -146,7 +148,7 @@ pub async fn create_package(
.s3_bucket .s3_bucket
.put_object( .put_object(
Some(&app_state.s3_credentials), Some(&app_state.s3_credentials),
&*format!("{scope}-{name}-{}.tar.gz", manifest.version), &format!("{scope}-{name}-{}.tar.gz", manifest.version),
) )
.sign(S3_EXPIRY); .sign(S3_EXPIRY);
@ -173,16 +175,13 @@ pub async fn get_package_version(
Some(package) => { Some(package) => {
if version == "latest" { if version == "latest" {
version = package version = package
.iter() .last()
.max_by(|a, b| a.version.cmp(&b.version))
.map(|v| v.version.to_string()) .map(|v| v.version.to_string())
.unwrap(); .unwrap();
} else { } else if !package.iter().any(|v| v.version.to_string() == version) {
if !package.iter().any(|v| v.version.to_string() == version) {
return Ok(HttpResponse::NotFound().finish()); return Ok(HttpResponse::NotFound().finish());
} }
} }
}
None => return Ok(HttpResponse::NotFound().finish()), None => return Ok(HttpResponse::NotFound().finish()),
} }
} }
@ -191,7 +190,7 @@ pub async fn get_package_version(
.s3_bucket .s3_bucket
.get_object( .get_object(
Some(&app_state.s3_credentials), Some(&app_state.s3_credentials),
&*format!("{scope}-{name}-{version}.tar.gz"), &format!("{scope}-{name}-{version}.tar.gz"),
) )
.sign(S3_EXPIRY); .sign(S3_EXPIRY);

View file

@ -27,11 +27,11 @@ pub async fn search_packages(
let query = query.query.as_deref().unwrap_or_default().trim(); let query = query.query.as_deref().unwrap_or_default().trim();
let query_parser = let query_parser =
tantivy::query::QueryParser::for_index(&searcher.index(), vec![name, description]); tantivy::query::QueryParser::for_index(searcher.index(), vec![name, description]);
let query = if query.is_empty() { let query = if query.is_empty() {
Box::new(AllQuery) Box::new(AllQuery)
} else { } else {
query_parser.parse_query(&query)? query_parser.parse_query(query)?
}; };
let top_docs: Vec<(DateTime, DocAddress)> = searcher let top_docs: Vec<(DateTime, DocAddress)> = searcher
@ -52,26 +52,20 @@ pub async fn search_packages(
let retrieved_doc = searcher.doc(doc_address).unwrap(); let retrieved_doc = searcher.doc(doc_address).unwrap();
let name: PackageName = retrieved_doc let name: PackageName = retrieved_doc
.get_first(name) .get_first(name)
.unwrap() .and_then(|v| v.as_text())
.as_text() .and_then(|v| v.parse().ok())
.unwrap()
.parse()
.unwrap(); .unwrap();
let version: Version = retrieved_doc let version: Version = retrieved_doc
.get_first(version) .get_first(version)
.unwrap() .and_then(|v| v.as_text())
.as_text() .and_then(|v| v.parse().ok())
.unwrap()
.parse()
.unwrap(); .unwrap();
let entry = index let entry = index
.package(&name) .package(&name)
.unwrap() .unwrap()
.unwrap() .and_then(|v| v.into_iter().find(|v| v.version == version))
.into_iter()
.find(|v| v.version == version)
.unwrap(); .unwrap();
json!({ json!({

View file

@ -57,13 +57,13 @@ impl ResponseError for Errors {
match self { match self {
Errors::UserYaml(err) => HttpResponse::BadRequest().json(ErrorResponse { Errors::UserYaml(err) => HttpResponse::BadRequest().json(ErrorResponse {
error: format!("Error parsing YAML file: {}", err.to_string()), error: format!("Error parsing YAML file: {err}"),
}), }),
Errors::PackageName(err) => HttpResponse::BadRequest().json(ErrorResponse { Errors::PackageName(err) => HttpResponse::BadRequest().json(ErrorResponse {
error: format!("Invalid package name: {}", err.to_string()), error: format!("Invalid package name: {err}"),
}), }),
Errors::QueryParser(err) => HttpResponse::BadRequest().json(ErrorResponse { Errors::QueryParser(err) => HttpResponse::BadRequest().json(ErrorResponse {
error: format!("Error parsing query: {}", err.to_string()), error: format!("Error parsing query: {err}"),
}), }),
_ => HttpResponse::InternalServerError().finish(), _ => HttpResponse::InternalServerError().finish(),
} }

View file

@ -141,11 +141,11 @@ fn search_index(index: &GitIndex) -> (IndexReader, IndexWriter) {
let entry = entry.unwrap(); let entry = entry.unwrap();
let path = entry.path(); let path = entry.path();
if !path.is_dir() || path.file_name().unwrap() == ".git" { if !path.is_dir() || path.file_name().is_some_and(|v| v == ".git") {
continue; continue;
} }
let scope = path.file_name().unwrap().to_str().unwrap(); let scope = path.file_name().and_then(|v| v.to_str()).unwrap();
for entry in read_dir(&path).unwrap() { for entry in read_dir(&path).unwrap() {
let entry = entry.unwrap(); let entry = entry.unwrap();
@ -155,16 +155,12 @@ fn search_index(index: &GitIndex) -> (IndexReader, IndexWriter) {
continue; continue;
} }
let package = path.file_name().unwrap().to_str().unwrap(); let package = path.file_name().and_then(|v| v.to_str()).unwrap();
let package_name = PackageName::new(scope, package).unwrap(); let package_name = PackageName::new(scope, package).unwrap();
let entries: IndexFile = let entries: IndexFile =
serde_yaml::from_slice(&std::fs::read(&path).unwrap()).unwrap(); serde_yaml::from_slice(&std::fs::read(&path).unwrap()).unwrap();
let entry = entries let entry = entries.last().unwrap().clone();
.iter()
.max_by(|a, b| a.version.cmp(&b.version))
.unwrap()
.clone();
search_writer search_writer
.add_document(doc!( .add_document(doc!(