diff --git a/docs/config-format.md b/docs/config-format.md index 5d32131..666e5a3 100644 --- a/docs/config-format.md +++ b/docs/config-format.md @@ -31,6 +31,7 @@ Entry | Description | Default `longkey` | use long keys for dotfiles when importing (see [Import dotfiles](usage.md#import-dotfiles)) | false `minversion` | (*for internal use, do not modify*) provides the minimal dotdrop version to use | - `showdiff` | on install show a diff before asking to overwrite (see `--showdiff`) | false +`template_dotfile_default` | disable templating on all dotfiles when set to false | true `upignore` | list of patterns to ignore when updating, apply to all dotfiles (enclose in quotes when using wildcards, see [ignore patterns](config.md#ignore-patterns)) | - `workdir` | path to the directory where templates are installed before being symlinked when using `link:link` or `link:link_children` (absolute path or relative to the config file location) | `~/.config/dotdrop` link_by_default | when importing a dotfile set `link` to that value per default | false @@ -48,6 +49,7 @@ Entry | Description `cmpignore` | list of patterns to ignore when comparing (enclose in quotes when using wildcards, see [ignore patterns](config.md#ignore-patterns)) `ignoreempty` | if true empty template will not be deployed (defaults to value of `ignoreempty`) `instignore` | list of patterns to ignore when installing (enclose in quotes when using wildcards, see [ignore patterns](config.md#ignore-patterns)) +`template` | if false disable template for this dotfile (defaults to value of `template_dotfile_default`) `trans_read` | transformation key to apply when installing this dotfile (must be defined in the **trans_read** entry below, see [transformations](config-details.md#entry-transformations)) `trans_write` | transformation key to apply when updating this dotfile (must be defined in the **trans_write** entry below, see [transformations](config-details.md#entry-transformations)) `upignore` | list of patterns to ignore when updating (enclose in quotes when using wildcards, see [ignore patterns](config.md#ignore-patterns)) @@ -69,6 +71,7 @@ Entry | Description - "" actions: - + template: (true|false) trans_read: trans_write: ``` diff --git a/docs/howto/symlink-dotfiles.md b/docs/howto/symlink-dotfiles.md index 47bf442..bf12068 100644 --- a/docs/howto/symlink-dotfiles.md +++ b/docs/howto/symlink-dotfiles.md @@ -13,8 +13,8 @@ Note that if the dotfile is using template directives, it will be symlinked into `~/.config/dotdrop` instead of directly into your *dotpath* (see [Templating symlinked dotfiles](#templating-symlinked-dotfiles)) -Although the config entries `link_on_import` and `link_dotfile_default` can be set to `link_children`, it -is not recommended since operations on a dotfile that is not a directory with the option `link_children` +Although the config entries `link_on_import` and `link_dotfile_default` can be set to the value `link_children`, +it is not recommended since operations on a dotfile that is not a directory with the option `link_children` will fail. ## Symlink a dotfile diff --git a/docs/templating.md b/docs/templating.md index 975f9c2..18de338 100644 --- a/docs/templating.md +++ b/docs/templating.md @@ -4,6 +4,19 @@ Dotdrop leverage the power of [jinja2](https://palletsprojects.com/p/jinja/) to templating of dotfiles. See [jinja2 template doc](https://jinja.palletsprojects.com/en/2.11.x/templates/) or the below sections for more information on how to template your dotfiles. +## Templating or not templating + +The dotfile config entry [template](config-format.md#dotfiles-entry) +and the global config entry [template_dotfile_default](config-format.md#config-entry) +allow to control if a dotfile is being process by the templating engine. + +Obviously if the dotfile uses template directives, it needs to be templated. However if it +is not, disabling templating will speed up its installation (since it won't have to be +processed by the engine). + +For dotfiles being symlinked (`link` or `link_children`), see +[the dedicated doc](howto/symlink-dotfiles.md#templating-symlinked-dotfiles) + ## Delimiters Dotdrop uses different delimiters than diff --git a/dotdrop/cfg_yaml.py b/dotdrop/cfg_yaml.py index 7ab5fa1..83255ea 100644 --- a/dotdrop/cfg_yaml.py +++ b/dotdrop/cfg_yaml.py @@ -57,6 +57,7 @@ class CfgYaml: key_dotfile_link = 'link' key_dotfile_actions = 'actions' key_dotfile_noempty = 'ignoreempty' + key_dotfile_template = 'template' # profile key_profile_dotfiles = 'dotfiles' @@ -82,6 +83,7 @@ class CfgYaml: key_settings_noempty = Settings.key_ignoreempty key_settings_minversion = Settings.key_minversion key_imp_link = Settings.key_link_on_import + key_settings_template = Settings.key_template_dotfile_default # link values lnk_nolink = LinkTypes.NOLINK.name.lower() @@ -610,6 +612,11 @@ class CfgYaml: if self.key_dotfile_noempty not in v: val = self.settings.get(self.key_settings_noempty, False) v[self.key_dotfile_noempty] = val + # apply template if undefined + if self.key_dotfile_template not in v: + val = self.settings.get(self.key_settings_template, True) + v[self.key_dotfile_template] = val + return new def _add_variables(self, new, shell=False, template=True, prio=False): diff --git a/dotdrop/dotdrop.py b/dotdrop/dotdrop.py index 26b4707..366aa57 100644 --- a/dotdrop/dotdrop.py +++ b/dotdrop/dotdrop.py @@ -129,11 +129,13 @@ def cmd_install(o): LOG.dbg(dotfile.prt()) if hasattr(dotfile, 'link') and dotfile.link == LinkTypes.LINK: r, err = inst.link(t, dotfile.src, dotfile.dst, - actionexec=pre_actions_exec) + actionexec=pre_actions_exec, + template=dotfile.template) elif hasattr(dotfile, 'link') and \ dotfile.link == LinkTypes.LINK_CHILDREN: r, err = inst.link_children(t, dotfile.src, dotfile.dst, - actionexec=pre_actions_exec) + actionexec=pre_actions_exec, + template=dotfile.template) else: src = dotfile.src tmp = None @@ -147,7 +149,8 @@ def cmd_install(o): r, err = inst.install(t, src, dotfile.dst, actionexec=pre_actions_exec, noempty=dotfile.noempty, - ignore=ignores) + ignore=ignores, + template=dotfile.template) if tmp: tmp = os.path.join(o.dotpath, tmp) if os.path.exists(tmp): @@ -264,7 +267,8 @@ def cmd_compare(o, tmp): continue # install dotfile to temporary dir and compare - ret, err, insttmp = inst.install_to_temp(t, tmp, src, dotfile.dst) + ret, err, insttmp = inst.install_to_temp(t, tmp, src, dotfile.dst, + template=dotfile.template) if not ret: # failed to install to tmp line = '=> compare {}: error' @@ -737,9 +741,14 @@ def main(): LOG.err('interrupted') ret = False + if o.debug: + LOG.dbg('done executing command') + if ret and o.conf.save(): LOG.log('config file updated') + if o.debug: + LOG.dbg('return {}'.format(ret)) return ret diff --git a/dotdrop/dotfile.py b/dotdrop/dotfile.py index ae2025c..da7890d 100644 --- a/dotdrop/dotfile.py +++ b/dotdrop/dotfile.py @@ -16,12 +16,13 @@ class Dotfile(DictParser): key_noempty = 'ignoreempty' key_trans_r = 'trans_read' key_trans_w = 'trans_write' + key_template = 'template' def __init__(self, key, dst, src, actions=[], trans_r=None, trans_w=None, link=LinkTypes.NOLINK, noempty=False, cmpignore=[], upignore=[], - instignore=[]): + instignore=[], template=True): """ constructor @key: dotfile key @@ -35,6 +36,7 @@ class Dotfile(DictParser): @upignore: patterns to ignore when updating @cmpignore: patterns to ignore when comparing @instignore: patterns to ignore when installing + @template: template this dotfile """ self.actions = actions self.dst = dst @@ -47,6 +49,7 @@ class Dotfile(DictParser): self.upignore = upignore self.cmpignore = cmpignore self.instignore = instignore + self.template = template if self.link != LinkTypes.NOLINK and \ ( @@ -91,6 +94,7 @@ class Dotfile(DictParser): value['noempty'] = value.get(cls.key_noempty, False) value['trans_r'] = value.get(cls.key_trans_r) value['trans_w'] = value.get(cls.key_trans_w) + value['template'] = value.get(cls.key_template, True) # remove old entries value.pop(cls.key_noempty, None) value.pop(cls.key_trans_r, None) @@ -104,8 +108,12 @@ class Dotfile(DictParser): return hash(self.dst) ^ hash(self.src) ^ hash(self.key) def __str__(self): - msg = 'key:\"{}\", src:\"{}\", dst:\"{}\", link:\"{}\"' - return msg.format(self.key, self.src, self.dst, str(self.link)) + msg = 'key:\"{}\"'.format(self.key) + msg += ', src:\"{}\"'.format(self.src) + msg += ', dst:\"{}\"'.format(self.dst) + msg += ', link:\"{}\"'.format(str(self.link)) + msg += ', template:{}'.format(self.template) + return msg def prt(self): """extended dotfile to str""" @@ -114,6 +122,7 @@ class Dotfile(DictParser): out += '\n{}src: \"{}\"'.format(indent, self.src) out += '\n{}dst: \"{}\"'.format(indent, self.dst) out += '\n{}link: \"{}\"'.format(indent, str(self.link)) + out += '\n{}template: \"{}\"'.format(indent, str(self.template)) out += '\n{}pre-action:'.format(indent) some = self.get_pre_actions() diff --git a/dotdrop/installer.py b/dotdrop/installer.py index ef0e0a9..6f1cb73 100644 --- a/dotdrop/installer.py +++ b/dotdrop/installer.py @@ -7,6 +7,7 @@ handle the installation of dotfiles import os import errno +import shutil # local imports from dotdrop.logger import Logger @@ -65,7 +66,7 @@ class Installer: def install(self, templater, src, dst, actionexec=None, noempty=False, - ignore=[]): + ignore=[], template=True): """ install src to dst using a template @templater: the templater object @@ -74,6 +75,7 @@ class Installer: @actionexec: action executor callback @noempty: render empty template flag @ignore: pattern to ignore when installing + @template: template this dotfile return - True, None : success @@ -103,22 +105,25 @@ class Installer: self.log.dbg('install {} to {}'.format(src, dst)) self.log.dbg('is a directory \"{}\": {}'.format(src, isdir)) if isdir: - b, e = self._handle_dir(templater, src, dst, - actionexec=actionexec, - noempty=noempty, ignore=ignore) + b, e = self._install_dir(templater, src, dst, + actionexec=actionexec, + noempty=noempty, ignore=ignore, + template=template) return self._log_install(b, e) - b, e = self._handle_file(templater, src, dst, - actionexec=actionexec, - noempty=noempty, ignore=ignore) + b, e = self._install_file(templater, src, dst, + actionexec=actionexec, + noempty=noempty, ignore=ignore, + template=template) return self._log_install(b, e) - def link(self, templater, src, dst, actionexec=None): + def link(self, templater, src, dst, actionexec=None, template=True): """ set src as the link target of dst @templater: the templater @src: dotfile source path in dotpath @dst: dotfile destination path in the FS @actionexec: action executor callback + @template: template this dotfile return - True, None : success @@ -140,28 +145,32 @@ class Installer: dst = os.path.normpath(os.path.expanduser(dst)) if self.totemp: # ignore actions - b, e = self.install(templater, src, dst, actionexec=None) + b, e = self.install(templater, src, dst, actionexec=None, + template=template) return self._log_install(b, e) - if Templategen.is_template(src): + if template and Templategen.is_template(src): if self.debug: self.log.dbg('dotfile is a template') self.log.dbg('install to {} and symlink'.format(self.workdir)) tmp = self._pivot_path(dst, self.workdir, striphome=True) - i, err = self.install(templater, src, tmp, actionexec=actionexec) + i, err = self.install(templater, src, tmp, actionexec=actionexec, + template=template) if not i and not os.path.exists(tmp): return self._log_install(i, err) src = tmp b, e = self._link(src, dst, actionexec=actionexec) return self._log_install(b, e) - def link_children(self, templater, src, dst, actionexec=None): + def link_children(self, templater, src, dst, actionexec=None, + template=True): """ - link all dotfiles in a given directory + link all files under a given directory @templater: the templater @src: dotfile source path in dotpath @dst: dotfile destination path in the FS @actionexec: action executor callback + @template: template this dotfile return - True, None: success @@ -221,13 +230,14 @@ class Installer: if self.debug: self.log.dbg('symlink child {} to {}'.format(src, dst)) - if Templategen.is_template(src): + if template and Templategen.is_template(src): if self.debug: self.log.dbg('dotfile is a template') self.log.dbg('install to {} and symlink' .format(self.workdir)) tmp = self._pivot_path(dst, self.workdir, striphome=True) - r, e = self.install(templater, src, tmp, actionexec=actionexec) + r, e = self.install(templater, src, tmp, actionexec=actionexec, + template=template) if not r and e and not os.path.exists(tmp): continue src = tmp @@ -264,7 +274,7 @@ class Installer: self.log.dry('would remove {} and link to {}'.format(dst, src)) return True, None if self.showdiff: - self._diff_before_write(src, dst) + self._diff_before_write(src, dst, quiet=False) msg = 'Remove "{}" for link creation?'.format(dst) if self.safe and not self.log.ask(msg): err = 'ignoring "{}", link was not created'.format(dst) @@ -306,14 +316,16 @@ class Installer: tmp['_dotfile_sub_abs_dst'] = dst return tmp - def _handle_file(self, templater, src, dst, - actionexec=None, noempty=False, - ignore=[]): + def _install_file(self, templater, src, dst, + actionexec=None, noempty=False, + ignore=[], template=True): """install src to dst when is a file""" if self.debug: - self.log.dbg('generate template for {}'.format(src)) + self.log.dbg('deploy file: {}'.format(src)) self.log.dbg('ignore empty: {}'.format(noempty)) self.log.dbg('ignore pattern: {}'.format(ignore)) + self.log.dbg('template: {}'.format(template)) + self.log.dbg('no empty: {}'.format(noempty)) if utils.must_ignore([src, dst], ignore, debug=self.debug): if self.debug: @@ -324,42 +336,55 @@ class Installer: # symlink loop err = 'dotfile points to itself: {}'.format(dst) return False, err - saved = templater.add_tmp_vars(self._get_tmp_file_vars(src, dst)) - try: - content = templater.generate(src) - except UndefinedException as e: - return False, str(e) - finally: - templater.restore_vars(saved) - if noempty and utils.content_empty(content): - if self.debug: - self.log.dbg('ignoring empty template: {}'.format(src)) - return False, None - if content is None: - err = 'empty template {}'.format(src) - return False, err + if not os.path.exists(src): err = 'source dotfile does not exist: {}'.format(src) return False, err - st = os.stat(src) - ret, err = self._write(src, dst, content, - st.st_mode, actionexec=actionexec) + + # handle the file + content = None + if template: + # template the file + saved = templater.add_tmp_vars(self._get_tmp_file_vars(src, dst)) + try: + content = templater.generate(src) + except UndefinedException as e: + return False, str(e) + finally: + templater.restore_vars(saved) + if noempty and utils.content_empty(content): + if self.debug: + self.log.dbg('ignoring empty template: {}'.format(src)) + return False, None + if content is None: + err = 'empty template {}'.format(src) + return False, err + ret, err = self._write(src, dst, + content=content, + actionexec=actionexec, + template=template) + + # build return values if ret < 0: + # error return False, err if ret > 0: + # already exists if self.debug: self.log.dbg('ignoring {}'.format(dst)) return False, None if ret == 0: + # success if not self.dry and not self.comparing: self.log.sub('copied {} to {}'.format(src, dst)) return True, None + # error err = 'installing {} to {}'.format(src, dst) return False, err - def _handle_dir(self, templater, src, dst, - actionexec=None, noempty=False, - ignore=[]): + def _install_dir(self, templater, src, dst, + actionexec=None, noempty=False, + ignore=[], template=True): """install src to dst when is a directory""" if self.debug: self.log.dbg('install dir {}'.format(src)) @@ -374,11 +399,12 @@ class Installer: f = os.path.join(src, entry) if not os.path.isdir(f): # is file - res, err = self._handle_file(templater, f, - os.path.join(dst, entry), - actionexec=actionexec, - noempty=noempty, - ignore=ignore) + res, err = self._install_file(templater, f, + os.path.join(dst, entry), + actionexec=actionexec, + noempty=noempty, + ignore=ignore, + template=template) if not res and err: # error occured ret = res, err @@ -388,11 +414,12 @@ class Installer: ret = True, None else: # is directory - res, err = self._handle_dir(templater, f, - os.path.join(dst, entry), - actionexec=actionexec, - noempty=noempty, - ignore=ignore) + res, err = self._install_dir(templater, f, + os.path.join(dst, entry), + actionexec=actionexec, + noempty=noempty, + ignore=ignore, + template=template) if not res and err: # error occured ret = res, err @@ -403,22 +430,31 @@ class Installer: return ret def _fake_diff(self, dst, content): - """fake diff by comparing file content with content""" + """ + fake diff by comparing file content with content + returns True if same + """ cur = '' with open(dst, 'br') as f: cur = f.read() return cur == content - def _write(self, src, dst, content, rights, actionexec=None): - """write content to file + def _write(self, src, dst, content=None, + actionexec=None, template=True): + """ + copy dotfile / write content to file return 0, None: for success, 1, None: when already exists - -1, err: when error""" + -1, err: when error + content is always empty if template is False + and is to be ignored + """ overwrite = not self.safe if self.dry: self.log.dry('would install {}'.format(dst)) return 0, None if os.path.lexists(dst): + rights = os.stat(src).st_mode samerights = False try: samerights = os.stat(dst).st_mode == rights @@ -427,15 +463,26 @@ class Installer: # broken symlink err = 'broken symlink {}'.format(dst) return -1, err - if self.diff and self._fake_diff(dst, content) and samerights: - if self.debug: - self.log.dbg('{} is the same'.format(dst)) - return 1, None + diff = None + if self.diff: + diff = self._diff_before_write(src, dst, + content=content, + quiet=True) + if not diff and samerights: + if self.debug: + self.log.dbg('{} is the same'.format(dst)) + return 1, None if self.safe: if self.debug: self.log.dbg('change detected for {}'.format(dst)) if self.showdiff: - self._diff_before_write(src, dst, content=content) + if diff is None: + # get diff + diff = self._diff_before_write(src, dst, + content=content, + quiet=True) + if diff: + self._print_diff(src, dst, diff) if not self.log.ask('Overwrite \"{}\"'.format(dst)): self.log.warn('ignoring {}'.format(dst)) return 1, None @@ -450,24 +497,39 @@ class Installer: if not r: return -1, e if self.debug: - self.log.dbg('writes content to \"{}\"'.format(dst)) + self.log.dbg('install dotfile to \"{}\"'.format(dst)) # re-check in case action created the file if self.safe and not overwrite and os.path.lexists(dst): if not self.log.ask('Overwrite \"{}\"'.format(dst)): self.log.warn('ignoring {}'.format(dst)) return 1, None - # write the file - try: - with open(dst, 'wb') as f: - f.write(content) - except NotADirectoryError as e: - err = 'opening dest file: {}'.format(e) - return -1, err - os.chmod(dst, rights) + + if template: + # write content the file + try: + with open(dst, 'wb') as f: + f.write(content) + shutil.copymode(src, dst) + except NotADirectoryError as e: + err = 'opening dest file: {}'.format(e) + return -1, err + except Exception as e: + return -1, str(e) + else: + # copy file + try: + shutil.copyfile(src, dst) + shutil.copymode(src, dst) + except Exception as e: + return -1, str(e) return 0, None - def _diff_before_write(self, src, dst, content=None): - """diff before writing when using --showdiff - not efficient""" + def _diff_before_write(self, src, dst, content=None, quiet=False): + """ + diff before writing + using a temp file if content is not None + returns diff string ('' if same) + """ tmp = None if content: tmp = utils.write_to_tmpfile(content) @@ -477,9 +539,12 @@ class Installer: if tmp: utils.remove(tmp, quiet=True) - # fake the output for readability - if not diff: - return + if not quiet and diff: + self._print_diff(src, dst, diff) + return diff + + def _print_diff(self, src, dst, diff): + """show diff to user""" self.log.log('diff \"{}\" VS \"{}\"'.format(dst, src)) self.log.emph(diff) @@ -530,12 +595,13 @@ class Installer: self.action_executed = True return ret, err - def _install_to_temp(self, templater, src, dst, tmpdir): + def _install_to_temp(self, templater, src, dst, tmpdir, template=True): """install a dotfile to a tempdir""" tmpdst = self._pivot_path(dst, tmpdir) - return self.install(templater, src, tmpdst), tmpdst + r = self.install(templater, src, tmpdst, template=template) + return r, tmpdst - def install_to_temp(self, templater, tmpdir, src, dst): + def install_to_temp(self, templater, tmpdir, src, dst, template=True): """install a dotfile to a tempdir""" ret = False tmpdst = '' @@ -553,7 +619,8 @@ class Installer: if self.debug: self.log.dbg('tmp install {} (defined dst: {})'.format(src, dst)) # install the dotfile to a temp directory for comparing - r, tmpdst = self._install_to_temp(templater, src, dst, tmpdir) + r, tmpdst = self._install_to_temp(templater, src, dst, tmpdir, + template=template) ret, err = r if self.debug: self.log.dbg('tmp installed in {}'.format(tmpdst)) diff --git a/dotdrop/settings.py b/dotdrop/settings.py index 264ccc2..64d0853 100644 --- a/dotdrop/settings.py +++ b/dotdrop/settings.py @@ -34,6 +34,7 @@ class Settings(DictParser): key_func_file = 'func_file' key_filter_file = 'filter_file' key_diff_command = 'diff_command' + key_template_dotfile_default = 'template_dotfile_default' # import keys key_import_actions = 'import_actions' @@ -49,7 +50,8 @@ class Settings(DictParser): upignore=[], cmpignore=[], instignore=[], workdir='~/.config/dotdrop', showdiff=False, minversion=None, func_file=[], filter_file=[], - diff_command='diff -r -u {0} {1}'): + diff_command='diff -r -u {0} {1}', + template_dotfile_default=True): self.backup = backup self.banner = banner self.create = create @@ -72,6 +74,7 @@ class Settings(DictParser): self.func_file = func_file self.filter_file = filter_file self.diff_command = diff_command + self.template_dotfile_default = template_dotfile_default def _serialize_seq(self, name, dic): """serialize attribute 'name' into 'dic'""" @@ -94,6 +97,7 @@ class Settings(DictParser): self.key_workdir: self.workdir, self.key_minversion: self.minversion, self.key_diff_command: self.diff_command, + self.key_template_dotfile_default: self.template_dotfile_default, } self._serialize_seq(self.key_default_actions, dic) self._serialize_seq(self.key_import_actions, dic) diff --git a/dotdrop/utils.py b/dotdrop/utils.py index 705c3fc..61f3d44 100644 --- a/dotdrop/utils.py +++ b/dotdrop/utils.py @@ -71,7 +71,7 @@ def shell(cmd, debug=False): def diff(original, modified, raw=True, diff_cmd='', debug=False): - """compare two files""" + """compare two files, returns '' if same""" if not diff_cmd: diff_cmd = 'diff -r -u {0} {1}' diff --git a/tests-ng/compare-ignore-relative.sh b/tests-ng/compare-ignore-relative.sh index a8c1260..4b9278c 100755 --- a/tests-ng/compare-ignore-relative.sh +++ b/tests-ng/compare-ignore-relative.sh @@ -7,7 +7,7 @@ # # exit on first error -#set -e +set -e # all this crap to get current path rl="readlink -f" diff --git a/tests-ng/compare-ignore.sh b/tests-ng/compare-ignore.sh index 53d86c9..cf162c4 100755 --- a/tests-ng/compare-ignore.sh +++ b/tests-ng/compare-ignore.sh @@ -7,7 +7,7 @@ # # exit on first error -#set -e +set -e # all this crap to get current path rl="readlink -f" diff --git a/tests-ng/corner-case.sh b/tests-ng/corner-case.sh index 1bc4e2a..bea39c1 100755 --- a/tests-ng/corner-case.sh +++ b/tests-ng/corner-case.sh @@ -12,7 +12,7 @@ # # exit on first error -#set -e +set -e # all this crap to get current path rl="readlink -f" diff --git a/tests-ng/diff-cmd.sh b/tests-ng/diff-cmd.sh index b09378d..166135d 100755 --- a/tests-ng/diff-cmd.sh +++ b/tests-ng/diff-cmd.sh @@ -7,7 +7,7 @@ # # exit on first error -#set -e +set -e # all this crap to get current path rl="readlink -f" diff --git a/tests-ng/global-compare-ignore.sh b/tests-ng/global-compare-ignore.sh index 056be9a..5f9ef10 100755 --- a/tests-ng/global-compare-ignore.sh +++ b/tests-ng/global-compare-ignore.sh @@ -7,7 +7,7 @@ # # exit on first error -#set -e +set -e # all this crap to get current path rl="readlink -f" diff --git a/tests-ng/global-update-ignore.sh b/tests-ng/global-update-ignore.sh index 5a387a6..4983d96 100755 --- a/tests-ng/global-update-ignore.sh +++ b/tests-ng/global-update-ignore.sh @@ -7,7 +7,7 @@ # # exit on first error -#set -e +set -e # all this crap to get current path rl="readlink -f" diff --git a/tests-ng/install-ignore.sh b/tests-ng/install-ignore.sh index 9651338..fd62890 100755 --- a/tests-ng/install-ignore.sh +++ b/tests-ng/install-ignore.sh @@ -7,7 +7,7 @@ # # exit on first error -#set -e +set -e # all this crap to get current path rl="readlink -f" diff --git a/tests-ng/notemplate.sh b/tests-ng/notemplate.sh new file mode 100755 index 0000000..4e5a72c --- /dev/null +++ b/tests-ng/notemplate.sh @@ -0,0 +1,286 @@ +#!/usr/bin/env bash +# author: deadc0de6 (https://github.com/deadc0de6) +# Copyright (c) 2020, deadc0de6 +# +# test notemplate +# returns 1 in case of error +# + +# 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 +#echo "dotfile source: ${tmps}" +# the dotfile destination +tmpd=`mktemp -d --suffix='-dotdrop-tests' || mktemp -d` +#echo "dotfile destination: ${tmpd}" + +# create the config file +cfg="${tmps}/config.yaml" + +# globally +cat > ${cfg} << _EOF +config: + backup: true + create: true + dotpath: dotfiles + template_dotfile_default: false +dotfiles: + f_f1: + dst: ${tmpd}/f1 + src: f1 + d_d1: + dst: ${tmpd}/dir1 + src: dir1 + d_d2: + dst: ${tmpd}/dir2 + src: dir2 + link: link + d_d3: + dst: ${tmpd}/dir3 + src: dir3 + link: link_children + f_fl: + dst: ${tmpd}/fl + src: fl + link: link + f_fn: + dst: ${tmpd}/fn + src: fn + template: true +profiles: + p1: + dotfiles: + - f_f1 + - d_d1 + - d_d2 + - d_d3 + - f_fl + - f_fn +_EOF +#cat ${cfg} + +# create the dotfile +echo "before" > ${tmps}/dotfiles/f1 +echo "{#@@ should not be stripped @@#}" >> ${tmps}/dotfiles/f1 +echo "{{@@ header() @@}}" >> ${tmps}/dotfiles/f1 +echo "after" >> ${tmps}/dotfiles/f1 + +# create the directory +mkdir -p ${tmps}/dotfiles/dir1/d1 +echo "{{@@ header() @@}}" > ${tmps}/dotfiles/dir1/d1/f2 + +# create the linked directory +mkdir -p ${tmps}/dotfiles/dir2/d1 +echo "{{@@ header() @@}}" > ${tmps}/dotfiles/dir2/d1/f2 + +# create the link_children directory +mkdir -p ${tmps}/dotfiles/dir3/{s1,s2,s3} +echo "{{@@ header() @@}}" > ${tmps}/dotfiles/dir3/s1/f1 +echo "{{@@ header() @@}}" > ${tmps}/dotfiles/dir3/s2/f2 + +# create the linked dotfile +echo "{{@@ header() @@}}" > ${tmps}/dotfiles/fl + +# create the normal dotfile +echo "before" > ${tmps}/dotfiles/fn +echo "{#@@ should not be stripped @@#}" >> ${tmps}/dotfiles/fn +echo "after" >> ${tmps}/dotfiles/fn + +# install +cd ${ddpath} | ${bin} install -f --showdiff -c ${cfg} -p p1 -V +cd ${ddpath} | ${bin} compare -c ${cfg} -p p1 -V + +# simple file +echo "doing globally" +echo "* test simple file" +[ ! -e ${tmpd}/f1 ] && echo 'not installed1' && exit 1 +grep 'header' ${tmpd}/f1 || (echo "header stripped" && exit 1) +grep 'should not be stripped' ${tmpd}/f1 || (echo "comment stripped" && exit 1) + +# directory +echo "* test directory" +[ ! -d ${tmpd}/dir1 ] && echo 'not installed1' && exit 1 +[ ! -d ${tmpd}/dir1/d1 ] && echo 'not installed2' && exit 1 +[ ! -e ${tmpd}/dir1/d1/f2 ] && echo 'not installed3' && exit 1 +grep 'header' ${tmpd}/dir1/d1/f2 || (echo "header stripped" && exit 1) + +# linked directory +echo "* test linked directory" +[ ! -h ${tmpd}/dir2 ] && echo 'not installed1' && exit 1 +[ ! -d ${tmpd}/dir2/d1 ] && echo 'not installed2' && exit 1 +[ ! -e ${tmpd}/dir2/d1/f2 ] && echo 'not installed3' && exit 1 +grep 'header' ${tmpd}/dir2/d1/f2 || (echo "header stripped" && exit 1) + +# children_link directory +echo "* test link_children directory" +[ ! -d ${tmpd}/dir3 ] && echo 'not installed1' && exit 1 +[ ! -h ${tmpd}/dir3/s1 ] && echo 'not installed2' && exit 1 +[ ! -h ${tmpd}/dir3/s2 ] && echo 'not installed3' && exit 1 +[ ! -h ${tmpd}/dir3/s3 ] && echo 'not installed4' && exit 1 +[ ! -e ${tmpd}/dir3/s1/f1 ] && echo 'not installed5' && exit 1 +[ ! -e ${tmpd}/dir3/s2/f2 ] && echo 'not installed6' && exit 1 +grep 'header' ${tmpd}/dir3/s1/f1 || (echo "header stripped" && exit 1) +grep 'header' ${tmpd}/dir3/s2/f2 || (echo "header stripped" && exit 1) + +# linked file +echo "* test linked file" +[ ! -h ${tmpd}/fl ] && echo 'not installed' && exit 1 +grep 'header' ${tmpd}/f1 || (echo "header stripped" && exit 1) + +# normal dotfile +echo "* normal dotfile" +[ ! -e ${tmpd}/fn ] && echo 'not installed' && exit 1 +grep 'should not be stripped' ${tmpd}/fn && echo "no templated" && exit 1 + +# test backup done +echo "before" > ${tmps}/dotfiles/f1 +cd ${ddpath} | ${bin} install -f --showdiff -c ${cfg} -p p1 -V +[ ! -e ${tmpd}/f1.dotdropbak ] && echo "backup not done" && exit 1 + +# re-create the dotfile +echo "before" > ${tmps}/dotfiles/f1 +echo "{#@@ should not be stripped @@#}" >> ${tmps}/dotfiles/f1 +echo "{{@@ header() @@}}" >> ${tmps}/dotfiles/f1 +echo "after" >> ${tmps}/dotfiles/f1 + +# through the dotfile +cat > ${cfg} << _EOF +config: + backup: true + create: true + dotpath: dotfiles + template_dotfile_default: true +dotfiles: + f_f1: + dst: ${tmpd}/f1 + src: f1 + template: false + d_d1: + dst: ${tmpd}/dir1 + src: dir1 + template: false + d_d2: + dst: ${tmpd}/dir2 + src: dir2 + link: link + template: false + d_d3: + dst: ${tmpd}/dir3 + src: dir3 + link: link_children + template: false + f_fl: + dst: ${tmpd}/fl + src: fl + link: link + template: false + f_fn: + dst: ${tmpd}/fn + src: fn +profiles: + p1: + dotfiles: + - f_f1 + - d_d1 + - d_d2 + - d_d3 + - f_fl + - f_fn +_EOF +#cat ${cfg} + +# clean destination +rm -rf ${tmpd}/* + +# install +cd ${ddpath} | ${bin} install -f --showdiff -c ${cfg} -p p1 -V +cd ${ddpath} | ${bin} compare -c ${cfg} -p p1 -V + +# simple file +echo "doing specifically" +echo "* test simple file" +[ ! -e ${tmpd}/f1 ] && echo 'not installed1' && exit 1 +grep 'header' ${tmpd}/f1 || (echo "header stripped" && exit 1) +grep 'should not be stripped' ${tmpd}/f1 || (echo "comment stripped" && exit 1) + +# directory +echo "* test directory" +[ ! -d ${tmpd}/dir1 ] && echo 'not installed1' && exit 1 +[ ! -d ${tmpd}/dir1/d1 ] && echo 'not installed2' && exit 1 +[ ! -e ${tmpd}/dir1/d1/f2 ] && echo 'not installed3' && exit 1 +grep 'header' ${tmpd}/dir1/d1/f2 || (echo "header stripped" && exit 1) + +# linked directory +echo "* test linked directory" +[ ! -h ${tmpd}/dir2 ] && echo 'not installed1' && exit 1 +[ ! -d ${tmpd}/dir2/d1 ] && echo 'not installed2' && exit 1 +[ ! -e ${tmpd}/dir2/d1/f2 ] && echo 'not installed3' && exit 1 +grep 'header' ${tmpd}/dir2/d1/f2 || (echo "header stripped" && exit 1) + +# children_link directory +echo "* test link_children directory" +[ ! -d ${tmpd}/dir3 ] && echo 'not installed1' && exit 1 +[ ! -h ${tmpd}/dir3/s1 ] && echo 'not installed2' && exit 1 +[ ! -h ${tmpd}/dir3/s2 ] && echo 'not installed3' && exit 1 +[ ! -h ${tmpd}/dir3/s3 ] && echo 'not installed4' && exit 1 +[ ! -e ${tmpd}/dir3/s1/f1 ] && echo 'not installed5' && exit 1 +[ ! -e ${tmpd}/dir3/s2/f2 ] && echo 'not installed6' && exit 1 +grep 'header' ${tmpd}/dir3/s1/f1 || (echo "header stripped" && exit 1) +grep 'header' ${tmpd}/dir3/s2/f2 || (echo "header stripped" && exit 1) + +# linked file +echo "* test linked file" +[ ! -h ${tmpd}/fl ] && echo 'not installed' && exit 1 +grep 'header' ${tmpd}/f1 || (echo "header stripped" && exit 1) + +# normal dotfile +echo "* normal dotfile" +[ ! -e ${tmpd}/fn ] && echo 'not installed' && exit 1 +grep 'should not be stripped' ${tmpd}/fn && echo "no templated" && exit 1 + + +## CLEANING +rm -rf ${tmps} ${tmpd} + +echo "OK" +exit 0 diff --git a/tests-ng/update-ignore-relative.sh b/tests-ng/update-ignore-relative.sh index 09d4021..d2302d5 100755 --- a/tests-ng/update-ignore-relative.sh +++ b/tests-ng/update-ignore-relative.sh @@ -7,7 +7,7 @@ # # exit on first error -#set -e +set -e # all this crap to get current path rl="readlink -f" diff --git a/tests-ng/update-ignore.sh b/tests-ng/update-ignore.sh index af9e34c..9794e36 100755 --- a/tests-ng/update-ignore.sh +++ b/tests-ng/update-ignore.sh @@ -7,7 +7,7 @@ # # exit on first error -#set -e +set -e # all this crap to get current path rl="readlink -f" @@ -99,7 +99,7 @@ cd ${ddpath} | ${bin} update -f -c ${cfg} --verbose --profile=p1 --key f_abc # check files haven't been updated grep 'b' ${dt}/a/c/acfile >/dev/null -[ -e ${dt}/a/newfile ] && exit 1 +[ -e ${dt}/a/newfile ] && echo "should not have been updated" && exit 1 ## CLEANING rm -rf ${tmps} ${tmpd}