From b8a0fc4e04a8a5bc728736b05f725633e7b75e7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=AD=A3=E8=B6=85?= Date: Mon, 22 Jun 2026 03:30:03 +0800 Subject: [PATCH] refactor: prune root e2e raw facade paths (#3705) --- crates/e2e_test/src/storage_compat.rs | 16 +- docs/architecture/crate-boundaries.md | 3 + docs/architecture/migration-progress.md | 49 ++++-- rustfs/src/storage_compat.rs | 152 +++++++++--------- scripts/check_architecture_migration_rules.sh | 11 ++ 5 files changed, 135 insertions(+), 96 deletions(-) diff --git a/crates/e2e_test/src/storage_compat.rs b/crates/e2e_test/src/storage_compat.rs index 693d71b3a..f20734981 100644 --- a/crates/e2e_test/src/storage_compat.rs +++ b/crates/e2e_test/src/storage_compat.rs @@ -14,13 +14,15 @@ #![allow(dead_code, unused_imports)] -pub(crate) type BucketTargetSys = rustfs_ecstore::api::bucket::bucket_target_sys::BucketTargetSys; -pub(crate) type TonicInterceptor = rustfs_ecstore::api::rpc::TonicInterceptor; -pub(crate) type VolumeInfo = rustfs_ecstore::api::disk::VolumeInfo; -pub(crate) type WalkDirOptions = rustfs_ecstore::api::disk::WalkDirOptions; +use rustfs_ecstore::api::{bucket as ecstore_bucket, disk as ecstore_disk, rpc as ecstore_rpc}; + +pub(crate) type BucketTargetSys = ecstore_bucket::bucket_target_sys::BucketTargetSys; +pub(crate) type TonicInterceptor = ecstore_rpc::TonicInterceptor; +pub(crate) type VolumeInfo = ecstore_disk::VolumeInfo; +pub(crate) type WalkDirOptions = ecstore_disk::WalkDirOptions; pub(crate) fn gen_tonic_signature_interceptor() -> TonicInterceptor { - TonicInterceptor::Signature(rustfs_ecstore::api::rpc::gen_tonic_signature_interceptor()) + TonicInterceptor::Signature(ecstore_rpc::gen_tonic_signature_interceptor()) } pub(crate) async fn node_service_time_out_client( @@ -32,7 +34,7 @@ pub(crate) async fn node_service_time_out_client( >, Box, > { - rustfs_ecstore::api::rpc::node_service_time_out_client(addr, interceptor).await + ecstore_rpc::node_service_time_out_client(addr, interceptor).await } pub(crate) async fn node_service_time_out_client_no_auth( @@ -43,5 +45,5 @@ pub(crate) async fn node_service_time_out_client_no_auth( >, Box, > { - rustfs_ecstore::api::rpc::node_service_time_out_client_no_auth(addr).await + ecstore_rpc::node_service_time_out_client_no_auth(addr).await } diff --git a/docs/architecture/crate-boundaries.md b/docs/architecture/crate-boundaries.md index abadac082..ee9fe31af 100644 --- a/docs/architecture/crate-boundaries.md +++ b/docs/architecture/crate-boundaries.md @@ -194,6 +194,9 @@ Peripheral consumer storage compatibility boundaries must follow the same pattern. IAM, heal, scanner, notify, observability, Swift, S3 Select, test, and fuzz storage compatibility modules keep raw ECStore facade access centralized behind local `ecstore_*` module aliases. +RustFS root runtime and e2e storage compatibility boundaries must follow the +same pattern, keeping raw ECStore facade access centralized behind local +`ecstore_*` module aliases. Scanner, notify, observability, and e2e `storage_compat.rs` boundaries must also stay narrow. Scanner must not restore grouped bucket compatibility exports for target, lifecycle, metadata, replication, or versioning modules. Notify diff --git a/docs/architecture/migration-progress.md b/docs/architecture/migration-progress.md index 93aaff268..1ecfe9854 100644 --- a/docs/architecture/migration-progress.md +++ b/docs/architecture/migration-progress.md @@ -5,16 +5,17 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block ## Current Context - Issue: [`rustfs/backlog#660`](https://github.com/rustfs/backlog/issues/660) -- Branch: `overtrue/arch-outer-consumer-compat-raw-facade-prune` -- Baseline: completed `C-011/C-012/C-013/API-055/API-059/API-079/API-080/API-081/API-082/API-083/API-084/API-085/API-086/API-087/API-088/API-089/API-090/API-091/API-092/API-093`. -- Stacked on: `overtrue/arch-outer-compat-raw-facade-prune` pending API-093 merge. +- Branch: `overtrue/arch-root-e2e-compat-raw-facade-prune` +- Baseline: completed `C-011/C-012/C-013/API-055/API-059/API-079/API-080/API-081/API-082/API-083/API-084/API-085/API-086/API-087/API-088/API-089/API-090/API-091/API-092/API-093/API-094`. +- Stacked on: `overtrue/arch-outer-consumer-compat-raw-facade-prune` pending API-094 merge. - PR type for this branch: `pure-move` - Runtime behavior changes: none. -- Rust code changes: centralize peripheral consumer storage compatibility raw - ECStore facade paths behind local `ecstore_*` module aliases. -- CI/script changes: guard peripheral consumer storage compatibility boundaries - against restoring scattered raw ECStore facade paths. -- Docs changes: record the API-094 consumer facade path cleanup. +- Rust code changes: centralize RustFS root runtime and e2e storage + compatibility raw ECStore facade paths behind local `ecstore_*` module + aliases. +- CI/script changes: guard RustFS root runtime and e2e storage compatibility + boundaries against restoring scattered raw ECStore facade paths. +- Docs changes: record the API-095 root/e2e facade path cleanup. ## Phase 0 Tasks @@ -348,6 +349,19 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block - Verification: RustFS compile coverage, consumer raw facade path residual scan, migration guard, formatting, diff hygiene, Rust risk scan, pre-commit quality gate, and three-expert review. +- [x] `API-095` Prune root/e2e raw facade paths. + - Completed slice: replace scattered raw `rustfs_ecstore::api::...` paths in + the RustFS root runtime and e2e storage compatibility boundaries with local + `ecstore_*` module aliases. + - Acceptance: `rustfs/src/storage_compat.rs` and + `crates/e2e_test/src/storage_compat.rs` no longer contain raw + `rustfs_ecstore::api::...` facade paths outside centralized local alias + imports. + - Must preserve: root runtime metadata/config/global/storage/RPC wrappers and + e2e RPC harness aliases. + - Verification: RustFS compile coverage, root/e2e raw facade path residual + scan, migration guard, formatting, diff hygiene, Rust risk scan, + pre-commit quality gate, and three-expert review. - [x] `G-012` Inventory placement and repair invariants. - Acceptance: [`placement-repair-invariants.md`](placement-repair-invariants.md) records @@ -3381,14 +3395,27 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block | Expert | Status | Notes | |---|---|---| -| Quality/architecture | passed | API-094 centralizes peripheral consumer ECStore facade paths behind local `ecstore_*` module aliases without adding nested compatibility modules. | -| Migration preservation | passed | IAM config and notifications, heal disk lookup, scanner lifecycle and tier helpers, notify server config IO, observability runtime metrics, Swift metadata wrappers, S3 Select error checks, and test/fuzz harness wrappers keep the same ECStore contracts. | -| Testing/verification | passed | RustFS compile coverage, consumer raw facade path residual scan, migration and layer guards, formatting, diff hygiene, Rust risk scan, full pre-commit, and three-expert review passed. | +| Quality/architecture | passed | API-095 centralizes RustFS root runtime and e2e ECStore facade paths behind local `ecstore_*` module aliases without adding nested compatibility modules. | +| Migration preservation | passed | Root runtime metadata/config/global/storage/RPC wrappers and e2e RPC harness aliases keep the same ECStore contracts. | +| Testing/verification | passed | RustFS compile coverage, root/e2e raw facade path residual scan, migration and layer guards, formatting, diff hygiene, Rust risk scan, full pre-commit, and three-expert review passed. | ## Verification Notes Passed before push: +- Issue #660 API-095 current slice: + - `cargo check -p rustfs`: passed. + - `cargo fmt --all --check`: passed. + - `git diff --check`: passed. + - `bash -n scripts/check_architecture_migration_rules.sh`: passed. + - `./scripts/check_architecture_migration_rules.sh`: passed. + - `./scripts/check_layer_dependencies.sh`: passed. + - RustFS root/e2e raw facade path residual scan: passed. + - Rust risk scan on changed Rust files: passed. + - `make pre-commit`: passed; nextest run + `a1771057-5015-4861-9a38-b856c8abb6f6`, 6354 passed, 111 skipped; doctests + passed. + - Issue #660 API-094 current slice: - `cargo check -p rustfs`: passed. - `cargo fmt --all --check`: passed. diff --git a/rustfs/src/storage_compat.rs b/rustfs/src/storage_compat.rs index 19e2b92d3..c7af4f74b 100644 --- a/rustfs/src/storage_compat.rs +++ b/rustfs/src/storage_compat.rs @@ -14,29 +14,35 @@ use std::{collections::HashMap, sync::Arc, time::Duration}; -pub(crate) const BUCKET_TABLE_CATALOG_META_PREFIX: &str = rustfs_ecstore::api::bucket::metadata::BUCKET_TABLE_CATALOG_META_PREFIX; +use rustfs_ecstore::api::{ + bucket as ecstore_bucket, cluster as ecstore_cluster, config as ecstore_config, disk as ecstore_disk, error as ecstore_error, + event as ecstore_event, global as ecstore_global, layout as ecstore_layout, notification as ecstore_notification, + rpc as ecstore_rpc, set_disk as ecstore_set_disk, storage as ecstore_storage, +}; + +pub(crate) const BUCKET_TABLE_CATALOG_META_PREFIX: &str = ecstore_bucket::metadata::BUCKET_TABLE_CATALOG_META_PREFIX; pub(crate) const BUCKET_TABLE_CATALOG_TABLE_BUCKETS_PREFIX: &str = - rustfs_ecstore::api::bucket::metadata::BUCKET_TABLE_CATALOG_TABLE_BUCKETS_PREFIX; -pub(crate) const BUCKET_TABLE_CONFIG: &str = rustfs_ecstore::api::bucket::metadata::BUCKET_TABLE_CONFIG; -pub(crate) const BUCKET_TABLE_RESERVED_PREFIX: &str = rustfs_ecstore::api::bucket::metadata::BUCKET_TABLE_RESERVED_PREFIX; -pub(crate) const RUSTFS_META_BUCKET: &str = rustfs_ecstore::api::disk::RUSTFS_META_BUCKET; -pub(crate) const TONIC_RPC_PREFIX: &str = rustfs_ecstore::api::rpc::TONIC_RPC_PREFIX; + ecstore_bucket::metadata::BUCKET_TABLE_CATALOG_TABLE_BUCKETS_PREFIX; +pub(crate) const BUCKET_TABLE_CONFIG: &str = ecstore_bucket::metadata::BUCKET_TABLE_CONFIG; +pub(crate) const BUCKET_TABLE_RESERVED_PREFIX: &str = ecstore_bucket::metadata::BUCKET_TABLE_RESERVED_PREFIX; +pub(crate) const RUSTFS_META_BUCKET: &str = ecstore_disk::RUSTFS_META_BUCKET; +pub(crate) const TONIC_RPC_PREFIX: &str = ecstore_rpc::TONIC_RPC_PREFIX; -pub(crate) type ECStore = rustfs_ecstore::api::storage::ECStore; -pub(crate) type EcstoreError = rustfs_ecstore::api::error::Error; -pub(crate) type EcstoreEventArgs = rustfs_ecstore::api::event::EventArgs; -pub(crate) type EcstoreResult = rustfs_ecstore::api::error::Result; -pub(crate) type Endpoint = rustfs_ecstore::api::disk::endpoint::Endpoint; -pub(crate) type EndpointServerPools = rustfs_ecstore::api::layout::EndpointServerPools; -pub(crate) type QuotaError = rustfs_ecstore::api::bucket::quota::QuotaError; -pub(crate) type StorageError = rustfs_ecstore::api::error::StorageError; +pub(crate) type ECStore = ecstore_storage::ECStore; +pub(crate) type EcstoreError = ecstore_error::Error; +pub(crate) type EcstoreEventArgs = ecstore_event::EventArgs; +pub(crate) type EcstoreResult = ecstore_error::Result; +pub(crate) type Endpoint = ecstore_disk::endpoint::Endpoint; +pub(crate) type EndpointServerPools = ecstore_layout::EndpointServerPools; +pub(crate) type QuotaError = ecstore_bucket::quota::QuotaError; +pub(crate) type StorageError = ecstore_error::StorageError; #[cfg(test)] -pub(crate) type DisksLayout = rustfs_ecstore::api::layout::DisksLayout; +pub(crate) type DisksLayout = ecstore_layout::DisksLayout; #[cfg(test)] -pub(crate) type Endpoints = rustfs_ecstore::api::layout::Endpoints; +pub(crate) type Endpoints = ecstore_layout::Endpoints; #[cfg(test)] -pub(crate) type PoolEndpoints = rustfs_ecstore::api::layout::PoolEndpoints; +pub(crate) type PoolEndpoints = ecstore_layout::PoolEndpoints; pub(crate) trait DiskAPI { fn endpoint(&self) -> Endpoint; @@ -45,68 +51,62 @@ pub(crate) trait DiskAPI { impl DiskAPI for T where - T: rustfs_ecstore::api::disk::DiskAPI, + T: ecstore_disk::DiskAPI, { fn endpoint(&self) -> Endpoint { - rustfs_ecstore::api::disk::DiskAPI::endpoint(self) + ecstore_disk::DiskAPI::endpoint(self) } fn to_string(&self) -> String { - rustfs_ecstore::api::disk::DiskAPI::to_string(self) + ecstore_disk::DiskAPI::to_string(self) } } pub(crate) fn table_catalog_path_hash(value: &str) -> String { - rustfs_ecstore::api::bucket::metadata::table_catalog_path_hash(value) + ecstore_bucket::metadata::table_catalog_path_hash(value) } -pub(crate) async fn get_bucket_metadata( - bucket: &str, -) -> rustfs_ecstore::api::error::Result> { - rustfs_ecstore::api::bucket::metadata_sys::get(bucket).await +pub(crate) async fn get_bucket_metadata(bucket: &str) -> ecstore_error::Result> { + ecstore_bucket::metadata_sys::get(bucket).await } -pub(crate) fn get_global_bucket_metadata_sys() --> Option>> { - rustfs_ecstore::api::bucket::metadata_sys::get_global_bucket_metadata_sys() +pub(crate) fn get_global_bucket_metadata_sys() -> Option>> +{ + ecstore_bucket::metadata_sys::get_global_bucket_metadata_sys() } -pub(crate) async fn get_notification_config( - bucket: &str, -) -> rustfs_ecstore::api::error::Result> { - rustfs_ecstore::api::bucket::metadata_sys::get_notification_config(bucket).await +pub(crate) async fn get_notification_config(bucket: &str) -> ecstore_error::Result> { + ecstore_bucket::metadata_sys::get_notification_config(bucket).await } pub(crate) async fn init_bucket_metadata_sys(api: Arc, buckets: Vec) { - rustfs_ecstore::api::bucket::metadata_sys::init_bucket_metadata_sys(api, buckets).await; + ecstore_bucket::metadata_sys::init_bucket_metadata_sys(api, buckets).await; } pub(crate) async fn try_migrate_bucket_metadata(store: Arc) { - rustfs_ecstore::api::bucket::migration::try_migrate_bucket_metadata(store).await; + ecstore_bucket::migration::try_migrate_bucket_metadata(store).await; } pub(crate) async fn try_migrate_iam_config(store: Arc) { - rustfs_ecstore::api::bucket::migration::try_migrate_iam_config(store).await; + ecstore_bucket::migration::try_migrate_iam_config(store).await; } -pub(crate) fn get_global_replication_pool() -> Option> { - rustfs_ecstore::api::bucket::replication::get_global_replication_pool() +pub(crate) fn get_global_replication_pool() -> Option> { + ecstore_bucket::replication::get_global_replication_pool() } pub(crate) fn replication_queue_current_count() -> Option { - rustfs_ecstore::api::bucket::replication::GLOBAL_REPLICATION_STATS - .get() - .and_then(|stats| { - stats - .q_cache - .try_lock() - .ok() - .map(|cache| cache.sr_queue_stats.curr.get_current_count()) - }) + ecstore_bucket::replication::GLOBAL_REPLICATION_STATS.get().and_then(|stats| { + stats + .q_cache + .try_lock() + .ok() + .map(|cache| cache.sr_queue_stats.curr.get_current_count()) + }) } pub(crate) async fn init_background_replication(storage: Arc) { - rustfs_ecstore::api::bucket::replication::init_background_replication(storage).await; + ecstore_bucket::replication::init_background_replication(storage).await; } pub(crate) fn topology_snapshot_from_endpoint_pools_with_capabilities( @@ -114,104 +114,100 @@ pub(crate) fn topology_snapshot_from_endpoint_pools_with_capabilities( capabilities: rustfs_storage_api::TopologyCapabilities, disk_capabilities: rustfs_storage_api::DiskCapabilities, ) -> rustfs_storage_api::TopologySnapshot { - rustfs_ecstore::api::cluster::topology_snapshot_from_endpoint_pools_with_capabilities( - endpoint_pools, - capabilities, - disk_capabilities, - ) + ecstore_cluster::topology_snapshot_from_endpoint_pools_with_capabilities(endpoint_pools, capabilities, disk_capabilities) } pub(crate) async fn read_ecstore_config(api: Arc, file: &str) -> EcstoreResult> { - rustfs_ecstore::api::config::com::read_config(api, file).await + ecstore_config::com::read_config(api, file).await } pub(crate) async fn save_ecstore_config(api: Arc, file: &str, data: Vec) -> EcstoreResult<()> { - rustfs_ecstore::api::config::com::save_config(api, file, data).await + ecstore_config::com::save_config(api, file, data).await } pub(crate) fn init_ecstore_config() { - rustfs_ecstore::api::config::init(); + ecstore_config::init(); } pub(crate) async fn init_global_config_sys(api: Arc) -> EcstoreResult<()> { - rustfs_ecstore::api::config::init_global_config_sys(api).await + ecstore_config::init_global_config_sys(api).await } pub(crate) async fn try_migrate_server_config(api: Arc) { - rustfs_ecstore::api::config::try_migrate_server_config(api).await; + ecstore_config::try_migrate_server_config(api).await; } pub(crate) fn register_event_dispatch_hook(hook: F) -> bool where F: Fn(EcstoreEventArgs) + Send + Sync + 'static, { - rustfs_ecstore::api::event::register_event_dispatch_hook(hook) + ecstore_event::register_event_dispatch_hook(hook) } pub(crate) fn get_global_endpoints_opt() -> Option { - rustfs_ecstore::api::global::get_global_endpoints_opt() + ecstore_global::get_global_endpoints_opt() } pub(crate) fn get_global_lock_clients() -> Option<&'static HashMap>> { - rustfs_ecstore::api::global::get_global_lock_clients() + ecstore_global::get_global_lock_clients() } pub(crate) fn get_global_region() -> Option { - rustfs_ecstore::api::global::get_global_region() + ecstore_global::get_global_region() } pub(crate) async fn is_dist_erasure() -> bool { - rustfs_ecstore::api::global::is_dist_erasure().await + ecstore_global::is_dist_erasure().await } pub(crate) fn resolve_object_store_handle() -> Option> { - rustfs_ecstore::api::global::resolve_object_store_handle() + ecstore_global::resolve_object_store_handle() } -pub(crate) fn set_global_endpoints(eps: Vec) { - rustfs_ecstore::api::global::set_global_endpoints(eps); +pub(crate) fn set_global_endpoints(eps: Vec) { + ecstore_global::set_global_endpoints(eps); } pub(crate) fn set_global_region(region: s3s::region::Region) { - rustfs_ecstore::api::global::set_global_region(region); + ecstore_global::set_global_region(region); } pub(crate) fn set_global_rustfs_port(value: u16) { - rustfs_ecstore::api::global::set_global_rustfs_port(value); + ecstore_global::set_global_rustfs_port(value); } pub(crate) fn shutdown_background_services() { - rustfs_ecstore::api::global::shutdown_background_services(); + ecstore_global::shutdown_background_services(); } -pub(crate) async fn update_erasure_type(setup_type: rustfs_ecstore::api::layout::SetupType) { - rustfs_ecstore::api::global::update_erasure_type(setup_type).await; +pub(crate) async fn update_erasure_type(setup_type: ecstore_layout::SetupType) { + ecstore_global::update_erasure_type(setup_type).await; } pub(crate) async fn new_global_notification_sys(eps: EndpointServerPools) -> EcstoreResult<()> { - rustfs_ecstore::api::notification::new_global_notification_sys(eps).await + ecstore_notification::new_global_notification_sys(eps).await } pub(crate) fn verify_rpc_signature(url: &str, method: &http::Method, headers: &http::HeaderMap) -> std::io::Result<()> { - rustfs_ecstore::api::rpc::verify_rpc_signature(url, method, headers) + ecstore_rpc::verify_rpc_signature(url, method, headers) } pub(crate) fn get_lock_acquire_timeout() -> Duration { - rustfs_ecstore::api::set_disk::get_lock_acquire_timeout() + ecstore_set_disk::get_lock_acquire_timeout() } -pub(crate) async fn all_local_disk() -> Vec { - rustfs_ecstore::api::storage::all_local_disk().await +pub(crate) async fn all_local_disk() -> Vec { + ecstore_storage::all_local_disk().await } pub(crate) async fn init_local_disks(endpoint_pools: EndpointServerPools) -> EcstoreResult<()> { - rustfs_ecstore::api::storage::init_local_disks(endpoint_pools).await + ecstore_storage::init_local_disks(endpoint_pools).await } pub(crate) fn init_lock_clients(endpoint_pools: EndpointServerPools) { - rustfs_ecstore::api::storage::init_lock_clients(endpoint_pools); + ecstore_storage::init_lock_clients(endpoint_pools); } pub(crate) async fn prewarm_local_disk_id_map() { - rustfs_ecstore::api::storage::prewarm_local_disk_id_map().await; + ecstore_storage::prewarm_local_disk_id_map().await; } diff --git a/scripts/check_architecture_migration_rules.sh b/scripts/check_architecture_migration_rules.sh index 457e420a7..4b48179aa 100755 --- a/scripts/check_architecture_migration_rules.sh +++ b/scripts/check_architecture_migration_rules.sh @@ -91,6 +91,7 @@ RUSTFS_OUTER_COMPAT_SIGNATURE_ALIAS_HITS_FILE="${TMP_DIR}/rustfs_outer_compat_si RUSTFS_STORAGE_COMPAT_RAW_FACADE_PATH_HITS_FILE="${TMP_DIR}/rustfs_storage_compat_raw_facade_path_hits.txt" RUSTFS_APP_ADMIN_COMPAT_RAW_FACADE_PATH_HITS_FILE="${TMP_DIR}/rustfs_app_admin_compat_raw_facade_path_hits.txt" OUTER_CONSUMER_COMPAT_RAW_FACADE_PATH_HITS_FILE="${TMP_DIR}/outer_consumer_compat_raw_facade_path_hits.txt" +RUSTFS_ROOT_E2E_COMPAT_RAW_FACADE_PATH_HITS_FILE="${TMP_DIR}/rustfs_root_e2e_compat_raw_facade_path_hits.txt" SCANNER_BUCKET_STORAGE_COMPAT_MODULE_HITS_FILE="${TMP_DIR}/scanner_bucket_storage_compat_module_hits.txt" NOTIFY_STORAGE_COMPAT_MODULE_HITS_FILE="${TMP_DIR}/notify_storage_compat_module_hits.txt" OBS_STORAGE_COMPAT_PASSTHROUGH_HITS_FILE="${TMP_DIR}/obs_storage_compat_passthrough_hits.txt" @@ -949,6 +950,16 @@ if [[ -s "$OUTER_CONSUMER_COMPAT_RAW_FACADE_PATH_HITS_FILE" ]]; then report_failure "outer consumer storage compatibility must use local ecstore_* module aliases instead of scattered raw ECStore facade paths: $(paste -sd '; ' "$OUTER_CONSUMER_COMPAT_RAW_FACADE_PATH_HITS_FILE")" fi +( + cd "$ROOT_DIR" + rg -n --no-heading 'rustfs_ecstore::api::' rustfs/src/storage_compat.rs crates/e2e_test/src/storage_compat.rs \ + | rg -v '^[^:]+:[0-9]+:use rustfs_ecstore::api::\{' || true +) >"$RUSTFS_ROOT_E2E_COMPAT_RAW_FACADE_PATH_HITS_FILE" + +if [[ -s "$RUSTFS_ROOT_E2E_COMPAT_RAW_FACADE_PATH_HITS_FILE" ]]; then + report_failure "RustFS root/e2e storage compatibility must use local ecstore_* module aliases instead of scattered raw ECStore facade paths: $(paste -sd '; ' "$RUSTFS_ROOT_E2E_COMPAT_RAW_FACADE_PATH_HITS_FILE")" +fi + ( cd "$ROOT_DIR" rg -n --no-heading 'pub\(crate\)\s+use rustfs_ecstore::api::bucket::\{[^}]*\b(?:bucket_target_sys|lifecycle|metadata_sys|replication|versioning|versioning_sys)\b[^}]*\}\s*;' \