Skip to content

Having /etc/nixos directory on macOS can cause rust-analyzer to assume the OS is nixOS #5641

@jieyouxu

Description

@jieyouxu
Info Version
OS macOS Catalina 10.15.5 (19F101)
Platform Darwin 19.5.0 x86_64 i386
VSCode 1.47.3
rust-analyzer VSCode client plugin 0.3.261-nightly

I tried to install rust-analyzer plugin in VSCode on macOS, and I can install the plugin, but can't successfully install the server binary. The culprit seems to be lines 16274 in the production script out/main.js checks the OS type:

// Patching executable if that's NixOS.
if (await fs.promises.stat("/etc/nixos").then(_ => true).catch(_ => false)) {
...

This seems to be generated from the lines
https://github.com/rust-analyzer/rust-analyzer/blob/56ade20380a028026eeb71af2a8a81e37ede7efb/editors/code/src/main.ts#L328-L331

The problem here is that this check for NixOS evaluates to true on my macOS system and it means that it tries to utilize NixOS utilities to patch the server binary, which I don't have, causing server installation failure.

This check is insufficient; it can give a false positive on macOS or other linux distributions, for that matter, if the user has the /etc/nixos directory for whatever reason (like myself), even if the directory is empty. It only looks like it's checking if the directory exists (using fs.stat calls underlying stat(2), and maps ENOENT to false).

I've tried to look for relevant APIs in Node.js docs, but os.platform() doesn't seem to provide sufficient info either (i.e. it might not distinguish between linux distros?).

As discussed by @eternaleye in PR #4555, which introduced this check, a better way may be checking for /etc/os-release, but that file seems to be only available if the user's distribution runs systemd. Maybe a few more checks can make that work.

Alternatively, a really hacky way that might be more accurate may be (assuming that it is gated by a linux-distro check):

const util = require('util');
const exec = util.promisify(require('child_process').exec);

async function is_nixos() {
    // On NixOS, `uname(3)` should give something like 
    // `Linux NixOS 4.9.53 #1-NixOS SMP ...`
    try {
        const { stdout } = await exec('uname -a');
        if (stdout.toLowerCase().contains("nixos")) {
            return true;
        } else {
            return false;
        }
    } catch (e) {
        return false;
    }
}

But I don't have NixOS installed and can't really test it out. (Running it my system gives a false as expected).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions