Skip to content

Commit 58f7435

Browse files
authored
feat(cli): print working dir in grey in stack traces, relative paths in check + compile output (#31194)
Before: <img width="928" height="135" alt="Screenshot 2025-11-05 at 11 43 03 AM" src="https://github.com/user-attachments/assets/f956a65c-d509-46ff-b8e4-58827dea3ca0" /> After: <img width="927" height="130" alt="Screenshot 2025-11-05 at 11 44 39 AM" src="https://github.com/user-attachments/assets/fb6aed36-8ca7-4744-81f1-425f7fbac5e5" />
1 parent cf4379d commit 58f7435

File tree

298 files changed

+618
-499
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

298 files changed

+618
-499
lines changed

Cargo.lock

Lines changed: 7 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ repository = "https://github.com/denoland/deno"
6161

6262
[workspace.dependencies]
6363
deno_ast = { version = "=0.50.3", features = ["transpiling"] }
64-
deno_core = { version = "0.365.0" }
64+
deno_core = { version = "0.367.0" }
6565

6666
deno_cache_dir = "=0.25.0"
6767
deno_doc = "=0.186.0"

cli/args/flags.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -760,6 +760,7 @@ pub struct InternalFlags {
760760

761761
#[derive(Clone, Debug, Eq, PartialEq, Default)]
762762
pub struct Flags {
763+
pub initial_cwd: Option<PathBuf>,
763764
/// Vector of CLI arguments - these are user script arguments, all Deno
764765
/// specific flags are removed.
765766
pub argv: Vec<String>,
@@ -1523,8 +1524,15 @@ static DENO_HELP: &str = cstr!(
15231524
<y>Discord:</> https://discord.gg/deno
15241525
");
15251526

1526-
/// Main entry point for parsing deno's command line flags.
15271527
pub fn flags_from_vec(args: Vec<OsString>) -> clap::error::Result<Flags> {
1528+
flags_from_vec_with_initial_cwd(args, None)
1529+
}
1530+
1531+
/// Main entry point for parsing deno's command line flags.
1532+
pub fn flags_from_vec_with_initial_cwd(
1533+
args: Vec<OsString>,
1534+
initial_cwd: Option<PathBuf>,
1535+
) -> clap::error::Result<Flags> {
15281536
let mut app = clap_root();
15291537
let mut matches =
15301538
app
@@ -1551,7 +1559,10 @@ pub fn flags_from_vec(args: Vec<OsString>) -> clap::error::Result<Flags> {
15511559
_ => e,
15521560
})?;
15531561

1554-
let mut flags = Flags::default();
1562+
let mut flags = Flags {
1563+
initial_cwd,
1564+
..Default::default()
1565+
};
15551566

15561567
// to pass all flags, even help and
15571568
if matches.subcommand_matches("deploy").is_some() {
@@ -1615,6 +1626,7 @@ pub fn flags_from_vec(args: Vec<OsString>) -> clap::error::Result<Flags> {
16151626
}
16161627

16171628
help_parse(&mut flags, subcommand);
1629+
16181630
return Ok(flags);
16191631
}
16201632

cli/factory.rs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -651,10 +651,16 @@ impl CliFactory {
651651
self.services.workspace_factory.get_or_try_init(|| {
652652
let initial_cwd = match self.overrides.initial_cwd.clone() {
653653
Some(v) => v,
654-
None => self
655-
.sys()
656-
.env_current_dir()
657-
.with_context(|| "Failed getting cwd.")?,
654+
None => {
655+
if let Some(initial_cwd) = self.flags.initial_cwd.clone() {
656+
initial_cwd
657+
} else {
658+
self
659+
.sys()
660+
.env_current_dir()
661+
.with_context(|| "Failed getting cwd.")?
662+
}
663+
}
658664
};
659665
let options = new_workspace_factory_options(&initial_cwd, &self.flags);
660666
let mut factory =
@@ -1135,6 +1141,9 @@ impl CliFactory {
11351141
no_legacy_abort: cli_options.no_legacy_abort(),
11361142
startup_snapshot: deno_snapshots::CLI_SNAPSHOT,
11371143
enable_raw_imports: cli_options.unstable_raw_imports(),
1144+
maybe_initial_cwd: Some(deno_path_util::url_from_directory_path(
1145+
cli_options.initial_cwd(),
1146+
)?),
11381147
})
11391148
}
11401149

@@ -1154,11 +1163,15 @@ impl CliFactory {
11541163
};
11551164
let maybe_coverage_dir = cli_options.coverage_dir();
11561165

1166+
let initial_cwd =
1167+
deno_path_util::url_from_directory_path(cli_options.initial_cwd())?;
1168+
11571169
Ok(CliMainWorkerOptions {
11581170
needs_test_modules: cli_options.sub_command().needs_test(),
11591171
create_hmr_runner,
11601172
maybe_coverage_dir,
11611173
default_npm_caching_strategy: cli_options.default_npm_caching_strategy(),
1174+
maybe_initial_cwd: Some(Arc::new(initial_cwd)),
11621175
})
11631176
}
11641177

cli/lib/worker.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,7 @@ pub struct LibMainWorkerOptions {
350350
pub startup_snapshot: Option<&'static [u8]>,
351351
pub serve_port: Option<u16>,
352352
pub serve_host: Option<String>,
353+
pub maybe_initial_cwd: Option<Url>,
353354
}
354355

355356
#[derive(Default, Clone)]
@@ -462,6 +463,7 @@ impl<TSys: DenoLibSys> LibWorkerFactorySharedState<TSys> {
462463
),
463464
permissions: args.permissions,
464465
};
466+
let maybe_initial_cwd = shared.options.maybe_initial_cwd.clone();
465467
let options = WebWorkerOptions {
466468
name: args.name,
467469
main_module: args.main_module.clone(),
@@ -503,7 +505,9 @@ impl<TSys: DenoLibSys> LibWorkerFactorySharedState<TSys> {
503505
.clone(),
504506
seed: shared.options.seed,
505507
create_web_worker_cb,
506-
format_js_error_fn: Some(Arc::new(format_js_error)),
508+
format_js_error_fn: Some(Arc::new(move |a| {
509+
format_js_error(a, maybe_initial_cwd.as_ref())
510+
})),
507511
worker_type: args.worker_type,
508512
stdio: stdio.clone(),
509513
cache_storage_dir,
@@ -657,6 +661,8 @@ impl<TSys: DenoLibSys> LibMainWorkerFactory<TSys> {
657661
bundle_provider: shared.bundle_provider.clone(),
658662
};
659663

664+
let maybe_initial_cwd = shared.options.maybe_initial_cwd.clone();
665+
660666
let options = WorkerOptions {
661667
bootstrap: BootstrapOptions {
662668
deno_version: crate::version::DENO_VERSION_INFO.deno.to_string(),
@@ -694,7 +700,9 @@ impl<TSys: DenoLibSys> LibMainWorkerFactory<TSys> {
694700
.unsafely_ignore_certificate_errors
695701
.clone(),
696702
seed: shared.options.seed,
697-
format_js_error_fn: Some(Arc::new(format_js_error)),
703+
format_js_error_fn: Some(Arc::new(move |e| {
704+
format_js_error(e, maybe_initial_cwd.as_ref())
705+
})),
698706
create_web_worker_cb: shared.create_web_worker_callback(stdio.clone()),
699707
maybe_inspector_server: shared.maybe_inspector_server.clone(),
700708
should_break_on_first_statement: shared.options.inspect_brk,

cli/main.rs

Lines changed: 53 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ use self::util::draw_thread::DrawThread;
6363
use crate::args::CompletionsFlags;
6464
use crate::args::DenoSubcommand;
6565
use crate::args::Flags;
66-
use crate::args::flags_from_vec;
66+
use crate::args::flags_from_vec_with_initial_cwd;
6767
use crate::args::get_default_v8_flags;
6868
use crate::util::display;
6969
use crate::util::v8::get_v8_flags_from_env;
@@ -558,9 +558,13 @@ fn exit_with_message(message: &str, code: i32) -> ! {
558558
deno_runtime::exit(code);
559559
}
560560

561-
fn exit_for_error(error: AnyError) -> ! {
561+
fn exit_for_error(error: AnyError, initial_cwd: Option<&std::path::Path>) -> ! {
562562
let error_string = match js_error_downcast_ref(&error) {
563-
Some(e) => format_js_error(e),
563+
Some(e) => {
564+
let initial_cwd = initial_cwd
565+
.and_then(|cwd| deno_path_util::url_from_directory_path(cwd).ok());
566+
format_js_error(e, initial_cwd.as_ref())
567+
}
564568
None => format!("{error:?}"),
565569
};
566570

@@ -619,50 +623,68 @@ pub fn main() {
619623
let roots = LibWorkerFactoryRoots::default();
620624

621625
#[cfg(unix)]
622-
let (waited_unconfigured_runtime, waited_args) =
626+
let (waited_unconfigured_runtime, waited_args, waited_cwd) =
623627
match wait_for_start(&args, roots.clone()) {
624628
Some(f) => match f.await {
625629
Ok(v) => match v {
626-
Some((u, a)) => (Some(u), Some(a)),
627-
None => (None, None),
630+
Some((u, a, c)) => (Some(u), Some(a), Some(c)),
631+
None => (None, None, None),
628632
},
629633
Err(e) => {
630634
panic!("Failure from control sock: {e}");
631635
}
632636
},
633-
None => (None, None),
637+
None => (None, None, None),
634638
};
635639

636640
#[cfg(not(unix))]
637-
let (waited_unconfigured_runtime, waited_args) = (None, None);
641+
let (waited_unconfigured_runtime, waited_args, waited_cwd) =
642+
(None, None, None);
638643

639644
let args = waited_args.unwrap_or(args);
645+
let initial_cwd = waited_cwd.map(Some).unwrap_or_else(|| {
646+
match std::env::current_dir().with_context(|| "Failed getting cwd.") {
647+
Ok(cwd) => Some(cwd),
648+
Err(err) => {
649+
log::error!("Failed getting cwd: {err}");
650+
None
651+
}
652+
}
653+
});
640654

641655
// NOTE(lucacasonato): due to new PKU feature introduced in V8 11.6 we need to
642656
// initialize the V8 platform on a parent thread of all threads that will spawn
643657
// V8 isolates.
644-
let flags = resolve_flags_and_init(args).await?;
658+
let flags = match resolve_flags_and_init(args, initial_cwd.clone()).await {
659+
Ok(flags) => flags,
660+
Err(err) => return (Err(err), initial_cwd),
661+
};
645662

646663
if waited_unconfigured_runtime.is_none() {
647664
init_v8(&flags);
648665
}
649666

650-
run_subcommand(Arc::new(flags), waited_unconfigured_runtime, roots).await
667+
(
668+
run_subcommand(Arc::new(flags), waited_unconfigured_runtime, roots).await,
669+
initial_cwd,
670+
)
651671
};
652672

653-
let result = create_and_run_current_thread_with_maybe_metrics(future);
673+
let (result, initial_cwd) =
674+
create_and_run_current_thread_with_maybe_metrics(future);
654675

655676
#[cfg(feature = "dhat-heap")]
656677
drop(profiler);
657678

658679
match result {
659680
Ok(exit_code) => deno_runtime::exit(exit_code),
660-
Err(err) => exit_for_error(err),
681+
Err(err) => exit_for_error(err, initial_cwd.as_deref()),
661682
}
662683
}
663684

664685
async fn resolve_flags_and_init(
665686
args: Vec<std::ffi::OsString>,
687+
initial_cwd: Option<std::path::PathBuf>,
666688
) -> Result<Flags, AnyError> {
667689
// this env var is used by clap to enable dynamic completions, it's set by the shell when
668690
// executing deno to get dynamic completions.
@@ -671,17 +693,18 @@ async fn resolve_flags_and_init(
671693
deno_runtime::exit(0);
672694
}
673695

674-
let mut flags = match flags_from_vec(args) {
675-
Ok(flags) => flags,
676-
Err(err @ clap::Error { .. })
677-
if err.kind() == clap::error::ErrorKind::DisplayVersion =>
678-
{
679-
// Ignore results to avoid BrokenPipe errors.
680-
let _ = err.print();
681-
deno_runtime::exit(0);
682-
}
683-
Err(err) => exit_for_error(AnyError::from(err)),
684-
};
696+
let mut flags =
697+
match flags_from_vec_with_initial_cwd(args, initial_cwd.clone()) {
698+
Ok(flags) => flags,
699+
Err(err @ clap::Error { .. })
700+
if err.kind() == clap::error::ErrorKind::DisplayVersion =>
701+
{
702+
// Ignore results to avoid BrokenPipe errors.
703+
let _ = err.print();
704+
deno_runtime::exit(0);
705+
}
706+
Err(err) => exit_for_error(AnyError::from(err), initial_cwd.as_deref()),
707+
};
685708
// preserve already loaded env variables
686709
if flags.subcommand.watch_flags().is_some() {
687710
WatchEnvTracker::snapshot();
@@ -706,7 +729,10 @@ async fn resolve_flags_and_init(
706729
// Tunnel sets up env vars and OTEL, so connect before everything else.
707730
if flags.tunnel {
708731
if let Err(err) = initialize_tunnel(&flags).await {
709-
exit_for_error(err.context("Failed to start with tunnel"));
732+
exit_for_error(
733+
err.context("Failed to start with tunnel"),
734+
initial_cwd.as_deref(),
735+
);
710736
}
711737
// SAFETY: We're doing this before any threads are created.
712738
unsafe {
@@ -816,7 +842,7 @@ fn wait_for_start(
816842
) -> Option<
817843
impl Future<
818844
Output = Result<
819-
Option<(UnconfiguredRuntime, Vec<std::ffi::OsString>)>,
845+
Option<(UnconfiguredRuntime, Vec<std::ffi::OsString>, PathBuf)>,
820846
AnyError,
821847
>,
822848
> + use<>,
@@ -935,7 +961,7 @@ fn wait_for_start(
935961

936962
let cmd: Start = deno_core::serde_json::from_slice(&buf)?;
937963

938-
std::env::set_current_dir(cmd.cwd)?;
964+
std::env::set_current_dir(&cmd.cwd)?;
939965

940966
for (k, v) in cmd.env {
941967
// SAFETY: We're doing this before any threads are created.
@@ -947,7 +973,7 @@ fn wait_for_start(
947973
.chain(cmd.args.into_iter().map(Into::into))
948974
.collect();
949975

950-
Ok(Some((unconfigured, args)))
976+
Ok(Some((unconfigured, args, PathBuf::from(cmd.cwd))))
951977
})
952978
}
953979

cli/rt/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ fn unwrap_or_exit<T>(result: Result<T, AnyError>) -> T {
4444
Ok(value) => value,
4545
Err(error) => {
4646
let error_string = match js_error_downcast_ref(&error) {
47-
Some(js_error) => format_js_error(js_error),
47+
Some(js_error) => format_js_error(js_error, None),
4848
None => format!("{:?}", error),
4949
};
5050

cli/rt/run.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1030,6 +1030,7 @@ pub async fn run(
10301030
no_legacy_abort: false,
10311031
startup_snapshot: deno_snapshots::CLI_SNAPSHOT,
10321032
enable_raw_imports: metadata.unstable_config.raw_imports,
1033+
maybe_initial_cwd: None,
10331034
};
10341035
let worker_factory = LibMainWorkerFactory::new(
10351036
Arc::new(BlobStore::default()),

0 commit comments

Comments
 (0)