{"id":13897962,"url":"https://github.com/weilbith/dotfiles","last_synced_at":"2026-01-18T00:52:44.198Z","repository":{"id":103104894,"uuid":"112511571","full_name":"weilbith/dotfiles","owner":"weilbith","description":"My private dotfiles to configure different applications. Used as backup, distribution and exchange.","archived":false,"fork":false,"pushed_at":"2024-07-09T08:16:12.000Z","size":123549,"stargazers_count":15,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-08-07T18:44:51.586Z","etag":null,"topics":["dotfiles"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/weilbith.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2017-11-29T18:20:21.000Z","updated_at":"2024-07-09T08:16:18.000Z","dependencies_parsed_at":"2023-12-07T16:50:33.864Z","dependency_job_id":null,"html_url":"https://github.com/weilbith/dotfiles","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/weilbith%2Fdotfiles","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/weilbith%2Fdotfiles/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/weilbith%2Fdotfiles/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/weilbith%2Fdotfiles/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/weilbith","download_url":"https://codeload.github.com/weilbith/dotfiles/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":226274619,"owners_count":17598850,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dotfiles"],"created_at":"2024-08-06T18:03:58.618Z","updated_at":"2026-01-18T00:52:44.180Z","avatar_url":"https://github.com/weilbith.png","language":"Shell","funding_links":[],"categories":["Shell"],"sub_categories":[],"readme":"[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![CircleCI](https://circleci.com/gh/weilbith/dotfiles/tree/master.svg?style=shield)](https://circleci.com/gh/weilbith/dotfiles/tree/master)\n[![Ansible](https://img.shields.io/badge/ansible-2.9.9-red.svg)](https://shields.io/)\n[![Vagrant](https://img.shields.io/badge/vagrant-2.2.9-blue.svg)](https://shields.io/)\n[![Docker](https://img.shields.io/badge/docker-19.03.11-lightblue.svg)](https://shields.io/)\n\n\u003cp align=\"center\"\u003e\u003cimg width=200\" src=\"./logo.png\"\u003e\u003c/p\u003e\n\n# Warhorse\n\nThe warhorse is my hero for my daily professional and private work. It is\nbasically just an awkward host name for my computer. The setup of my computer is\nsomething really personal to me. It includes a lot of research, hard work and\npassion over many years. It got extended continuously with new tools, tool\nexchanges, setup configuration reworks as well as conceptual reorientations.\nTherefore it is my desire to fix this setup in a replicable manner. Having it,\nI can make any computer become my Workhorse. And it even allows me to\nsynchronize within a herd. In fact it is a more powerful [dotfile\nrepository](https://github.com/search?q=dotfiles).\n\nThis all may sound crazy to you. And it probably is. I can't deny. This is in\nfirst place just for me. In second to share with others. My only hope could be\nthat this inspires you. If you are only interested into the configuration for\nsome certain tools, checkout their files in the according role directories.\n\n## Usage\n\n### Pre-requisites\n\nThe warhorse is expected to run on a machine with\n[ArchLinux](https://wiki.archlinux.org/) as operation system. Other OS are not\nsupported and expected to fail. Besides that there are only two packages needed.\nThese are `base-devel`, to enable the usage of the `Makefile`, and `git` to\ncheckout the sources and install the basic package manager. Everything else can\nbe setup with the provided [installation](#installation) targets.\n\nPlease be aware that the setup is meant to run on the targeting machine. This is\na requirement to make it work that the configuration files get linked.\nFurthermore must the provision targets be run by the correct user to secure the\nfile relation and permission. Moreover he will need access `sudo` to get root\npermissions for installing system packages and similar.\n\nFinally you will eventually need a file called `.vault.pwd` in the projects root\ndirectory. It is necessary to decrypt secrets stored for the Ansible setup (e.g.\nconfiguration files with an OAuth token).\n\n### Installation\n\nThis step is necessary for [provision](#provision) and [testing](#testing). It\nmakes sure that all dependencies are available and well configured.\n\nRun `make install` to initialize the full setup. Checkout the section\n_Installation Targets_ on `make help` for more focused sub-targets like only\ntesting.\n\nPlease be aware that these targets actually install packages onto your operation\nsystem. They are not limited to this projects repository. Anyways you can still\ncancel when you get asked to provide your password for executing commands with\nroot permissions.\n\n### Provision\n\nThis is the actual heart of this project. It provides your **local** machine to\nbecome the Workhorse. Thereby it makes sure that everything is fully installed,\ncompletely configured and synchronized. There are even more targets to sync data\nfrom the mail server and similar sources. The whole setup is idempotent. Means\nit always makes sure that the system is aligned with the configuration here.\nThereby it can be used for initialization, but also to update. Running the\nprovisioning multiple times without any changes leaves your system unaffected.\n\nRun `make provide` to do a full setup. For more focused provision the different\nroles are group into diverse Ansible playbooks. The main book simply includes\nall of them. You can select a single book with `provide-book BOOK=\u003cname-here\u003e`.\nCheckout `provide-book-list` to get a full list off all available book names.\nThe same goes for the `provide-role ROLE=\u003cname-here\u003e` target to focus a single\nrole only.\n\nThe dotfiles themselves are symbolically linked in the file system. Thereby you\nmust not call the provision again to update them. Concurrently it allows to edit\nthese files at their target location where the tools expect them.\n\n### Testing\n\nThere are different targets to test the setup. They intend to test the validity\nof the Workhorse setup, not the dotfiles that get provisioned. Watch-out for the\n`Testing Targets` section when you call `make help`. They require to install\nsome dependencies first via `make install-testing`. Such include the git hooks,\nthe virtual machine testing with Vagrant and the local CircleCI version.\n\n#### Linting \u0026 Formatting with Pre-commit\n\nWhen you installed the full setup you will have got established the Pre-commit\nhooks for git already. Besides some basic checks there are a bunch of linting\nhooks for the Ansible, Vagrant, Docker and CircleCI configuration included. You\ncan run them manually with `make test-lint`. If you don't install the hooks the\ncontinuous integration tests will do it finally.\n\nFormatting is checked as well, but there is no target to actually fix formatting\nissues. It is recommended to install such tools manually to your development\nenvironment.\n\n#### Virtual Machine with Vagrant\n\nTo test the setup in practice without applying it to the active system,\na virtual machine is used. This machine is managed with Vagrant, described with\nin the `Vagrantfile`. During the provision step, the setup of the Workhorse gets\napplied to the test machine. Since Ansible works idempotent the provision can be\nrun over and over again to apply changes to the same machine continuously. In\nbetween the machine gets suspended. The `make test-vagrant-provide` target\nprovides a convenient approach to do all of this at once. The target does also\nallow to define the `BOOK` and `ROLE` variables to select a specific playbook or\nrole accordingly. This allows to speed up the tests and focus them to the\ncurrent development. These variables get simply forwarded to the according\nprovision targets.\n\nPer default the `test-vagrant-provide` target will also automatically suspend the\nvirtual machine at the end. This is a compromise to be relatively fast in\nresuming the machine and suspending it. If you want to free the RAM, use\n`vagrant halt`. The next time running a test will take significantly longer to\nget the machine up and running.\nIf you plan to run the tests multiple times in a row (e.g. adding a new role and\nfocus on it with the `ROLE` variable), it make sense to define the `FAST`\nvariable (any truthy value). This will prevent the virtual machine from becoming\nsuspended. Thereby the next run will be faster and also connecting to the\nmachine via SSH works out of the box.\n\nTo verify or debug the provided setup, you can SSH into the virtual machine. The\ndata of the setup get synchronized automatically thanks to Vagrant. Remind that\nthe `test-vagrant-provide` target will suspend the machine per default as long\nas the `FAST` mode is not set. Therefore it is necessary to first resume the\nmachine with `vagrant resume \u0026\u0026 vagrant ssh`.\n\nIf there is the need to verify a setup visually like (e.g. test the X11 role),\nthe command `make test-vagrant-gui` can be used to restart the virtual machine\nwith a graphical interface. The default login is user-name and password\n`vagrant`.\n\nFurthermore can specific roles ask to get test data copied into the virtual\nmachine. The data can then be used to test the application practically. This can\nbe for example a PDF document or some images. The role itself specifies which\ntype of data it needs. The test data gets copied to the home directory of the\ntest user, attempting to follow the directory structure of the actual system.\nTo remove the copied data again, run the `make test-vagrant-remove-test-data`\ntarget.\n\nUnfortunately can't Ansible handle breaking changes. While it is idempotent it\ndoes not automatically clean up old runs according to a diff with a more recent\nversion. So if there are breaking changes necessary, it is advised to recreate\na new virtual machine, running the provision from zero.\n\n#### Continuous Integration with CircleCI\n\nFinally the continuous integration tests make sure that the setup is actually\nworking. This is meant as a last check in case the git hooks and the virtual\nmachine tests have not been maintained locally.\n\nThe CircleCI workflow creates a dummy password file for ansible-vault. The setup\nhas been customized to not throw decryption errors when they occur within\na CircleCI job.\n\n---\n\n## Concepts \u0026 Design\n\n### Base Role\n\nEach role should inheriting the `base_role`. It provides most-likely all features\na role needs in a generic manner. While most roles just work out of the box,\nsome need more specification and fine tuning via variables. Everything that is not\nachievable with the base role because it is special for this specific role must\nbe done in additional task definitions.\n\nExample:\n\n```yaml\n- import_role:\n    name: base_role\n  vars:\n    additional_packages:\n      - pcsclite # Smartcard middleware library\n      - ccid # Smartcard interface driver\n    link_configuration_children: true\n    systemd_units_user:\n      - gpg-agent.service\n      - gpg-agent-ssh.socket\n    systemd_units_system:\n      - pcscd.service\n```\n\nThe Following lists all task-modules of the base role, what they do and the\nconfiguration variables. A whole module or some tasks of it get ignored if there\nis nothing defined for the current role. The console output will always\nreference the original role name instead of `base_role` where the tasks are\nactually defined.\nThe order of the modules is fixed, because they partially can have dependencies\nto each other (like first a package must be installed).\n\n#### Install Packages\n\nMakes sure that certain packages are installed on the system. Uses an AUR helper\n(`pikaur` per default) to also resolve user repositories. Requires to handle\nlocal `PKGBUILD` files as well.\n\n| Variable              |    Type    |     Default      | Description                                                   |\n| :-------------------- | :--------: | :--------------: | :------------------------------------------------------------ |\n| `base_package`        |  `string`  | name of the role | Fundamental package of the role, set as empty string to omit. |\n| `additional_packages` | `string[]` |       `[]`       | List of more package names to install if necessary.           |\n| `pkgbuild_urls`       | `string[]` |       `[]`       | List of URLs that resolve to `PKGBUILD` files to install.     |\n\n#### Make Directories\n\nMakes sure that certain directories exist at the system. This is for example\nuseful if a tool can't create its own configured cache directory (`\"{{ xdg_config_home }}/tool\"`).\n\n| Variable          |    Type    | Default | Description                                           |\n| :---------------- | :--------: | :-----: | :---------------------------------------------------- |\n| `new_directories` | `string[]` |  `[]`   | List of absolute paths to create if not existing yet. |\n\n#### Link Configuration\n\nCreates a symbolic link of the configuration directory or files from the local\nrepository to the required location. Kinda the core of each dotfile management\nrepository. Though this module behaves quite complex. The directory must be\nstrictly named and being part of the role its files (i.e.\n`\u003crole_name\u003e/files/configuration`). The module will search for such directory\nand skip if it does not exist. The rest should be possible to derive from the\nvariable descriptions.\n\n| Variable                           |   Type    |            Default             | Description                                                                                                 |\n| :--------------------------------- | :-------: | :----------------------------: | :---------------------------------------------------------------------------------------------------------- |\n| `configuration_destination`        | `string`  | `$XDG_CONFIG_HOME/\u003crole-name\u003e` | Path for symbolic link target or directory to create for linked children.                                   |\n| `configuration_mode`               | `number`  |             `0700`             | File system mode for link target or new directory.                                                          |\n| `link_configuration_children`      | `boolean` |            `false`             | Do not link directory, but create destination path and link all children from source.                       |\n| `link_configuration_as_root`       | `boolean` |            `false`             | Make use of root privileges to link configuration (e.g. under `/etc/`).                                     |\n| `force_to_overwrite_configuration` | `boolean` |            `false`             | Use the force flag when linking or creating the destination in case there is already something per default. |\n\n#### Enable SystemD Units\n\nLinks and enables units (services, timers, sockets, ...) for SystemD. Handles\nunits for user and system scope. Units are always enabled, but never started.\nFurthermore it detects custom unit files at `\u003crole_name\u003e/files/systemd/`. If\nthere is a custom service **and** timer with the same name, the service gets\nonly linked, while the timer gets enabled. Non-custom units must be installed\nvia the required packages from the module above.\n\nFor the CircleCI test environment these tasks do not get executed, since they\nbasically do not work.\n\n| Variable                     |        Type        | Default | Description                                                                |\n| :--------------------------- | :----------------: | :-----: | :------------------------------------------------------------------------- |\n| `systemd_units_user`         |     `string[]`     |  `[]`   | List of unit names to enable for user scope.                               |\n| `systemd_units_system`       |     `string[]`     |  `[]`   | List of unit names to enable for system scope (requires root permissions). |\n| `systemd_units_custom_scope` | `user` or `system` | `user`  | Scope to apply for detected custom unit files.                             |\n\n#### Copy Test Data\n\nThis is only relevant for the Vagrant test environment to allow further testing\nof the applied roles. Such data can be images, documents or anything else. Roles\ncan defined which kind of data they need to get provided within the test\nenvironment. The source data is stored within the base role itself, not by the\nrole using it (i.e. `base_role/files/\u003cdata_kind\u003e`). Files get placed under the\nhome directory, following the directory structure from the source. This always\ntries to imitate the future directory structure as used by me and thereby how\nthe applications expect it (if they have such kind of configuration).\n\nIf necessary, all test data can be removed from the current Vagrant box with the\n`make test-vagrant-remove-test-data` command target.\n\n| Variable            |    Type    | Default | Description                                                                                     |\n| :------------------ | :--------: | :-----: | :---------------------------------------------------------------------------------------------- |\n| `provide_test_data` | `string[]` |  `[]`   | List of folder names from the source directory to copy recursively (e.g. `[audio, documents]`). |\n\n#### Link Shared Directory\n\nThis is a looped task and runs for the below listed items. It implements the\n[shared directory feature](#shared-directories) for each role if they have such.\nTherefore it checks if the role has any of these directories\n`\u003crole_name\u003e/files/\u003cshared_directory\u003e/*`. If so, it links all its children to\nthe system directory shared between all roles. If this is the first role using this\nshared directory, it will create they system directory. Checkout the above\nlinked section for more details of this concept.\n\nShared directories (roles must have directory with name of last path segment):\n\n- `$XDG_CONFIG_HOME/environment.d`\n- `$XDG_CONFIG_HOME/profile.d`\n- `$XDG_DATA_HOME/applications`\n- `$XDG_CONFIG_HOME/hotkey.d`\n- `$XDG_CONFIG_HOME/cheat.d`\n- `$XDG_CONFIG_HOME/notifications.d`\n\n### Shared Directories\n\nThe concept of shared directories is nothing newly invented here. Rather it is\nan effective approach that gets used and extended. The point is that all roles\nshould remain as independent of each other as possible. This is also the reason\nwhy there is no usage of `meta` files. If there is one role provided, no other\nrole gets ever installed automatically as well (note that the `base_role` is\nkind of an exception). Such an approach could result into an uncontrolled chain\nof dependencies that is not wished (at least not within this repository).\nFurthermore it would be hard to decide which are hard requirements and what are\njust nice to have extenstions. Even more important should no role include any\nconfiguration or reference to another application that is out of this roles\nscope. For example a tool that is used for global hotkeys should not include all\nthe commands that actually get installed by other roles. It should only provide\nthe feature that you can define hotkeys.\n\nThe approach is that each role can provide files that get collected into\na single directory. From there they get consumed by a handler who is responsible\nfor them. This means as long as the role providing the handler of a shared\ndirectory is not installed, these shared files will not take effect. This\nconcept makes sure that roles remain independent on a configuration file\nlevel. If a role should be removed, it must not be worried that at any place\ntheir is something left of this role and its applications. No environment\nvariable, not shell script, no hotkey, nothing. This follows the\nopen-closed-principle. Handlers are open to get easily extended, while their\nown configuration is closed (does not change), as long as this basic\nfunctionality must not been touched. This also leads to a beautiful clean\nversion control history. Each change in any configuration is always only\nrelated to the according role.\n\nThis eventually becomes more obvious when taking about already widely\nestablished shared directories. Note that while many of those have a system global\nversion as well, we only care about their user version here. An example is\nthe `$XDG_DATA_HOME/applications` directory. Every application can place its\n`.desktop` files there. A tool like `rofi` can then list these files with a nice\nUI presentation (including icon etc.) and let the user search/filter them and\nfinally start the selected application. Another example is the\n`$XDG_CONFIG_HOME/environment.d` directory. Each file defines a list of\nvariables. They get sourced by SystemD and enhance the user scope environment.\nThis environment is then sourced by a Shell (no default behavior).\nShared directories on system level are for the network manager, package manger,\nUDev and many more.\n\nUsually (but not always) these directories have a naming scheme of `\u003cname\u003e.d`.\nThis comes from the fact there is often a file with `\u003cname\u003e.\u003cextension\u003e` next to\nthe directory that is responsible to source all files in the directory. Any\nnewly added shared directory in this repository sticks to this convention to\nmake them more obvious to see.\nFiles in these directories often have a leading number in their file name\n(`01-\u003cname\u003e.\u003cextension\u003e`). This is used to get a strict loading order of all\nfiles. This is for example relevant when the variables of one file reference\nother variables that must be defined before (e.g. XDG-base-directories).\nWatch-out for the existing files to determine their scheme order.\n\nIt is not uncommon that shared directory handler roles inject their own files\nthemselves. Handlers are meant to be exchangeable without (much) work to the\nroles providing shared files. But this is not always the case/achievable (e.g.\nspecific syntax used).\n\nHere comes a list of all supported shared directories (via the according [base\nrole module](#link-shared-directory)).\n\n#### Environment\n\nTarget directory is `$XDG_CONFIG_HOME/environment.d`. This is a native feature\nby SystemD that constructs a list of environment variables. The advantage is\nthat these variables are also available within all user services. The build\nenvironment gets also sourced by the Shell (`.zshenv` in this case). The order\nmatters to make inherited variables get resolved correctly. Each role that needs\nto define an environment variable should define it via this shared directory.\nOnly if the variables value contains more complex text (unfortunately are spaces\npart of it), this should be moved to a profile.\n\n#### Profiles\n\nTarget directory is `$XDG_CONFIG_HOME/profile.d`. This is kind of an adopted\nnative feature by some Shells (probably it gets abused here). This is basically\na collection of scripts that should get sourced by the Shell. Their purpose is\nto initialize tools, define alias and functions, add plugins etc. Their order of\nloading might be relevant if one profile depends on that another has been\nsourced before. The handler of this shared directory is the `zsh` role (i.e. in\n`.zshrc`)\n\n#### Plugins\n\nTarget directory is `$XDG_CONFIG_HOME/profile.d`. This is a new shared directory\nused by the plugin manager for Zsh plugins (`zinit` at the current state). Each\nrole can add plugins (e.g. to provide completion support for an application)\nthat then get automatically detected and managed by the plugin manager who is\nthe handler of this shared directory. The handler gets sourced itself as\na profile of the shell. The order of plugins might matter.\n\n#### Applications\n\nTarget directory is `$XDG_DATA_HOME/applications`. This is a native feature of\nUnix operation systems. The files inside usually share the `.desktop` extension.\nThe handler can be multiple. Here they are made accessible with `rofi`. Note\nthat some packages might provide their own desktop files, also those take place\nat the global `/usr/share/applications` directory. The files do not have any\norder.\n\n#### Hotkeys\n\nTarget directory is `$XDG_CONFIG_HOME/hotkey.d`. This is a new shard directory\nused by the hotkey manager. Roles can define their hotkeys that allow to trigger\nactions globally within a desktop environment (e.g. volume, lock screen, ..).\nThe handler here is `sxhkd`. Their order does not matter.\n\n#### Cheats\n\nTarget directory is `$XDG_CONFIG_HOME/cheat.d`. This is a new shared directory\nused to collect cheat sheets for individual tools. The handler is `cheat`. Files\nin this directory take precedence over the in parallel installed community\nsheets. There is no order of the files. `cheat` does also support the usage of\nsub-directories as long as their names still equals the command name.\n\n#### Notifications\n\nTarget directory is `$XDG_CONFIG_HOME/notifications.d`. This is a new shared\ndirectory to customize notifications. It allows to filter send notifications and\nmanipulate them (e.g. change color or icon). The handler is `dunst`. Their order\ndoes not matter.\n\n#### Polybar Segments\n\n\u003e TODO\n\u003e Not yet implemented, but there is a need to for it. Some technical issues for\n\u003e an exact implementation are not resolved yet.\n\n### SystemD\n\n\u003e TODO\n\u003e SystemD units as first class citizen with all their high power.\n\u003e Explain custom artificial dependencies for desktop related services to Xorg.\n\n---\n\n## List of Useful Tools\n\nThese packages are tend to be installed temporally only when needed for special\ncases. So they do not have their own roles here.\n\n- `tuc` disk usage visualization as graph\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fweilbith%2Fdotfiles","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fweilbith%2Fdotfiles","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fweilbith%2Fdotfiles/lists"}