11import * as vscode from 'vscode' ;
22import * as path from "path" ;
33import * as os from "os" ;
4- import { promises as fs } from "fs" ;
4+ import { promises as fs , PathLike } from "fs" ;
55
66import * as commands from './commands' ;
77import { activateInlayHints } from './inlay_hints' ;
@@ -12,6 +12,7 @@ import { log, assert, isValidExecutable } from './util';
1212import { PersistentState } from './persistent_state' ;
1313import { fetchRelease , download } from './net' ;
1414import { activateTaskProvider } from './tasks' ;
15+ import { exec } from 'child_process' ;
1516
1617let ctx : Ctx | undefined ;
1718
@@ -188,6 +189,46 @@ async function bootstrapServer(config: Config, state: PersistentState): Promise<
188189 return path ;
189190}
190191
192+ async function patchelf ( dest : PathLike ) : Promise < void > {
193+ await vscode . window . withProgress (
194+ {
195+ location : vscode . ProgressLocation . Notification ,
196+ title : "Patching rust-analysis for NixOS"
197+ } ,
198+ async ( progress , _ ) => {
199+ let patch_path = path . join ( os . tmpdir ( ) , "patch-ra.nix" )
200+ progress . report ( { message : "Writing nix file" , increment : 5 } )
201+ await fs . writeFile ( patch_path , `
202+ {src, pkgs ? import <nixpkgs> {}}:
203+ pkgs.stdenv.mkDerivation {
204+ name = "rust-analyzer";
205+ inherit src;
206+ phases = [ "installPhase" "fixupPhase" ];
207+ installPhase = "cp $src $out";
208+ fixupPhase = ''
209+ chmod 755 $out
210+ patchelf --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" $out
211+ '';
212+ }
213+ ` )
214+ let orig_file = dest + "-orig"
215+ await fs . rename ( dest , orig_file )
216+ progress . report ( { message : "Patching executable" , increment : 20 } )
217+ await new Promise ( ( resolve , reject ) => {
218+ exec ( `nix-build ${ patch_path } --arg src '${ orig_file } ' -o ${ dest } ` ,
219+ ( err , stdout , stderr ) => {
220+ if ( err != null ) {
221+ reject ( Error ( stderr ) )
222+ } else {
223+ resolve ( stdout )
224+ }
225+ } )
226+ } )
227+ // await fs.unlink(orig_file)
228+ }
229+ )
230+ }
231+
191232async function getServer ( config : Config , state : PersistentState ) : Promise < string | undefined > {
192233 const explicitPath = process . env . __RA_LSP_SERVER_DEBUG ?? config . serverPath ;
193234 if ( explicitPath ) {
@@ -237,6 +278,12 @@ async function getServer(config: Config, state: PersistentState): Promise<string
237278 assert ( ! ! artifact , `Bad release: ${ JSON . stringify ( release ) } ` ) ;
238279
239280 await download ( artifact . browser_download_url , dest , "Downloading rust-analyzer server" , { mode : 0o755 } ) ;
281+
282+ // Patching executable if that's NixOS.
283+ if ( fs . stat ( "/etc/nixos" ) . then ( _ => true ) . catch ( _ => false ) ) {
284+ await patchelf ( dest )
285+ }
286+
240287 await state . updateServerVersion ( config . package . version ) ;
241288 return dest ;
242289}
0 commit comments