Remove eol and cleanup

This commit is contained in:
Labrys of Knossos 2022-12-14 23:15:55 -05:00
commit d50d738cb7
9 changed files with 1 additions and 480 deletions

View file

@ -2,11 +2,6 @@ import datetime
import os
import sys
import eol
import cleanup
eol.check()
cleanup.clean(cleanup.FOLDER_STRUCTURE)
import nzb2media
from nzb2media import logger, main_db
from nzb2media.auto_process import comics, games, movies, music, tv, books

View file

@ -46,13 +46,6 @@ jobs:
pytest tests --doctest-modules --junitxml=junit/test-results.xml
displayName: 'pytest'
- script: |
rm -rf .git
python cleanup.py
python TorrentToMedia.py
python nzbToMedia.py
displayName: 'Test source install cleanup'
- task: PublishTestResults@2
inputs:
testResultsFiles: '**/test-results.xml'

View file

@ -1,207 +0,0 @@
#!/usr/bin/env python
from __future__ import annotations
import os
import shutil
import subprocess
import sys
sys.dont_write_bytecode = True
FOLDER_STRUCTURE = {
'nzb2media': [
'auto_process',
'extractor',
'plugins',
'processor',
'utils',
],
}
class WorkingDirectory:
"""Context manager for changing current working directory."""
def __init__(self, new, original=None):
self.working_directory = new
self.original_directory = os.getcwd() if original is None else original
def __enter__(self):
os.chdir(self.working_directory)
return self
def __exit__(self, exc_type, exc_val, exc_tb):
try:
os.chdir(self.original_directory)
except OSError as error:
print(
'Unable to return to {original_directory}: {error}\n'
'Continuing in {working_directory}'.format(
original_directory=self.original_directory,
error=error,
working_directory=self.working_directory,
),
)
def module_path(module=__file__, parent=False):
"""
Detect path for a module.
:param module: The module who's path is being detected. Defaults to current module.
:param parent: True to return the parent folder of the current module.
:return: The absolute normalized path to the module or its parent.
"""
try:
path = module.__file__
except AttributeError:
path = module
directory = os.path.dirname(path)
if parent:
directory = os.path.join(directory, os.pardir)
absolute = os.path.abspath(directory)
normalized = os.path.normpath(absolute)
return normalized
def git_clean(
remove_directories=False, force=False, dry_run=False, interactive=False, quiet=False, exclude=None,
ignore_rules=False, clean_ignored=False, paths=None,
):
"""Execute git clean commands."""
command = ['git', 'clean']
if remove_directories:
command.append('-d')
if force:
command.append('--force')
if interactive:
command.append('--interactive')
if quiet:
command.append('--quiet')
if dry_run:
command.append('--dry-run')
if exclude:
try:
exclude = exclude.split(' ')
except AttributeError:
pass
for exclusion in exclude:
command.append(f'--exclude={exclusion}')
if ignore_rules:
command.append('-x')
if clean_ignored:
command.append('-X')
if paths:
try:
paths = paths.split(' ')
except AttributeError:
pass
command.extend(paths)
return subprocess.check_output(command)
def clean_bytecode():
"""Clean bytecode files."""
try:
result = git_clean(
remove_directories=True,
force=True,
exclude=[
'*.*', # exclude everything
'!*.py[co]', # except bytecode
'!**/__pycache__/', # and __pycache__ folders
],
)
print(result)
except subprocess.CalledProcessError as error:
sys.exit(f'Error Code: {error.returncode}')
except OSError as error:
sys.exit(f'Error: {error}')
else:
return result
def clean_folders(*paths):
"""Clean obsolete folders."""
try:
result = git_clean(
remove_directories=True,
force=True,
ignore_rules=True,
paths=paths,
)
except subprocess.CalledProcessError as error:
sys.exit(f'Error Code: {error.returncode}')
except OSError as error:
sys.exit(f'Error: {error}')
else:
return result
def force_clean_folder(path, required):
"""
Force clean a folder and exclude any required subfolders.
:param path: Target folder to remove subfolders
:param required: Keep only the required subfolders
"""
root, dirs, files = next(os.walk(path))
required = sorted(required)
if required:
print('Skipping required subfolders', required)
remove = sorted(set(dirs).difference(required))
missing = sorted(set(required).difference(dirs))
for path in remove:
pathname = os.path.join(root, path)
print('Removing', pathname)
shutil.rmtree(pathname)
if missing:
raise Exception('Required subfolders missing:', missing)
def clean(paths):
"""Clean up bytecode and obsolete folders."""
def _report_error(msg):
print('WARNING: Automatic cleanup could not be executed.')
print(' If errors occur, manual cleanup may be required.')
print(f'REASON : {msg}')
with WorkingDirectory(module_path()) as cwd:
if cwd.working_directory != cwd.original_directory:
print('Changing to directory:', cwd.working_directory)
print('\n-- Cleaning bytecode --')
try:
result = clean_bytecode()
except SystemExit as error:
_report_error(error)
else:
print(result or 'No bytecode to clean')
if paths and os.path.exists('.git'):
print(f'\n-- Cleaning folders: {list(paths)} --')
try:
result = clean_folders(*paths)
except SystemExit as error:
_report_error(error)
else:
print(result or 'No folders to clean\n')
else:
print('\nDirectory is not a git repository')
try:
items = paths.items()
except AttributeError:
_report_error('Failed to clean, no subfolder structure given')
else:
for folder, subfolders in items:
print('\nForce cleaning folder:', folder)
force_clean_folder(folder, subfolders)
if cwd.working_directory != cwd.original_directory:
print('Returning to directory: ', cwd.original_directory)
print('\n-- Cleanup finished --\n')
if __name__ == '__main__':
clean(FOLDER_STRUCTURE)

184
eol.py
View file

@ -1,184 +0,0 @@
#!/usr/bin/env python
from __future__ import annotations
import datetime
import sys
import warnings
__version__ = '1.0.0'
def date(string, fmt='%Y-%m-%d'):
"""
Convert date string to date.
:param string: A date string
:param fmt: Format to use when parsing the date string
:return: A datetime.date
"""
return datetime.datetime.strptime(string, fmt).date()
# https://devguide.python.org/
# https://devguide.python.org/devcycle/#devcycle
PYTHON_EOL = {
(3, 11): date('2027-10-1'),
(3, 10): date('2026-10-01'),
(3, 9): date('2025-10-05'),
(3, 8): date('2024-10-14'),
(3, 7): date('2023-06-27'),
(3, 6): date('2021-12-23'),
(3, 5): date('2020-09-13'),
(3, 4): date('2019-03-16'),
(3, 3): date('2017-09-29'),
(3, 2): date('2016-02-20'),
(3, 1): date('2012-04-09'),
(3, 0): date('2009-01-13'),
(2, 7): date('2020-01-01'),
(2, 6): date('2013-10-29'),
}
class Error(Exception):
"""An error has occurred."""
class LifetimeError(Error):
"""Lifetime has been exceeded and upgrade is required."""
class LifetimeWarning(Warning):
"""Lifetime has been exceeded and is no longer supported."""
def lifetime(version=None):
"""
Calculate days left till End-of-Life for a version.
:param version: An optional tuple with version information
If a version is not provided, the current system version will be used.
:return: Days left until End-of-Life
"""
if version is None:
version = sys.version_info
major = version[0]
minor = version[1]
now = datetime.datetime.now().date()
time_left = PYTHON_EOL[(major, minor)] - now
return time_left.days
def expiration(version=None, grace_period=0):
"""
Calculate expiration date for a version given a grace period.
:param version: An optional tuple with version information
If a version is not provided, the current system version will be used.
:param grace_period: An optional number of days grace period
:return: Total days till expiration
"""
days_left = lifetime(version)
return days_left + grace_period
def check(version=None, grace_period=0):
"""
Raise an exception if end of life has been reached and recommend upgrade.
:param version: An optional tuple with version information
If a version is not provided, the current system version will be used.
:param grace_period: An optional number of days grace period
If a grace period is not provided, a default 60 days grace period will
be used.
:return: None
"""
try:
warn_for_status(version, grace_period)
except LifetimeError as error:
print('Please use a newer version of Python.')
print_statuses()
sys.exit(error)
def raise_for_status(version=None, grace_period=0):
"""
Raise an exception if end of life has been reached.
:param version: An optional tuple with version information
If a version is not provided, the current system version will be used.
:param grace_period: An optional number of days grace period
If a grace period is not provided, a default 60 days grace period will
be used.
:return: None
"""
if version is None:
version = sys.version_info
days_left = lifetime(version)
expires = days_left + grace_period
if expires <= 0:
msg = 'Python {major}.{minor} is no longer supported.'.format(
major=version[0],
minor=version[1],
)
raise LifetimeError(msg)
def warn_for_status(version=None, grace_period=0):
"""
Warn if end of life has been reached.
:param version: An optional tuple with version information
If a version is not provided, the current system version will be used.
:param grace_period: An optional number of days grace period
:return: None
"""
if version is None:
version = sys.version_info
days_left = lifetime(version)
expires = days_left + grace_period
if expires <= 0:
msg = 'Python {major}.{minor} is no longer supported.'.format(
major=version[0],
minor=version[1],
)
warnings.warn(msg, LifetimeWarning)
def print_statuses(show_expired=False):
"""
Print end-of-life statuses of known python versions.
:param show_expired: If true also print expired python version statuses
"""
lifetimes = sorted(
(lifetime(python_version), python_version)
for python_version in PYTHON_EOL
)
print('Python End-of-Life for current versions:')
for days_left, python_version in lifetimes:
if days_left >= 0:
print(
'v{major}.{minor} in {remaining:>4} days'.format(
major=python_version[0],
minor=python_version[1],
remaining=days_left,
),
)
if not show_expired:
return
print()
print('Python End-of-Life for expired versions:')
for days_left, python_version in lifetimes:
if days_left < 0:
print(
'v{major}.{minor} {remaining:>4} days ago'.format(
major=python_version[0],
minor=python_version[1],
remaining=-days_left,
),
)
if __name__ == '__main__':
print_statuses(show_expired=True)

View file

@ -11,8 +11,6 @@ import sys
import time
import typing
import eol
try:
import win32event
except ImportError:
@ -1581,35 +1579,6 @@ def configure_utility_locations():
)
def check_python():
"""Check End-of-Life status for Python version."""
# Raise if end of life
eol.check()
# Warn if within grace period
grace_period = 365 # days
eol.warn_for_status(grace_period=-grace_period)
# Log warning if within grace period
days_left = eol.lifetime()
if days_left > 0:
logger.info(
'Python v{major}.{minor} will reach end of life in {x} days.'.format(
major=sys.version_info[0],
minor=sys.version_info[1],
x=days_left,
),
)
else:
logger.info(
'Python v{major}.{minor} reached end of life {x} days ago.'.format(
major=sys.version_info[0],
minor=sys.version_info[1],
x=-days_left,
),
)
if days_left <= grace_period:
logger.warning('Please upgrade to a more recent Python version.')
def initialize(section=None):
@ -1628,9 +1597,6 @@ def initialize(section=None):
configure_migration()
configure_logging_part_2()
# check python version
check_python()
# initialize the main SB database
main_db.upgrade_database(main_db.DBConnection(), databases.InitialSchema)

View file

@ -12,7 +12,6 @@ import tarfile
import traceback
from urllib.request import urlretrieve
import cleanup
import nzb2media
from nzb2media import github_api as github
from nzb2media import logger
@ -79,7 +78,6 @@ class CheckVersion:
def update(self):
if self.updater.need_update():
result = self.updater.update()
cleanup.clean(cleanup.FOLDER_STRUCTURE)
return result

View file

@ -1,12 +1,6 @@
import os
import sys
import eol
import cleanup
eol.check()
cleanup.clean(cleanup.FOLDER_STRUCTURE)
import nzb2media
from nzb2media import logger
from nzb2media.processor import nzbget, sab, manual

View file

@ -53,6 +53,6 @@ include_package_data = true
[tool.setuptools.packages.find]
where = [""]
include = ["core", "libs", "nzbTo*", "TorrentToMedia", "eol", "cleanup"]
include = ["nzb2media", "nzbTo*", "TorrentToMedia"]
[tool.setuptools_scm]

View file

@ -4,40 +4,6 @@ from __future__ import annotations
import nzb2media
def test_eol():
import eol
eol.check()
def test_cleanup():
import cleanup
cleanup.clean(cleanup.FOLDER_STRUCTURE)
def test_import_core():
pass
def test_import_core_auto_process():
pass
def test_import_core_plugins():
pass
def test_import_core_user_scripts():
pass
def test_import_six():
pass
def test_import_core_utils():
pass
def test_initial():
nzb2media.initialize()
del nzb2media.MYAPP