mirror of
https://github.com/pesde-pkg/pesde.git
synced 2025-04-19 03:13:51 +01:00
refactor: specify many new clippy lints
Adds quite a lot of Clippy lints which fit with my personal taste for how pesde's codebase should look like. Stylistic lints are mostly warns, and behavioural lints are mostly denied.
This commit is contained in:
parent
7520e8e8fc
commit
ff5c2e5d61
72 changed files with 657 additions and 431 deletions
144
Cargo.toml
144
Cargo.toml
|
@ -42,7 +42,151 @@ path = "src/main.rs"
|
||||||
required-features = ["bin"]
|
required-features = ["bin"]
|
||||||
|
|
||||||
[workspace.lints.clippy]
|
[workspace.lints.clippy]
|
||||||
|
zero_sized_map_values = "warn"
|
||||||
|
while_float = "deny"
|
||||||
|
useless_let_if_seq = "warn"
|
||||||
|
unused_trait_names = "warn"
|
||||||
|
unused_result_ok = "warn"
|
||||||
|
unused_peekable = "warn"
|
||||||
|
unused_async = "warn"
|
||||||
|
unreadable_literal = "warn"
|
||||||
|
unnested_or_patterns = "warn"
|
||||||
|
unneeded_field_pattern = "warn"
|
||||||
|
unnecessary_wraps = "warn"
|
||||||
|
unnecessary_semicolon = "warn"
|
||||||
|
unnecessary_self_imports = "warn"
|
||||||
|
unnecessary_literal_bound = "warn"
|
||||||
|
unnecessary_join = "warn"
|
||||||
|
unnecessary_box_returns = "warn"
|
||||||
uninlined_format_args = "warn"
|
uninlined_format_args = "warn"
|
||||||
|
type_repetition_in_bounds = "warn"
|
||||||
|
try_err = "warn"
|
||||||
|
trivially_copy_pass_by_ref = "warn"
|
||||||
|
trait_duplication_in_bounds = "warn"
|
||||||
|
todo = "deny"
|
||||||
|
suspicious_operation_groupings = "warn"
|
||||||
|
suboptimal_flops = "deny"
|
||||||
|
struct_field_names = "warn"
|
||||||
|
string_to_string = "warn"
|
||||||
|
string_lit_chars_any = "warn"
|
||||||
|
string_lit_as_bytes = "warn"
|
||||||
|
str_split_at_newline = "warn"
|
||||||
|
stable_sort_primitive = "warn"
|
||||||
|
single_option_map = "warn"
|
||||||
|
single_match_else = "warn"
|
||||||
|
single_char_pattern = "warn"
|
||||||
|
significant_drop_tightening = "warn"
|
||||||
|
significant_drop_in_scrutinee = "warn"
|
||||||
|
set_contains_or_insert = "deny"
|
||||||
|
separated_literal_suffix = "warn"
|
||||||
|
semicolon_inside_block = "warn"
|
||||||
|
semicolon_if_nothing_returned = "warn"
|
||||||
|
self_named_module_files = "warn"
|
||||||
|
same_functions_in_if_condition = "warn"
|
||||||
|
return_and_then = "warn"
|
||||||
|
renamed_function_params = "warn"
|
||||||
|
ref_patterns = "deny"
|
||||||
|
ref_option = "deny"
|
||||||
|
ref_binding_to_reference = "deny"
|
||||||
|
redundant_type_annotations = "deny"
|
||||||
|
redundant_else = "warn"
|
||||||
|
redundant_closure_for_method_calls = "warn"
|
||||||
|
redundant_clone = "deny"
|
||||||
|
read_zero_byte_vec = "warn"
|
||||||
|
rc_buffer = "deny"
|
||||||
|
range_plus_one = "deny"
|
||||||
|
range_minus_one = "deny"
|
||||||
|
pub_without_shorthand = "deny"
|
||||||
|
pub_underscore_fields = "deny"
|
||||||
|
precedence_bits = "deny"
|
||||||
|
pathbuf_init_then_push = "warn"
|
||||||
|
path_buf_push_overwrite = "warn"
|
||||||
|
option_option = "deny"
|
||||||
|
option_as_ref_cloned = "deny"
|
||||||
|
nonstandard_macro_braces = "deny"
|
||||||
|
non_zero_suggestions = "deny"
|
||||||
|
no_effect_underscore_binding = "warn"
|
||||||
|
needless_raw_string_hashes = "warn"
|
||||||
|
needless_pass_by_value = "deny"
|
||||||
|
needless_pass_by_ref_mut = "warn"
|
||||||
|
needless_for_each = "deny"
|
||||||
|
needless_continue = "deny"
|
||||||
|
needless_collect = "deny"
|
||||||
|
needless_bitwise_bool = "deny"
|
||||||
|
mut_mut = "deny"
|
||||||
|
must_use_candidate = "warn"
|
||||||
|
mem_forget = "deny"
|
||||||
|
maybe_infinite_iter = "deny"
|
||||||
|
match_wildcard_for_single_variants = "deny"
|
||||||
|
match_bool = "warn"
|
||||||
|
map_unwrap_or = "warn"
|
||||||
|
map_err_ignore = "warn"
|
||||||
|
manual_midpoint = "warn"
|
||||||
|
manual_let_else = "warn"
|
||||||
|
manual_is_variant_and = "warn"
|
||||||
|
manual_is_power_of_two = "warn"
|
||||||
|
lossy_float_literal = "deny"
|
||||||
|
literal_string_with_formatting_args = "warn"
|
||||||
|
large_types_passed_by_value = "warn"
|
||||||
|
large_stack_frames = "warn"
|
||||||
|
large_stack_arrays = "warn"
|
||||||
|
large_digit_groups = "deny"
|
||||||
|
iter_with_drain = "deny"
|
||||||
|
iter_on_single_items = "deny"
|
||||||
|
iter_on_empty_collections = "deny"
|
||||||
|
iter_filter_is_some = "deny"
|
||||||
|
iter_filter_is_ok = "deny"
|
||||||
|
invalid_upcast_comparisons = "deny"
|
||||||
|
integer_division = "deny"
|
||||||
|
infinite_loop = "deny"
|
||||||
|
inefficient_to_string = "warn"
|
||||||
|
index_refutable_slice = "deny"
|
||||||
|
inconsistent_struct_constructor = "warn"
|
||||||
|
imprecise_flops = "deny"
|
||||||
|
implicit_clone = "warn"
|
||||||
|
if_then_some_else_none = "warn"
|
||||||
|
if_not_else = "warn"
|
||||||
|
get_unwrap = "warn"
|
||||||
|
from_iter_instead_of_collect = "warn"
|
||||||
|
format_push_string = "warn"
|
||||||
|
format_collect = "warn"
|
||||||
|
fn_to_numeric_cast_any = "deny"
|
||||||
|
float_cmp_const = "deny"
|
||||||
|
float_cmp = "deny"
|
||||||
|
float_arithmetic = "warn"
|
||||||
|
flat_map_option = "warn"
|
||||||
|
filter_map_next = "warn"
|
||||||
|
filetype_is_file = "deny"
|
||||||
|
explicit_iter_loop = "warn"
|
||||||
|
explicit_into_iter_loop = "warn"
|
||||||
|
explicit_deref_methods = "warn"
|
||||||
|
equatable_if_let = "warn"
|
||||||
|
enum_glob_use = "warn"
|
||||||
|
empty_structs_with_brackets = "warn"
|
||||||
|
empty_enum_variants_with_brackets = "warn"
|
||||||
|
empty_drop = "warn"
|
||||||
|
elidable_lifetime_names = "warn"
|
||||||
|
doc_link_with_quotes = "warn"
|
||||||
|
doc_link_code = "warn"
|
||||||
|
doc_include_without_cfg = "warn"
|
||||||
|
disallowed_script_idents = "warn"
|
||||||
|
derive_partial_eq_without_eq = "warn"
|
||||||
|
deref_by_slicing = "warn"
|
||||||
|
default_numeric_fallback = "warn"
|
||||||
|
dbg_macro = "deny"
|
||||||
|
comparison_chain = "warn"
|
||||||
|
collection_is_never_read = "warn"
|
||||||
|
cloned_instead_of_copied = "warn"
|
||||||
|
clear_with_drain = "warn"
|
||||||
|
cfg_not_test = "warn"
|
||||||
|
cast_sign_loss = "deny"
|
||||||
|
cast_precision_loss = "deny"
|
||||||
|
cast_possible_wrap = "deny"
|
||||||
|
case_sensitive_file_extension_comparisons = "warn"
|
||||||
|
branches_sharing_code = "warn"
|
||||||
|
bool_to_int_with_if = "warn"
|
||||||
|
assigning_clones = "warn"
|
||||||
|
as_underscore = "warn"
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
1
clippy.toml
Normal file
1
clippy.toml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
avoid-breaking-exported-api = false
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
auth::{get_token_from_req, AuthImpl, UserId},
|
auth::{get_token_from_req, AuthImpl, UserId},
|
||||||
error::{display_error, ReqwestErrorExt},
|
error::{display_error, ReqwestErrorExt as _},
|
||||||
};
|
};
|
||||||
use actix_web::{dev::ServiceRequest, Error as ActixError};
|
use actix_web::{dev::ServiceRequest, Error as ActixError};
|
||||||
use reqwest::StatusCode;
|
use reqwest::StatusCode;
|
||||||
|
@ -21,9 +21,8 @@ struct TokenRequestBody {
|
||||||
|
|
||||||
impl AuthImpl for GitHubAuth {
|
impl AuthImpl for GitHubAuth {
|
||||||
async fn for_write_request(&self, req: &ServiceRequest) -> Result<Option<UserId>, ActixError> {
|
async fn for_write_request(&self, req: &ServiceRequest) -> Result<Option<UserId>, ActixError> {
|
||||||
let token = match get_token_from_req(req) {
|
let Some(token) = get_token_from_req(req) else {
|
||||||
Some(token) => token,
|
return Ok(None);
|
||||||
None => return Ok(None),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let response = match self
|
let response = match self
|
||||||
|
|
|
@ -11,11 +11,11 @@ use actix_web::{
|
||||||
error::Error as ActixError,
|
error::Error as ActixError,
|
||||||
http::header::AUTHORIZATION,
|
http::header::AUTHORIZATION,
|
||||||
middleware::Next,
|
middleware::Next,
|
||||||
web, HttpMessage, HttpResponse,
|
web, HttpMessage as _, HttpResponse,
|
||||||
};
|
};
|
||||||
use pesde::source::pesde::IndexConfig;
|
use pesde::source::pesde::IndexConfig;
|
||||||
use sentry::add_breadcrumb;
|
use sentry::add_breadcrumb;
|
||||||
use sha2::{Digest, Sha256};
|
use sha2::{Digest as _, Sha256};
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Hash, PartialOrd, PartialEq, Eq, Ord)]
|
#[derive(Debug, Copy, Clone, Hash, PartialOrd, PartialEq, Eq, Ord)]
|
||||||
|
@ -106,13 +106,10 @@ pub async fn write_mw(
|
||||||
req: ServiceRequest,
|
req: ServiceRequest,
|
||||||
next: Next<impl MessageBody + 'static>,
|
next: Next<impl MessageBody + 'static>,
|
||||||
) -> Result<ServiceResponse<impl MessageBody>, ActixError> {
|
) -> Result<ServiceResponse<impl MessageBody>, ActixError> {
|
||||||
let user_id = match app_state.auth.for_write_request(&req).await? {
|
let Some(user_id) = app_state.auth.for_write_request(&req).await? else {
|
||||||
Some(user_id) => user_id,
|
return Ok(req
|
||||||
None => {
|
.into_response(HttpResponse::Unauthorized().finish())
|
||||||
return Ok(req
|
.map_into_right_body());
|
||||||
.into_response(HttpResponse::Unauthorized().finish())
|
|
||||||
.map_into_right_body())
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
add_breadcrumb(sentry::Breadcrumb {
|
add_breadcrumb(sentry::Breadcrumb {
|
||||||
|
@ -124,7 +121,9 @@ pub async fn write_mw(
|
||||||
|
|
||||||
req.extensions_mut().insert(user_id);
|
req.extensions_mut().insert(user_id);
|
||||||
|
|
||||||
next.call(req).await.map(|res| res.map_into_left_body())
|
next.call(req)
|
||||||
|
.await
|
||||||
|
.map(ServiceResponse::map_into_left_body)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn read_mw(
|
pub async fn read_mw(
|
||||||
|
@ -133,13 +132,10 @@ pub async fn read_mw(
|
||||||
next: Next<impl MessageBody + 'static>,
|
next: Next<impl MessageBody + 'static>,
|
||||||
) -> Result<ServiceResponse<impl MessageBody>, ActixError> {
|
) -> Result<ServiceResponse<impl MessageBody>, ActixError> {
|
||||||
if app_state.auth.read_needs_auth() {
|
if app_state.auth.read_needs_auth() {
|
||||||
let user_id = match app_state.auth.for_read_request(&req).await? {
|
let Some(user_id) = app_state.auth.for_read_request(&req).await? else {
|
||||||
Some(user_id) => user_id,
|
return Ok(req
|
||||||
None => {
|
.into_response(HttpResponse::Unauthorized().finish())
|
||||||
return Ok(req
|
.map_into_right_body());
|
||||||
.into_response(HttpResponse::Unauthorized().finish())
|
|
||||||
.map_into_right_body())
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
add_breadcrumb(sentry::Breadcrumb {
|
add_breadcrumb(sentry::Breadcrumb {
|
||||||
|
@ -154,7 +150,9 @@ pub async fn read_mw(
|
||||||
req.extensions_mut().insert(None::<UserId>);
|
req.extensions_mut().insert(None::<UserId>);
|
||||||
}
|
}
|
||||||
|
|
||||||
next.call(req).await.map(|res| res.map_into_left_body())
|
next.call(req)
|
||||||
|
.await
|
||||||
|
.map(ServiceResponse::map_into_left_body)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_auth_from_env(config: &IndexConfig) -> Auth {
|
pub fn get_auth_from_env(config: &IndexConfig) -> Auth {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::auth::{get_token_from_req, AuthImpl, UserId};
|
use crate::auth::{get_token_from_req, AuthImpl, UserId};
|
||||||
use actix_web::{dev::ServiceRequest, Error as ActixError};
|
use actix_web::{dev::ServiceRequest, Error as ActixError};
|
||||||
use constant_time_eq::constant_time_eq_32;
|
use constant_time_eq::constant_time_eq_32;
|
||||||
use sha2::{Digest, Sha256};
|
use sha2::{Digest as _, Sha256};
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -12,33 +12,23 @@ pub struct RwTokenAuth {
|
||||||
|
|
||||||
impl AuthImpl for RwTokenAuth {
|
impl AuthImpl for RwTokenAuth {
|
||||||
async fn for_write_request(&self, req: &ServiceRequest) -> Result<Option<UserId>, ActixError> {
|
async fn for_write_request(&self, req: &ServiceRequest) -> Result<Option<UserId>, ActixError> {
|
||||||
let token = match get_token_from_req(req) {
|
let Some(token) = get_token_from_req(req) else {
|
||||||
Some(token) => token,
|
return Ok(None);
|
||||||
None => return Ok(None),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let token: [u8; 32] = Sha256::digest(token.as_bytes()).into();
|
let token: [u8; 32] = Sha256::digest(token.as_bytes()).into();
|
||||||
|
|
||||||
Ok(if constant_time_eq_32(&self.write_token, &token) {
|
Ok(constant_time_eq_32(&self.write_token, &token).then_some(UserId::DEFAULT))
|
||||||
Some(UserId::DEFAULT)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn for_read_request(&self, req: &ServiceRequest) -> Result<Option<UserId>, ActixError> {
|
async fn for_read_request(&self, req: &ServiceRequest) -> Result<Option<UserId>, ActixError> {
|
||||||
let token = match get_token_from_req(req) {
|
let Some(token) = get_token_from_req(req) else {
|
||||||
Some(token) => token,
|
return Ok(None);
|
||||||
None => return Ok(None),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let token: [u8; 32] = Sha256::digest(token.as_bytes()).into();
|
let token: [u8; 32] = Sha256::digest(token.as_bytes()).into();
|
||||||
|
|
||||||
Ok(if constant_time_eq_32(&self.read_token, &token) {
|
Ok(constant_time_eq_32(&self.read_token, &token).then_some(UserId::DEFAULT))
|
||||||
Some(UserId::DEFAULT)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_needs_auth(&self) -> bool {
|
fn read_needs_auth(&self) -> bool {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::auth::{get_token_from_req, AuthImpl, UserId};
|
use crate::auth::{get_token_from_req, AuthImpl, UserId};
|
||||||
use actix_web::{dev::ServiceRequest, Error as ActixError};
|
use actix_web::{dev::ServiceRequest, Error as ActixError};
|
||||||
use constant_time_eq::constant_time_eq_32;
|
use constant_time_eq::constant_time_eq_32;
|
||||||
use sha2::{Digest, Sha256};
|
use sha2::{Digest as _, Sha256};
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -12,18 +12,13 @@ pub struct TokenAuth {
|
||||||
|
|
||||||
impl AuthImpl for TokenAuth {
|
impl AuthImpl for TokenAuth {
|
||||||
async fn for_write_request(&self, req: &ServiceRequest) -> Result<Option<UserId>, ActixError> {
|
async fn for_write_request(&self, req: &ServiceRequest) -> Result<Option<UserId>, ActixError> {
|
||||||
let token = match get_token_from_req(req) {
|
let Some(token) = get_token_from_req(req) else {
|
||||||
Some(token) => token,
|
return Ok(None);
|
||||||
None => return Ok(None),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let token: [u8; 32] = Sha256::digest(token.as_bytes()).into();
|
let token: [u8; 32] = Sha256::digest(token.as_bytes()).into();
|
||||||
|
|
||||||
Ok(if constant_time_eq_32(&self.token, &token) {
|
Ok(constant_time_eq_32(&self.token, &token).then_some(UserId::DEFAULT))
|
||||||
Some(UserId::DEFAULT)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ use crate::{
|
||||||
error::RegistryError,
|
error::RegistryError,
|
||||||
package::read_package,
|
package::read_package,
|
||||||
request_path::{resolve_version_and_target, AnyOrSpecificTarget, LatestOrSpecificVersion},
|
request_path::{resolve_version_and_target, AnyOrSpecificTarget, LatestOrSpecificVersion},
|
||||||
storage::StorageImpl,
|
storage::StorageImpl as _,
|
||||||
AppState,
|
AppState,
|
||||||
};
|
};
|
||||||
use pesde::names::PackageName;
|
use pesde::names::PackageName;
|
||||||
|
@ -19,7 +19,7 @@ pub async fn get_package_archive(
|
||||||
return Ok(HttpResponse::NotFound().finish());
|
return Ok(HttpResponse::NotFound().finish());
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(v_id) = resolve_version_and_target(&file, version, target) else {
|
let Some(v_id) = resolve_version_and_target(&file, version, &target) else {
|
||||||
return Ok(HttpResponse::NotFound().finish());
|
return Ok(HttpResponse::NotFound().finish());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ use crate::{
|
||||||
error::RegistryError,
|
error::RegistryError,
|
||||||
package::read_package,
|
package::read_package,
|
||||||
request_path::{resolve_version_and_target, AnyOrSpecificTarget, LatestOrSpecificVersion},
|
request_path::{resolve_version_and_target, AnyOrSpecificTarget, LatestOrSpecificVersion},
|
||||||
storage::StorageImpl,
|
storage::StorageImpl as _,
|
||||||
AppState,
|
AppState,
|
||||||
};
|
};
|
||||||
use actix_web::{web, HttpResponse};
|
use actix_web::{web, HttpResponse};
|
||||||
|
@ -29,10 +29,10 @@ pub fn find_package_doc<'a>(
|
||||||
match doc {
|
match doc {
|
||||||
DocEntryKind::Page { name, hash } if name == doc_name => return Some(hash.as_str()),
|
DocEntryKind::Page { name, hash } if name == doc_name => return Some(hash.as_str()),
|
||||||
DocEntryKind::Category { items, .. } => {
|
DocEntryKind::Category { items, .. } => {
|
||||||
queue.extend(items.iter().map(|item| &item.kind))
|
queue.extend(items.iter().map(|item| &item.kind));
|
||||||
}
|
}
|
||||||
_ => continue,
|
DocEntryKind::Page { .. } => {}
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
|
@ -54,7 +54,7 @@ pub async fn get_package_doc(
|
||||||
return Ok(HttpResponse::NotFound().finish());
|
return Ok(HttpResponse::NotFound().finish());
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(v_id) = resolve_version_and_target(&file, version, target) else {
|
let Some(v_id) = resolve_version_and_target(&file, version, &target) else {
|
||||||
return Ok(HttpResponse::NotFound().finish());
|
return Ok(HttpResponse::NotFound().finish());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ use crate::{
|
||||||
error::RegistryError,
|
error::RegistryError,
|
||||||
package::read_package,
|
package::read_package,
|
||||||
request_path::{resolve_version_and_target, AnyOrSpecificTarget, LatestOrSpecificVersion},
|
request_path::{resolve_version_and_target, AnyOrSpecificTarget, LatestOrSpecificVersion},
|
||||||
storage::StorageImpl,
|
storage::StorageImpl as _,
|
||||||
AppState,
|
AppState,
|
||||||
};
|
};
|
||||||
use pesde::names::PackageName;
|
use pesde::names::PackageName;
|
||||||
|
@ -19,7 +19,7 @@ pub async fn get_package_readme(
|
||||||
return Ok(HttpResponse::NotFound().finish());
|
return Ok(HttpResponse::NotFound().finish());
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(v_id) = resolve_version_and_target(&file, version, target) else {
|
let Some(v_id) = resolve_version_and_target(&file, version, &target) else {
|
||||||
return Ok(HttpResponse::NotFound().finish());
|
return Ok(HttpResponse::NotFound().finish());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ use crate::{
|
||||||
error::RegistryError,
|
error::RegistryError,
|
||||||
package::{read_package, PackageResponse},
|
package::{read_package, PackageResponse},
|
||||||
request_path::{resolve_version_and_target, AnyOrSpecificTarget, LatestOrSpecificVersion},
|
request_path::{resolve_version_and_target, AnyOrSpecificTarget, LatestOrSpecificVersion},
|
||||||
storage::StorageImpl,
|
storage::StorageImpl as _,
|
||||||
AppState,
|
AppState,
|
||||||
};
|
};
|
||||||
use pesde::names::PackageName;
|
use pesde::names::PackageName;
|
||||||
|
@ -28,7 +28,7 @@ pub async fn get_package_version_v0(
|
||||||
return Ok(HttpResponse::NotFound().finish());
|
return Ok(HttpResponse::NotFound().finish());
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(v_id) = resolve_version_and_target(&file, version, target) else {
|
let Some(v_id) = resolve_version_and_target(&file, version, &target) else {
|
||||||
return Ok(HttpResponse::NotFound().finish());
|
return Ok(HttpResponse::NotFound().finish());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ pub async fn get_package_version(
|
||||||
return Ok(HttpResponse::NotFound().finish());
|
return Ok(HttpResponse::NotFound().finish());
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(v_id) = resolve_version_and_target(&file, version, target) else {
|
let Some(v_id) = resolve_version_and_target(&file, version, &target) else {
|
||||||
return Ok(HttpResponse::NotFound().finish());
|
return Ok(HttpResponse::NotFound().finish());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -4,17 +4,17 @@ use crate::{
|
||||||
git::push_changes,
|
git::push_changes,
|
||||||
package::{read_package, read_scope_info},
|
package::{read_package, read_scope_info},
|
||||||
search::update_search_version,
|
search::update_search_version,
|
||||||
storage::StorageImpl,
|
storage::StorageImpl as _,
|
||||||
AppState,
|
AppState,
|
||||||
};
|
};
|
||||||
use actix_web::{web, web::Bytes, HttpResponse};
|
use actix_web::{web, web::Bytes, HttpResponse};
|
||||||
use async_compression::Level;
|
use async_compression::Level;
|
||||||
use convert_case::{Case, Casing};
|
use convert_case::{Case, Casing as _};
|
||||||
use fs_err::tokio as fs;
|
use fs_err::tokio as fs;
|
||||||
use pesde::{
|
use pesde::{
|
||||||
manifest::{DependencyType, Manifest},
|
manifest::{DependencyType, Manifest},
|
||||||
source::{
|
source::{
|
||||||
git_index::GitBasedSource,
|
git_index::GitBasedSource as _,
|
||||||
ids::VersionId,
|
ids::VersionId,
|
||||||
pesde::{DocEntry, DocEntryKind, IndexFileEntry, ScopeInfo, SCOPE_INFO_FILE},
|
pesde::{DocEntry, DocEntryKind, IndexFileEntry, ScopeInfo, SCOPE_INFO_FILE},
|
||||||
specifiers::DependencySpecifiers,
|
specifiers::DependencySpecifiers,
|
||||||
|
@ -25,13 +25,13 @@ use pesde::{
|
||||||
};
|
};
|
||||||
use sentry::add_breadcrumb;
|
use sentry::add_breadcrumb;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use sha2::{Digest, Sha256};
|
use sha2::{Digest as _, Sha256};
|
||||||
use std::{
|
use std::{
|
||||||
collections::{BTreeSet, HashMap},
|
collections::{BTreeSet, HashMap},
|
||||||
io::Cursor,
|
io::Cursor,
|
||||||
};
|
};
|
||||||
use tokio::{
|
use tokio::{
|
||||||
io::{AsyncReadExt, AsyncWriteExt},
|
io::{AsyncReadExt as _, AsyncWriteExt as _},
|
||||||
task::JoinSet,
|
task::JoinSet,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -144,7 +144,7 @@ pub async fn publish_package(
|
||||||
);
|
);
|
||||||
let mut bytes = vec![];
|
let mut bytes = vec![];
|
||||||
gz.read_to_end(&mut bytes).await?;
|
gz.read_to_end(&mut bytes).await?;
|
||||||
docs_pages.insert(hash.to_string(), bytes);
|
docs_pages.insert(hash.clone(), bytes);
|
||||||
|
|
||||||
let mut lines = content.lines().peekable();
|
let mut lines = content.lines().peekable();
|
||||||
let front_matter = if lines.peek().filter(|l| **l == "---").is_some() {
|
let front_matter = if lines.peek().filter(|l| **l == "---").is_some() {
|
||||||
|
@ -166,10 +166,10 @@ pub async fn publish_package(
|
||||||
let h1 = lines
|
let h1 = lines
|
||||||
.find(|l| !l.trim().is_empty())
|
.find(|l| !l.trim().is_empty())
|
||||||
.and_then(|l| l.strip_prefix("# "))
|
.and_then(|l| l.strip_prefix("# "))
|
||||||
.map(|s| s.to_string());
|
.map(ToString::to_string);
|
||||||
|
|
||||||
let info: DocEntryInfo =
|
let info: DocEntryInfo =
|
||||||
serde_yaml::from_str(&front_matter).map_err(|_| {
|
serde_yaml::from_str(&front_matter).map_err(|_e| {
|
||||||
RegistryError::InvalidArchive(format!(
|
RegistryError::InvalidArchive(format!(
|
||||||
"doc {file_name}'s frontmatter isn't valid YAML"
|
"doc {file_name}'s frontmatter isn't valid YAML"
|
||||||
))
|
))
|
||||||
|
@ -194,7 +194,7 @@ pub async fn publish_package(
|
||||||
)
|
)
|
||||||
})?
|
})?
|
||||||
// ensure that the path is always using forward slashes
|
// ensure that the path is always using forward slashes
|
||||||
.replace("\\", "/"),
|
.replace('\\', "/"),
|
||||||
hash,
|
hash,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -341,19 +341,16 @@ pub async fn publish_package(
|
||||||
let mut files = HashMap::new();
|
let mut files = HashMap::new();
|
||||||
|
|
||||||
let scope = read_scope_info(&app_state, manifest.name.scope(), &source).await?;
|
let scope = read_scope_info(&app_state, manifest.name.scope(), &source).await?;
|
||||||
match scope {
|
if let Some(info) = scope {
|
||||||
Some(info) => {
|
if !info.owners.contains(&user_id.0) {
|
||||||
if !info.owners.contains(&user_id.0) {
|
return Ok(HttpResponse::Forbidden().finish());
|
||||||
return Ok(HttpResponse::Forbidden().finish());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
None => {
|
} else {
|
||||||
let scope_info = toml::to_string(&ScopeInfo {
|
let scope_info = toml::to_string(&ScopeInfo {
|
||||||
owners: BTreeSet::from([user_id.0]),
|
owners: BTreeSet::from([user_id.0]),
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
files.insert(SCOPE_INFO_FILE.to_string(), scope_info.into_bytes());
|
files.insert(SCOPE_INFO_FILE.to_string(), scope_info.into_bytes());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut file = read_package(&app_state, &manifest.name, &source)
|
let mut file = read_package(&app_state, &manifest.name, &source)
|
||||||
|
@ -414,6 +411,7 @@ pub async fn publish_package(
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
drop(source);
|
||||||
|
|
||||||
update_search_version(&app_state, &manifest.name, &new_entry);
|
update_search_version(&app_state, &manifest.name, &new_entry);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ use actix_web::{web, HttpResponse};
|
||||||
use pesde::names::PackageName;
|
use pesde::names::PackageName;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::{collections::HashMap, sync::Arc};
|
use std::{collections::HashMap, sync::Arc};
|
||||||
use tantivy::{collector::Count, query::AllQuery, schema::Value, DateTime, Order};
|
use tantivy::{collector::Count, query::AllQuery, schema::Value as _, DateTime, Order};
|
||||||
use tokio::task::JoinSet;
|
use tokio::task::JoinSet;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
|
@ -64,9 +64,7 @@ pub async fn search_packages(
|
||||||
let source = source.clone();
|
let source = source.clone();
|
||||||
|
|
||||||
async move {
|
async move {
|
||||||
let id = doc
|
let id = (&doc[&id])
|
||||||
.get(&id)
|
|
||||||
.unwrap()
|
|
||||||
.as_str()
|
.as_str()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.parse::<PackageName>()
|
.parse::<PackageName>()
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{benv, error::RegistryError, AppState};
|
use crate::{benv, error::RegistryError, AppState};
|
||||||
use git2::{Remote, Repository, Signature};
|
use git2::{Remote, Repository, Signature};
|
||||||
use pesde::source::{git_index::GitBasedSource, pesde::PesdePackageSource};
|
use pesde::source::{git_index::GitBasedSource as _, pesde::PesdePackageSource};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use tokio::task::spawn_blocking;
|
use tokio::task::spawn_blocking;
|
||||||
|
|
||||||
|
@ -26,8 +26,8 @@ fn get_refspec(repo: &Repository, remote: &mut Remote) -> Result<String, git2::E
|
||||||
Ok(refspec.to_string())
|
Ok(refspec.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
const FILE_FILEMODE: i32 = 0o100644;
|
const FILE_FILEMODE: i32 = 0o100_644;
|
||||||
const DIR_FILEMODE: i32 = 0o040000;
|
const DIR_FILEMODE: i32 = 0o040_000;
|
||||||
|
|
||||||
pub async fn push_changes(
|
pub async fn push_changes(
|
||||||
app_state: &AppState,
|
app_state: &AppState,
|
||||||
|
|
|
@ -16,14 +16,14 @@ use fs_err::tokio as fs;
|
||||||
use pesde::{
|
use pesde::{
|
||||||
source::{
|
source::{
|
||||||
pesde::PesdePackageSource,
|
pesde::PesdePackageSource,
|
||||||
traits::{PackageSource, RefreshOptions},
|
traits::{PackageSource as _, RefreshOptions},
|
||||||
},
|
},
|
||||||
AuthConfig, Project,
|
AuthConfig, Project,
|
||||||
};
|
};
|
||||||
use std::{env::current_dir, path::PathBuf, sync::Arc};
|
use std::{env::current_dir, path::PathBuf, sync::Arc};
|
||||||
use tracing::level_filters::LevelFilter;
|
use tracing::level_filters::LevelFilter;
|
||||||
use tracing_subscriber::{
|
use tracing_subscriber::{
|
||||||
fmt::format::FmtSpan, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter,
|
fmt::format::FmtSpan, layer::SubscriberExt as _, util::SubscriberInitExt as _, EnvFilter,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod auth;
|
mod auth;
|
||||||
|
@ -35,6 +35,7 @@ mod request_path;
|
||||||
mod search;
|
mod search;
|
||||||
mod storage;
|
mod storage;
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn make_reqwest() -> reqwest::Client {
|
pub fn make_reqwest() -> reqwest::Client {
|
||||||
reqwest::ClientBuilder::new()
|
reqwest::ClientBuilder::new()
|
||||||
.user_agent(concat!(
|
.user_agent(concat!(
|
||||||
|
|
|
@ -6,7 +6,7 @@ use pesde::{
|
||||||
},
|
},
|
||||||
names::PackageName,
|
names::PackageName,
|
||||||
source::{
|
source::{
|
||||||
git_index::{read_file, root_tree, GitBasedSource},
|
git_index::{read_file, root_tree, GitBasedSource as _},
|
||||||
ids::VersionId,
|
ids::VersionId,
|
||||||
pesde::{IndexFile, IndexFileEntry, PesdePackageSource, ScopeInfo, SCOPE_INFO_FILE},
|
pesde::{IndexFile, IndexFileEntry, PesdePackageSource, ScopeInfo, SCOPE_INFO_FILE},
|
||||||
specifiers::DependencySpecifiers,
|
specifiers::DependencySpecifiers,
|
||||||
|
@ -155,7 +155,7 @@ pub struct PackageResponse {
|
||||||
|
|
||||||
impl PackageResponse {
|
impl PackageResponse {
|
||||||
pub fn new(name: &PackageName, version_id: &VersionId, file: &IndexFile) -> Self {
|
pub fn new(name: &PackageName, version_id: &VersionId, file: &IndexFile) -> Self {
|
||||||
let entry = file.entries.get(version_id).unwrap();
|
let entry = &file.entries[version_id];
|
||||||
|
|
||||||
PackageResponse {
|
PackageResponse {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
|
@ -201,7 +201,7 @@ impl PackageVersionsResponse {
|
||||||
pub fn new(name: &PackageName, file: &IndexFile) -> Self {
|
pub fn new(name: &PackageName, file: &IndexFile) -> Self {
|
||||||
let mut versions = BTreeMap::<Version, PackageVersionsResponseVersion>::new();
|
let mut versions = BTreeMap::<Version, PackageVersionsResponseVersion>::new();
|
||||||
|
|
||||||
for (v_id, entry) in file.entries.iter() {
|
for (v_id, entry) in &file.entries {
|
||||||
let versions_resp = versions.entry(v_id.version().clone()).or_default();
|
let versions_resp = versions.entry(v_id.version().clone()).or_default();
|
||||||
|
|
||||||
versions_resp.description = entry.description.clone().unwrap_or_default();
|
versions_resp.description = entry.description.clone().unwrap_or_default();
|
||||||
|
|
|
@ -49,16 +49,18 @@ impl<'de> Deserialize<'de> for AnyOrSpecificTarget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_version_and_target(
|
pub fn resolve_version_and_target<'a>(
|
||||||
file: &IndexFile,
|
file: &'a IndexFile,
|
||||||
version: LatestOrSpecificVersion,
|
version: LatestOrSpecificVersion,
|
||||||
target: AnyOrSpecificTarget,
|
target: &AnyOrSpecificTarget,
|
||||||
) -> Option<&VersionId> {
|
) -> Option<&'a VersionId> {
|
||||||
let version = match version {
|
let version = match version {
|
||||||
LatestOrSpecificVersion::Latest => match file.entries.keys().map(|k| k.version()).max() {
|
LatestOrSpecificVersion::Latest => {
|
||||||
Some(latest) => latest.clone(),
|
match file.entries.keys().map(VersionId::version).max() {
|
||||||
None => return None,
|
Some(latest) => latest.clone(),
|
||||||
},
|
None => return None,
|
||||||
|
}
|
||||||
|
}
|
||||||
LatestOrSpecificVersion::Specific(version) => version,
|
LatestOrSpecificVersion::Specific(version) => version,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -70,7 +72,7 @@ pub fn resolve_version_and_target(
|
||||||
match target {
|
match target {
|
||||||
AnyOrSpecificTarget::Any => versions.min_by_key(|(v_id, _)| v_id.target()),
|
AnyOrSpecificTarget::Any => versions.min_by_key(|(v_id, _)| v_id.target()),
|
||||||
AnyOrSpecificTarget::Specific(kind) => {
|
AnyOrSpecificTarget::Specific(kind) => {
|
||||||
versions.find(|(_, entry)| entry.target.kind() == kind)
|
versions.find(|(_, entry)| entry.target.kind() == *kind)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.map(|(v_id, _)| v_id)
|
.map(|(v_id, _)| v_id)
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
use crate::AppState;
|
use crate::AppState;
|
||||||
use async_stream::stream;
|
|
||||||
use futures::{Stream, StreamExt};
|
|
||||||
use pesde::{
|
use pesde::{
|
||||||
names::PackageName,
|
names::PackageName,
|
||||||
source::{
|
source::{
|
||||||
git_index::{root_tree, GitBasedSource},
|
git_index::{root_tree, GitBasedSource as _},
|
||||||
ids::VersionId,
|
ids::VersionId,
|
||||||
pesde::{IndexFile, IndexFileEntry, PesdePackageSource, SCOPE_INFO_FILE},
|
pesde::{IndexFile, IndexFileEntry, PesdePackageSource, SCOPE_INFO_FILE},
|
||||||
},
|
},
|
||||||
Project,
|
Project,
|
||||||
};
|
};
|
||||||
|
use std::collections::BTreeMap;
|
||||||
use tantivy::{
|
use tantivy::{
|
||||||
doc,
|
doc,
|
||||||
query::QueryParser,
|
query::QueryParser,
|
||||||
|
@ -17,54 +16,78 @@ use tantivy::{
|
||||||
tokenizer::TextAnalyzer,
|
tokenizer::TextAnalyzer,
|
||||||
DateTime, IndexReader, IndexWriter, Term,
|
DateTime, IndexReader, IndexWriter, Term,
|
||||||
};
|
};
|
||||||
use tokio::pin;
|
|
||||||
|
|
||||||
async fn all_packages(
|
type Entries = BTreeMap<String, gix::ObjectId>;
|
||||||
source: &PesdePackageSource,
|
|
||||||
project: &Project,
|
|
||||||
) -> impl Stream<Item = (PackageName, IndexFile)> {
|
|
||||||
let path = source.path(project);
|
|
||||||
|
|
||||||
stream! {
|
struct TreeIterator<'repo> {
|
||||||
let repo = gix::open(&path).expect("failed to open index");
|
repo: &'repo gix::Repository,
|
||||||
let tree = root_tree(&repo).expect("failed to get root tree");
|
entries: Entries,
|
||||||
|
current: Option<(String, Entries)>,
|
||||||
|
}
|
||||||
|
|
||||||
for entry in tree.iter() {
|
fn collect_entries(tree: &gix::Tree) -> Result<Entries, gix::objs::decode::Error> {
|
||||||
let entry = entry.expect("failed to read entry");
|
tree.iter()
|
||||||
let object = entry.object().expect("failed to get object");
|
.map(|res| res.map(|r| (r.filename().to_string(), r.object_id())))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
// directories will be trees, and files will be blobs
|
impl Iterator for TreeIterator<'_> {
|
||||||
if !matches!(object.kind, gix::object::Kind::Tree) {
|
type Item = (PackageName, IndexFile);
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let package_scope = entry.filename().to_string();
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
if self
|
||||||
|
.current
|
||||||
|
.as_ref()
|
||||||
|
.is_none_or(|(_, entries)| entries.is_empty())
|
||||||
|
{
|
||||||
|
loop {
|
||||||
|
let (scope_name, scope_oid) = self.entries.pop_last()?;
|
||||||
|
|
||||||
for inner_entry in object.into_tree().iter() {
|
let object = self
|
||||||
let inner_entry = inner_entry.expect("failed to read inner entry");
|
.repo
|
||||||
let object = inner_entry.object().expect("failed to get object");
|
.find_object(scope_oid)
|
||||||
|
.expect("failed to get scope object");
|
||||||
|
|
||||||
if !matches!(object.kind, gix::object::Kind::Blob) {
|
if object.kind != gix::objs::Kind::Tree {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let package_name = inner_entry.filename().to_string();
|
let tree = object.into_tree();
|
||||||
|
let mut entries = collect_entries(&tree).expect("failed to read scope entries");
|
||||||
|
|
||||||
if package_name == SCOPE_INFO_FILE {
|
entries.remove(SCOPE_INFO_FILE);
|
||||||
|
|
||||||
|
if entries.is_empty() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let blob = object.into_blob();
|
self.current = Some((scope_name, entries));
|
||||||
let string = String::from_utf8(blob.data.clone()).expect("failed to parse utf8");
|
break;
|
||||||
|
|
||||||
let file: IndexFile = toml::from_str(&string).expect("failed to parse index file");
|
|
||||||
|
|
||||||
// if this panics, it's an issue with the index.
|
|
||||||
let name = format!("{package_scope}/{package_name}").parse().unwrap();
|
|
||||||
|
|
||||||
yield (name, file);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let (scope_name, entries) = self.current.as_mut()?;
|
||||||
|
let (file_name, file_oid) = entries.pop_last()?;
|
||||||
|
|
||||||
|
let object = self
|
||||||
|
.repo
|
||||||
|
.find_object(file_oid)
|
||||||
|
.expect("failed to get scope entry object");
|
||||||
|
|
||||||
|
if object.kind != gix::objs::Kind::Blob {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut blob = object.into_blob();
|
||||||
|
let string = String::from_utf8(blob.take_data()).expect("failed to parse utf8");
|
||||||
|
|
||||||
|
let file = toml::from_str(&string).expect("failed to parse index file");
|
||||||
|
|
||||||
|
Some((
|
||||||
|
// if this panics, it's an issue with the index.
|
||||||
|
format!("{scope_name}/{file_name}").parse().unwrap(),
|
||||||
|
file,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,10 +137,17 @@ pub async fn make_search(
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let mut search_writer = search_index.writer(50_000_000).unwrap();
|
let mut search_writer = search_index.writer(50_000_000).unwrap();
|
||||||
|
|
||||||
let stream = all_packages(source, project).await;
|
let path = source.path(project);
|
||||||
pin!(stream);
|
let repo = gix::open(path).expect("failed to open index");
|
||||||
|
let tree = root_tree(&repo).expect("failed to get root tree");
|
||||||
|
|
||||||
while let Some((pkg_name, file)) = stream.next().await {
|
let iter = TreeIterator {
|
||||||
|
entries: collect_entries(&tree).expect("failed to read entries"),
|
||||||
|
repo: &repo,
|
||||||
|
current: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (pkg_name, file) in iter {
|
||||||
if !file.meta.deprecated.is_empty() {
|
if !file.meta.deprecated.is_empty() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -163,6 +193,7 @@ pub fn update_search_version(app_state: &AppState, name: &PackageName, entry: &I
|
||||||
)).unwrap();
|
)).unwrap();
|
||||||
|
|
||||||
search_writer.commit().unwrap();
|
search_writer.commit().unwrap();
|
||||||
|
drop(search_writer);
|
||||||
app_state.search_reader.reload().unwrap();
|
app_state.search_reader.reload().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,6 +211,7 @@ pub fn search_version_changed(app_state: &AppState, name: &PackageName, file: &I
|
||||||
|
|
||||||
search_writer.delete_term(Term::from_field_text(id_field, &name.to_string()));
|
search_writer.delete_term(Term::from_field_text(id_field, &name.to_string()));
|
||||||
search_writer.commit().unwrap();
|
search_writer.commit().unwrap();
|
||||||
|
drop(search_writer);
|
||||||
app_state.search_reader.reload().unwrap();
|
app_state.search_reader.reload().unwrap();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
error::{RegistryError, ReqwestErrorExt},
|
error::{RegistryError, ReqwestErrorExt as _},
|
||||||
storage::StorageImpl,
|
storage::StorageImpl,
|
||||||
};
|
};
|
||||||
use actix_web::{http::header::LOCATION, HttpResponse};
|
use actix_web::{http::header::LOCATION, HttpResponse};
|
||||||
|
@ -7,7 +7,7 @@ use pesde::{names::PackageName, source::ids::VersionId};
|
||||||
use reqwest::header::{CONTENT_ENCODING, CONTENT_TYPE};
|
use reqwest::header::{CONTENT_ENCODING, CONTENT_TYPE};
|
||||||
use rusty_s3::{
|
use rusty_s3::{
|
||||||
actions::{GetObject, PutObject},
|
actions::{GetObject, PutObject},
|
||||||
Bucket, Credentials, S3Action,
|
Bucket, Credentials, S3Action as _,
|
||||||
};
|
};
|
||||||
use std::{fmt::Display, time::Duration};
|
use std::{fmt::Display, time::Duration};
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use crate::cli::config::{read_config, write_config};
|
use crate::cli::config::{read_config, write_config};
|
||||||
use anyhow::Context;
|
use anyhow::Context as _;
|
||||||
use gix::bstr::BStr;
|
use gix::bstr::BStr;
|
||||||
use keyring::Entry;
|
use keyring::Entry;
|
||||||
use reqwest::header::AUTHORIZATION;
|
use reqwest::header::AUTHORIZATION;
|
||||||
use serde::{ser::SerializeMap, Deserialize, Serialize};
|
use serde::{ser::SerializeMap as _, Deserialize, Serialize};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use tokio::task::spawn_blocking;
|
use tokio::task::spawn_blocking;
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::str::FromStr;
|
use std::str::FromStr as _;
|
||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context as _;
|
||||||
use clap::Args;
|
use clap::Args;
|
||||||
use semver::VersionReq;
|
use semver::VersionReq;
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ use pesde::{
|
||||||
path::{specifier::PathDependencySpecifier, PathPackageSource},
|
path::{specifier::PathDependencySpecifier, PathPackageSource},
|
||||||
pesde::{specifier::PesdeDependencySpecifier, PesdePackageSource},
|
pesde::{specifier::PesdeDependencySpecifier, PesdePackageSource},
|
||||||
specifiers::DependencySpecifiers,
|
specifiers::DependencySpecifiers,
|
||||||
traits::{PackageSource, RefreshOptions, ResolveOptions},
|
traits::{PackageSource as _, RefreshOptions, ResolveOptions},
|
||||||
workspace::{specifier::WorkspaceDependencySpecifier, WorkspacePackageSource},
|
workspace::{specifier::WorkspaceDependencySpecifier, WorkspacePackageSource},
|
||||||
PackageSources,
|
PackageSources,
|
||||||
},
|
},
|
||||||
|
@ -186,8 +186,7 @@ impl AddCommand {
|
||||||
.to_string()
|
.to_string()
|
||||||
.split('/')
|
.split('/')
|
||||||
.next_back()
|
.next_back()
|
||||||
.map(|s| s.to_string())
|
.map_or_else(|| url.path.to_string(), ToString::to_string),
|
||||||
.unwrap_or_else(|| url.path.to_string()),
|
|
||||||
AnyPackageIdentifier::Workspace(versioned) => versioned.0.name().to_string(),
|
AnyPackageIdentifier::Workspace(versioned) => versioned.0.name().to_string(),
|
||||||
AnyPackageIdentifier::Path(path) => path
|
AnyPackageIdentifier::Path(path) => path
|
||||||
.file_name()
|
.file_name()
|
||||||
|
@ -203,7 +202,7 @@ impl AddCommand {
|
||||||
|
|
||||||
match specifier {
|
match specifier {
|
||||||
DependencySpecifiers::Pesde(spec) => {
|
DependencySpecifiers::Pesde(spec) => {
|
||||||
field["name"] = toml_edit::value(spec.name.clone().to_string());
|
field["name"] = toml_edit::value(spec.name.to_string());
|
||||||
field["version"] = toml_edit::value(format!("^{}", version_id.version()));
|
field["version"] = toml_edit::value(format!("^{}", version_id.version()));
|
||||||
|
|
||||||
if version_id.target() != project_target {
|
if version_id.target() != project_target {
|
||||||
|
@ -244,7 +243,7 @@ impl AddCommand {
|
||||||
println!("added git {}#{} to {dependency_key}", spec.repo, spec.rev);
|
println!("added git {}#{} to {dependency_key}", spec.repo, spec.rev);
|
||||||
}
|
}
|
||||||
DependencySpecifiers::Workspace(spec) => {
|
DependencySpecifiers::Workspace(spec) => {
|
||||||
field["workspace"] = toml_edit::value(spec.name.clone().to_string());
|
field["workspace"] = toml_edit::value(spec.name.to_string());
|
||||||
if let AnyPackageIdentifier::Workspace(versioned) = self.name {
|
if let AnyPackageIdentifier::Workspace(versioned) = self.name {
|
||||||
if let Some(version) = versioned.1 {
|
if let Some(version) = versioned.1 {
|
||||||
field["version"] = toml_edit::value(version.to_string());
|
field["version"] = toml_edit::value(version.to_string());
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use anyhow::Context;
|
use anyhow::Context as _;
|
||||||
use clap::Args;
|
use clap::Args;
|
||||||
use console::style;
|
use console::style;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
@ -13,7 +13,7 @@ use crate::cli::{
|
||||||
use pesde::{
|
use pesde::{
|
||||||
source::{
|
source::{
|
||||||
pesde::PesdePackageSource,
|
pesde::PesdePackageSource,
|
||||||
traits::{PackageSource, RefreshOptions},
|
traits::{PackageSource as _, RefreshOptions},
|
||||||
},
|
},
|
||||||
Project,
|
Project,
|
||||||
};
|
};
|
||||||
|
@ -145,12 +145,11 @@ impl LoginCommand {
|
||||||
return Ok(access_token);
|
return Ok(access_token);
|
||||||
}
|
}
|
||||||
AccessTokenResponse::Error(e) => match e {
|
AccessTokenResponse::Error(e) => match e {
|
||||||
AccessTokenError::AuthorizationPending => continue,
|
AccessTokenError::AuthorizationPending => {}
|
||||||
AccessTokenError::SlowDown {
|
AccessTokenError::SlowDown {
|
||||||
interval: new_interval,
|
interval: new_interval,
|
||||||
} => {
|
} => {
|
||||||
interval = std::time::Duration::from_secs(new_interval);
|
interval = std::time::Duration::from_secs(new_interval);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
AccessTokenError::ExpiredToken => {
|
AccessTokenError::ExpiredToken => {
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -2,7 +2,7 @@ use crate::cli::auth::set_token;
|
||||||
use clap::Args;
|
use clap::Args;
|
||||||
|
|
||||||
#[derive(Debug, Args)]
|
#[derive(Debug, Args)]
|
||||||
pub struct LogoutCommand {}
|
pub struct LogoutCommand;
|
||||||
|
|
||||||
impl LogoutCommand {
|
impl LogoutCommand {
|
||||||
pub async fn run(self, index_url: gix::Url) -> anyhow::Result<()> {
|
pub async fn run(self, index_url: gix::Url) -> anyhow::Result<()> {
|
||||||
|
|
|
@ -2,17 +2,14 @@ use crate::cli::auth::get_tokens;
|
||||||
use clap::Args;
|
use clap::Args;
|
||||||
|
|
||||||
#[derive(Debug, Args)]
|
#[derive(Debug, Args)]
|
||||||
pub struct TokenCommand {}
|
pub struct TokenCommand;
|
||||||
|
|
||||||
impl TokenCommand {
|
impl TokenCommand {
|
||||||
pub async fn run(self, index_url: gix::Url) -> anyhow::Result<()> {
|
pub async fn run(self, index_url: gix::Url) -> anyhow::Result<()> {
|
||||||
let tokens = get_tokens().await?;
|
let tokens = get_tokens().await?;
|
||||||
let token = match tokens.0.get(&index_url) {
|
let Some(token) = tokens.0.get(&index_url) else {
|
||||||
Some(token) => token,
|
println!("not logged in into {index_url}");
|
||||||
None => {
|
return Ok(());
|
||||||
println!("not logged in into {index_url}");
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
println!("token for {index_url}: \"{token}\"");
|
println!("token for {index_url}: \"{token}\"");
|
||||||
|
|
|
@ -3,17 +3,14 @@ use clap::Args;
|
||||||
use console::style;
|
use console::style;
|
||||||
|
|
||||||
#[derive(Debug, Args)]
|
#[derive(Debug, Args)]
|
||||||
pub struct WhoAmICommand {}
|
pub struct WhoAmICommand;
|
||||||
|
|
||||||
impl WhoAmICommand {
|
impl WhoAmICommand {
|
||||||
pub async fn run(self, index_url: gix::Url, reqwest: reqwest::Client) -> anyhow::Result<()> {
|
pub async fn run(self, index_url: gix::Url, reqwest: reqwest::Client) -> anyhow::Result<()> {
|
||||||
let tokens = get_tokens().await?;
|
let tokens = get_tokens().await?;
|
||||||
let token = match tokens.0.get(&index_url) {
|
let Some(token) = tokens.0.get(&index_url) else {
|
||||||
Some(token) => token,
|
println!("not logged in into {index_url}");
|
||||||
None => {
|
return Ok(());
|
||||||
println!("not logged in into {index_url}");
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
|
|
|
@ -5,11 +5,11 @@ use crate::{
|
||||||
},
|
},
|
||||||
util::remove_empty_dir,
|
util::remove_empty_dir,
|
||||||
};
|
};
|
||||||
use anyhow::Context;
|
use anyhow::Context as _;
|
||||||
use async_stream::try_stream;
|
use async_stream::try_stream;
|
||||||
use clap::Args;
|
use clap::Args;
|
||||||
use fs_err::tokio as fs;
|
use fs_err::tokio as fs;
|
||||||
use futures::{future::BoxFuture, FutureExt, Stream, StreamExt};
|
use futures::{future::BoxFuture, FutureExt as _, Stream, StreamExt as _};
|
||||||
use pesde::{
|
use pesde::{
|
||||||
source::fs::{FsEntry, PackageFs},
|
source::fs::{FsEntry, PackageFs},
|
||||||
Project,
|
Project,
|
||||||
|
@ -22,7 +22,7 @@ use std::{
|
||||||
use tokio::task::JoinSet;
|
use tokio::task::JoinSet;
|
||||||
|
|
||||||
#[derive(Debug, Args)]
|
#[derive(Debug, Args)]
|
||||||
pub struct PruneCommand {}
|
pub struct PruneCommand;
|
||||||
|
|
||||||
async fn read_dir_stream(
|
async fn read_dir_stream(
|
||||||
dir: &Path,
|
dir: &Path,
|
||||||
|
@ -47,7 +47,7 @@ async fn get_nlinks(path: &Path) -> anyhow::Result<u64> {
|
||||||
// life if rust stabilized the nightly feature from 2019
|
// life if rust stabilized the nightly feature from 2019
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
{
|
{
|
||||||
use std::os::windows::ffi::OsStrExt;
|
use std::os::windows::ffi::OsStrExt as _;
|
||||||
use windows::{
|
use windows::{
|
||||||
core::PWSTR,
|
core::PWSTR,
|
||||||
Win32::{
|
Win32::{
|
||||||
|
@ -139,7 +139,7 @@ async fn discover_cas_packages(cas_dir: &Path) -> anyhow::Result<HashMap<PathBuf
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(res);
|
return Ok(res);
|
||||||
};
|
}
|
||||||
|
|
||||||
let contents = fs::read_to_string(entry.path()).await?;
|
let contents = fs::read_to_string(entry.path()).await?;
|
||||||
let fs = toml::from_str(&contents).context("failed to deserialize PackageFs")?;
|
let fs = toml::from_str(&contents).context("failed to deserialize PackageFs")?;
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
use crate::cli::{get_index, style::SUCCESS_STYLE};
|
use crate::cli::{get_index, style::SUCCESS_STYLE};
|
||||||
use anyhow::Context;
|
use anyhow::Context as _;
|
||||||
use clap::Args;
|
use clap::Args;
|
||||||
use pesde::{
|
use pesde::{
|
||||||
names::PackageName,
|
names::PackageName,
|
||||||
source::{
|
source::{
|
||||||
pesde::PesdePackageSource,
|
pesde::PesdePackageSource,
|
||||||
traits::{PackageSource, RefreshOptions},
|
traits::{PackageSource as _, RefreshOptions},
|
||||||
},
|
},
|
||||||
Project,
|
Project,
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,7 +3,7 @@ use crate::cli::{
|
||||||
reporters::{self, CliReporter},
|
reporters::{self, CliReporter},
|
||||||
VersionedPackageName,
|
VersionedPackageName,
|
||||||
};
|
};
|
||||||
use anyhow::Context;
|
use anyhow::Context as _;
|
||||||
use clap::Args;
|
use clap::Args;
|
||||||
use console::style;
|
use console::style;
|
||||||
use fs_err::tokio as fs;
|
use fs_err::tokio as fs;
|
||||||
|
@ -17,7 +17,7 @@ use pesde::{
|
||||||
ids::PackageId,
|
ids::PackageId,
|
||||||
pesde::{specifier::PesdeDependencySpecifier, PesdePackageSource},
|
pesde::{specifier::PesdeDependencySpecifier, PesdePackageSource},
|
||||||
traits::{
|
traits::{
|
||||||
DownloadOptions, GetTargetOptions, PackageSource, RefreshOptions, ResolveOptions,
|
DownloadOptions, GetTargetOptions, PackageSource as _, RefreshOptions, ResolveOptions,
|
||||||
},
|
},
|
||||||
PackageSources,
|
PackageSources,
|
||||||
},
|
},
|
||||||
|
@ -27,7 +27,7 @@ use semver::VersionReq;
|
||||||
use std::{
|
use std::{
|
||||||
env::current_dir,
|
env::current_dir,
|
||||||
ffi::OsString,
|
ffi::OsString,
|
||||||
io::{Stderr, Write},
|
io::{Stderr, Write as _},
|
||||||
process::Command,
|
process::Command,
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
@ -237,6 +237,6 @@ impl ExecuteCommand {
|
||||||
drop(caller);
|
drop(caller);
|
||||||
drop(tempdir);
|
drop(tempdir);
|
||||||
|
|
||||||
std::process::exit(status.code().unwrap_or(1))
|
std::process::exit(status.code().unwrap_or(1i32))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ use crate::cli::{
|
||||||
config::read_config,
|
config::read_config,
|
||||||
style::{ERROR_PREFIX, INFO_STYLE, SUCCESS_STYLE},
|
style::{ERROR_PREFIX, INFO_STYLE, SUCCESS_STYLE},
|
||||||
};
|
};
|
||||||
use anyhow::Context;
|
use anyhow::Context as _;
|
||||||
use clap::Args;
|
use clap::Args;
|
||||||
use inquire::validator::Validation;
|
use inquire::validator::Validation;
|
||||||
use pesde::{
|
use pesde::{
|
||||||
|
@ -10,20 +10,20 @@ use pesde::{
|
||||||
manifest::{target::TargetKind, DependencyType},
|
manifest::{target::TargetKind, DependencyType},
|
||||||
names::{PackageName, PackageNames},
|
names::{PackageName, PackageNames},
|
||||||
source::{
|
source::{
|
||||||
git_index::GitBasedSource,
|
git_index::GitBasedSource as _,
|
||||||
ids::PackageId,
|
ids::PackageId,
|
||||||
pesde::{specifier::PesdeDependencySpecifier, PesdePackageSource},
|
pesde::{specifier::PesdeDependencySpecifier, PesdePackageSource},
|
||||||
specifiers::DependencySpecifiers,
|
specifiers::DependencySpecifiers,
|
||||||
traits::{GetTargetOptions, PackageSource, RefreshOptions, ResolveOptions},
|
traits::{GetTargetOptions, PackageSource as _, RefreshOptions, ResolveOptions},
|
||||||
PackageSources,
|
PackageSources,
|
||||||
},
|
},
|
||||||
Project, RefreshedSources, DEFAULT_INDEX_NAME, SCRIPTS_LINK_FOLDER,
|
Project, RefreshedSources, DEFAULT_INDEX_NAME, SCRIPTS_LINK_FOLDER,
|
||||||
};
|
};
|
||||||
use semver::VersionReq;
|
use semver::VersionReq;
|
||||||
use std::{fmt::Display, path::Path, str::FromStr, sync::Arc};
|
use std::{fmt::Display, path::Path, str::FromStr as _, sync::Arc};
|
||||||
|
|
||||||
#[derive(Debug, Args)]
|
#[derive(Debug, Args)]
|
||||||
pub struct InitCommand {}
|
pub struct InitCommand;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum PackageNameOrCustom {
|
enum PackageNameOrCustom {
|
||||||
|
@ -48,7 +48,7 @@ impl InitCommand {
|
||||||
}
|
}
|
||||||
Err(ManifestReadError::Io(e)) if e.kind() == std::io::ErrorKind::NotFound => {}
|
Err(ManifestReadError::Io(e)) if e.kind() == std::io::ErrorKind::NotFound => {}
|
||||||
Err(e) => return Err(e.into()),
|
Err(e) => return Err(e.into()),
|
||||||
};
|
}
|
||||||
|
|
||||||
let mut manifest = toml_edit::DocumentMut::new();
|
let mut manifest = toml_edit::DocumentMut::new();
|
||||||
|
|
||||||
|
@ -232,8 +232,8 @@ impl InitCommand {
|
||||||
anyhow::bail!("scripts package has no scripts.")
|
anyhow::bail!("scripts package has no scripts.")
|
||||||
};
|
};
|
||||||
|
|
||||||
let scripts_field = &mut manifest["scripts"]
|
let scripts_field =
|
||||||
.or_insert(toml_edit::Item::Table(toml_edit::Table::new()));
|
manifest["scripts"].or_insert(toml_edit::Item::Table(toml_edit::Table::new()));
|
||||||
|
|
||||||
for script_name in scripts.keys() {
|
for script_name in scripts.keys() {
|
||||||
scripts_field[script_name] = toml_edit::value(format!(
|
scripts_field[script_name] = toml_edit::value(format!(
|
||||||
|
@ -241,7 +241,7 @@ impl InitCommand {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let dev_deps = &mut manifest["dev_dependencies"]
|
let dev_deps = manifest["dev_dependencies"]
|
||||||
.or_insert(toml_edit::Item::Table(toml_edit::Table::new()));
|
.or_insert(toml_edit::Item::Table(toml_edit::Table::new()));
|
||||||
|
|
||||||
let field = &mut dev_deps["scripts"];
|
let field = &mut dev_deps["scripts"];
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context as _;
|
||||||
use clap::Args;
|
use clap::Args;
|
||||||
|
|
||||||
use crate::cli::{
|
use crate::cli::{
|
||||||
|
@ -14,7 +14,7 @@ use pesde::{
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Args)]
|
#[derive(Debug, Args)]
|
||||||
pub struct ListCommand {}
|
pub struct ListCommand;
|
||||||
|
|
||||||
impl ListCommand {
|
impl ListCommand {
|
||||||
pub async fn run(self, project: Project) -> anyhow::Result<()> {
|
pub async fn run(self, project: Project) -> anyhow::Result<()> {
|
||||||
|
|
|
@ -2,12 +2,12 @@ use crate::cli::{
|
||||||
style::{ADDED_STYLE, INFO_STYLE, REMOVED_STYLE, SUCCESS_STYLE},
|
style::{ADDED_STYLE, INFO_STYLE, REMOVED_STYLE, SUCCESS_STYLE},
|
||||||
up_to_date_lockfile,
|
up_to_date_lockfile,
|
||||||
};
|
};
|
||||||
use anyhow::Context;
|
use anyhow::Context as _;
|
||||||
use clap::Args;
|
use clap::Args;
|
||||||
use pesde::{
|
use pesde::{
|
||||||
source::{
|
source::{
|
||||||
specifiers::DependencySpecifiers,
|
specifiers::DependencySpecifiers,
|
||||||
traits::{PackageRef, PackageSource, RefreshOptions, ResolveOptions},
|
traits::{PackageRef as _, PackageSource as _, RefreshOptions, ResolveOptions},
|
||||||
},
|
},
|
||||||
Project, RefreshedSources,
|
Project, RefreshedSources,
|
||||||
};
|
};
|
||||||
|
@ -82,7 +82,7 @@ impl OutdatedCommand {
|
||||||
DependencySpecifiers::Git(_) => {}
|
DependencySpecifiers::Git(_) => {}
|
||||||
DependencySpecifiers::Workspace(_) => {}
|
DependencySpecifiers::Workspace(_) => {}
|
||||||
DependencySpecifiers::Path(_) => {}
|
DependencySpecifiers::Path(_) => {}
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let new_id = source
|
let new_id = source
|
||||||
|
|
|
@ -4,7 +4,7 @@ use crate::cli::{
|
||||||
style::{CLI_STYLE, INFO_STYLE, WARN_PREFIX},
|
style::{CLI_STYLE, INFO_STYLE, WARN_PREFIX},
|
||||||
up_to_date_lockfile, VersionedPackageName,
|
up_to_date_lockfile, VersionedPackageName,
|
||||||
};
|
};
|
||||||
use anyhow::Context;
|
use anyhow::Context as _;
|
||||||
use clap::Args;
|
use clap::Args;
|
||||||
use console::style;
|
use console::style;
|
||||||
use fs_err::tokio as fs;
|
use fs_err::tokio as fs;
|
||||||
|
@ -12,7 +12,7 @@ use pesde::{
|
||||||
patches::setup_patches_repo,
|
patches::setup_patches_repo,
|
||||||
source::{
|
source::{
|
||||||
refs::PackageRefs,
|
refs::PackageRefs,
|
||||||
traits::{DownloadOptions, PackageRef, PackageSource},
|
traits::{DownloadOptions, PackageRef as _, PackageSource as _},
|
||||||
},
|
},
|
||||||
Project, MANIFEST_FILE_NAME,
|
Project, MANIFEST_FILE_NAME,
|
||||||
};
|
};
|
||||||
|
@ -71,9 +71,9 @@ impl PatchCommand {
|
||||||
setup_patches_repo(&directory)?;
|
setup_patches_repo(&directory)?;
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
r#"done! modify the files in the directory, then run {} {}{} to apply.
|
r"done! modify the files in the directory, then run {} {}{} to apply.
|
||||||
{WARN_PREFIX}: do not commit these changes
|
{WARN_PREFIX}: do not commit these changes
|
||||||
{}: the {MANIFEST_FILE_NAME} file will be ignored when patching"#,
|
{}: the {MANIFEST_FILE_NAME} file will be ignored when patching",
|
||||||
CLI_STYLE.apply_to(concat!("`", env!("CARGO_BIN_NAME"), " patch-commit")),
|
CLI_STYLE.apply_to(concat!("`", env!("CARGO_BIN_NAME"), " patch-commit")),
|
||||||
style(format!("'{}'", directory.display())).cyan().bold(),
|
style(format!("'{}'", directory.display())).cyan().bold(),
|
||||||
CLI_STYLE.apply_to("`"),
|
CLI_STYLE.apply_to("`"),
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::cli::up_to_date_lockfile;
|
use crate::cli::up_to_date_lockfile;
|
||||||
use anyhow::Context;
|
use anyhow::Context as _;
|
||||||
use clap::Args;
|
use clap::Args;
|
||||||
use fs_err::tokio as fs;
|
use fs_err::tokio as fs;
|
||||||
use pesde::{
|
use pesde::{
|
||||||
|
@ -8,7 +8,7 @@ use pesde::{
|
||||||
source::ids::{PackageId, VersionId},
|
source::ids::{PackageId, VersionId},
|
||||||
Project,
|
Project,
|
||||||
};
|
};
|
||||||
use std::{path::PathBuf, str::FromStr};
|
use std::{path::PathBuf, str::FromStr as _};
|
||||||
|
|
||||||
#[derive(Debug, Args)]
|
#[derive(Debug, Args)]
|
||||||
pub struct PatchCommitCommand {
|
pub struct PatchCommitCommand {
|
||||||
|
|
|
@ -3,7 +3,7 @@ use crate::cli::{
|
||||||
style::{ERROR_PREFIX, ERROR_STYLE, SUCCESS_STYLE, WARN_PREFIX},
|
style::{ERROR_PREFIX, ERROR_STYLE, SUCCESS_STYLE, WARN_PREFIX},
|
||||||
up_to_date_lockfile,
|
up_to_date_lockfile,
|
||||||
};
|
};
|
||||||
use anyhow::Context;
|
use anyhow::Context as _;
|
||||||
use async_compression::Level;
|
use async_compression::Level;
|
||||||
use clap::Args;
|
use clap::Args;
|
||||||
use console::style;
|
use console::style;
|
||||||
|
@ -15,7 +15,9 @@ use pesde::{
|
||||||
source::{
|
source::{
|
||||||
pesde::{specifier::PesdeDependencySpecifier, PesdePackageSource},
|
pesde::{specifier::PesdeDependencySpecifier, PesdePackageSource},
|
||||||
specifiers::DependencySpecifiers,
|
specifiers::DependencySpecifiers,
|
||||||
traits::{GetTargetOptions, PackageRef, PackageSource, RefreshOptions, ResolveOptions},
|
traits::{
|
||||||
|
GetTargetOptions, PackageRef as _, PackageSource as _, RefreshOptions, ResolveOptions,
|
||||||
|
},
|
||||||
workspace::{
|
workspace::{
|
||||||
specifier::{VersionType, VersionTypeOrReq},
|
specifier::{VersionType, VersionTypeOrReq},
|
||||||
WorkspacePackageSource,
|
WorkspacePackageSource,
|
||||||
|
@ -24,12 +26,17 @@ use pesde::{
|
||||||
},
|
},
|
||||||
Project, RefreshedSources, DEFAULT_INDEX_NAME, MANIFEST_FILE_NAME,
|
Project, RefreshedSources, DEFAULT_INDEX_NAME, MANIFEST_FILE_NAME,
|
||||||
};
|
};
|
||||||
|
use relative_path::RelativePath;
|
||||||
use reqwest::{header::AUTHORIZATION, StatusCode};
|
use reqwest::{header::AUTHORIZATION, StatusCode};
|
||||||
use semver::VersionReq;
|
use semver::VersionReq;
|
||||||
use std::{path::PathBuf, sync::Arc};
|
use std::{
|
||||||
|
collections::{BTreeMap, BTreeSet},
|
||||||
|
path::PathBuf,
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
use tempfile::Builder;
|
use tempfile::Builder;
|
||||||
use tokio::{
|
use tokio::{
|
||||||
io::{AsyncSeekExt, AsyncWriteExt},
|
io::{AsyncSeekExt as _, AsyncWriteExt as _},
|
||||||
task::JoinSet,
|
task::JoinSet,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -105,7 +112,7 @@ impl PublishCommand {
|
||||||
|
|
||||||
if manifest.target.lib_path().is_none()
|
if manifest.target.lib_path().is_none()
|
||||||
&& manifest.target.bin_path().is_none()
|
&& manifest.target.bin_path().is_none()
|
||||||
&& manifest.target.scripts().is_none_or(|s| s.is_empty())
|
&& manifest.target.scripts().is_none_or(BTreeMap::is_empty)
|
||||||
{
|
{
|
||||||
anyhow::bail!("no exports found in target");
|
anyhow::bail!("no exports found in target");
|
||||||
}
|
}
|
||||||
|
@ -114,7 +121,7 @@ impl PublishCommand {
|
||||||
manifest.target,
|
manifest.target,
|
||||||
Target::Roblox { .. } | Target::RobloxServer { .. }
|
Target::Roblox { .. } | Target::RobloxServer { .. }
|
||||||
) {
|
) {
|
||||||
if manifest.target.build_files().is_none_or(|f| f.is_empty()) {
|
if manifest.target.build_files().is_none_or(BTreeSet::is_empty) {
|
||||||
anyhow::bail!("no build files found in target");
|
anyhow::bail!("no build files found in target");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,8 +200,14 @@ impl PublishCommand {
|
||||||
let mut display_build_files: Vec<String> = vec![];
|
let mut display_build_files: Vec<String> = vec![];
|
||||||
|
|
||||||
let (lib_path, bin_path, scripts, target_kind) = (
|
let (lib_path, bin_path, scripts, target_kind) = (
|
||||||
manifest.target.lib_path().map(|p| p.to_relative_path_buf()),
|
manifest
|
||||||
manifest.target.bin_path().map(|p| p.to_relative_path_buf()),
|
.target
|
||||||
|
.lib_path()
|
||||||
|
.map(RelativePath::to_relative_path_buf),
|
||||||
|
manifest
|
||||||
|
.target
|
||||||
|
.bin_path()
|
||||||
|
.map(RelativePath::to_relative_path_buf),
|
||||||
manifest.target.scripts().cloned(),
|
manifest.target.scripts().cloned(),
|
||||||
manifest.target.kind(),
|
manifest.target.kind(),
|
||||||
);
|
);
|
||||||
|
@ -207,7 +220,7 @@ impl PublishCommand {
|
||||||
|
|
||||||
let mut paths = matching_globs(
|
let mut paths = matching_globs(
|
||||||
project.package_dir(),
|
project.package_dir(),
|
||||||
manifest.includes.iter().map(|s| s.as_str()),
|
manifest.includes.iter().map(String::as_str),
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
|
@ -247,13 +260,13 @@ impl PublishCommand {
|
||||||
path.display(),
|
path.display(),
|
||||||
ScriptName::RobloxSyncConfigGenerator
|
ScriptName::RobloxSyncConfigGenerator
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
anyhow::bail!(
|
|
||||||
"forbidden file {} was included at `{}`",
|
|
||||||
file_name.to_string_lossy(),
|
|
||||||
path.display()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
anyhow::bail!(
|
||||||
|
"forbidden file {} was included at `{}`",
|
||||||
|
file_name.to_string_lossy(),
|
||||||
|
path.display()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,9 +276,9 @@ impl PublishCommand {
|
||||||
.any(|ct| ct == std::path::Component::Normal(ignored_path.as_ref()))
|
.any(|ct| ct == std::path::Component::Normal(ignored_path.as_ref()))
|
||||||
}) {
|
}) {
|
||||||
anyhow::bail!(
|
anyhow::bail!(
|
||||||
r#"forbidden file {ignored_path} was included.
|
r"forbidden file {ignored_path} was included.
|
||||||
info: if this was a toolchain manager's manifest file, do not include it due to it possibly messing with user scripts
|
info: if this was a toolchain manager's manifest file, do not include it due to it possibly messing with user scripts
|
||||||
info: otherwise, the file was deemed unnecessary, if you don't understand why, please contact the maintainers"#,
|
info: otherwise, the file was deemed unnecessary, if you don't understand why, please contact the maintainers",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -301,9 +314,8 @@ info: otherwise, the file was deemed unnecessary, if you don't understand why, p
|
||||||
.next()
|
.next()
|
||||||
.with_context(|| format!("{name} must contain at least one part"))?;
|
.with_context(|| format!("{name} must contain at least one part"))?;
|
||||||
|
|
||||||
let first_part = match first_part {
|
let relative_path::Component::Normal(first_part) = first_part else {
|
||||||
relative_path::Component::Normal(part) => part,
|
anyhow::bail!("{name} must be within project directory");
|
||||||
_ => anyhow::bail!("{name} must be within project directory"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if paths.insert(
|
if paths.insert(
|
||||||
|
@ -483,8 +495,10 @@ info: otherwise, the file was deemed unnecessary, if you don't understand why, p
|
||||||
VersionReq::STAR
|
VersionReq::STAR
|
||||||
}
|
}
|
||||||
VersionTypeOrReq::Req(r) => r,
|
VersionTypeOrReq::Req(r) => r,
|
||||||
v => VersionReq::parse(&format!("{v}{}", manifest.version))
|
VersionTypeOrReq::VersionType(v) => {
|
||||||
.with_context(|| format!("failed to parse version for {v}"))?,
|
VersionReq::parse(&format!("{v}{}", manifest.version))
|
||||||
|
.with_context(|| format!("failed to parse version for {v}"))?
|
||||||
|
}
|
||||||
},
|
},
|
||||||
index: manifest
|
index: manifest
|
||||||
.indices
|
.indices
|
||||||
|
@ -528,8 +542,7 @@ info: otherwise, the file was deemed unnecessary, if you don't understand why, p
|
||||||
manifest
|
manifest
|
||||||
.repository
|
.repository
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|r| r.as_str())
|
.map_or("(none)", url::Url::as_str)
|
||||||
.unwrap_or("(none)")
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let roblox_target = roblox_target.is_some_and(|_| true);
|
let roblox_target = roblox_target.is_some_and(|_| true);
|
||||||
|
@ -540,7 +553,7 @@ info: otherwise, the file was deemed unnecessary, if you don't understand why, p
|
||||||
manifest
|
manifest
|
||||||
.target
|
.target
|
||||||
.lib_path()
|
.lib_path()
|
||||||
.map_or_else(|| "(none)".to_string(), |p| p.to_string())
|
.map_or_else(|| "(none)".to_string(), ToString::to_string)
|
||||||
);
|
);
|
||||||
|
|
||||||
if roblox_target {
|
if roblox_target {
|
||||||
|
@ -551,7 +564,7 @@ info: otherwise, the file was deemed unnecessary, if you don't understand why, p
|
||||||
manifest
|
manifest
|
||||||
.target
|
.target
|
||||||
.bin_path()
|
.bin_path()
|
||||||
.map_or_else(|| "(none)".to_string(), |p| p.to_string())
|
.map_or_else(|| "(none)".to_string(), ToString::to_string)
|
||||||
);
|
);
|
||||||
println!(
|
println!(
|
||||||
"\tscripts: {}",
|
"\tscripts: {}",
|
||||||
|
@ -706,10 +719,10 @@ info: otherwise, the file was deemed unnecessary, if you don't understand why, p
|
||||||
.await;
|
.await;
|
||||||
if project.workspace_dir().is_some() {
|
if project.workspace_dir().is_some() {
|
||||||
return result;
|
return result;
|
||||||
} else {
|
|
||||||
display_err(result, " occurred publishing workspace root");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
display_err(result, " occurred publishing workspace root");
|
||||||
|
|
||||||
run_on_workspace_members(&project, |project| {
|
run_on_workspace_members(&project, |project| {
|
||||||
let reqwest = reqwest.clone();
|
let reqwest = reqwest.clone();
|
||||||
let this = self.clone();
|
let this = self.clone();
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::str::FromStr;
|
use std::str::FromStr as _;
|
||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context as _;
|
||||||
use clap::Args;
|
use clap::Args;
|
||||||
|
|
||||||
use crate::cli::{
|
use crate::cli::{
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
use crate::cli::up_to_date_lockfile;
|
use crate::cli::up_to_date_lockfile;
|
||||||
use anyhow::Context;
|
use anyhow::Context as _;
|
||||||
use clap::Args;
|
use clap::Args;
|
||||||
use futures::{StreamExt, TryStreamExt};
|
use futures::{StreamExt as _, TryStreamExt as _};
|
||||||
use pesde::{
|
use pesde::{
|
||||||
errors::{ManifestReadError, WorkspaceMembersError},
|
errors::{ManifestReadError, WorkspaceMembersError},
|
||||||
linking::generator::generate_bin_linking_module,
|
linking::generator::generate_bin_linking_module,
|
||||||
names::{PackageName, PackageNames},
|
names::{PackageName, PackageNames},
|
||||||
source::traits::{GetTargetOptions, PackageRef, PackageSource, RefreshOptions},
|
source::traits::{GetTargetOptions, PackageRef as _, PackageSource as _, RefreshOptions},
|
||||||
Project, MANIFEST_FILE_NAME,
|
Project, MANIFEST_FILE_NAME,
|
||||||
};
|
};
|
||||||
use relative_path::RelativePathBuf;
|
use relative_path::RelativePathBuf;
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashSet, env::current_dir, ffi::OsString, io::Write, path::Path, process::Command,
|
collections::HashSet, env::current_dir, ffi::OsString, io::Write as _, path::Path,
|
||||||
sync::Arc,
|
process::Command, sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Args)]
|
#[derive(Debug, Args)]
|
||||||
|
@ -51,7 +51,7 @@ impl RunCommand {
|
||||||
|
|
||||||
drop(caller);
|
drop(caller);
|
||||||
|
|
||||||
std::process::exit(status.code().unwrap_or(1))
|
std::process::exit(status.code().unwrap_or(1i32))
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(package_or_script) = self.package_or_script else {
|
let Some(package_or_script) = self.package_or_script else {
|
||||||
|
@ -133,7 +133,7 @@ impl RunCommand {
|
||||||
);
|
);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
let relative_path = RelativePathBuf::from(package_or_script);
|
let relative_path = RelativePathBuf::from(package_or_script);
|
||||||
let path = relative_path.to_path(project.package_dir());
|
let path = relative_path.to_path(project.package_dir());
|
||||||
|
@ -158,8 +158,10 @@ impl RunCommand {
|
||||||
|
|
||||||
let members = members
|
let members = members
|
||||||
.map(|res| {
|
.map(|res| {
|
||||||
res.map_err(anyhow::Error::from)
|
res.map_err(anyhow::Error::from)?
|
||||||
.and_then(|(path, _)| path.canonicalize().map_err(Into::into))
|
.0
|
||||||
|
.canonicalize()
|
||||||
|
.map_err(anyhow::Error::from)
|
||||||
})
|
})
|
||||||
.chain(futures::stream::once(async {
|
.chain(futures::stream::once(async {
|
||||||
workspace_dir.canonicalize().map_err(Into::into)
|
workspace_dir.canonicalize().map_err(Into::into)
|
||||||
|
@ -169,7 +171,7 @@ impl RunCommand {
|
||||||
.context("failed to collect workspace members")?;
|
.context("failed to collect workspace members")?;
|
||||||
|
|
||||||
let root = 'finder: {
|
let root = 'finder: {
|
||||||
let mut current_path = path.to_path_buf();
|
let mut current_path = path.clone();
|
||||||
loop {
|
loop {
|
||||||
let canonical_path = current_path
|
let canonical_path = current_path
|
||||||
.canonicalize()
|
.canonicalize()
|
||||||
|
|
|
@ -3,7 +3,7 @@ use crate::cli::{
|
||||||
version::replace_pesde_bin_exe,
|
version::replace_pesde_bin_exe,
|
||||||
HOME_DIR,
|
HOME_DIR,
|
||||||
};
|
};
|
||||||
use anyhow::Context;
|
use anyhow::Context as _;
|
||||||
use clap::Args;
|
use clap::Args;
|
||||||
use console::style;
|
use console::style;
|
||||||
use std::env::current_exe;
|
use std::env::current_exe;
|
||||||
|
@ -22,15 +22,16 @@ impl SelfInstallCommand {
|
||||||
{
|
{
|
||||||
if !self.skip_add_to_path {
|
if !self.skip_add_to_path {
|
||||||
use crate::cli::style::WARN_STYLE;
|
use crate::cli::style::WARN_STYLE;
|
||||||
use anyhow::Context;
|
use anyhow::Context as _;
|
||||||
use windows_registry::CURRENT_USER;
|
use windows_registry::CURRENT_USER;
|
||||||
|
|
||||||
|
let bin_dir = crate::cli::bin_dir().await?;
|
||||||
|
|
||||||
let env = CURRENT_USER
|
let env = CURRENT_USER
|
||||||
.create("Environment")
|
.create("Environment")
|
||||||
.context("failed to open Environment key")?;
|
.context("failed to open Environment key")?;
|
||||||
let path = env.get_string("Path").context("failed to get Path value")?;
|
let path = env.get_string("Path").context("failed to get Path value")?;
|
||||||
|
|
||||||
let bin_dir = crate::cli::bin_dir().await?;
|
|
||||||
let bin_dir = bin_dir.to_string_lossy();
|
let bin_dir = bin_dir.to_string_lossy();
|
||||||
|
|
||||||
let exists = path.split(';').any(|part| *part == bin_dir);
|
let exists = path.split(';').any(|part| *part == bin_dir);
|
||||||
|
@ -53,7 +54,7 @@ impl SelfInstallCommand {
|
||||||
CLI_STYLE.apply_to(env!("CARGO_BIN_NAME")),
|
CLI_STYLE.apply_to(env!("CARGO_BIN_NAME")),
|
||||||
ADDED_STYLE.apply_to(env!("CARGO_PKG_VERSION")),
|
ADDED_STYLE.apply_to(env!("CARGO_PKG_VERSION")),
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
{
|
{
|
||||||
|
@ -68,7 +69,7 @@ and then restart your shell.
|
||||||
ADDED_STYLE.apply_to(env!("CARGO_PKG_VERSION")),
|
ADDED_STYLE.apply_to(env!("CARGO_PKG_VERSION")),
|
||||||
style(format!(r#"export PATH="$PATH:$HOME/{HOME_DIR}/bin""#)).green(),
|
style(format!(r#"export PATH="$PATH:$HOME/{HOME_DIR}/bin""#)).green(),
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
replace_pesde_bin_exe(¤t_exe().context("failed to get current exe path")?).await?;
|
replace_pesde_bin_exe(¤t_exe().context("failed to get current exe path")?).await?;
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ use crate::{
|
||||||
},
|
},
|
||||||
util::no_build_metadata,
|
util::no_build_metadata,
|
||||||
};
|
};
|
||||||
use anyhow::Context;
|
use anyhow::Context as _;
|
||||||
use clap::Args;
|
use clap::Args;
|
||||||
use pesde::engine::EngineKind;
|
use pesde::engine::EngineKind;
|
||||||
use semver::VersionReq;
|
use semver::VersionReq;
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use crate::cli::{get_index, style::SUCCESS_STYLE};
|
use crate::cli::{get_index, style::SUCCESS_STYLE};
|
||||||
use anyhow::Context;
|
use anyhow::Context as _;
|
||||||
use clap::Args;
|
use clap::Args;
|
||||||
use pesde::{
|
use pesde::{
|
||||||
manifest::target::TargetKind,
|
manifest::target::TargetKind,
|
||||||
names::PackageName,
|
names::PackageName,
|
||||||
source::{
|
source::{
|
||||||
pesde::PesdePackageSource,
|
pesde::PesdePackageSource,
|
||||||
traits::{PackageSource, RefreshOptions},
|
traits::{PackageSource as _, RefreshOptions},
|
||||||
},
|
},
|
||||||
Project,
|
Project,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::cli::{auth::Tokens, home_dir};
|
use crate::cli::{auth::Tokens, home_dir};
|
||||||
use anyhow::Context;
|
use anyhow::Context as _;
|
||||||
use fs_err::tokio as fs;
|
use fs_err::tokio as fs;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
|
|
|
@ -6,7 +6,7 @@ use crate::cli::{
|
||||||
style::{ADDED_STYLE, REMOVED_STYLE, WARN_PREFIX},
|
style::{ADDED_STYLE, REMOVED_STYLE, WARN_PREFIX},
|
||||||
up_to_date_lockfile,
|
up_to_date_lockfile,
|
||||||
};
|
};
|
||||||
use anyhow::Context;
|
use anyhow::Context as _;
|
||||||
use console::style;
|
use console::style;
|
||||||
use fs_err::tokio as fs;
|
use fs_err::tokio as fs;
|
||||||
use pesde::{
|
use pesde::{
|
||||||
|
@ -19,7 +19,7 @@ use pesde::{
|
||||||
source::{
|
source::{
|
||||||
pesde::PesdePackageSource,
|
pesde::PesdePackageSource,
|
||||||
refs::PackageRefs,
|
refs::PackageRefs,
|
||||||
traits::{PackageRef, RefreshOptions},
|
traits::{PackageRef as _, RefreshOptions},
|
||||||
PackageSources,
|
PackageSources,
|
||||||
},
|
},
|
||||||
version_matches, Project, RefreshedSources, LOCKFILE_FILE_NAME, MANIFEST_FILE_NAME,
|
version_matches, Project, RefreshedSources, LOCKFILE_FILE_NAME, MANIFEST_FILE_NAME,
|
||||||
|
@ -452,8 +452,8 @@ pub async fn install(
|
||||||
|
|
||||||
print_package_diff(
|
print_package_diff(
|
||||||
&format!("{} {}:", manifest.name, manifest.target),
|
&format!("{} {}:", manifest.name, manifest.target),
|
||||||
old_graph,
|
&old_graph,
|
||||||
new_lockfile.graph,
|
&new_lockfile.graph,
|
||||||
);
|
);
|
||||||
|
|
||||||
println!("done in {:.2}s", elapsed.as_secs_f64());
|
println!("done in {:.2}s", elapsed.as_secs_f64());
|
||||||
|
@ -463,20 +463,20 @@ pub async fn install(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prints the difference between two graphs.
|
/// Prints the difference between two graphs.
|
||||||
pub fn print_package_diff(prefix: &str, old_graph: DependencyGraph, new_graph: DependencyGraph) {
|
pub fn print_package_diff(prefix: &str, old_graph: &DependencyGraph, new_graph: &DependencyGraph) {
|
||||||
let mut old_pkg_map = BTreeMap::new();
|
let mut old_pkg_map = BTreeMap::new();
|
||||||
let mut old_direct_pkg_map = BTreeMap::new();
|
let mut old_direct_pkg_map = BTreeMap::new();
|
||||||
let mut new_pkg_map = BTreeMap::new();
|
let mut new_pkg_map = BTreeMap::new();
|
||||||
let mut new_direct_pkg_map = BTreeMap::new();
|
let mut new_direct_pkg_map = BTreeMap::new();
|
||||||
|
|
||||||
for (id, node) in &old_graph {
|
for (id, node) in old_graph {
|
||||||
old_pkg_map.insert(id, node);
|
old_pkg_map.insert(id, node);
|
||||||
if node.direct.is_some() {
|
if node.direct.is_some() {
|
||||||
old_direct_pkg_map.insert(id, node);
|
old_direct_pkg_map.insert(id, node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (id, node) in &new_graph {
|
for (id, node) in new_graph {
|
||||||
new_pkg_map.insert(id, node);
|
new_pkg_map.insert(id, node);
|
||||||
if node.direct.is_some() {
|
if node.direct.is_some() {
|
||||||
new_direct_pkg_map.insert(id, node);
|
new_direct_pkg_map.insert(id, node);
|
||||||
|
|
|
@ -2,9 +2,9 @@ use crate::cli::{
|
||||||
config::read_config,
|
config::read_config,
|
||||||
style::{ERROR_STYLE, INFO_STYLE, WARN_STYLE},
|
style::{ERROR_STYLE, INFO_STYLE, WARN_STYLE},
|
||||||
};
|
};
|
||||||
use anyhow::Context;
|
use anyhow::Context as _;
|
||||||
use fs_err::tokio as fs;
|
use fs_err::tokio as fs;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt as _;
|
||||||
use pesde::{
|
use pesde::{
|
||||||
errors::ManifestReadError,
|
errors::ManifestReadError,
|
||||||
lockfile::Lockfile,
|
lockfile::Lockfile,
|
||||||
|
@ -135,11 +135,7 @@ pub async fn up_to_date_lockfile(project: &Project) -> anyhow::Result<Option<Loc
|
||||||
|
|
||||||
tracing::debug!("dependencies are the same: {same_dependencies}");
|
tracing::debug!("dependencies are the same: {same_dependencies}");
|
||||||
|
|
||||||
Ok(if same_dependencies {
|
Ok(same_dependencies.then_some(lockfile))
|
||||||
Some(lockfile)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -172,26 +168,25 @@ impl VersionedPackageName {
|
||||||
self,
|
self,
|
||||||
graph: &pesde::graph::DependencyGraph,
|
graph: &pesde::graph::DependencyGraph,
|
||||||
) -> anyhow::Result<pesde::source::ids::PackageId> {
|
) -> anyhow::Result<pesde::source::ids::PackageId> {
|
||||||
let version_id = match self.1 {
|
let version_id = if let Some(version) = self.1 {
|
||||||
Some(version) => version,
|
version
|
||||||
None => {
|
} else {
|
||||||
let versions = graph
|
let versions = graph
|
||||||
.keys()
|
.keys()
|
||||||
.filter(|id| *id.name() == self.0)
|
.filter(|id| *id.name() == self.0)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
match versions.len() {
|
match versions.len() {
|
||||||
0 => anyhow::bail!("package not found"),
|
0 => anyhow::bail!("package not found"),
|
||||||
1 => versions[0].version_id().clone(),
|
1 => versions[0].version_id().clone(),
|
||||||
_ => anyhow::bail!(
|
_ => anyhow::bail!(
|
||||||
"multiple versions found, please specify one of: {}",
|
"multiple versions found, please specify one of: {}",
|
||||||
versions
|
versions
|
||||||
.iter()
|
.iter()
|
||||||
.map(|v| v.to_string())
|
.map(ToString::to_string)
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join(", ")
|
.join(", ")
|
||||||
),
|
),
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -336,18 +331,17 @@ pub async fn get_index(project: &Project, index: Option<&str>) -> anyhow::Result
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
match index_url {
|
if let Some(url) = index_url {
|
||||||
Some(url) => Ok(url),
|
return Ok(url);
|
||||||
None => {
|
|
||||||
let index_name = index.unwrap_or(DEFAULT_INDEX_NAME);
|
|
||||||
|
|
||||||
manifest
|
|
||||||
.unwrap()
|
|
||||||
.indices
|
|
||||||
.remove(index_name)
|
|
||||||
.with_context(|| format!("index {index_name} not found in manifest"))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let index_name = index.unwrap_or(DEFAULT_INDEX_NAME);
|
||||||
|
|
||||||
|
manifest
|
||||||
|
.unwrap()
|
||||||
|
.indices
|
||||||
|
.remove(index_name)
|
||||||
|
.with_context(|| format!("index {index_name} not found in manifest"))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dep_type_to_key(dep_type: DependencyType) -> &'static str {
|
pub fn dep_type_to_key(dep_type: DependencyType) -> &'static str {
|
||||||
|
|
|
@ -187,7 +187,7 @@ impl<W: Write + Send + Sync + 'static> PatchesReporter for CliReporter<W> {
|
||||||
|
|
||||||
CliPatchProgressReporter {
|
CliPatchProgressReporter {
|
||||||
root_reporter: self,
|
root_reporter: self,
|
||||||
name: name.to_string(),
|
name,
|
||||||
progress,
|
progress,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,19 +9,19 @@ use crate::{
|
||||||
},
|
},
|
||||||
util::no_build_metadata,
|
util::no_build_metadata,
|
||||||
};
|
};
|
||||||
use anyhow::Context;
|
use anyhow::Context as _;
|
||||||
use console::Style;
|
use console::Style;
|
||||||
use fs_err::tokio as fs;
|
use fs_err::tokio as fs;
|
||||||
use jiff::SignedDuration;
|
use jiff::SignedDuration;
|
||||||
use pesde::{
|
use pesde::{
|
||||||
engine::{
|
engine::{
|
||||||
source::{
|
source::{
|
||||||
traits::{DownloadOptions, EngineSource, ResolveOptions},
|
traits::{DownloadOptions, EngineSource as _, ResolveOptions},
|
||||||
EngineSources,
|
EngineSources,
|
||||||
},
|
},
|
||||||
EngineKind,
|
EngineKind,
|
||||||
},
|
},
|
||||||
reporters::DownloadsReporter,
|
reporters::DownloadsReporter as _,
|
||||||
version_matches,
|
version_matches,
|
||||||
};
|
};
|
||||||
use semver::{Version, VersionReq};
|
use semver::{Version, VersionReq};
|
||||||
|
@ -167,7 +167,7 @@ pub async fn get_or_download_engine(
|
||||||
.with_extension(std::env::consts::EXE_EXTENSION));
|
.with_extension(std::env::consts::EXE_EXTENSION));
|
||||||
}
|
}
|
||||||
|
|
||||||
let path = run_with_reporter(|_, root_progress, reporter| async {
|
run_with_reporter(|_, root_progress, reporter| async {
|
||||||
let root_progress = root_progress;
|
let root_progress = root_progress;
|
||||||
let reporter = reporter;
|
let reporter = reporter;
|
||||||
|
|
||||||
|
@ -221,19 +221,17 @@ pub async fn get_or_download_engine(
|
||||||
.await
|
.await
|
||||||
.context("failed to write to file")?;
|
.context("failed to write to file")?;
|
||||||
|
|
||||||
|
make_executable(&path)
|
||||||
|
.await
|
||||||
|
.context("failed to make downloaded version executable")?;
|
||||||
|
|
||||||
|
if engine != EngineKind::Pesde {
|
||||||
|
make_linker_if_needed(engine).await?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok::<_, anyhow::Error>(path)
|
Ok::<_, anyhow::Error>(path)
|
||||||
})
|
})
|
||||||
.await?;
|
.await
|
||||||
|
|
||||||
make_executable(&path)
|
|
||||||
.await
|
|
||||||
.context("failed to make downloaded version executable")?;
|
|
||||||
|
|
||||||
if engine != EngineKind::Pesde {
|
|
||||||
make_linker_if_needed(engine).await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(path)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "trace")]
|
#[instrument(level = "trace")]
|
||||||
|
@ -243,7 +241,7 @@ pub async fn replace_pesde_bin_exe(with: &Path) -> anyhow::Result<()> {
|
||||||
.join(EngineKind::Pesde.to_string())
|
.join(EngineKind::Pesde.to_string())
|
||||||
.with_extension(std::env::consts::EXE_EXTENSION);
|
.with_extension(std::env::consts::EXE_EXTENSION);
|
||||||
|
|
||||||
let exists = bin_exe_path.exists();
|
let exists = fs::metadata(&bin_exe_path).await.is_ok();
|
||||||
|
|
||||||
if cfg!(target_os = "linux") && exists {
|
if cfg!(target_os = "linux") && exists {
|
||||||
fs::remove_file(&bin_exe_path)
|
fs::remove_file(&bin_exe_path)
|
||||||
|
@ -277,9 +275,8 @@ pub async fn make_linker_if_needed(engine: EngineKind) -> anyhow::Result<()> {
|
||||||
let linker = bin_dir
|
let linker = bin_dir
|
||||||
.join(engine.to_string())
|
.join(engine.to_string())
|
||||||
.with_extension(std::env::consts::EXE_EXTENSION);
|
.with_extension(std::env::consts::EXE_EXTENSION);
|
||||||
let exists = linker.exists();
|
|
||||||
|
|
||||||
if !exists {
|
if fs::metadata(&linker).await.is_err() {
|
||||||
let exe = current_exe().context("failed to get current exe path")?;
|
let exe = current_exe().context("failed to get current exe path")?;
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
graph::{DependencyGraph, DependencyGraphNode},
|
graph::{DependencyGraph, DependencyGraphNode},
|
||||||
reporters::{DownloadProgressReporter, DownloadsReporter},
|
reporters::{DownloadProgressReporter as _, DownloadsReporter},
|
||||||
source::{
|
source::{
|
||||||
fs::PackageFs,
|
fs::PackageFs,
|
||||||
ids::PackageId,
|
ids::PackageId,
|
||||||
traits::{DownloadOptions, PackageRef, PackageSource, RefreshOptions},
|
traits::{DownloadOptions, PackageRef as _, PackageSource as _, RefreshOptions},
|
||||||
},
|
},
|
||||||
Project, RefreshedSources,
|
Project, RefreshedSources,
|
||||||
};
|
};
|
||||||
|
@ -12,7 +12,7 @@ use async_stream::try_stream;
|
||||||
use futures::Stream;
|
use futures::Stream;
|
||||||
use std::{num::NonZeroUsize, sync::Arc};
|
use std::{num::NonZeroUsize, sync::Arc};
|
||||||
use tokio::{sync::Semaphore, task::JoinSet};
|
use tokio::{sync::Semaphore, task::JoinSet};
|
||||||
use tracing::{instrument, Instrument};
|
use tracing::{instrument, Instrument as _};
|
||||||
|
|
||||||
/// Options for downloading.
|
/// Options for downloading.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -116,7 +116,7 @@ impl Project {
|
||||||
|
|
||||||
let _permit = semaphore.acquire().await;
|
let _permit = semaphore.acquire().await;
|
||||||
|
|
||||||
if let Some(ref progress_reporter) = progress_reporter {
|
if let Some(progress_reporter) = &progress_reporter {
|
||||||
progress_reporter.report_start();
|
progress_reporter.report_start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,12 +9,12 @@ use crate::{
|
||||||
reporters::{DownloadsReporter, PatchesReporter},
|
reporters::{DownloadsReporter, PatchesReporter},
|
||||||
source::{
|
source::{
|
||||||
ids::PackageId,
|
ids::PackageId,
|
||||||
traits::{GetTargetOptions, PackageRef, PackageSource},
|
traits::{GetTargetOptions, PackageRef as _, PackageSource as _},
|
||||||
},
|
},
|
||||||
Project, RefreshedSources, SCRIPTS_LINK_FOLDER,
|
Project, RefreshedSources, SCRIPTS_LINK_FOLDER,
|
||||||
};
|
};
|
||||||
use fs_err::tokio as fs;
|
use fs_err::tokio as fs;
|
||||||
use futures::TryStreamExt;
|
use futures::TryStreamExt as _;
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
convert::Infallible,
|
convert::Infallible,
|
||||||
|
@ -24,11 +24,11 @@ use std::{
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
use tokio::{pin, task::JoinSet};
|
use tokio::{pin, task::JoinSet};
|
||||||
use tracing::{instrument, Instrument};
|
use tracing::{instrument, Instrument as _};
|
||||||
|
|
||||||
/// Hooks to perform actions after certain events during download and linking.
|
/// Hooks to perform actions after certain events during download and linking.
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
pub trait DownloadAndLinkHooks {
|
pub trait DownloadAndLinkHooks: Send + Sync {
|
||||||
/// The error type for the hooks.
|
/// The error type for the hooks.
|
||||||
type Error: std::error::Error + Send + Sync + 'static;
|
type Error: std::error::Error + Send + Sync + 'static;
|
||||||
|
|
||||||
|
@ -89,6 +89,7 @@ where
|
||||||
Hooks: DownloadAndLinkHooks + Send + Sync + 'static,
|
Hooks: DownloadAndLinkHooks + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
/// Creates a new download options with the given reqwest client and reporter.
|
/// Creates a new download options with the given reqwest client and reporter.
|
||||||
|
#[must_use]
|
||||||
pub fn new(reqwest: reqwest::Client) -> Self {
|
pub fn new(reqwest: reqwest::Client) -> Self {
|
||||||
Self {
|
Self {
|
||||||
reqwest,
|
reqwest,
|
||||||
|
@ -102,36 +103,42 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the downloads reporter.
|
/// Sets the downloads reporter.
|
||||||
|
#[must_use]
|
||||||
pub fn reporter(mut self, reporter: impl Into<Arc<Reporter>>) -> Self {
|
pub fn reporter(mut self, reporter: impl Into<Arc<Reporter>>) -> Self {
|
||||||
self.reporter.replace(reporter.into());
|
self.reporter.replace(reporter.into());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the download and link hooks.
|
/// Sets the download and link hooks.
|
||||||
|
#[must_use]
|
||||||
pub fn hooks(mut self, hooks: impl Into<Arc<Hooks>>) -> Self {
|
pub fn hooks(mut self, hooks: impl Into<Arc<Hooks>>) -> Self {
|
||||||
self.hooks.replace(hooks.into());
|
self.hooks.replace(hooks.into());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the refreshed sources.
|
/// Sets the refreshed sources.
|
||||||
|
#[must_use]
|
||||||
pub fn refreshed_sources(mut self, refreshed_sources: RefreshedSources) -> Self {
|
pub fn refreshed_sources(mut self, refreshed_sources: RefreshedSources) -> Self {
|
||||||
self.refreshed_sources = refreshed_sources;
|
self.refreshed_sources = refreshed_sources;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets whether to skip dev dependencies.
|
/// Sets whether to skip dev dependencies.
|
||||||
|
#[must_use]
|
||||||
pub fn prod(mut self, prod: bool) -> Self {
|
pub fn prod(mut self, prod: bool) -> Self {
|
||||||
self.prod = prod;
|
self.prod = prod;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the max number of concurrent network requests.
|
/// Sets the max number of concurrent network requests.
|
||||||
|
#[must_use]
|
||||||
pub fn network_concurrency(mut self, network_concurrency: NonZeroUsize) -> Self {
|
pub fn network_concurrency(mut self, network_concurrency: NonZeroUsize) -> Self {
|
||||||
self.network_concurrency = network_concurrency;
|
self.network_concurrency = network_concurrency;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets whether to re-install all dependencies even if they are already installed
|
/// Sets whether to re-install all dependencies even if they are already installed
|
||||||
|
#[must_use]
|
||||||
pub fn force(mut self, force: bool) -> Self {
|
pub fn force(mut self, force: bool) -> Self {
|
||||||
self.force = force;
|
self.force = force;
|
||||||
self
|
self
|
||||||
|
@ -294,7 +301,7 @@ impl Project {
|
||||||
node.container_folder_from_project(&id, project, manifest_target_kind)
|
node.container_folder_from_project(&id, project, manifest_target_kind)
|
||||||
.as_path(),
|
.as_path(),
|
||||||
);
|
);
|
||||||
let id = Arc::new(id.clone());
|
let id = Arc::new(id);
|
||||||
let project = project.clone();
|
let project = project.clone();
|
||||||
|
|
||||||
async move {
|
async move {
|
||||||
|
@ -311,7 +318,7 @@ impl Project {
|
||||||
|
|
||||||
Ok::<_, errors::DownloadAndLinkError<Hooks::Error>>((
|
Ok::<_, errors::DownloadAndLinkError<Hooks::Error>>((
|
||||||
Arc::into_inner(id).unwrap(),
|
Arc::into_inner(id).unwrap(),
|
||||||
DependencyGraphNodeWithTarget { node, target },
|
DependencyGraphNodeWithTarget { target, node },
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -39,7 +39,8 @@ impl FromStr for EngineKind {
|
||||||
|
|
||||||
impl EngineKind {
|
impl EngineKind {
|
||||||
/// Returns the source to get this engine from
|
/// Returns the source to get this engine from
|
||||||
pub fn source(&self) -> EngineSources {
|
#[must_use]
|
||||||
|
pub fn source(self) -> EngineSources {
|
||||||
match self {
|
match self {
|
||||||
EngineKind::Pesde => EngineSources::pesde(),
|
EngineKind::Pesde => EngineSources::pesde(),
|
||||||
EngineKind::Lune => EngineSources::lune(),
|
EngineKind::Lune => EngineSources::lune(),
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use futures::StreamExt;
|
use futures::StreamExt as _;
|
||||||
use std::{
|
use std::{
|
||||||
collections::BTreeSet,
|
collections::BTreeSet,
|
||||||
mem::ManuallyDrop,
|
mem::ManuallyDrop,
|
||||||
|
@ -8,10 +8,10 @@ use std::{
|
||||||
task::{Context, Poll},
|
task::{Context, Poll},
|
||||||
};
|
};
|
||||||
use tokio::{
|
use tokio::{
|
||||||
io::{AsyncBufRead, AsyncRead, AsyncReadExt, ReadBuf},
|
io::{AsyncBufRead, AsyncRead, AsyncReadExt as _, ReadBuf},
|
||||||
pin,
|
pin,
|
||||||
};
|
};
|
||||||
use tokio_util::compat::{Compat, FuturesAsyncReadCompatExt};
|
use tokio_util::compat::{Compat, FuturesAsyncReadCompatExt as _};
|
||||||
|
|
||||||
/// The kind of encoding used for the archive
|
/// The kind of encoding used for the archive
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
@ -53,7 +53,7 @@ impl FromStr for ArchiveInfo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) type ArchiveReader = Pin<Box<dyn AsyncBufRead>>;
|
pub(crate) type ArchiveReader = Pin<Box<dyn AsyncBufRead + Send>>;
|
||||||
|
|
||||||
/// An archive
|
/// An archive
|
||||||
pub struct Archive {
|
pub struct Archive {
|
||||||
|
@ -84,9 +84,9 @@ impl AsyncRead for TarReader {
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ArchiveEntryInner {
|
enum ArchiveEntryInner {
|
||||||
Tar(tokio_tar::Entry<tokio_tar::Archive<TarReader>>),
|
Tar(Box<tokio_tar::Entry<tokio_tar::Archive<TarReader>>>),
|
||||||
Zip {
|
Zip {
|
||||||
archive: *mut async_zip::tokio::read::seek::ZipFileReader<std::io::Cursor<Vec<u8>>>,
|
archive: ArchivePointer,
|
||||||
reader: ManuallyDrop<
|
reader: ManuallyDrop<
|
||||||
Compat<
|
Compat<
|
||||||
async_zip::tokio::read::ZipEntryReader<
|
async_zip::tokio::read::ZipEntryReader<
|
||||||
|
@ -105,7 +105,7 @@ impl Drop for ArchiveEntryInner {
|
||||||
Self::Tar(_) => {}
|
Self::Tar(_) => {}
|
||||||
Self::Zip { archive, reader } => unsafe {
|
Self::Zip { archive, reader } => unsafe {
|
||||||
ManuallyDrop::drop(reader);
|
ManuallyDrop::drop(reader);
|
||||||
drop(Box::from_raw(*archive));
|
drop(Box::from_raw(archive.0));
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -131,6 +131,10 @@ impl AsyncRead for ArchiveEntry {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ArchivePointer(*mut async_zip::tokio::read::seek::ZipFileReader<std::io::Cursor<Vec<u8>>>);
|
||||||
|
|
||||||
|
unsafe impl Send for ArchivePointer {}
|
||||||
|
|
||||||
impl Archive {
|
impl Archive {
|
||||||
/// Finds the executable in the archive and returns it as an [`ArchiveEntry`]
|
/// Finds the executable in the archive and returns it as an [`ArchiveEntry`]
|
||||||
pub async fn find_executable(
|
pub async fn find_executable(
|
||||||
|
@ -226,7 +230,7 @@ impl Archive {
|
||||||
|
|
||||||
let path = entry.path()?;
|
let path = entry.path()?;
|
||||||
if path == candidate.path {
|
if path == candidate.path {
|
||||||
return Ok(ArchiveEntry(ArchiveEntryInner::Tar(entry)));
|
return Ok(ArchiveEntry(ArchiveEntryInner::Tar(Box::new(entry))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -269,8 +273,8 @@ impl Archive {
|
||||||
|
|
||||||
let path: &Path = entry.filename().as_str()?.as_ref();
|
let path: &Path = entry.filename().as_str()?.as_ref();
|
||||||
if candidate.path == path {
|
if candidate.path == path {
|
||||||
let ptr = Box::into_raw(Box::new(archive));
|
let ptr = ArchivePointer(Box::into_raw(Box::new(archive)));
|
||||||
let reader = (unsafe { &mut *ptr }).reader_without_entry(i).await?;
|
let reader = (unsafe { &mut *ptr.0 }).reader_without_entry(i).await?;
|
||||||
return Ok(ArchiveEntry(ArchiveEntryInner::Zip {
|
return Ok(ArchiveEntry(ArchiveEntryInner::Zip {
|
||||||
archive: ptr,
|
archive: ptr,
|
||||||
reader: ManuallyDrop::new(reader.compat()),
|
reader: ManuallyDrop::new(reader.compat()),
|
||||||
|
|
|
@ -83,6 +83,7 @@ impl EngineSource for EngineSources {
|
||||||
|
|
||||||
impl EngineSources {
|
impl EngineSources {
|
||||||
/// Returns the source for the pesde engine
|
/// Returns the source for the pesde engine
|
||||||
|
#[must_use]
|
||||||
pub fn pesde() -> Self {
|
pub fn pesde() -> Self {
|
||||||
let mut parts = env!("CARGO_PKG_REPOSITORY").split('/').skip(3);
|
let mut parts = env!("CARGO_PKG_REPOSITORY").split('/').skip(3);
|
||||||
let (owner, repo) = (
|
let (owner, repo) = (
|
||||||
|
@ -102,6 +103,7 @@ impl EngineSources {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the source for the lune engine
|
/// Returns the source for the lune engine
|
||||||
|
#[must_use]
|
||||||
pub fn lune() -> Self {
|
pub fn lune() -> Self {
|
||||||
EngineSources::GitHub(github::GitHubEngineSource {
|
EngineSources::GitHub(github::GitHubEngineSource {
|
||||||
owner: "lune-org".into(),
|
owner: "lune-org".into(),
|
||||||
|
|
|
@ -7,7 +7,7 @@ use crate::{
|
||||||
ids::{PackageId, VersionId},
|
ids::{PackageId, VersionId},
|
||||||
refs::PackageRefs,
|
refs::PackageRefs,
|
||||||
specifiers::DependencySpecifiers,
|
specifiers::DependencySpecifiers,
|
||||||
traits::PackageRef,
|
traits::PackageRef as _,
|
||||||
},
|
},
|
||||||
Project, PACKAGES_CONTAINER_NAME,
|
Project, PACKAGES_CONTAINER_NAME,
|
||||||
};
|
};
|
||||||
|
@ -49,6 +49,7 @@ impl DependencyGraphNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the folder to store the contents of the package in
|
/// Returns the folder to store the contents of the package in
|
||||||
|
#[must_use]
|
||||||
pub fn container_folder(&self, package_id: &PackageId) -> PathBuf {
|
pub fn container_folder(&self, package_id: &PackageId) -> PathBuf {
|
||||||
let (name, v_id) = package_id.parts();
|
let (name, v_id) = package_id.parts();
|
||||||
|
|
||||||
|
@ -68,6 +69,7 @@ impl DependencyGraphNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the folder to store the contents of the package in starting from the project's package directory
|
/// Returns the folder to store the contents of the package in starting from the project's package directory
|
||||||
|
#[must_use]
|
||||||
pub fn container_folder_from_project(
|
pub fn container_folder_from_project(
|
||||||
&self,
|
&self,
|
||||||
package_id: &PackageId,
|
package_id: &PackageId,
|
||||||
|
|
28
src/lib.rs
28
src/lib.rs
|
@ -1,4 +1,5 @@
|
||||||
#![warn(missing_docs, clippy::redundant_closure_for_method_calls)]
|
#![warn(missing_docs)]
|
||||||
|
#![deny(clippy::future_not_send)]
|
||||||
//! A package manager for the Luau programming language, supporting multiple runtimes including Roblox and Lune.
|
//! A package manager for the Luau programming language, supporting multiple runtimes including Roblox and Lune.
|
||||||
//! pesde has its own registry, however it can also use Wally, and Git repositories as package sources.
|
//! pesde has its own registry, however it can also use Wally, and Git repositories as package sources.
|
||||||
//! It has been designed with multiple targets in mind, namely Roblox, Lune, and Luau.
|
//! It has been designed with multiple targets in mind, namely Roblox, Lune, and Luau.
|
||||||
|
@ -7,7 +8,7 @@ use crate::{
|
||||||
lockfile::Lockfile,
|
lockfile::Lockfile,
|
||||||
manifest::{target::TargetKind, Manifest},
|
manifest::{target::TargetKind, Manifest},
|
||||||
source::{
|
source::{
|
||||||
traits::{PackageSource, RefreshOptions},
|
traits::{PackageSource as _, RefreshOptions},
|
||||||
PackageSources,
|
PackageSources,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -19,12 +20,12 @@ use semver::{Version, VersionReq};
|
||||||
use std::{
|
use std::{
|
||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet},
|
||||||
fmt::Debug,
|
fmt::Debug,
|
||||||
hash::{Hash, Hasher},
|
hash::{Hash as _, Hasher as _},
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
use wax::Pattern;
|
use wax::Pattern as _;
|
||||||
|
|
||||||
/// Downloading packages
|
/// Downloading packages
|
||||||
pub mod download;
|
pub mod download;
|
||||||
|
@ -84,12 +85,14 @@ pub struct AuthConfig {
|
||||||
|
|
||||||
impl AuthConfig {
|
impl AuthConfig {
|
||||||
/// Create a new `AuthConfig`
|
/// Create a new `AuthConfig`
|
||||||
|
#[must_use]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
AuthConfig::default()
|
AuthConfig::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the tokens
|
/// Set the tokens
|
||||||
/// Panics if the `AuthConfig` is shared
|
/// Panics if the `AuthConfig` is shared
|
||||||
|
#[must_use]
|
||||||
pub fn with_tokens<I: IntoIterator<Item = (gix::Url, S)>, S: AsRef<str>>(
|
pub fn with_tokens<I: IntoIterator<Item = (gix::Url, S)>, S: AsRef<str>>(
|
||||||
mut self,
|
mut self,
|
||||||
tokens: I,
|
tokens: I,
|
||||||
|
@ -103,17 +106,20 @@ impl AuthConfig {
|
||||||
|
|
||||||
/// Set the git credentials
|
/// Set the git credentials
|
||||||
/// Panics if the `AuthConfig` is shared
|
/// Panics if the `AuthConfig` is shared
|
||||||
|
#[must_use]
|
||||||
pub fn with_git_credentials(mut self, git_credentials: Option<Account>) -> Self {
|
pub fn with_git_credentials(mut self, git_credentials: Option<Account>) -> Self {
|
||||||
Arc::get_mut(&mut self.shared).unwrap().git_credentials = git_credentials;
|
Arc::get_mut(&mut self.shared).unwrap().git_credentials = git_credentials;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the tokens
|
/// Get the tokens
|
||||||
|
#[must_use]
|
||||||
pub fn tokens(&self) -> &HashMap<gix::Url, String> {
|
pub fn tokens(&self) -> &HashMap<gix::Url, String> {
|
||||||
&self.shared.tokens
|
&self.shared.tokens
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the git credentials
|
/// Get the git credentials
|
||||||
|
#[must_use]
|
||||||
pub fn git_credentials(&self) -> Option<&Account> {
|
pub fn git_credentials(&self) -> Option<&Account> {
|
||||||
self.shared.git_credentials.as_ref()
|
self.shared.git_credentials.as_ref()
|
||||||
}
|
}
|
||||||
|
@ -137,6 +143,7 @@ pub struct Project {
|
||||||
|
|
||||||
impl Project {
|
impl Project {
|
||||||
/// Create a new `Project`
|
/// Create a new `Project`
|
||||||
|
#[must_use]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
package_dir: impl AsRef<Path>,
|
package_dir: impl AsRef<Path>,
|
||||||
workspace_dir: Option<impl AsRef<Path>>,
|
workspace_dir: Option<impl AsRef<Path>>,
|
||||||
|
@ -156,26 +163,31 @@ impl Project {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The directory of the package
|
/// The directory of the package
|
||||||
|
#[must_use]
|
||||||
pub fn package_dir(&self) -> &Path {
|
pub fn package_dir(&self) -> &Path {
|
||||||
&self.shared.package_dir
|
&self.shared.package_dir
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The directory of the workspace this package belongs to, if any
|
/// The directory of the workspace this package belongs to, if any
|
||||||
|
#[must_use]
|
||||||
pub fn workspace_dir(&self) -> Option<&Path> {
|
pub fn workspace_dir(&self) -> Option<&Path> {
|
||||||
self.shared.workspace_dir.as_deref()
|
self.shared.workspace_dir.as_deref()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The directory to store general-purpose data
|
/// The directory to store general-purpose data
|
||||||
|
#[must_use]
|
||||||
pub fn data_dir(&self) -> &Path {
|
pub fn data_dir(&self) -> &Path {
|
||||||
&self.shared.data_dir
|
&self.shared.data_dir
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The CAS (content-addressable storage) directory
|
/// The CAS (content-addressable storage) directory
|
||||||
|
#[must_use]
|
||||||
pub fn cas_dir(&self) -> &Path {
|
pub fn cas_dir(&self) -> &Path {
|
||||||
&self.shared.cas_dir
|
&self.shared.cas_dir
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The authentication configuration
|
/// The authentication configuration
|
||||||
|
#[must_use]
|
||||||
pub fn auth_config(&self) -> &AuthConfig {
|
pub fn auth_config(&self) -> &AuthConfig {
|
||||||
&self.shared.auth_config
|
&self.shared.auth_config
|
||||||
}
|
}
|
||||||
|
@ -324,7 +336,7 @@ pub async fn matching_globs<'a, P: AsRef<Path> + Debug, I: IntoIterator<Item = &
|
||||||
paths.insert(if relative {
|
paths.insert(if relative {
|
||||||
relative_path.to_path_buf()
|
relative_path.to_path_buf()
|
||||||
} else {
|
} else {
|
||||||
path.to_path_buf()
|
path.clone()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -339,6 +351,7 @@ pub struct RefreshedSources(Arc<tokio::sync::Mutex<HashSet<u64>>>);
|
||||||
|
|
||||||
impl RefreshedSources {
|
impl RefreshedSources {
|
||||||
/// Create a new empty `RefreshedSources`
|
/// Create a new empty `RefreshedSources`
|
||||||
|
#[must_use]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
RefreshedSources::default()
|
RefreshedSources::default()
|
||||||
}
|
}
|
||||||
|
@ -418,9 +431,9 @@ pub async fn find_roots(
|
||||||
if get_workspace_members(&path).await?.contains(&cwd) {
|
if get_workspace_members(&path).await?.contains(&cwd) {
|
||||||
// initializing a new member of a workspace
|
// initializing a new member of a workspace
|
||||||
return Ok((cwd, Some(path)));
|
return Ok((cwd, Some(path)));
|
||||||
} else {
|
|
||||||
project_root = Some(path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
project_root = Some(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
(None, Some(_)) => unreachable!(),
|
(None, Some(_)) => unreachable!(),
|
||||||
|
@ -434,6 +447,7 @@ pub async fn find_roots(
|
||||||
|
|
||||||
/// Returns whether a version matches a version requirement
|
/// Returns whether a version matches a version requirement
|
||||||
/// Differs from `VersionReq::matches` in that EVERY version matches `*`
|
/// Differs from `VersionReq::matches` in that EVERY version matches `*`
|
||||||
|
#[must_use]
|
||||||
pub fn version_matches(req: &VersionReq, version: &Version) -> bool {
|
pub fn version_matches(req: &VersionReq, version: &Version) -> bool {
|
||||||
*req == VersionReq::STAR || req.matches(version)
|
*req == VersionReq::STAR || req.matches(version)
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,13 +18,13 @@ impl Visitor for TypeVisitor {
|
||||||
let mut declaration_generics = vec![];
|
let mut declaration_generics = vec![];
|
||||||
let mut generics = vec![];
|
let mut generics = vec![];
|
||||||
|
|
||||||
for generic in declaration.generics().iter() {
|
for generic in declaration.generics() {
|
||||||
declaration_generics.push(generic.to_string());
|
declaration_generics.push(generic.to_string());
|
||||||
|
|
||||||
if generic.default_type().is_some() {
|
if generic.default_type().is_some() {
|
||||||
generics.push(generic.parameter().to_string())
|
generics.push(generic.parameter().to_string());
|
||||||
} else {
|
} else {
|
||||||
generics.push(generic.to_string())
|
generics.push(generic.to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,6 +64,7 @@ pub(crate) fn get_file_types(file: &str) -> Vec<String> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate a linking module for a library
|
/// Generate a linking module for a library
|
||||||
|
#[must_use]
|
||||||
pub fn generate_lib_linking_module<I: IntoIterator<Item = S>, S: AsRef<str>>(
|
pub fn generate_lib_linking_module<I: IntoIterator<Item = S>, S: AsRef<str>>(
|
||||||
path: &str,
|
path: &str,
|
||||||
types: I,
|
types: I,
|
||||||
|
@ -119,6 +120,7 @@ fn luau_style_path(path: &Path) -> String {
|
||||||
/// Get the require path for a library
|
/// Get the require path for a library
|
||||||
#[instrument(skip(project_manifest), level = "trace")]
|
#[instrument(skip(project_manifest), level = "trace")]
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
#[must_use]
|
||||||
pub fn get_lib_require_path(
|
pub fn get_lib_require_path(
|
||||||
target: TargetKind,
|
target: TargetKind,
|
||||||
base_dir: &Path,
|
base_dir: &Path,
|
||||||
|
@ -182,26 +184,27 @@ pub fn get_lib_require_path(
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>()
|
.collect::<String>();
|
||||||
.join("");
|
|
||||||
|
|
||||||
return Ok(format!("{prefix}{path}"));
|
return Ok(format!("{prefix}{path}"));
|
||||||
};
|
}
|
||||||
|
|
||||||
Ok(luau_style_path(&path))
|
Ok(luau_style_path(&path))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate a linking module for a binary
|
/// Generate a linking module for a binary
|
||||||
|
#[must_use]
|
||||||
pub fn generate_bin_linking_module<P: AsRef<Path>>(package_root: P, require_path: &str) -> String {
|
pub fn generate_bin_linking_module<P: AsRef<Path>>(package_root: P, require_path: &str) -> String {
|
||||||
format!(
|
format!(
|
||||||
r#"_G.PESDE_ROOT = {:?}
|
r"_G.PESDE_ROOT = {:?}
|
||||||
return require({require_path})"#,
|
return require({require_path})",
|
||||||
package_root.as_ref().to_string_lossy()
|
package_root.as_ref().to_string_lossy()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the require path for a binary
|
/// Get the require path for a binary
|
||||||
#[instrument(level = "trace")]
|
#[instrument(level = "trace")]
|
||||||
|
#[must_use]
|
||||||
pub fn get_bin_require_path(
|
pub fn get_bin_require_path(
|
||||||
base_dir: &Path,
|
base_dir: &Path,
|
||||||
bin_file: &RelativePath,
|
bin_file: &RelativePath,
|
||||||
|
@ -215,12 +218,14 @@ pub fn get_bin_require_path(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate a linking module for a script
|
/// Generate a linking module for a script
|
||||||
|
#[must_use]
|
||||||
pub fn generate_script_linking_module(require_path: &str) -> String {
|
pub fn generate_script_linking_module(require_path: &str) -> String {
|
||||||
format!(r#"return require({require_path})"#)
|
format!(r"return require({require_path})")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the require path for a script
|
/// Get the require path for a script
|
||||||
#[instrument(level = "trace")]
|
#[instrument(level = "trace")]
|
||||||
|
#[must_use]
|
||||||
pub fn get_script_require_path(
|
pub fn get_script_require_path(
|
||||||
base_dir: &Path,
|
base_dir: &Path,
|
||||||
script_file: &RelativePath,
|
script_file: &RelativePath,
|
||||||
|
|
|
@ -3,7 +3,7 @@ use crate::{
|
||||||
Project, PACKAGES_CONTAINER_NAME, SCRIPTS_LINK_FOLDER,
|
Project, PACKAGES_CONTAINER_NAME, SCRIPTS_LINK_FOLDER,
|
||||||
};
|
};
|
||||||
use fs_err::tokio as fs;
|
use fs_err::tokio as fs;
|
||||||
use futures::FutureExt;
|
use futures::FutureExt as _;
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashSet,
|
collections::HashSet,
|
||||||
path::{Component, Path, PathBuf},
|
path::{Component, Path, PathBuf},
|
||||||
|
@ -12,7 +12,7 @@ use std::{
|
||||||
use tokio::task::JoinSet;
|
use tokio::task::JoinSet;
|
||||||
|
|
||||||
fn index_entry(
|
fn index_entry(
|
||||||
entry: fs::DirEntry,
|
entry: &fs::DirEntry,
|
||||||
packages_index_dir: &Path,
|
packages_index_dir: &Path,
|
||||||
tasks: &mut JoinSet<Result<(), errors::RemoveUnusedError>>,
|
tasks: &mut JoinSet<Result<(), errors::RemoveUnusedError>>,
|
||||||
used_paths: &Arc<HashSet<PathBuf>>,
|
used_paths: &Arc<HashSet<PathBuf>>,
|
||||||
|
@ -54,13 +54,13 @@ fn index_entry(
|
||||||
}
|
}
|
||||||
#[cfg(feature = "wally-compat")]
|
#[cfg(feature = "wally-compat")]
|
||||||
{
|
{
|
||||||
if !used_paths.contains(&path_relative) {
|
if used_paths.contains(&path_relative) {
|
||||||
fs::remove_dir_all(path).await?;
|
|
||||||
} else {
|
|
||||||
#[cfg(feature = "patches")]
|
#[cfg(feature = "patches")]
|
||||||
if !patched_packages.contains(&path_relative) {
|
if !patched_packages.contains(&path_relative) {
|
||||||
crate::patches::remove_patch(path.join(package_name)).await?;
|
crate::patches::remove_patch(path.join(package_name)).await?;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
fs::remove_dir_all(path).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
@ -104,7 +104,7 @@ fn packages_entry(
|
||||||
) {
|
) {
|
||||||
let expected_aliases = expected_aliases.clone();
|
let expected_aliases = expected_aliases.clone();
|
||||||
tasks.spawn(async move {
|
tasks.spawn(async move {
|
||||||
if !entry.file_type().await?.is_file() {
|
if entry.file_type().await?.is_dir() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,7 +241,7 @@ impl Project {
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
Some(entry) = index_entries.next_entry().map(Result::transpose) => {
|
Some(entry) = index_entries.next_entry().map(Result::transpose) => {
|
||||||
index_entry(
|
index_entry(
|
||||||
entry?,
|
&entry?,
|
||||||
&packages_index_dir,
|
&packages_index_dir,
|
||||||
&mut tasks,
|
&mut tasks,
|
||||||
&used_paths,
|
&used_paths,
|
||||||
|
|
|
@ -6,7 +6,7 @@ use crate::{
|
||||||
source::{
|
source::{
|
||||||
fs::{cas_path, store_in_cas},
|
fs::{cas_path, store_in_cas},
|
||||||
ids::PackageId,
|
ids::PackageId,
|
||||||
traits::PackageRef,
|
traits::PackageRef as _,
|
||||||
},
|
},
|
||||||
Project, LINK_LIB_NO_FILE_FOUND, PACKAGES_CONTAINER_NAME, SCRIPTS_LINK_FOLDER,
|
Project, LINK_LIB_NO_FILE_FOUND, PACKAGES_CONTAINER_NAME, SCRIPTS_LINK_FOLDER,
|
||||||
};
|
};
|
||||||
|
@ -18,7 +18,7 @@ use std::{
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
use tokio::task::{spawn_blocking, JoinSet};
|
use tokio::task::{spawn_blocking, JoinSet};
|
||||||
use tracing::{instrument, Instrument};
|
use tracing::{instrument, Instrument as _};
|
||||||
|
|
||||||
/// Generates linking modules for a project
|
/// Generates linking modules for a project
|
||||||
pub mod generator;
|
pub mod generator;
|
||||||
|
@ -41,7 +41,7 @@ async fn write_cas(destination: PathBuf, cas_dir: &Path, contents: &str) -> std:
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
Err(e) if e.kind() == std::io::ErrorKind::PermissionDenied => {}
|
Err(e) if e.kind() == std::io::ErrorKind::PermissionDenied => {}
|
||||||
Err(e) => return Err(e),
|
Err(e) => return Err(e),
|
||||||
};
|
}
|
||||||
|
|
||||||
fs::hard_link(cas_path(&hash, cas_dir), destination).await
|
fs::hard_link(cas_path(&hash, cas_dir), destination).await
|
||||||
}
|
}
|
||||||
|
@ -102,7 +102,9 @@ impl Project {
|
||||||
manifest_target_kind,
|
manifest_target_kind,
|
||||||
);
|
);
|
||||||
|
|
||||||
let types = if lib_file.as_str() != LINK_LIB_NO_FILE_FOUND {
|
let types = if lib_file.as_str() == LINK_LIB_NO_FILE_FOUND {
|
||||||
|
vec![]
|
||||||
|
} else {
|
||||||
let lib_file = lib_file.to_path(&container_folder);
|
let lib_file = lib_file.to_path(&container_folder);
|
||||||
|
|
||||||
let contents = match fs::read_to_string(&lib_file).await {
|
let contents = match fs::read_to_string(&lib_file).await {
|
||||||
|
@ -122,8 +124,6 @@ impl Project {
|
||||||
tracing::debug!("contains {} exported types", types.len());
|
tracing::debug!("contains {} exported types", types.len());
|
||||||
|
|
||||||
types
|
types
|
||||||
} else {
|
|
||||||
vec![]
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(build_files) = Some(&node.target)
|
if let Some(build_files) = Some(&node.target)
|
||||||
|
|
|
@ -107,6 +107,8 @@ pub mod old {
|
||||||
|
|
||||||
impl LockfileOld {
|
impl LockfileOld {
|
||||||
/// Converts this lockfile to a new lockfile
|
/// Converts this lockfile to a new lockfile
|
||||||
|
#[must_use]
|
||||||
|
#[allow(clippy::wrong_self_convention)]
|
||||||
pub fn to_new(self) -> super::Lockfile {
|
pub fn to_new(self) -> super::Lockfile {
|
||||||
super::Lockfile {
|
super::Lockfile {
|
||||||
name: self.name,
|
name: self.name,
|
||||||
|
|
19
src/main.rs
19
src/main.rs
|
@ -1,7 +1,7 @@
|
||||||
#[cfg(feature = "version-management")]
|
#[cfg(feature = "version-management")]
|
||||||
use crate::cli::version::{check_for_updates, current_version, get_or_download_engine};
|
use crate::cli::version::{check_for_updates, current_version, get_or_download_engine};
|
||||||
use crate::cli::{auth::get_tokens, display_err, home_dir, HOME_DIR};
|
use crate::cli::{auth::get_tokens, display_err, home_dir, HOME_DIR};
|
||||||
use anyhow::Context;
|
use anyhow::Context as _;
|
||||||
use clap::{builder::styling::AnsiColor, Parser};
|
use clap::{builder::styling::AnsiColor, Parser};
|
||||||
use fs_err::tokio as fs;
|
use fs_err::tokio as fs;
|
||||||
use indicatif::MultiProgress;
|
use indicatif::MultiProgress;
|
||||||
|
@ -10,13 +10,14 @@ use semver::VersionReq;
|
||||||
use std::{
|
use std::{
|
||||||
io,
|
io,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
str::FromStr,
|
str::FromStr as _,
|
||||||
sync::Mutex,
|
sync::Mutex,
|
||||||
};
|
};
|
||||||
use tempfile::NamedTempFile;
|
use tempfile::NamedTempFile;
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
use tracing_subscriber::{
|
use tracing_subscriber::{
|
||||||
filter::LevelFilter, fmt::MakeWriter, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter,
|
filter::LevelFilter, fmt::MakeWriter, layer::SubscriberExt as _, util::SubscriberInitExt as _,
|
||||||
|
EnvFilter,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod cli;
|
mod cli;
|
||||||
|
@ -98,8 +99,8 @@ pub struct IndicatifWriter;
|
||||||
|
|
||||||
impl IndicatifWriter {
|
impl IndicatifWriter {
|
||||||
fn suspend<F: FnOnce() -> R, R>(f: F) -> R {
|
fn suspend<F: FnOnce() -> R, R>(f: F) -> R {
|
||||||
match *PROGRESS_BARS.lock().unwrap() {
|
match &*PROGRESS_BARS.lock().unwrap() {
|
||||||
Some(ref progress_bars) => progress_bars.suspend(f),
|
Some(progress_bars) => progress_bars.suspend(f),
|
||||||
None => f(),
|
None => f(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -191,8 +192,8 @@ async fn run() -> anyhow::Result<()> {
|
||||||
.status()
|
.status()
|
||||||
.expect("failed to run lune");
|
.expect("failed to run lune");
|
||||||
|
|
||||||
std::process::exit(status.code().unwrap_or(1));
|
std::process::exit(status.code().unwrap_or(1i32));
|
||||||
}
|
};
|
||||||
|
|
||||||
let tracing_env_filter = EnvFilter::builder()
|
let tracing_env_filter = EnvFilter::builder()
|
||||||
.with_default_directive(LevelFilter::INFO.into())
|
.with_default_directive(LevelFilter::INFO.into())
|
||||||
|
@ -315,8 +316,8 @@ async fn run() -> anyhow::Result<()> {
|
||||||
.status()
|
.status()
|
||||||
.expect("failed to run new version");
|
.expect("failed to run new version");
|
||||||
|
|
||||||
std::process::exit(status.code().unwrap_or(1));
|
std::process::exit(status.code().unwrap_or(1i32));
|
||||||
}
|
};
|
||||||
|
|
||||||
#[cfg(feature = "version-management")]
|
#[cfg(feature = "version-management")]
|
||||||
display_err(
|
display_err(
|
||||||
|
|
|
@ -155,7 +155,7 @@ impl Eq for Alias {}
|
||||||
|
|
||||||
impl Hash for Alias {
|
impl Hash for Alias {
|
||||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
self.0.to_lowercase().hash(state)
|
self.0.to_lowercase().hash(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,6 +204,7 @@ impl schemars::JsonSchema for Alias {
|
||||||
|
|
||||||
impl Alias {
|
impl Alias {
|
||||||
/// Get the alias as a string
|
/// Get the alias as a string
|
||||||
|
#[must_use]
|
||||||
pub fn as_str(&self) -> &str {
|
pub fn as_str(&self) -> &str {
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,6 +59,7 @@ impl TargetKind {
|
||||||
|
|
||||||
/// The folder to store packages in for this target
|
/// The folder to store packages in for this target
|
||||||
/// self is the project's target, dependency is the target of the dependency
|
/// self is the project's target, dependency is the target of the dependency
|
||||||
|
#[must_use]
|
||||||
pub fn packages_folder(self, dependency: Self) -> String {
|
pub fn packages_folder(self, dependency: Self) -> String {
|
||||||
// the code below might seem better, but it's just going to create issues with users trying
|
// the code below might seem better, but it's just going to create issues with users trying
|
||||||
// to use a build script, since imports would break between targets
|
// to use a build script, since imports would break between targets
|
||||||
|
@ -71,7 +72,8 @@ impl TargetKind {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether this target is a Roblox target
|
/// Returns whether this target is a Roblox target
|
||||||
pub fn is_roblox(&self) -> bool {
|
#[must_use]
|
||||||
|
pub fn is_roblox(self) -> bool {
|
||||||
matches!(self, TargetKind::Roblox | TargetKind::RobloxServer)
|
matches!(self, TargetKind::Roblox | TargetKind::RobloxServer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -135,6 +137,7 @@ pub enum Target {
|
||||||
|
|
||||||
impl Target {
|
impl Target {
|
||||||
/// Returns the kind of this target
|
/// Returns the kind of this target
|
||||||
|
#[must_use]
|
||||||
pub fn kind(&self) -> TargetKind {
|
pub fn kind(&self) -> TargetKind {
|
||||||
match self {
|
match self {
|
||||||
Target::Roblox { .. } => TargetKind::Roblox,
|
Target::Roblox { .. } => TargetKind::Roblox,
|
||||||
|
@ -145,6 +148,7 @@ impl Target {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the path to the lib export file
|
/// Returns the path to the lib export file
|
||||||
|
#[must_use]
|
||||||
pub fn lib_path(&self) -> Option<&RelativePath> {
|
pub fn lib_path(&self) -> Option<&RelativePath> {
|
||||||
match self {
|
match self {
|
||||||
Target::Roblox { lib, .. } => lib.as_deref(),
|
Target::Roblox { lib, .. } => lib.as_deref(),
|
||||||
|
@ -155,6 +159,7 @@ impl Target {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the path to the bin export file
|
/// Returns the path to the bin export file
|
||||||
|
#[must_use]
|
||||||
pub fn bin_path(&self) -> Option<&RelativePath> {
|
pub fn bin_path(&self) -> Option<&RelativePath> {
|
||||||
match self {
|
match self {
|
||||||
Target::Roblox { .. } => None,
|
Target::Roblox { .. } => None,
|
||||||
|
@ -165,6 +170,7 @@ impl Target {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the Roblox build files
|
/// Returns the Roblox build files
|
||||||
|
#[must_use]
|
||||||
pub fn build_files(&self) -> Option<&BTreeSet<String>> {
|
pub fn build_files(&self) -> Option<&BTreeSet<String>> {
|
||||||
match self {
|
match self {
|
||||||
Target::Roblox { build_files, .. } => Some(build_files),
|
Target::Roblox { build_files, .. } => Some(build_files),
|
||||||
|
@ -174,6 +180,7 @@ impl Target {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the scripts exported by this target
|
/// Returns the scripts exported by this target
|
||||||
|
#[must_use]
|
||||||
pub fn scripts(&self) -> Option<&BTreeMap<String, RelativePathBuf>> {
|
pub fn scripts(&self) -> Option<&BTreeMap<String, RelativePathBuf>> {
|
||||||
match self {
|
match self {
|
||||||
Target::Lune { scripts, .. } => Some(scripts),
|
Target::Lune { scripts, .. } => Some(scripts),
|
||||||
|
|
15
src/names.rs
15
src/names.rs
|
@ -88,21 +88,25 @@ impl schemars::JsonSchema for PackageName {
|
||||||
|
|
||||||
impl PackageName {
|
impl PackageName {
|
||||||
/// Returns the parts of the package name
|
/// Returns the parts of the package name
|
||||||
|
#[must_use]
|
||||||
pub fn as_str(&self) -> (&str, &str) {
|
pub fn as_str(&self) -> (&str, &str) {
|
||||||
(&self.0, &self.1)
|
(&self.0, &self.1)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the package name as a string suitable for use in the filesystem
|
/// Returns the package name as a string suitable for use in the filesystem
|
||||||
|
#[must_use]
|
||||||
pub fn escaped(&self) -> String {
|
pub fn escaped(&self) -> String {
|
||||||
format!("{}+{}", self.0, self.1)
|
format!("{}+{}", self.0, self.1)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the scope of the package name
|
/// Returns the scope of the package name
|
||||||
|
#[must_use]
|
||||||
pub fn scope(&self) -> &str {
|
pub fn scope(&self) -> &str {
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the name of the package name
|
/// Returns the name of the package name
|
||||||
|
#[must_use]
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> &str {
|
||||||
&self.1
|
&self.1
|
||||||
}
|
}
|
||||||
|
@ -123,6 +127,7 @@ ser_display_deser_fromstr!(PackageNames);
|
||||||
|
|
||||||
impl PackageNames {
|
impl PackageNames {
|
||||||
/// Returns the parts of the package name
|
/// Returns the parts of the package name
|
||||||
|
#[must_use]
|
||||||
pub fn as_str(&self) -> (&str, &str) {
|
pub fn as_str(&self) -> (&str, &str) {
|
||||||
match self {
|
match self {
|
||||||
PackageNames::Pesde(name) => name.as_str(),
|
PackageNames::Pesde(name) => name.as_str(),
|
||||||
|
@ -132,6 +137,7 @@ impl PackageNames {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the package name as a string suitable for use in the filesystem
|
/// Returns the package name as a string suitable for use in the filesystem
|
||||||
|
#[must_use]
|
||||||
pub fn escaped(&self) -> String {
|
pub fn escaped(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
PackageNames::Pesde(name) => name.escaped(),
|
PackageNames::Pesde(name) => name.escaped(),
|
||||||
|
@ -146,6 +152,7 @@ impl PackageNames {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the scope of the package name
|
/// Returns the scope of the package name
|
||||||
|
#[must_use]
|
||||||
pub fn scope(&self) -> &str {
|
pub fn scope(&self) -> &str {
|
||||||
match self {
|
match self {
|
||||||
PackageNames::Pesde(name) => name.scope(),
|
PackageNames::Pesde(name) => name.scope(),
|
||||||
|
@ -155,6 +162,7 @@ impl PackageNames {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the name of the package name
|
/// Returns the name of the package name
|
||||||
|
#[must_use]
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> &str {
|
||||||
match self {
|
match self {
|
||||||
PackageNames::Pesde(name) => name.name(),
|
PackageNames::Pesde(name) => name.name(),
|
||||||
|
@ -181,7 +189,7 @@ impl FromStr for PackageNames {
|
||||||
#[cfg(feature = "wally-compat")]
|
#[cfg(feature = "wally-compat")]
|
||||||
if let Some(wally_name) = s
|
if let Some(wally_name) = s
|
||||||
.strip_prefix("wally#")
|
.strip_prefix("wally#")
|
||||||
.or_else(|| if s.contains('-') { Some(s) } else { None })
|
.or_else(|| s.contains('-').then_some(s))
|
||||||
.and_then(|s| wally::WallyPackageName::from_str(s).ok())
|
.and_then(|s| wally::WallyPackageName::from_str(s).ok())
|
||||||
{
|
{
|
||||||
return Ok(PackageNames::Wally(wally_name));
|
return Ok(PackageNames::Wally(wally_name));
|
||||||
|
@ -259,21 +267,25 @@ pub mod wally {
|
||||||
|
|
||||||
impl WallyPackageName {
|
impl WallyPackageName {
|
||||||
/// Returns the parts of the package name
|
/// Returns the parts of the package name
|
||||||
|
#[must_use]
|
||||||
pub fn as_str(&self) -> (&str, &str) {
|
pub fn as_str(&self) -> (&str, &str) {
|
||||||
(&self.0, &self.1)
|
(&self.0, &self.1)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the package name as a string suitable for use in the filesystem
|
/// Returns the package name as a string suitable for use in the filesystem
|
||||||
|
#[must_use]
|
||||||
pub fn escaped(&self) -> String {
|
pub fn escaped(&self) -> String {
|
||||||
format!("wally#{}+{}", self.0, self.1)
|
format!("wally#{}+{}", self.0, self.1)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the scope of the package name
|
/// Returns the scope of the package name
|
||||||
|
#[must_use]
|
||||||
pub fn scope(&self) -> &str {
|
pub fn scope(&self) -> &str {
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the name of the package name
|
/// Returns the name of the package name
|
||||||
|
#[must_use]
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> &str {
|
||||||
&self.1
|
&self.1
|
||||||
}
|
}
|
||||||
|
@ -316,6 +328,7 @@ pub mod errors {
|
||||||
|
|
||||||
/// Errors that can occur when working with Wally package names
|
/// Errors that can occur when working with Wally package names
|
||||||
#[cfg(feature = "wally-compat")]
|
#[cfg(feature = "wally-compat")]
|
||||||
|
#[allow(clippy::enum_variant_names)]
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum WallyPackageNameError {
|
pub enum WallyPackageNameError {
|
||||||
/// The package name is not in the format `scope/name`
|
/// The package name is not in the format `scope/name`
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
reporters::{PatchProgressReporter, PatchesReporter},
|
reporters::{PatchProgressReporter as _, PatchesReporter},
|
||||||
source::ids::PackageId,
|
source::ids::PackageId,
|
||||||
MANIFEST_FILE_NAME,
|
MANIFEST_FILE_NAME,
|
||||||
};
|
};
|
||||||
use fs_err::tokio as fs;
|
use fs_err::tokio as fs;
|
||||||
use futures::TryFutureExt;
|
use futures::TryFutureExt as _;
|
||||||
use git2::{ApplyLocation, Diff, DiffFormat, DiffLineType, Repository, Signature};
|
use git2::{ApplyLocation, Diff, DiffFormat, DiffLineType, Repository, Signature};
|
||||||
use std::{
|
use std::{
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
|
@ -37,7 +37,7 @@ pub fn setup_patches_repo<P: AsRef<Path>>(dir: P) -> Result<Repository, git2::Er
|
||||||
&tree,
|
&tree,
|
||||||
&[],
|
&[],
|
||||||
)?;
|
)?;
|
||||||
}
|
};
|
||||||
|
|
||||||
Ok(repo)
|
Ok(repo)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
#![allow(unused_variables)]
|
#![allow(unused_variables)]
|
||||||
|
|
||||||
use async_stream::stream;
|
use async_stream::stream;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt as _;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::io::AsyncBufRead;
|
use tokio::io::AsyncBufRead;
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ pub(crate) fn response_to_async_read<R: DownloadProgressReporter>(
|
||||||
let chunk = match chunk {
|
let chunk = match chunk {
|
||||||
Ok(chunk) => chunk,
|
Ok(chunk) => chunk,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
yield Err(std::io::Error::new(std::io::ErrorKind::Other, err));
|
yield Err(std::io::Error::other(err));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,13 +5,13 @@ use crate::{
|
||||||
ids::PackageId,
|
ids::PackageId,
|
||||||
pesde::PesdePackageSource,
|
pesde::PesdePackageSource,
|
||||||
specifiers::DependencySpecifiers,
|
specifiers::DependencySpecifiers,
|
||||||
traits::{PackageRef, PackageSource, RefreshOptions, ResolveOptions},
|
traits::{PackageRef as _, PackageSource as _, RefreshOptions, ResolveOptions},
|
||||||
PackageSources,
|
PackageSources,
|
||||||
},
|
},
|
||||||
Project, RefreshedSources,
|
Project, RefreshedSources,
|
||||||
};
|
};
|
||||||
use std::collections::{btree_map::Entry, HashMap, VecDeque};
|
use std::collections::{btree_map::Entry, HashMap, VecDeque};
|
||||||
use tracing::{instrument, Instrument};
|
use tracing::{instrument, Instrument as _};
|
||||||
|
|
||||||
fn insert_node(
|
fn insert_node(
|
||||||
graph: &mut DependencyGraph,
|
graph: &mut DependencyGraph,
|
||||||
|
@ -183,7 +183,7 @@ impl Project {
|
||||||
.indices
|
.indices
|
||||||
.get(&specifier.index)
|
.get(&specifier.index)
|
||||||
.ok_or_else(|| errors::DependencyGraphError::IndexNotFound(
|
.ok_or_else(|| errors::DependencyGraphError::IndexNotFound(
|
||||||
specifier.index.to_string(),
|
specifier.index.clone(),
|
||||||
))?
|
))?
|
||||||
.clone()
|
.clone()
|
||||||
} else {
|
} else {
|
||||||
|
@ -203,7 +203,7 @@ impl Project {
|
||||||
.wally_indices
|
.wally_indices
|
||||||
.get(&specifier.index)
|
.get(&specifier.index)
|
||||||
.ok_or_else(|| errors::DependencyGraphError::WallyIndexNotFound(
|
.ok_or_else(|| errors::DependencyGraphError::WallyIndexNotFound(
|
||||||
specifier.index.to_string(),
|
specifier.index.clone(),
|
||||||
))?
|
))?
|
||||||
.clone()
|
.clone()
|
||||||
} else {
|
} else {
|
||||||
|
@ -297,11 +297,7 @@ impl Project {
|
||||||
}
|
}
|
||||||
|
|
||||||
let node = DependencyGraphNode {
|
let node = DependencyGraphNode {
|
||||||
direct: if depth == 0 {
|
direct: (depth == 0).then(|| (alias.clone(), specifier.clone(), ty)),
|
||||||
Some((alias.clone(), specifier.clone(), ty))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
},
|
|
||||||
pkg_ref: pkg_ref.clone(),
|
pkg_ref: pkg_ref.clone(),
|
||||||
dependencies: Default::default(),
|
dependencies: Default::default(),
|
||||||
resolved_ty,
|
resolved_ty,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::Project;
|
use crate::Project;
|
||||||
use futures::FutureExt;
|
use futures::FutureExt as _;
|
||||||
use std::{
|
use std::{
|
||||||
ffi::OsStr,
|
ffi::OsStr,
|
||||||
fmt::{Debug, Display, Formatter},
|
fmt::{Debug, Display, Formatter},
|
||||||
|
@ -7,7 +7,7 @@ use std::{
|
||||||
process::Stdio,
|
process::Stdio,
|
||||||
};
|
};
|
||||||
use tokio::{
|
use tokio::{
|
||||||
io::{AsyncBufReadExt, BufReader},
|
io::{AsyncBufReadExt as _, BufReader},
|
||||||
process::Command,
|
process::Command,
|
||||||
};
|
};
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
|
|
|
@ -5,7 +5,7 @@ use crate::{
|
||||||
use fs_err::tokio as fs;
|
use fs_err::tokio as fs;
|
||||||
use relative_path::RelativePathBuf;
|
use relative_path::RelativePathBuf;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sha2::{Digest, Sha256};
|
use sha2::{Digest as _, Sha256};
|
||||||
use std::{
|
use std::{
|
||||||
collections::BTreeMap,
|
collections::BTreeMap,
|
||||||
fmt::Debug,
|
fmt::Debug,
|
||||||
|
@ -13,7 +13,7 @@ use std::{
|
||||||
};
|
};
|
||||||
use tempfile::Builder;
|
use tempfile::Builder;
|
||||||
use tokio::{
|
use tokio::{
|
||||||
io::{AsyncReadExt, AsyncWriteExt},
|
io::{AsyncReadExt as _, AsyncWriteExt as _},
|
||||||
pin,
|
pin,
|
||||||
task::JoinSet,
|
task::JoinSet,
|
||||||
};
|
};
|
||||||
|
@ -112,7 +112,7 @@ pub(crate) async fn store_in_cas<R: tokio::io::AsyncRead + Unpin, P: AsRef<Path>
|
||||||
}
|
}
|
||||||
Err(e) if e.error.kind() == std::io::ErrorKind::AlreadyExists => {}
|
Err(e) if e.error.kind() == std::io::ErrorKind::AlreadyExists => {}
|
||||||
Err(e) => return Err(e.error),
|
Err(e) => return Err(e.error),
|
||||||
};
|
}
|
||||||
|
|
||||||
Ok(hash)
|
Ok(hash)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,9 @@ use crate::{
|
||||||
git::{pkg_ref::GitPackageRef, specifier::GitDependencySpecifier},
|
git::{pkg_ref::GitPackageRef, specifier::GitDependencySpecifier},
|
||||||
git_index::{read_file, GitBasedSource},
|
git_index::{read_file, GitBasedSource},
|
||||||
specifiers::DependencySpecifiers,
|
specifiers::DependencySpecifiers,
|
||||||
traits::{DownloadOptions, GetTargetOptions, PackageRef, RefreshOptions, ResolveOptions},
|
traits::{
|
||||||
|
DownloadOptions, GetTargetOptions, PackageRef as _, RefreshOptions, ResolveOptions,
|
||||||
|
},
|
||||||
PackageSource, ResolveResult, VersionId, ADDITIONAL_FORBIDDEN_FILES, IGNORED_DIRS,
|
PackageSource, ResolveResult, VersionId, ADDITIONAL_FORBIDDEN_FILES, IGNORED_DIRS,
|
||||||
IGNORED_FILES,
|
IGNORED_FILES,
|
||||||
},
|
},
|
||||||
|
@ -48,6 +50,7 @@ impl GitBasedSource for GitPackageSource {
|
||||||
|
|
||||||
impl GitPackageSource {
|
impl GitPackageSource {
|
||||||
/// Creates a new Git package source
|
/// Creates a new Git package source
|
||||||
|
#[must_use]
|
||||||
pub fn new(repo_url: Url) -> Self {
|
pub fn new(repo_url: Url) -> Self {
|
||||||
Self { repo_url }
|
Self { repo_url }
|
||||||
}
|
}
|
||||||
|
@ -59,7 +62,7 @@ impl GitPackageSource {
|
||||||
|
|
||||||
fn transform_pesde_dependencies(
|
fn transform_pesde_dependencies(
|
||||||
manifest: &Manifest,
|
manifest: &Manifest,
|
||||||
repo_url: Url,
|
repo_url: &Url,
|
||||||
rev: &str,
|
rev: &str,
|
||||||
root_tree: &gix::Tree,
|
root_tree: &gix::Tree,
|
||||||
) -> Result<BTreeMap<Alias, (DependencySpecifiers, DependencyType)>, errors::ResolveError> {
|
) -> Result<BTreeMap<Alias, (DependencySpecifiers, DependencyType)>, errors::ResolveError> {
|
||||||
|
@ -77,7 +80,7 @@ fn transform_pesde_dependencies(
|
||||||
.get(&specifier.index)
|
.get(&specifier.index)
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
errors::ResolveError::PesdeIndexNotFound(
|
errors::ResolveError::PesdeIndexNotFound(
|
||||||
specifier.index.to_string(),
|
specifier.index.clone(),
|
||||||
Box::new(repo_url.clone()),
|
Box::new(repo_url.clone()),
|
||||||
)
|
)
|
||||||
})?
|
})?
|
||||||
|
@ -90,7 +93,7 @@ fn transform_pesde_dependencies(
|
||||||
.get(&specifier.index)
|
.get(&specifier.index)
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
errors::ResolveError::WallyIndexNotFound(
|
errors::ResolveError::WallyIndexNotFound(
|
||||||
specifier.index.to_string(),
|
specifier.index.clone(),
|
||||||
Box::new(repo_url.clone()),
|
Box::new(repo_url.clone()),
|
||||||
)
|
)
|
||||||
})?
|
})?
|
||||||
|
@ -138,10 +141,10 @@ fn transform_pesde_dependencies(
|
||||||
repo: repo_url.clone(),
|
repo: repo_url.clone(),
|
||||||
rev: rev.to_string(),
|
rev: rev.to_string(),
|
||||||
path: Some(path),
|
path: Some(path),
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
DependencySpecifiers::Path(_) => {
|
DependencySpecifiers::Path(_) => {
|
||||||
return Err(errors::ResolveError::Path(Box::new(repo_url.clone())))
|
return Err(errors::ResolveError::Path(Box::new(repo_url.clone())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,12 +296,8 @@ impl PackageSource for GitPackageSource {
|
||||||
return Err(errors::ResolveError::NoManifest(Box::new(repo_url.clone())));
|
return Err(errors::ResolveError::NoManifest(Box::new(repo_url.clone())));
|
||||||
};
|
};
|
||||||
|
|
||||||
let dependencies = transform_pesde_dependencies(
|
let dependencies =
|
||||||
&manifest,
|
transform_pesde_dependencies(&manifest, &repo_url, &specifier.rev, &root_tree)?;
|
||||||
repo_url.clone(),
|
|
||||||
&specifier.rev,
|
|
||||||
&root_tree,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
PackageNames::Pesde(manifest.name),
|
PackageNames::Pesde(manifest.name),
|
||||||
|
|
|
@ -138,9 +138,8 @@ pub fn root_tree(repo: &gix::Repository) -> Result<gix::Tree, errors::TreeError>
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let refspec = match remote.refspecs(Direction::Fetch).first() {
|
let Some(refspec) = remote.refspecs(Direction::Fetch).first() else {
|
||||||
Some(head) => head,
|
return Err(errors::TreeError::NoRefSpecs(path));
|
||||||
None => return Err(errors::TreeError::NoRefSpecs(path)),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let spec_ref = refspec.to_ref();
|
let spec_ref = refspec.to_ref();
|
||||||
|
@ -153,7 +152,7 @@ pub fn root_tree(repo: &gix::Repository) -> Result<gix::Tree, errors::TreeError>
|
||||||
|
|
||||||
let reference = match repo.find_reference(&local_ref) {
|
let reference = match repo.find_reference(&local_ref) {
|
||||||
Ok(reference) => reference,
|
Ok(reference) => reference,
|
||||||
Err(e) => return Err(errors::TreeError::NoReference(local_ref.to_string(), e)),
|
Err(e) => return Err(errors::TreeError::NoReference(local_ref.clone(), e)),
|
||||||
};
|
};
|
||||||
|
|
||||||
let reference_name = reference.name().as_bstr().to_string();
|
let reference_name = reference.name().as_bstr().to_string();
|
||||||
|
|
|
@ -9,21 +9,25 @@ ser_display_deser_fromstr!(VersionId);
|
||||||
|
|
||||||
impl VersionId {
|
impl VersionId {
|
||||||
/// Creates a new version ID
|
/// Creates a new version ID
|
||||||
|
#[must_use]
|
||||||
pub fn new(version: Version, target: TargetKind) -> Self {
|
pub fn new(version: Version, target: TargetKind) -> Self {
|
||||||
VersionId(version, target)
|
VersionId(version, target)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access the version
|
/// Access the version
|
||||||
|
#[must_use]
|
||||||
pub fn version(&self) -> &Version {
|
pub fn version(&self) -> &Version {
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access the target
|
/// Access the target
|
||||||
|
#[must_use]
|
||||||
pub fn target(&self) -> TargetKind {
|
pub fn target(&self) -> TargetKind {
|
||||||
self.1
|
self.1
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns this version ID as a string that can be used in the filesystem
|
/// Returns this version ID as a string that can be used in the filesystem
|
||||||
|
#[must_use]
|
||||||
pub fn escaped(&self) -> String {
|
pub fn escaped(&self) -> String {
|
||||||
format!("{}+{}", self.0, self.1)
|
format!("{}+{}", self.0, self.1)
|
||||||
}
|
}
|
||||||
|
@ -34,6 +38,7 @@ impl VersionId {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access the parts of the version ID
|
/// Access the parts of the version ID
|
||||||
|
#[must_use]
|
||||||
pub fn parts(&self) -> (&Version, TargetKind) {
|
pub fn parts(&self) -> (&Version, TargetKind) {
|
||||||
(&self.0, self.1)
|
(&self.0, self.1)
|
||||||
}
|
}
|
||||||
|
@ -96,21 +101,25 @@ ser_display_deser_fromstr!(PackageId);
|
||||||
|
|
||||||
impl PackageId {
|
impl PackageId {
|
||||||
/// Creates a new package ID
|
/// Creates a new package ID
|
||||||
|
#[must_use]
|
||||||
pub fn new(names: PackageNames, version_id: VersionId) -> Self {
|
pub fn new(names: PackageNames, version_id: VersionId) -> Self {
|
||||||
PackageId(names, version_id)
|
PackageId(names, version_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access the name
|
/// Access the name
|
||||||
|
#[must_use]
|
||||||
pub fn name(&self) -> &PackageNames {
|
pub fn name(&self) -> &PackageNames {
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access the version ID
|
/// Access the version ID
|
||||||
|
#[must_use]
|
||||||
pub fn version_id(&self) -> &VersionId {
|
pub fn version_id(&self) -> &VersionId {
|
||||||
&self.1
|
&self.1
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access the parts of the package ID
|
/// Access the parts of the package ID
|
||||||
|
#[must_use]
|
||||||
pub fn parts(&self) -> (&PackageNames, &VersionId) {
|
pub fn parts(&self) -> (&PackageNames, &VersionId) {
|
||||||
(&self.0, &self.1)
|
(&self.0, &self.1)
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,7 @@ impl PackageSource for PathPackageSource {
|
||||||
.get(&spec.index)
|
.get(&spec.index)
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
errors::ResolveError::IndexNotFound(
|
errors::ResolveError::IndexNotFound(
|
||||||
spec.index.to_string(),
|
spec.index.clone(),
|
||||||
specifier.path.clone(),
|
specifier.path.clone(),
|
||||||
)
|
)
|
||||||
})?
|
})?
|
||||||
|
@ -66,7 +66,7 @@ impl PackageSource for PathPackageSource {
|
||||||
.get(&spec.index)
|
.get(&spec.index)
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
errors::ResolveError::IndexNotFound(
|
errors::ResolveError::IndexNotFound(
|
||||||
spec.index.to_string(),
|
spec.index.clone(),
|
||||||
specifier.path.clone(),
|
specifier.path.clone(),
|
||||||
)
|
)
|
||||||
})?
|
})?
|
||||||
|
|
|
@ -27,7 +27,7 @@ use crate::{
|
||||||
version_matches, Project,
|
version_matches, Project,
|
||||||
};
|
};
|
||||||
use fs_err::tokio as fs;
|
use fs_err::tokio as fs;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt as _;
|
||||||
use semver::VersionReq;
|
use semver::VersionReq;
|
||||||
use tokio::{pin, task::spawn_blocking};
|
use tokio::{pin, task::spawn_blocking};
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
|
@ -68,6 +68,7 @@ impl GitBasedSource for PesdePackageSource {
|
||||||
|
|
||||||
impl PesdePackageSource {
|
impl PesdePackageSource {
|
||||||
/// Creates a new pesde package source
|
/// Creates a new pesde package source
|
||||||
|
#[must_use]
|
||||||
pub fn new(repo_url: Url) -> Self {
|
pub fn new(repo_url: Url) -> Self {
|
||||||
Self { repo_url }
|
Self { repo_url }
|
||||||
}
|
}
|
||||||
|
@ -353,11 +354,13 @@ impl AllowedRegistries {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether the given URL is allowed
|
/// Whether the given URL is allowed
|
||||||
|
#[must_use]
|
||||||
pub fn is_allowed(&self, url: Url) -> bool {
|
pub fn is_allowed(&self, url: Url) -> bool {
|
||||||
self._is_allowed(&simplify_url(url))
|
self._is_allowed(&simplify_url(url))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether the given URL is allowed, or is the same as the given URL
|
/// Whether the given URL is allowed, or is the same as the given URL
|
||||||
|
#[must_use]
|
||||||
pub fn is_allowed_or_same(&self, this: Url, external: Url) -> bool {
|
pub fn is_allowed_or_same(&self, this: Url, external: Url) -> bool {
|
||||||
let this = simplify_url(this);
|
let this = simplify_url(this);
|
||||||
let external = simplify_url(external);
|
let external = simplify_url(external);
|
||||||
|
@ -394,11 +397,13 @@ pub struct IndexConfig {
|
||||||
|
|
||||||
impl IndexConfig {
|
impl IndexConfig {
|
||||||
/// The URL of the API
|
/// The URL of the API
|
||||||
|
#[must_use]
|
||||||
pub fn api(&self) -> &str {
|
pub fn api(&self) -> &str {
|
||||||
self.api.as_str().trim_end_matches('/')
|
self.api.as_str().trim_end_matches('/')
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The URL to download packages from
|
/// The URL to download packages from
|
||||||
|
#[must_use]
|
||||||
pub fn download(&self) -> String {
|
pub fn download(&self) -> String {
|
||||||
self.download
|
self.download
|
||||||
.as_deref()
|
.as_deref()
|
||||||
|
|
|
@ -24,6 +24,7 @@ pub enum PackageRefs {
|
||||||
|
|
||||||
impl PackageRefs {
|
impl PackageRefs {
|
||||||
/// Returns whether this package reference should be treated as a Wally package
|
/// Returns whether this package reference should be treated as a Wally package
|
||||||
|
#[must_use]
|
||||||
pub fn is_wally_package(&self) -> bool {
|
pub fn is_wally_package(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
#[cfg(feature = "wally-compat")]
|
#[cfg(feature = "wally-compat")]
|
||||||
|
|
|
@ -25,8 +25,8 @@ use relative_path::RelativePathBuf;
|
||||||
use reqwest::header::AUTHORIZATION;
|
use reqwest::header::AUTHORIZATION;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::{collections::BTreeMap, path::PathBuf};
|
use std::{collections::BTreeMap, path::PathBuf};
|
||||||
use tokio::{io::AsyncReadExt, pin, task::spawn_blocking};
|
use tokio::{io::AsyncReadExt as _, pin, task::spawn_blocking};
|
||||||
use tokio_util::compat::FuturesAsyncReadCompatExt;
|
use tokio_util::compat::FuturesAsyncReadCompatExt as _;
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
|
|
||||||
pub(crate) mod compat_util;
|
pub(crate) mod compat_util;
|
||||||
|
@ -57,6 +57,7 @@ impl GitBasedSource for WallyPackageSource {
|
||||||
|
|
||||||
impl WallyPackageSource {
|
impl WallyPackageSource {
|
||||||
/// Creates a new Wally package source
|
/// Creates a new Wally package source
|
||||||
|
#[must_use]
|
||||||
pub fn new(repo_url: Url) -> Self {
|
pub fn new(repo_url: Url) -> Self {
|
||||||
Self { repo_url }
|
Self { repo_url }
|
||||||
}
|
}
|
||||||
|
@ -168,12 +169,11 @@ impl PackageSource for WallyPackageSource {
|
||||||
}
|
}
|
||||||
Ok(None) => {
|
Ok(None) => {
|
||||||
tracing::debug!("{} not found in {}", specifier.name, source.repo_url);
|
tracing::debug!("{} not found in {}", specifier.name, source.repo_url);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
Err(e) => return Err(e),
|
Err(e) => return Err(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
let Some(string) = string else {
|
let Some(string) = string else {
|
||||||
return Err(errors::ResolveError::NotFound(specifier.name.to_string()));
|
return Err(errors::ResolveError::NotFound(specifier.name.to_string()));
|
||||||
|
@ -202,7 +202,7 @@ impl PackageSource for WallyPackageSource {
|
||||||
manifest.package.version,
|
manifest.package.version,
|
||||||
match manifest.package.realm {
|
match manifest.package.realm {
|
||||||
Realm::Server => TargetKind::RobloxServer,
|
Realm::Server => TargetKind::RobloxServer,
|
||||||
_ => TargetKind::Roblox,
|
Realm::Shared => TargetKind::Roblox,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
WallyPackageRef {
|
WallyPackageRef {
|
||||||
|
@ -247,7 +247,7 @@ impl PackageSource for WallyPackageSource {
|
||||||
}
|
}
|
||||||
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {}
|
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {}
|
||||||
Err(e) => return Err(errors::DownloadError::ReadIndex(e)),
|
Err(e) => return Err(errors::DownloadError::ReadIndex(e)),
|
||||||
};
|
}
|
||||||
|
|
||||||
let (scope, name) = id.name().as_str();
|
let (scope, name) = id.name().as_str();
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ use crate::{
|
||||||
ResolveResult,
|
ResolveResult,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use futures::StreamExt;
|
use futures::StreamExt as _;
|
||||||
use relative_path::RelativePathBuf;
|
use relative_path::RelativePathBuf;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use tokio::pin;
|
use tokio::pin;
|
||||||
|
@ -86,7 +86,7 @@ impl PackageSource for WorkspacePackageSource {
|
||||||
.get(&spec.index)
|
.get(&spec.index)
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
errors::ResolveError::IndexNotFound(
|
errors::ResolveError::IndexNotFound(
|
||||||
spec.index.to_string(),
|
spec.index.clone(),
|
||||||
manifest.name.to_string(),
|
manifest.name.to_string(),
|
||||||
)
|
)
|
||||||
})?
|
})?
|
||||||
|
@ -99,7 +99,7 @@ impl PackageSource for WorkspacePackageSource {
|
||||||
.get(&spec.index)
|
.get(&spec.index)
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
errors::ResolveError::IndexNotFound(
|
errors::ResolveError::IndexNotFound(
|
||||||
spec.index.to_string(),
|
spec.index.clone(),
|
||||||
manifest.name.to_string(),
|
manifest.name.to_string(),
|
||||||
)
|
)
|
||||||
})?
|
})?
|
||||||
|
|
19
src/util.rs
19
src/util.rs
|
@ -6,7 +6,7 @@ use serde::{
|
||||||
de::{MapAccess, Visitor},
|
de::{MapAccess, Visitor},
|
||||||
Deserialize, Deserializer, Serializer,
|
Deserialize, Deserializer, Serializer,
|
||||||
};
|
};
|
||||||
use sha2::{Digest, Sha256};
|
use sha2::{Digest as _, Sha256};
|
||||||
use std::{
|
use std::{
|
||||||
collections::{BTreeMap, HashSet},
|
collections::{BTreeMap, HashSet},
|
||||||
fmt::{Display, Formatter},
|
fmt::{Display, Formatter},
|
||||||
|
@ -29,8 +29,8 @@ pub fn authenticate_conn(
|
||||||
next: gix::credentials::helper::NextAction::from(ctx),
|
next: gix::credentials::helper::NextAction::from(ctx),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
gix::credentials::helper::Action::Store(_) => Ok(None),
|
gix::credentials::helper::Action::Store(_)
|
||||||
gix::credentials::helper::Action::Erase(_) => Ok(None),
|
| gix::credentials::helper::Action::Erase(_) => Ok(None),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -98,6 +98,7 @@ pub fn is_default<T: Default + Eq>(t: &T) -> bool {
|
||||||
t == &T::default()
|
t == &T::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn no_build_metadata(version: &Version) -> Version {
|
pub fn no_build_metadata(version: &Version) -> Version {
|
||||||
let mut version = version.clone();
|
let mut version = version.clone();
|
||||||
version.build = semver::BuildMetadata::EMPTY;
|
version.build = semver::BuildMetadata::EMPTY;
|
||||||
|
@ -163,21 +164,21 @@ where
|
||||||
formatter.write_str("a map with no duplicate keys")
|
formatter.write_str("a map with no duplicate keys")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_map<A>(self, mut access: A) -> Result<Self::Value, A::Error>
|
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
|
||||||
where
|
where
|
||||||
A: MapAccess<'de>,
|
A: MapAccess<'de>,
|
||||||
{
|
{
|
||||||
let mut map = self.map;
|
let mut res = self.map;
|
||||||
|
|
||||||
while let Some((key, value)) = access.next_entry()? {
|
while let Some((key, value)) = map.next_entry()? {
|
||||||
if map.contains_key(&key) {
|
if res.contains_key(&key) {
|
||||||
return Err(serde::de::Error::custom(format!("duplicate key `{key}`")));
|
return Err(serde::de::Error::custom(format!("duplicate key `{key}`")));
|
||||||
}
|
}
|
||||||
|
|
||||||
map.insert(key, value);
|
res.insert(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(map)
|
Ok(res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue