# This file exists within 'dob':
#
# https://github.com/hotoffthehamster/dob
#
# Copyright © 2018-2020 Landon Bouma. All rights reserved.
#
# 'dob' is free software: you can redistribute it and/or modify it under the terms
# of the GNU General Public License as published by the Free Software Foundation,
# either version 3 of the License, or (at your option) any later version.
#
# 'dob' is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU General Public License for more details.
#
# You can find the GNU General Public License reprinted in the file titled 'LICENSE',
# or visit <http://www.gnu.org/licenses/>.
import os
import shutil
import sys
from gettext import gettext as _
from nark import __file__ as nark___file__
from nark.helpers.app_dirs import ensure_directory_exists
from dob_bright.help_newbs import NEWBIE_HELP_WELCOME
from dob_bright.termio import (
attr,
click_echo,
dob_in_user_exit,
dob_in_user_warning,
fg,
highlight_value
)
from . import __arg0name__
__all__ = (
'control',
'downgrade',
'upgrade',
'version',
'latest_version',
'upgrade_legacy_database_file',
'upgrade_legacy_database_instructions',
# Private:
# '_barf_legacy_database',
# '_instruct_upgrade',
# '_upgrade_legacy_database_file',
)
[docs]def control(controller):
err_msg = None
success = False
versioned = version(controller, silent_check=True, must=False)
if not versioned:
# MAYBE/2018-05-18: (lb): Also check if legacy database!
success = controller.store.migrations.control()
if success is None:
err_msg = _('Something went wrong! Sorry!!')
if not success and not err_msg:
err_msg = _('The database is already versioned!')
if err_msg:
dob_in_user_exit(err_msg)
[docs]def downgrade(controller):
version(controller, silent_check=True, must=True)
response = controller.store.migrations.downgrade()
assert response is not None
if not response:
dob_in_user_exit(_('The database is already at the earliest version'))
[docs]def upgrade(controller):
version(controller, silent_check=True, must=True)
response = controller.store.migrations.upgrade()
assert response is not None
if not response:
dob_in_user_exit(_('The database is already at the latest version'))
[docs]def version(controller, silent_check=False, must=True):
db_version = controller.store.migrations.version()
if db_version is not None:
if not silent_check:
click_echo(db_version)
return db_version
elif must:
_barf_legacy_database(controller)
return None
[docs]def latest_version(controller, silent_check=False, must=True):
latest_ver = controller.store.migrations.latest_version()
if latest_ver is not None:
if not silent_check:
click_echo(latest_ver)
return latest_ver
elif must:
_barf_legacy_database(controller)
return None
# ***
UPGRADE_INSTRUCTIONS = _(
"""
If your database was created long ago by the original hamster,
`hamster-applet`, run the legacy database upgrade script, e.g.,
{mintgreen}{prog_name} store upgrade-legacy \\
{legacy_path}{reset}
Be sure to make a backup first, in case something goes wrong!
"""
)
# 2020-03-31: I had a link to the project page here but there's
# no additional information there, so why bother. It read,
#
# See the project page for more information:
#
# https://github.com/hotoffthehamster/nark
#
# As for actual upgrade help online, there's only one spot, but
# it says nothing more than what we've said here. It's at
#
# https://dob.readthedocs.io/en/latest/usage.html#upgrade-hamster
# USER: If your database was created more recently by the new `hamster-lib`
# rewrite (2016-2017), there are 3 database changes to make. (lb): I did not
# add an upgrade path from hamster-lib because it seemed like that project
# was never quite released. So I assume no one's using it?
[docs]def upgrade_legacy_database_instructions(controller):
""""""
nark_path = os.path.dirname(os.path.dirname(nark___file__))
up_legacy_rel = os.path.join(
'migrations', 'legacy', 'upgrade_hamster-applet_db.sh',
)
up_legacy_path = os.path.join(nark_path, up_legacy_rel)
db_path = controller.config['db.path']
instructions = UPGRADE_INSTRUCTIONS.format(
prog_name=__arg0name__,
legacy_path="~/.local/share/hamster-applet/hamster.db",
db_path=db_path,
nark_path=nark_path,
up_legacy_path=up_legacy_path,
# FIXME: (lb): Replace hardcoded styles. Assign from styles.conf. #styling
mintgreen=(fg('spring_green_2a') + attr('bold')),
reset=attr('reset'),
)
return instructions
def _barf_legacy_database(controller):
""""""
prefix = '''
If this is a legacy database, upgrade and register the database.
'''.strip()
msg1 = prefix + upgrade_legacy_database_instructions(controller)
msg2 = _('The database is not versioned!')
msg2 = '{}{}{}'.format(fg('red_3b'), msg2, attr('reset'))
msg = '{}\n{}'.format(msg2, msg1)
click_echo(msg)
sys.exit(1)
# ***
[docs]def upgrade_legacy_database_file(ctx, controller, file_in, force):
""""""
db_path = controller.config['db.path']
def _upgrade_legacy_database_file():
if file_in is None:
echo_help()
return None
else:
copy_and_upgrade()
return True
def copy_and_upgrade():
copy_into_place()
run_upgrade()
run_migrations()
click_echo(
_('Seeded data store at {}')
.format(highlight_value(db_path))
)
def copy_into_place():
if os.path.exists(db_path) and os.path.samefile(db_path, file_in.name):
return
controller.must_unlink_db_path(force=force)
must_copy_new_db_to_db_path()
def must_copy_new_db_to_db_path():
try:
db_dir = os.path.dirname(db_path)
ensure_directory_exists(db_dir)
shutil.copyfile(file_in.name, db_path)
except Exception as err:
msg = _('Failed to copy new database to ‘{}’').format(str(err))
dob_in_user_warning(msg)
def echo_help():
if controller.is_germinated:
click_echo(ctx.get_help())
else:
_instruct_upgrade(ctx, controller)
def run_upgrade():
try:
controller.store.migrations.legacy_upgrade_from_hamster_applet(db_path)
except Exception as err:
dob_in_user_exit(_('Upgrade failed! ERROR: {}').format(str(err)))
def run_migrations():
db_version = controller.store.migrations.version()
assert db_version is None
control(controller)
db_version = controller.store.migrations.version()
assert db_version == 0
response = True
while response:
response = controller.store.migrations.upgrade()
return _upgrade_legacy_database_file()
def _instruct_upgrade(ctx, controller):
click_echo(
'\n{}\n{}'.format(
NEWBIE_HELP_WELCOME(ctx),
upgrade_legacy_database_instructions(controller),
)
)