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
62 changes: 39 additions & 23 deletions src/install/lockfile/Package.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,38 @@ fn invalid_trusted_dependencies(
crate::Error::InvalidPackageJSON
}

/// A declared `trustedDependencies` (even `[]`) replaces the default list, so the set becomes `Some` as soon as the field exists.
pub(crate) fn parse_append_trusted_dependencies(
trusted_dependencies: &mut Option<TrustedDependenciesSet>,
log: &mut bun_ast::Log,
source: &bun_ast::Source,
json: Expr,
bump: &bun_alloc::Arena,
) -> crate::Result<()> {
let Some(q) = json.as_property(b"trustedDependencies") else {
return Ok(());
};
let count = match &q.expr.data {
ExprData::EArray(arr) => arr.items.len_u32() as usize,
ExprData::EArrayJSON(arr) => arr.get().items().len(),
_ => return Err(invalid_trusted_dependencies(log, source, q.loc)),
};
let trusted = trusted_dependencies.get_or_insert_with(Default::default);
trusted.ensure_unused_capacity(count)?;
if let Some(mut items) = q.expr.as_array() {
while let Some(item) = items.next() {
let Some(name) = item.as_string(bump) else {
return Err(invalid_trusted_dependencies(log, source, q.loc));
};
trusted.put_assume_capacity(
semver::string::Builder::string_hash(name) as TruncatedPackageNameHash,
Box::<[u8]>::from(name),
);
}
}
Ok(())
}

// `SemverIntType` defaults to `u64`, the only instantiation the lockfile/PM
// call sites name unqualified.
//
Expand Down Expand Up @@ -2466,29 +2498,13 @@ impl Package<u64> {
}

if FEATURES.trusted_dependencies {
if let Some(q) = json.as_property(b"trustedDependencies") {
let count = match &q.expr.data {
ExprData::EArray(arr) => arr.items.len_u32() as usize,
ExprData::EArrayJSON(arr) => arr.get().items().len(),
_ => return Err(invalid_trusted_dependencies(log, source, q.loc)),
};
if lockfile.trusted_dependencies.is_none() {
lockfile.trusted_dependencies = Some(Default::default());
}
let trusted = lockfile.trusted_dependencies.as_mut().unwrap();
trusted.ensure_unused_capacity(count)?;
if let Some(mut items) = q.expr.as_array() {
while let Some(item) = items.next() {
let Some(name) = item.as_string(&bump) else {
return Err(invalid_trusted_dependencies(log, source, q.loc));
};
trusted.put_assume_capacity(
semver::string::Builder::string_hash(name) as TruncatedPackageNameHash,
Box::<[u8]>::from(name),
);
}
}
}
parse_append_trusted_dependencies(
&mut lockfile.trusted_dependencies,
log,
source,
json,
&bump,
)?;
}

if FEATURES.is_main {
Expand Down
106 changes: 86 additions & 20 deletions src/install/migration.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::Error;
use bun_ast::{E, ExprData};
use bun_core::strings;
use bun_core::{Output, zstr};
use bun_paths::PathBuffer;
use bun_core::{Output, ZStr, zstr};
use bun_paths::{AutoAbsPath, PathBuffer};
use bun_semver::query::token::Wildcard;
use bun_semver::{self as Semver, SlicedString};
use bun_sys::{self, Fd, File, O};
Expand All @@ -11,8 +11,8 @@ use crate::install::{self as Install, PackageManager, Subcommand};
use crate::lockfile::{
Format as LockfileFormat, LoadResult, LoadResultErr, LoadResultOk, LoadStep, Lockfile, Migrated,
};
use crate::lockfile_real::package::PackageColumns as _;
use crate::lockfile_real::package::workspace_map::{MissingWorkspace, NamesArray, WorkspaceMap};
use crate::lockfile_real::package::{PackageColumns as _, parse_append_trusted_dependencies};
use crate::npm::{self as Npm};
use crate::pnpm;
use crate::pnpm::MigratePnpmLockfileError;
Expand Down Expand Up @@ -64,11 +64,13 @@ pub fn detect_and_load_other_lockfile<'a>(
}
};

if matches!(migrate_result, LoadResult::Ok { .. }) {
report_migrated(manager, log, &timer, "package-lock.json");
}

return migrate_result;
return finish_migration(
migrate_result,
manager,
log,
&timer,
zstr!("package-lock.json"),
);
}

'yarn: {
Expand All @@ -88,11 +90,7 @@ pub fn detect_and_load_other_lockfile<'a>(
}
};

if matches!(migrate_result, LoadResult::Ok { .. }) {
report_migrated(manager, log, &timer, "yarn.lock");
}

return migrate_result;
return finish_migration(migrate_result, manager, log, &timer, zstr!("yarn.lock"));
}

'pnpm: {
Expand Down Expand Up @@ -155,16 +153,81 @@ pub fn detect_and_load_other_lockfile<'a>(
}
};

if matches!(migrate_result, LoadResult::Ok { .. }) {
report_migrated(manager, log, &timer, "pnpm-lock.yaml");
}

return migrate_result;
return finish_migration(
migrate_result,
manager,
log,
&timer,
zstr!("pnpm-lock.yaml"),
);
}

LoadResult::NotFound
}

fn finish_migration<'a>(
migrate_result: LoadResult<'a>,
manager: &mut PackageManager,
log: &mut bun_ast::Log,
timer: &std::time::Instant,
lockfile_name: &'static ZStr,
) -> LoadResult<'a> {
let ok = match migrate_result {
LoadResult::Ok(ok) => ok,
other => return other,
};
if let Err(err) = record_trusted_dependencies(&mut *ok.lockfile, manager, log) {
if !manager.options.log_level.is_silent() && log.has_errors() {
let _ = log.print(std::ptr::from_mut(Output::error_writer()));
Output::flush();
}
log.reset();
return LoadResult::Err(LoadResultErr {
step: LoadStep::Migrating,
value: err,
lockfile_path: lockfile_name,
format: LockfileFormat::Text,
});
}
report_migrated(manager, log, timer, lockfile_name);
LoadResult::Ok(ok)
}

/// Other lockfiles have no `trustedDependencies`; read the root's and the members' from package.json like `Package::parse_with_json` does, since `bun pm migrate` saves this lockfile as-is.
fn record_trusted_dependencies(
lockfile: &mut Lockfile,
manager: &mut PackageManager,
log: &mut bun_ast::Log,
) -> Result<(), Error> {
let bump = bun_alloc::Arena::new();
let string_bytes = lockfile.buffers.string_bytes.as_slice();
let root: &[u8] = b"";
let members = lockfile
.workspace_paths
.values()
.iter()
.map(|path| path.slice(string_bytes));
Comment thread
robobun marked this conversation as resolved.
for relative_dir in core::iter::once(root).chain(members) {
let mut package_json_path = AutoAbsPath::init_top_level_dir();
let _ = package_json_path.append(relative_dir);
let _ = package_json_path.append(b"package.json");
let crate::GetJsonResult::Entry(entry) = manager
.workspace_package_json_cache
.get_with_path(log, package_json_path.slice(), Default::default())
else {
continue;
};
parse_append_trusted_dependencies(
&mut lockfile.trusted_dependencies,
log,
&entry.source,
entry.root,
&bump,
)?;
}
Ok(())
}

/// True when the migrator already printed the version warn/error + upgrade note, so lockfile-load reporters must stay quiet.
pub fn reported_unsupported_lockfile_version(err: &LoadResultErr) -> bool {
err.step == LoadStep::Migrating && matches!(err.value, Error::UnexpectedLockfileVersion)
Expand Down Expand Up @@ -229,7 +292,7 @@ fn report_migrated(
manager: &PackageManager,
log: &mut bun_ast::Log,
timer: &std::time::Instant,
lockfile_name: &str,
lockfile_name: &ZStr,
) {
if manager.options.log_level.is_silent() {
log.reset();
Expand All @@ -240,7 +303,10 @@ fn report_migrated(
log.reset();
}
Output::print_elapsed(timer.elapsed().as_nanos() as f64 / 1_000_000.0);
bun_core::pretty_errorln!(" <d>migrated lockfile from <r><green>{}<r>", lockfile_name);
bun_core::pretty_errorln!(
" <d>migrated lockfile from <r><green>{}<r>",
bstr::BStr::new(lockfile_name.as_bytes())
);
Output::flush();
}

Expand Down
Loading
Loading