mirror of
https://github.com/clinton-hall/nzbToMedia.git
synced 2025-08-21 05:43:16 -07:00
Merge pull request #1945 from clinton-hall/undying
Remove eol and cleanup
This commit is contained in:
commit
f40837746f
9 changed files with 1 additions and 480 deletions
|
@ -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
|
||||
|
|
|
@ -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'
|
||||
|
|
207
cleanup.py
207
cleanup.py
|
@ -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
184
eol.py
|
@ -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)
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue