@@ -26,6 +26,7 @@ public class WindowsPrerequisiteHelper : IPrerequisiteHelper
26
26
private const string VcRedistDownloadUrl = "https://aka.ms/vs/16/release/vc_redist.x64.exe" ;
27
27
private const string TkinterDownloadUrl =
28
28
"https://cdn.lykos.ai/tkinter-cpython-embedded-3.10.11-win-x64.zip" ;
29
+ private const string NodeDownloadUrl = "https://nodejs.org/dist/v20.11.0/node-v20.11.0-win-x64.zip" ;
29
30
30
31
private string HomeDir => settingsManager . LibraryDir ;
31
32
@@ -49,8 +50,10 @@ public class WindowsPrerequisiteHelper : IPrerequisiteHelper
49
50
private string TkinterZipPath => Path . Combine ( AssetsDir , "tkinter.zip" ) ;
50
51
private string TkinterExtractPath => PythonDir ;
51
52
private string TkinterExistsPath => Path . Combine ( PythonDir , "tkinter" ) ;
52
- public string GitBinPath => Path . Combine ( PortableGitInstallDir , "bin" ) ;
53
+ private string NodeExistsPath => Path . Combine ( AssetsDir , "nodejs" , "npm.cmd" ) ;
54
+ private string NodeDownloadPath => Path . Combine ( AssetsDir , "nodejs.zip" ) ;
53
55
56
+ public string GitBinPath => Path . Combine ( PortableGitInstallDir , "bin" ) ;
54
57
public bool IsPythonInstalled => File . Exists ( PythonDllPath ) ;
55
58
56
59
public WindowsPrerequisiteHelper (
@@ -111,12 +114,28 @@ public async Task<string> GetGitOutput(string? workingDirectory = null, params s
111
114
return process ;
112
115
}
113
116
117
+ public async Task RunNpm (
118
+ ProcessArgs args ,
119
+ string ? workingDirectory = null ,
120
+ Action < ProcessOutput > ? onProcessOutput = null
121
+ )
122
+ {
123
+ var result = await ProcessRunner
124
+ . GetProcessResultAsync ( NodeExistsPath , args , workingDirectory )
125
+ . ConfigureAwait ( false ) ;
126
+
127
+ result . EnsureSuccessExitCode ( ) ;
128
+ onProcessOutput ? . Invoke ( ProcessOutput . FromStdOutLine ( result . StandardOutput ) ) ;
129
+ onProcessOutput ? . Invoke ( ProcessOutput . FromStdErrLine ( result . StandardError ) ) ;
130
+ }
131
+
114
132
public async Task InstallAllIfNecessary ( IProgress < ProgressReport > ? progress = null )
115
133
{
116
134
await InstallVcRedistIfNecessary ( progress ) ;
117
135
await UnpackResourcesIfNecessary ( progress ) ;
118
136
await InstallPythonIfNecessary ( progress ) ;
119
137
await InstallGitIfNecessary ( progress ) ;
138
+ await InstallNodeIfNecessary ( progress ) ;
120
139
}
121
140
122
141
public async Task UnpackResourcesIfNecessary ( IProgress < ProgressReport > ? progress = null )
@@ -372,6 +391,42 @@ await downloadService.DownloadToFileAsync(
372
391
File . Delete ( VcRedistDownloadPath ) ;
373
392
}
374
393
394
+ [ SupportedOSPlatform ( "windows" ) ]
395
+ public async Task InstallNodeIfNecessary ( IProgress < ProgressReport > ? progress = null )
396
+ {
397
+ if ( File . Exists ( NodeExistsPath ) )
398
+ {
399
+ Logger . Info ( "node already installed" ) ;
400
+ return ;
401
+ }
402
+
403
+ Logger . Info ( "Downloading node" ) ;
404
+ await downloadService . DownloadToFileAsync ( NodeDownloadUrl , NodeDownloadPath , progress : progress ) ;
405
+
406
+ Logger . Info ( "Installing node" ) ;
407
+ progress ? . Report (
408
+ new ProgressReport (
409
+ progress : 0.5f ,
410
+ isIndeterminate : true ,
411
+ type : ProgressType . Generic ,
412
+ message : "Installing prerequisites..."
413
+ )
414
+ ) ;
415
+
416
+ // unzip
417
+ await ArchiveHelper . Extract ( NodeDownloadPath , AssetsDir , progress ) ;
418
+
419
+ // move to assets dir
420
+ var existingNodeDir = Path . Combine ( AssetsDir , "node-v20.11.0-win-x64" ) ;
421
+ Directory . Move ( existingNodeDir , Path . Combine ( AssetsDir , "nodejs" ) ) ;
422
+
423
+ progress ? . Report (
424
+ new ProgressReport ( progress : 1f , message : "Node install complete" , type : ProgressType . Generic )
425
+ ) ;
426
+
427
+ File . Delete ( NodeDownloadPath ) ;
428
+ }
429
+
375
430
private async Task UnzipGit ( IProgress < ProgressReport > ? progress = null )
376
431
{
377
432
if ( progress == null )
0 commit comments