Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .github/workflows/pm-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,12 @@ jobs:
- name: Disable Windows Defender
if: runner.os == 'Windows'
shell: powershell
run: Set-MpPreference -DisableRealtimeMonitoring $true
run: |
try {
Set-MpPreference -DisableRealtimeMonitoring $true -ErrorAction Stop
} catch {
Write-Warning "Unable to disable Windows Defender real-time monitoring: $_"
}
# Add: Configure Git longpaths on Windows
- name: Configure Git (Windows)
Expand Down
18 changes: 16 additions & 2 deletions .github/workflows/pm-e2e-bench.yml
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ jobs:
targets: x86_64-unknown-linux-gnu
- name: Cache cargo
uses: Swatinem/rust-cache@v2
continue-on-error: true
with:
shared-key: pm-build-linux
cache-bin: false
Expand Down Expand Up @@ -200,6 +201,7 @@ jobs:
targets: aarch64-apple-darwin
- name: Cache cargo
uses: Swatinem/rust-cache@v2
continue-on-error: true
with:
shared-key: pm-build-mac-arm64
cache-bin: false
Expand Down Expand Up @@ -232,6 +234,7 @@ jobs:
run: rustup target add x86_64-apple-darwin
- name: Cache cargo
uses: Swatinem/rust-cache@v2
continue-on-error: true
with:
shared-key: pm-build-mac-x64
cache-bin: false
Expand All @@ -254,7 +257,12 @@ jobs:
- uses: actions/checkout@v4
- name: Disable Windows Defender
shell: powershell
run: Set-MpPreference -DisableRealtimeMonitoring $true
run: |
try {
Set-MpPreference -DisableRealtimeMonitoring $true -ErrorAction Stop
} catch {
Write-Warning "Unable to disable Windows Defender real-time monitoring: $_"
}
- name: Init git submodules
run: git submodule update --init --recursive --depth 1
- name: Setup Rust toolchain
Expand All @@ -264,6 +272,7 @@ jobs:
targets: x86_64-pc-windows-msvc
- name: Cache cargo
uses: Swatinem/rust-cache@v2
continue-on-error: true
with:
shared-key: pm-build-windows
cache-bin: false
Expand Down Expand Up @@ -408,7 +417,12 @@ jobs:
- uses: actions/checkout@v4
- name: Disable Windows Defender
shell: powershell
run: Set-MpPreference -DisableRealtimeMonitoring $true
run: |
try {
Set-MpPreference -DisableRealtimeMonitoring $true -ErrorAction Stop
} catch {
Write-Warning "Unable to disable Windows Defender real-time monitoring: $_"
}
- name: Setup node
uses: actions/setup-node@v4
with:
Expand Down
41 changes: 37 additions & 4 deletions crates/pm/src/cmd/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ use crate::util::user_config::get_registry;

/// View package information from registry, similar to npm view
pub async fn view(package_spec: &str) -> Result<()> {
let registry_url = get_registry();
view_with_registry(package_spec, &registry_url).await
}

async fn view_with_registry(package_spec: &str, registry_url: &str) -> Result<()> {
tracing::debug!("Viewing package: {package_spec}");

// Parse package specification
Expand All @@ -18,9 +23,8 @@ pub async fn view(package_spec: &str) -> Result<()> {
tracing::debug!("Resolved package: {name} (spec: {version_spec})");

// Fetch full manifest directly from registry (Complete format for display, no ETag)
let registry_url = get_registry();
let (full_manifest, _etag) =
fetch_full_manifest_fresh(&registry_url, name, MetadataFormat::Complete)
fetch_full_manifest_fresh(registry_url, name, MetadataFormat::Complete)
.await
.map_err(|e| anyhow!("Failed to fetch package info for {}: {}", package_spec, e))?;

Expand Down Expand Up @@ -356,12 +360,41 @@ mod tests {
/// because the registry service used ETag caching.
#[tokio::test]
async fn test_view_twice_no_304_error() {
use mockito::Matcher;

let mut server = mockito::Server::new_async().await;
let manifest = r#"{
"name": "is-odd",
"description": "mock package",
"dist-tags": { "latest": "1.0.0" },
"versions": {
"1.0.0": {
"name": "is-odd",
"version": "1.0.0",
"description": "mock package",
"dist": {}
}
}
}"#;
let mock = server
.mock("GET", "/is-odd")
.match_header("accept", "application/json")
.match_header("if-none-match", Matcher::Missing)
.with_status(200)
.with_header("content-type", "application/json")
.with_header("etag", "\"mock-etag\"")
.with_body(manifest)
.expect(2)
.create_async()
.await;

// First view - should succeed
let result1 = view("is-odd").await;
let result1 = view_with_registry("is-odd", &server.url()).await;
assert!(result1.is_ok(), "First view failed: {:?}", result1.err());

// Second view - should also succeed (not fail with 304 error)
let result2 = view("is-odd").await;
let result2 = view_with_registry("is-odd", &server.url()).await;
assert!(result2.is_ok(), "Second view failed: {:?}", result2.err());
mock.assert_async().await;
}
}
39 changes: 34 additions & 5 deletions crates/pm/src/service/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ pub async fn install_packages(
groups: &HashMap<usize, Vec<(String, Package)>>,
cwd: &Path,
omit: &HashSet<OmitType>,
scheduler: Option<&super::install_scheduler::InstallScheduler>,
) -> Result<()> {
use crate::util::cloner::clone_package_once;

Expand Down Expand Up @@ -144,11 +145,26 @@ pub async fn install_packages(
// Check if this is an optional dependency
let is_optional =
package.optional == Some(true) || package.dev_optional == Some(true);
let scheduler = scheduler.cloned();

let task = tokio::spawn(async move {
if let Err(e) =
clone_package_once(&name, &version, &resolved, &target_path).await
{
let clone_result = match scheduler {
Some(scheduler) => {
scheduler
.ensure_clone(
name.clone(),
version,
resolved,
target_path.clone(),
)
.await
}
None => {
clone_package_once(&name, &version, &resolved, &target_path).await
}
};

if let Err(e) = clone_result {
if is_optional {
tracing::warn!(
"Optional dependency {name} failed (ignored): {e:#}"
Expand Down Expand Up @@ -264,9 +280,22 @@ impl InstallService {
}

let link_start = Instant::now();
install_packages(&groups, root_path, omit)
let scheduler_handle = if use_fresh_lock {
Some(super::install_scheduler::InstallSchedulerHandle::start())
} else {
None
};
let scheduler = scheduler_handle.as_ref().map(|handle| handle.scheduler());

let install_result = install_packages(&groups, root_path, omit, scheduler.as_ref())
.await
.context("Failed to install packages")?;
.context("Failed to install packages");

if let Some(handle) = scheduler_handle {
handle.shutdown().await;
}

install_result?;

// Wait for pipeline workers to complete (if any)
if let Some(handles) = pipeline_handles {
Expand Down
Loading
Loading