Skip to content

Commit

Permalink
Merge pull request #46 from Yesser-Studios/wt-env-var
Browse files Browse the repository at this point in the history
Fix Windows Terminal progress ring escape sequence showing in terminals not supporting this feature
  • Loading branch information
yesseruser authored Feb 11, 2024
2 parents cab5663 + 9be6803 commit d2a1fe4
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 46 deletions.
81 changes: 44 additions & 37 deletions src/ypkgupgr/__init__.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import asyncio
import subprocess
import sys
import os
import asyncio
import logging
import platformdirs

import click

from .appdata import create_appdata_dirs, log_dir
from .colors import Colors
from .consts import APP_NAME, AUTHOR_NAME
from .logs import *
from .appdata import create_appdata_dirs, log_dir
from .graphics import progress_update, progress_ring, clear_screen
from .ignored import ignored, get_ignored_packages, ignore_packages, unignore_packages
from .ignored import unignore_all as actually_unignore_all
from .graphics import progress_update, progress_ring, clear_screen
from .logs import *
from .misc import *


async def update(name: str, line: int):
"""
Updates the package using its name.
Expand All @@ -25,8 +25,8 @@ async def update(name: str, line: int):
global ypkgupgr_outdated

get_ignored_packages()
if (name in ignored): # Package in ignored

if (name in ignored): # Package in ignored
logger.info(f"Package {name} ignored.")
progress_update(line, f"{name}: {Colors.YELLOW}Ignored")
finished_count += 1
Expand Down Expand Up @@ -60,14 +60,14 @@ async def update(name: str, line: int):
process = await asyncio.create_subprocess_shell('"' + sys.executable + '"' + " -m pip install --upgrade " + name,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE)

logger.debug("Subprocess shell created.")

# Gets this process' return code.
return_code = await process.wait()

logger.debug(f"Subprocess ended with code {return_code}")

# Adds a finished and updates the progress ring.
finished_count += 1
progress = int((finished_count / outdated_count) * 100)
Expand All @@ -87,24 +87,25 @@ async def update(name: str, line: int):
logger.error(errline)

logger.info("End of pip output.")

progress_update(line, f"{name}: {Colors.RED}Error")
# print(f"{name} failed to update. ({progress}% - {finished_count}/{outdated_count} complete or failed)")

if failed == "":
failed = name
else:
failed += ", " + name

logger.debug(f"Added {name} to failed.")


async def start_updates(lines: list[str]):
"""Updates each package."""
global line_count

tasks = []

line_no = 3 # Tasks start at line 3, because there was 1 line already printed + one to separate.
line_no = 3 # Tasks start at line 3, because there was 1 line already printed + one to separate.
for line in lines:
package_info = line.split()
package_name = package_info[0]
Expand All @@ -115,12 +116,13 @@ async def start_updates(lines: list[str]):
tasks.append(asyncio.create_task(update(package_name, line_no)))

line_no += 1

line_count = line_no

for task in tasks:
await task


def update_packages():
"""
If calling from a python file, please use a subprocess instead.
Expand All @@ -130,28 +132,29 @@ def update_packages():
global ypkgupgr_outdated

logger.info(f"Starting update. Platform: {sys.platform}")

# Clears the screen.
clear_screen()

progress_ring(progress = 0, intermediate = True)
progress_ring(progress=0, intermediate=True)

print("Getting outdated pip packages...")
logger.info("Getting outdated packages.")

# Runs the pip list --outdated command to get the outdated packages.
outdated_packages = subprocess.check_output([sys.executable, '-m', 'pip', 'list', '--outdated', '--disable-pip-version-check']).decode('utf-8')
outdated_packages = subprocess.check_output(
[sys.executable, '-m', 'pip', 'list', '--outdated', '--disable-pip-version-check']).decode('utf-8')

# Splits the output into lines and ignore the header.
lines = outdated_packages.strip().split('\n')[2:]

# Checks if there are any outdated packages.
if len(lines) <= 0:
progress_ring(progress = 100, complete = True)
progress_ring(progress=100, complete=True)
print("No outdated packages found.")
logger.info("No outdated packages.")
return

outdated_count = len(lines)

logger.info(f"Outdated packages: {lines}")
Expand Down Expand Up @@ -179,10 +182,12 @@ def update_packages():

# Warns the user if ypkgupgr hasn't been updated.
if ypkgupgr_outdated:
print(f'The ypkgupgr package is outdated, and you are using the script. Please use "{sys.executable} -m ypkgupgr" to update it.\n')
print(
f'The ypkgupgr package is outdated, and you are using the script. Please use "{sys.executable} -m ypkgupgr" to update it.\n')
logger.info("ypkgupgr is outdated and the script is used on Windows.")

progress_ring(progress = 100,complete = True)

progress_ring(progress=100, complete=True)


@click.group(context_settings=dict(help_option_names=["-?", "--help"]), invoke_without_command=True)
@click.option('--clear-log', is_flag=True, help='Clear the log file before writing to it.')
Expand All @@ -195,80 +200,82 @@ def update_command(ctx, clear_log, log_debug_var, ignore, unignore, unignore_all
global outdated_count
global ypkgupgr_outdated
global ran_from_script

create_appdata_dirs()

# Log commands are handled in init_logging.
init_logging(clear_log, log_debug_var)

if ran_from_script:
log_info("Running from script.")

if (ctx.invoked_subcommand is not None):
log_info(f"Starting command {ctx.invoked_subcommand}.")
return

log_info(f"Starting command. Options: {clear_log}, {log_debug_var}, {ignore}, {unignore}, {unignore_all_var}")

if (len(ignore) > 0):
ignore_packages(list(ignore))
# ^ ignores everything after --ignore.

if (len(unignore) > 0):
unignore_packages(list(unignore))
# ^ unignores everything after --unignore.

if (unignore_all_var):
actually_unignore_all()

# Return after both ignoring and unignoring packages.
if (len(ignore) > 0 or len(unignore) > 0 or unignore_all_var):
return

update_packages()


@update_command.command(help="Add all packages in the given arguments to the ignored file and exit.")
@click.argument("to_ignore", nargs=-1)
@click.option('--clear-log', is_flag=True, help='Clear the log file before writing to it.')
@click.option('--log-debug', 'log_debug_var', is_flag=True, help='Log debug information.')
def ignore(to_ignore, clear_log, log_debug_var):

init_logging(clear_log, log_debug_var)

if (len(to_ignore) > 0):
ignore_packages(to_ignore)


@update_command.command(help="Remove all packages in the given arguments from the ignored file and exit.")
@click.option('--clear-log', is_flag=True, help='Clear the log file before writing to it.')
@click.option('--log-debug', 'log_debug_var', is_flag=True, help='Log debug information.')
@click.argument("to_unignore", nargs=-1)
def unignore(to_unignore, clear_log, log_debug_var):

init_logging(clear_log, log_debug_var)

if (len(to_unignore) > 0):
unignore_packages(to_unignore)


@update_command.command(help="Clear the ignored file and exit.")
@click.option('--clear-log', is_flag=True, help='Clear the log file before writing to it.')
@click.option('--log-debug', 'log_debug_var', is_flag=True, help='Log debug information.')
def unignore_all(clear_log, log_debug_var):

init_logging(clear_log, log_debug_var)

actually_unignore_all()


@update_command.command(help="Open the logs directory with your default file explorer and exit.")
def open_logs():
click.launch(log_dir)

def run_from_script():

def run_from_script():
"""
Runs update_packages() and sets ran_from_script to True. That contributes to fixing issue #11 of the original repo. (https://github.com/yesseruser/yesserpackageupdater/issues/11)
"""

global ran_from_script

ran_from_script = True

update_command()
update_command()
21 changes: 12 additions & 9 deletions src/ypkgupgr/graphics.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@
import sys
import os
from .logs import log_debug
from .colors import Colors
from .misc import failed, line_length


def clear_screen():
print("\033c", end='')
os.system('cls' if os.name == 'nt' else 'clear')


def progress_ring(progress, complete = False, intermediate = False):
def progress_ring(progress, complete=False, intermediate=False):
"""
Updates Windows Terminal's progress ring.
"""

global outdated_count
global finished_count

# Checks if the user is on Windows. Otherwise the progress string might be printed and would confuse the user on Linux and Mac.
if sys.platform != "win32":
log_debug("Progress ring not shown because platform is not Windows.")
# Checks if the WT_SESSION variable is set to prevent printing on consoles where this isn't supported.
if "WT_SESSION" not in os.environ:
log_debug("Progress ring not shown because WT_SESSION key not present.")
return

# Gets the correct progress ring state.
state = 0
if complete:
Expand All @@ -29,14 +31,15 @@ def progress_ring(progress, complete = False, intermediate = False):
state = 1
else:
state = 2

# Prints the progress string according to https://github.com/MicrosoftDocs/terminal/blob/main/TerminalDocs/tutorials/progress-bar-sequences.md
print(f"{chr(27)}]9;4;{state};{progress}{chr(7)}", end="")

log_debug(f"Progress ring updated with the following data: State: {state}; Progress: {progress}")


def progress_update(line: int, text: str):
for i in range(line_length[line] + 1):
text += " "
print(f"\033[{line};1H" + Colors.RESET + text)
line_length[line] = len(text)
line_length[line] = len(text)

0 comments on commit d2a1fe4

Please sign in to comment.