Compare commits

...

38 commits

Author SHA1 Message Date
Lance Edgar 8bddce1329 bump: version 0.4.4 → 0.4.5 2025-02-01 15:19:59 -06:00
Lance Edgar 542875a44c fix: purge email settings for wuttjamaican also 2024-12-18 19:07:30 -06:00
Lance Edgar 8bd4236291 bump: version 0.4.3 → 0.4.4 2024-10-03 10:36:07 -05:00
Lance Edgar 00b0082302 fix: update project source links, kallithea -> forgejo 2024-09-14 11:51:19 -05:00
Lance Edgar 515ccc9f0c docs: use markdown for readme file 2024-09-13 18:40:32 -05:00
Lance Edgar e2ce4fd257 bump: version 0.4.2 → 0.4.3 2024-08-06 23:20:33 -05:00
Lance Edgar fcfe741b51 fix: setup basic log files for CORE Lane 2024-08-04 10:11:45 -05:00
Lance Edgar 59ab46a335 fix: avoid rich traceback for overnight luigi commands 2024-08-03 11:54:42 -05:00
Lance Edgar 8ab21914bd fix: avoid rich traceback for backup script 2024-07-25 10:08:41 -05:00
Lance Edgar 9eb44fa172 fix: avoid rich traceback for overnight luigi commands 2024-07-18 10:09:56 -05:00
Lance Edgar 65a9a7c9be fix: install more dependencies for borg 2024-07-18 10:09:47 -05:00
Lance Edgar 5ffcf0297c fix: install emacs-common-non-dfsg only if available
which it is not always, depending on apt sources
2024-07-12 12:00:39 -05:00
Lance Edgar 7d031e1a41 bump: version 0.4.1 → 0.4.2 2024-07-05 11:10:21 -05:00
Lance Edgar 04c586a11e fix: install non-dfsg package for emacs
for sake of tramp info manual

cf. https://www.reddit.com/r/emacs/comments/d6r3dt/comment/f0vujx6/
2024-07-03 14:18:29 -05:00
Lance Edgar d0425115da fix: remove references, dependency for six package 2024-07-01 16:35:08 -05:00
Lance Edgar 8b5bb956ae bump: version 0.4.0 → 0.4.1 2024-06-30 11:12:39 -05:00
Lance Edgar 5c5038144f fix: always install venv pkg when bootstrapping python 2024-06-15 21:17:42 -05:00
Lance Edgar 014982028b bump: version 0.3.6 → 0.4.0 2024-06-10 19:14:58 -05:00
Lance Edgar 8c51ee8735 feat: switch from setup.cfg to pyproject.toml + hatchling 2024-06-10 19:12:50 -05:00
Lance Edgar 4e3b8f6520 Update changelog 2024-05-31 17:47:41 -05:00
Lance Edgar be728e9bb3 Fix default dist filename for release task
not sure why this fix was needed, did setuptools behavior change?

and stop declaring explicit support for python 3.5, that makes no sense
2024-05-31 17:44:56 -05:00
Lance Edgar 284e55c05c Update changelog 2024-05-31 17:43:30 -05:00
Lance Edgar 88acb15c1c Fix command line args in scripts, per typer 2024-05-29 06:31:41 -05:00
Lance Edgar 8f8013aee0 Update changelog 2024-05-07 14:14:33 -05:00
Lance Edgar 305e4c40c7 Fix shell when creating new linux user account 2024-05-07 14:13:46 -05:00
Lance Edgar 6a15b5ae5e Add docstring to explain param 2023-11-06 21:25:13 -06:00
Lance Edgar c13e9ff23c Update changelog 2023-09-25 18:09:31 -05:00
Lance Edgar ae7cb45ab3 Remove bash -c prefix for pg_dump command
need to keep the `sudo -u postgres pg_dump ..` part as simple as
possible, since must declare `sudoers` allowance for that
2023-09-17 11:10:48 -05:00
Lance Edgar 24d632b7e3 Add option to skip raw SQL file when dumping postgres DB
trying to cut down on disk space, we'll see how well this works..
2023-09-16 16:57:10 -05:00
Lance Edgar 8e9a685006 Try again, to move postgres dump file to /tmp before restoring
so the postgres can cd to current workdir without error..fingers
crossed this doesn't break anything else again
2023-08-08 19:19:33 -05:00
Lance Edgar bedca74ca1 Revert "Move sql file to temp path when restoring postgres db"
This reverts commit 94945fbc30.

apparently that breaks some nightly cloning (prod -> stage)
2023-08-06 19:20:53 -05:00
Lance Edgar e2369b1f53 Add mysql.get_version_string() convenience function 2023-08-04 16:32:42 -05:00
Lance Edgar ab1baaa6d2 Add clang workaround for pythonz
needed that to install python 3.6.8 on debian 12
2023-08-03 21:26:47 -05:00
Lance Edgar 94945fbc30 Move sql file to temp path when restoring postgres db
otherwise postgres may throw an error, if it can't cd to current workdir
2023-08-03 10:54:33 -05:00
Lance Edgar 6479af6a57 Preserve correct owner for .bashrc when configuring nodejs 2023-08-03 10:53:59 -05:00
Lance Edgar 075f931b5e Add separate functions for dump, restore of mysql DB 2023-07-18 15:17:18 -05:00
Lance Edgar 989f1574dc Update changelog 2023-06-10 19:03:49 -05:00
Lance Edgar d713bbe522 Let caller override default fannie/config.php
also make `deploy.full_path()` honor absolute path when given one
2023-06-10 18:57:57 -05:00
25 changed files with 348 additions and 141 deletions

2
.gitignore vendored
View file

@ -1,2 +1,4 @@
*~
*.pyc
dist/
rattail_fabric2.egg-info/

53
CHANGELOG.md Normal file
View file

@ -0,0 +1,53 @@
# Changelog
All notable changes to rattail-fabric2 will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
## v0.4.5 (2025-02-01)
### Fix
- purge email settings for wuttjamaican also
## v0.4.4 (2024-10-03)
### Fix
- update project source links, kallithea -> forgejo
## v0.4.3 (2024-08-06)
### Fix
- setup basic log files for CORE Lane
- avoid rich traceback for overnight luigi commands
- avoid rich traceback for backup script
- avoid rich traceback for overnight luigi commands
- install more dependencies for borg
- install `emacs-common-non-dfsg` only if available
## v0.4.2 (2024-07-05)
### Fix
- install non-dfsg package for emacs
- remove references, dependency for `six` package
## v0.4.1 (2024-06-30)
### Fix
- always install `venv` pkg when bootstrapping python
## v0.4.0 (2024-06-10)
### Feat
- switch from setup.cfg to pyproject.toml + hatchling
## Older Releases
Please see `docs/OLDCHANGES.rst` for older release notes.

11
README.md Normal file
View file

@ -0,0 +1,11 @@
# rattail-fabric2
Rattail is a retail software framework, released under the GNU General Public
License.
This package contains various utility functions for use with
[Fabric](http://www.fabfile.org/) (v2).
Please see Rattail's [home page](https://rattailproject.org/) for more
information.

View file

@ -1,14 +0,0 @@
rattail-fabric2
===============
Rattail is a retail software framework, released under the GNU General Public
License.
This package contains various utility functions for use with `Fabric`_ (v2).
.. _`Fabric`: http://www.fabfile.org/
Please see Rattail's `home page`_ for more information.
.. _`home page`: https://rattailproject.org/

View file

@ -2,6 +2,50 @@
CHANGELOG
=========
NB. this file contains "old" release notes only. for newer releases
see the `CHANGELOG.md` file in the source root folder.
0.3.6 (2024-05-31)
------------------
* Bump version to fix PyPI upload.
0.3.5 (2024-05-31)
------------------
* Fix command line args in scripts, per typer.
0.3.4 (2024-05-07)
------------------
* Fix shell when creating new linux user account.
0.3.3 (2023-09-25)
------------------
* Add separate functions for dump, restore of mysql DB.
* Preserve correct owner for ``.bashrc`` when configuring node.js.
* Move sql file to temp path when restoring postgres db.
* Add ``clang`` workaround for pythonz.
* Add ``mysql.get_version_string()`` convenience function.
* Add option to skip raw SQL file when dumping postgres DB.
0.3.2 (2023-06-10)
------------------
* Let caller override default ``fannie/config.php``.
0.3.1 (2023-06-10)
------------------

41
pyproject.toml Normal file
View file

@ -0,0 +1,41 @@
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "rattail-fabric2"
version = "0.4.5"
description = "Fabric (v2) Utilities for Rattail"
readme = "README.md"
authors = [{name = "Lance Edgar", email = "lance@edbob.org"}]
license = {text = "GNU GPL v3+"}
classifiers = [
"Development Status :: 3 - Alpha",
"Environment :: Console",
"Intended Audience :: Developers",
"License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
"Natural Language :: English",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
"Topic :: System :: Systems Administration",
"Topic :: Software Development :: Libraries :: Python Modules",
]
dependencies = [
"fabric2",
"invoke",
"rattail",
]
[project.urls]
Homepage = "https://rattailproject.org"
Repository = "https://forgejo.wuttaproject.org/rattail/rattail-fabric2"
Changelog = "https://forgejo.wuttaproject.org/rattail/rattail-fabric2/src/branch/master/CHANGELOG.md"
[tool.commitizen]
version_provider = "pep621"
tag_format = "v$version"
update_changelog_on_bump = true

View file

@ -1,3 +1,9 @@
# -*- coding: utf-8; -*-
__version__ = '0.3.1'
try:
from importlib.metadata import version
except ImportError:
from importlib_metadata import version
__version__ = version('rattail-fabric2')

View file

@ -112,4 +112,10 @@ def install_emacs(c):
if ubuntu_version and ubuntu_version < 16:
emacs = 'emacs23-nox'
install(c, emacs, 'emacs-goodies-el')
install(c, emacs,
'emacs-goodies-el',
)
# nb. this includes tramp manual
if c.sudo('dpkg -s emacs-common-non-dfsg', warn=True).ok:
install(c, 'emacs-common-non-dfsg')

View file

@ -103,7 +103,7 @@ def deploy_backup_app(c, deploy, envname, mkvirtualenv=True, user='rattail',
# rattail
mkdir(c, os.path.join(envpath, 'src'), use_sudo=True, runas_user=user)
if not exists(c, os.path.join(envpath, 'src/rattail')):
c.sudo('git clone https://kallithea.rattailproject.org/rattail-project/rattail {}/src/rattail'.format(envpath), user=user)
c.sudo(f'git clone https://forgejo.wuttaproject.org/rattail/rattail.git {envpath}/src/rattail', user=user)
c.sudo("bash -c 'PIP_CONFIG_FILE={0}/pip.conf {0}/bin/pip install --editable {0}/src/rattail'".format(envpath),
user=user)
deploy_generic(c, 'backup/git-exclude', os.path.join(envpath, 'src/rattail/.git/info/exclude'), use_sudo=True, owner=user)

View file

@ -2,7 +2,7 @@
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2018 Lance Edgar
# Copyright © 2010-2024 Lance Edgar
#
# This file is part of Rattail.
#
@ -26,8 +26,6 @@ Fabric library for Borg backups
https://www.borgbackup.org/
"""
from __future__ import unicode_literals, absolute_import
from rattail_fabric2 import apt
@ -39,6 +37,9 @@ def install_dependencies(c):
c,
'libacl1-dev',
'libfuse-dev',
'liblz4-dev',
'libssl-dev',
'libxxhash-dev',
'libzstd-dev',
'pkg-config',
)

View file

@ -33,7 +33,7 @@ def install_from_source(c, user='rattail'):
"""
if not exists(c, '/usr/local/src/byjove'):
mkdir(c, '/usr/local/src/byjove', use_sudo=True, owner=user)
c.sudo('git clone https://kallithea.rattailproject.org/rattail-project/byjove /usr/local/src/byjove',
c.sudo('git clone https://forgejo.wuttaproject.org/rattail/byjove.git /usr/local/src/byjove',
user=user)
c.sudo("bash -l -c 'cd /usr/local/src/byjove; npm link'",
user=user)

View file

@ -129,21 +129,29 @@ def mkdir(c, paths, owner=None, mode=None,
def make_normal_user(c, username, full_name=None,
# TODO: ugh why is this true by default..should change that
disabled_login=True,
password=None):
shell='/bin/bash',
password=None,
disabled_login=False):
"""
Make a new "normal" user account.
:param disabled_login: If true, will leave the account in a
non-usable state, i.e. with invalid shell.
"""
if not c.run('getent passwd {}'.format(username), warn=True).failed:
# do not bother if user exists
missing = c.run(f'getent passwd {username}', warn=True).failed
if not missing:
return
if password:
disabled_login = True
disabled_login = '--disabled-login' if disabled_login else ''
c.sudo("adduser --gecos '{}' {} {}".format(full_name or username,
disabled_login,
username))
# nb. specify --disabled-login to avoid being prompted for password
c.sudo("adduser --gecos '{}' --disabled-login {}".format(full_name or username,
username))
# then fix the shell unless we shouldn't
if not disabled_login:
c.sudo(f'usermod -s {shell} {username}')
# and maybe set password
if password:
c.sudo(f"bash -c 'echo {username}:{password} | chpasswd'",
echo=False)
@ -239,6 +247,8 @@ class Deployer(object):
self.deploy(c, local_path, remote_path, **kwargs)
def full_path(self, local_path):
if local_path.startswith('/'):
return local_path
return '{}/{}'.format(self.deploy_path, local_path)
def local_exists(self, local_path):

View file

@ -41,7 +41,8 @@ def install_corepos(c, rootdir, rooturl_office, production=True,
mysql_name_prefix='',
composer='composer.phar',
composer_install=True,
make_shadowread=False):
make_shadowread=False,
fannie_config=True):
"""
Install the CORE software to the given location.
@ -93,22 +94,31 @@ def install_corepos(c, rootdir, rooturl_office, production=True,
user='{}@localhost'.format(mysql_username))
# fannie config
remote_path = '{}/IS4C/fannie/config.php'.format(rootdir)
if not exists(c, remote_path):
deploy_generic(c, 'corepos/fannie-config.php.mako', remote_path,
use_sudo=True, owner='www-data:{}'.format(user), mode='0640',
context={'rootdir': rootdir,
'rooturl': rooturl_office,
'mysql_username': mysql_username,
'mysql_password': mysql_password,
'mysql_name_prefix': mysql_name_prefix})
if fannie_config:
remote_path = '{}/IS4C/fannie/config.php'.format(rootdir)
if not exists(c, remote_path):
if fannie_config is True:
fannie_config = 'corepos/fannie-config.php.mako'
deploy_generic(c, fannie_config, remote_path,
use_sudo=True, owner='www-data:{}'.format(user), mode='0640',
context={'rootdir': rootdir,
'rooturl': rooturl_office,
'mysql_username': mysql_username,
'mysql_password': mysql_password,
'mysql_name_prefix': mysql_name_prefix})
# fannie logging
# office logging
mkdir(c, f'{is4c}/fannie/logs', use_sudo=True,
owner=f'{user}:www-data', mode='0775')
c.sudo(f"bash -c 'cd {is4c}/fannie/logs && touch fannie.log debug_fannie.log'",
user='www-data')
# lane logging
mkdir(c, f'{is4c}/pos/is4c-nf/log', use_sudo=True,
owner=f'{user}:www-data', mode='0775')
c.sudo(f"bash -c 'cd {is4c}/pos/is4c-nf/log && touch lane.log debug_lane.log'",
user='www-data')
# TODO: deprecate / remove this
def install_fannie(c, rootdir, user='www-data', branch='version-2.10',

View file

@ -11,6 +11,8 @@ else
fi
RATTAIL="/srv/envs/${envname}/bin/rattail --config=$CONFIG $PROGRESS $VERBOSE"
# nb. avoid rich-formatted traceback here since it's so "noisy"
export _TYPER_STANDARD_TRACEBACK=1
# sanity check

View file

@ -3,9 +3,10 @@
cd ${envroot}
export RATTAIL_CONFIG_FILES=${overnight_conf}
# nb. avoid rich-formatted traceback here since it's so "noisy"
export _TYPER_STANDARD_TRACEBACK=1
bin/rattail overnight -k ${automation.lower()} <%text>\</%text>
--no-versioning <%text>\</%text>
bin/rattail --no-versioning overnight -k ${automation.lower()} <%text>\</%text>
% if email_key is not Undefined and email_key:
--email-key '${email_key}' <%text>\</%text>
% endif

View file

@ -3,9 +3,10 @@
cd ${envroot}
export RATTAIL_CONFIG_FILES=${overnight_conf}
# nb. avoid rich-formatted traceback here since it's so "noisy"
export _TYPER_STANDARD_TRACEBACK=1
bin/rattail overnight -k ${automation.lower()} <%text>\</%text>
--no-versioning <%text>\</%text>
bin/rattail --no-versioning overnight -k ${automation.lower()} <%text>\</%text>
% if email_key is not Undefined and email_key:
--email-key '${email_key}' <%text>\</%text>
% endif

View file

@ -2,7 +2,7 @@
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2021 Lance Edgar
# Copyright © 2010-2023 Lance Edgar
#
# This file is part of Rattail.
#
@ -24,6 +24,8 @@
Fabric Library for MySQL
"""
import re
from rattail_fabric2 import apt, make_deploy, sed
@ -38,6 +40,18 @@ def install(c):
apt.install(c, 'default-mysql-server')
def get_version_string(c):
"""
Fetch the version of MySQL running on the target system
"""
result = c.sudo('mysql --version', warn=True)
if not result.failed:
# match = re.match(r'^mysql .*?(\d+\.\d+\.\d+)-MariaDB', result.stdout)
match = re.match(r'^mysql +Ver +(\d+\.\d+\.\d+)-.*', result.stdout)
if match:
return match.group(1)
def set_bind_address(c, address):
"""
Configure the 'bind-address' setting with the given value.
@ -149,20 +163,31 @@ def script(c, path, database=''):
c.sudo("bash -c 'mysql {} < {}'".format(database, path))
def dump_db(c, name, skip_triggers=False):
"""
Dump a database to file, on the server represented by ``c`` param.
This function returns the name of the DB dump file. The name will
not have a path component as it's assumed to be in the home folder
of the connection user.
"""
skip_triggers = '--skip-triggers' if skip_triggers else ''
# note, we force sudo "as root" to ensure -H flag is used
# (which allows us to leverage /root/.my.cnf config file)
c.sudo(f'mysqldump {skip_triggers} --result-file={name}.sql {name}',
user='root')
c.sudo(f'gzip --force {name}.sql')
return f'{name}.sql.gz'
def download_db(c, name, destination=None, **kwargs):
"""
Download a database from the "current" server.
"""
if destination is None:
destination = './{}.sql.gz'.format(name)
triggers = '--skip-triggers' if kwargs.get('skip_triggers') else ''
mysqldump = 'mysqldump {0} --result-file={1}.sql {1}'.format(triggers, name)
# note, we force sudo "as root" to ensure -H flag is used
# (which allows us to leverage /root/.my.cnf config file)
c.sudo(mysqldump, user='root')
c.sudo('gzip --force {}.sql'.format(name))
c.get('{}.sql.gz'.format(name), destination)
c.sudo('rm {}.sql.gz'.format(name))
filename = dump_db(c, name,
skip_triggers=kwargs.get('skip_triggers', False))
c.get(filename, destination or f'./{filename}')
c.sudo(f'rm {filename}')
def clone_db(c, name, download, user=None, force=False):
@ -193,3 +218,20 @@ def clone_db(c, name, download, user=None, force=False):
c.run('gunzip --force {}.sql.gz'.format(name))
c.sudo("bash -c 'mysql {0} < {0}.sql'".format(name))
c.run('rm {}.sql'.format(name))
def restore_db(c, name, path):
"""
Restore a database from a dump file.
:param name: Name of the database to restore.
:param path: Path to the DB dump file, which should end in ``.sql.gz``
"""
if not path.endswith('.sql.gz'):
raise ValueError("Path to dump file must end in `.sql.gz`")
c.sudo(f'gunzip --force {path}')
sql_path = path[:-3]
c.sudo(f"bash -c 'mysql {name} < {sql_path}'")
c.sudo(f'rm {sql_path}')

View file

@ -2,7 +2,7 @@
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2019 Lance Edgar
# Copyright © 2010-2023 Lance Edgar
#
# This file is part of Rattail.
#
@ -46,6 +46,9 @@ def install(c, version=None, user=None):
profile = os.path.join(home, '.profile')
kwargs = {'use_sudo': bool(user)}
if kwargs['use_sudo']:
c.sudo(f'touch {profile}')
c.sudo(f'chown {user}: {profile}')
append(c, profile, 'export NVM_DIR="{}"'.format(nvm), **kwargs)
append(c, profile, '[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"', **kwargs)
append(c, profile, '[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"', **kwargs)

View file

@ -199,7 +199,8 @@ def drop_db(c, name, checkfirst=True):
c.sudo('dropdb {}'.format(name), user='postgres')
def dump_db(c, name, port=None, exclude_tables=None):
def dump_db(c, name, port=None, exclude_tables=None,
skip_raw_file=False):
"""
Dump a database to file, on the server represented by ``c`` param.
@ -209,22 +210,39 @@ def dump_db(c, name, port=None, exclude_tables=None):
"""
c.run('touch {}.sql'.format(name))
c.run('chmod 0666 {}.sql'.format(name))
cmd = 'pg_dump {port} {exclude_tables} --file={name}.sql {name}'.format(
name=name,
port='--port={}'.format(port) if port else '',
exclude_tables='--exclude-table-data={}'.format(exclude_tables) if exclude_tables else '')
c.sudo(cmd, user='postgres')
c.run('gzip --force {}.sql'.format(name))
return '{}.sql.gz'.format(name)
sql_name = f'{name}.sql'
gz_name = f'{sql_name}.gz'
filename = gz_name if skip_raw_file else sql_name
port = f'--port={port}' if port else ''
exclude_tables = f'--exclude-table-data={exclude_tables}' if exclude_tables else ''
filename = '' if skip_raw_file else f'--file={filename}'
cmd = f'pg_dump {port} {exclude_tables} {filename} {name}'
if skip_raw_file:
tmp_name = f'/tmp/{gz_name}'
cmd = f'{cmd} | gzip -c > {tmp_name}'
c.sudo(cmd, user='postgres')
# TODO: should remove this file
c.run(f"cp {tmp_name} {gz_name}")
else:
c.sudo(cmd, user='postgres')
c.run(f'gzip --force {sql_name}')
return gz_name
def download_db(c, name, destination=None, port=None, exclude_tables=None):
def download_db(c, name, destination=None, port=None, exclude_tables=None,
skip_raw_file=False):
"""
Download a database from the server represented by ``c`` param.
"""
if destination is None:
destination = './{}.sql.gz'.format(name)
dumpfile = dump_db(c, name, port=port, exclude_tables=exclude_tables)
dumpfile = dump_db(c, name, port=port, exclude_tables=exclude_tables,
skip_raw_file=skip_raw_file)
c.get(dumpfile, destination)
c.run('rm {}'.format(dumpfile))
@ -259,7 +277,12 @@ def clone_db(c, name, owner, download, user='rattail', force=False, workdir=None
os.chdir(curdir)
# restore database on target server
restore_db(c, name, '{}.sql.gz'.format(name))
# TODO: first tried c.sudo('mv ...') but that did not work for the "typical"
# scenario of connecting as rattail@server to obtain db dump, since the dump
# cmd is normally carved out via sudoers config, but 'sudo mv ..' is not
filename = f'{name}.sql.gz'
c.run(f'mv {filename} /tmp/')
restore_db(c, name, f'/tmp/{filename}')
def restore_db(c, name, path):

View file

@ -2,7 +2,7 @@
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2022 Lance Edgar
# Copyright © 2010-2023 Lance Edgar
#
# This file is part of Rattail.
#
@ -50,6 +50,7 @@ def bootstrap_python(c, deploy=None,
apt.install(
c,
'python3-dev',
'python3-venv',
'libffi-dev',
'libjpeg-dev',
'libssl-dev',
@ -112,7 +113,8 @@ def configure_pythonz(c, user):
use_sudo=True)
def install_python(c, version, globally=False, verbose=False):
def install_python(c, version, globally=False, verbose=False,
use_clang=False):
"""
Install a specific version of python, via pythonz.
@ -121,10 +123,17 @@ def install_python(c, version, globally=False, verbose=False):
symlink, if installed, will use the "short" version, e.g. if the
``version`` specified is ``'3.5.3'`` then the symlink will be named
``'python3.5'``.
:param use_clang: Use `clang` instead of default compiler. May be
needed in rare cases for older python versions. See also
https://stackoverflow.com/a/73267352
"""
if use_clang:
apt.install(c, 'clang')
if not exists(c, '/usr/local/pythonz/pythons/CPython-{}'.format(version)):
clang = 'CC=clang' if use_clang else ''
verbose = '--verbose' if verbose else ''
c.sudo("bash -lc 'pythonz install {} {}'".format(verbose, version))
c.sudo(f"bash -lc '{clang} pythonz install {verbose} {version}'")
if globally:
short_version = '.'.join(version.split('.')[:2])
c.sudo('ln -sf /usr/local/pythonz/pythons/CPython-{0}/bin/python{1} /usr/local/bin/python{1}'.format(

View file

@ -108,6 +108,14 @@ def delete_email_recipients(c, dbname):
"""
Purge all email recipient settings for the given database.
"""
# purge new-style for wuttjamaican
postgresql.sql(c, "delete from setting where name like 'rattail.email.%.sender';", database=dbname)
postgresql.sql(c, "delete from setting where name like 'rattail.email.%.to';", database=dbname)
postgresql.sql(c, "delete from setting where name like 'rattail.email.%.cc';", database=dbname)
postgresql.sql(c, "delete from setting where name like 'rattail.email.%.bcc';", database=dbname)
# purge old-style for rattail
postgresql.sql(c, "delete from setting where name like 'rattail.mail.%.from';", database=dbname)
postgresql.sql(c, "delete from setting where name like 'rattail.mail.%.to';", database=dbname)
postgresql.sql(c, "delete from setting where name like 'rattail.mail.%.cc';", database=dbname)
postgresql.sql(c, "delete from setting where name like 'rattail.mail.%.bcc';", database=dbname)

View file

@ -111,8 +111,6 @@ def append(c, filename, text, use_sudo=False, partial=False, escape=True,
"""
func = use_sudo and c.sudo or c.run
# Normalize non-list input to be a list
# TODO: do we need to check for six.something here?
# if isinstance(text, basestring):
if isinstance(text, str):
text = [text]
for line in text:

View file

@ -1,34 +0,0 @@
# -*- coding: utf-8; -*-
[metadata]
name = rattail-fabric2
version = attr: rattail_fabric2.__version__
author = Lance Edgar
author_email = lance@edbob.org
url = https://rattailproject.org/
license = GNU GPL v3
description = Fabric (v2) Utilities for Rattail
long_description = file: README.rst
classifiers =
Development Status :: 3 - Alpha
Environment :: Console
Intended Audience :: Developers
License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
Natural Language :: English
Operating System :: OS Independent
Programming Language :: Python :: 3
Programming Language :: Python :: 3.5
Topic :: System :: Systems Administration
Topic :: Software Development :: Libraries :: Python Modules
[options]
install_requires =
fabric2
invoke
rattail
six
packages = find:
include_package_data = True
zip_safe = False

View file

@ -1,26 +0,0 @@
# -*- coding: utf-8; -*-
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2023 Lance Edgar
#
# This file is part of Rattail.
#
# Rattail 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.
#
# Rattail 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 should have received a copy of the GNU General Public License along with
# Rattail. If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
from setuptools import setup
setup()

View file

@ -2,7 +2,7 @@
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2020 Lance Edgar
# Copyright © 2010-2024 Lance Edgar
#
# This file is part of Rattail.
#
@ -24,16 +24,25 @@
Tasks for rattail-fabric2
"""
from __future__ import unicode_literals, absolute_import
import os
import re
import shutil
from invoke import task
here = os.path.abspath(os.path.dirname(__file__))
exec(open(os.path.join(here, 'rattail_fabric2', '_version.py')).read())
__version__ = None
pattern = re.compile(r'^version = "(\d+\.\d+\.\d+)"$')
with open(os.path.join(here, 'pyproject.toml'), 'rt') as f:
for line in f:
line = line.rstrip('\n')
match = pattern.match(line)
if match:
__version__ = match.group(1)
break
if not __version__:
raise RuntimeError("could not parse version!")
@task
@ -41,9 +50,10 @@ def release(c):
"""
Release a new version of 'rattail-fabric2'.
"""
shutil.rmtree('rattail_fabric2.egg-info')
if os.path.exists('rattail_fabric2.egg-info'):
shutil.rmtree('rattail_fabric2.egg-info')
# TODO: this seems heavy-handed? for sake of recursive-include in MANIFEST
# TODO: what i esp. don't like is, this doesn't consider .gitignore
c.run("find . -name '*~' -delete")
c.run('python setup.py sdist --formats=gztar')
c.run('twine upload dist/rattail-fabric2-{}.tar.gz'.format(__version__))
c.run('python -m build --sdist')
c.run(f'twine upload dist/rattail_fabric2-{__version__}.tar.gz')