windows running
This commit is contained in:
parent
ddcdcd5647
commit
d1705e3942
6 changed files with 84 additions and 55 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -142,4 +142,6 @@ docker/*.whl
|
||||||
docker/root/*.whl
|
docker/root/*.whl
|
||||||
docker/root/defaults/examples
|
docker/root/defaults/examples
|
||||||
|
|
||||||
.local/
|
.local/
|
||||||
|
|
||||||
|
ffmpeg.exe
|
||||||
|
|
@ -1,11 +1,6 @@
|
||||||
import argparse
|
import argparse
|
||||||
import errno
|
|
||||||
import fcntl
|
|
||||||
import gc
|
import gc
|
||||||
import os
|
|
||||||
import sys
|
import sys
|
||||||
from contextlib import contextmanager
|
|
||||||
from pathlib import Path
|
|
||||||
from typing import List
|
from typing import List
|
||||||
from typing import Tuple
|
from typing import Tuple
|
||||||
|
|
||||||
|
|
@ -13,8 +8,8 @@ from ytdl_sub.cli.download_args_parser import DownloadArgsParser
|
||||||
from ytdl_sub.cli.main_args_parser import parser
|
from ytdl_sub.cli.main_args_parser import parser
|
||||||
from ytdl_sub.config.config_file import ConfigFile
|
from ytdl_sub.config.config_file import ConfigFile
|
||||||
from ytdl_sub.subscriptions.subscription import Subscription
|
from ytdl_sub.subscriptions.subscription import Subscription
|
||||||
from ytdl_sub.utils.exceptions import ValidationException
|
|
||||||
from ytdl_sub.utils.file_handler import FileHandlerTransactionLog
|
from ytdl_sub.utils.file_handler import FileHandlerTransactionLog
|
||||||
|
from ytdl_sub.utils.file_lock import working_directory_lock
|
||||||
from ytdl_sub.utils.logger import Logger
|
from ytdl_sub.utils.logger import Logger
|
||||||
|
|
||||||
logger = Logger.get()
|
logger = Logger.get()
|
||||||
|
|
@ -119,45 +114,6 @@ def _view_url_from_cli(
|
||||||
return subscription, subscription.download(dry_run=True)
|
return subscription, subscription.download(dry_run=True)
|
||||||
|
|
||||||
|
|
||||||
@contextmanager
|
|
||||||
def _working_directory_lock(config: ConfigFile):
|
|
||||||
"""
|
|
||||||
Create and try to lock the file /tmp/working_directory_name
|
|
||||||
|
|
||||||
Raises
|
|
||||||
------
|
|
||||||
ValidationException
|
|
||||||
Lock is acquired from another process running ytdl-sub in the same working directory
|
|
||||||
OSError
|
|
||||||
Other lock error occurred
|
|
||||||
"""
|
|
||||||
working_directory_path = Path(os.getcwd()) / config.config_options.working_directory
|
|
||||||
lock_file_path = (
|
|
||||||
Path(os.getcwd())
|
|
||||||
/ config.config_options.lock_directory
|
|
||||||
/ str(working_directory_path).replace("/", "_")
|
|
||||||
)
|
|
||||||
|
|
||||||
lock_file = open(lock_file_path, "w", encoding="utf-8")
|
|
||||||
|
|
||||||
try:
|
|
||||||
fcntl.lockf(lock_file, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
|
||||||
except OSError as exc:
|
|
||||||
if exc.errno in (errno.EACCES, errno.EAGAIN):
|
|
||||||
raise ValidationException(
|
|
||||||
"Cannot run two instances of ytdl-sub "
|
|
||||||
"with the same working directory at the same time"
|
|
||||||
) from exc
|
|
||||||
lock_file.close()
|
|
||||||
raise exc
|
|
||||||
|
|
||||||
try:
|
|
||||||
yield
|
|
||||||
finally:
|
|
||||||
fcntl.flock(lock_file, fcntl.LOCK_UN)
|
|
||||||
lock_file.close()
|
|
||||||
|
|
||||||
|
|
||||||
def main() -> List[Tuple[Subscription, FileHandlerTransactionLog]]:
|
def main() -> List[Tuple[Subscription, FileHandlerTransactionLog]]:
|
||||||
"""
|
"""
|
||||||
Entrypoint for ytdl-sub, without the error handling
|
Entrypoint for ytdl-sub, without the error handling
|
||||||
|
|
@ -172,7 +128,7 @@ def main() -> List[Tuple[Subscription, FileHandlerTransactionLog]]:
|
||||||
config: ConfigFile = ConfigFile.from_file_path(args.config).initialize()
|
config: ConfigFile = ConfigFile.from_file_path(args.config).initialize()
|
||||||
transaction_logs: List[Tuple[Subscription, FileHandlerTransactionLog]] = []
|
transaction_logs: List[Tuple[Subscription, FileHandlerTransactionLog]] = []
|
||||||
|
|
||||||
with _working_directory_lock(config=config):
|
with working_directory_lock(config=config):
|
||||||
if args.subparser == "sub":
|
if args.subparser == "sub":
|
||||||
transaction_logs = _download_subscriptions_from_yaml_files(config=config, args=args)
|
transaction_logs = _download_subscriptions_from_yaml_files(config=config, args=args)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
@ -26,7 +27,10 @@ class FFMPEG:
|
||||||
@classmethod
|
@classmethod
|
||||||
def _ensure_installed(cls):
|
def _ensure_installed(cls):
|
||||||
try:
|
try:
|
||||||
subprocess.check_output(["which", "ffmpeg"])
|
if sys.platform.startswith("win32"):
|
||||||
|
subprocess.check_output([".\\ffmpeg", "-version"])
|
||||||
|
else:
|
||||||
|
subprocess.check_output(["which", "ffmpeg"])
|
||||||
except subprocess.CalledProcessError as subprocess_error:
|
except subprocess.CalledProcessError as subprocess_error:
|
||||||
raise ValidationException(
|
raise ValidationException(
|
||||||
"Trying to use a feature which requires ffmpeg, but it cannot be found"
|
"Trying to use a feature which requires ffmpeg, but it cannot be found"
|
||||||
|
|
|
||||||
67
src/ytdl_sub/utils/file_lock.py
Normal file
67
src/ytdl_sub/utils/file_lock.py
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
import errno
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from contextlib import contextmanager
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from ytdl_sub.config.config_file import ConfigFile
|
||||||
|
from ytdl_sub.utils.exceptions import ValidationException
|
||||||
|
from ytdl_sub.utils.logger import Logger
|
||||||
|
|
||||||
|
logger = Logger.get()
|
||||||
|
|
||||||
|
|
||||||
|
@contextmanager
|
||||||
|
def _working_directory_lock_unix(config: ConfigFile):
|
||||||
|
"""
|
||||||
|
Create and try to lock the file /tmp/working_directory_name
|
||||||
|
|
||||||
|
Raises
|
||||||
|
------
|
||||||
|
ValidationException
|
||||||
|
Lock is acquired from another process running ytdl-sub in the same working directory
|
||||||
|
OSError
|
||||||
|
Other lock error occurred
|
||||||
|
"""
|
||||||
|
# pylint: disable=import-outside-toplevel
|
||||||
|
import fcntl
|
||||||
|
|
||||||
|
working_directory_path = Path(os.getcwd()) / config.config_options.working_directory
|
||||||
|
lock_file_path = (
|
||||||
|
Path(os.getcwd())
|
||||||
|
/ config.config_options.lock_directory
|
||||||
|
/ str(working_directory_path).replace("/", "_")
|
||||||
|
)
|
||||||
|
|
||||||
|
lock_file = open(lock_file_path, "w", encoding="utf-8")
|
||||||
|
|
||||||
|
try:
|
||||||
|
fcntl.lockf(lock_file, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
||||||
|
except OSError as exc:
|
||||||
|
if exc.errno in (errno.EACCES, errno.EAGAIN):
|
||||||
|
raise ValidationException(
|
||||||
|
"Cannot run two instances of ytdl-sub "
|
||||||
|
"with the same working directory at the same time"
|
||||||
|
) from exc
|
||||||
|
lock_file.close()
|
||||||
|
raise exc
|
||||||
|
|
||||||
|
try:
|
||||||
|
yield
|
||||||
|
finally:
|
||||||
|
fcntl.flock(lock_file, fcntl.LOCK_UN)
|
||||||
|
lock_file.close()
|
||||||
|
|
||||||
|
|
||||||
|
@contextmanager
|
||||||
|
def working_directory_lock(config: ConfigFile):
|
||||||
|
if sys.platform.startswith("win32"):
|
||||||
|
logger.info(
|
||||||
|
"Working directory lock not supported in Windows. "
|
||||||
|
"Ensure only one instance of ytdl-sub runs at once using working directory %s",
|
||||||
|
config.config_options.working_directory,
|
||||||
|
)
|
||||||
|
yield
|
||||||
|
else:
|
||||||
|
with _working_directory_lock_unix(config):
|
||||||
|
yield
|
||||||
|
|
@ -3,9 +3,9 @@ from pathlib import Path
|
||||||
|
|
||||||
REGENERATE_FIXTURES: bool = False
|
REGENERATE_FIXTURES: bool = False
|
||||||
|
|
||||||
RESOURCE_PATH = Path("tests/resources")
|
RESOURCE_PATH: Path = Path("tests") / "resources"
|
||||||
_FILE_FIXTURE_PATH = RESOURCE_PATH / "file_fixtures"
|
_FILE_FIXTURE_PATH: Path = RESOURCE_PATH / "file_fixtures"
|
||||||
|
|
||||||
|
|
||||||
def copy_file_fixture(fixture_name: str, output_file_path: str | Path) -> None:
|
def copy_file_fixture(fixture_name: str, output_file_path: Path) -> None:
|
||||||
shutil.copy(_FILE_FIXTURE_PATH / fixture_name, output_file_path)
|
shutil.copy(_FILE_FIXTURE_PATH / fixture_name, output_file_path)
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,9 @@ import time
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from ytdl_sub.cli.main import _working_directory_lock
|
|
||||||
from ytdl_sub.config.config_file import ConfigFile
|
from ytdl_sub.config.config_file import ConfigFile
|
||||||
from ytdl_sub.utils.exceptions import ValidationException
|
from ytdl_sub.utils.exceptions import ValidationException
|
||||||
|
from ytdl_sub.utils.file_lock import working_directory_lock
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
|
|
@ -18,15 +18,15 @@ def config() -> ConfigFile:
|
||||||
def test_working_directory_lock(config: ConfigFile):
|
def test_working_directory_lock(config: ConfigFile):
|
||||||
new_pid = os.fork()
|
new_pid = os.fork()
|
||||||
if new_pid == 0: # is child
|
if new_pid == 0: # is child
|
||||||
with _working_directory_lock(config=config):
|
with working_directory_lock(config=config):
|
||||||
time.sleep(3)
|
time.sleep(3)
|
||||||
return
|
return
|
||||||
|
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
with pytest.raises(ValidationException, match="Cannot run two instances of ytdl-sub"):
|
with pytest.raises(ValidationException, match="Cannot run two instances of ytdl-sub"):
|
||||||
with _working_directory_lock(config=config):
|
with working_directory_lock(config=config):
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
||||||
time.sleep(3)
|
time.sleep(3)
|
||||||
with _working_directory_lock(config=config):
|
with working_directory_lock(config=config):
|
||||||
pass
|
pass
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue