mirror of https://github.com/borgbase/vorta
Compare commits
27 Commits
d5e5b62bf4
...
37a0d504f8
Author | SHA1 | Date |
---|---|---|
Sam | 37a0d504f8 | |
Manu | 9cabbbd193 | |
Aryaman Sharma | 3268bf1599 | |
Manu | 7642002573 | |
Sam | 58137f004d | |
Sam | 59803e6f18 | |
Sam | ba695dd4d5 | |
yfprojects | 8d4ed3b19d | |
Sam | 73e7d966b0 | |
Sam | bef54e1985 | |
Sam | 65fa36b69a | |
Sam | eee0b42def | |
Sam | 0c3829ce73 | |
Sam | 5f5b4e3739 | |
Sam | f0f33c7e0e | |
Sam | 77f5c33b5a | |
Sam | 2f40b7c405 | |
Sam | a5c6729064 | |
Sam | 1d76358404 | |
Sam | 767dcc126a | |
Sam | 4f03af6675 | |
Sam | d21316b920 | |
Sam | 4b299f9a4c | |
Sam | b4f2e64662 | |
Sam | 5f07abd8d0 | |
Sam | 7b800661c2 | |
Sam | 6abd0f5862 |
|
@ -3,17 +3,21 @@ on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
branch:
|
branch:
|
||||||
description: 'Branch to use for building macOS release'
|
description: 'Branch to use for building release'
|
||||||
required: true
|
required: true
|
||||||
default: 'master'
|
default: 'master'
|
||||||
borg_version:
|
borg_version:
|
||||||
description: 'Borg version to package'
|
description: 'Borg version to package'
|
||||||
required: true
|
required: true
|
||||||
default: '1.2.1'
|
default: '1.2.8'
|
||||||
|
macos_version:
|
||||||
|
description: 'macOS version for building'
|
||||||
|
required: true
|
||||||
|
default: 'macos-11'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: macos-11
|
runs-on: ${{ github.event.inputs.macos_version }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Check out selected branch
|
- name: Check out selected branch
|
||||||
|
|
|
@ -6,10 +6,13 @@ on:
|
||||||
jobs:
|
jobs:
|
||||||
stale:
|
stale:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
issues: write
|
||||||
|
pull-requests: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/stale@v8
|
- uses: actions/stale@v8
|
||||||
with:
|
with:
|
||||||
days-before-issue-stale: 60
|
days-before-issue-stale: 90
|
||||||
days-before-pr-stale: -1
|
days-before-pr-stale: -1
|
||||||
days-before-issue-close: 7
|
days-before-issue-close: 7
|
||||||
# days-before-pr-close: 10
|
# days-before-pr-close: 10
|
|
@ -56,5 +56,44 @@
|
||||||
],
|
],
|
||||||
"tags": ["type:dev", "editor:android-studio", "os:linux"],
|
"tags": ["type:dev", "editor:android-studio", "os:linux"],
|
||||||
"author": "shivansh02"
|
"author": "shivansh02"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Jetbrains IDEs cache, config, path and logs",
|
||||||
|
"slug": "jetbrains",
|
||||||
|
"patterns": [
|
||||||
|
"fm:*/.config/JetBrains",
|
||||||
|
"fm:*/.cache/JetBrains",
|
||||||
|
"fm:*/.local/share/JetBrains"
|
||||||
|
],
|
||||||
|
"tags": ["type:dev", "editor:jetbrains", "os:linux"],
|
||||||
|
"author": "SAMAD101"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "AWS artefacts",
|
||||||
|
"slug": "aws-artefacts",
|
||||||
|
"patterns": [
|
||||||
|
"fm:*/.aws"
|
||||||
|
],
|
||||||
|
"tags": ["type:dev", "cloud:aws", "os:linux", "os:darwin"],
|
||||||
|
"author": "SAMAD101"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Spotify cache and config files",
|
||||||
|
"slug": "spotify",
|
||||||
|
"patterns": [
|
||||||
|
"fm:*/.cache/spotify",
|
||||||
|
"fm:*/.config/spotify"
|
||||||
|
],
|
||||||
|
"tags": ["type:media", "media:spotify", "os:linux"],
|
||||||
|
"author": "SAMAD101"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Docker artefacts",
|
||||||
|
"slug": "docker-artefacts",
|
||||||
|
"patterns": [
|
||||||
|
"fm:*/.docker"
|
||||||
|
],
|
||||||
|
"tags": ["type:dev", "cloud:docker", "os:linux", "os:darwin"],
|
||||||
|
"author": "SAMAD101"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -459,6 +459,7 @@ class VortaScheduler(QtCore.QObject):
|
||||||
Pruning and checking after successful backup.
|
Pruning and checking after successful backup.
|
||||||
"""
|
"""
|
||||||
profile = BackupProfileModel.get(id=profile_id)
|
profile = BackupProfileModel.get(id=profile_id)
|
||||||
|
notifier = VortaNotifications.pick()
|
||||||
logger.info('Doing post-backup jobs for %s', profile.name)
|
logger.info('Doing post-backup jobs for %s', profile.name)
|
||||||
if profile.prune_on:
|
if profile.prune_on:
|
||||||
msg = BorgPruneJob.prepare(profile)
|
msg = BorgPruneJob.prepare(profile)
|
||||||
|
@ -489,6 +490,11 @@ class VortaScheduler(QtCore.QObject):
|
||||||
self.app.jobs_manager.add_job(job)
|
self.app.jobs_manager.add_job(job)
|
||||||
|
|
||||||
logger.info('Finished background task for profile %s', profile.name)
|
logger.info('Finished background task for profile %s', profile.name)
|
||||||
|
notifier.deliver(
|
||||||
|
self.tr('Vorta Backup'),
|
||||||
|
self.tr('Post Backup Tasks successful for %s' % profile.name),
|
||||||
|
level='info',
|
||||||
|
)
|
||||||
|
|
||||||
def remove_job(self, profile_id):
|
def remove_job(self, profile_id):
|
||||||
if profile_id in self.timers:
|
if profile_id in self.timers:
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
from typing import Any, Optional
|
||||||
|
|
||||||
from peewee import Tuple, fn
|
from peewee import SqliteDatabase, Tuple, fn
|
||||||
from playhouse import signals
|
from playhouse import signals
|
||||||
|
|
||||||
from vorta import config
|
from vorta import config
|
||||||
|
@ -28,18 +29,18 @@ SCHEMA_VERSION = 22
|
||||||
|
|
||||||
|
|
||||||
@signals.post_save(sender=SettingsModel)
|
@signals.post_save(sender=SettingsModel)
|
||||||
def setup_autostart(model_class, instance, created):
|
def setup_autostart(model_class, instance, created) -> None:
|
||||||
if instance.key == 'autostart':
|
if instance.key == 'autostart':
|
||||||
open_app_at_startup(instance.value)
|
open_app_at_startup(instance.value)
|
||||||
|
|
||||||
|
|
||||||
def cleanup_db():
|
def cleanup_db() -> None:
|
||||||
# Clean up database
|
# Clean up database
|
||||||
DB.execute_sql("VACUUM")
|
DB.execute_sql("VACUUM")
|
||||||
DB.close()
|
DB.close()
|
||||||
|
|
||||||
|
|
||||||
def init_db(con=None):
|
def init_db(con: Optional[SqliteDatabase] = None) -> None:
|
||||||
if con is not None:
|
if con is not None:
|
||||||
os.umask(0o0077)
|
os.umask(0o0077)
|
||||||
DB.initialize(con)
|
DB.initialize(con)
|
||||||
|
@ -62,12 +63,12 @@ def init_db(con=None):
|
||||||
# Delete old log entries after 6 months.
|
# Delete old log entries after 6 months.
|
||||||
# The last `create` command of each profile must not be deleted
|
# The last `create` command of each profile must not be deleted
|
||||||
# since the scheduler uses it to determine the last backup time.
|
# since the scheduler uses it to determine the last backup time.
|
||||||
last_backups_per_profile = (
|
last_backups_per_profile = Tuple(
|
||||||
EventLogModel.select(EventLogModel.profile, fn.MAX(EventLogModel.start_time))
|
EventLogModel.select(EventLogModel.profile, fn.MAX(EventLogModel.start_time))
|
||||||
.where(EventLogModel.subcommand == 'create')
|
.where(EventLogModel.subcommand == 'create')
|
||||||
.group_by(EventLogModel.profile)
|
.group_by(EventLogModel.profile)
|
||||||
)
|
)
|
||||||
last_scheduled_backups_per_profile = (
|
last_scheduled_backups_per_profile = Tuple(
|
||||||
EventLogModel.select(EventLogModel.profile, fn.MAX(EventLogModel.start_time))
|
EventLogModel.select(EventLogModel.profile, fn.MAX(EventLogModel.start_time))
|
||||||
.where(EventLogModel.subcommand == 'create', EventLogModel.category == 'scheduled')
|
.where(EventLogModel.subcommand == 'create', EventLogModel.category == 'scheduled')
|
||||||
.group_by(EventLogModel.profile)
|
.group_by(EventLogModel.profile)
|
||||||
|
@ -105,7 +106,7 @@ def init_db(con=None):
|
||||||
s.save()
|
s.save()
|
||||||
|
|
||||||
|
|
||||||
def backup_current_db(schema_version):
|
def backup_current_db(schema_version: Any) -> None:
|
||||||
"""
|
"""
|
||||||
Creates a backup copy of settings.db
|
Creates a backup copy of settings.db
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
import peewee as pw
|
import peewee as pw
|
||||||
|
from peewee import SqliteDatabase
|
||||||
from playhouse.migrate import SqliteMigrator, migrate
|
from playhouse.migrate import SqliteMigrator, migrate
|
||||||
|
|
||||||
from .models import (
|
from .models import (
|
||||||
|
@ -9,13 +11,14 @@ from .models import (
|
||||||
BackupProfileModel,
|
BackupProfileModel,
|
||||||
EventLogModel,
|
EventLogModel,
|
||||||
RepoModel,
|
RepoModel,
|
||||||
|
SchemaVersion,
|
||||||
SettingsModel,
|
SettingsModel,
|
||||||
SourceFileModel,
|
SourceFileModel,
|
||||||
WifiSettingModel,
|
WifiSettingModel,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def run_migrations(current_schema, db_connection):
|
def run_migrations(current_schema: SchemaVersion, db_connection: SqliteDatabase):
|
||||||
"""
|
"""
|
||||||
Apply new schema versions to database.
|
Apply new schema versions to database.
|
||||||
|
|
||||||
|
@ -251,7 +254,7 @@ def run_migrations(current_schema, db_connection):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _apply_schema_update(current_schema, version_after, *operations):
|
def _apply_schema_update(current_schema: Any, version_after: int, *operations) -> None:
|
||||||
with DB.atomic():
|
with DB.atomic():
|
||||||
migrate(*operations)
|
migrate(*operations)
|
||||||
current_schema.version = version_after
|
current_schema.version = version_after
|
||||||
|
|
|
@ -8,6 +8,7 @@ import json
|
||||||
import logging
|
import logging
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
from typing import Any, Dict, Optional
|
||||||
|
|
||||||
import peewee as pw
|
import peewee as pw
|
||||||
from playhouse import signals
|
from playhouse import signals
|
||||||
|
@ -26,11 +27,11 @@ class JSONField(pw.TextField):
|
||||||
From: https://gist.github.com/rosscdh/f4f26758b0228f475b132c688f15af2b
|
From: https://gist.github.com/rosscdh/f4f26758b0228f475b132c688f15af2b
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def db_value(self, value):
|
def db_value(self, value) -> Optional[str]:
|
||||||
"""Convert the python value for storage in the database."""
|
"""Convert the python value for storage in the database."""
|
||||||
return value if value is None else json.dumps(value)
|
return value if value is None else json.dumps(value)
|
||||||
|
|
||||||
def python_value(self, value):
|
def python_value(self, value) -> Optional[str]:
|
||||||
"""Convert the database value to a pythonic value."""
|
"""Convert the database value to a pythonic value."""
|
||||||
return value if value is None else json.loads(value)
|
return value if value is None else json.loads(value)
|
||||||
|
|
||||||
|
@ -53,7 +54,7 @@ class RepoModel(BaseModel):
|
||||||
create_backup_cmd = pw.CharField(default='')
|
create_backup_cmd = pw.CharField(default='')
|
||||||
extra_borg_arguments = pw.CharField(default='')
|
extra_borg_arguments = pw.CharField(default='')
|
||||||
|
|
||||||
def is_remote_repo(self):
|
def is_remote_repo(self) -> bool:
|
||||||
return not self.url.startswith('/')
|
return not self.url.startswith('/')
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -103,14 +104,14 @@ class BackupProfileModel(BaseModel):
|
||||||
post_backup_cmd = pw.CharField(default='')
|
post_backup_cmd = pw.CharField(default='')
|
||||||
dont_run_on_metered_networks = pw.BooleanField(default=True)
|
dont_run_on_metered_networks = pw.BooleanField(default=True)
|
||||||
|
|
||||||
def refresh(self):
|
def refresh(self) -> None:
|
||||||
return type(self).get(self._pk_expr())
|
return type(self).get(self._pk_expr())
|
||||||
|
|
||||||
def slug(self):
|
def slug(self) -> str:
|
||||||
return slugify(self.name)
|
return slugify(self.name)
|
||||||
|
|
||||||
def get_combined_exclusion_string(self):
|
def get_combined_exclusion_string(self) -> str:
|
||||||
allPresets = get_exclusion_presets()
|
allPresets: Dict[str, Dict[str, Any]] = get_exclusion_presets()
|
||||||
excludes = ""
|
excludes = ""
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
@ -202,7 +203,7 @@ class ArchiveModel(BaseModel):
|
||||||
size = pw.IntegerField(null=True)
|
size = pw.IntegerField(null=True)
|
||||||
trigger = pw.CharField(null=True)
|
trigger = pw.CharField(null=True)
|
||||||
|
|
||||||
def formatted_time(self):
|
def formatted_time(self) -> None:
|
||||||
return
|
return
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -266,5 +267,5 @@ class SettingsModel(BaseModel):
|
||||||
class BackupProfileMixin:
|
class BackupProfileMixin:
|
||||||
"""Extend to support multiple profiles later."""
|
"""Extend to support multiple profiles later."""
|
||||||
|
|
||||||
def profile(self):
|
def profile(self) -> BackupProfileModel:
|
||||||
return BackupProfileModel.get(id=self.window().current_profile.id)
|
return BackupProfileModel.get(id=self.window().current_profile.id)
|
||||||
|
|
Loading…
Reference in New Issue