Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a dev mode that allows for local storing of config files and logs #1682

Merged
merged 32 commits into from
May 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
7bd4900
Add development flag to options.
ratchek Feb 22, 2023
29d7bf2
Add tooltips to settings. (#1521)
real-yfprojects Feb 25, 2023
58d71ac
Fix detecting whether sources are configured (#1613)
diivi Mar 2, 2023
4538ce7
Add a development mode (#1162)
ratchek Mar 3, 2023
5e1b601
Merge branch 'master' into dev_mode
ratchek Mar 16, 2023
fac82a0
Fix before merge
ratchek Mar 17, 2023
4d2f969
Modify the config directory to a hidden directory and add config to t…
ratchek Mar 17, 2023
073e6b1
Merge branch 'master' into dev_mode
ratchek Apr 4, 2023
3ef5e54
Add support for custom dev dirs
ratchek Apr 4, 2023
28d9340
Change the default dev config dir in gitignore
ratchek Apr 4, 2023
2b0b756
Clean up print statements used for debugging
ratchek Apr 4, 2023
097cac7
Add development flag to options.
ratchek Feb 22, 2023
a2d7e75
Change the default dev config dir in gitignore
ratchek Apr 4, 2023
2a21651
Add a development mode (#1162)
ratchek Mar 3, 2023
382eb70
Modify the config directory to a hidden directory and add config to t…
ratchek Mar 17, 2023
e7ba167
Add support for custom dev dirs
ratchek Apr 4, 2023
8e4a5a1
Clean up print statements used for debugging
ratchek Apr 4, 2023
93c2515
Merge branch 'dev_mode' of github.com:ratchek/vorta into dev_mode
ratchek Apr 5, 2023
949da74
Add DEFAULT_DIR_FLAG
ratchek Apr 19, 2023
67ea287
Fix issues as discussed in #1682.
ratchek Apr 19, 2023
f4d57b0
Fix issues as discussed in #1682.
ratchek Apr 19, 2023
2784172
Update logger to import config properly
ratchek Apr 19, 2023
330ca1c
Initialize as system wide when running through application.py
ratchek Apr 19, 2023
8fa0772
Merge upstream
ratchek May 10, 2023
0198ce8
Fix typo and loading config
ratchek May 11, 2023
a3238a4
Initialize config values in config module
ratchek May 11, 2023
5e651ad
Resolve paths when passed to dev mode
ratchek May 11, 2023
5f1d6c7
Shift path resolution to config
ratchek May 12, 2023
3761bcc
Merge branch 'master' into dev_mode
ratchek May 23, 2023
6224e88
Add docstrings and typing
ratchek May 23, 2023
1814782
Merge branch 'master' into dev_mode
ratchek May 29, 2023
b6578e6
Add metavar for better help message
ratchek May 29, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ env
venv
.env
.venv
# dirs created by the --development option
.dev_config/
# Avoid adding translations of source language
# Files are still used by Transifex
src/vorta/i18n/ts/vorta.en.ts
Expand Down
18 changes: 15 additions & 3 deletions src/vorta/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@

from peewee import SqliteDatabase

# Need to import config as a whole module instead of individual variables
# because we will be overriding the modules variables
real-yfprojects marked this conversation as resolved.
Show resolved Hide resolved
from vorta import config
from vorta._version import __version__
from vorta.config import SETTINGS_DIR
from vorta.i18n import trans_late, translate
from vorta.log import init_logger, logger
from vorta.store.connection import init_db
from vorta.updater import get_updater
from vorta.utils import parse_args
from vorta.utils import DEFAULT_DIR_FLAG, parse_args


def main():
Expand Down Expand Up @@ -48,6 +50,7 @@ def exception_handler(type, value, tb):

want_version = getattr(args, 'version', False)
want_background = getattr(args, 'daemonize', False)
want_development = getattr(args, 'development', False)

if want_version:
print(f"Vorta {__version__}") # noqa: T201
Expand All @@ -57,11 +60,20 @@ def exception_handler(type, value, tb):
if os.fork():
sys.exit()

if want_development:
# if we're using the default dev dir
if want_development is DEFAULT_DIR_FLAG:
config.init_dev_mode(config.default_dev_dir())
else:
# if we're not using the default dev dir and
# instead we're using whatever dir is passed as an argument
config.init_dev_mode(want_development)

init_logger(background=want_background)

# Init database
sqlite_db = SqliteDatabase(
SETTINGS_DIR / 'settings.db',
config.SETTINGS_DIR / 'settings.db',
pragmas={
'journal_mode': 'wal',
},
Expand Down
12 changes: 8 additions & 4 deletions src/vorta/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
from PyQt6 import QtCore
from PyQt6.QtWidgets import QMessageBox

from vorta import config
from vorta.borg.break_lock import BorgBreakJob
from vorta.borg.create import BorgCreateJob
from vorta.borg.jobs_manager import JobsManager
from vorta.borg.version import BorgVersionJob
from vorta.config import LOG_DIR, PROFILE_BOOTSTRAP_FILE, TEMP_DIR
from vorta.i18n import init_translations, translate
from vorta.notifications import VortaNotifications
from vorta.profile_export import ProfileExport
Expand All @@ -25,7 +25,7 @@

logger = logging.getLogger(__name__)

APP_ID = TEMP_DIR / "socket"
APP_ID = config.TEMP_DIR / "socket"


class VortaApp(QtSingleApplication):
Expand Down Expand Up @@ -261,7 +261,11 @@ def break_lock(self, profile):
job = BorgBreakJob(params['cmd'], params)
self.jobs_manager.add_job(job)

def bootstrap_profile(self, bootstrap_file=PROFILE_BOOTSTRAP_FILE):
def bootstrap_profile(self, bootstrap_file=None):
# Necessary to dynamically load the variable from config during runtime
# Check out pull request for #1682 for context
ratchek marked this conversation as resolved.
Show resolved Hide resolved
bootstrap_file = bootstrap_file or config.PROFILE_BOOTSTRAP_FILE

"""
Make sure there is at least one profile when first starting Vorta.
Will either import a profile placed in ~/.vorta-init.json
Expand Down Expand Up @@ -334,7 +338,7 @@ def check_failed_response(self, result: Dict[str, Any]):
msg.setIcon(QMessageBox.Icon.Warning)
text = translate(
'VortaApp', 'Borg exited with warning status (rc 1). See the <a href="{0}">logs</a> for details.'
).format(LOG_DIR.as_uri())
).format(config.LOG_DIR.as_uri())
infotext = error_message
elif returncode > 128:
# 128+N - killed by signal N (e.g. 137 == kill -9)
Expand Down
4 changes: 2 additions & 2 deletions src/vorta/borg/check.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Any, Dict

from vorta.config import LOG_DIR
from vorta import config
from vorta.i18n import translate
from vorta.utils import borg_compat

Expand All @@ -27,7 +27,7 @@ def finished_event(self, result: Dict[str, Any]):
self.app.backup_progress_event.emit(
f"[{self.params['profile_name']}] "
+ translate('RepoCheckJob', 'Repo check failed. See the <a href="{0}">logs</a> for details.').format(
LOG_DIR.as_uri()
config.LOG_DIR.as_uri()
)
)
self.app.check_failed_event.emit(result)
Expand Down
4 changes: 2 additions & 2 deletions src/vorta/borg/compact.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Any, Dict

from vorta.config import LOG_DIR
from vorta import config
from vorta.i18n import trans_late, translate
from vorta.utils import borg_compat

Expand Down Expand Up @@ -30,7 +30,7 @@ def finished_event(self, result: Dict[str, Any]):
f"[{self.params['profile_name']}] "
+ translate(
'BorgCompactJob', 'Errors during compaction. See the <a href="{0}">logs</a> for details.'
).format(LOG_DIR.as_uri())
).format(config.LOG_DIR.as_uri())
)
else:
self.app.backup_progress_event.emit(f"[{self.params['profile_name']}] {self.tr('Compaction completed.')}")
Expand Down
4 changes: 2 additions & 2 deletions src/vorta/borg/create.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import tempfile
from datetime import datetime as dt

from vorta.config import LOG_DIR
from vorta import config
from vorta.i18n import trans_late, translate
from vorta.store.models import (
ArchiveModel,
Expand Down Expand Up @@ -46,7 +46,7 @@ def process_result(self, result):
+ translate(
'BorgCreateJob',
'Backup finished with warnings. See the <a href="{0}">logs</a> for details.',
).format(LOG_DIR.as_uri())
).format(config.LOG_DIR.as_uri())
)
else:
self.app.backup_log_event.emit('', {})
Expand Down
61 changes: 52 additions & 9 deletions src/vorta/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,57 @@
APP_NAME = 'Vorta'
APP_AUTHOR = 'BorgBase'
APP_ID_DARWIN = 'com.borgbase.client.macos'
dirs = platformdirs.PlatformDirs(APP_NAME, APP_AUTHOR)
SETTINGS_DIR = dirs.user_data_path
LOG_DIR = dirs.user_log_path
CACHE_DIR = dirs.user_cache_path
TEMP_DIR = CACHE_DIR / "tmp"
PROFILE_BOOTSTRAP_FILE = Path.home() / '.vorta-init.json'
SETTINGS_DIR = None
LOG_DIR = None
CACHE_DIR = None
TEMP_DIR = None
PROFILE_BOOTSTRAP_FILE = None


# ensure directories exist
for dir in (SETTINGS_DIR, LOG_DIR, CACHE_DIR, TEMP_DIR):
dir.mkdir(parents=True, exist_ok=True)
def default_dev_dir() -> Path:
"""Returns a default dir for config files in the project's main folder"""
return Path(__file__).parent.parent.parent / '.dev_config'


def init_from_platformdirs():
"""Initializes config dirs for system-wide use"""
dirs = platformdirs.PlatformDirs(APP_NAME, APP_AUTHOR)
init(dirs.user_data_path, dirs.user_log_path, dirs.user_cache_path, dirs.user_cache_path / 'tmp', Path.home())


def init_dev_mode(dir: Path):
"""Initializes config dirs for local use inside provided dir"""
dir_full_path = Path(dir).resolve()
init(
dir_full_path / 'settings',
dir_full_path / 'logs',
dir_full_path / 'cache',
dir_full_path / 'tmp',
dir_full_path,
)


def init(settings: Path, logs: Path, cache: Path, tmp: Path, bootstrap: Path):
"""Initializes config directories with provided paths"""
global SETTINGS_DIR
global LOG_DIR
global CACHE_DIR
global TEMP_DIR
global PROFILE_BOOTSTRAP_FILE
SETTINGS_DIR = settings
LOG_DIR = logs
CACHE_DIR = cache
TEMP_DIR = tmp
PROFILE_BOOTSTRAP_FILE = bootstrap / '.vorta-init.json'
ensure_dirs()


def ensure_dirs():
"""Creates config dirs and parent dirs if they don't exist"""
# ensure directories exist
for dir in (SETTINGS_DIR, LOG_DIR, CACHE_DIR, TEMP_DIR):
dir.mkdir(parents=True, exist_ok=True)


# Make sure that the config values are valid
init_from_platformdirs()
4 changes: 2 additions & 2 deletions src/vorta/log.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import logging
from logging.handlers import TimedRotatingFileHandler

from .config import LOG_DIR
from vorta import config

logger = logging.getLogger()

Expand All @@ -23,7 +23,7 @@ def init_logger(background=False):
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

# create handlers
fh = TimedRotatingFileHandler(LOG_DIR / 'vorta.log', when='d', interval=1, backupCount=5)
fh = TimedRotatingFileHandler(config.LOG_DIR / 'vorta.log', when='d', interval=1, backupCount=5)
fh.setLevel(logging.DEBUG)
fh.setFormatter(formatter)
logger.addHandler(fh)
Expand Down
20 changes: 19 additions & 1 deletion src/vorta/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
from vorta.log import logger
from vorta.network_status.abc import NetworkStatusMonitor

# Used to store whether a user wanted to override the
# default directory for the --development flag
DEFAULT_DIR_FLAG = object()

borg_compat = BorgCompatibility()
_network_status_monitor = None

Expand Down Expand Up @@ -353,7 +357,21 @@ def parse_args():
help='Create a backup in the background using the given profile. '
'Vorta must already be running for this to work.',
)

# the "development" attribute will be None if the flag is not called
# if the flag is called without an extra argument, the "development" attribute
# will be set to the value of DEFAULT_DIR_FLAG.
# if the flag is called with an extra argument, the "development" attribute
# will be set to that argument
parser.add_argument(
'--development',
'-D',
nargs='?',
const=DEFAULT_DIR_FLAG,
metavar="CONFIG_DIRECTORY",
help='Start vorta in a local development environment. '
'All log, config, cache, and temp files will be stored within the project tree. '
'You can follow this flag with an optional path and it will store the files in the provided location.',
)
return parser.parse_known_args()[0]


Expand Down
5 changes: 3 additions & 2 deletions src/vorta/views/misc_tab.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
QSpacerItem,
)

from vorta import config
from vorta._version import __version__
from vorta.config import LOG_DIR
from vorta.i18n import translate
from vorta.store.models import BackupProfileMixin, SettingsModel
from vorta.store.settings import get_misc_settings
Expand All @@ -34,7 +34,8 @@ def __init__(self, parent=None):
self.setupUi(parent)
self.versionLabel.setText(__version__)
self.logLink.setText(
f'<a href="file://{LOG_DIR}"><span style="text-decoration:' 'underline; color:#0984e3;">Log</span></a>'
f'<a href="file://{config.LOG_DIR}"><span style="text-decoration:'
'underline; color:#0984e3;">Log</span></a>'
)

self.checkboxLayout = QFormLayout(self.frameSettings)
Expand Down