Compare commits
16 Commits
v0.2.0
...
39f01b266f
| Author | SHA1 | Date | |
|---|---|---|---|
|
39f01b266f
|
|||
|
31c3f7d438
|
|||
| 4ea3b28081 | |||
|
702aa2a75b
|
|||
| 529cd19ec6 | |||
|
fdff738fa7
|
|||
|
7f629fd752
|
|||
|
801c8e24a1
|
|||
| f63ef85dd7 | |||
|
c2013fc205
|
|||
| e5015ec2f3 | |||
|
1163744af9
|
|||
| e3c703aa32 | |||
|
aff319cc5f
|
|||
|
fc8b885214
|
|||
|
7067f0872b
|
45
.gitea/scripts/cleanup_versions.sh
Executable file
45
.gitea/scripts/cleanup_versions.sh
Executable file
@@ -0,0 +1,45 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# cleanup_dev_versions.sh - Delete old PyPI dev versions from Gitea package registry
|
||||||
|
|
||||||
|
# Required environment variables
|
||||||
|
USERNAME="${TWINE_USERNAME}"
|
||||||
|
TOKEN="${TWINE_PASSWORD}"
|
||||||
|
REPO="${GITHUB_REPOSITORY}" # e.g., maxp/repocat
|
||||||
|
API_BASE="${GITHUB_API_URL%/}" # Strip trailing slash if present
|
||||||
|
|
||||||
|
OWNER="${REPO%%/*}"
|
||||||
|
PACKAGE_NAME="${REPO##*/}"
|
||||||
|
API_URL="${API_BASE}/packages/${OWNER}/pypi/${PACKAGE_NAME}"
|
||||||
|
|
||||||
|
# Fetch the list of versions
|
||||||
|
response=$(curl -s -u "$USERNAME:$TOKEN" "$API_URL")
|
||||||
|
|
||||||
|
# Extract all .dev versions, sort by creation time
|
||||||
|
mapfile -t versions_to_delete < <(echo "$response" | jq -r '
|
||||||
|
map(select(.version | test("\\.dev"))) |
|
||||||
|
sort_by(.created_at) |
|
||||||
|
.[0:-1][] |
|
||||||
|
.version')
|
||||||
|
|
||||||
|
# Determine latest version to keep
|
||||||
|
latest_version=$(echo "$response" | jq -r '
|
||||||
|
map(select(.version | test("\\.dev"))) |
|
||||||
|
sort_by(.created_at) |
|
||||||
|
last.version')
|
||||||
|
|
||||||
|
if [[ -z "$latest_version" || ${#versions_to_delete[@]} -eq 0 ]]; then
|
||||||
|
echo "No old .dev versions to delete."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Keeping latest .dev version: $latest_version"
|
||||||
|
|
||||||
|
# Delete old .dev versions
|
||||||
|
for version in "${versions_to_delete[@]}"; do
|
||||||
|
echo "Deleting old .dev version: $version"
|
||||||
|
curl -s -X DELETE -u "$USERNAME:$TOKEN" "$API_URL/$version"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Cleanup complete."
|
||||||
@@ -53,3 +53,10 @@ jobs:
|
|||||||
TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }}
|
TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }}
|
||||||
run: |
|
run: |
|
||||||
poetry run twine upload --repository-url ${{ secrets.TWINE_URL }} dist/*
|
poetry run twine upload --repository-url ${{ secrets.TWINE_URL }} dist/*
|
||||||
|
|
||||||
|
- name: Cleanup old dev versions
|
||||||
|
run: |
|
||||||
|
.gitea/scripts/cleanup_versions.sh '\.dev'
|
||||||
|
env:
|
||||||
|
TWINE_USERNAME: ${{ secrets.TWINE_USERNAME }}
|
||||||
|
TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }}
|
||||||
@@ -1,222 +1,18 @@
|
|||||||
name: Auto Changelog & Release
|
name: Auto Changelog & (Release)
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
- '**'
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
detect-version-change:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
outputs:
|
|
||||||
version_changed: ${{ steps.set.outputs.version_changed }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Check if VERSION file changed
|
|
||||||
if: github.ref == 'refs/heads/main'
|
|
||||||
run: |
|
|
||||||
echo "🔍 Vergleich mit github.event.before:"
|
|
||||||
echo "Before: ${{ github.event.before }}"
|
|
||||||
echo "After: ${{ github.sha }}"
|
|
||||||
|
|
||||||
echo "📄 Changed files between before and after:"
|
|
||||||
git diff --name-only ${{ github.event.before }} ${{ github.sha }} || echo "(diff failed)"
|
|
||||||
|
|
||||||
if git diff --name-only ${{ github.event.before }} ${{ github.sha }} | grep -q '^VERSION$'; then
|
|
||||||
echo "✅ VERSION file was changed"
|
|
||||||
echo "VERSION_CHANGED=true" >> $GITHUB_ENV
|
|
||||||
else
|
|
||||||
echo "ℹ️ VERSION file not changed"
|
|
||||||
echo "VERSION_CHANGED=false" >> $GITHUB_ENV
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Set output (always)
|
|
||||||
id: set
|
|
||||||
run: |
|
|
||||||
echo "version_changed=${VERSION_CHANGED:-false}" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
changelog-only:
|
|
||||||
needs: detect-version-change
|
|
||||||
if: github.ref != 'refs/heads/main' || needs.detect-version-change.outputs.version_changed == 'false'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Set Git Author
|
|
||||||
run: |
|
|
||||||
git config user.name "$CI_COMMIT_AUTHOR_NAME"
|
|
||||||
git config user.email "$CI_COMMIT_AUTHOR_EMAIL"
|
|
||||||
|
|
||||||
- name: Read CLIFF_VERSION from cliff.toml
|
|
||||||
id: cliff_version
|
|
||||||
run: |
|
|
||||||
echo "version=$(awk -F '=' '/^# CLIFF_VERSION=/ { gsub(/[" ]/, "", $2); print $2 }' cliff.toml)" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Restore git-cliff cache
|
|
||||||
id: restore-cliff
|
|
||||||
uses: https://git.0xmax42.io/actions/cache@v1
|
|
||||||
with:
|
|
||||||
key: cargo-cliff-${{ steps.cliff_version.outputs.version }}
|
|
||||||
paths: |
|
|
||||||
/root/.cargo/bin
|
|
||||||
|
|
||||||
- name: Install git-cliff
|
|
||||||
if: steps.restore-cliff.outputs.cache-hit != 'true'
|
|
||||||
run: |
|
|
||||||
cargo install git-cliff --version "${{ steps.cliff_version.outputs.version }}" --features gitea
|
|
||||||
|
|
||||||
- name: Generate unreleased changelog (if file exists or on main)
|
|
||||||
run: |
|
|
||||||
if [[ -f CHANGELOG.md || "${GITHUB_REF##refs/heads/}" == "main" ]]; then
|
|
||||||
echo "Generating CHANGELOG.md..."
|
|
||||||
git-cliff -c cliff.toml -o CHANGELOG.md
|
|
||||||
else
|
|
||||||
echo "CHANGELOG.md does not exist and this is not 'main'. Skipping generation."
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Commit updated CHANGELOG
|
|
||||||
run: |
|
|
||||||
git add CHANGELOG.md
|
|
||||||
if git diff --cached --quiet; then
|
|
||||||
echo "No changes to commit"
|
|
||||||
else
|
|
||||||
git commit -m "chore(changelog): update unreleased changelog"
|
|
||||||
git push origin "${GITHUB_REF##refs/heads/}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
release:
|
release:
|
||||||
needs: detect-version-change
|
|
||||||
if: needs.detect-version-change.outputs.version_changed == 'true' && github.ref == 'refs/heads/main'
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
- name: Release
|
||||||
- name: Set Git Author
|
uses: https://git.0xmax42.io/actions/auto-changelog-release-action@v1
|
||||||
run: |
|
|
||||||
git config user.name "$CI_COMMIT_AUTHOR_NAME"
|
|
||||||
git config user.email "$CI_COMMIT_AUTHOR_EMAIL"
|
|
||||||
|
|
||||||
- name: Read VERSION
|
|
||||||
id: version
|
|
||||||
run: echo "value=$(cat VERSION)" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Read CLIFF_VERSION from cliff.toml
|
|
||||||
id: cliff_version
|
|
||||||
run: |
|
|
||||||
echo "version=$(awk -F '=' '/^# CLIFF_VERSION=/ { gsub(/[" ]/, "", $2); print $2 }' cliff.toml)" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Restore git-cliff cache
|
|
||||||
id: restore-cliff
|
|
||||||
uses: https://git.0xmax42.io/actions/cache@v1
|
|
||||||
with:
|
with:
|
||||||
key: cargo-cliff-${{ steps.cliff_version.outputs.version }}
|
token: ${{ secrets.RELEASE_PUBLISH_TOKEN }}
|
||||||
paths: |
|
|
||||||
/root/.cargo/bin
|
|
||||||
|
|
||||||
- name: Install git-cliff
|
|
||||||
if: steps.restore-cliff.outputs.cache-hit != 'true'
|
|
||||||
run: |
|
|
||||||
cargo install git-cliff --version "${{ steps.cliff_version.outputs.version }}" --features gitea
|
|
||||||
|
|
||||||
- name: Generate changelog for release and tag
|
|
||||||
id: generate-changelog
|
|
||||||
run: |
|
|
||||||
VERSION=${{ steps.version.outputs.value }}
|
|
||||||
git-cliff -c cliff.toml -t "v$VERSION" -o CHANGELOG.md
|
|
||||||
|
|
||||||
BODY=$(mktemp)
|
|
||||||
ESCAPED_VERSION=$(echo "$VERSION" | sed 's/\./\\./g')
|
|
||||||
|
|
||||||
awk -v ver="$ESCAPED_VERSION" '
|
|
||||||
$0 ~ "^## \\[" ver "\\]" {
|
|
||||||
print_flag=1
|
|
||||||
line = $0
|
|
||||||
sub(/^## /, "", line)
|
|
||||||
sub(/\\s*\\(.*\\)/, "", line) # entfernt z. B. "(...)" oder "(*)"
|
|
||||||
print line
|
|
||||||
next
|
|
||||||
}
|
|
||||||
$0 ~ "^## \\[" && $0 !~ "^## \\[" ver "\\]" {
|
|
||||||
print_flag=0
|
|
||||||
}
|
|
||||||
print_flag
|
|
||||||
' CHANGELOG.md > "$BODY"
|
|
||||||
|
|
||||||
echo "changelog_body_path=$BODY" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
|
|
||||||
- name: Commit updated CHANGELOG
|
|
||||||
run: |
|
|
||||||
git add CHANGELOG.md
|
|
||||||
if git diff --cached --quiet; then
|
|
||||||
echo "No changes to commit"
|
|
||||||
else
|
|
||||||
git commit -m "chore(changelog): update changelog for v${{ steps.version.outputs.value }}"
|
|
||||||
git push origin main
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Create Git tag (if not exists)
|
|
||||||
run: |
|
|
||||||
VERSION=${{ steps.version.outputs.value }}
|
|
||||||
if git rev-parse "v$VERSION" >/dev/null 2>&1; then
|
|
||||||
echo "Tag v$VERSION already exists, skipping tag creation."
|
|
||||||
else
|
|
||||||
git tag -a "v$VERSION" -F "${{ steps.generate-changelog.outputs.changelog_body_path }}" --cleanup=verbatim
|
|
||||||
git push origin "v$VERSION"
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Create Gitea release
|
|
||||||
env:
|
|
||||||
RELEASE_PUBLISH_TOKEN: ${{ secrets.RELEASE_PUBLISH_TOKEN }}
|
|
||||||
run: |
|
|
||||||
VERSION=${{ steps.version.outputs.value }}
|
|
||||||
BODY_FILE="${{ steps.generate-changelog.outputs.changelog_body_path }}"
|
|
||||||
|
|
||||||
OWNER=$(echo "$GITHUB_REPOSITORY" | cut -d/ -f1)
|
|
||||||
REPO=$(echo "$GITHUB_REPOSITORY" | cut -d/ -f2)
|
|
||||||
|
|
||||||
# Token-Auswahl
|
|
||||||
TOKEN="${RELEASE_PUBLISH_TOKEN:-$ACTIONS_RUNTIME_TOKEN}"
|
|
||||||
|
|
||||||
if [[ -z "${RELEASE_PUBLISH_TOKEN:-}" ]]; then
|
|
||||||
echo "::warning title=Limited Release Propagation::"
|
|
||||||
echo "RELEASE_PUBLISH_TOKEN is not set. Using ACTIONS_RUNTIME_TOKEN instead."
|
|
||||||
echo "⚠️ Release events may not trigger other workflows if created with the runtime token."
|
|
||||||
echo
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Prüfe, ob der Release schon existiert
|
|
||||||
if curl -sf "$GITHUB_API_URL/repos/$OWNER/$REPO/releases/tags/v$VERSION" \
|
|
||||||
-H "Authorization: token $TOKEN" > /dev/null; then
|
|
||||||
echo "🔁 Release for tag v$VERSION already exists, skipping."
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "🚀 Creating Gitea release for v$VERSION"
|
|
||||||
|
|
||||||
# Release-Beschreibung vorbereiten
|
|
||||||
RELEASE_BODY=$(tail -n +2 "$BODY_FILE" | jq -Rs .)
|
|
||||||
|
|
||||||
curl -X POST "$GITHUB_API_URL/repos/$OWNER/$REPO/releases" \
|
|
||||||
-H "Authorization: token $TOKEN" \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d @- <<EOF
|
|
||||||
{
|
|
||||||
"tag_name": "v$VERSION",
|
|
||||||
"target_commitish": "main",
|
|
||||||
"name": "Release v$VERSION",
|
|
||||||
"body": $RELEASE_BODY,
|
|
||||||
"draft": false,
|
|
||||||
"prerelease": false
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
|
|
||||||
echo "✅ Release for tag $VERSION created successfully."
|
|
||||||
|
|||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,2 +1,3 @@
|
|||||||
*__pycache__*
|
*__pycache__*
|
||||||
dist/
|
dist/
|
||||||
|
**/.env
|
||||||
18
CHANGELOG.md
18
CHANGELOG.md
@@ -2,6 +2,24 @@
|
|||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
## [0.3.0](https://git.0xmax42.io/maxp/repoCat/compare/v0.2.0..v0.3.0) - 2025-11-27
|
||||||
|
|
||||||
|
### 🚀 Features
|
||||||
|
|
||||||
|
- *(clean)* Add snapshot support for volatile repo cleanup - ([7f629fd](https://git.0xmax42.io/maxp/repoCat/commit/7f629fd752d7301c6c84d8227918853dd0538ff5))
|
||||||
|
- *(workflows)* Add cleanup step for old dev versions - ([aff319c](https://git.0xmax42.io/maxp/repoCat/commit/aff319cc5f5c8f954367a6a6b89c84ece6b19f4e))
|
||||||
|
- *(scripts)* Add script to clean old PyPI dev versions - ([fc8b885](https://git.0xmax42.io/maxp/repoCat/commit/fc8b885214b1f5b1d9dcff20612a583aca89f6f9))
|
||||||
|
|
||||||
|
### 📚 Documentation
|
||||||
|
|
||||||
|
- Fix typo in German documentation comment - ([801c8e2](https://git.0xmax42.io/maxp/repoCat/commit/801c8e24a139f36f714bada00e5308efb848d4f4))
|
||||||
|
|
||||||
|
### ⚙️ Miscellaneous Tasks
|
||||||
|
|
||||||
|
- *(scripts)* Update file mode to make script executable - ([c2013fc](https://git.0xmax42.io/maxp/repoCat/commit/c2013fc20538a377fc5de45bd384b6ac438fb61c))
|
||||||
|
- *(scripts)* Rename cleanup script for broader usage - ([1163744](https://git.0xmax42.io/maxp/repoCat/commit/1163744af9a3d908d6e7dbb716818bd67ec76a63))
|
||||||
|
- *(gitignore)* Update ignored files for environment and build - ([7067f08](https://git.0xmax42.io/maxp/repoCat/commit/7067f0872bdd8b456d52b3f9dab4834fd0798977))
|
||||||
|
|
||||||
## [0.2.0](https://git.0xmax42.io/maxp/repoCat/compare/v0.1.0..v0.2.0) - 2025-05-11
|
## [0.2.0](https://git.0xmax42.io/maxp/repoCat/compare/v0.1.0..v0.2.0) - 2025-05-11
|
||||||
|
|
||||||
### 🚀 Features
|
### 🚀 Features
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "repocat"
|
name = "repocat"
|
||||||
version = "0.2.0"
|
version = "0.3.0"
|
||||||
description = ""
|
description = ""
|
||||||
authors = ["Max P. <Mail@MPassarello.de>"]
|
authors = ["Max P. <Mail@MPassarello.de>"]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ def archive_repo(source: Path, target_dir: Path, dry_run: bool) -> Path:
|
|||||||
return archive_path
|
return archive_path
|
||||||
|
|
||||||
with open(archive_path, "wb") as f:
|
with open(archive_path, "wb") as f:
|
||||||
cctx = zstandard.ZstdCompressor(level=20)
|
cctx = zstandard.ZstdCompressor(level=20, threads=-1)
|
||||||
with cctx.stream_writer(f) as compressor:
|
with cctx.stream_writer(f) as compressor:
|
||||||
with tarfile.open(fileobj=compressor, mode="w|") as tar:
|
with tarfile.open(fileobj=compressor, mode="w|") as tar:
|
||||||
tar.add(source, arcname=source.name)
|
tar.add(source, arcname=source.name)
|
||||||
@@ -69,6 +69,9 @@ def run(
|
|||||||
continue
|
continue
|
||||||
if category and cat.config.name not in category:
|
if category and cat.config.name not in category:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
if cat.config.days == 0 or cat.config.days is None:
|
||||||
|
continue
|
||||||
|
|
||||||
limit_days = cat.config.days if cat.config.days is not None else older_than
|
limit_days = cat.config.days if cat.config.days is not None else older_than
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ from typer import Typer, Option
|
|||||||
from rich.console import Console
|
from rich.console import Console
|
||||||
from rich.table import Table
|
from rich.table import Table
|
||||||
import shutil
|
import shutil
|
||||||
|
import os
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
from repocat.config import load_config
|
from repocat.config import load_config
|
||||||
from repocat.models.catalog import RepoCatalogState
|
from repocat.models.catalog import RepoCatalogState
|
||||||
@@ -21,9 +23,18 @@ def clean_volatile(
|
|||||||
category: list[str] = Option(None, "--category", "-c", help="Nur bestimmte Kategorien reinigen", autocompletion=complete_categories),
|
category: list[str] = Option(None, "--category", "-c", help="Nur bestimmte Kategorien reinigen", autocompletion=complete_categories),
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Löscht **bedingungslos** alle Repositories aus `volatile`-Kategorien (z.\u200bB. `scratches`).
|
Löscht **bedingungslos** alle Repositories aus `volatile`-Kategorien (z.B. `scratches`).
|
||||||
"""
|
"""
|
||||||
catalog = RepoCatalogState.from_config(load_config())
|
config = load_config()
|
||||||
|
catalog = RepoCatalogState.from_config(config)
|
||||||
|
|
||||||
|
# Snapshot configuration
|
||||||
|
use_snapshots = config.defaults.snapshots if config.defaults else False
|
||||||
|
snapshot_count = config.defaults.snapshot_count if config.defaults else 5
|
||||||
|
|
||||||
|
snapshot_root = config.base_dir / ".snapshots"
|
||||||
|
timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
|
||||||
|
current_snapshot_dir = snapshot_root / timestamp
|
||||||
|
|
||||||
table = Table(title="Clean – Volatile (Zerstörung)")
|
table = Table(title="Clean – Volatile (Zerstörung)")
|
||||||
table.add_column("Kategorie")
|
table.add_column("Kategorie")
|
||||||
@@ -33,6 +44,7 @@ def clean_volatile(
|
|||||||
|
|
||||||
deleted = 0
|
deleted = 0
|
||||||
skipped = 0
|
skipped = 0
|
||||||
|
snapshotted_categories = set()
|
||||||
|
|
||||||
for cat in catalog.categories:
|
for cat in catalog.categories:
|
||||||
if not cat.config.volatile:
|
if not cat.config.volatile:
|
||||||
@@ -40,23 +52,78 @@ def clean_volatile(
|
|||||||
if category and cat.config.name not in category:
|
if category and cat.config.name not in category:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
for repo in cat.repos:
|
# If snapshots are enabled, we handle the whole category at once
|
||||||
size_mb = repo.size_mb
|
if use_snapshots:
|
||||||
|
if not cat.path.exists():
|
||||||
|
continue
|
||||||
|
|
||||||
if dry_run:
|
if dry_run:
|
||||||
action = "[yellow]Würde löschen[/]"
|
action = f"[yellow]Würde verschieben nach .snapshots/{timestamp}[/]"
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
shutil.rmtree(repo.path)
|
# Create snapshot dir only if we actually have something to move
|
||||||
action = "[red]Gelöscht[/]"
|
if not current_snapshot_dir.exists():
|
||||||
deleted += 1
|
current_snapshot_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
target_dir = current_snapshot_dir / cat.config.subdir
|
||||||
|
# Ensure parent of target exists (if subdir is nested)
|
||||||
|
target_dir.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
# Move the whole category folder
|
||||||
|
# Note: shutil.move(src, dst) where dst does not exist moves src to dst.
|
||||||
|
# If dst exists, it moves src inside dst.
|
||||||
|
# We want to rename cat.path to target_dir.
|
||||||
|
shutil.move(str(cat.path), str(target_dir))
|
||||||
|
|
||||||
|
# Recreate the empty category folder
|
||||||
|
cat.path.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
action = f"[green]Verschoben nach .snapshots/{timestamp}[/]"
|
||||||
|
snapshotted_categories.add(cat.config.name)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
action = f"[red]Fehler: {e}[/]"
|
action = f"[red]Fehler beim Verschieben: {e}[/]"
|
||||||
|
|
||||||
table.add_row(cat.config.name, repo.name, f"{size_mb:.1f}", action)
|
# Add rows for all repos in this category to show what happened to them
|
||||||
|
if cat.repos:
|
||||||
|
for repo in cat.repos:
|
||||||
|
table.add_row(cat.config.name, repo.name, f"{repo.size_mb:.1f}", action)
|
||||||
|
deleted += 1 # Count as "processed/removed from volatile"
|
||||||
|
else:
|
||||||
|
# If no repos but folder existed (and maybe had other files), show a generic row
|
||||||
|
table.add_row(cat.config.name, "(Alle Dateien)", "-", action)
|
||||||
|
|
||||||
|
else:
|
||||||
|
# Old behavior: Delete individual repos
|
||||||
|
for repo in cat.repos:
|
||||||
|
size_mb = repo.size_mb
|
||||||
|
|
||||||
|
if dry_run:
|
||||||
|
action = "[yellow]Würde löschen[/]"
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
shutil.rmtree(repo.path)
|
||||||
|
action = "[red]Gelöscht[/]"
|
||||||
|
deleted += 1
|
||||||
|
except Exception as e:
|
||||||
|
action = f"[red]Fehler: {e}[/]"
|
||||||
|
|
||||||
|
table.add_row(cat.config.name, repo.name, f"{size_mb:.1f}", action)
|
||||||
|
|
||||||
console.print(table)
|
console.print(table)
|
||||||
console.print(f"\n[green]✓ Volatile-Clean abgeschlossen[/] – {deleted} gelöscht, {skipped} übersprungen")
|
|
||||||
|
# Prune old snapshots
|
||||||
|
if use_snapshots and not dry_run and snapshot_root.exists():
|
||||||
|
try:
|
||||||
|
snapshots = sorted([p for p in snapshot_root.iterdir() if p.is_dir()], key=lambda p: p.name)
|
||||||
|
if len(snapshots) > snapshot_count:
|
||||||
|
to_delete = snapshots[:-snapshot_count]
|
||||||
|
for snap in to_delete:
|
||||||
|
shutil.rmtree(snap)
|
||||||
|
console.print(f"[dim]Alte Snapshots bereinigt: {len(to_delete)} gelöscht[/]")
|
||||||
|
except Exception as e:
|
||||||
|
console.print(f"[red]Fehler beim Bereinigen der Snapshots: {e}[/]")
|
||||||
|
|
||||||
|
console.print(f"\n[green]✓ Volatile-Clean abgeschlossen[/] – {deleted} Repositories verarbeitet")
|
||||||
|
|
||||||
|
|
||||||
@app.command()
|
@app.command()
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ class RepoCategory(BaseModel):
|
|||||||
class RepoCatDefaults(BaseModel):
|
class RepoCatDefaults(BaseModel):
|
||||||
dry_run: bool = True
|
dry_run: bool = True
|
||||||
auto_create_directories: bool = True
|
auto_create_directories: bool = True
|
||||||
|
snapshots: bool = False
|
||||||
|
snapshot_count: int = 5
|
||||||
|
|
||||||
class RepoCatConfig(BaseModel):
|
class RepoCatConfig(BaseModel):
|
||||||
base_dir: Path = Field(default=Path("~/Repositories").expanduser())
|
base_dir: Path = Field(default=Path("~/Repositories").expanduser())
|
||||||
|
|||||||
Reference in New Issue
Block a user