https://github.com/pablopunk/dot
Manage your apps, dotfiles, preferences, and their dependencies automagically
https://github.com/pablopunk/dot
automagically brew dependencies dotfiles homebrew install linux mac magic
Last synced: 3 months ago
JSON representation
Manage your apps, dotfiles, preferences, and their dependencies automagically
- Host: GitHub
- URL: https://github.com/pablopunk/dot
- Owner: pablopunk
- Created: 2024-10-09T12:57:07.000Z (9 months ago)
- Default Branch: main
- Last Pushed: 2025-02-19T21:52:02.000Z (5 months ago)
- Last Synced: 2025-04-05T08:34:27.773Z (3 months ago)
- Topics: automagically, brew, dependencies, dotfiles, homebrew, install, linux, mac, magic
- Language: Lua
- Homepage:
- Size: 96.7 KB
- Stars: 4
- Watchers: 1
- Forks: 1
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# `dot`
![]()
![]()
> Manage your apps, dotfiles, preferences, and their dependencies automagically
## Table of Contents
- [Installation](#installation)
- [Quick Start](#quick-start)
- [Usage](#usage)
- [Modules](#modules)
- [Dependencies](#dependencies)
- [Dotfiles](#dotfiles)
- [macOS Preferences (defaults)](#macos-preferences-defaults)
- [Profiles](#profiles)
- [Force Mode `-f`](#force-mode--f)
- [Unlinking Configs `--unlink`](#unlinking-configs---unlink)
- [Purging Modules `--purge`](#purging-modules---purge)
- [Hooks](#hooks)
- [Summary of Command-Line Options](#summary-of-command-line-options)
- [Examples](#examples)
- [To do](#to-do)## Installation
```bash
$ brew install pablopunk/brew/dot
```## Quick Start
```bash
$ cd /path/to/dotfiles
$ treeprofiles/
├── work.lua
├── personal.lua
├── linux-server.lua
modules/
├── neovim/
│ ├── init.lua
│ └── config/
├── zsh/
│ ├── init.lua
│ └── zshrc
└── apps/
├── work/
│ └── init.lua
└── personal/
└── init.lua$ dot # Link all dotfiles and install dependencies
$ dot neovim # Only process the 'neovim' module
$ dot work # Only process the 'work' profile
```## Usage
### Modules
Each module under the `modules/` folder needs to have at least an `init.lua`. If not, it will be ignored. **Modules can be recursive**, meaning you can have nested directories within the `modules/` folder, and each can contain its own `init.lua` to define configurations and dependencies.
#### `init.lua`
Example for neovim:
```lua
-- modules/neovim/init.lua
return {
brew = {
{ name = "neovim", options = "--HEAD" },
"ripgrep"
},
config = {
source = "./config", -- Our config directory within the module
output = "~/.config/nvim", -- Where the config will be linked to
}
}
```### Dependencies
#### Brew
As you can see, you can declare dependencies as [Homebrew](https://brew.sh) packages, which makes it possible to also use `dot` to install GUI apps (Homebrew casks). You can create a module without any config to use it as an installer for your apps:
```lua
-- modules/apps/init.lua
return {
brew = { "whatsapp", "spotify", "slack", "vscode" }
}
```#### Wget
`dot` now supports downloading files using `wget`. This can be useful for fetching binaries or other resources that are not available through Homebrew. You can specify a `wget` configuration in your module's `init.lua` file.
Example:
```lua
-- modules/apps/init.lua
return {
wget = {
{
url = "https://app1piece.com/1Piece-4.2.1.zip",
output = "/Applications/1Piece.app",
zip = true,
},
{
url = "https://fakedomain.com/fake.app",
output = "/Applications/Fake.app",
},
},
}
```> [!NOTE]
> When using `zip = true`, make sure the output file name matches the unzipped file name. In the example above, the output is `/Applications/1Piece.app` because the zip file contains a file named `1Piece.app`.### Dotfiles
The config will be linked to the home folder with a soft link. In this case:
```bash
~/.config/nvim → ~/dotfiles/modules/neovim/config
```You can also specify multiple configurations for a single module:
```lua
-- modules/multi-config/init.lua
return {
brew = { "cursor" },
config = {
{
source = "./config/settings.json",
output = "~/Library/Application Support/Cursor/User/settings.json",
},
{
source = "./config/keybindings.json",
output = "~/Library/Application Support/Cursor/User/keybindings.json",
}
}
}
```This will create two symlinks:
```bash
~/Library/Application Support/Cursor/User/settings.json → ~/dotfiles/modules/multi-config/config/settings.json
~/Library/Application Support/Cursor/User/keybindings.json → ~/dotfiles/modules/multi-config/config/keybindings.json
```### macOS Preferences (defaults)
You can manage macOS application preferences using the `defaults` field in your module's `init.lua`. This allows you to export and import application preferences to and from plist files. Since macOS `defaults` don't play nice with symlinks, you'll need to run `dot` every time you want to update/import the preferences. But don't worry, it's easy:
Example:
```lua
-- modules/defaults_test/init.lua
return {
defaults = {
{
plist = "./defaults/SwiftShift.plist",
app = "com.pablopunk.Swift-Shift", -- Info on how to get this below
}
}
}
```> [!NOTE]
> To find the app id, you can run `defaults domains | tr ', ' '\n' | grep -i `.https://github.com/user-attachments/assets/173d882c-3fb5-4fe1-bce4-4ac8fa6be7f0
The first time you run this without any files, it will export the current preferences to the plist file.
Whenever you want them to be exported again, run:
```bash
$ dot defaults_test --defaults-export
```To import the preferences from the saved file, run:
```bash
$ dot defaults_test --defaults-import
```By default, `dot` will only alert you that your saved preferences differ from the current ones.
It's up to you to choose which one you want to keep.### Profiles
If you have several machines, you might not want to install all tools on every computer. That's why `dot` allows **profiles**.
Let's create a new "personal" profile:
```lua
-- profiles/personal.lua
return {
modules = {
"*",
"!apps/work",
}
}
```In this example, running `dot personal` will:
- `*`: Install everything under `modules/`, including nested directories.
- `!apps/work`: Exclude the `apps/work` module and its submodules.You can use the following patterns in your profile:
- `"*"`: Include all modules recursively.
- `"!module_name"`: Exclude a specific module and its submodules.
- `"module_name"`: Include a specific module.For example, a work profile might look like this:
```lua
-- profiles/work.lua
return {
modules = {
"apps/work",
"slack",
"neovim",
"zsh"
}
}
```> [!NOTE]
> If your profile is named just like a module (e.g., `profiles/neovim` and `modules/neovim`), running `dot neovim` will default to the profile.#### Profiles are persistent
When you run `dot `, it will remember it, so next time you only need to run `dot` to use the same profile.
```bash
$ dot work
...installing work profile...$ dot
...installing work profile again...
```To get rid of the last profile used, select any other profile or run:
```bash
$ dot --remove-profile
```### Force Mode `-f`
By default, `dot` won't touch your existing dotfiles if the destination already exists. If you still want to replace them, you can use the `-f` flag:
```bash
$ dot -f neovim
```> [!NOTE]
> It won't remove the existing config but will move it to a new path: `.before-dot`.### Unlinking Configs `--unlink`
If you want to remove the symlinks created by `dot` for a specific module but keep your configuration, you can use the `--unlink` option:
```bash
$ dot --unlink neovim
```This command will:
- Remove the symlink at the destination specified in `config.output`.
- Copy the config source from `config.source` to the output location.This is useful if you want to maintain your configuration files without `dot` managing them anymore.
### Purging Modules `--purge`
To completely remove a module, including uninstalling its dependencies and removing its configuration, use the `--purge` option:
```bash
$ dot --purge neovim
```This command will:
- Uninstall the Homebrew dependencies listed in the module's `init.lua`.
- Remove the symlink or config file/directory specified in `config.output`.
- Run any `post_purge` hooks if defined in the module.> [!WARNING]
> `--purge` will uninstall packages from your system and remove configuration files. Use with caution.### Hooks
You can define `post_install` and `post_purge` hooks in your module's `init.lua` to run arbitrary commands after the module has been installed or purged.
```lua
return {
brew = { "gh" },
post_install = "gh auth login"
}
```You can also define multi-line hooks:
```lua
return {
brew = { "gh" },
post_install = [[
gh auth status | grep 'Logged in to github.com account' > /dev/null || gh auth login --web -h github.com
gh extension list | grep gh-copilot > /dev/null || gh extension install github/gh-copilot
]],
}
```## Summary of Command-Line Options
- **Install Modules**: Install dependencies and link configurations.
```bash
$ dot # Install all modules
$ dot neovim # Install only the 'neovim' module
$ dot work # Install only the 'work' profile
```- **Force Mode**: Replace existing configurations, backing them up to `.before-dot`.
```bash
$ dot -f # Force install all modules
$ dot -f neovim # Force install the 'neovim' module
```- **Unlink Configs**: Remove symlinks but keep the config files in their destination.
```bash
$ dot --unlink neovim
```- **Purge Modules**: Uninstall dependencies and remove configurations.
```bash
$ dot --purge neovim
```- **Defaults Export/Import**: Manage macOS application preferences.
```bash
$ dot defaults_test --defaults-export # Export app preferences to plist
$ dot defaults_test --defaults-import # Import app preferences from plist
```## Examples
- [pablopunk/dotfiles](https://github.com/pablopunk/dotfiles): my own dotfiles, using `dot` to manage them.
## To do
- [x] `dot` will install dependencies and link files.
- [x] Support Homebrew dependencies.
- [x] `dot -f` will remove the existing configs if they exist (moves config to `*.before-dot`).
- [x] Allow post-install hooks in bash.
- [x] Allow installing only one module with `dot neovim`.
- [x] Allow multiple setups in one repo. Similar to "hosts" in Nix, `dot work` reads `profiles/work.lua` which includes whatever it wants from `modules/`.
- [x] Package and distribute `dot` through Homebrew.
- [x] Add `--unlink` option to remove symlinks and copy configs to output.
- [x] Add `--purge` option to uninstall dependencies and remove configurations.
- [x] Allow array of config. For example I could like two separate folders that are not siblings
- [x] Improve profiles syntax. For example, `{ "*", "apps/work" }` should still be recursive except in "apps/". Or maybe accept negative patterns like `{ "!apps/personal" }` -> everything but apps/personal.
- [x] Add screenshots to the README.
- [ ] Support more ways of adding dependencies (e.g., wget binaries, git clone, apt...).
- [x] wget
- [ ] git clone
- [ ] apt
- [ ] Unlinking dotfiles without copying. An option like `dot --unlink --no-copy` could be added.
- [ ] `dot --purge-all` to purge all modules at once.
- [x] Support Mac defaults, similar to `nix-darwin`.
- [x] Add tests
- [x] Ignore on linux
- [x] Add cog images to the header so it's easier to tell that it's not only about plaintext dotfiles
- [ ] Support an `os` field. i.e `os = { "mac" }` will be ignored on Linux.
- [x] After using a profile, like `dot profile1`, it should remember it and all calls to `dot` should be done with this profile unless another profile is explicitely invoked, like `dot profile2`, which will replace it for the next invokations.