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 support for glob pattern in application config files #1807

Open
wants to merge 18 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
- Added support for notion-enhancer (via @fharper)
- Added support for GitFox (via @L3K0V)
- Updated support for Bartender through SetApp (via @dbhagen)
- Added support for glob pattern in application config files (via @jneuendorf and @semkagtn)

## Mackup 0.8.33

Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,4 @@ release: clean
pipenv run twine upload dist/*

black:
black --target-version py27 .
pipenv run black --target-version py34 .
jneuendorf marked this conversation as resolved.
Show resolved Hide resolved
3 changes: 1 addition & 2 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ docopt = "*"
six = "*"

[dev-packages]
# Black is still a pre-release. Replaced with `brew install black` for now.
# black = "*"
black = "*"
coverage = "*"
nose = "*"
twine = "*"
284 changes: 175 additions & 109 deletions Pipfile.lock

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions mackup/applications/traktor.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[application]
name = Traktor

[options]
enable_glob = true

[configuration_files]
Documents/Native Instruments/Traktor *.*.*/Traktor Settings.tsi
29 changes: 23 additions & 6 deletions mackup/appsdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
The Applications Database provides an easy to use interface to load application
data from the Mackup Database (files).
"""
import glob
import os
from pathlib import Path

try:
import configparser
Expand Down Expand Up @@ -34,25 +36,27 @@ def __init__(self):
if config.read(config_file):
# Get the filename without the directory name
filename = os.path.basename(config_file)
# The app name is the cfg filename with the extension
# The app name is the cfg filename without the extension
app_name = filename[: -len(".cfg")]

# Start building a dict for this app
self.apps[app_name] = dict()
app = dict()

# Add the fancy name for the app, for display purpose
app_pretty_name = config.get("application", "name")
self.apps[app_name]["name"] = app_pretty_name
app["name"] = app_pretty_name

# Add the configuration files to sync
self.apps[app_name]["configuration_files"] = set()
app["configuration_files"] = set()
if config.has_section("configuration_files"):
for path in config.options("configuration_files"):
if path.startswith("/"):
raise ValueError(
"Unsupported absolute path: {}".format(path)
)
self.apps[app_name]["configuration_files"].add(path)
app["configuration_files"] |= self.get_resolves_paths(
path, config
)

# Add the XDG configuration files to sync
home = os.path.expanduser("~/")
Expand All @@ -72,7 +76,11 @@ def __init__(self):
)
path = os.path.join(xdg_config_home, path)
path = path.replace(home, "")
(self.apps[app_name]["configuration_files"].add(path))
app["configuration_files"] |= self.get_resolves_paths(
path, config
)

self.apps[app_name] = app

@staticmethod
def get_config_files():
Expand Down Expand Up @@ -168,3 +176,12 @@ def get_pretty_app_names(self):
pretty_app_names.add(self.get_name(app_name))

return pretty_app_names

def get_resolves_paths(self, path, config):
if config.getboolean("options", "enable_glob", fallback=False):
return {
str(p.relative_to(os.environ["HOME"]))
for p in Path(os.environ["HOME"]).glob(path)
}
else:
return set([path])
2 changes: 1 addition & 1 deletion mackup/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ def _setup_parser(self, filename=None):
filename = MACKUP_CONFIG_FILE

parser = configparser.SafeConfigParser(allow_no_value=True)
parser.read(os.path.join(os.path.join(os.environ["HOME"], filename)))
parser.read(os.path.join(os.environ["HOME"], filename))

return parser

Expand Down
5 changes: 2 additions & 3 deletions tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ Feel free to add more, the more the better!
## How to run the tests

```bash
cd src/mackup
pip install -r requirements.txt
nosetests
pipenv install --dev
make test
```

And you should see
Expand Down
57 changes: 57 additions & 0 deletions tests/apps_config_tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import os
import tempfile
import unittest
from unittest.mock import patch
import stat

from mackup import utils
from mackup.appsdb import ApplicationsDatabase


realpath = os.path.dirname(os.path.realpath(__file__))
APPLICATIONS_DIR = os.path.join(realpath, "..", "mackup", "applications")
FIXTURES_DIR = os.path.join(realpath, "fixtures")


class TestMackup(unittest.TestCase):
config_file_path = os.path.join(APPLICATIONS_DIR, "test-app.cfg")

def setUp(self):
os.environ["HOME"] = FIXTURES_DIR

with open(self.config_file_path, "w") as config_file:
config_file.write(
"\n".join(
[
"[application]",
"name = Test App",
"",
"[options]",
"enable_glob = true",
"",
"[configuration_files]",
"Library/Application Support/Test App/*/data.txt",
]
)
)

def tearDown(self):
os.remove(self.config_file_path)

def test_glob_configuration_paths(self):
with patch.object(
ApplicationsDatabase,
"get_config_files",
return_value=[self.config_file_path],
) as method:
app_db = ApplicationsDatabase()
print(app_db.apps)

self.assertEqual(
app_db.get_files("test-app"),
{
"Library/Application Support/Test App/2020/data.txt",
"Library/Application Support/Test App/2021/data.txt",
"Library/Application Support/Test App/2022/data.txt",
},
)
60 changes: 30 additions & 30 deletions tests/config_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ def test_config_no_config(self):
assert cfg.path == "/home/some_user/Dropbox"

assert isinstance(cfg.directory, str)
assert cfg.directory == u"Mackup"
assert cfg.directory == "Mackup"

assert isinstance(cfg.fullpath, str)
assert cfg.fullpath == u"/home/some_user/Dropbox/Mackup"
assert cfg.fullpath == "/home/some_user/Dropbox/Mackup"

assert cfg.apps_to_ignore == set()
assert cfg.apps_to_sync == set()
Expand All @@ -43,13 +43,13 @@ def test_config_empty(self):
assert cfg.engine == ENGINE_DROPBOX

assert isinstance(cfg.path, str)
assert cfg.path == u"/home/some_user/Dropbox"
assert cfg.path == "/home/some_user/Dropbox"

assert isinstance(cfg.directory, str)
assert cfg.directory == u"Mackup"
assert cfg.directory == "Mackup"

assert isinstance(cfg.fullpath, str)
assert cfg.fullpath == u"/home/some_user/Dropbox/Mackup"
assert cfg.fullpath == "/home/some_user/Dropbox/Mackup"

assert cfg.apps_to_ignore == set()
assert cfg.apps_to_sync == set()
Expand All @@ -61,13 +61,13 @@ def test_config_engine_dropbox(self):
assert cfg.engine == ENGINE_DROPBOX

assert isinstance(cfg.path, str)
assert cfg.path == u"/home/some_user/Dropbox"
assert cfg.path == "/home/some_user/Dropbox"

assert isinstance(cfg.directory, str)
assert cfg.directory == u"some_weirld_name"
assert cfg.directory == "some_weirld_name"

assert isinstance(cfg.fullpath, str)
assert cfg.fullpath == u"/home/some_user/Dropbox/some_weirld_name"
assert cfg.fullpath == "/home/some_user/Dropbox/some_weirld_name"

assert cfg.apps_to_ignore == set()
assert cfg.apps_to_sync == set()
Expand All @@ -79,13 +79,13 @@ def test_config_engine_filesystem_absolute(self):
assert cfg.engine == ENGINE_FS

assert isinstance(cfg.path, str)
assert cfg.path == u"/some/absolute/folder"
assert cfg.path == "/some/absolute/folder"

assert isinstance(cfg.directory, str)
assert cfg.directory == u"custom_folder"
assert cfg.directory == "custom_folder"

assert isinstance(cfg.fullpath, str)
assert cfg.fullpath == u"/some/absolute/folder/custom_folder"
assert cfg.fullpath == "/some/absolute/folder/custom_folder"

assert cfg.apps_to_ignore == set(["subversion", "sequel-pro"])
assert cfg.apps_to_sync == set()
Expand All @@ -98,15 +98,15 @@ def test_config_engine_filesystem(self):

assert isinstance(cfg.path, str)
assert cfg.path.endswith(
os.path.join(os.environ[u"HOME"], u"some/relative/folder")
os.path.join(os.environ["HOME"], "some/relative/folder")
)

assert isinstance(cfg.directory, str)
assert cfg.directory == u"Mackup"
assert cfg.directory == "Mackup"

assert isinstance(cfg.fullpath, str)
assert cfg.fullpath == os.path.join(
os.environ[u"HOME"], u"some/relative/folder", u"Mackup"
os.environ["HOME"], "some/relative/folder", "Mackup"
)

assert cfg.apps_to_ignore == set()
Expand All @@ -119,13 +119,13 @@ def test_config_engine_google_drive(self):
assert cfg.engine == ENGINE_GDRIVE

assert isinstance(cfg.path, str)
assert cfg.path == u"/Users/whatever/Google Drive"
assert cfg.path == "/Users/whatever/Google Drive"

assert isinstance(cfg.directory, str)
assert cfg.directory == u"Mackup"
assert cfg.directory == "Mackup"

assert isinstance(cfg.fullpath, str)
assert cfg.fullpath.endswith(u"/Google Drive/Mackup")
assert cfg.fullpath.endswith("/Google Drive/Mackup")

assert cfg.apps_to_ignore == set(["subversion", "sequel-pro", "sabnzbd"])
assert cfg.apps_to_sync == set(["sublime-text-3", "x11", "sabnzbd"])
Expand All @@ -137,13 +137,13 @@ def test_config_engine_copy(self):
assert cfg.engine == ENGINE_COPY

assert isinstance(cfg.path, str)
assert cfg.path == u"/Users/someuser/Copy"
assert cfg.path == "/Users/someuser/Copy"

assert isinstance(cfg.directory, str)
assert cfg.directory == u"Mackup"
assert cfg.directory == "Mackup"

assert isinstance(cfg.fullpath, str)
assert cfg.fullpath.endswith(u"/Copy/Mackup")
assert cfg.fullpath.endswith("/Copy/Mackup")

assert cfg.apps_to_ignore == set(["subversion", "sequel-pro", "sabnzbd"])
assert cfg.apps_to_sync == set(["sublime-text-3", "x11", "sabnzbd"])
Expand All @@ -160,10 +160,10 @@ def test_config_engine_icloud(self):
)

assert isinstance(cfg.directory, str)
assert cfg.directory == u"Mackup"
assert cfg.directory == "Mackup"

assert isinstance(cfg.fullpath, str)
assert cfg.fullpath.endswith(u"/com~apple~CloudDocs/Mackup")
assert cfg.fullpath.endswith("/com~apple~CloudDocs/Mackup")

assert cfg.apps_to_ignore == set(["subversion", "sequel-pro", "sabnzbd"])
assert cfg.apps_to_sync == set(["sublime-text-3", "x11", "sabnzbd"])
Expand All @@ -186,10 +186,10 @@ def test_config_apps_to_ignore(self):
assert cfg.path == "/home/some_user/Dropbox"

assert isinstance(cfg.directory, str)
assert cfg.directory == u"Mackup"
assert cfg.directory == "Mackup"

assert isinstance(cfg.fullpath, str)
assert cfg.fullpath == u"/home/some_user/Dropbox/Mackup"
assert cfg.fullpath == "/home/some_user/Dropbox/Mackup"

assert cfg.apps_to_ignore == set(["subversion", "sequel-pro", "sabnzbd"])
assert cfg.apps_to_sync == set()
Expand All @@ -201,13 +201,13 @@ def test_config_apps_to_sync(self):
assert cfg.engine == ENGINE_DROPBOX

assert isinstance(cfg.path, str)
assert cfg.path == u"/home/some_user/Dropbox"
assert cfg.path == "/home/some_user/Dropbox"

assert isinstance(cfg.directory, str)
assert cfg.directory == u"Mackup"
assert cfg.directory == "Mackup"

assert isinstance(cfg.fullpath, str)
assert cfg.fullpath == u"/home/some_user/Dropbox/Mackup"
assert cfg.fullpath == "/home/some_user/Dropbox/Mackup"

assert cfg.apps_to_ignore == set()
assert cfg.apps_to_sync == set(["sabnzbd", "sublime-text-3", "x11"])
Expand All @@ -219,13 +219,13 @@ def test_config_apps_to_ignore_and_sync(self):
assert cfg.engine == ENGINE_DROPBOX

assert isinstance(cfg.path, str)
assert cfg.path == u"/home/some_user/Dropbox"
assert cfg.path == "/home/some_user/Dropbox"

assert isinstance(cfg.directory, str)
assert cfg.directory == u"Mackup"
assert cfg.directory == "Mackup"

assert isinstance(cfg.fullpath, str)
assert cfg.fullpath == u"/home/some_user/Dropbox/Mackup"
assert cfg.fullpath == "/home/some_user/Dropbox/Mackup"

assert cfg.apps_to_ignore == set(["subversion", "sequel-pro", "sabnzbd"])
assert cfg.apps_to_sync == set(["sabnzbd", "sublime-text-3", "x11", "vim"])
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
2020
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
2021
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
2022