1
1
import * as vscode from 'vscode' ;
2
2
import * as path from "path" ;
3
3
import * as os from "os" ;
4
- import { promises as fs } from "fs" ;
4
+ import { promises as fs , PathLike } from "fs" ;
5
5
6
6
import * as commands from './commands' ;
7
7
import { activateInlayHints } from './inlay_hints' ;
@@ -12,6 +12,7 @@ import { log, assert, isValidExecutable } from './util';
12
12
import { PersistentState } from './persistent_state' ;
13
13
import { fetchRelease , download } from './net' ;
14
14
import { activateTaskProvider } from './tasks' ;
15
+ import { exec } from 'child_process' ;
15
16
16
17
let ctx : Ctx | undefined ;
17
18
@@ -188,6 +189,46 @@ async function bootstrapServer(config: Config, state: PersistentState): Promise<
188
189
return path ;
189
190
}
190
191
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
+
191
232
async function getServer ( config : Config , state : PersistentState ) : Promise < string | undefined > {
192
233
const explicitPath = process . env . __RA_LSP_SERVER_DEBUG ?? config . serverPath ;
193
234
if ( explicitPath ) {
@@ -237,6 +278,12 @@ async function getServer(config: Config, state: PersistentState): Promise<string
237
278
assert ( ! ! artifact , `Bad release: ${ JSON . stringify ( release ) } ` ) ;
238
279
239
280
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
+
240
287
await state . updateServerVersion ( config . package . version ) ;
241
288
return dest ;
242
289
}
0 commit comments