88import subprocess
99import numpy as np
1010import cv2
11-
11+ import requests
12+ from msal import PublicClientApplication
1213class LoggingManager :
1314 """A top level manager of the logging process. This is responsible for
1415 creating log folders, log metadata files, and for replaying components from log
@@ -129,11 +130,19 @@ def log_components(self,components : List[str]) -> None:
129130
130131 def log_ros_topics (self , topics : List [str ], rosbag_options : str = '' ) -> Optional [str ]:
131132 if topics :
132- command = ['rosbag' ,'record' ,'--output-name={}' .format (os .path .join (self .log_folder ,'vehicle.bag' ))]
133- command += rosbag_options .split ()
134- command += topics
135- self .rosbag_process = subprocess .Popen (command , stdin = subprocess .PIPE , stdout = subprocess .PIPE )
136- return ' ' .join (command )
133+ rosbag_command = 'rosbag record --output-name={} {} {}' .format (
134+ os .path .join (self .log_folder , 'vehicle.bag' ),
135+ rosbag_options ,
136+ ' ' .join (topics )
137+ )
138+ full_command = f'source catkin_ws/devel/setup.bash && { rosbag_command } '
139+
140+ # Run the command in a bash shell
141+ self .rosbag_process = subprocess .Popen (
142+ ['bash' , '-c' , full_command ],
143+ stdin = subprocess .PIPE ,
144+ stdout = subprocess .PIPE
145+ )
137146 return None
138147
139148 def set_vehicle_time (self , vehicle_time : float ) -> None :
@@ -207,7 +216,7 @@ def dump_debug(self):
207216 else :
208217 isevent [col ] = True
209218 f .write (',' .join (columns )+ '\n ' )
210- nrows = max (len (v [col ]) for col in v )
219+ nrows = max (( len (v [col ]) for col in v ), default = 0 )
211220 for i in range (nrows ):
212221 row = []
213222 for col ,vals in v .items ():
@@ -263,6 +272,8 @@ def log_component_stderr(self, component : str, msg : List[str]) -> None:
263272 self .component_output_loggers [component ][1 ].write (timestr + ': ' + l + '\n ' )
264273
265274 def close (self ):
275+
276+
266277 self .dump_debug ()
267278 self .debug_messages = {}
268279 if self .rosbag_process is not None :
@@ -276,6 +287,54 @@ def close(self):
276287 print ('Log file size in MegaBytes is {}' .format (loginfo .st_size / (1024 * 1024 )))
277288 print ('-------------------------------------------' )
278289 self .rosbag_process = None
290+
291+
292+
293+ record_bag = input ("Do you want to upload this Rosbag? Y/N (default: Y): " ) or "Y"
294+
295+
296+ if (record_bag not in ["N" , "no" , "n" , "No" ]):
297+
298+ # Azure App credentials (trying not to hardcode)
299+ # export CLIENT_ID= ""
300+ # export TENANT_ID =""
301+ CLIENT_ID = os .getenv ("CLIENT_ID" )
302+ TENANT_ID = os .getenv ("TENANT_ID" )
303+ AUTHORITY = f'https://login.microsoftonline.com/{ TENANT_ID } '
304+ SCOPES = ['Files.ReadWrite.All' ]
305+
306+ app = PublicClientApplication (CLIENT_ID , authority = AUTHORITY )
307+ accounts = app .get_accounts ()
308+
309+
310+ if accounts :
311+ result = app .acquire_token_silent (SCOPES , account = accounts [0 ])
312+ else :
313+ print ("Opening Authentication Window" )
314+
315+ result = app .acquire_token_interactive (SCOPES )
316+
317+ if 'access_token' in result :
318+ access_token = result ['access_token' ]
319+ headers = {
320+ 'Authorization' : f'Bearer { access_token } ' ,
321+ 'Content-Type' : 'application/octet-stream'
322+ }
323+ file_path = os .path .join (self .log_folder ,'vehicle.bag' )
324+ file_name = os .path .basename (file_path )
325+
326+ upload_url = f'https://graph.microsoft.com/v1.0/me/drive/root:/{ file_name } :/content'
327+
328+ with open (file_path , 'rb' ) as file :
329+ response = requests .put (upload_url , headers = headers , data = file )
330+
331+ if response .status_code == 201 or response .status_code == 200 :
332+ print (f"✅ Successfully uploaded '{ file_name } ' to OneDrive." )
333+ else :
334+ print (f"❌ Upload failed: { response .status_code } - { response .text } " )
335+ else :
336+ print ("❌ Authentication failed." )
337+
279338
280339 def __del__ (self ):
281340 self .close ()
0 commit comments