Metadata-Version: 2.4
Name: dotfilesmanager
Version: 1.17.1
Summary: dotfile管理工具，支持多平台
Author-email: xyz1001 <zgzf1001@gmail.com>
License-Expression: MIT
Project-URL: Repository, https://github.com/xyz1001/dotfilesmanager
Keywords: python,dotfiles
Classifier: Programming Language :: Python :: 3
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: click<8.2,>=8.1.8
Requires-Dist: questionary==2.1.0
Requires-Dist: prompt-toolkit<3.0.52,>=3.0.37
Requires-Dist: platformdirs==4.3.6
Requires-Dist: PyYAML>=6.0
Requires-Dist: cryptography<47,>=46.0.6
Provides-Extra: dev
Requires-Dist: build; extra == "dev"
Requires-Dist: twine; extra == "dev"
Requires-Dist: ruff; extra == "dev"
Requires-Dist: pytest; extra == "dev"
Provides-Extra: typecheck
Requires-Dist: mypy<1.15,>=1.14; extra == "typecheck"
Requires-Dist: types-PyYAML<6.0.12.20250326,>=6.0.12.20241221; extra == "typecheck"
Dynamic: license-file

# 📂 dotfilesmanager (dfm)

**Language:** [Chinese/中文](README_zh.md)

<p align="center">
  <a href="https://pypi.org/project/dotfilesmanager/">
    <img src="https://img.shields.io/pypi/v/dotfilesmanager?color=blue&logo=pypi&logoColor=white" alt="PyPI version">
  </a>
  <a href="https://pypi.org/project/dotfilesmanager/">
    <img src="https://img.shields.io/pypi/pyversions/dotfilesmanager?color=brightgreen&logo=python&logoColor=white" alt="Python Versions">
  </a>
  <a href="https://github.com/xyz1001/dotfilesmanager/blob/main/LICENSE">
    <img src="https://img.shields.io/github/license/xyz1001/dotfilesmanager?color=orange" alt="License">
  </a>
</p>

`dotfilesmanager` (or `dfm` for short) is a **minimal, lightweight, and cross-platform** configuration file (dotfiles) manager.

Unlike traditional synchronization or copying tools, `dfm` uses a **“move the original file + automatically create a symlink”** workflow. It centrally archives your configuration files in `~/dotfiles` under your home directory and creates symbolic links at their original locations. This lets you synchronize and back up configurations across machines while preserving their native real-time update behavior.

---

## ✨ Core Features

- 🚀 **Immediate effect**: Uses symlinks, so configuration changes take effect immediately without manual copying or synchronization.
- 💻 **Native cross-platform support**: Consistently supports Linux, macOS, Windows, and Android (Termux).
- 🧠 **Smart path recommendations**: When sharing configurations across platforms, automatically recommends the most suitable path according to the target system (for example, `~/.config` on macOS and an AppData path on Windows).
- 🔍 **Clear view**: Automatically generates a read-only directory of links organized by platform under `~/dotfiles/view/` for easy overview.
- 🩺 **Health diagnostics**: Includes a one-command check to quickly locate and fix broken symlinks, configuration conflicts, and other issues.

---

## 🆚 Positioning and comparison

- **Central repository + live paths**: `dfm` moves originals into a central `~/dotfiles` repository and places symlinks at live configuration paths, so edits take effect immediately. Its path mappings explicitly cover Linux, macOS, Windows, Android, and Termux, with platform-specific destinations recorded in `dfm.yaml`.
- **Compared with GNU Stow**: Both can create symlinks, but GNU Stow primarily provides a simpler Unix package-to-home-directory symlink model. `dfm` additionally provides cross-platform path mappings and `share` and `view` workflows.
- **Encryption scope**: `dfm` supports structured selected field/value encryption as well as whole-file encryption.
- **Boundaries**: `dfm` is neither a template engine nor a secret manager. Git or another external transport remains responsible for synchronizing the repository. Symlink creation and permissions are platform-dependent.

---

## 💾 Installation

Install with `pip` in one step:

```bash
pip install dotfilesmanager
```

After installation, you can use the **`dfm`** command directly from the command line.

---

## ⌨️ Shell Autocompletion

Click's completion feature only generates completion scripts; it does not install or enable them automatically. Save the script to the appropriate location for your Shell, or output it and load it manually:

```bash
# Bash: common bash-completion directory (or source into the current Shell)
_DFM_COMPLETE=bash_source dfm > ~/.local/share/bash-completion/completions/dfm

# Zsh: completion function directory
_DFM_COMPLETE=zsh_source dfm > ~/.zfunc/_dfm

# Fish: completion script directory
_DFM_COMPLETE=fish_source dfm > ~/.config/fish/completions/dfm.fish
```

Before first use, create the directories above yourself and configure your Shell to load the scripts: for Bash, run `source` or reload bash-completion; for Zsh, add `~/.zfunc` to `fpath` and run `compinit`; Fish loads from its completions directory. Autocompletion is not enabled automatically by these steps.

---

## 🏁 Quick Start

### 🛠️ Scenario 1: Add a local configuration to management

Enter a file or directory path to add it to `~/dotfiles`:

```bash
dfm add ~/.bashrc
```

> 💡 **Interactive wizard**
>
> In an interactive terminal (TTY), `dfm` automatically detects and asks whether you also want to share this configuration on other platforms (such as Windows / macOS / Android), and intelligently recommends a default path.
> 
> If this configuration belongs only to the current system and does not need to be shared across platforms, use the `--system` option:
> ```bash
> dfm add ~/.bashrc --system
> ```

### 🔐 Encrypt a new configuration with git-crypt

Install, prepare, and unlock git-crypt yourself before using `--encrypt`:

```bash
dfm add ~/.secret-config --encrypt
```

### 🔄 Scenario 2: Restore configurations on a new machine or system

After cloning your `~/dotfiles` repository to a new machine, rebuild all symbolic links with one command:

```bash
dfm install
```

To install only a specific configuration:

```bash
dfm install <保存的配置名/路径>
```

### 🤝 Scenario 3: Share an existing configuration across systems or at a new path

To use a configuration already managed by `dfm` on the current system at a different path:

```bash
dfm share <已保存配置项的路径> <当前系统下的新安装目标路径>
```

### 🗑️ Scenario 4: Stop managing a configuration and restore the file

When you no longer want `dfm` to manage a configuration and want to restore it to its original state:

```bash
dfm rm <路径>
```
This safely removes the symbolic link and **restores the original file or directory without data loss** from `~/dotfiles` to its initial installation path.

> [!TIP]
> To completely remove this configuration's associations on all systems and delete its source file from `~/dotfiles`, use:
> ```bash
> dfm rm <路径> --all
> ```

---

## 📑 Common Commands

| Command | Description |
| :--- | :--- |
| **`dfm add <path>`** | Manage a configuration file or directory by moving it into `~/dotfiles` and creating a link at its original location. |
| **`dfm rm <path>`** | Stop managing a configuration, remove the symbolic link, and put the file back in its original location. |
| **`dfm install [<path>]`** | Rebuild symbolic links for all (or a specified) configuration files for the current system. |
| **`dfm share <saved> <new>`** | Share an existing configuration with the current system and install it at the specified new path. |
| **`dfm view`** | Generate a clearly categorized read-only link view under `~/dotfiles/view` for easy management and inspection. |
| **`dfm doctor`** | Scan and diagnose the current system's configurations for broken links, conflicts, or unregistered files. |
| **`dfm setup`** | **(Windows only)** Check and enable Developer Mode so ordinary user permissions can create symbolic links. |

---

## 🔧 Platform Notes

### 🪟 Windows Users
* Creating symbolic links on Windows usually requires administrator privileges or Developer Mode.
* If you encounter a permissions error while running a command, execute **`dfm setup`**. It will guide you through enabling Developer Mode via UAC, after which you can use `dfm` normally with standard user permissions.

### 🤖 Android (Termux) Users
* `dfm` fully supports the Termux environment on Android (the system identifier is `android`).
* You can rebuild or share Unix-style configuration files on mobile devices.

---

## 📂 Storage and Configuration Management

* **Physical storage**: The originals of all managed files are stored in `~/dotfiles/files/`.
* **Data manifest**: `dfm.yaml` is the only automatically generated configuration file and persists path mappings for each configuration across platforms.
* **Version control recommendation**: We strongly recommend initializing the entire `~/dotfiles` directory as a Git repository and pushing it to GitHub or another platform for backup.
  > [!TIP]
  > We recommend adding `/view/` to your `.gitignore` to avoid committing generated temporary view files to the Git repository.

### 🔐 Partial value encryption

This feature requires `cryptography` and a configured GPG default/self key. In the
repository, create `dfm.yaml` with filename globs mapped to key lists, then run
`dfm init`. This creates the base configuration, wrapped key, local
`.git/line-crypt.key` cache, reserved `.git-filters/map.yaml`, and Git filter
attributes. The reserved map starts as `{version: 1, mappings: {}}`, is always
full-encrypted, and is not declared in `dfm.yaml`; repeated `dfm init` runs
preserve the wrapped data key and map. Normal `git add`, commit,
and checkout store deterministic `ENCv1:` values while the worktree stays
plaintext. Use `dfm lock` and `dfm unlock` to remove or restore local key access;
both require a clean tracked worktree and leave untracked files ignored.

During an interactive `dfm add`, regular UTF-8 files use one generic checkbox to
select detected sensitive fields and/or configured map literals. The selected modes
are applied in one encryption operation; no selection changes nothing. Directories,
binary files, non-interactive adds, and legacy `--encrypt` are not prompted. Map
suggestions require the plaintext `.git-filters/map.yaml` from `dfm unlock`; an
unavailable or invalid map leaves the ordinary field option usable.

The add-time candidate list is stored in `dfm.yaml` and can be manually edited;
users must add or remove entries themselves:

```yaml
encryption:
  sensitive_keys: [password, secret, token, key, email, username, user, uuid]
```

The scanner is deliberately format-agnostic: rules remain filename globs mapped to
`keys` lists. Optional `patterns` lists may use regular expressions; only capture
group 1 is encrypted during clean, while the rest of each match is preserved.
Patterns only need to describe plaintext; for a configured file, smudge scans and
decrypts every `ENCv1:` envelope directly:

Add a file-specific rule with repeated keys using:

```bash
dfm encrypt path/to/settings.conf --key password --key email
```

Without `--key`, `dfm encrypt` prompts for a comma-separated key list. It updates
the rule, filter attributes, and only renormalizes the selected path. The visible
command is not a command group; Git invokes the hidden internal command
`dfm encrypt-filter clean|smudge %f`.

Configured keys absent from a file are ignored by the filter. When adding keys
with `dfm encrypt`, each newly supplied key must occur in the target file; otherwise
the command fails before changing configuration or Git attributes.

For whole-file or binary content, use `dfm encrypt path/to/file --full`. This does
not prompt for keys and cannot be combined with `--key`; it creates or updates the
target rule as `full: true` and only renormalizes that path.

To stop encrypting one file, run `dfm unencrypt path/to/file`. It removes only
that file's exact rule and filter attribute, then renormalizes the path. Make
sure the repository is unlocked first. The file will be plaintext in the index
afterward, so future commits can expose its contents; review the staged diff
before committing.

```yaml
encryption:
  rules:
    "*.ini":
      patterns: ["(?m)^token\\s*=\\s*([^\\r\\n]*)$"]
```

For whole-file or binary content, use `full: true`; the complete input becomes
one `ENCv1:` envelope, and smudge leaves non-envelope input unchanged. A matching
full rule takes precedence over `keys` and `patterns`.

To enable reversible literal mapping for a file, use `--map`:

```bash
dfm encrypt path/to/settings.conf --map
dfm encrypt path/to/settings.conf --key password --map
```

`--map` does not prompt for keys and may be combined with `--key`, but not with
`--full`. Clean encrypts configured keys/patterns first, then replaces matching
map literals with frames such as `{{dfm:ENDPOINT}}` (longest literal first, once).
Plaintext containing any `{{dfm:` frame-like syntax is rejected as reserved; frames are generated only by clean. Smudge reverses generated frames before decrypting envelopes. The reserved
`.git-filters/map.yaml` is never map-transformed.
Map operations require its plaintext worktree copy; if it is missing or still an
`ENCv1:` envelope, run `dfm unlock`.

Key scanning remains format-agnostic and finds exact
bare or single-/double-quoted keys followed by `:`, `=`, or whitespace, with
optional whitespace around punctuation. Values may be bare or single-/double-
quoted. Clean and smudge preserve the original syntax and only replace value
interiors. Bare values extend through the logical line until a generic structural
boundary; trailing whitespace and comments remain outside the encrypted value.
This intentionally does not support multiline or block values; use simple
key/value fields when migrating fields from any configuration format.
`dfm lock` and `dfm unlock` manage the local cache without rewriting the index.
