mirror of
https://github.com/deadc0de6/dotdrop.git
synced 2026-02-10 20:14:16 +00:00
adding key_prefix and key_separator for #335
This commit is contained in:
@@ -33,6 +33,8 @@ Entry | Description | Default
|
|||||||
`import_variables` | List of paths to load variables from (absolute paths or relative to the config file location; see [Import variables from file](config-details.md#import_variables-entry)) | -
|
`import_variables` | List of paths to load variables from (absolute paths or relative to the config file location; see [Import variables from file](config-details.md#import_variables-entry)) | -
|
||||||
`instignore` | List of patterns to ignore when installing, applied to all dotfiles (enclose in quotes when using wildcards; see [ignore patterns](config.md#ignore-patterns)) | -
|
`instignore` | List of patterns to ignore when installing, applied to all dotfiles (enclose in quotes when using wildcards; see [ignore patterns](config.md#ignore-patterns)) | -
|
||||||
`keepdot` | Preserve leading dot when importing hidden file in the `dotpath` | false
|
`keepdot` | Preserve leading dot when importing hidden file in the `dotpath` | false
|
||||||
|
`key_prefix` | Prefix dotfile key on `import` with `f<key_separator>` for file and `d<key_separator>` for directory | true
|
||||||
|
`key_separator` | Separator to use on dotfile key generation on `import` | `_`
|
||||||
`link_dotfile_default` | Set a dotfile's `link` attribute to this value when undefined. Possible values: *nolink*, *link* (See [Symlinking dotfiles](config.md#symlinking-dotfiles)) | `nolink`
|
`link_dotfile_default` | Set a dotfile's `link` attribute to this value when undefined. Possible values: *nolink*, *link* (See [Symlinking dotfiles](config.md#symlinking-dotfiles)) | `nolink`
|
||||||
`link_on_import` | Set a dotfile's `link` attribute to this value when importing. Possible values: *nolink*, *link* [Symlinking dotfiles](config.md#symlinking-dotfiles)) | `nolink`
|
`link_on_import` | Set a dotfile's `link` attribute to this value when importing. Possible values: *nolink*, *link* [Symlinking dotfiles](config.md#symlinking-dotfiles)) | `nolink`
|
||||||
`longkey` | Use long keys for dotfiles when importing (See [Import dotfiles](usage.md#import-dotfiles)) | false
|
`longkey` | Use long keys for dotfiles when importing (See [Import dotfiles](usage.md#import-dotfiles)) | false
|
||||||
|
|||||||
@@ -42,12 +42,13 @@ $ dotdrop import ~/.xinitrc
|
|||||||
```
|
```
|
||||||
|
|
||||||
You can control how the dotfile key is generated in the config file
|
You can control how the dotfile key is generated in the config file
|
||||||
with the config entry `longkey` (defaults to *false*).
|
with the following config entries:
|
||||||
|
|
||||||
Two formats are available:
|
* `longkey`
|
||||||
|
* *short format* (default): take the shortest unique path
|
||||||
* *short format* (default): take the shortest unique path
|
* *long format*: take the full path
|
||||||
* *long format*: take the full path
|
* `key_prefix`: defines if the key is prefixed with `f<key_separator>` for file and `d<key_separator>` for directory
|
||||||
|
* `key_separator`: defines the separator to use (defaults to `_`)
|
||||||
|
|
||||||
For example, `~/.config/awesome/rc.lua` gives:
|
For example, `~/.config/awesome/rc.lua` gives:
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ class CfgAggregator:
|
|||||||
|
|
||||||
file_prefix = 'f'
|
file_prefix = 'f'
|
||||||
dir_prefix = 'd'
|
dir_prefix = 'd'
|
||||||
key_sep = '_'
|
|
||||||
|
|
||||||
def __init__(self, path, profile_key, debug=False, dry=False):
|
def __init__(self, path, profile_key, debug=False, dry=False):
|
||||||
"""
|
"""
|
||||||
@@ -228,6 +227,8 @@ class CfgAggregator:
|
|||||||
|
|
||||||
# settings
|
# settings
|
||||||
self.settings = Settings.parse(None, self.cfgyaml.settings)
|
self.settings = Settings.parse(None, self.cfgyaml.settings)
|
||||||
|
self.key_prefix = self.settings.key_prefix
|
||||||
|
self.key_separator = self.settings.key_separator
|
||||||
|
|
||||||
# dotfiles
|
# dotfiles
|
||||||
self.dotfiles = Dotfile.parse_dict(self.cfgyaml.dotfiles)
|
self.dotfiles = Dotfile.parse_dict(self.cfgyaml.dotfiles)
|
||||||
@@ -333,8 +334,12 @@ class CfgAggregator:
|
|||||||
absolute path of path
|
absolute path of path
|
||||||
"""
|
"""
|
||||||
dirs = self._split_path_for_key(path)
|
dirs = self._split_path_for_key(path)
|
||||||
prefix = self.dir_prefix if os.path.isdir(path) else self.file_prefix
|
prefix = []
|
||||||
key = self.key_sep.join([prefix] + dirs)
|
if self.key_prefix:
|
||||||
|
prefix = [self.file_prefix]
|
||||||
|
if os.path.isdir(path):
|
||||||
|
prefix = [self.dir_prefix]
|
||||||
|
key = self.key_separator.join(prefix + dirs)
|
||||||
return self._uniq_key(key, keys)
|
return self._uniq_key(key, keys)
|
||||||
|
|
||||||
def _get_short_key(self, path, keys):
|
def _get_short_key(self, path, keys):
|
||||||
@@ -344,11 +349,15 @@ class CfgAggregator:
|
|||||||
"""
|
"""
|
||||||
dirs = self._split_path_for_key(path)
|
dirs = self._split_path_for_key(path)
|
||||||
dirs.reverse()
|
dirs.reverse()
|
||||||
prefix = self.dir_prefix if os.path.isdir(path) else self.file_prefix
|
prefix = []
|
||||||
|
if self.key_prefix:
|
||||||
|
prefix = [self.file_prefix]
|
||||||
|
if os.path.isdir(path):
|
||||||
|
prefix = [self.dir_prefix]
|
||||||
entries = []
|
entries = []
|
||||||
for dri in dirs:
|
for dri in dirs:
|
||||||
entries.insert(0, dri)
|
entries.insert(0, dri)
|
||||||
key = self.key_sep.join([prefix] + entries)
|
key = self.key_separator.join(prefix + entries)
|
||||||
if key not in keys:
|
if key not in keys:
|
||||||
return key
|
return key
|
||||||
return self._uniq_key(key, keys)
|
return self._uniq_key(key, keys)
|
||||||
@@ -360,7 +369,7 @@ class CfgAggregator:
|
|||||||
while newkey in keys:
|
while newkey in keys:
|
||||||
# if unable to get a unique path
|
# if unable to get a unique path
|
||||||
# get a random one
|
# get a random one
|
||||||
newkey = self.key_sep.join([key, str(cnt)])
|
newkey = self.key_separator.join([key, str(cnt)])
|
||||||
cnt += 1
|
cnt += 1
|
||||||
return newkey
|
return newkey
|
||||||
|
|
||||||
|
|||||||
@@ -134,6 +134,8 @@ class Options(AttrMonitor):
|
|||||||
self.chmod_on_import = None
|
self.chmod_on_import = None
|
||||||
self.check_version = None
|
self.check_version = None
|
||||||
self.clear_workdir = None
|
self.clear_workdir = None
|
||||||
|
self.key_prefix = None
|
||||||
|
self.key_separator = None
|
||||||
|
|
||||||
# args parsing
|
# args parsing
|
||||||
self.args = {}
|
self.args = {}
|
||||||
@@ -223,8 +225,9 @@ class Options(AttrMonitor):
|
|||||||
self.conf = Cfg(self.confpath, self.profile, debug=self.debug,
|
self.conf = Cfg(self.confpath, self.profile, debug=self.debug,
|
||||||
dry=self.dry)
|
dry=self.dry)
|
||||||
# transform the config settings to self attribute
|
# transform the config settings to self attribute
|
||||||
debug_dict('effective settings', self.conf.get_settings(), self.debug)
|
settings = self.conf.get_settings()
|
||||||
for k, val in self.conf.get_settings().items():
|
debug_dict('effective settings', settings, self.debug)
|
||||||
|
for k, val in settings.items():
|
||||||
setattr(self, k, val)
|
setattr(self, k, val)
|
||||||
|
|
||||||
def _apply_args_files(self):
|
def _apply_args_files(self):
|
||||||
|
|||||||
@@ -48,6 +48,8 @@ class Settings(DictParser):
|
|||||||
key_check_version = 'check_version'
|
key_check_version = 'check_version'
|
||||||
key_clear_workdir = 'clear_workdir'
|
key_clear_workdir = 'clear_workdir'
|
||||||
key_compare_workdir = 'compare_workdir'
|
key_compare_workdir = 'compare_workdir'
|
||||||
|
key_key_prefix = 'key_prefix'
|
||||||
|
key_key_separator = 'key_separator'
|
||||||
|
|
||||||
# import keys
|
# import keys
|
||||||
key_import_actions = 'import_actions'
|
key_import_actions = 'import_actions'
|
||||||
@@ -69,7 +71,8 @@ class Settings(DictParser):
|
|||||||
ignore_missing_in_dotdrop=False,
|
ignore_missing_in_dotdrop=False,
|
||||||
force_chmod=False, chmod_on_import=False,
|
force_chmod=False, chmod_on_import=False,
|
||||||
check_version=False, clear_workdir=False,
|
check_version=False, clear_workdir=False,
|
||||||
compare_workdir=False):
|
compare_workdir=False, key_prefix=True,
|
||||||
|
key_separator='_'):
|
||||||
self.backup = backup
|
self.backup = backup
|
||||||
self.banner = banner
|
self.banner = banner
|
||||||
self.create = create
|
self.create = create
|
||||||
@@ -102,6 +105,8 @@ class Settings(DictParser):
|
|||||||
self.check_version = check_version
|
self.check_version = check_version
|
||||||
self.clear_workdir = clear_workdir
|
self.clear_workdir = clear_workdir
|
||||||
self.compare_workdir = compare_workdir
|
self.compare_workdir = compare_workdir
|
||||||
|
self.key_prefix = key_prefix
|
||||||
|
self.key_separator = key_separator
|
||||||
|
|
||||||
def _serialize_seq(self, name, dic):
|
def _serialize_seq(self, name, dic):
|
||||||
"""serialize attribute 'name' into 'dic'"""
|
"""serialize attribute 'name' into 'dic'"""
|
||||||
@@ -131,6 +136,8 @@ class Settings(DictParser):
|
|||||||
self.key_check_version: self.check_version,
|
self.key_check_version: self.check_version,
|
||||||
self.key_clear_workdir: self.clear_workdir,
|
self.key_clear_workdir: self.clear_workdir,
|
||||||
self.key_compare_workdir: self.compare_workdir,
|
self.key_compare_workdir: self.compare_workdir,
|
||||||
|
self.key_key_prefix: self.key_prefix,
|
||||||
|
self.key_key_separator: self.key_separator,
|
||||||
}
|
}
|
||||||
self._serialize_seq(self.key_default_actions, dic)
|
self._serialize_seq(self.key_default_actions, dic)
|
||||||
self._serialize_seq(self.key_import_actions, dic)
|
self._serialize_seq(self.key_import_actions, dic)
|
||||||
|
|||||||
@@ -246,7 +246,7 @@ def must_ignore(paths, ignores, debug=False):
|
|||||||
nign = nign[1:]
|
nign = nign[1:]
|
||||||
if debug:
|
if debug:
|
||||||
msg = 'trying to match :\"{}\" with non-ignore-pattern:\"{}\"'
|
msg = 'trying to match :\"{}\" with non-ignore-pattern:\"{}\"'
|
||||||
LOG.dbg(msg.format(path, nign))
|
LOG.dbg(msg.format(path, nign), force=True)
|
||||||
if fnmatch.fnmatch(path, nign):
|
if fnmatch.fnmatch(path, nign):
|
||||||
if debug:
|
if debug:
|
||||||
msg = 'negative ignore \"{}\" match: {}'.format(nign, path)
|
msg = 'negative ignore \"{}\" match: {}'.format(nign, path)
|
||||||
@@ -444,23 +444,23 @@ def debug_list(title, elems, debug):
|
|||||||
"""pretty print list"""
|
"""pretty print list"""
|
||||||
if not debug:
|
if not debug:
|
||||||
return
|
return
|
||||||
LOG.dbg('{}:'.format(title))
|
LOG.dbg('{}:'.format(title), force=debug)
|
||||||
for elem in elems:
|
for elem in elems:
|
||||||
LOG.dbg('\t- {}'.format(elem))
|
LOG.dbg('\t- {}'.format(elem), force=debug)
|
||||||
|
|
||||||
|
|
||||||
def debug_dict(title, elems, debug):
|
def debug_dict(title, elems, debug):
|
||||||
"""pretty print dict"""
|
"""pretty print dict"""
|
||||||
if not debug:
|
if not debug:
|
||||||
return
|
return
|
||||||
LOG.dbg('{}:'.format(title))
|
LOG.dbg('{}:'.format(title), force=debug)
|
||||||
for k, val in elems.items():
|
for k, val in elems.items():
|
||||||
if isinstance(val, list):
|
if isinstance(val, list):
|
||||||
LOG.dbg('\t- \"{}\":'.format(k))
|
LOG.dbg('\t- \"{}\":'.format(k), force=debug)
|
||||||
for i in val:
|
for i in val:
|
||||||
LOG.dbg('\t\t- {}'.format(i))
|
LOG.dbg('\t\t- {}'.format(i), force=debug)
|
||||||
else:
|
else:
|
||||||
LOG.dbg('\t- \"{}\": {}'.format(k, val))
|
LOG.dbg('\t- \"{}\": {}'.format(k, val), force=debug)
|
||||||
|
|
||||||
|
|
||||||
def check_version():
|
def check_version():
|
||||||
|
|||||||
119
tests-ng/key-prefix-sep.sh
Executable file
119
tests-ng/key-prefix-sep.sh
Executable file
@@ -0,0 +1,119 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# author: deadc0de6 (https://github.com/deadc0de6)
|
||||||
|
# Copyright (c) 2021, deadc0de6
|
||||||
|
#
|
||||||
|
# test key_prefix and key_separator
|
||||||
|
#
|
||||||
|
|
||||||
|
# exit on first error
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# all this crap to get current path
|
||||||
|
rl="readlink -f"
|
||||||
|
if ! ${rl} "${0}" >/dev/null 2>&1; then
|
||||||
|
rl="realpath"
|
||||||
|
|
||||||
|
if ! hash ${rl}; then
|
||||||
|
echo "\"${rl}\" not found !" && exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
cur=$(dirname "$(${rl} "${0}")")
|
||||||
|
|
||||||
|
#hash dotdrop >/dev/null 2>&1
|
||||||
|
#[ "$?" != "0" ] && echo "install dotdrop to run tests" && exit 1
|
||||||
|
|
||||||
|
#echo "called with ${1}"
|
||||||
|
|
||||||
|
# dotdrop path can be pass as argument
|
||||||
|
ddpath="${cur}/../"
|
||||||
|
[ "${1}" != "" ] && ddpath="${1}"
|
||||||
|
[ ! -d ${ddpath} ] && echo "ddpath \"${ddpath}\" is not a directory" && exit 1
|
||||||
|
|
||||||
|
export PYTHONPATH="${ddpath}:${PYTHONPATH}"
|
||||||
|
bin="python3 -m dotdrop.dotdrop"
|
||||||
|
hash coverage 2>/dev/null && bin="coverage run -a --source=dotdrop -m dotdrop.dotdrop" || true
|
||||||
|
|
||||||
|
echo "dotdrop path: ${ddpath}"
|
||||||
|
echo "pythonpath: ${PYTHONPATH}"
|
||||||
|
|
||||||
|
# get the helpers
|
||||||
|
source ${cur}/helpers
|
||||||
|
|
||||||
|
echo -e "$(tput setaf 6)==> RUNNING $(basename $BASH_SOURCE) <==$(tput sgr0)"
|
||||||
|
|
||||||
|
################################################################
|
||||||
|
# this is the test
|
||||||
|
################################################################
|
||||||
|
|
||||||
|
# the dotfile source
|
||||||
|
tmps=`mktemp -d --suffix='-dotdrop-tests' || mktemp -d`
|
||||||
|
mkdir -p ${tmps}/dotfiles
|
||||||
|
# the dotfile destination
|
||||||
|
tmpd=`mktemp -d --suffix='-dotdrop-tests' || mktemp -d`
|
||||||
|
#echo "dotfile destination: ${tmpd}"
|
||||||
|
|
||||||
|
clear_on_exit "${tmps}"
|
||||||
|
clear_on_exit "${tmpd}"
|
||||||
|
|
||||||
|
# create the dotfile
|
||||||
|
mkdir -p ${tmpd}/top
|
||||||
|
touch ${tmpd}/top/.colors
|
||||||
|
mkdir -p ${tmpd}/.mutt/sub
|
||||||
|
touch ${tmpd}/.mutt/sub/colors
|
||||||
|
|
||||||
|
# create the config file
|
||||||
|
cfg="${tmps}/config.yaml"
|
||||||
|
|
||||||
|
# normal behavior
|
||||||
|
cat > ${cfg} << _EOF
|
||||||
|
config:
|
||||||
|
backup: true
|
||||||
|
create: true
|
||||||
|
dotpath: dotfiles
|
||||||
|
longkey: true
|
||||||
|
key_prefix: true
|
||||||
|
key_separator: '_'
|
||||||
|
dotfiles:
|
||||||
|
profiles:
|
||||||
|
_EOF
|
||||||
|
|
||||||
|
# import
|
||||||
|
cd ${ddpath} | ${bin} import -c ${cfg} -p p1 -V ${tmpd}/top/.colors
|
||||||
|
cd ${ddpath} | ${bin} import -c ${cfg} -p p1 -V ${tmpd}/.mutt/sub
|
||||||
|
|
||||||
|
cd ${ddpath} | ${bin} files -c ${cfg} -p p1 -G | cut -f1 -d',' | grep -q '_top_colors'
|
||||||
|
cd ${ddpath} | ${bin} files -c ${cfg} -p p1 -G | cut -f1 -d',' | grep -q '_mutt_sub'
|
||||||
|
|
||||||
|
cd ${ddpath} | ${bin} files -c ${cfg} -p p1 -G | cut -f1 -d',' | grep '_top_colors' | grep -q 'f_'
|
||||||
|
cd ${ddpath} | ${bin} files -c ${cfg} -p p1 -G | cut -f1 -d',' | grep '_mutt_sub' | grep -q 'd_'
|
||||||
|
|
||||||
|
# pimping
|
||||||
|
rm -rf ${tmps}/*
|
||||||
|
|
||||||
|
cat > ${cfg} << _EOF
|
||||||
|
config:
|
||||||
|
backup: true
|
||||||
|
create: true
|
||||||
|
dotpath: dotfiles
|
||||||
|
longkey: true
|
||||||
|
key_prefix: false
|
||||||
|
key_separator: '+'
|
||||||
|
dotfiles:
|
||||||
|
profiles:
|
||||||
|
_EOF
|
||||||
|
|
||||||
|
# import
|
||||||
|
cd ${ddpath} | ${bin} import -c ${cfg} -p p1 -V ${tmpd}/top/.colors
|
||||||
|
cd ${ddpath} | ${bin} import -c ${cfg} -p p1 -V ${tmpd}/.mutt/sub
|
||||||
|
|
||||||
|
cat ${cfg}
|
||||||
|
cd ${ddpath} | ${bin} files -c ${cfg} -p p1 -G
|
||||||
|
|
||||||
|
cd ${ddpath} | ${bin} files -c ${cfg} -p p1 -G | cut -f1 -d',' | grep -q '+top+colors'
|
||||||
|
cd ${ddpath} | ${bin} files -c ${cfg} -p p1 -G | cut -f1 -d',' | grep -q '+mutt+sub'
|
||||||
|
|
||||||
|
cd ${ddpath} | ${bin} files -c ${cfg} -p p1 -G | cut -f1 -d',' | grep '+top+colors' | grep -qv 'f_'
|
||||||
|
cd ${ddpath} | ${bin} files -c ${cfg} -p p1 -G | cut -f1 -d',' | grep '+mutt+sub' | grep -qv 'd_'
|
||||||
|
|
||||||
|
echo "OK"
|
||||||
|
exit 0
|
||||||
Reference in New Issue
Block a user