Skip to content
Open
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
86 changes: 86 additions & 0 deletions .agent/workflows/setup_local_env.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
---
description: Setup local development environment for Deno
---

# Setup Local Deno Development Environment

This guide helps you set up your system to build and contribute to Deno.

## Option 1: VS Code Dev Containers (Recommended)

If you use VS Code, the easiest way is to use the provided Dev Container
configuration.

1. Install [Docker Desktop](https://www.docker.com/products/docker-desktop).
2. Install the
[Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers)
in VS Code.
3. Open the project folder in VS Code.
4. Click "Reopen in Container" when prompted, or run the command
`Dev Containers: Reopen in Container`.

This will automatically set up all dependencies (Rust, Python, CMake, Protobuf,
etc.).

## Option 2: Manual Setup

### 1. Install Prerequisites

#### Rust

Deno requires a specific version of Rust.

```bash
# Install rustup if you haven't
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Install the specific version required by Deno (currently 1.90.0)
rustup install 1.90.0
rustup default 1.90.0
rustup component add rustfmt clippy
```
Comment on lines +33 to +41
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check for rust-toolchain configuration files and version specifications

echo "=== Looking for rust-toolchain files ==="
fd -t f "rust-toolchain" .

echo -e "\n=== Checking for Rust version in TOML files ==="
rg -n "^\[" Cargo.toml 2>/dev/null | head -20

echo -e "\n=== Searching for version specifications (1.90.0 or rust version references) ==="
rg -n "1\.90\.0|rust.*version|toolchain" --type toml --type json --type yaml -C 2

echo -e "\n=== Checking GitHub Actions workflows for Rust version ==="
fd -t f "\.yml$|\.yaml$" .github/workflows 2>/dev/null -exec basename {} \; 2>/dev/null | head -5

Repository: denoland/deno

Length of output: 170


🌐 Web query:

Deno rust version requirement 1.90.0

💡 Result:

Do you mean: (A) confirm which Rust version Deno requires to build (e.g. "Rust 1.90.0"), or (B) how to install/use Rust 1.90.0 for building Deno?


🌐 Web query:

Deno build requirements minimum Rust version

💡 Result:

Short answer: Deno requires the Rust toolchain version specified in the repository's rust-toolchain.toml file — check that file in the denoland/deno repo for the exact minimum Rust version for the release you plan to build. [1][2]

How to check locally or in the repo:

  • View the file on GitHub: https://github.com/denoland/deno and open rust-toolchain.toml. [1]
  • Or from a shell after cloning: cat rust-toolchain.toml (the file explicitly pins the Rust toolchain to use). [2]

Sources:

  • denoland/deno repository (README and repo files). [1]
  • deno CONTRIBUTING / building-from-source instructions (notes that Deno requires the Rust release listed in rust-toolchain.toml). [2]

If you want, I can fetch the current rust-toolchain.toml and tell you the exact Rust version right now.


🌐 Web query:

site:github.com/denoland/deno rust-toolchain.toml

💡 Result:

The file rust-toolchain.toml is present at the root of the denoland/deno repository on GitHub. [1][2]

Sources

  • denoland/deno repository file list (shows rust-toolchain.toml). [1]
  • rust-toolchain.toml blob page in the denoland/deno repo. [2]

🌐 Web query:

fetch denoland deno rust-toolchain.toml raw content current version

💡 Result:

Here’s the rust-toolchain.toml content from the denoland/deno repo (current toolchain channel in the file):

[toolchain]
channel = "1.89.0"
components = ["rustfmt", "clippy"].

Sources: [1], [2]

Sources:
[1] mirror of denoland/deno rust-toolchain.toml (shows content).
[2] denoland/deno repository file listing on GitHub.


Rust version in documentation is incorrect — should be 1.89.0, not 1.90.0.

The documentation specifies Rust 1.90.0 (lines 37–38), but the project's rust-toolchain.toml file specifies channel = "1.89.0". Using the wrong version will cause build failures or unnecessary upgrades. Update the documentation to match the actual requirement:

# Install the specific version required by Deno (currently 1.89.0)
rustup install 1.89.0
rustup default 1.89.0
rustup component add rustfmt clippy
🤖 Prompt for AI Agents
.agent/workflows/setup_local_env.md around lines 33 to 41: the docs install Rust
1.90.0 but the project requires 1.89.0 per rust-toolchain.toml; update the three
rustup commands to use 1.89.0 (install, default) and keep adding rustfmt and
clippy so the documented commands match the project's required Rust channel.


#### Python 3

Ensure you have Python 3 installed and accessible as `python` or `python3`.

#### Protobuf Compiler

- **Mac:** `brew install protobuf`
- **Linux:** `apt install -y protobuf-compiler`
- **Windows:** Download binary release from GitHub.

#### CMake

- **Mac:** `brew install cmake`
- **Linux:** `apt install -y cmake`

#### Native Compilers

- **Mac:** XCode Command Line Tools (`xcode-select --install`)
- **Linux:** `apt install -y build-essential libglib2.0-dev`

### 2. Build Deno

```bash
# Clone with submodules if you haven't already
git submodule update --init --recursive

# Build
cargo build -vv
```

### 3. Verify Setup

Run the tests to ensure everything is working:

```bash
# Run unit tests
cargo test -vv

# Format code
./tools/format.js

# Lint code
./tools/lint.js
```
Comment on lines +1 to +86
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

This documentation appears unrelated to the PR objective.

The PR adds a --allow-env-file flag for environment variable permissions, but this file documents general Deno development environment setup with no mention of the new flag. Was this file accidentally included, or is there a broader context not reflected in the PR description?

34 changes: 34 additions & 0 deletions cli/args/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -786,6 +786,7 @@ pub struct Flags {
pub ignore: Vec<String>,
pub import_map_path: Option<String>,
pub env_file: Option<Vec<String>>,
pub allow_env_file: Option<Vec<String>>,
pub inspect_brk: Option<SocketAddr>,
pub inspect_wait: Option<SocketAddr>,
pub inspect: Option<SocketAddr>,
Expand Down Expand Up @@ -2216,6 +2217,7 @@ If you specify a directory instead of a file, the path is expanded to all contai
.arg(no_clear_screen_arg())
.arg(script_arg().last(true))
.arg(env_file_arg())
.arg(allow_env_file_arg())
.arg(executable_ext_arg())
})
}
Expand Down Expand Up @@ -2391,6 +2393,7 @@ Future runs of this module will trigger no downloads or compilation unless --rel
.arg(allow_import_arg())
.arg(deny_import_arg())
.arg(env_file_arg())
.arg(allow_env_file_arg())
})
}

Expand Down Expand Up @@ -2570,6 +2573,7 @@ On the first invocation of `deno compile`, Deno will download the relevant binar
)
.arg(executable_ext_arg())
.arg(env_file_arg())
.arg(allow_env_file_arg())
.arg(
script_arg()
.num_args(0..=1)
Expand Down Expand Up @@ -2883,6 +2887,7 @@ This command has implicit access to all permissions.
.required_unless_present("help"),
)
.arg(env_file_arg())
.arg(allow_env_file_arg())
})
}

Expand Down Expand Up @@ -3233,6 +3238,7 @@ These must be added to the path manually if required."), UnstableArgsConfig::Res
.help("Install dependents of the specified entrypoint(s)"),
)
.arg(env_file_arg())
.arg(allow_env_file_arg())
.arg(add_dev_arg().conflicts_with("entrypoint").conflicts_with("global"))
.args(default_registry_args().into_iter().map(|arg| arg.conflicts_with("entrypoint").conflicts_with("global")))
})
Expand Down Expand Up @@ -3628,6 +3634,7 @@ TypeScript is supported, however it is not type-checked, only transpiled."
<p(245)>[default: $DENO_DIR/deno_history.txt]</>"))
})
.arg(env_file_arg())
.arg(allow_env_file_arg())
.arg(
Arg::new("args")
.num_args(0..)
Expand All @@ -3651,6 +3658,7 @@ fn run_args(command: Command, top_level: bool) -> Command {
script_arg().trailing_var_arg(true)
})
.arg(env_file_arg())
.arg(allow_env_file_arg())
.arg(no_code_cache_arg())
.arg(coverage_arg())
.arg(tunnel_arg())
Expand Down Expand Up @@ -3729,6 +3737,7 @@ Start a server defined in server.ts, watching for changes and running on port 50
.trailing_var_arg(true),
)
.arg(env_file_arg())
.arg(allow_env_file_arg())
.arg(no_code_cache_arg())
.arg(tunnel_arg())
}
Expand Down Expand Up @@ -3992,6 +4001,7 @@ or <c>**/__tests__/**</>:
.action(ArgAction::SetTrue)
)
.arg(env_file_arg())
.arg(allow_env_file_arg())
.arg(executable_ext_arg())
)
}
Expand Down Expand Up @@ -4755,6 +4765,21 @@ fn env_file_arg() -> Arg {
.action(ArgAction::Append)
}

fn allow_env_file_arg() -> Arg {
Arg::new("allow-env-file")
.long("allow-env-file")
.value_name("FILE")
.help(cstr!(
"Specify an environment file to load and allow reading its variables
<p(245)>This flag behaves like --env-file, but also grants read permissions to the variables defined in the file.</>"
))
.value_hint(ValueHint::FilePath)
.default_missing_value(".env")
.require_equals(true)
.num_args(0..=1)
.action(ArgAction::Append)
}

fn reload_arg() -> Arg {
Arg::new("reload")
.short('r')
Expand Down Expand Up @@ -5502,6 +5527,7 @@ fn cache_parse(
allow_scripts_arg_parse(flags, matches)?;
allow_and_deny_import_parse(flags, matches)?;
env_file_arg_parse(flags, matches);
allow_env_file_arg_parse(flags, matches);
let files = matches.remove_many::<String>("file").unwrap().collect();
flags.subcommand = DenoSubcommand::Cache(CacheFlags { files });
Ok(())
Expand Down Expand Up @@ -6181,6 +6207,7 @@ fn repl_parse(
seed_arg_parse(flags, matches);
enable_testing_features_arg_parse(flags, matches);
env_file_arg_parse(flags, matches);
allow_env_file_arg_parse(flags, matches);
trace_ops_parse(flags, matches);

let eval_files = matches
Expand Down Expand Up @@ -6875,6 +6902,7 @@ fn runtime_args_parse(
seed_arg_parse(flags, matches);
enable_testing_features_arg_parse(flags, matches);
env_file_arg_parse(flags, matches);
allow_env_file_arg_parse(flags, matches);
trace_ops_parse(flags, matches);
eszip_arg_parse(flags, matches);
Ok(())
Expand Down Expand Up @@ -6902,6 +6930,12 @@ fn env_file_arg_parse(flags: &mut Flags, matches: &mut ArgMatches) {
.map(|values| values.cloned().collect());
}

fn allow_env_file_arg_parse(flags: &mut Flags, matches: &mut ArgMatches) {
flags.allow_env_file = matches
.get_many::<String>("allow-env-file")
.map(|values| values.cloned().collect());
}

fn reload_arg_parse(
flags: &mut Flags,
matches: &mut ArgMatches,
Expand Down
25 changes: 25 additions & 0 deletions cli/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ use crate::util::display;
use crate::util::v8::get_v8_flags_from_env;
use crate::util::v8::init_v8_flags;
use crate::util::watch_env_tracker::WatchEnvTracker;
use crate::util::watch_env_tracker::get_env_vars_from_env_file;
use crate::util::watch_env_tracker::load_env_variables_from_env_files;

#[cfg(feature = "dhat-heap")]
Expand Down Expand Up @@ -715,6 +716,30 @@ async fn resolve_flags_and_init(
.map(|files| files.iter().map(PathBuf::from).collect());
load_env_variables_from_env_files(env_file_paths.as_ref(), flags.log_level);

let allow_env_file_paths: Option<Vec<std::path::PathBuf>> = flags
.allow_env_file
.as_ref()
.map(|files| files.iter().map(PathBuf::from).collect());

if let Some(paths) = &allow_env_file_paths {
let mut allowed_vars = std::collections::HashSet::new();
for path in paths {
if let Some(vars) = get_env_vars_from_env_file(path, flags.log_level) {
for (key, _) in vars {
allowed_vars.insert(key);
}
}
}
if !flags.permissions.allow_all {
if let Some(ref mut env_perms) = flags.permissions.allow_env {
env_perms.extend(allowed_vars);
} else {
flags.permissions.allow_env = Some(allowed_vars.into_iter().collect());
}
}
load_env_variables_from_env_files(Some(paths), flags.log_level);
}

if deno_lib::args::has_flag_env_var("DENO_CONNECTED") {
flags.tunnel = true;
}
Expand Down
34 changes: 34 additions & 0 deletions cli/util/watch_env_tracker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,3 +256,37 @@ pub fn load_env_variables_from_env_files(
}
}
}

pub fn get_env_vars_from_env_file(
file_path: &Path,
log_level: Option<log::Level>,
) -> Option<HashMap<String, String>> {
match dotenvy::from_path_iter(file_path) {
Ok(iter) => {
let mut vars = HashMap::new();
for item in iter {
match item {
Ok((key, value)) => {
vars.insert(key, value);
}
Err(e) => {
WatchEnvTracker::handle_dotenvy_error(e, file_path, log_level);
}
}
}
Some(vars)
}
Err(e) => {
#[allow(clippy::print_stderr)]
if log_level.map(|l| l >= log::Level::Info).unwrap_or(true) {
eprintln!(
"{} Failed to read {}: {}",
colors::yellow("Warning"),
file_path.display(),
e
);
}
None
}
}
}
Loading