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 os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import eol
|
|
||||||
import cleanup
|
|
||||||
eol.check()
|
|
||||||
cleanup.clean(cleanup.FOLDER_STRUCTURE)
|
|
||||||
|
|
||||||
import nzb2media
|
import nzb2media
|
||||||
from nzb2media import logger, main_db
|
from nzb2media import logger, main_db
|
||||||
from nzb2media.auto_process import comics, games, movies, music, tv, books
|
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
|
pytest tests --doctest-modules --junitxml=junit/test-results.xml
|
||||||
displayName: 'pytest'
|
displayName: 'pytest'
|
||||||
|
|
||||||
- script: |
|
|
||||||
rm -rf .git
|
|
||||||
python cleanup.py
|
|
||||||
python TorrentToMedia.py
|
|
||||||
python nzbToMedia.py
|
|
||||||
displayName: 'Test source install cleanup'
|
|
||||||
|
|
||||||
- task: PublishTestResults@2
|
- task: PublishTestResults@2
|
||||||
inputs:
|
inputs:
|
||||||
testResultsFiles: '**/test-results.xml'
|
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 time
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
import eol
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import win32event
|
import win32event
|
||||||
except ImportError:
|
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):
|
def initialize(section=None):
|
||||||
|
@ -1628,9 +1597,6 @@ def initialize(section=None):
|
||||||
configure_migration()
|
configure_migration()
|
||||||
configure_logging_part_2()
|
configure_logging_part_2()
|
||||||
|
|
||||||
# check python version
|
|
||||||
check_python()
|
|
||||||
|
|
||||||
# initialize the main SB database
|
# initialize the main SB database
|
||||||
main_db.upgrade_database(main_db.DBConnection(), databases.InitialSchema)
|
main_db.upgrade_database(main_db.DBConnection(), databases.InitialSchema)
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,6 @@ import tarfile
|
||||||
import traceback
|
import traceback
|
||||||
from urllib.request import urlretrieve
|
from urllib.request import urlretrieve
|
||||||
|
|
||||||
import cleanup
|
|
||||||
import nzb2media
|
import nzb2media
|
||||||
from nzb2media import github_api as github
|
from nzb2media import github_api as github
|
||||||
from nzb2media import logger
|
from nzb2media import logger
|
||||||
|
@ -79,7 +78,6 @@ class CheckVersion:
|
||||||
def update(self):
|
def update(self):
|
||||||
if self.updater.need_update():
|
if self.updater.need_update():
|
||||||
result = self.updater.update()
|
result = self.updater.update()
|
||||||
cleanup.clean(cleanup.FOLDER_STRUCTURE)
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,6 @@
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import eol
|
|
||||||
import cleanup
|
|
||||||
|
|
||||||
eol.check()
|
|
||||||
cleanup.clean(cleanup.FOLDER_STRUCTURE)
|
|
||||||
|
|
||||||
import nzb2media
|
import nzb2media
|
||||||
from nzb2media import logger
|
from nzb2media import logger
|
||||||
from nzb2media.processor import nzbget, sab, manual
|
from nzb2media.processor import nzbget, sab, manual
|
||||||
|
|
|
@ -53,6 +53,6 @@ include_package_data = true
|
||||||
|
|
||||||
[tool.setuptools.packages.find]
|
[tool.setuptools.packages.find]
|
||||||
where = [""]
|
where = [""]
|
||||||
include = ["core", "libs", "nzbTo*", "TorrentToMedia", "eol", "cleanup"]
|
include = ["nzb2media", "nzbTo*", "TorrentToMedia"]
|
||||||
|
|
||||||
[tool.setuptools_scm]
|
[tool.setuptools_scm]
|
||||||
|
|
|
@ -4,40 +4,6 @@ from __future__ import annotations
|
||||||
import nzb2media
|
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():
|
def test_initial():
|
||||||
nzb2media.initialize()
|
nzb2media.initialize()
|
||||||
del nzb2media.MYAPP
|
del nzb2media.MYAPP
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue