-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
33 changed files
with
483 additions
and
90 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
from country_workspace.versioning.management.manager import Manager | ||
|
||
|
||
def run_scripts(): | ||
m = Manager() | ||
m.forward(m.max_version) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
Empty file.
Empty file.
26 changes: 26 additions & 0 deletions
26
src/country_workspace/versioning/management/commands/applyversion.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
from django.core.management.base import BaseCommand, no_translations | ||
|
||
from country_workspace.versioning.management.manager import Manager | ||
|
||
|
||
class Command(BaseCommand): | ||
help = "Creates new version for apps." | ||
|
||
def add_arguments(self, parser): | ||
parser.add_argument("num", nargs="?", help="Specify the version label") | ||
|
||
@no_translations | ||
def handle(self, num, **options): | ||
m = Manager() | ||
if not num: | ||
num = m.max_version | ||
print(f"Available update {m.max_version}") | ||
print(f"Applied update {m.max_applied_version}") | ||
if num == "zero": | ||
m.zero() | ||
else: | ||
num = int(num) | ||
if not num: | ||
num = m.max_applied_version | ||
if num >= m.max_applied_version: | ||
m.forward(num) |
48 changes: 48 additions & 0 deletions
48
src/country_workspace/versioning/management/commands/makeversion.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import re | ||
from pathlib import Path | ||
|
||
from django.core.management.base import BaseCommand, no_translations | ||
from django.utils.timezone import now | ||
|
||
import country_workspace | ||
|
||
VERSION_TEMPLATE = """# Generated by HCW %(version)s on %(timestamp)s | ||
class Version: | ||
operations = [] | ||
""" | ||
|
||
regex = re.compile(r"(\d+).*") | ||
|
||
|
||
def get_version(filename): | ||
if m := regex.match(filename): | ||
return int(m.group(1)) | ||
return None | ||
|
||
|
||
ts = now().strftime("%Y_%m_%d_%H%M%S") | ||
|
||
|
||
class Command(BaseCommand): | ||
help = "Creates new version" | ||
|
||
def add_arguments(self, parser): | ||
parser.add_argument( | ||
"label", | ||
nargs="?", | ||
help="Specify the version label", | ||
) | ||
|
||
@no_translations | ||
def handle(self, label, **options): | ||
folder = Path(__file__).parent.parent.parent / "versions" | ||
last_ver = 0 | ||
for filename in folder.iterdir(): | ||
if ver := get_version(filename.name): | ||
last_ver = max(last_ver, ver) | ||
new_ver = last_ver + 1 | ||
dest_file = folder / "{:>04}_{}.py".format(new_ver, label or ts) | ||
with dest_file.open("w") as f: | ||
f.write(VERSION_TEMPLATE % {"timestamp": ts, "version": country_workspace.VERSION}) | ||
print(f"Created version {dest_file.name}") |
39 changes: 39 additions & 0 deletions
39
src/country_workspace/versioning/management/commands/showversion.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import re | ||
from pathlib import Path | ||
|
||
from django.core.management.base import BaseCommand, no_translations | ||
|
||
from country_workspace.versioning.models import Version | ||
|
||
regex = re.compile(r"(\d+).*") | ||
|
||
|
||
def get_version(filename): | ||
if m := regex.match(filename): | ||
return int(m.group(1)) | ||
return None | ||
|
||
|
||
class Command(BaseCommand): | ||
help = "Creates new version for apps." | ||
|
||
def add_arguments(self, parser): | ||
parser.add_argument( | ||
"num", | ||
nargs="?", | ||
help="Specify the version label", | ||
) | ||
|
||
@no_translations | ||
def handle(self, *app_labels, **options): | ||
folder = Path(__file__).parent.parent.parent / "versions" | ||
existing = {} | ||
applied = list(Version.objects.order_by("name").values_list("name", flat=True)) | ||
for filename in sorted(folder.iterdir()): | ||
if ver := get_version(filename.name): | ||
existing[ver] = filename.name | ||
for filename in existing.values(): | ||
if filename in applied: | ||
print(f"[x] {filename}") | ||
else: | ||
print(f"[ ] {filename}") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import importlib.util | ||
import re | ||
from pathlib import Path | ||
from typing import Callable | ||
|
||
from country_workspace import VERSION | ||
from country_workspace.versioning.models import Version | ||
|
||
regex = re.compile(r"(\d+).*") | ||
default_folder = Path(__file__).parent.parent / "scripts" | ||
|
||
|
||
def get_version(filename): | ||
if m := regex.match(filename): | ||
return int(m.group(1)) | ||
return None | ||
|
||
|
||
def get_funcs(filename: Path, direction: str = "forward"): | ||
if not filename.exists(): # pragma: no cover | ||
raise FileNotFoundError(filename) | ||
spec = importlib.util.spec_from_file_location("version", filename.absolute()) | ||
module = importlib.util.module_from_spec(spec) | ||
spec.loader.exec_module(module) | ||
funcs = [] | ||
for op in module.Version.operations: | ||
if isinstance(op, (list, tuple)): | ||
if direction == "forward": | ||
funcs.append(op[0]) | ||
else: | ||
funcs.append(op[1]) | ||
else: | ||
if direction == "forward": | ||
funcs.append(op) | ||
else: | ||
funcs.append(lambda: True) | ||
|
||
return funcs | ||
|
||
|
||
class Manager: | ||
def __init__(self, folder: Path = default_folder): | ||
self.folder = folder | ||
self.existing = [] | ||
self.applied = list(Version.objects.order_by("name").values_list("name", flat=True)) | ||
self.max_version = 0 | ||
self.max_applied_version = 0 | ||
for applied in self.applied: | ||
self.max_applied_version = max(get_version(applied), self.max_applied_version) | ||
|
||
for filename in sorted(self.folder.iterdir()): | ||
if v := get_version(filename.name): | ||
self.existing.append(filename) | ||
self.max_version = max(self.max_version, v) | ||
|
||
def zero(self): | ||
self.backward(0) | ||
|
||
def forward(self, to_num) -> list[tuple[Path, list[Callable[[None], None]]]]: | ||
print("Upgrading...") | ||
processed = [] | ||
for entry in self.existing: | ||
if get_version(entry.stem) > to_num: | ||
break | ||
if entry.name not in self.applied: | ||
funcs = get_funcs(entry, direction="forward") | ||
print(f" Applying {entry.stem}") | ||
for func in funcs: | ||
func() | ||
Version.objects.create(name=entry.name, version=VERSION) | ||
processed.append((entry, funcs)) | ||
self.applied = list(Version.objects.order_by("name").values_list("name", flat=True)) | ||
return processed | ||
|
||
def backward(self, to_num) -> list[tuple[Path, list[Callable[[None], None]]]]: | ||
print("Downgrading...") | ||
processed = [] | ||
for entry in reversed(self.applied): | ||
if get_version(entry) <= to_num: | ||
break | ||
file_path = Path(self.folder) / entry | ||
funcs = get_funcs(file_path, direction="backward") | ||
print(f" Discharging {file_path.stem}") | ||
for func in funcs: | ||
func() | ||
Version.objects.get(name=file_path.name).delete() | ||
processed.append((entry, funcs)) | ||
self.applied = list(Version.objects.order_by("name").values_list("name", flat=True)) | ||
return processed |
23 changes: 23 additions & 0 deletions
23
src/country_workspace/versioning/migrations/0001_initial.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# Generated by Django 5.1.1 on 2024-10-15 16:45 | ||
|
||
import django.utils.timezone | ||
from django.db import migrations, models | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
initial = True | ||
|
||
dependencies = [] | ||
|
||
operations = [ | ||
migrations.CreateModel( | ||
name="Version", | ||
fields=[ | ||
("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), | ||
("name", models.CharField(max_length=255, unique=True)), | ||
("version", models.CharField(max_length=255)), | ||
("applied", models.DateTimeField(default=django.utils.timezone.now)), | ||
], | ||
), | ||
] |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
from django.db import models | ||
from django.utils.timezone import now | ||
|
||
|
||
class Version(models.Model): | ||
name = models.CharField(max_length=255, unique=True) | ||
version = models.CharField(max_length=255) | ||
applied = models.DateTimeField(default=now) |
Oops, something went wrong.