django-maintenance-mode icon indicating copy to clipboard operation
django-maintenance-mode copied to clipboard

maintenance_mode_state file always gets deleted under Windows

Open williwacker opened this issue 1 year ago • 3 comments

Python version 3.10

Django version 4.2.0

Package version latest from GIT

Current behavior (bug description) maintenance_mode_state.txt file gets deleted from directory

Expected behavior maintenance_mode_state.txt file should be stay

Problem under Windows is that the atomic mode is not working. Therefore I have added a switch checking for the platform and either using atomic or non_atomic write. In the write_file routine the same problem exists.

Have changed io.py accordingly.

import fsutil
import platform


def read_file(file_path, default_content=""):
    """
    Read file at the specified path.
    If file doesn't exist, it will be created with default-content.
    Returns the file content.
    """
    if not fsutil.exists(file_path):
        fsutil.write_file(file_path, default_content, atomic=False if platform.system() == 'Windows' else True)
    return fsutil.read_file(file_path) or default_content


def write_file(file_path, content):
    """
    Write file at the specified path with content.
    If file exists, it will be overwritten.
    """
    fsutil.write_file(file_path, content, atomic=False if platform.system() == 'Windows' else True)

williwacker avatar Apr 30 '24 15:04 williwacker

@williwacker thank you for reporting this.

Have you the opportunity to debug this problem better? However this seems to be more a python-fsutil issue.

fabiocaccamo avatar Apr 30 '24 15:04 fabiocaccamo

The only thing I could debug was listing the directory files using print() at the end of the "_write_file_atomic" routine, which is called from the "write_file" routine. And after calling the "_write_file_atomic" routine the file is gone from the directory.

def _write_file_atomic(
    path: PathIn,
    content: str,
    *,
    append: bool = False,
    encoding: str = "utf-8",
) -> None:
    path = _get_path(path)
    mode = "a" if append else "w"
    if append:
        content = read_file(path, encoding=encoding) + content
    dirpath, _ = split_filepath(path)
    try:
        with tempfile.NamedTemporaryFile(
            mode=mode,
            dir=dirpath,
            delete=True,
            encoding=encoding,
        ) as file:
            file.write(content)
            file.flush()
            os.fsync(file.fileno())
            temp_path = file.name
            permissions = get_permissions(path) if exists(path) else None
            os.replace(temp_path, path)
            if permissions:
                set_permissions(path, permissions)
            print('File exists', os.listdir(dirpath))
    except FileNotFoundError:
        # success - the NamedTemporaryFile has not been able
        # to remove the temp file on __exit__ because the temp file
        # has replaced atomically the file at path.
        pass

def write_file(
    path: PathIn,
    content: str,
    *,
    append: bool = False,
    encoding: str = "utf-8",
    atomic: bool = False,
) -> None:
    """
    Write file with the specified content at the given path.
    """
    path = _get_path(path)
    assert_not_dir(path)
    make_dirs_for_file(path)
    write_file_func = _write_file_atomic if atomic else _write_file_non_atomic
    write_file_func(
        path,
        content,
        append=append,
        encoding=encoding,
    )
    print('File is gone', os.listdir(path))

williwacker avatar Apr 30 '24 16:04 williwacker

Could you submit a PR with a failing test case on python-fsutil repo?

The CI runs also on Windows, so the error should be reproducible.

fabiocaccamo avatar Apr 30 '24 16:04 fabiocaccamo