#配置管理 #仓库 #配置文件 #主目录 #模块 #惰性评估 #配对

app dfm

为懒人和配对程序员提供的dotfile管理器

12个稳定版本

10.1.3 2024年5月29日
10.1.0 2023年12月8日
10.0.5 2023年11月24日
10.0.3 2023年8月30日
8.0.1 2019年8月17日

#11 in 配置

Apache-2.0

69KB
1K SLoC

Rust 1K SLoC // 0.0% comments Shell 148 SLoC // 0.1% comments

dfm

为懒人和配对程序员提供的dotfile管理器。

目录

特性

dfm支持以下特性,在其他Dotfile管理解决方案中找不到。

多个dotfile配置文件

dfm的核心特性是配置文件的概念。配置文件仅仅是dfm管理和链接到$HOME目录或配置目录的dotfile集合。这意味着你可以拥有多个配置文件,并重叠它们。

这个特性难以描述,我将通过两个用例来说明它的有用性

工作配置文件

我使用一台笔记本电脑进行工作和个人项目,在我的dfm配置文件中,我有我的个人配置文件chasinglogic,它包含所有我的dotfile,例如Emacs和git,以及一个“工作”配置文件,它只有一个包含我的工作电子邮件的.gitconfig。因此,我的配置文件目录看起来像这样

profiles/
├── chasinglogic
│   ├── agignore
│   ├── bash
│   ├── bashrc
│   ├── gitconfig
│   ├── gnupg
│   ├── password-store
│   ├── pypirc
│   ├── spacemacs.d
│   └── tmux.conf
└── work
    └── gitconfig

由于dfm在链接时仅覆盖新配置文件中的文件,因此我可以运行dfm link work而仍能访问我的emacs配置,但我的gitconfig已被更新为使用我的工作邮箱。类似地,当我离开工作时,只需运行dfm link chasinglogic即可切换回去。

有关针对此特定用例的更佳解决方案,请参阅配置文件模块

结对编程

这个工具最初的灵感来源于我与朋友lionize的结对编程。lionize有一个dotfiles仓库,因此我可以使用dfm的git后端克隆它,命令为dfm clone --name lionize https://github.com/lionize/dotfiles

现在我们的配置文件目录看起来像这样

profiles/
├── chasinglogic
│   ├── .dfm.yml
│   ├── .git
│   ├── .gitignore
│   ├── agignore
│   ├── bash
│   ├── bashrc
│   ├── gitconfig
│   ├── gnupg
│   ├── password-store
│   ├── pypirc
│   ├── spacemacs.d
│   └── tmux.conf
├── lionize
│   ├── .agignore
│   ├── .git
│   ├── .gitconfig
│   ├── .gitignore_global
│   ├── .gitmessage
│   ├── .scripts
│   ├── .tmux.conf
│   ├── .vim
│   ├── .vimrc -> ./.vim/init.vim
│   └── .zshrc
└── work
    ├── .git
    └── gitconfig

现在我开车时,只需运行dfm link chasinglogic,当我回到lionize那里时,他运行dfm link lionize,我们不必反过来处理多个机器。

配置文件模块

dfm支持配置文件模块,可以是dfm clone命令接受的附加dotfiles配置文件,也可以是任何git仓库,例如Spacemacs。您可以在配置中了解有关如何使用它们以及如何配置它们的更多信息。

命令前和命令后钩子

dfm支持命令前和命令后钩子。这允许您指定在命令之前和之后运行的脚本。例如,我使用配置文件模块来在加密的git仓库中保留某些ssh密钥。每次我运行dfm sync命令时,我都会使用钩子来修复密钥的权限并将它们添加到我的ssh代理中。您可以在配置中了解如何编写自己的钩子。

尊重 $XDG_CONFIG_HOME

dfm尊重存在于$XDG_CONFIG_HOME目录中的dotfiles,这意味着如果您的仓库中有一个名为config.config的文件夹,它将自动将其转换为$XDG_CONFIG_HOME目录。类似地,当使用dfm add时,如果您的$XDG_CONFIG_HOME或$HOME/.configuration目录中,它会相应地将这些添加到仓库中。

跳过相关文件

dfm默认会跳过多个相关文件。

  • .git

dfm会跳过.git目录,这意味着您的$HOME目录不会被转换为git仓库。

  • .gitignore

如果您想存储全局.gitignore文件,您可以选择省略开头的点(因此仅为gitignore)或命名全局的一个为.ggitignore,dfm会为您转换名称。否则,它假定.gitignore是配置文件仓库的gitignore,因此跳过它。

  • README

想要为您的dotfiles编写README吗?请继续!只要文件名以README开头,dfm就会忽略它。所以README.txtREADME.mdREADME.rst或您能想到的其他任何变体都行。

  • LICENSE

您应该将所有上传到互联网上的代码加上许可证,一些点文件/配置实际上是代码(参见:Emacs)。如果您在您的个人资料中加上许可证,dfm会尊重您作为良好的开源公民,并避免在$HOME目录中添加杂乱。

  • .dfm.yml

这是一个特殊的dfm文件,用于今天的钩子,未来用于扩展dfm的其他方式。因此,dfm不会将其放入您的$HOME目录。

自定义映射

上面的忽略是通过名为映射的dfm功能实现的。您可以编写自己的映射来跳过、基于平台跳过或将文件转换到dfm通常放置它们的不同位置。您可以在配置中阅读如何配置自己的映射

加密Dotfiles

使用钩子和映射,您可以集成GPG与DFM,以便有一个加密的点文件存储库。

根据配置文档,如果您将以下.dfm.yml添加到您的存储库

---
mappings:
  - match: '.*.gpg'
    skip: true

hooks:
  before_sync:
    - interpreter: /bin/bash -c
      script: |
        echo "encrypting files..."
        for file in $(find . -not -name '*.gpg' -not -name '.dfm.yml' -not -name '.gitignore' -not -path './.git/*'); do
          echo "Encrypting $file to ${file/.gpg/}"
          gpg --batch --yes --encrypt ${file/.gpg/}
        done
  after_sync:
    - interpreter: /bin/bash -c
      script: |
        for file in $(git ls-files | grep -v .dfm.yml | grep -v .gitignore); do
          gpg --batch --yes --decrypt -o ${file/.gpg/} $file
        done

以下.gitignore文件

*
!*/
!.gitignore
!.dfm.yml
!*.gpg

然后当运行dfm sync时,DFM将运行gpg命令来加密所有文件,然后git将忽略所有非GPG加密文件(由于.gitignore),并在同步后,DFM将解密所有GPG加密文件。

这所有的事情都在链接之前发生,当您运行dfm link时,由于mapping配置,DFM将忽略所有gpg加密文件。然后它只会将未加密的版本链接到您的家目录。

安装

从发行版安装

dfm在GitHub发行版上可用,应从那里安装。

最新版本可在此处找到。

下载适用于您平台适当的存档,并将其提取到您的$PATH。一个常见的有效路径位置是/usr/local/bin

您可以使用以下命令来自动安装(在大多数平台上,这并不总是有效)

platform=$(uname -s)
arch=$(uname -m)
# If you're running on an M1 Macbook run this:
# arch="x86_64"
download_url=$(curl -s https://api.github.com/repos/chasinglogic/dfm/releases/latest | grep "browser_download_url.*$arch.*${platform,,}" | cut -d : -f 2,3 | sed 's/"//g' | xargs)
curl -L -o /tmp/dfm.tar.gz "$download_url"
tar -C /tmp -xzvf /tmp/dfm.tar.gz
mv $(find /$(readlink /tmp) -perm +111 -type f -name dfm 2>/dev/null) /usr/local/bin/

从源码安装

您需要一个rust编译器来从源码构建dfm。

克隆存储库并运行./scripts/local_install.sh

git clone https://github.com/chasinglogic/dfm
cd dfm
./scripts/local_install.sh

对于您的系统,您可能需要以sudo运行安装脚本。

使用

Usage:
    dfm [options] <command> [<args>...]
    dfm help
    dfm sync
    dfm link <profile>

Dotfile management written for pair programmers. Examples on getting
started with dfm are avialable at https://github.com/chasinglogic/dfm

Options:
    -v, --verbose  If provided print more logging info
    --debug        If provided print debug level logging info
    -h, --help     Print this help information

Commands:
    help           Print usage information about dfm commands
    sync (s)       Sync your dotfiles
    add (a)        Add the file to the current dotfile profile
    clean (x)      Clean dead symlinks
    clone (c)      Use git clone to download an existing profile
    git (g)        Run the given git command on the current profile
    init (i)       Create a new profile
    link (l)       Create links for a profile
    list (ls)      List available profiles
    remove (rm)    Remove a profile
    run-hook (rh)  Run dfm hooks without using normal commands
    where (w)      Prints the location of the current dotfile profile

See 'dfm help <command>' for more information on a specific command.

快速入门

快速入门(现有点文件存储库)

如果您已经有了点文件存储库,您可以使用clone命令开始。

SSH URL也将有效。

dfm clone https://github.com/chasinglogic/dotfiles

如果您正在使用GitHub,您可以简化域名

dfm clone chasinglogic/dotfiles

如果您想在一行命令中克隆和链接点文件

dfm clone --link chasinglogic/dotfiles

如果您有现有的非符号链接版本的点文件,您可能还需要使用--overwrite

一旦您有多个配置文件,您可以使用dfm link在它们之间切换

dfm link some-other-profile

请参阅下面的使用说明,以了解一些关于其他dfm命令的快速信息。

快速入门(没有现有点文件存储库)

如果您没有点文件存储库,从dfm init开始是最好的。

dfm init my-new-profile

然后运行dfm link将其设置为活动配置文件,这也是切换配置文件的方式

dfm link my-new-profile

一旦完成,您就可以开始添加您的 dotfiles

dfm add ~/.bashrc

或者,您可以一次性添加多个文件

dfm add ~/.bashrc ~/.vimrc ~/.vim ~/.emacs.d

然后在 GitHub 上创建您的 dotfiles 仓库。如何创建的说明可以在这里找到。创建完成后,获取您新仓库的 "clone" URL,并将其设置为配置文件的 origin

注意:在创建远程仓库时,不要选择任何选项,如“使用 README 初始化此仓库”,否则由于最近 Git 的更新以及它处理不相关历史的方式,Git 在添加远程仓库时可能会变得挑剔。如果您这样做,不用担心,相关帖子解释了如何解决这个问题。

dfm git remote add origin <your clone URL>

然后只需运行 dfm sync 将您的 dotfiles 同步到远程

dfm sync

现在您已经完成了!

配置

dfm 支持在您的仓库根目录中的 .dfm.yml 文件,该文件在同步和链接配置文件时更改 dfm 的行为。在运行 dfm link 时将忽略此文件,因此不会出现在您的家目录中。可以使用 .dfm.yml 配置这些功能

模块

dfm 中的模块是子配置文件。它们是克隆到特殊目录中的 Git 仓库:$XDG_CONFIG_HOME/dfm/modules。它们在配置文件之间共享,因此如果两个 dotfile 配置文件具有相同的模块,它们将共享该模块。

定义最小模块的语法如下

modules:
    - repository: [email protected]:chasinglogic/dotfiles

这将我的 dotfiles 仓库作为模块克隆到 $XDG_CONFIG_HOME/dfm/modules/chasinglogic。如果我想使用唯一的名称或某些其他文件夹名称,以便它不会共享,可以指定一个附加选项 name

modules:
    - repository: [email protected]:chasinglogic/dotfiles
      name: chasinglogic-dotfiles

这将克隆到 $XDG_CONFIG_HOME/dfm/modules/chasinglogic-dotfiles。您可以定义多个模块

modules:
    - repository: [email protected]:chasinglogic/dotfiles
      name: chasinglogic-dotfiles
    - repository: [email protected]:lionize/dotfiles

确保您指定一个名称,因为 git 定义的克隆位置可能会冲突,就像我们在这里看到的那样。这两个都会克隆到 dotfiles,如果我们没有为 chasinglogic 的 dotfiles 指定名称,这将导致第二个模块的克隆失败。

模块的另一个用途是克隆 Git 仓库但不链接。一个示例用途是下载 Spacemacs 或任何此类社区配置,如 oh-my-zsh 等。

modules:
    - repo: [email protected]:syl20bnr/spacemacs
      link: none
      pull_only: true
      location: ~/.emacs.d

在这里,我们指定了一些额外的键。它们的目的应该是显而易见的,但如果您好奇,下面 是所有模块配置支持的键的详细说明。

模块就像任何其他 dfm 配置文件一样工作,因此如果您要拉取的模块中包含 .dfm.yml,它将被加载并相应执行。包括下载它定义的任何模块。

可用的键

repo

必需的,这是克隆模块的 Git 仓库。

name

此操作更改克隆的名称。仅在未提供位置信息时才有效。通常,Git 仓库会被克隆到 $XDG_CONFIG_HOME/dfm/modules 目录,并且生成的文件夹将根据 Git URL 命名。如果提供了此信息,它将被克隆到指定名称的模块目录中。这对于多个配置文件使用同一模块很有用。

location

如果提供了模块,它将被克隆到指定的位置。您可以使用 ~ bash 扩展来表示 $HOME。没有其他可用的扩展。此选项对于克隆社区配置(如 oh-my-zsh 或 spacemacs)很有用。

确定何时链接模块。在此上下文中,链接意味着它将被视为一个常规的配置文件配置文件,因此所有文件都将通过像常规配置文件一样的翻译规则进行翻译,并相应地链接。可用值为 postprenone。默认值为 post,表示模块将在父配置文件之后链接。如果想要使用此配置文件中的大部分文件并覆盖父文件中的少量文件(因为 dfm 将使用找到的最后一个链接覆盖链接),则“pre”表示在父配置文件之前链接。如果“none”,表示模块不是配置文件配置文件,不应链接,例如 oh-my-zsh 或 spacemacs 这样的社区配置存储库。

pull_only

如果设置为 true,则不会尝试推送任何更改。重要的是要知道 dfm 总是尝试推送到 origin master,所以如果您没有对存储库的写访问权或不想自动推送到 master,则应将其设置为 true。这对于社区配置存储库很有用。

mappings

映射 部分所述的文件映射列表。模块不会继承父级映射,但它们确实会继承 跳过相关文件 中所述的默认映射。

映射

映射是一种定义自定义文件位置的方法。要了解映射,必须了解 dfm 的默认链接行为。

默认行为

例如,假设您在配置文件存储库中有一个名为 my_config.txt 的文件。dfm 将尝试将其翻译为新的位置 $HOME/.my_config.txt。然后,它将在该位置创建一个指向配置文件存储库中 my_config.txt 的符号链接。

使用映射

使用映射,您可以替换此行为,并使 dfm 在您希望的位置链接 my_config。如果您需要存储实际全局的配置文件,这很有用,例如配置文件将放在 /etc/ 中,或者您想要同步存储库中的某些文件但又不希望链接它们。

以下是一个简单的示例

mappings:
  - match: .config/some-dir
    link_as_dir: true
  - match: my_global_etc_files
    target_dir: /etc/
  - match: something_want_to_skip_but_sync
    skip: true
  - match: something_only_for_macos
    target_os: "Darwin"
  - match: some_file_for_mac_and_linux_only
    target_os:
        - "Linux"
        - "Darwin"
  - match: some_specific_translation_for_mac
    dest: ~/.mac_os_dotfile
    target_os:
        - "Darwin"

在 dfm 中,它使用正则表达式匹配 dotfile 仓库中的文件路径。当它找到一个与正则表达式匹配的路径时,它会添加一个替代链接行为。对于任何 skip 为 true 的情况,它将简单地跳过链接。对于任何具有 target_dir 的值,该值将覆盖链接时使用的 $HOME。对于任何具有 target_os 值的情况,只有当 dfm 在指定的 os 上运行时,文件才会被链接。

如上所示,使用 link_as_dir 选项进行映射。当此选项设置为 true 时,match: 的值将作为 dotfile 仓库根目录下的目录使用,并将其作为目录进行链接。通常,DFM 只链接文件,这可能会在某些类型的配置中引起问题,例如您经常生成文件,如片段工具。考虑以下 dotfile 仓库中的 dotfiles

$REPO/.config/nvim
├── UltiSnips
   ├── gitcommit.snippets
   └── python.snippets

这将产生以下链接 $HOME/.config/nvim

$HOME/.config/nvim
├── UltiSnips
   ├── gitcommit.snippets -> $HOME/.config/dfm/profiles/chasinglogic/.config/nvim/UltiSnips/gitcommit.snippets
│   └── python.snippets -> $HOME/.config/dfm/profiles/chasinglogic/.config/nvim/UltiSnips/python.snippets

每次您使用 :UltiSnipsEdit 创建新的片段文件类型时,您必须手动将其移动到您的 dotfile 仓库中,并重新运行 dfm link。为了解决这个问题,您可以在您的 .dfm.yml 中使用以下映射,而不是将其文件链接到 UltiSnips 目录

mappings:
  - match: .config/nvim/UltiSnips
    link_as_dir: true

现在 DFM 将 $HOME/.config/nvim/UltiSnips 目录链接到 $REPO/.config/nvim/UltiSnips

$HOME/.config/nvim
├── UltiSnips -> $HOME/.config/dfm/profiles/chasinglogic/.config/nvim/UltiSnips

可用配置

映射支持以下配置选项

match

匹配是用于匹配您的 dotfile 仓库中任何文件路径的正则表达式。这用于确定是否应使用文件的自定义链接行为。

这些是 Python 风格的正则表达式,并使用 re.findall 方法进行匹配,因此默认为模糊匹配。

skip

如果提供,则不会链接文件。

dest

文件的新完整路径。这可以用来完全更改文件名或将文件放置在全新的位置。这比 target_dir 更具体,并涵盖了 target_dir 不适用的案例(例如,如果文件在一个操作系统上是 dotfile,但在另一个操作系统上不是。)

target_dir

将文件链接到的位置。这里支持 $HOME~ 展开形式,但没有其他展开形式可用。值得注意的是,如果您在 target_dir 中使用 ~,那么您可能只需在您的 git 仓库中创建目录结构。

target_os

匹配操作系统字符串或字符串列表,以便链接此文件。以下是一些常见的非详尽值:LinuxDarwinWindows。这匹配 Python 的 platform.system() 函数返回的字符串。

钩子

dfm 中的钩子用于那些您需要在 dotfiles 同步或链接时执行的少量额外任务。

以我的个人 dotfiles 为例,每次同步 dotfiles 时都会运行 Ansible playbooks。为了实现这一点,我编写了一个 after_sync 钩子,如下所示

hooks:
  after_sync:
    - ansible-playbook ansible/dev-mac.yml

现在,每次同步 dotfiles 时,Ansible 都会运行我的 dev-mac playbooks,以确保我的软件包等也同步!

hooks 选项只是一个支持以下键的 YAML 映射:after_linkbefore_linkafter_syncbefore_sync。这些键的值是一个 YAML 字符串列表,将通过 /bin/sh -c '$YOUR COMMAND' 在 shell 中执行。例如

hooks:
  after_link:
    - ls -l
    - whoami
    - echo "All done!"

所有命令都以您 dotfile 存储库的工作目录运行,并将当前进程环境传递给进程,因此您可以在命令中使用 $HOME 等环境变量。

默认情况下,命令将以 /bin/sh -c 解释器运行。因此,上述第一个钩子的展开命令行将是

/bin/sh -c 'ls -l'

如果您想使用不同的解释器,您可以使用以下钩子格式

hooks:
  after_link:
    - interpreter: python -c
      script: |
        print("hello world from Python")

您可能需要在需要复杂逻辑(如应驻留在 Python 脚本中的逻辑)或例如在基于 Debian 的系统上这样做,这些系统使用 dash 而不是 bash 作为 /bin/sh 解释器,因此具有非常有限的展开功能集。

贡献

  1. 分叉它!
  2. 创建您的功能分支:git checkout -b my-new-feature
  3. 提交您的更改:git commit -am 'Add some feature'
  4. 推送到分支:git push origin my-new-feature
  5. 🔥 提交一个拉取请求 :D 🔥

所有拉取请求都应提交到 develop 分支,而不是 master。谢谢!

许可

此代码在 GNU 通用公共许可证下分发

    Copyright (C) 2018 Mathew Robinson

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

依赖项

~8–18MB
~239K SLoC