Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
83 changes: 21 additions & 62 deletions src/install/PackageInstall.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2278,68 +2278,27 @@ impl<'a> PackageInstall<'a> {
let state = manager.get_preinstall_state(package_id);
match state {
crate::PreinstallState::Done => false,
_ => 'brk: {
if self.patch.is_none() {
let exists = match resolution_tag {
resolution::Tag::Npm => 'package_json_exists: {
// SAFETY: `buf` and `self.cache_dir_subpath` both derive from the
// same thread-local `cached_package_folder_name_buf` raw pointer
// (the debug_assert below checks the subpath aliases this buffer),
// so there is no cross-thread access. No other `&mut` into the
// buffer is created while `buf` is live, and the only writes are
// at indices >= `subpath_len` — past the subpath's contents — with
// the NUL terminator restored by the scopeguard before the borrow
// ends.
let buf: &mut [u8] = unsafe {
(*crate::package_manager::cached_package_folder_name_buf())
.as_mut_slice()
};

debug_assert!(bun_core::is_slice_in_buffer(
self.cache_dir_subpath.as_bytes(),
buf
));

let subpath_len =
strings::without_trailing_slash(self.cache_dir_subpath.as_bytes())
.len();
buf[subpath_len] = SEP;
// SAFETY: p points into the long-lived cached_package_folder_name_buf;
// subpath_len is in bounds (was the prior NUL position).
let _restore =
scopeguard::guard(buf.as_mut_ptr(), move |p: *mut u8| unsafe {
*p.add(subpath_len) = 0;
});
buf[subpath_len + 1..subpath_len + 1 + b"package.json\0".len()]
.copy_from_slice(b"package.json\0");
// SAFETY: NUL written above.
let subpath =
ZStr::from_buf(&buf[..], subpath_len + 1 + b"package.json".len());
break 'package_json_exists sys::exists_at(self.cache_dir, subpath);
}
_ => sys::directory_exists_at(self.cache_dir, self.cache_dir_subpath)
.unwrap_or(false),
};
if exists {
manager.set_preinstall_state(package_id, crate::PreinstallState::Done);
}
break 'brk !exists;
}
let idx = strings::last_index_of(self.cache_dir_subpath.as_bytes(), b"_patch_hash=")
.unwrap_or_else(|| {
panic!("Patched dependency cache dir subpath does not have the \"_patch_hash=HASH\" suffix. This is a bug, please file a GitHub issue.")
});
let cache_dir_subpath_without_patch_hash =
&self.cache_dir_subpath.as_bytes()[..idx];
// Use a stack PathBuffer (no shared state).
let mut join_buf = PathBuffer::uninit();
join_buf[..cache_dir_subpath_without_patch_hash.len()]
.copy_from_slice(cache_dir_subpath_without_patch_hash);
join_buf[cache_dir_subpath_without_patch_hash.len()] = 0;
// SAFETY: NUL written above.
let subpath =
ZStr::from_buf(&join_buf[..], cache_dir_subpath_without_patch_hash.len());
let exists = sys::directory_exists_at(self.cache_dir, subpath).unwrap_or(false);
_ => {
let exists = if self.patch.is_none() {
crate::package_manager::directories::is_package_in_cache_at(
self.cache_dir,
self.cache_dir_subpath,
resolution_tag,
)
} else {
let idx =
strings::last_index_of(self.cache_dir_subpath.as_bytes(), b"_patch_hash=")
.unwrap_or_else(|| {
panic!("Patched dependency cache dir subpath does not have the \"_patch_hash=HASH\" suffix. This is a bug, please file a GitHub issue.")
});
let non_patched =
bun_core::ZBox::from_bytes(&self.cache_dir_subpath.as_bytes()[..idx]);
crate::package_manager::directories::is_package_in_cache_at(
self.cache_dir,
&non_patched,
resolution_tag,
)
};
if exists {
manager.set_preinstall_state(package_id, crate::PreinstallState::Done);
}
Expand Down
23 changes: 23 additions & 0 deletions src/install/PackageManager/PackageManagerDirectories.rs
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,29 @@ pub fn is_folder_in_cache(this: &mut PackageManager, folder_path: &ZStr) -> bool
sys::directory_exists_at(get_cache_directory(this), folder_path).unwrap_or(false)
}

/// Cache hit for an unpatched entry: npm folders must contain `package.json`, git checkouts the `.bun-tag` written last.
pub fn is_package_in_cache_at(cache_dir: Fd, folder_path: &ZStr, tag: ResolutionTag) -> bool {
let marker: &[u8] = match tag {
ResolutionTag::Npm => b"package.json",
ResolutionTag::Git => b".bun-tag",
_ => return sys::directory_exists_at(cache_dir, folder_path).unwrap_or(false),
};
let mut buf = PathBuffer::uninit();
let marker_path = path::resolve_path::join_z_buf::<path::platform::Auto>(
&mut buf.0,
&[folder_path.as_bytes(), marker],
);
sys::exists_at(cache_dir, marker_path)
}

pub fn is_package_in_cache(
this: &mut PackageManager,
folder_path: &ZStr,
tag: ResolutionTag,
) -> bool {
is_package_in_cache_at(get_cache_directory(this), folder_path, tag)
}

// ─────────────────────────── global directories ───────────────────────────────

pub fn setup_global_dir(manager: &mut PackageManager, ctx: &Command::Context) -> Result<(), Error> {
Expand Down
10 changes: 8 additions & 2 deletions src/install/PackageManager/PackageManagerLifecycle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,12 @@ impl PackageManager {
return PreinstallState::Extract;
}

if directories::is_folder_in_cache(self, folder_path) {
let in_cache = if patch_hash.is_some() {
directories::is_folder_in_cache(self, folder_path)
} else {
directories::is_package_in_cache(self, folder_path, pkg.resolution.tag)
};
if in_cache {
self.set_preinstall_state(pkg.meta.id, PreinstallState::Done);
return PreinstallState::Done;
}
Expand All @@ -181,7 +186,8 @@ impl PackageManager {
});
// Owned NUL-terminated copy.
let non_patched_path = ZBox::from_bytes(&folder_path.as_bytes()[..idx]);
if directories::is_folder_in_cache(self, &non_patched_path) {
if directories::is_package_in_cache(self, &non_patched_path, pkg.resolution.tag)
{
self.set_preinstall_state(pkg.meta.id, PreinstallState::ApplyPatch);
// yay step 1 is already done for us
return PreinstallState::ApplyPatch;
Expand Down
Loading
Loading