@@ -17,7 +17,7 @@ use anyhow::Context;
1717use serde:: { Deserialize , Serialize } ;
1818use std:: collections:: HashMap ;
1919use std:: path:: { Path , PathBuf } ;
20- use std:: process:: { Command , ExitCode } ;
20+ use std:: process:: ExitCode ;
2121use std:: sync:: mpsc:: { channel, Receiver , Sender } ;
2222use std:: sync:: Arc ;
2323use std:: { fmt, thread} ;
@@ -73,24 +73,28 @@ pub trait Collector {
7373 fn stop ( & self ) -> Result < ( ) , anyhow:: Error > ;
7474}
7575
76- /// Process id is an OS identifier for a process.
77- #[ derive( Serialize , Deserialize , Debug , PartialEq , Clone ) ]
78- pub struct ProcessId ( pub u32 ) ;
79-
8076/// Represent a relevant life cycle event of a process.
8177///
8278/// In the current implementation, we only have one event, the `Started` event.
8379/// This event is sent when a process is started. It contains the process id
8480/// and the execution information.
8581#[ derive( Serialize , Deserialize , Debug , PartialEq , Clone ) ]
8682pub struct Event {
87- pub pid : ProcessId ,
83+ pub pid : u32 ,
8884 pub execution : Execution ,
8985}
9086
87+ impl Event {
88+ /// Creates a new event that is originated from the current process.
89+ pub fn new ( execution : Execution ) -> Self {
90+ let pid = std:: process:: id ( ) ;
91+ Event { pid, execution }
92+ }
93+ }
94+
9195impl fmt:: Display for Event {
9296 fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
93- write ! ( f, "Event pid={}, execution={}" , self . pid. 0 , self . execution)
97+ write ! ( f, "Event pid={}, execution={}" , self . pid, self . execution)
9498 }
9599}
96100
@@ -107,6 +111,69 @@ pub struct Execution {
107111 pub environment : HashMap < String , String > ,
108112}
109113
114+ impl Execution {
115+ /// Capture the execution information of the current process.
116+ pub fn capture ( ) -> anyhow:: Result < Self > {
117+ let executable = std:: env:: current_exe ( ) ?;
118+ let arguments = std:: env:: args ( ) . collect ( ) ;
119+ let working_dir = std:: env:: current_dir ( ) ?;
120+ let environment = std:: env:: vars ( ) . collect ( ) ;
121+
122+ Ok ( Self {
123+ executable,
124+ arguments,
125+ working_dir,
126+ environment,
127+ } )
128+ }
129+
130+ pub fn with_executable ( & self , executable : & Path ) -> Self {
131+ let mut updated = self . clone ( ) ;
132+ updated. executable = executable. to_path_buf ( ) ;
133+ updated
134+ }
135+
136+ pub fn with_environment ( & self , environment : HashMap < String , String > ) -> Self {
137+ let mut updated = self . clone ( ) ;
138+ updated. environment = environment;
139+ updated
140+ }
141+ }
142+
143+ impl TryFrom < args:: BuildCommand > for Execution {
144+ type Error = anyhow:: Error ;
145+
146+ /// Converts the `BuildCommand` to an `Execution` object.
147+ fn try_from ( value : args:: BuildCommand ) -> Result < Self , Self :: Error > {
148+ let executable = value
149+ . arguments
150+ . first ( )
151+ . ok_or_else ( || anyhow:: anyhow!( "No executable found" ) ) ?
152+ . clone ( )
153+ . into ( ) ;
154+ let arguments = value. arguments . to_vec ( ) ;
155+ let working_dir = std:: env:: current_dir ( ) ?;
156+ let environment = std:: env:: vars ( ) . collect ( ) ;
157+
158+ Ok ( Self {
159+ executable,
160+ arguments,
161+ working_dir,
162+ environment,
163+ } )
164+ }
165+ }
166+
167+ impl From < Execution > for std:: process:: Command {
168+ fn from ( val : Execution ) -> Self {
169+ let mut command = std:: process:: Command :: new ( val. executable ) ;
170+ command. args ( val. arguments . iter ( ) . skip ( 1 ) ) ;
171+ command. envs ( val. environment ) ;
172+ command. current_dir ( val. working_dir ) ;
173+ command
174+ }
175+ }
176+
110177impl fmt:: Display for Execution {
111178 fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
112179 write ! (
@@ -145,7 +212,7 @@ pub fn event(
145212 environment : HashMap < & str , & str > ,
146213) -> Event {
147214 Event {
148- pid : ProcessId ( pid ) ,
215+ pid,
149216 execution : execution ( executable, arguments, working_dir, environment) ,
150217 }
151218}
@@ -286,13 +353,9 @@ impl InterceptEnvironment {
286353 pub fn execute_build_command ( & self , input : args:: BuildCommand ) -> anyhow:: Result < ExitCode > {
287354 // TODO: record the execution of the build command
288355
289- let environment = self . environment ( ) ;
290- let process = input. arguments [ 0 ] . clone ( ) ;
291- let arguments = input. arguments [ 1 ..] . to_vec ( ) ;
292-
293- let mut child = Command :: new ( process) ;
294-
295- let exit_status = supervise ( child. args ( arguments) . envs ( environment) ) ?;
356+ let child: Execution = TryInto :: < Execution > :: try_into ( input) ?
357+ . with_environment ( self . environment ( ) . into_iter ( ) . collect ( ) ) ;
358+ let exit_status = supervise ( child) ?;
296359 log:: info!( "Execution finished with status: {:?}" , exit_status) ;
297360
298361 // The exit code is not always available. When the process is killed by a signal,
0 commit comments