Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Oct 15, 2025

Problem

Zephyr IDE was unconditionally overriding environment variables like ZEPHYR_BASE and ZEPHYR_SDK_INSTALL_DIR, breaking containerized workflows and pre-configured development environments. This caused issues for users working with:

  • Docker containers with pre-installed Zephyr SDK
  • VS Code DevContainers
  • CI/CD pipelines with custom toolchain locations
  • Team-standardized development environments
  • Multiple Zephyr-related extensions (as shown in the screenshot below, where nRF Connect Terminal conflicts with Zephyr IDE)

Environment variable conflict

The extension was also setting ZEPHYR_SDK_INSTALL_DIR unconditionally, even when no setup state existed, preventing users from maintaining their own environment configuration.

Solution

This PR implements three complementary approaches to respect externally managed environments:

1. Configuration Setting

Users can now opt-in to using system environment variables by adding to .vscode/settings.json:

{
  "zephyr-ide.use-system-environment": true
}

When enabled, Zephyr IDE will not override any environment variables (ZEPHYR_BASE, ZEPHYR_SDK_INSTALL_DIR, VIRTUAL_ENV, PATH).

2. Externally Managed Workspace

A new "Externally Managed" workspace type appears in the West Workspaces panel, allowing users to explicitly select externally managed mode via:

  • UI: Click the target icon next to "Externally Managed" in West Workspaces panel
  • Command Palette: "Zephyr IDE: Use Externally Managed West Workspace"

3. Fixed Environment Variable Management

Following maintainer guidance, ZEPHYR_SDK_INSTALL_DIR is now only set when a setup state exists, preventing unconditional overrides.

Changes

Core Logic (src/utilities/utils.ts)

  • Modified reloadEnvironmentVariables() to check use-system-environment setting
  • Moved ZEPHYR_SDK_INSTALL_DIR update inside if (setupState) check
  • Early return when system environment is preferred

Setup State (src/setup_utilities/types.ts)

  • Added externallyManaged?: boolean flag to SetupState interface
  • Created generateExternallyManagedSetupState() function
  • Reads ZEPHYR_BASE from system environment when in external mode

UI Integration (src/panels/west_workspace_view/WestWorkspaceView.ts)

  • Added "Externally Managed" option in West Workspaces panel
  • Shows with database icon (🗄️)
  • Handles activation/deactivation like other workspaces

Command (src/extension.ts, package.json)

  • Registered use-externally-managed-west-workspace command
  • Added configuration property use-system-environment

Testing and Documentation

  • Created comprehensive unit tests (src/test/externally-managed.test.ts)
  • Added detailed documentation with examples (docs/externally-managed-environment.md)

Use Cases

DevContainer Example

// .devcontainer/devcontainer.json
{
  "image": "zephyrprojectrtos/ci:latest",
  "customizations": {
    "vscode": {
      "settings": {
        "zephyr-ide.use-system-environment": true
      }
    }
  }
}

Docker Environment Example

FROM zephyrprojectrtos/ci:v0.26.6
ENV ZEPHYR_BASE=/workspaces/zephyrproject/zephyr
ENV ZEPHYR_SDK_INSTALL_DIR=/opt/toolchains/zephyr-sdk-0.16.8

Then enable use-system-environment setting or select "Externally Managed" workspace.

CI/CD Example

env:
  ZEPHYR_BASE: ${{ github.workspace }}/zephyr
  ZEPHYR_SDK_INSTALL_DIR: /opt/zephyr-sdk

With use-system-environment: true in settings, CI pipelines and local development both respect the environment.

Backward Compatibility

No breaking changes

  • Default behavior unchanged (use-system-environment defaults to false)
  • Existing workspaces continue to work as before
  • Users must explicitly opt-in to new behavior

Testing

  • ✅ TypeScript compilation passing
  • ✅ ESLint checks passing
  • ✅ esbuild bundling successful
  • ✅ Unit tests created and passing
  • ✅ Code review completed

Documentation

Comprehensive documentation added at docs/externally-managed-environment.md including:

  • Feature overview and configuration instructions
  • Docker, DevContainer, and CI/CD examples
  • Troubleshooting guide
  • Migration guide from managed to externally managed mode

Fixes #86

Original prompt

This section details on the original issue you should resolve

<issue_title>Avoid replacing env-var ZEPHYR_SDK_INSTALL_DIR, etc.</issue_title>
<issue_description>Would it be possible to avoid replacing the ZEPHYR_SDK_INSTALL_DIR, ZEPHYR_BASE, etc., environment variables, if they're already configured for the environment?

I have a VSCode Workspace template that's based around Devcontainers. I do all my work inside a Docker container, which is built based on the needs of the Zephyr project I'm working on ATM, and therefore already has all the necessary tools installed at system or West-venv level. It has exactly the versions needed for SDK and tools, and whatnot.

In other words, in some cases, there's no need for another tool to assume control of those Zephyr-related env-vars. It would be nice to have the option to disable manipulation of env-vars, or at least give the option to force a specific value for some of them in settings.json.

In my case, specifically:

  • My Zephyr app declares dependency to a specific Zephyr version in its west.yml.
  • ZEPHYR_BASE is configured to be the Zephyr cloned by west init. This allows me to open (in VSCode, etc.) and use the exact Zephyr version my application needs;
  • ZEPHYR_SDK_INSTALL_DIR points to a Zephyr SDK installed as part of the Docker image's build process. Its version is fixed in the Dockerfile.

In a way, my environment is prepared to automate as much of the boring stuff as possible. The intention is for any developer to just clone, run a command or two and open the project in VSCode, and nothing more. If preference is given to some Zephyr-related extension, they're free to install and use, as long as the extension is capable of identifying what the environment provides, and uses it as much as possible.

So, this is the motivation, for my case specifically. However, the direct manipulation of ZEPHYR_SDK_INSTALL_DIR and other Zephyr-related environment variables in the Terminal breaks many use-cases, even related to other extensions:

Image

Looking into Zephyr IDE's source code, I see that ZEPHYR_SDK_INSTALL_DIR is set to be replaced, at this part of the extension's code:

context.environmentVariableCollection.replace("ZEPHYR_SDK_INSTALL_DIR", getToolchainDir(), { applyAtProcessCreation: true, applyAtShellIntegration: true });

And getToolchainDir() is somewhat hardcoded, and the folder it points to may not even be in a layout expected for an user of Zephyr SDK (I mean, which references ZEPHYR_SDK_INSTALL_DIR... I think?):

export function getToolsDir() {
let toolsdir = path.join(os.homedir(), toolsfoldername);
const configuration = vscode.workspace.getConfiguration();
let toolsDirFromFile: string | undefined = configuration.get("zephyr-ide.tools_directory");
if (toolsDirFromFile) {
toolsdir = toolsDirFromFile;
}
// Ensure directory exists before returning
try {
if (!fs.pathExistsSync(toolsdir)) {
fs.ensureDirSync(toolsdir);
}
} catch (e) {
console.error("Failed to ensure tools directory exists:", toolsdir, e);
}
return toolsdir;
}
export function getToolchainDir() {
return path.join(getToolsDir(), "toolchains");
}

So, is there a way to make this behavior optional, or at least configurable to some extent? (Not only for ZEPHYR_SDK_INSTALL_DIR, but for ZEPHYR_BASE and any other env-var that Zephyr IDE intends to manage)</issue_description>

Comments on the Issue (you are @copilot in this section)

@rijesha Thanks for the issue. I think this can be implemented fairly easily. I'm a little busy at the moment but hopefully I can get to this by the end of the month.

As an aside I was wanting to add a new panel that listed zephyr installations, this panel could be used to select none and not update the environment variables.

@rijesha The best way to implement this is to do the following actions:

In the reloadEnvironmentVariables function the update to "ZEPHYR_SDK_INSTALL_DIR" should be moved into the check for if (setupState).

Then there are a bunch of checks on wsConfig.activeSetupState in project_utilities and zephyr_utilities. These need to be either removed or a flag should be added to disable the checks if a configuration setting is present in .vscode/settings.json. Another solution that may be better is creating a new dummy setup state called "externally managed" or something similar to keep the logic as is. We would then need a mechanism to select externally managed. This could be a command "use-externally-managed-west-workspace" and also an action button on the west workspace panel.

Fixes #189


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI and others added 3 commits October 15, 2025 17:45
- Add use-system-environment configuration setting
- Move ZEPHYR_SDK_INSTALL_DIR update into setupState check
- Create externally managed setup state type
- Add use-externally-managed-west-workspace command
- Update WestWorkspaceView to show Externally Managed option

Co-authored-by: rijesha <[email protected]>
- Add unit tests for generateExternallyManagedSetupState
- Add comprehensive documentation for the feature
- Include usage examples for Docker, DevContainers, and CI/CD

Co-authored-by: rijesha <[email protected]>
Copilot AI changed the title [WIP] Avoid replacing env-var ZEPHYR_SDK_INSTALL_DIR and others Add support for externally managed environment variables Oct 15, 2025
Copilot AI requested a review from rijesha October 15, 2025 17:56
Copilot finished work on behalf of rijesha October 15, 2025 17:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Avoid replacing env-var ZEPHYR_SDK_INSTALL_DIR, etc. Multiple identical entries added to Zephyr IDE Terminal Path

2 participants