@@ -417,7 +417,7 @@ defmodule Hemdal.Host do
417417 defp run_in_background ( caller , cmd , args , send_result , % __MODULE__ { host: % _ { module: mod } = host } ) do
418418 mod . transaction ( host , fn handler ->
419419 with { :ok , errorlevel , output } <- exec_cmd ( handler , mod , caller , cmd , args ) ,
420- { :ok , % { "status" => status } = data } <- decode ( output ) do
420+ { :ok , % { "status" => status } = data } <- decode ( output , errorlevel , cmd . decode ) do
421421 Logger . debug ( "command exit(#{ errorlevel } ) output: #{ inspect ( data ) } " )
422422 run_result ( data , errorlevel , status )
423423 else
@@ -430,16 +430,38 @@ defmodule Hemdal.Host do
430430 :ok
431431 end
432432
433- defp decode ( output ) do
433+ defp decode ( nil , 0 , _ ) , do: { :ok , % { "status" => "OK" , "errorlevel" => 0 } }
434+
435+ defp decode ( nil , errorlevel , _ ) do
436+ { :error , % { "status" => "UNKNOWN" , "errorlevel" => errorlevel } }
437+ end
438+
439+ defp decode ( output , 0 , false ) when is_binary ( output ) do
440+ { :ok , % { "status" => "OK" , "message" => output } }
441+ end
442+
443+ defp decode ( output , 0 , false ) do
444+ { :ok , % { "status" => "OK" , "message" => "#{ inspect ( output ) } " } }
445+ end
446+
447+ defp decode ( output , errorlevel , false ) when is_binary ( output ) do
448+ { :ok , % { "status" => "OK" , "message" => output , "errorlevel" => errorlevel } }
449+ end
450+
451+ defp decode ( output , errorlevel , false ) do
452+ { :ok , % { "status" => "OK" , "message" => "#{ inspect ( output ) } " , "errorlevel" => errorlevel } }
453+ end
454+
455+ defp decode ( output , errorlevel , true ) do
434456 case Jason . decode ( output ) do
435457 { :ok , [ status , message ] } ->
436- { :ok , % { "status" => status , "message" => message } }
458+ { :ok , % { "status" => status , "message" => message , "errorlevel" => errorlevel } }
437459
438460 { :ok , status } when is_binary ( status ) ->
439- { :ok , % { "status" => status } }
461+ { :ok , % { "status" => status , "errorlevel" => errorlevel } }
440462
441463 { :error , % Jason.DecodeError { data: error } } ->
442- { :error , % { "message" => error , "status" => "UNKNOWN" } }
464+ { :error , % { "message" => error , "status" => "UNKNOWN" , "errorlevel" => errorlevel } }
443465
444466 other_resp ->
445467 other_resp
@@ -453,12 +475,18 @@ defmodule Hemdal.Host do
453475 |> String . pad_leading ( 7 , "0" )
454476 end
455477
478+ defp exec_cmd ( handler , mod , caller , % Command { type: "shell" } = cmd , _args ) do
479+ opts = [ output: cmd . output , timeout: cmd . idle_timeout , command: cmd . command ]
480+ mod . shell ( handler , caller , opts )
481+ end
482+
456483 defp exec_cmd ( handler , mod , _caller , % Command { type: "line" , command: command , interactive: false } , _args ) do
457484 mod . exec ( handler , command )
458485 end
459486
460- defp exec_cmd ( handler , mod , caller , % Command { type: "line" , command: command } , _args ) do
461- mod . exec_interactive ( handler , command , caller )
487+ defp exec_cmd ( handler , mod , caller , % Command { type: "line" , command: command } = cmd , _args ) do
488+ opts = [ output: cmd . output , timeout: cmd . idle_timeout ]
489+ mod . exec_interactive ( handler , command , caller , opts )
462490 end
463491
464492 defp exec_cmd ( handler , mod , _caller , % Command { type: "script" , command: script , interactive: false } , args ) do
@@ -479,7 +507,7 @@ defmodule Hemdal.Host do
479507 end
480508 end
481509
482- defp exec_cmd ( handler , mod , caller , % Command { type: "script" , command: script } , args ) do
510+ defp exec_cmd ( handler , mod , caller , % Command { type: "script" , command: script } = command , args ) do
483511 tmp_file = Path . join ( [ @ default_temporal_dir , random_string ( ) ] )
484512
485513 sh =
@@ -490,7 +518,8 @@ defmodule Hemdal.Host do
490518
491519 mod . write_file ( handler , tmp_file , script )
492520 cmd = Enum . join ( [ sh , tmp_file | args ] , " " )
493- mod . exec_interactive ( handler , cmd , caller )
521+ opts = [ output: command . output , timeout: command . idle_timeout ]
522+ mod . exec_interactive ( handler , cmd , caller , opts )
494523 end
495524
496525 @ typedoc """
@@ -552,13 +581,31 @@ defmodule Hemdal.Host do
552581 """
553582 @ callback exec ( handler ( ) , command ( ) ) :: { :ok , errorlevel ( ) , output ( ) } | { :error , reason ( ) }
554583
584+ @ typedoc """
585+ The options for `exec_interactive/4` and `shell/2` let us define if we want to
586+ accumulate the output (it's usually not desirable for shell sessions) and the
587+ timeout for idle. It means the time it wait between interactions to close the
588+ communication.
589+ """
590+ @ type exec_mod_opts ( ) :: [
591+ output: boolean ( ) ,
592+ timeout: timeout ( )
593+ ]
594+
555595 @ doc """
556596 Exec an interactive command implemented by the module where it's
557597 implemented. The `c:exec_interactive/3` command is getting a handler from the
558598 transaction and the command to be executed as a string.
559599 """
560- @ callback exec_interactive ( handler ( ) , command ( ) , pid ( ) ) ::
561- { :ok , errorlevel ( ) , output ( ) } | { :error , reason ( ) }
600+ @ callback exec_interactive ( handler ( ) , command ( ) , pid ( ) , exec_mod_opts ( ) ) ::
601+ { :ok , pid ( ) } | { :ok , errorlevel ( ) , output ( ) } | { :error , reason ( ) }
602+
603+ @ doc """
604+ Start a shell and connect to it. The shell usually has specific features that let
605+ us to do more than in normal or usual exec commands.
606+ """
607+ @ callback shell ( handler ( ) , pid ( ) , exec_mod_opts ( ) ) ::
608+ { :ok , pid ( ) } | { :ok , errorlevel ( ) , output ( ) } | { :error , reason ( ) }
562609
563610 @ doc """
564611 Write a file in the remote (or local) host. It's intended to write the
0 commit comments