Skip to content

Commit 68d9b11

Browse files
Merge pull request #51 from HPCNow/main
froster v0.11.7
2 parents 62441ff + da328ae commit 68d9b11

File tree

6 files changed

+117
-77
lines changed

6 files changed

+117
-77
lines changed

Diff for: .github/workflows/python-publish.yml

+2-8
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,8 @@
99
name: Upload Python Package
1010

1111
on:
12-
workflow_dispatch:
13-
inputs:
14-
logLevel:
15-
description: 'Log level'
16-
required: true
17-
default: 'warning'
18-
tags:
19-
description: 'Test scenario tags'
12+
release:
13+
types: [created]
2014

2115
permissions:
2216
contents: read

Diff for: froster/froster.py

+85-24
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,10 @@ def __init__(self):
177177
if self.aws_profile and self.aws_region:
178178
self.aws_init = True
179179

180+
# Last timestamp we checked for an updated
181+
self.update_check_timestamp = config.get(
182+
'UPDATE', 'timestamp', fallback=None)
183+
180184
# Shared configuration
181185
self.is_shared = config.getboolean(
182186
'SHARED', 'is_shared', fallback=False)
@@ -254,6 +258,7 @@ def __init__(self):
254258

255259
if self.user_init and self.aws_init and self.s3_init and self.nih_init:
256260
self.configuration_done = True
261+
257262
except Exception:
258263
print_error()
259264

@@ -1197,6 +1202,27 @@ def set_slurm(self, args):
11971202
print_error()
11981203
return False
11991204

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+
12001226

12011227
class AWSBoto:
12021228
'''AWS handler class. This class is used to interact with AWS services.'''
@@ -6147,7 +6173,7 @@ def subcmd_index(self, cfg: ConfigManager, arch: Archiver):
61476173
except Exception:
61486174
print_error()
61496175

6150-
def subcmd_archive(self, arch: Archiver):
6176+
def subcmd_archive(self, arch: Archiver, aws: AWSBoto):
61516177
'''Check command for archiving folders for Froster.'''
61526178

61536179
try:
@@ -6174,6 +6200,10 @@ def subcmd_archive(self, arch: Archiver):
61746200
arch.reset_folder(folder, self.args.recursive)
61756201
return
61766202

6203+
if not aws.check_credentials():
6204+
print('\nError: invalid credentials. Check the AWS configuration with "froster config --aws"\n')
6205+
sys.exit(1)
6206+
61776207
# Check if the user provided the hotspots argument
61786208
if self.args.hotspots:
61796209
if self.args.folders:
@@ -6200,6 +6230,10 @@ def subcmd_restore(self, arch: Archiver, aws: AWSBoto):
62006230
'''Check command for restoring folders for Froster.'''
62016231

62026232
try:
6233+
if not aws.check_credentials():
6234+
print('\nError: invalid credentials. Check the AWS configuration with "froster config --aws"\n')
6235+
sys.exit(1)
6236+
62036237
if self.args.monitor:
62046238
# aws inactivity and cost monitoring
62056239
aws.monitor_ec2()
@@ -6235,10 +6269,14 @@ def subcmd_restore(self, arch: Archiver, aws: AWSBoto):
62356269
except Exception:
62366270
print_error()
62376271

6238-
def subcmd_delete(self, arch: Archiver):
6272+
def subcmd_delete(self, arch: Archiver, aws: AWSBoto):
62396273
'''Check command for deleting folders for Froster.'''
62406274

62416275
try:
6276+
if not aws.check_credentials():
6277+
print('\nError: invalid credentials. Check the AWS configuration with "froster config --aws"\n')
6278+
sys.exit(1)
6279+
62426280
if not self.args.folders:
62436281

62446282
# Get the list of folders from the archive
@@ -6269,9 +6307,13 @@ def subcmd_delete(self, arch: Archiver):
62696307
except Exception:
62706308
print_error()
62716309

6272-
def subcmd_mount(self, arch: Archiver):
6310+
def subcmd_mount(self, arch: Archiver, aws: AWSBoto):
62736311

62746312
try:
6313+
if not aws.check_credentials():
6314+
print('\nError: invalid credentials. Check the AWS configuration with "froster config --aws"\n')
6315+
sys.exit(1)
6316+
62756317
if self.args.list:
62766318
arch.print_current_mounts()
62776319
return
@@ -6413,26 +6455,40 @@ def subcmd_credentials(self, cfg: ConfigManager, aws: AWSBoto):
64136455
return False
64146456

64156457
def subcmd_update(self):
6416-
'''Update Froster'''
6417-
6458+
'''Check if an update is available'''
64186459
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)
64266460

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'\nA 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'\nFroster is up to date: froster v{current}\n')
64326491

6433-
if p.returncode != 0:
6434-
print(
6435-
f"Error: The update failed with exit code {p.returncode}.")
64366492
except Exception:
64376493
print_error()
64386494

@@ -6871,15 +6927,15 @@ def main():
68716927
elif args.subcmd in ['index', 'ind']:
68726928
cmd.subcmd_index(cfg, arch)
68736929
elif args.subcmd in ['archive', 'arc']:
6874-
cmd.subcmd_archive(arch)
6930+
cmd.subcmd_archive(arch, aws)
68756931
elif args.subcmd in ['restore', 'rst']:
68766932
cmd.subcmd_restore(arch, aws)
68776933
elif args.subcmd in ['delete', 'del']:
6878-
cmd.subcmd_delete(arch)
6934+
cmd.subcmd_delete(arch, aws)
68796935
elif args.subcmd in ['mount', 'mnt']:
6880-
cmd.subcmd_mount(arch)
6936+
cmd.subcmd_mount(arch, aws)
68816937
elif args.subcmd in ['umount']:
6882-
cmd.subcmd_umount(arch)
6938+
cmd.subcmd_umount(arch, aws)
68836939
elif args.subcmd in ['ssh', 'scp']:
68846940
cmd.subcmd_ssh(cfg, aws)
68856941
elif args.subcmd in ['credentials', 'crd']:
@@ -6889,6 +6945,11 @@ def main():
68896945
else:
68906946
cmd.print_help()
68916947

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
68926953
aws.close_session()
68936954

68946955
except Exception:

Diff for: install.sh

+6-15
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,9 @@ backup_old_installation() {
205205
fi
206206

207207
if pipx list | grep froster >/dev/null 2>&1; then
208-
pipx uninstall froster &
208+
# If froster is installed with pipx, uninstall it and ignore errors
209+
# sometime pipx uninstall fails with error code 1 if PIPX_HOME is set, but froster is still uninstalled
210+
pipx uninstall froster >/dev/null 2>&1 &
209211
spinner $!
210212
fi
211213

@@ -234,22 +236,11 @@ install_froster() {
234236
# Ensure ~/.local/bin is in the PATH
235237
pipx ensurepath >/dev/null 2>&1
236238

237-
# TODO: Update path once froster is in PyPi repository
238-
239-
# Get the repository and branch from the github environment variables (if any)
240-
# or set the default repository and branch
241-
if [[ -v REPO ]]; then
242-
REPO="https://github.com/$REPO"
243-
else
244-
REPO="https://github.com/dirkpetersen/froster.git"
245-
fi
246-
247-
BRANCH=${BRANCH:-"main"}
248-
249239
echo
250-
echo "Installing latest version of froster from \"$REPO@$BRANCH\"..."
240+
echo "Installing latest version of froster..."
251241

252-
pipx install git+$REPO@$BRANCH >/dev/null 2>&1 &
242+
# Install froster from PyPi package repository
243+
pipx install froster >/dev/null 2>&1 &
253244
spinner $!
254245

255246
# Keep the config.ini file (if any)

Diff for: pyproject.toml

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
[build-system]
2+
requires = ["poetry-core>=1.0.0"]
3+
build-backend = "poetry.core.masonry.api"
4+
5+
[tool.poetry]
6+
name = "froster"
7+
version = "0.11.7"
8+
description = "Froster is a tool for easy data transfer between local file systems and AWS S3 storage."
9+
authors = ["Victor Machado <[email protected]>"]
10+
readme = "README.md"
11+
license = "MIT"
12+
13+
[tool.poetry.dependencies]
14+
python = "^3.6"
15+
boto3 = "^1.34.104"
16+
duckdb = "^0.10.2"
17+
inquirer = "^3.2.4"
18+
psutil = "^5.9.0"
19+
requests = "^2.31.0"
20+
textual = "^0.59.0"
21+
visidata = "^3.0.2"
22+
23+
[tool.poetry.scripts]
24+
froster = "froster.froster:main"

Diff for: requirements.txt

-7
This file was deleted.

Diff for: setup.py

-23
This file was deleted.

0 commit comments

Comments
 (0)