# -*- coding: utf-8 -*-
from setuptools import setup

packages = \
['hamstercage', 'hamstercage.tests']

package_data = \
{'': ['*'], 'hamstercage.tests': ['repo/tags/all/*', 'repo/tags/foo/*']}

install_requires = \
['PyYAML>=6.0,<7.0', 'importlib-resources>=5.7.1,<6.0.0']

entry_points = \
{'console_scripts': ['hamstercage = hamstercage:__main__.main']}

setup_kwargs = {
    'name': 'hamstercage',
    'version': '0.0.12',
    'description': 'Pets not cattle. A straightforward way to manage configuration files.',
    'long_description': '# Hamstercage - Config Management for Pets, not Cattle\n\n## Overview\nIf you work professionally with many machines and config, you like will have heard "cattle, not pets" as the philosophy for managing machines, VMs, etc., and you\'re likely using Ansible, Puppet, SaltStack, or another configuration management system that allows you to express configuration as code. This approach works well when you have many targets that share many traits, you have a lab where you can test configuration changes, and you have full time staff to take care of it all.\n\nHowever, if you\'re running a handful of boxes or VPSes for a small organisation, or just for yourself and your friends and family, your workflow might actually look quite different: you make changes to the live configuration of your web server, for example, and after you\'re satisfied that everything is working, you might want to save the key bits of config somewhere safe, so you can refer back to it later. Setting up any of the heavy tools can be cumbersome, especially for making quick provisional changes: in the worstcase scenario, you modify a file in the source repo, commit it, then run the tool to apply it to your machine.\n\nHamstercage aims to make it easy to save and restore your config by using a Git repo, by editing the config files directly on the target machine, then saving the new config into the repository. In other words: pets, not cattle.\n\nHamstercage is geared towards managing config files as complete files. To keep things simple, there are no facilities to update individual lines in files, update system configuration settings through some API, or other more complex logic. Hamstercage can be used to manage shell script files or binaries for custom tools, however.\n\nTo allow one repository to be used for multiple targets, sets of files can be managed. Each set is called a tag. You can select the tags to use each time you run Hamstercage. The manifest also contains a list of hostnames and the tags to use for each. This makes it possible to run the same Hamstercage command on multiple hosts, and have files be applied to each according to their respective purpose. \n\n## Theory of Operation\n\nHamstercage keeps a list of files under management in a **manifest** file, by default `hamstercage.yaml`. The various Hamstercage commands can be used to add, update, and remove files from the manifest, but you can always make changes manually, for example to correct the owner or mode of a file.\n\nManaged files are kept not as a single list, but as multiple lists, one for each **tag**. A tag is simply a label for a set of files. You are free to choose tags to organize sets of files as you see fit, for example, by purpose, application, operating system, or any other metric.\n\nIn addition to the managed files, the manifest also contains a list of **hostnames**, with the tags that should be applied to each hostname. This allows you to run the same Hamstercage command across multiple hosts and have files applied according to the hosts\' respective tags.\n\nThe contents of files is kept alongside the manifest, using the path of the target. For example, a target file `/etc/bash_profile` would be stored in `repo/all/etc/bash_profile`.\n\nWhile Hamstercage manages files very efficiently, there are some configuration tasks that require manipulation of existing files, refreshing a set of files, or restarting a daemon. Hamstercage does not attempt to implement any such actions. **Hooks** allow you to supply your own custom logic for these kinds of actions. You can define hooks to run before or after a command is executed (for example before a `save` or after an `apply`). Hooks are defined on tags, so you can cater the commands to the set of files that are managed. Hooks can be individual shell commands, any executable including scripts, or Python programs that are executed inside Hamstercages Python process.\n\n## Installation\n\nHamstercage is a Python module. You can install it from this source repository, or from PyPi.\n\n\n```shell\npip install hamstercage\n```\n\n## Using Hamstercage\n\nAfter installation, Hamstercage is available on the path as `hamstercage`.\n\n### Creating a new Hamstercage repo\n\nHamstercage needs a manifest file in order to track files managed through it. You can create this file manually, or you can have Hamstercage create a template file for you:\n\n```shell\nhamstercage init\n```\n\nThis creates `hamstercage.yaml` in the current directory.\n\n### The Hamstercage Manifest\n\nAll information about file entries is stored in the manifest file `hamstercage.yaml`. This [YAML](https://yaml.org) file consists of these top-level entries:\n* `hosts`: each entry describes one host, in particular the set of tags that apply to it\n* `tags`: each entry contains a list of files managed for this tag\n\nThis is a very minimal example with one host, one tag and one file:\n```yaml\nhosts:\n  testing.example.com:\n    description: \'\'\n    tags:\n    - all\ntags:\n  all:\n    description: files that apply to all hosts\n    entries:\n      foo.txt:\n        group: staff\n        mode: 0o644\n        owner: stb\n        type: file\n```\n\n#### Hosts\n\nEach entry in this dict defines one host. Hosts are distinguished by their fully-qualified hostname. When running Hamstercage, you can override the hostname by specifying the `-h` option. Each host definition can have these fields:\n* `description`: allows you to add a description or note to this entry. Optional.\n* `tags`: a list of one or more tags to apply to this host.\n\n#### Tags\n\nEach entry in this dict defines one tag. Tag names can be freely chosen; it is recommended to stick to alpha-numeric identifiers though, to keep the names compatible with shell scripts, etc. Each entry has these fields:\n* `description`: allows you to add a description or note to this entry. Optional.\n* `entries`: a dict of files managed through this tag. See below for details.\n* `hooks`: a dict of hook scripts that will be run. See below for details.\n\n#### Tags: Entries\n\nThe entries field in a tag entry describes files, directories, and symbolic links that are managed through that tag. Each entry can have these fields:\n* `group`: the group name owning this file.\n* `mode`: the access mode for this file. You need to specify the mode as an octal number (`0o644`) or as a string in quotes (`"644"`). If you simply give a number, it will be interpreted as a base-10 integer, leading to unexpected mode bits\n* `owner`: the user name owning this file.\n* `target`: the path the link points to, only applicable to `type`=`link`\n* `type`: must be one of `dir`, `file`, or `link`.\n\nNote that Hamstercage only manages symbolic links (soft links). Hard links are not supported.\n\n#### Tags: Hooks\n\nThe `hooks` dict in a tag allows you to hook scripts into Hamstercages execution. The name of each entry defines when to run the script; the contents of the dict define what command to execute.\n\nThe name consists of two parts separated by a dash: the prefix `pre` or `post`, and the name of the Hamstercage command. For example, the hook defined by the name `pre-save` will be executed when you run `hamstercage save`, just before the contents of the files will be copied from the target system to the repository. A hook `post-apply` will be run right after all files have been updated by the command `hamstercage apply`.\n\nHamstercage searches for a matching hook definition in this order:\n1. for the exact match *step*`-`*command* (for example, `pre-save`)\n2. for the wildcard match `*-`*command* (for example, `*-save`)\n3. for the wildcard match *step*`-*` (for example, `pre-*`)\n4. for the fallback wildcard `*`.\n\nThe first match found will be executed.\n\nEach entry has these fields:\n* `command`: the command or script to execute.\n* `description`: allows you to add a description or note to this entry. Optional.\n* `type`: the type of command or script to run.\n  * `exec`: run the program specified by `command`. If `command` is not an absolute path, the system will search for it on the `PATH`. See [subprocess.Popen](https://docs.python.org/3/library/subprocess.html#subprocess.Popen) for details. The command will be invoked with the Hamstercage command, the step, and the tag the hook is defined in as parameters, for example `.../myhook.sh apply post all`.\n  * `python`: `command` should specify a Python script. A relative path is interpreted relative to the repository directory. See below for global variables available to the script.\n  * `shell`: run `command` through the shell. Typically, this will be the shell of the user running Hamstercage.\n\nThe `exec` and `shell` hooks receive the following environment variables:\n* `HAMSTERCAGE_CMD`: the command being executed\n* `HAMSTERCAGE_MANIFEST`: the manifest file path name\n* `HAMSTERCAGE_HOOK`: the name of the hook entry\n* `HAMSTERCAGE_REPO`: the repo directory, which is the directory the manifest file lives in\n* `HAMSTERCAGE_STEP`: the step (`pre` or `post`)\n* `HAMSTERCAGE_TAG`: the tag name this hook is defined in\n\nThe `python` script receives these global variables:\n* `cmd`: the command being executed\n* `manifest`: the manifest object\n* `hook`: the name of the hook entry\n* `repo`: the repo directory, which is the directory the manifest file lives in\n* `step`: the step (`pre` or `post`)\n* `tag`: the tag object this hook is defined in\n* `__file__`: the Python hook file\n* `__name__`: the constant `__hamstercage__`.\n\n\n\n## Command Reference\n\nHamstercage commands take a number of options and parameters.\n\n### General Options\n\n#### Target Directory `-d` / `--directory`\n\nThe directory where the managed files live, default `/`. You can set this to a different path when restoring config from a backup, or when managing a jail or container from the outside.\n\n#### Hostname `-n` / `--hostname`\n\nThe hostname of the local host. By default the value of `hostname(1)`. When applying files to the target directory, the hostname is used to obtain the default list of tags to use. Specifying this can be useful when restoring a host from backup, or when working on a container or jail.\n\n#### Manifest File `-f` / `--file`\n\nThe name of the manifest file that tracks all managed files, as well as settings for the repository. Default is `./hamstercage.yaml`.\n\n#### Repository Base Directory `-r` / `--rep`\n\nAll managed files are stored under this directory. The default is the same directory the manifest file lives in.\n\n#### Tags `-t` / `--tag`\n\nWhen adding files or applying them to the target directory, one or more tags can be specified. See the `add` and `apply` commands.\n\n### Verbose output `-v` / `--verbose`\n\nBy default, Hamstercage will only print warnings or error. With this flag, progress will be reported on all operations.\n\n### Commands\n\n#### Adding Files `add`\n\n```shell\nhamstercage -t mytag add file...\n```\n\nAdd one or more files to the repository. You need to specify exactly one tag, which determines the tag the file will be added to. The file will be added to the manifest, and the contents of the file copied to the repository.\n\n#### Applying Files `apply`\n\n```shell\nhamstercage apply [file...]\n```\n\nApply files from the repository to the target. Without any further options and parameters, will apply all files from the default tags for this hostname. Specify one or more tags to limit files to those in those tags, or specify filenames that should be applied.\n\nAdding a file that is already in the manifest for the given tag is an error.\n\n#### Determining Differences `diff`\n\n```shell\nhamstercage diff [file...]\n```\nPrints out a unified diff between all files in the repository and in the target. This allows you to preview what changed `apply` or `save` will make.\n\n#### Initialize a New Repository `init`\n\n```shell\nhamstercage init\n```\n\nCreates a new manifest file, by default `./hamstercage.yaml`. Combine this with `git init` to create a new Hamstercage repository.\n\n#### List Entries `list`\n\n```shell\nhamstercage list [-l]\n```\nLists all entries in the manifest. When `-l` is given, will print more details on each entry.\n\n#### Remove Files From Repository `remove`\n\n```shell\nhamstercage -t tag remove file...\n```\n\nRemoves one or more files from the specified tag. Does not change files in the target.\n\n#### Save Target to Repository `save`\n\n```shell\nhamstercage save [file...]\n```\n\nUpdates the manifest entries and repository files from the target.\n\n#### Adding Tags `tag add`\n\nAdds a new tag to the manifest.\n\n```shell\nhamstercage tag add [-d description] [file...]\n```\n\n# Developing Hamstercage\n\n## Poetry For Dependency Management and Building\n\nThe project uses [Poetry](https://python-poetry.org), which you should install locally. After installing Poetry, you can install all necessary dependencies:\n```shell\npoetry install\n```\n\n\n## Source Code Formatting With Black\n\nThe GitHub workflow checks source code formatting with [black](https://github.com/psf/black).\n\nTo format all code automatically:\n```shell\npoetry run black .\n```\n\nWhen working on the code, you might want to [configure your IDE to automatically reformat the code with black](https://black.readthedocs.io/en/stable/integrations/editors.html).',
    'author': 'Stefan Bethke',
    'author_email': 'stb@lassitu.de',
    'maintainer': None,
    'maintainer_email': None,
    'url': 'https://hamstercage.io',
    'packages': packages,
    'package_data': package_data,
    'install_requires': install_requires,
    'entry_points': entry_points,
    'python_requires': '>=3.8,<4.0',
}


setup(**setup_kwargs)
