@@ -177,6 +177,10 @@ def __init__(self):
177
177
if self .aws_profile and self .aws_region :
178
178
self .aws_init = True
179
179
180
+ # Last timestamp we checked for an updated
181
+ self .update_check_timestamp = config .get (
182
+ 'UPDATE' , 'timestamp' , fallback = None )
183
+
180
184
# Shared configuration
181
185
self .is_shared = config .getboolean (
182
186
'SHARED' , 'is_shared' , fallback = False )
@@ -254,6 +258,7 @@ def __init__(self):
254
258
255
259
if self .user_init and self .aws_init and self .s3_init and self .nih_init :
256
260
self .configuration_done = True
261
+
257
262
except Exception :
258
263
print_error ()
259
264
@@ -1197,6 +1202,27 @@ def set_slurm(self, args):
1197
1202
print_error ()
1198
1203
return False
1199
1204
1205
+ def check_update (self ):
1206
+ '''Set the update check'''
1207
+
1208
+ try :
1209
+ timestamp = time .time ()
1210
+
1211
+ if hasattr (self , 'update_check_timestamp' ) and self .update_check_timestamp is not None :
1212
+ # Check if last day was less than 86400 * 7 = (1 day) * 7 = 1 week
1213
+ if timestamp - self .update_check_timestamp < (86400 * 7 ):
1214
+ # Less than a week since last check
1215
+ return False
1216
+
1217
+ # Set the update check flag in the config file
1218
+ self .__set_configuration_entry (
1219
+ 'UPDATE' , 'update_check_timestamp' , timestamp )
1220
+ return True
1221
+
1222
+ except Exception :
1223
+ print_error ()
1224
+ return False
1225
+
1200
1226
1201
1227
class AWSBoto :
1202
1228
'''AWS handler class. This class is used to interact with AWS services.'''
@@ -6147,7 +6173,7 @@ def subcmd_index(self, cfg: ConfigManager, arch: Archiver):
6147
6173
except Exception :
6148
6174
print_error ()
6149
6175
6150
- def subcmd_archive (self , arch : Archiver ):
6176
+ def subcmd_archive (self , arch : Archiver , aws : AWSBoto ):
6151
6177
'''Check command for archiving folders for Froster.'''
6152
6178
6153
6179
try :
@@ -6174,6 +6200,10 @@ def subcmd_archive(self, arch: Archiver):
6174
6200
arch .reset_folder (folder , self .args .recursive )
6175
6201
return
6176
6202
6203
+ if not aws .check_credentials ():
6204
+ print ('\n Error: invalid credentials. Check the AWS configuration with "froster config --aws"\n ' )
6205
+ sys .exit (1 )
6206
+
6177
6207
# Check if the user provided the hotspots argument
6178
6208
if self .args .hotspots :
6179
6209
if self .args .folders :
@@ -6200,6 +6230,10 @@ def subcmd_restore(self, arch: Archiver, aws: AWSBoto):
6200
6230
'''Check command for restoring folders for Froster.'''
6201
6231
6202
6232
try :
6233
+ if not aws .check_credentials ():
6234
+ print ('\n Error: invalid credentials. Check the AWS configuration with "froster config --aws"\n ' )
6235
+ sys .exit (1 )
6236
+
6203
6237
if self .args .monitor :
6204
6238
# aws inactivity and cost monitoring
6205
6239
aws .monitor_ec2 ()
@@ -6235,10 +6269,14 @@ def subcmd_restore(self, arch: Archiver, aws: AWSBoto):
6235
6269
except Exception :
6236
6270
print_error ()
6237
6271
6238
- def subcmd_delete (self , arch : Archiver ):
6272
+ def subcmd_delete (self , arch : Archiver , aws : AWSBoto ):
6239
6273
'''Check command for deleting folders for Froster.'''
6240
6274
6241
6275
try :
6276
+ if not aws .check_credentials ():
6277
+ print ('\n Error: invalid credentials. Check the AWS configuration with "froster config --aws"\n ' )
6278
+ sys .exit (1 )
6279
+
6242
6280
if not self .args .folders :
6243
6281
6244
6282
# Get the list of folders from the archive
@@ -6269,9 +6307,13 @@ def subcmd_delete(self, arch: Archiver):
6269
6307
except Exception :
6270
6308
print_error ()
6271
6309
6272
- def subcmd_mount (self , arch : Archiver ):
6310
+ def subcmd_mount (self , arch : Archiver , aws : AWSBoto ):
6273
6311
6274
6312
try :
6313
+ if not aws .check_credentials ():
6314
+ print ('\n Error: invalid credentials. Check the AWS configuration with "froster config --aws"\n ' )
6315
+ sys .exit (1 )
6316
+
6275
6317
if self .args .list :
6276
6318
arch .print_current_mounts ()
6277
6319
return
@@ -6413,26 +6455,40 @@ def subcmd_credentials(self, cfg: ConfigManager, aws: AWSBoto):
6413
6455
return False
6414
6456
6415
6457
def subcmd_update (self ):
6416
- '''Update Froster'''
6417
-
6458
+ '''Check if an update is available'''
6418
6459
try :
6419
- if self .args .rclone :
6420
- cmd = "rclone selfupdate"
6421
- else :
6422
- cmd = "curl -s https://raw.githubusercontent.com/dirkpetersen/froster/main/install.sh?$(date +%s) | bash"
6423
-
6424
- p = subprocess .Popen (cmd , stdout = subprocess .PIPE ,
6425
- stderr = subprocess .STDOUT , shell = True )
6426
6460
6427
- for line in iter (p .stdout .readline , b'' ):
6428
- print (line .decode (), end = '' )
6429
-
6430
- # Wait for the process to finish and get the exit code
6431
- p .wait ()
6461
+ cmd = "curl -s https://api.github.com/repos/dirkpetersen/froster/releases"
6462
+
6463
+ result = subprocess .run (cmd , shell = True , text = True ,
6464
+ stdout = subprocess .PIPE , stderr = subprocess .PIPE )
6465
+
6466
+ if result .returncode != 0 :
6467
+ print (f"Error checking if froster update available. Command run: { cmd } : { result .stderr .strip ()} " )
6468
+ return False
6469
+
6470
+ def compare_versions (version1 , version2 ):
6471
+ v1 = [int (v ) for v in version1 .split ("." )]
6472
+ v2 = [int (v ) for v in version2 .split ("." )]
6473
+
6474
+ for i in range (max (len (v1 ), len (v2 ))):
6475
+ v1_part = v1 [i ] if i < len (v1 ) else 0
6476
+ v2_part = v2 [i ] if i < len (v2 ) else 0
6477
+ if v1_part != v2_part :
6478
+ return v1_part - v2_part
6479
+ return 0
6480
+
6481
+ releases = json .loads (result .stdout )
6482
+ latest = releases [0 ]['tag_name' ].replace ('v' , '' )
6483
+ current = pkg_resources .get_distribution ("froster" ).version
6484
+
6485
+ if compare_versions (latest , current ) > 0 :
6486
+ print (f'\n A froster update is available: froster v{ latest } ' )
6487
+ print (f'You can update froster using the command:' )
6488
+ print (f' curl -s https://raw.githubusercontent.com/dirkpetersen/froster/main/install.sh?$(date +%s) | bash\n ' )
6489
+ else :
6490
+ print (f'\n Froster is up to date: froster v{ current } \n ' )
6432
6491
6433
- if p .returncode != 0 :
6434
- print (
6435
- f"Error: The update failed with exit code { p .returncode } ." )
6436
6492
except Exception :
6437
6493
print_error ()
6438
6494
@@ -6871,15 +6927,15 @@ def main():
6871
6927
elif args .subcmd in ['index' , 'ind' ]:
6872
6928
cmd .subcmd_index (cfg , arch )
6873
6929
elif args .subcmd in ['archive' , 'arc' ]:
6874
- cmd .subcmd_archive (arch )
6930
+ cmd .subcmd_archive (arch , aws )
6875
6931
elif args .subcmd in ['restore' , 'rst' ]:
6876
6932
cmd .subcmd_restore (arch , aws )
6877
6933
elif args .subcmd in ['delete' , 'del' ]:
6878
- cmd .subcmd_delete (arch )
6934
+ cmd .subcmd_delete (arch , aws )
6879
6935
elif args .subcmd in ['mount' , 'mnt' ]:
6880
- cmd .subcmd_mount (arch )
6936
+ cmd .subcmd_mount (arch , aws )
6881
6937
elif args .subcmd in ['umount' ]:
6882
- cmd .subcmd_umount (arch )
6938
+ cmd .subcmd_umount (arch , aws )
6883
6939
elif args .subcmd in ['ssh' , 'scp' ]:
6884
6940
cmd .subcmd_ssh (cfg , aws )
6885
6941
elif args .subcmd in ['credentials' , 'crd' ]:
@@ -6889,6 +6945,11 @@ def main():
6889
6945
else :
6890
6946
cmd .print_help ()
6891
6947
6948
+ # Check if there are updates on froster every X days
6949
+ if cfg .check_update ():
6950
+ cmd .subcmd_update (cfg )
6951
+
6952
+ # Close the AWS session
6892
6953
aws .close_session ()
6893
6954
6894
6955
except Exception :
0 commit comments