Compare commits
21 Commits
2a9d0baa6a
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 5978ced62a | |||
| 7a69524e91 | |||
| ffc326a940 | |||
| aea3418854 | |||
| 0dc0e5e135 | |||
| 44902487b0 | |||
| 2147d48f6b | |||
| 450b83c3ef | |||
| 364ee6e066 | |||
| eef8a9cbcb | |||
| 862d8cf5f8 | |||
| 104a6822bc | |||
| 82517a10a7 | |||
| 4d671a283f | |||
| 7b32044803 | |||
| 46e94a5d84 | |||
| 531ea9f1c2 | |||
| 2c735de7e7 | |||
| 4bcca0b832 | |||
| f6034a32fc | |||
| be652dfadd |
2
.github/workflows/sync.yaml
vendored
2
.github/workflows/sync.yaml
vendored
@@ -9,7 +9,7 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
sync-images:
|
sync-images:
|
||||||
runs-on: ubuntu-latest
|
runs-on: [liteyukios-latest]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|||||||
9
dockerfiles/cloudreve-aio.Dockerfile
Normal file
9
dockerfiles/cloudreve-aio.Dockerfile
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
FROM cloudreve/cloudreve:4.0.0-beta.6
|
||||||
|
|
||||||
|
# Install ffmpeg LibreOffice and VIPS
|
||||||
|
|
||||||
|
RUN apk add --no-cache \
|
||||||
|
ffmpeg \
|
||||||
|
libreoffice \
|
||||||
|
vips-tools \
|
||||||
|
&& rm -rf /var/cache/apk/*
|
||||||
@@ -24,4 +24,7 @@ images:
|
|||||||
- "20"
|
- "20"
|
||||||
- "20-slim"
|
- "20-slim"
|
||||||
- "18"
|
- "18"
|
||||||
- "18-slim"
|
- "18-slim"
|
||||||
|
|
||||||
|
- dockerfile: "./dockerfiles/cloudreve-aio.Dockerfile"
|
||||||
|
target: "reg.liteyuki.icu/reedit/cloudreve-aio:latest"
|
||||||
@@ -9,3 +9,9 @@ dependencies = [
|
|||||||
"pydantic>=2.11.3",
|
"pydantic>=2.11.3",
|
||||||
"pyyaml>=6.0.2",
|
"pyyaml>=6.0.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
[[tool.uv.index]]
|
||||||
|
name = "liteyuki"
|
||||||
|
url = "https://git.liteyuki.icu/api/packages/snowykami/pypi/simple"
|
||||||
|
explicit = true
|
||||||
|
|||||||
81
sync.py
81
sync.py
@@ -1,19 +1,20 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
from types import CoroutineType
|
|
||||||
from typing import Any, Awaitable, Callable, Coroutine
|
|
||||||
import aiofiles
|
import aiofiles
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
|
from typing import Any, Callable, Coroutine
|
||||||
|
from functools import partial
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
class Config(BaseModel):
|
class Config(BaseModel):
|
||||||
images: list["Images"] = []
|
images: list["Images"] = []
|
||||||
|
|
||||||
class Images(BaseModel):
|
class Images(BaseModel):
|
||||||
source: str
|
dockerfile: str | None = None
|
||||||
|
source: str | None = None
|
||||||
target: str
|
target: str
|
||||||
tags: list[str] = []
|
tags: list[str] = []
|
||||||
|
|
||||||
|
|
||||||
async def run_command(command: str) -> int | None:
|
async def run_command(command: str) -> int | None:
|
||||||
process = await asyncio.create_subprocess_shell(
|
process = await asyncio.create_subprocess_shell(
|
||||||
command,
|
command,
|
||||||
@@ -28,26 +29,52 @@ async def run_command(command: str) -> int | None:
|
|||||||
print(f"[STDERR]\n{stderr.decode()}")
|
print(f"[STDERR]\n{stderr.decode()}")
|
||||||
|
|
||||||
return process.returncode
|
return process.returncode
|
||||||
|
|
||||||
async def docker_pull(image: str) -> int | None:
|
async def docker_pull(image: str) -> int | None:
|
||||||
print(f"Pulling image {image}...")
|
print(f"Pulling image {image}...")
|
||||||
return await run_command(f"docker pull {image}")
|
return await run_command(f"docker pull {image}")
|
||||||
|
|
||||||
async def docker_tag(source: str, target: str) -> int | None:
|
async def docker_tag(source: str, target: str) -> int | None:
|
||||||
print(f"Tagging image {source} as {target}...")
|
print(f"Tagging image {source} as {target}...")
|
||||||
return await run_command(f"docker tag {source} {target}")
|
return await run_command(f"docker tag {source} {target}")
|
||||||
|
|
||||||
async def docker_push(image: str) -> int | None:
|
async def docker_push(image: str) -> int | None:
|
||||||
print(f"Pushing image {image}...")
|
print(f"Pushing image {image}...")
|
||||||
return await run_command(f"docker push {image}")
|
return await run_command(f"docker push {image}")
|
||||||
|
|
||||||
semaphore = asyncio.Semaphore(5)
|
async def docker_build(dockerfile: str, target: str) -> int | None:
|
||||||
|
print(f"Building image from {dockerfile}...")
|
||||||
|
return await run_command(f"docker build -t {target} -f {dockerfile} .")
|
||||||
|
|
||||||
async def limited_task[T: Any](task: Callable[[], Coroutine[None, None, T]]) -> T:
|
async def docker_sync_task(source: str, target: str) -> int | None:
|
||||||
|
print(f"Pulling image {source}...")
|
||||||
|
if r := await docker_pull(source):
|
||||||
|
if r != 0:
|
||||||
|
return r
|
||||||
|
if r := await docker_tag(source, target):
|
||||||
|
if r != 0:
|
||||||
|
return r
|
||||||
|
if r := await docker_push(target):
|
||||||
|
if r != 0:
|
||||||
|
return r
|
||||||
|
return 0
|
||||||
|
|
||||||
|
async def docker_build_task(dockerfile: str, target: str) -> int | None:
|
||||||
|
print(f"Building image from {dockerfile}...")
|
||||||
|
if r := await docker_build(dockerfile, target):
|
||||||
|
if r != 0:
|
||||||
|
return r
|
||||||
|
if r := await docker_push(target):
|
||||||
|
if r != 0:
|
||||||
|
return r
|
||||||
|
return 0
|
||||||
|
|
||||||
|
semaphore = asyncio.Semaphore(20)
|
||||||
|
|
||||||
|
async def limited_task[T: Any](semaphore: asyncio.Semaphore, task: Callable[[], Coroutine[None, None, T]]) -> T:
|
||||||
async with semaphore:
|
async with semaphore:
|
||||||
return await task()
|
return await task()
|
||||||
|
|
||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
async with aiofiles.open('images.yaml', 'r') as file:
|
async with aiofiles.open('images.yaml', 'r') as file:
|
||||||
config = await file.read()
|
config = await file.read()
|
||||||
@@ -60,28 +87,26 @@ async def main():
|
|||||||
|
|
||||||
tasks = []
|
tasks = []
|
||||||
for image in config.images:
|
for image in config.images:
|
||||||
if len(image.tags) > 0:
|
if image.dockerfile:
|
||||||
|
# 若有dockerfile提供,則使用docker build
|
||||||
|
if len(image.tags) > 0:
|
||||||
|
# 若有tags提供,則使用docker build和docker tag
|
||||||
|
for tag in image.tags:
|
||||||
|
tasks.append(limited_task(semaphore, partial(docker_build_task, image.dockerfile, f"{image.target}:{tag}")))
|
||||||
|
else:
|
||||||
|
tasks.append(limited_task(semaphore, partial(docker_build_task, image.dockerfile, image.target)))
|
||||||
|
elif len(image.tags) > 0:
|
||||||
|
# 若有tags提供,則使用docker pull和docker tag
|
||||||
for tag in image.tags:
|
for tag in image.tags:
|
||||||
async def task() -> int | None:
|
tasks.append(limited_task(semaphore, partial(docker_sync_task, f"{image.source}:{tag}", f"{image.target}:{tag}")))
|
||||||
return (await docker_pull(f"{image.source}:{tag}")) \
|
|
||||||
or (await docker_pull(f"{image.source}:{tag}")) \
|
|
||||||
or (await docker_push(f"{image.target}:{tag}"))
|
|
||||||
tasks.append(limited_task(task))
|
|
||||||
else:
|
else:
|
||||||
async def task() -> int | None:
|
tasks.append(limited_task(semaphore, partial(docker_sync_task, image.source, image.target)))
|
||||||
return (await docker_pull(image.source)) \
|
|
||||||
or (await docker_pull(image.source)) \
|
|
||||||
or (await docker_push(image.target))
|
|
||||||
tasks.append(limited_task(task))
|
|
||||||
|
|
||||||
results = await asyncio.gather(*tasks)
|
results = await asyncio.gather(*tasks)
|
||||||
print(tasks)
|
failed_tasks = sum(1 for result in results if result is not None and result != 0)
|
||||||
failed_tasks = 0
|
|
||||||
for result in results:
|
|
||||||
if result is not None and result != 0:
|
|
||||||
failed_tasks += 1
|
|
||||||
|
|
||||||
print(f"{len(results)} tasks completed. {len(results) - failed_tasks} succeed, {failed_tasks} failed.")
|
print(f"{len(results)} tasks completed. {len(results) - failed_tasks} succeed, {failed_tasks} failed.")
|
||||||
|
if failed_tasks > 0:
|
||||||
|
raise Exception(f"{failed_tasks} tasks failed.")
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
asyncio.run(main())
|
asyncio.run(main())
|
||||||
10
uv.lock
generated
10
uv.lock
generated
@@ -27,6 +27,7 @@ dependencies = [
|
|||||||
{ name = "aiofiles" },
|
{ name = "aiofiles" },
|
||||||
{ name = "pydantic" },
|
{ name = "pydantic" },
|
||||||
{ name = "pyyaml" },
|
{ name = "pyyaml" },
|
||||||
|
{ name = "test-pypi" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.metadata]
|
[package.metadata]
|
||||||
@@ -34,6 +35,7 @@ requires-dist = [
|
|||||||
{ name = "aiofiles", specifier = ">=24.1.0" },
|
{ name = "aiofiles", specifier = ">=24.1.0" },
|
||||||
{ name = "pydantic", specifier = ">=2.11.3" },
|
{ name = "pydantic", specifier = ">=2.11.3" },
|
||||||
{ name = "pyyaml", specifier = ">=6.0.2" },
|
{ name = "pyyaml", specifier = ">=6.0.2" },
|
||||||
|
{ name = "test-pypi", specifier = ">=0.1.1", index = "https://git.liteyuki.icu/api/packages/snowykami/pypi/simple" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -119,6 +121,14 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446 },
|
{ url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446 },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "test-pypi"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = { registry = "https://git.liteyuki.icu/api/packages/snowykami/pypi/simple" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://git.liteyuki.icu/api/packages/snowykami/pypi/files/test-pypi/0.1.1/test_pypi-0.1.1-py3-none-any.whl", hash = "sha256:b34310401079188a6b286cbf95c60c24c5ae950c7682e07cda7259d73c8b3b67" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typing-extensions"
|
name = "typing-extensions"
|
||||||
version = "4.13.2"
|
version = "4.13.2"
|
||||||
|
|||||||
Reference in New Issue
Block a user