@@ -21,19 +21,22 @@ local receipt = require "mason-core.receipt"
2121--- @field cwd InstallContextCwd
2222--- @field opts PackageInstallOpts
2323--- @field stdio_sink StdioSink
24+ --- @field runner { suspend : fun (), resume : async fun () }
2425--- @field links { bin : table<string , string> , share : table<string , string> , opt : table<string , string> }
2526local InstallContext = {}
2627InstallContext .__index = InstallContext
2728
2829--- @param handle InstallHandle
2930--- @param opts PackageInstallOpts
30- function InstallContext :new (handle , opts )
31+ --- @param runner { suspend : fun (), resume : async fun () }
32+ function InstallContext :new (handle , opts , runner )
3133 local cwd = InstallContextCwd :new (handle )
3234 local spawn = InstallContextSpawn :new (handle , cwd , false )
3335 local fs = InstallContextFs :new (cwd )
3436 return setmetatable ({
3537 cwd = cwd ,
3638 spawn = spawn ,
39+ runner = runner ,
3740 handle = handle ,
3841 location = handle .location , -- for convenience
3942 package = handle .package , -- for convenience
@@ -264,6 +267,7 @@ function InstallContext:link_bin(executable, rel_path)
264267end
265268
266269InstallContext .CONTEXT_REQUEST = {}
270+ InstallContext .ABORT = {}
267271
268272--- @generic T
269273--- @param fn fun ( context : InstallContext ): T
@@ -277,14 +281,17 @@ function InstallContext:execute(fn)
277281 local step
278282 local ret_val
279283 step = function (...)
280- local ok , result = coroutine.resume (thread , ... )
284+ local results = { coroutine.resume (thread , ... ) }
285+ local ok , result = results [1 ], results [2 ]
281286 if not ok then
282287 error (result , 0 )
283288 elseif result == InstallContext .CONTEXT_REQUEST then
284289 step (self )
290+ elseif result == InstallContext .ABORT then
291+ ret_val = Result .failure (results [3 ])
285292 elseif coroutine.status (thread ) == " suspended" then
286293 -- yield to parent coroutine
287- step (coroutine.yield (result ))
294+ step (coroutine.yield (result , unpack ( results , 3 ) ))
288295 else
289296 ret_val = result
290297 end
@@ -293,6 +300,31 @@ function InstallContext:execute(fn)
293300 return ret_val
294301end
295302
303+ --- @async
304+ --- @param system_pkg SystemPackage
305+ function InstallContext :require (system_pkg )
306+ local result = Result .try (function (try )
307+ if try (system_pkg :needs_install ()) then
308+ self .stdio_sink :stdout (" Installing dependency " .. system_pkg .name .. " .\n " )
309+ self .runner .suspend ()
310+ try (system_pkg :install ():on_failure (function ()
311+ if self .opts .force then
312+ self .runner .resume ()
313+ end
314+ end ))
315+ self .runner .resume ()
316+ end
317+ end )
318+ if result :is_failure () then
319+ if not self .opts .force then
320+ self .stdio_sink :stderr " Run with :MasonInstall --force to attempt installation anyway.\n "
321+ coroutine.yield (InstallContext .ABORT , result :err_or_nil ())
322+ else
323+ self .stdio_sink :stderr (result :err_or_nil () .. " \n " )
324+ end
325+ end
326+ end
327+
296328--- @async
297329function InstallContext :build_receipt ()
298330 log .fmt_debug (" Building receipt for %s" , self .package )
0 commit comments