Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
266 changes: 126 additions & 140 deletions src/install/PackageManager/patchPackage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,161 +159,125 @@ pub fn do_patch_commit(
};

let mut iterator = tree::Iterator::<{ tree::IteratorPathStyle::NodeModules }>::init(&lockfile);
// reshaped for borrowck — `compute_cache_dir_and_subpath` borrows
// `manager` mutably while the package name/resolution borrow `lockfile`
// (which itself sometimes aliases `manager.lockfile`). Clone the slice/
// resolution out first, then compute, then assemble the result tuple.
let (cache_dir, cache_dir_subpath, changes_dir, pkg): (Fd, &ZStr, Vec<u8>, Package) =
match arg_kind {
PatchArgKind::Path => 'result: {
let package_json_path =
resolve_path::join_z::<platform::Auto>(&[argument, b"package.json"]);
let package_json_source: bun_ast::Source =
match bun_ast::to_source(package_json_path, Default::default()) {
Ok(s) => s,
Err(e) => {
Output::err(
e,
"failed to read {f}",
(bun_fmt::quote(package_json_path.as_bytes()),),
);
Global::crash();
}
};

initialize_store();
let log = manager.log_mut();
let parsed = match JSON::ParsedJson::parse_package_json(&package_json_source, log) {
Ok(p) => p,
Err(err) => {
let _ = log.print(std::ptr::from_mut(Output::error_writer()));
bun_core::pretty_errorln!(
"<r><red>{}<r> parsing package.json in <b>\"{}\"<r>",
err.name(),
bstr::BStr::new(package_json_source.path.pretty_dir()),
let (changes_dir, pkg): (Vec<u8>, Package) = match arg_kind {
PatchArgKind::Path => 'result: {
let package_json_path =
resolve_path::join_z::<platform::Auto>(&[argument, b"package.json"]);
let package_json_source: bun_ast::Source =
match bun_ast::to_source(package_json_path, Default::default()) {
Ok(s) => s,
Err(e) => {
Output::err(
e,
"failed to read {f}",
(bun_fmt::quote(package_json_path.as_bytes()),),
);
Global::crash();
}
};
let json = parsed.root;

let version: &[u8] = 'version: {
if let Some(v) = json.get(b"version") {
if let bun_ast::ExprData::EString(s) = &v.data {
let s = s.data.slice();
break 'version s;
}
}
bun_core::pretty_error!(
"<r><red>error<r>: invalid package.json, missing or invalid property \"version\": {}<r>\n",
bstr::BStr::new(package_json_source.path.text()),
initialize_store();
let log = manager.log_mut();
let parsed = match JSON::ParsedJson::parse_package_json(&package_json_source, log) {
Ok(p) => p,
Err(err) => {
let _ = log.print(std::ptr::from_mut(Output::error_writer()));
bun_core::pretty_errorln!(
"<r><red>{}<r> parsing package.json in <b>\"{}\"<r>",
err.name(),
bstr::BStr::new(package_json_source.path.pretty_dir()),
);
Global::crash();
};

let mut resolver: () = ();
let mut package = Package::default();
let log = manager.log_mut();
package.parse_with_json::<()>(
&mut lockfile,
manager,
log,
&package_json_source,
json,
&mut resolver,
Features::FOLDER,
)?;
}
};
let json = parsed.root;

let actual_package = match lockfile.package_index.get(&package.name_hash) {
None => {
bun_core::pretty_error!(
"<r><red>error<r>: failed to find package in lockfile package index, this is a bug in Bun. Please file a GitHub issue.<r>\n",
);
Global::crash();
let version: &[u8] = 'version: {
if let Some(v) = json.get(b"version") {
if let bun_ast::ExprData::EString(s) = &v.data {
let s = s.data.slice();
break 'version s;
}
Some(PackageIndexEntry::Id(id)) => *lockfile.packages.get(*id as usize),
Some(PackageIndexEntry::Ids(ids)) => 'brk: {
let mut resolution_label = Vec::new();
for &id in ids.as_slice() {
let pkg = *lockfile.packages.get(id as usize);
if print_resolution_label(
&mut resolution_label,
&pkg.resolution,
lockfile.buffers.string_bytes.as_slice(),
) == version
{
break 'brk pkg;
}
}
bun_core::pretty_error!(
"<r><red>error<r>: could not find package with name:<r> {}\n<r>",
bstr::BStr::new(
package.name.slice(lockfile.buffers.string_bytes.as_slice())
),
);
Global::crash();
}
};

let name = lockfile.str(&package.name).to_vec();
let resolution_clone = actual_package.resolution;
let cache_result = compute_cache_dir_and_subpath(
manager,
&name,
&resolution_clone,
&mut folder_path_buf,
None,
}
bun_core::pretty_error!(
"<r><red>error<r>: invalid package.json, missing or invalid property \"version\": {}<r>\n",
bstr::BStr::new(package_json_source.path.text()),
);
let cache_dir = cache_result.cache_dir;
let cache_dir_subpath = cache_result.cache_dir_subpath;

let changes_dir = argument.to_vec();
Global::crash();
};

break 'result (cache_dir, cache_dir_subpath, changes_dir, actual_package);
}
PatchArgKind::NameAndVersion => 'brk: {
let (name, version) = Dependency::split_name_and_maybe_version(argument);
let (pkg_id, node_modules_relative_path) = pkg_info_for_name_and_version(
&lockfile,
&mut iterator,
argument,
name,
version,
);
let mut resolver: () = ();
let mut package = Package::default();
let log = manager.log_mut();
package.parse_with_json::<()>(
&mut lockfile,
manager,
log,
&package_json_source,
json,
&mut resolver,
Features::FOLDER,
)?;

let actual_package = match lockfile.package_index.get(&package.name_hash) {
None => {
bun_core::pretty_error!(
"<r><red>error<r>: failed to find package in lockfile package index, this is a bug in Bun. Please file a GitHub issue.<r>\n",
);
Global::crash();
}
Some(PackageIndexEntry::Id(id)) => *lockfile.packages.get(*id as usize),
Some(PackageIndexEntry::Ids(ids)) => 'brk: {
let mut resolution_label = Vec::new();
for &id in ids.as_slice() {
let pkg = *lockfile.packages.get(id as usize);
if print_resolution_label(
&mut resolution_label,
&pkg.resolution,
lockfile.buffers.string_bytes.as_slice(),
) == version
{
break 'brk pkg;
}
}
bun_core::pretty_error!(
"<r><red>error<r>: could not find package with name:<r> {}\n<r>",
bstr::BStr::new(
package.name.slice(lockfile.buffers.string_bytes.as_slice())
),
);
Global::crash();
}
};

let changes_dir = resolve_path::join_z_buf::<platform::Auto>(
&mut pathbuf[..],
&[&node_modules_relative_path, name],
)
.as_bytes()
.to_vec();
let pkg = *lockfile.packages.get(pkg_id as usize);

let pkg_name_slice = pkg
.name
.slice(lockfile.buffers.string_bytes.as_slice())
.to_vec();
let resolution_clone = pkg.resolution;
let cache_result = compute_cache_dir_and_subpath(
manager,
&pkg_name_slice,
&resolution_clone,
&mut folder_path_buf,
None,
);
let cache_dir = cache_result.cache_dir;
let cache_dir_subpath = cache_result.cache_dir_subpath;
break 'brk (cache_dir, cache_dir_subpath, changes_dir, pkg);
}
};
break 'result (argument.to_vec(), actual_package);
}
PatchArgKind::NameAndVersion => 'brk: {
let (name, version) = Dependency::split_name_and_maybe_version(argument);
let (pkg_id, node_modules_relative_path) =
pkg_info_for_name_and_version(&lockfile, &mut iterator, argument, name, version);

let changes_dir = resolve_path::join_z_buf::<platform::Auto>(
&mut pathbuf[..],
&[&node_modules_relative_path, name],
)
.as_bytes()
.to_vec();
break 'brk (changes_dir, *lockfile.packages.get(pkg_id as usize));
}
};

// zls
let cache_dir: Fd = cache_dir;
let cache_dir_subpath: &ZStr = cache_dir_subpath;
// `compute_cache_dir_and_subpath` resolves `pkg.resolution`'s strings against `manager.lockfile`.
manager.lockfile = lockfile;
let name = manager.lockfile.str(&pkg.name).to_vec();
let cache_result =
compute_cache_dir_and_subpath(manager, &name, &pkg.resolution, &mut folder_path_buf, None);
let cache_dir: Fd = cache_result.cache_dir;
let cache_dir_subpath: &ZStr = cache_result.cache_dir_subpath;
let changes_dir: &[u8] = &changes_dir;
let pkg: Package = pkg;
let lockfile: &Lockfile = &manager.lockfile;

let name = pkg.name.slice(lockfile.buffers.string_bytes.as_slice());
let name = name.as_slice();
let mut patch_key = Vec::new();
write!(
&mut patch_key,
Expand Down Expand Up @@ -653,6 +617,14 @@ fn escape_patch_filename(name: &[u8]) -> Option<Box<[u8]>> {
Newline,
CarriageReturn,
Tab,
// NTFS-reserved; escaped on every OS so a committed patches/ dir checks out on Windows.
Colon,
Question,
Asterisk,
Quote,
LessThan,
GreaterThan,
Pipe,
// Dot,
Other,
}
Expand All @@ -666,6 +638,13 @@ fn escape_patch_filename(name: &[u8]) -> Option<Box<[u8]>> {
EscapeVal::Newline => Some(b"%0A"),
EscapeVal::CarriageReturn => Some(b"%0D"),
EscapeVal::Tab => Some(b"%09"),
EscapeVal::Colon => Some(b"%3A"),
EscapeVal::Question => Some(b"%3F"),
EscapeVal::Asterisk => Some(b"%2A"),
EscapeVal::Quote => Some(b"%22"),
EscapeVal::LessThan => Some(b"%3C"),
EscapeVal::GreaterThan => Some(b"%3E"),
EscapeVal::Pipe => Some(b"%7C"),
// EscapeVal::Dot => Some(b"%2E"),
EscapeVal::Other => None,
}
Expand All @@ -681,6 +660,13 @@ fn escape_patch_filename(name: &[u8]) -> Option<Box<[u8]>> {
table[b'\n' as usize] = EscapeVal::Newline;
table[b'\r' as usize] = EscapeVal::CarriageReturn;
table[b'\t' as usize] = EscapeVal::Tab;
table[b':' as usize] = EscapeVal::Colon;
table[b'?' as usize] = EscapeVal::Question;
table[b'*' as usize] = EscapeVal::Asterisk;
table[b'"' as usize] = EscapeVal::Quote;
table[b'<' as usize] = EscapeVal::LessThan;
table[b'>' as usize] = EscapeVal::GreaterThan;
table[b'|' as usize] = EscapeVal::Pipe;
table
};
let mut count: usize = 0;
Expand Down
Loading
Loading