diff --git a/package.json b/package.json index 23f7b9b..ac81d82 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@loupeteam/lpm", - "version": "1.3.0-beta.1", + "version": "1.3.0", "description": "LPM - Loupe Package Manager. A lightweight wrapper around NPM that processes Loupe packages.", "homepage": "https://loupeteam.github.io/LoupeDocs/tools/lpm.html", "repository": { diff --git a/src/LPM.py b/src/LPM.py index 99ff5f1..23a49ee 100644 --- a/src/LPM.py +++ b/src/LPM.py @@ -319,7 +319,10 @@ def cmd_install(args): deps = getPackageManifestField('package.json', ['dependencies']) or {} packages = list(deps.keys()) # Move packages from the node_modules folder into the project/main directory. - syncPackages(getAllDependencies(packages)) + with spinner('Resolving dependencies'): + allDeps = getAllDependencies(packages) + with spinner('Syncing packages'): + syncPackages(allDeps) sourceDependencies = [] else: if packages: @@ -334,13 +337,15 @@ def cmd_install(args): print('Deploying ' + ', '.join(packages) + ' to the following configurations: ' + ', '.join(deploymentConfigs)) for config in deploymentConfigs: if not args.source: - deployPackages(config, getAllDependencies(packages)) + with spinner(f'Deploying to {config}'): + deployPackages(config, getAllDependencies(packages)) else: # TODO: this split below may not be necessary, TBD. # For case of source, deploy the source first. - deployPackages(config, packages) - # Then deploy all of its dependencies. - deployPackages(config, sourceDependencies) + with spinner(f'Deploying source to {config}'): + deployPackages(config, packages) + # Then deploy all of its dependencies. + deployPackages(config, sourceDependencies) cprint('Operation completed successfully.', 'green') for package in packages: packageManifestPath = os.path.join('node_modules', package, 'package.json') @@ -367,7 +372,10 @@ def cmd_uninstall(args): except: cprint('Error while attempting to uninstall package(s).', 'yellow') return - syncPackages(getAllDependencies(packages)) + with spinner('Resolving dependencies'): + allDeps = getAllDependencies(packages) + with spinner('Syncing packages'): + syncPackages(allDeps) cprint('Operation completed successfully.', 'green') diff --git a/src/lpm_core.py b/src/lpm_core.py index e1c9bcb..879460b 100644 --- a/src/lpm_core.py +++ b/src/lpm_core.py @@ -13,19 +13,53 @@ everything else lives here so it can be reused and tested in isolation. """ +import itertools import json import os import os.path import re import shutil import subprocess +import sys +import threading from concurrent.futures import ThreadPoolExecutor +from contextlib import contextmanager import aspython as ASTools import requests from termcolor import colored, cprint +@contextmanager +def spinner(message): + # Show a rotating ASCII spinner while a silent phase runs so the user can + # tell lpm is still working. Falls back to a single static line when stdout + # isn't a TTY (CI logs, redirected output) so we don't spam carriage returns. + if not sys.stdout.isatty(): + print(f'{message}...') + yield + return + + stop_event = threading.Event() + frames = itertools.cycle('|/-\\') + + def animate(): + while not stop_event.is_set(): + sys.stdout.write(f'\r{next(frames)} {message}...') + sys.stdout.flush() + stop_event.wait(0.1) + + thread = threading.Thread(target=animate, daemon=True) + thread.start() + try: + yield + finally: + stop_event.set() + thread.join(timeout=0.5) + sys.stdout.write('\r' + ' ' * (len(message) + 6) + '\r') + sys.stdout.flush() + + def isAuthenticated(): command = [] command.append('npm whoami')