Compare commits
28 Commits
14ee5ba856
...
v0.2.0
| Author | SHA1 | Date | |
|---|---|---|---|
| bca361ab95 | |||
| 400db96e3e | |||
| 4250475933 | |||
| 60455082c2 | |||
| 86a64570c5 | |||
|
6d62bcf3ab
|
|||
| 7783f88f0e | |||
| 7ca9442dca | |||
| 2c7fd637ff | |||
| 07550ed290 | |||
| 8d9ae25b26 | |||
| 9f4ff81133 | |||
| c5e6238e77 | |||
| 7644910bf1 | |||
| a4c701df0d | |||
| 539f961f4c | |||
|
c1baccee23
|
|||
|
7806c859fc
|
|||
|
523f23d301
|
|||
|
c730a98168
|
|||
|
c3b1d69416
|
|||
|
a87045e3c6
|
|||
|
e5b1022e0b
|
|||
|
cfed5c4807
|
|||
| 8c54fd318a | |||
| 22f5c05d92 | |||
| 721d96101f | |||
| e061c160fd |
19
.gitea/actions/poetrybuild/action.yaml
Normal file
19
.gitea/actions/poetrybuild/action.yaml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2023 DB Systel GmbH
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
name: "Reusable Poetry build workflow"
|
||||||
|
inputs:
|
||||||
|
poetry_install_args:
|
||||||
|
default: ""
|
||||||
|
description: "Value for additional poetry install arguments"
|
||||||
|
required: false
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: "composite"
|
||||||
|
steps:
|
||||||
|
- name: Install poetry
|
||||||
|
run: pip install poetry
|
||||||
|
- name: Install poetry package
|
||||||
|
run: poetry install --no-interaction ${{ inputs.poetry_install_args }}
|
||||||
|
shell: bash
|
||||||
41
.gitea/workflows/linting.yaml
Normal file
41
.gitea/workflows/linting.yaml
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2023 Max Mehl <https://mehl.mx>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
name: Python Linters
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
pylint:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Install dependencies
|
||||||
|
uses: ./.gitea/actions/poetrybuild
|
||||||
|
- name: Lint with pylint
|
||||||
|
run: poetry run pylint seafile_mirror
|
||||||
|
|
||||||
|
formatting:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Install dependencies
|
||||||
|
uses: ./.gitea/actions/poetrybuild
|
||||||
|
- name: Test formatting with isort and black
|
||||||
|
run: |
|
||||||
|
poetry run isort --check seafile_mirror/
|
||||||
|
poetry run black .
|
||||||
|
|
||||||
|
mypy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Install dependencies
|
||||||
|
uses: ./.gitea/actions/poetrybuild
|
||||||
|
- name: Test typing with mypy
|
||||||
|
run: poetry run mypy
|
||||||
18
.gitea/workflows/publish.yaml
Normal file
18
.gitea/workflows/publish.yaml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2023 Max Mehl <https://mehl.mx>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
name: Python package
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- "v*.*.*"
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Build and publish to PyPI
|
||||||
|
uses: https://github.com/JRubics/poetry-publish@v1.17
|
||||||
|
with:
|
||||||
|
pypi_token: ${{ secrets.PYPI_TOKEN }}
|
||||||
19
.gitea/workflows/reuse.yaml
Normal file
19
.gitea/workflows/reuse.yaml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2023 Max Mehl <https://mehl.mx>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
name: REUSE Compliance
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
reuse:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Check REUSE Compliance
|
||||||
|
uses: https://github.com/fsfe/reuse-action@v2
|
||||||
57
.gitea/workflows/selftests.yaml
Normal file
57
.gitea/workflows/selftests.yaml
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2023 DB Systel GmbH
|
||||||
|
# SPDX-FileCopyrightText: 2023 Max Mehl <https://mehl.mx>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
name: Selftests
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
# Test building the package and installing it via pip3
|
||||||
|
test-build-install:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Install poetry
|
||||||
|
run: pip install poetry
|
||||||
|
- name: Build package
|
||||||
|
run: poetry build
|
||||||
|
- name: Install package
|
||||||
|
run: pip3 install dist/seafile_mirror-*.tar.gz
|
||||||
|
- name: Run package
|
||||||
|
run: |
|
||||||
|
seafile-mirror --version
|
||||||
|
seafile-mirror --help
|
||||||
|
|
||||||
|
# Run tool and sync a test library
|
||||||
|
test-sync:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Install dependencies
|
||||||
|
uses: ./.gitea/actions/poetrybuild
|
||||||
|
# using minimal set of dependencies
|
||||||
|
with:
|
||||||
|
poetry_install_args: "--without dev"
|
||||||
|
- name: Install seaf-cli
|
||||||
|
run: |
|
||||||
|
apt-get update
|
||||||
|
apt-get install -y seafile-cli
|
||||||
|
- name: Configure seaf-cli and start daemon
|
||||||
|
run: |
|
||||||
|
seaf-cli init -d /tmp
|
||||||
|
seaf-cli start
|
||||||
|
- name: Fill configuration for test library
|
||||||
|
run: |
|
||||||
|
sed -i "s|__seafile_server__|${{ secrets.SEAFILE_SERVER }}|" tests/seafile_mirror.conf.yaml
|
||||||
|
sed -i "s|__seafile_user__|${{ secrets.SEAFILE_USER }}|" tests/seafile_mirror.conf.yaml
|
||||||
|
sed -i "s|__seafile_pass__|${{ secrets.SEAFILE_PASS }}|" tests/seafile_mirror.conf.yaml
|
||||||
|
- name: Sync the library
|
||||||
|
run: poetry run seafile-mirror -c tests -v
|
||||||
|
- name: Attempt to find expected string in library
|
||||||
|
run: grep "__ci_test_expect__" tests/ci-test/testfile.txt
|
||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -2,6 +2,10 @@
|
|||||||
#
|
#
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
dist/
|
||||||
|
venv/
|
||||||
.seafile_mirror.db.json
|
.seafile_mirror.db.json
|
||||||
|
/seafile_mirror.conf.yaml
|
||||||
__pycache__/
|
__pycache__/
|
||||||
*.log
|
*.log
|
||||||
|
tests/ci-test/
|
||||||
|
|||||||
41
README.md
41
README.md
@@ -6,6 +6,10 @@ SPDX-License-Identifier: Apache-2.0
|
|||||||
|
|
||||||
# Seafile Mirror
|
# Seafile Mirror
|
||||||
|
|
||||||
|
[](https://api.reuse.software/info/src.mehl.mx/mxmehl/seafile-mirror)
|
||||||
|
[](https://pypi.org/project/seafile-mirror/)
|
||||||
|
[](https://pypi.org/project/seafile-mirror/)
|
||||||
|
|
||||||
A Python tool to handle clean read-only (re-)syncs of
|
A Python tool to handle clean read-only (re-)syncs of
|
||||||
[Seafile](https://www.seafile.com) libraries with the intention to mirror them.
|
[Seafile](https://www.seafile.com) libraries with the intention to mirror them.
|
||||||
|
|
||||||
@@ -39,30 +43,47 @@ Seafile servers!
|
|||||||
## Install
|
## Install
|
||||||
|
|
||||||
The tool depends on the following applications:
|
The tool depends on the following applications:
|
||||||
* `Python 3` and its library `yaml`
|
* `Python 3`
|
||||||
* [`seafile-cli`](https://help.seafile.com/syncing_client/linux-cli/), available e.g. in [Debian](https://packages.debian.org/bullseye/seafile-cli)
|
* [`seafile-cli`](https://help.seafile.com/syncing_client/linux-cli/), available
|
||||||
|
e.g. in [Debian](https://packages.debian.org/bullseye/seafile-cli)
|
||||||
|
|
||||||
You can execute the tool with `python3 seafile_mirror.py`. The `--help` flag
|
You can install the latest release via `pip3 install seafile-mirror`.
|
||||||
informs you about the required and available commands.
|
|
||||||
|
The tool is executable by `seafile-mirror`. The `--help` flag informs you about
|
||||||
|
the required and available commands.
|
||||||
|
|
||||||
There is also an [Ansible
|
There is also an [Ansible
|
||||||
role](https://src.mehl.mx/mxmehl/seafile-mirror-ansible) that takes care of
|
role](https://src.mehl.mx/mxmehl/seafile-mirror-ansible) that takes care of
|
||||||
installing the tool, setting up a systemd service, and running it daily.
|
installing the tool via `pipx`, setting up a systemd service, and running it
|
||||||
|
daily.
|
||||||
|
|
||||||
To keep the Seafile daemon that is required for `seafile-cli` running in the background, check out this [exemplary systemd service](examples/seaf-daemon.service).
|
To keep the Seafile daemon that is required for `seafile-cli` running in the
|
||||||
|
background, check out this [exemplary systemd
|
||||||
|
service](examples/seaf-daemon.service).
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
Configuration is done in a YAML file called `seafile_mirror.conf.yaml`. You can find an example [here](examples/seafile_mirror.conf.yaml).
|
Configuration is done in a YAML file called `seafile_mirror.conf.yaml`. You can
|
||||||
|
find an example [here](examples/seafile_mirror.conf.yaml).
|
||||||
|
|
||||||
If that configuration file resides in the same location as the `seafile_mirror.py` file you are running, you should provide `--configdir ./`.
|
If that configuration file resides in the same location your current working
|
||||||
|
directory, you should provide `--configdir ./`.
|
||||||
|
|
||||||
## Logging and caching
|
## Logging and caching
|
||||||
|
|
||||||
The tool creates `seafile_mirror.log` in addition to the log to the standard
|
The tool creates `seafile_mirror.log` in addition to the log to the standard
|
||||||
output. With `-v` you can print DEBUG messages that will help you in case of
|
output in the configuration directory. With `-v` you can print DEBUG messages
|
||||||
problems.
|
that will help you in case of problems.
|
||||||
|
|
||||||
It also caches the current status of synced libraries and their latest full
|
It also caches the current status of synced libraries and their latest full
|
||||||
download in the file `.seafile_mirror.db.json`. Do not delete this file unless
|
download in the file `.seafile_mirror.db.json`. Do not delete this file unless
|
||||||
you don't mind that the tool will re-sync all libraries in the next run.
|
you don't mind that the tool will re-sync all libraries in the next run.
|
||||||
|
|
||||||
|
## Contribute and Development
|
||||||
|
|
||||||
|
Contributions are welcome! The development is easiest with `poetry`: `poetry
|
||||||
|
install` and `poetry run seafile-mirror` will get you started.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Apache-2.0, Copyright Max Mehl
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
# SPDX-FileCopyrightText: 2023 Max Mehl <https://mehl.mx>
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
434
poetry.lock
generated
Normal file
434
poetry.lock
generated
Normal file
@@ -0,0 +1,434 @@
|
|||||||
|
# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand.
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "astroid"
|
||||||
|
version = "3.0.2"
|
||||||
|
description = "An abstract syntax tree for Python with inference support."
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8.0"
|
||||||
|
files = [
|
||||||
|
{file = "astroid-3.0.2-py3-none-any.whl", hash = "sha256:d6e62862355f60e716164082d6b4b041d38e2a8cf1c7cd953ded5108bac8ff5c"},
|
||||||
|
{file = "astroid-3.0.2.tar.gz", hash = "sha256:4a61cf0a59097c7bb52689b0fd63717cd2a8a14dc9f1eee97b82d814881c8c91"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""}
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "black"
|
||||||
|
version = "23.12.1"
|
||||||
|
description = "The uncompromising code formatter."
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "black-23.12.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e0aaf6041986767a5e0ce663c7a2f0e9eaf21e6ff87a5f95cbf3675bfd4c41d2"},
|
||||||
|
{file = "black-23.12.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c88b3711d12905b74206227109272673edce0cb29f27e1385f33b0163c414bba"},
|
||||||
|
{file = "black-23.12.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a920b569dc6b3472513ba6ddea21f440d4b4c699494d2e972a1753cdc25df7b0"},
|
||||||
|
{file = "black-23.12.1-cp310-cp310-win_amd64.whl", hash = "sha256:3fa4be75ef2a6b96ea8d92b1587dd8cb3a35c7e3d51f0738ced0781c3aa3a5a3"},
|
||||||
|
{file = "black-23.12.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8d4df77958a622f9b5a4c96edb4b8c0034f8434032ab11077ec6c56ae9f384ba"},
|
||||||
|
{file = "black-23.12.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:602cfb1196dc692424c70b6507593a2b29aac0547c1be9a1d1365f0d964c353b"},
|
||||||
|
{file = "black-23.12.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c4352800f14be5b4864016882cdba10755bd50805c95f728011bcb47a4afd59"},
|
||||||
|
{file = "black-23.12.1-cp311-cp311-win_amd64.whl", hash = "sha256:0808494f2b2df923ffc5723ed3c7b096bd76341f6213989759287611e9837d50"},
|
||||||
|
{file = "black-23.12.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:25e57fd232a6d6ff3f4478a6fd0580838e47c93c83eaf1ccc92d4faf27112c4e"},
|
||||||
|
{file = "black-23.12.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2d9e13db441c509a3763a7a3d9a49ccc1b4e974a47be4e08ade2a228876500ec"},
|
||||||
|
{file = "black-23.12.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d1bd9c210f8b109b1762ec9fd36592fdd528485aadb3f5849b2740ef17e674e"},
|
||||||
|
{file = "black-23.12.1-cp312-cp312-win_amd64.whl", hash = "sha256:ae76c22bde5cbb6bfd211ec343ded2163bba7883c7bc77f6b756a1049436fbb9"},
|
||||||
|
{file = "black-23.12.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1fa88a0f74e50e4487477bc0bb900c6781dbddfdfa32691e780bf854c3b4a47f"},
|
||||||
|
{file = "black-23.12.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a4d6a9668e45ad99d2f8ec70d5c8c04ef4f32f648ef39048d010b0689832ec6d"},
|
||||||
|
{file = "black-23.12.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b18fb2ae6c4bb63eebe5be6bd869ba2f14fd0259bda7d18a46b764d8fb86298a"},
|
||||||
|
{file = "black-23.12.1-cp38-cp38-win_amd64.whl", hash = "sha256:c04b6d9d20e9c13f43eee8ea87d44156b8505ca8a3c878773f68b4e4812a421e"},
|
||||||
|
{file = "black-23.12.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3e1b38b3135fd4c025c28c55ddfc236b05af657828a8a6abe5deec419a0b7055"},
|
||||||
|
{file = "black-23.12.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4f0031eaa7b921db76decd73636ef3a12c942ed367d8c3841a0739412b260a54"},
|
||||||
|
{file = "black-23.12.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97e56155c6b737854e60a9ab1c598ff2533d57e7506d97af5481141671abf3ea"},
|
||||||
|
{file = "black-23.12.1-cp39-cp39-win_amd64.whl", hash = "sha256:dd15245c8b68fe2b6bd0f32c1556509d11bb33aec9b5d0866dd8e2ed3dba09c2"},
|
||||||
|
{file = "black-23.12.1-py3-none-any.whl", hash = "sha256:78baad24af0f033958cad29731e27363183e140962595def56423e626f4bee3e"},
|
||||||
|
{file = "black-23.12.1.tar.gz", hash = "sha256:4ce3ef14ebe8d9509188014d96af1c456a910d5b5cbf434a09fef7e024b3d0d5"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
click = ">=8.0.0"
|
||||||
|
mypy-extensions = ">=0.4.3"
|
||||||
|
packaging = ">=22.0"
|
||||||
|
pathspec = ">=0.9.0"
|
||||||
|
platformdirs = ">=2"
|
||||||
|
tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
|
||||||
|
typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""}
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
colorama = ["colorama (>=0.4.3)"]
|
||||||
|
d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"]
|
||||||
|
jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
|
||||||
|
uvloop = ["uvloop (>=0.15.2)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "click"
|
||||||
|
version = "8.1.7"
|
||||||
|
description = "Composable command line interface toolkit"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
files = [
|
||||||
|
{file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"},
|
||||||
|
{file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
colorama = {version = "*", markers = "platform_system == \"Windows\""}
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colorama"
|
||||||
|
version = "0.4.6"
|
||||||
|
description = "Cross-platform colored terminal text."
|
||||||
|
optional = false
|
||||||
|
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
|
||||||
|
files = [
|
||||||
|
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
|
||||||
|
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dill"
|
||||||
|
version = "0.3.7"
|
||||||
|
description = "serialize all of Python"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
files = [
|
||||||
|
{file = "dill-0.3.7-py3-none-any.whl", hash = "sha256:76b122c08ef4ce2eedcd4d1abd8e641114bfc6c2867f49f3c41facf65bf19f5e"},
|
||||||
|
{file = "dill-0.3.7.tar.gz", hash = "sha256:cc1c8b182eb3013e24bd475ff2e9295af86c1a38eb1aff128dac8962a9ce3c03"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
graph = ["objgraph (>=1.7.2)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "isort"
|
||||||
|
version = "5.13.2"
|
||||||
|
description = "A Python utility / library to sort Python imports."
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8.0"
|
||||||
|
files = [
|
||||||
|
{file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"},
|
||||||
|
{file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
colors = ["colorama (>=0.4.6)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mccabe"
|
||||||
|
version = "0.7.0"
|
||||||
|
description = "McCabe checker, plugin for flake8"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
files = [
|
||||||
|
{file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"},
|
||||||
|
{file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mypy"
|
||||||
|
version = "1.8.0"
|
||||||
|
description = "Optional static typing for Python"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "mypy-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:485a8942f671120f76afffff70f259e1cd0f0cfe08f81c05d8816d958d4577d3"},
|
||||||
|
{file = "mypy-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:df9824ac11deaf007443e7ed2a4a26bebff98d2bc43c6da21b2b64185da011c4"},
|
||||||
|
{file = "mypy-1.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2afecd6354bbfb6e0160f4e4ad9ba6e4e003b767dd80d85516e71f2e955ab50d"},
|
||||||
|
{file = "mypy-1.8.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8963b83d53ee733a6e4196954502b33567ad07dfd74851f32be18eb932fb1cb9"},
|
||||||
|
{file = "mypy-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:e46f44b54ebddbeedbd3d5b289a893219065ef805d95094d16a0af6630f5d410"},
|
||||||
|
{file = "mypy-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:855fe27b80375e5c5878492f0729540db47b186509c98dae341254c8f45f42ae"},
|
||||||
|
{file = "mypy-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4c886c6cce2d070bd7df4ec4a05a13ee20c0aa60cb587e8d1265b6c03cf91da3"},
|
||||||
|
{file = "mypy-1.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d19c413b3c07cbecf1f991e2221746b0d2a9410b59cb3f4fb9557f0365a1a817"},
|
||||||
|
{file = "mypy-1.8.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9261ed810972061388918c83c3f5cd46079d875026ba97380f3e3978a72f503d"},
|
||||||
|
{file = "mypy-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:51720c776d148bad2372ca21ca29256ed483aa9a4cdefefcef49006dff2a6835"},
|
||||||
|
{file = "mypy-1.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:52825b01f5c4c1c4eb0db253ec09c7aa17e1a7304d247c48b6f3599ef40db8bd"},
|
||||||
|
{file = "mypy-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f5ac9a4eeb1ec0f1ccdc6f326bcdb464de5f80eb07fb38b5ddd7b0de6bc61e55"},
|
||||||
|
{file = "mypy-1.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afe3fe972c645b4632c563d3f3eff1cdca2fa058f730df2b93a35e3b0c538218"},
|
||||||
|
{file = "mypy-1.8.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:42c6680d256ab35637ef88891c6bd02514ccb7e1122133ac96055ff458f93fc3"},
|
||||||
|
{file = "mypy-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:720a5ca70e136b675af3af63db533c1c8c9181314d207568bbe79051f122669e"},
|
||||||
|
{file = "mypy-1.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:028cf9f2cae89e202d7b6593cd98db6759379f17a319b5faf4f9978d7084cdc6"},
|
||||||
|
{file = "mypy-1.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4e6d97288757e1ddba10dd9549ac27982e3e74a49d8d0179fc14d4365c7add66"},
|
||||||
|
{file = "mypy-1.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f1478736fcebb90f97e40aff11a5f253af890c845ee0c850fe80aa060a267c6"},
|
||||||
|
{file = "mypy-1.8.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42419861b43e6962a649068a61f4a4839205a3ef525b858377a960b9e2de6e0d"},
|
||||||
|
{file = "mypy-1.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:2b5b6c721bd4aabaadead3a5e6fa85c11c6c795e0c81a7215776ef8afc66de02"},
|
||||||
|
{file = "mypy-1.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5c1538c38584029352878a0466f03a8ee7547d7bd9f641f57a0f3017a7c905b8"},
|
||||||
|
{file = "mypy-1.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ef4be7baf08a203170f29e89d79064463b7fc7a0908b9d0d5114e8009c3a259"},
|
||||||
|
{file = "mypy-1.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7178def594014aa6c35a8ff411cf37d682f428b3b5617ca79029d8ae72f5402b"},
|
||||||
|
{file = "mypy-1.8.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ab3c84fa13c04aeeeabb2a7f67a25ef5d77ac9d6486ff33ded762ef353aa5592"},
|
||||||
|
{file = "mypy-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:99b00bc72855812a60d253420d8a2eae839b0afa4938f09f4d2aa9bb4654263a"},
|
||||||
|
{file = "mypy-1.8.0-py3-none-any.whl", hash = "sha256:538fd81bb5e430cc1381a443971c0475582ff9f434c16cd46d2c66763ce85d9d"},
|
||||||
|
{file = "mypy-1.8.0.tar.gz", hash = "sha256:6ff8b244d7085a0b425b56d327b480c3b29cafbd2eff27316a004f9a7391ae07"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
mypy-extensions = ">=1.0.0"
|
||||||
|
tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
|
||||||
|
typing-extensions = ">=4.1.0"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
dmypy = ["psutil (>=4.0)"]
|
||||||
|
install-types = ["pip"]
|
||||||
|
mypyc = ["setuptools (>=50)"]
|
||||||
|
reports = ["lxml"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mypy-extensions"
|
||||||
|
version = "1.0.0"
|
||||||
|
description = "Type system extensions for programs checked with the mypy type checker."
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.5"
|
||||||
|
files = [
|
||||||
|
{file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"},
|
||||||
|
{file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "packaging"
|
||||||
|
version = "23.1"
|
||||||
|
description = "Core utilities for Python packages"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
files = [
|
||||||
|
{file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"},
|
||||||
|
{file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pathspec"
|
||||||
|
version = "0.11.2"
|
||||||
|
description = "Utility library for gitignore style pattern matching of file paths."
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
files = [
|
||||||
|
{file = "pathspec-0.11.2-py3-none-any.whl", hash = "sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20"},
|
||||||
|
{file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "platformdirs"
|
||||||
|
version = "3.10.0"
|
||||||
|
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
files = [
|
||||||
|
{file = "platformdirs-3.10.0-py3-none-any.whl", hash = "sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d"},
|
||||||
|
{file = "platformdirs-3.10.0.tar.gz", hash = "sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"]
|
||||||
|
test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pycodestyle"
|
||||||
|
version = "2.11.0"
|
||||||
|
description = "Python style guide checker"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "pycodestyle-2.11.0-py2.py3-none-any.whl", hash = "sha256:5d1013ba8dc7895b548be5afb05740ca82454fd899971563d2ef625d090326f8"},
|
||||||
|
{file = "pycodestyle-2.11.0.tar.gz", hash = "sha256:259bcc17857d8a8b3b4a2327324b79e5f020a13c16074670f9c8c8f872ea76d0"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pydocstyle"
|
||||||
|
version = "6.3.0"
|
||||||
|
description = "Python docstring style checker"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
files = [
|
||||||
|
{file = "pydocstyle-6.3.0-py3-none-any.whl", hash = "sha256:118762d452a49d6b05e194ef344a55822987a462831ade91ec5c06fd2169d019"},
|
||||||
|
{file = "pydocstyle-6.3.0.tar.gz", hash = "sha256:7ce43f0c0ac87b07494eb9c0b462c0b73e6ff276807f204d6b53edc72b7e44e1"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
snowballstemmer = ">=2.2.0"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
toml = ["tomli (>=1.2.3)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pyflakes"
|
||||||
|
version = "3.1.0"
|
||||||
|
description = "passive checker of Python programs"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "pyflakes-3.1.0-py2.py3-none-any.whl", hash = "sha256:4132f6d49cb4dae6819e5379898f2b8cce3c5f23994194c24b77d5da2e36f774"},
|
||||||
|
{file = "pyflakes-3.1.0.tar.gz", hash = "sha256:a0aae034c444db0071aa077972ba4768d40c830d9539fd45bf4cd3f8f6992efc"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pylama"
|
||||||
|
version = "8.4.1"
|
||||||
|
description = "Code audit tool for python"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
files = [
|
||||||
|
{file = "pylama-8.4.1-py3-none-any.whl", hash = "sha256:5bbdbf5b620aba7206d688ed9fc917ecd3d73e15ec1a89647037a09fa3a86e60"},
|
||||||
|
{file = "pylama-8.4.1.tar.gz", hash = "sha256:2d4f7aecfb5b7466216d48610c7d6bad1c3990c29cdd392ad08259b161e486f6"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
mccabe = ">=0.7.0"
|
||||||
|
pycodestyle = ">=2.9.1"
|
||||||
|
pydocstyle = ">=6.1.1"
|
||||||
|
pyflakes = ">=2.5.0"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
all = ["eradicate", "mypy", "pylint", "radon", "vulture"]
|
||||||
|
eradicate = ["eradicate"]
|
||||||
|
mypy = ["mypy"]
|
||||||
|
pylint = ["pylint"]
|
||||||
|
radon = ["radon"]
|
||||||
|
tests = ["eradicate (>=2.0.0)", "mypy", "pylama-quotes", "pylint (>=2.11.1)", "pytest (>=7.1.2)", "pytest-mypy", "radon (>=5.1.0)", "toml", "types-setuptools", "types-toml", "vulture"]
|
||||||
|
toml = ["toml (>=0.10.2)"]
|
||||||
|
vulture = ["vulture"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pylint"
|
||||||
|
version = "3.0.3"
|
||||||
|
description = "python code static checker"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8.0"
|
||||||
|
files = [
|
||||||
|
{file = "pylint-3.0.3-py3-none-any.whl", hash = "sha256:7a1585285aefc5165db81083c3e06363a27448f6b467b3b0f30dbd0ac1f73810"},
|
||||||
|
{file = "pylint-3.0.3.tar.gz", hash = "sha256:58c2398b0301e049609a8429789ec6edf3aabe9b6c5fec916acd18639c16de8b"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
astroid = ">=3.0.1,<=3.1.0-dev0"
|
||||||
|
colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""}
|
||||||
|
dill = [
|
||||||
|
{version = ">=0.2", markers = "python_version < \"3.11\""},
|
||||||
|
{version = ">=0.3.6", markers = "python_version >= \"3.11\""},
|
||||||
|
{version = ">=0.3.7", markers = "python_version >= \"3.12\""},
|
||||||
|
]
|
||||||
|
isort = ">=4.2.5,<5.13.0 || >5.13.0,<6"
|
||||||
|
mccabe = ">=0.6,<0.8"
|
||||||
|
platformdirs = ">=2.2.0"
|
||||||
|
tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
|
||||||
|
tomlkit = ">=0.10.1"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
spelling = ["pyenchant (>=3.2,<4.0)"]
|
||||||
|
testutils = ["gitpython (>3)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pyyaml"
|
||||||
|
version = "6.0.1"
|
||||||
|
description = "YAML parser and emitter for Python"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
files = [
|
||||||
|
{file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"},
|
||||||
|
{file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"},
|
||||||
|
{file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"},
|
||||||
|
{file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"},
|
||||||
|
{file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"},
|
||||||
|
{file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"},
|
||||||
|
{file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"},
|
||||||
|
{file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"},
|
||||||
|
{file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"},
|
||||||
|
{file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"},
|
||||||
|
{file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"},
|
||||||
|
{file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"},
|
||||||
|
{file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"},
|
||||||
|
{file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"},
|
||||||
|
{file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"},
|
||||||
|
{file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"},
|
||||||
|
{file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"},
|
||||||
|
{file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"},
|
||||||
|
{file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"},
|
||||||
|
{file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"},
|
||||||
|
{file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"},
|
||||||
|
{file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"},
|
||||||
|
{file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"},
|
||||||
|
{file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"},
|
||||||
|
{file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"},
|
||||||
|
{file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"},
|
||||||
|
{file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"},
|
||||||
|
{file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"},
|
||||||
|
{file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"},
|
||||||
|
{file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"},
|
||||||
|
{file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"},
|
||||||
|
{file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"},
|
||||||
|
{file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"},
|
||||||
|
{file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"},
|
||||||
|
{file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"},
|
||||||
|
{file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"},
|
||||||
|
{file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"},
|
||||||
|
{file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"},
|
||||||
|
{file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"},
|
||||||
|
{file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"},
|
||||||
|
{file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"},
|
||||||
|
{file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"},
|
||||||
|
{file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"},
|
||||||
|
{file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"},
|
||||||
|
{file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"},
|
||||||
|
{file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"},
|
||||||
|
{file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"},
|
||||||
|
{file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"},
|
||||||
|
{file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"},
|
||||||
|
{file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "snowballstemmer"
|
||||||
|
version = "2.2.0"
|
||||||
|
description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms."
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
files = [
|
||||||
|
{file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"},
|
||||||
|
{file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tomli"
|
||||||
|
version = "2.0.1"
|
||||||
|
description = "A lil' TOML parser"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
files = [
|
||||||
|
{file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
|
||||||
|
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tomlkit"
|
||||||
|
version = "0.12.1"
|
||||||
|
description = "Style preserving TOML library"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
files = [
|
||||||
|
{file = "tomlkit-0.12.1-py3-none-any.whl", hash = "sha256:712cbd236609acc6a3e2e97253dfc52d4c2082982a88f61b640ecf0817eab899"},
|
||||||
|
{file = "tomlkit-0.12.1.tar.gz", hash = "sha256:38e1ff8edb991273ec9f6181244a6a391ac30e9f5098e7535640ea6be97a7c86"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "types-pyyaml"
|
||||||
|
version = "6.0.12.11"
|
||||||
|
description = "Typing stubs for PyYAML"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
files = [
|
||||||
|
{file = "types-PyYAML-6.0.12.11.tar.gz", hash = "sha256:7d340b19ca28cddfdba438ee638cd4084bde213e501a3978738543e27094775b"},
|
||||||
|
{file = "types_PyYAML-6.0.12.11-py3-none-any.whl", hash = "sha256:a461508f3096d1d5810ec5ab95d7eeecb651f3a15b71959999988942063bf01d"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typing-extensions"
|
||||||
|
version = "4.8.0"
|
||||||
|
description = "Backported and Experimental Type Hints for Python 3.8+"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "typing_extensions-4.8.0-py3-none-any.whl", hash = "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0"},
|
||||||
|
{file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
lock-version = "2.0"
|
||||||
|
python-versions = "^3.10"
|
||||||
|
content-hash = "332efc80877eca1b272474c2e628ab22411accbcd37e72188e0e26bd618fba32"
|
||||||
3
poetry.lock.license
Normal file
3
poetry.lock.license
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
SPDX-FileCopyrightText: 2023 Max Mehl <https://mehl.mx>
|
||||||
|
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
43
pyproject.toml
Normal file
43
pyproject.toml
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2023 Max Mehl <https://mehl.mx>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
[tool.poetry]
|
||||||
|
name = "seafile-mirror"
|
||||||
|
version = "0.2.0"
|
||||||
|
description = "Handle clean read-only (re-)syncs of Seafile libraries to mirror them"
|
||||||
|
authors = ["Max Mehl <mail@mehl.mx>"]
|
||||||
|
license = "Apache-2.0"
|
||||||
|
readme = "README.md"
|
||||||
|
repository = "https://src.mehl.mx/mxmehl/seafile-mirror"
|
||||||
|
packages = [{ include = "seafile_mirror" }]
|
||||||
|
|
||||||
|
[tool.poetry.scripts]
|
||||||
|
seafile-mirror = 'seafile_mirror.seafile_mirror:main'
|
||||||
|
|
||||||
|
[tool.poetry.dependencies]
|
||||||
|
python = "^3.10"
|
||||||
|
pyyaml = "^6.0.1"
|
||||||
|
|
||||||
|
[tool.poetry.group.dev.dependencies]
|
||||||
|
pylint = "^3.0.0"
|
||||||
|
isort = "^5.12.0"
|
||||||
|
black = "^23.9.1"
|
||||||
|
mypy = "^1.5.1"
|
||||||
|
pylama = "^8.4.1"
|
||||||
|
types-pyyaml = "^6.0.12.11"
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["poetry-core"]
|
||||||
|
build-backend = "poetry.core.masonry.api"
|
||||||
|
|
||||||
|
# FORMATTING settings
|
||||||
|
[tool.isort]
|
||||||
|
profile = "black"
|
||||||
|
|
||||||
|
[tool.black]
|
||||||
|
line-length = 100
|
||||||
|
|
||||||
|
# MYPY settings
|
||||||
|
[tool.mypy]
|
||||||
|
files = ["seafile_mirror/*.py"]
|
||||||
4
renovate.json5
Normal file
4
renovate.json5
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
$schema: "https://docs.renovatebot.com/renovate-schema.json",
|
||||||
|
extends: ["local>renovate-bot/renovate-config"],
|
||||||
|
}
|
||||||
3
renovate.json5.license
Normal file
3
renovate.json5.license
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
SPDX-FileCopyrightText: 2023 Max Mehl <https://mehl.mx>
|
||||||
|
|
||||||
|
SPDX-License-Identifier: Apache-2.0
|
||||||
10
seafile_mirror/__init__.py
Executable file
10
seafile_mirror/__init__.py
Executable file
@@ -0,0 +1,10 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2023 Max Mehl <https://mehl.mx>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
|
||||||
|
"""Global init file"""
|
||||||
|
|
||||||
|
from importlib.metadata import version
|
||||||
|
|
||||||
|
__version__ = version("seafile-mirror")
|
||||||
@@ -43,9 +43,7 @@ def db_update(dbdict, libid, **kwargs):
|
|||||||
if libid not in dbdict:
|
if libid not in dbdict:
|
||||||
dbdict[libid] = {}
|
dbdict[libid] = {}
|
||||||
for key, value in kwargs.items():
|
for key, value in kwargs.items():
|
||||||
logging.debug(
|
logging.debug("Updating '%s' of library '%s' in in-memory cache dictionary", key, libid)
|
||||||
"Updating '%s' of library '%s' in in-memory cache dictionary", key, libid
|
|
||||||
)
|
|
||||||
dbdict[libid][key] = value
|
dbdict[libid][key] = value
|
||||||
|
|
||||||
db_write(dbdict)
|
db_write(dbdict)
|
||||||
@@ -39,3 +39,14 @@ def findstring(text, string):
|
|||||||
def countlines(string: str) -> int:
|
def countlines(string: str) -> int:
|
||||||
"""Count number of lines in a variable"""
|
"""Count number of lines in a variable"""
|
||||||
return len(string.splitlines())
|
return len(string.splitlines())
|
||||||
|
|
||||||
|
|
||||||
|
def convert_bytes(size):
|
||||||
|
"""Convert bytes to KB, MB etc depending on size"""
|
||||||
|
power = 1024
|
||||||
|
level = 0
|
||||||
|
labels = {0: "B", 1: "KB", 2: "MB", 3: "GB", 4: "TB"}
|
||||||
|
while size > power:
|
||||||
|
size /= power
|
||||||
|
level += 1
|
||||||
|
return f"{round(size, 2)} {labels[level]}"
|
||||||
@@ -10,7 +10,7 @@ import subprocess
|
|||||||
import sys
|
import sys
|
||||||
from time import sleep
|
from time import sleep
|
||||||
|
|
||||||
from .cachedb import db_get_library_key, db_update
|
from ._cachedb import db_get_library_key, db_update
|
||||||
|
|
||||||
# Constants
|
# Constants
|
||||||
# Seafile CLI command
|
# Seafile CLI command
|
||||||
@@ -38,7 +38,7 @@ def sf_runcmd(auth: list, *arguments: str) -> str:
|
|||||||
# check for errors
|
# check for errors
|
||||||
if ret.returncode != 0:
|
if ret.returncode != 0:
|
||||||
logging.error("The command '%s' returned an error: %s", ret.args, ret.stderr)
|
logging.error("The command '%s' returned an error: %s", ret.args, ret.stderr)
|
||||||
return False
|
return ""
|
||||||
|
|
||||||
return ret.stdout.decode("UTF-8")
|
return ret.stdout.decode("UTF-8")
|
||||||
|
|
||||||
@@ -50,20 +50,20 @@ def sf_parse(output: str, fromcommand: str) -> list:
|
|||||||
for lib in output.splitlines()[1:]:
|
for lib in output.splitlines()[1:]:
|
||||||
# If list, split is by " ", and structure is name,id,dir
|
# If list, split is by " ", and structure is name,id,dir
|
||||||
if fromcommand == "list":
|
if fromcommand == "list":
|
||||||
lib = [x.strip() for x in lib.split(" ")]
|
lib_info = [x.strip() for x in lib.split(" ")]
|
||||||
lib = {"name": lib[0], "id": lib[1], "dir": lib[2]}
|
lib_dict = {"name": lib_info[0], "id": lib_info[1], "dir": lib_info[2]}
|
||||||
libs.append(lib)
|
libs.append(lib_dict)
|
||||||
# If status, split is by "\t", and structure is name,status,progress
|
# If status, split is by "\t", and structure is name,status,progress
|
||||||
elif fromcommand == "status":
|
elif fromcommand == "status":
|
||||||
lib_tmp = [x.strip() for x in lib.split("\t")]
|
lib_tmp = [x.strip() for x in lib.split("\t")]
|
||||||
lib = {"name": lib_tmp[0], "status": lib_tmp[1]}
|
lib_dict = {"name": lib_tmp[0], "status": lib_tmp[1]}
|
||||||
# Add progress if it exists
|
# Add progress if it exists
|
||||||
try:
|
try:
|
||||||
lib["progress"] = lib_tmp[2]
|
lib_dict["progress"] = lib_tmp[2]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
lib["progress"] = None
|
lib_dict["progress"] = ""
|
||||||
|
|
||||||
libs.append(lib)
|
libs.append(lib_dict)
|
||||||
|
|
||||||
return libs
|
return libs
|
||||||
|
|
||||||
@@ -71,8 +71,8 @@ def sf_parse(output: str, fromcommand: str) -> list:
|
|||||||
def sf_getstatus(libname: str) -> dict:
|
def sf_getstatus(libname: str) -> dict:
|
||||||
"""Return the current status of a library (name, status, progress)"""
|
"""Return the current status of a library (name, status, progress)"""
|
||||||
# Get output of `status` and parse it
|
# Get output of `status` and parse it
|
||||||
libsstatus = sf_runcmd(None, "status")
|
libsstatus_cmd = sf_runcmd([], "status")
|
||||||
libsstatus = sf_parse(libsstatus, "status")
|
libsstatus = sf_parse(libsstatus_cmd, "status")
|
||||||
|
|
||||||
# In the list of statuses, get the one for the requested library. None if no match
|
# In the list of statuses, get the one for the requested library. None if no match
|
||||||
status = next((item for item in libsstatus if item["name"] == libname), None)
|
status = next((item for item in libsstatus if item["name"] == libname), None)
|
||||||
@@ -140,10 +140,10 @@ def sf_desync_all(cache):
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
def sf_waitforsynced(libname) -> int:
|
def sf_waitforsynced(libname) -> float:
|
||||||
"""Regularly check status of the library that started to sync"""
|
"""Regularly check status of the library that started to sync"""
|
||||||
libsynced = False
|
libsynced = False
|
||||||
syncwaitmins = 0
|
syncwaitmins: float = 0
|
||||||
nostatus, nostatus_limit = 0, 10
|
nostatus, nostatus_limit = 0, 10
|
||||||
while libsynced is not True:
|
while libsynced is not True:
|
||||||
libstatus = sf_getstatus(libname)
|
libstatus = sf_getstatus(libname)
|
||||||
@@ -183,8 +183,8 @@ def sf_waitforsynced(libname) -> int:
|
|||||||
libname,
|
libname,
|
||||||
nostatus_limit,
|
nostatus_limit,
|
||||||
)
|
)
|
||||||
sf_runcmd(None, "stop")
|
sf_runcmd([], "stop")
|
||||||
sf_runcmd(None, "start")
|
sf_runcmd([], "start")
|
||||||
|
|
||||||
# If library not synced yet or no status available, wait
|
# If library not synced yet or no status available, wait
|
||||||
if not libsynced:
|
if not libsynced:
|
||||||
@@ -14,9 +14,10 @@ from time import sleep
|
|||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
from functions.cachedb import db_read
|
from . import __version__
|
||||||
from functions.helpers import findstring, get_lock
|
from ._cachedb import db_read
|
||||||
from functions.seafile import (
|
from ._helpers import convert_bytes, findstring, get_lock
|
||||||
|
from ._seafile import (
|
||||||
sf_bump_cache_status,
|
sf_bump_cache_status,
|
||||||
sf_desync_all,
|
sf_desync_all,
|
||||||
sf_lastsync_old_enough,
|
sf_lastsync_old_enough,
|
||||||
@@ -48,10 +49,18 @@ parser.add_argument(
|
|||||||
default=False,
|
default=False,
|
||||||
help="Print and log DEBUG messages",
|
help="Print and log DEBUG messages",
|
||||||
)
|
)
|
||||||
|
parser.add_argument("--version", action="version", version="%(prog)s " + __version__)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main(): # pylint: disable=too-many-locals, too-many-statements
|
||||||
"""Main function"""
|
"""Main function"""
|
||||||
|
args = parser.parse_args()
|
||||||
|
# Set files depending on configdir
|
||||||
|
configdir = args.configdir.rstrip("/") + "/"
|
||||||
|
configfile = configdir + "seafile_mirror.conf.yaml"
|
||||||
|
cachefile = configdir + ".seafile_mirror.db.json"
|
||||||
|
logfile = configdir + "seafile_mirror.log"
|
||||||
|
|
||||||
# Logging
|
# Logging
|
||||||
log = logging.getLogger()
|
log = logging.getLogger()
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
@@ -86,7 +95,7 @@ def main():
|
|||||||
sf_desync_all(cache)
|
sf_desync_all(cache)
|
||||||
|
|
||||||
# Create list of libraries we handle(d) for final output
|
# Create list of libraries we handle(d) for final output
|
||||||
libsdone = []
|
libsdone = {"libs": [], "bytes": 0, "time": 0}
|
||||||
|
|
||||||
# Go through users in config
|
# Go through users in config
|
||||||
for access in config:
|
for access in config:
|
||||||
@@ -114,16 +123,12 @@ def main():
|
|||||||
libid = lib["id"]
|
libid = lib["id"]
|
||||||
# Set resync interval if there is a lib-specific setting. Otherwise default
|
# Set resync interval if there is a lib-specific setting. Otherwise default
|
||||||
libresyncinterval = (
|
libresyncinterval = (
|
||||||
lib["resync_interval_days"]
|
lib["resync_interval_days"] if "resync_interval_days" in lib else resyncinterval
|
||||||
if "resync_interval_days" in lib
|
|
||||||
else resyncinterval
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Check if last sync of library is older than resync_interval_days
|
# Check if last sync of library is older than resync_interval_days
|
||||||
if sf_lastsync_old_enough(cache, libid, args.force, libresyncinterval):
|
if sf_lastsync_old_enough(cache, libid, args.force, libresyncinterval):
|
||||||
logging.info(
|
logging.info("Starting to re-sync library %s (%s) to %s", libname, libid, libdir)
|
||||||
"Starting to re-sync library %s (%s) to %s", libname, libid, libdir
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
logging.info(
|
logging.info(
|
||||||
"Local mirror of library %s (%s) at %s is still recent enough. Skipping it.",
|
"Local mirror of library %s (%s) at %s is still recent enough. Skipping it.",
|
||||||
@@ -183,22 +188,33 @@ def main():
|
|||||||
)
|
)
|
||||||
sf_runcmd(None, "desync", "-d", libdir)
|
sf_runcmd(None, "desync", "-d", libdir)
|
||||||
|
|
||||||
|
# Get size of directory (libdir) in bytes
|
||||||
|
# Note: this is not fully equivalent with what `du` would show. It's
|
||||||
|
# caused by the fact that `du` considers filesystem block sizes
|
||||||
|
libdirsize = sum(f.stat().st_size for f in libdir.glob("**/*") if f.is_file())
|
||||||
|
|
||||||
# Update libsdone and cache
|
# Update libsdone and cache
|
||||||
libsdone.append(libname)
|
libsdone["libs"].append(libname)
|
||||||
|
libsdone["bytes"] += libdirsize
|
||||||
|
libsdone["time"] += syncduration
|
||||||
sf_bump_cache_status(cache, libid, status="synced", duration=syncduration)
|
sf_bump_cache_status(cache, libid, status="synced", duration=syncduration)
|
||||||
|
|
||||||
logging.info(
|
logging.info(
|
||||||
"Library %s (%s) has been re-synced to %s", libname, libid, libdir
|
"Library %s (%s) has been re-synced to %s. Duration: %s minutes. Size: %s",
|
||||||
|
libname,
|
||||||
|
libid,
|
||||||
|
libdir,
|
||||||
|
round(syncduration),
|
||||||
|
convert_bytes(libdirsize),
|
||||||
)
|
)
|
||||||
|
|
||||||
logging.info("Fully re-synced the following libraries: %s", ", ".join(libsdone))
|
logging.info(
|
||||||
|
"Fully re-synced the following libraries: %s. Total duration: %s minutes. Total size: %s",
|
||||||
|
", ".join(libsdone["libs"]),
|
||||||
|
round(libsdone["time"]),
|
||||||
|
convert_bytes(libsdone["bytes"]),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
args = parser.parse_args()
|
|
||||||
# Set files depending on configdir
|
|
||||||
configdir = args.configdir.rstrip("/") + "/"
|
|
||||||
configfile = configdir + "seafile_mirror.conf.yaml"
|
|
||||||
cachefile = configdir + ".seafile_mirror.db.json"
|
|
||||||
logfile = configdir + "seafile_mirror.log"
|
|
||||||
main()
|
main()
|
||||||
18
tests/seafile_mirror.conf.yaml
Normal file
18
tests/seafile_mirror.conf.yaml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2023 Max Mehl <https://mehl.mx>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
# Configuration file for seafile-mirror which will be filled in and applied in
|
||||||
|
# the CI test
|
||||||
|
- server: __seafile_server__
|
||||||
|
user: __seafile_user__
|
||||||
|
password: __seafile_pass__
|
||||||
|
# The default resync interval
|
||||||
|
resync_interval_days: 7
|
||||||
|
# Define the libraries which shall be synced
|
||||||
|
libs:
|
||||||
|
- name: ci-test
|
||||||
|
# ID of the Seafile library (can be seen in the web UI)
|
||||||
|
id: 558667f5-cee2-443d-8f8e-668e70a23e9f
|
||||||
|
# local directory where the mirror shall be created
|
||||||
|
dir: tests/ci-test
|
||||||
Reference in New Issue
Block a user