dotsync 0.1.18 → 0.1.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/AGENTS.md +93 -0
- data/CHANGELOG.md +53 -0
- data/Gemfile.lock +1 -1
- data/README.md +275 -24
- data/lib/dotsync/errors.rb +5 -0
- data/lib/dotsync/icons.rb +1 -0
- data/lib/dotsync/models/mapping.rb +18 -1
- data/lib/dotsync/runner.rb +13 -0
- data/lib/dotsync/utils/directory_differ.rb +9 -1
- data/lib/dotsync/utils/file_transfer.rb +75 -5
- data/lib/dotsync/utils/version_checker.rb +114 -0
- data/lib/dotsync/version.rb +1 -1
- data/lib/dotsync.rb +4 -3
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b3c840b83736169eaabf3296862872f088fc9ae49dc15545adf49bf75439620e
|
|
4
|
+
data.tar.gz: c8cf364077464a687df689c9bc6f43aa75fa45c61df531fcdc498a043ab2b02d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 105b36727336e5169a23de08a2a8f2165a568682a8ea4f590f93d93525990181cf3994239151d9a1e72d75e33416c217777a604373a37fbd0d7ff3e1aca94d93
|
|
7
|
+
data.tar.gz: 97a767742387ebd6af332e8e1a1d4e19b887c019fe5fb4863d449ea9e9ba6c9ddcf8459bee0a018362761d7f2c4d699bd7b69240af45ebc144c9ded697d46115
|
data/AGENTS.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Agents
|
|
2
|
+
|
|
3
|
+
This document describes AI agents and automation helpers that can assist with developing and maintaining the Dotsync project.
|
|
4
|
+
|
|
5
|
+
## Development Agents
|
|
6
|
+
|
|
7
|
+
### Code Review Agent
|
|
8
|
+
|
|
9
|
+
**Purpose**: Review code changes for quality, consistency, and adherence to Ruby best practices.
|
|
10
|
+
|
|
11
|
+
**When to use**:
|
|
12
|
+
- Before submitting pull requests
|
|
13
|
+
- After implementing new features
|
|
14
|
+
- When refactoring existing code
|
|
15
|
+
|
|
16
|
+
**What it checks**:
|
|
17
|
+
- Ruby style guide compliance (follows .rubocop.yml)
|
|
18
|
+
- Test coverage for new functionality
|
|
19
|
+
- Proper error handling
|
|
20
|
+
- Documentation completeness
|
|
21
|
+
- Performance considerations
|
|
22
|
+
|
|
23
|
+
### Test Generation Agent
|
|
24
|
+
|
|
25
|
+
**Purpose**: Generate and enhance RSpec tests for Dotsync functionality.
|
|
26
|
+
|
|
27
|
+
**When to use**:
|
|
28
|
+
- When adding new actions or utilities
|
|
29
|
+
- When test coverage is insufficient
|
|
30
|
+
- When refactoring existing code
|
|
31
|
+
|
|
32
|
+
**Focus areas**:
|
|
33
|
+
- Unit tests for models (Mapping, Diff)
|
|
34
|
+
- Integration tests for actions (PullAction, PushAction, WatchAction)
|
|
35
|
+
- Edge cases and error scenarios
|
|
36
|
+
- File system operations
|
|
37
|
+
|
|
38
|
+
### Documentation Agent
|
|
39
|
+
|
|
40
|
+
**Purpose**: Maintain and improve project documentation.
|
|
41
|
+
|
|
42
|
+
**When to use**:
|
|
43
|
+
- After adding new features
|
|
44
|
+
- When configuration options change
|
|
45
|
+
- When updating usage examples
|
|
46
|
+
|
|
47
|
+
**Responsibilities**:
|
|
48
|
+
- Keep README.md synchronized with code
|
|
49
|
+
- Update inline code documentation
|
|
50
|
+
- Maintain CHANGELOG.md
|
|
51
|
+
- Generate usage examples
|
|
52
|
+
|
|
53
|
+
## Maintenance Agents
|
|
54
|
+
|
|
55
|
+
### Dependency Update Agent
|
|
56
|
+
|
|
57
|
+
**Purpose**: Monitor and suggest updates for gem dependencies.
|
|
58
|
+
|
|
59
|
+
**What it monitors**:
|
|
60
|
+
- Security vulnerabilities in dependencies
|
|
61
|
+
- New versions of runtime and development dependencies
|
|
62
|
+
- Ruby version compatibility
|
|
63
|
+
|
|
64
|
+
### Release Agent
|
|
65
|
+
|
|
66
|
+
**Purpose**: Assist with the release process following RELEASING.md guidelines.
|
|
67
|
+
|
|
68
|
+
**Checklist**:
|
|
69
|
+
- Version number updated in version.rb
|
|
70
|
+
- CHANGELOG.md updated with changes
|
|
71
|
+
- Tests passing
|
|
72
|
+
- RuboCop compliance
|
|
73
|
+
- Tag creation and push
|
|
74
|
+
- Gem publication to rubygems.org
|
|
75
|
+
|
|
76
|
+
## Usage
|
|
77
|
+
|
|
78
|
+
To work with these agents effectively:
|
|
79
|
+
|
|
80
|
+
1. **Be specific**: Provide clear context about what you're working on
|
|
81
|
+
2. **Reference files**: Point to specific files or line numbers when discussing issues
|
|
82
|
+
3. **Run tests**: Always run `rake spec` after changes
|
|
83
|
+
4. **Follow conventions**: Adhere to existing code patterns and Ruby style guide
|
|
84
|
+
|
|
85
|
+
## Contributing
|
|
86
|
+
|
|
87
|
+
When working with agents on this project:
|
|
88
|
+
|
|
89
|
+
- Review generated code carefully before committing
|
|
90
|
+
- Ensure all tests pass (`rake spec`)
|
|
91
|
+
- Run RuboCop (`bundle exec rubocop`)
|
|
92
|
+
- Update documentation as needed
|
|
93
|
+
- Follow the project's [Code of Conduct](CODE_OF_CONDUCT.md)
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,56 @@
|
|
|
1
|
+
# 0.1.20
|
|
2
|
+
|
|
3
|
+
**Robustness & Error Handling:**
|
|
4
|
+
- Add specific error classes for better error handling (`PermissionError`, `DiskFullError`, `SymlinkError`, `TypeConflictError`)
|
|
5
|
+
- Add symlink support with proper preservation of link targets (regular, broken, and relative symlinks)
|
|
6
|
+
- Add type conflict detection to prevent overwriting directories with files or vice versa
|
|
7
|
+
- Enhance FileTransfer error handling for permission issues and disk space errors
|
|
8
|
+
|
|
9
|
+
**Testing & Quality:**
|
|
10
|
+
- Add 16 new test cases covering edge cases and error scenarios
|
|
11
|
+
- Add comprehensive symlink handling tests (regular, broken, relative)
|
|
12
|
+
- Add path traversal security validation tests
|
|
13
|
+
- Add Unicode filename compatibility tests (Russian, Japanese, Chinese, emoji)
|
|
14
|
+
- Add empty directory transfer tests
|
|
15
|
+
- Add Mapping#apply_to tests for path handling and force flag preservation
|
|
16
|
+
- Improve content comparison tests to verify actual file changes
|
|
17
|
+
- Improve path validation tests with more edge cases
|
|
18
|
+
- Total test count increased from 136 to 152 examples
|
|
19
|
+
|
|
20
|
+
**Developer Experience:**
|
|
21
|
+
- All tests passing (152 examples, 0 failures)
|
|
22
|
+
- RuboCop compliant with no offenses
|
|
23
|
+
|
|
24
|
+
# 0.1.19
|
|
25
|
+
|
|
26
|
+
**Documentation & Testing:**
|
|
27
|
+
- Add comprehensive icons test suite with 40 test cases covering all icon functionality
|
|
28
|
+
- Add icons customization documentation section to README with complete examples
|
|
29
|
+
- Add "What is Dotsync?" overview section highlighting 7 key features
|
|
30
|
+
- Add Table of Contents for improved README navigation
|
|
31
|
+
- Add Quick Start guide with 5-step setup process
|
|
32
|
+
- Add Common Use Cases section with practical configuration examples (Neovim, Alacritty, shell configs)
|
|
33
|
+
- Add comprehensive Troubleshooting section covering 6 common issues and solutions
|
|
34
|
+
- Enhance Pro Tips section with 7 useful tips including environment variables and backup locations
|
|
35
|
+
- Add License and Ruby version badges to README
|
|
36
|
+
- Add IMPORTANT callout about --apply flag and preview mode behavior
|
|
37
|
+
|
|
38
|
+
**Bug Fixes:**
|
|
39
|
+
- Fix duplicate `src` typo in push/watch mapping examples (corrected to `dest`)
|
|
40
|
+
- Fix section title: "force and ignore" → "force, only, and ignore"
|
|
41
|
+
- Add defensive nil handling in `Icons.load_custom_icons` method
|
|
42
|
+
|
|
43
|
+
**Developer Experience:**
|
|
44
|
+
- Add AGENTS.md with AI agent guidelines for project development
|
|
45
|
+
- Improve user onboarding with clearer documentation and examples
|
|
46
|
+
|
|
47
|
+
# 0.1.18
|
|
48
|
+
|
|
49
|
+
- Add automatic version checking with non-intrusive upgrade prompts
|
|
50
|
+
- Version check runs once per 24 hours using cached timestamp
|
|
51
|
+
- Can be disabled with `DOTSYNC_NO_UPDATE_CHECK` environment variable
|
|
52
|
+
- Cache stored in XDG-compliant location (`~/.cache/dotsync/last_version_check`)
|
|
53
|
+
|
|
1
54
|
# 0.1.17
|
|
2
55
|
|
|
3
56
|
- Fixes skipped files
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -2,11 +2,42 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://rubygems.org/gems/dotsync)
|
|
4
4
|
[](https://github.com/dsaenztagarro/dotsync/actions)
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
[](https://www.ruby-lang.org/)
|
|
5
7
|
|
|
6
8
|
> [!WARNING]
|
|
7
9
|
> This gem is under active development. You can expect new changes that may not be backward-compatible.
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
## What is Dotsync?
|
|
12
|
+
|
|
13
|
+
Dotsync is a powerful Ruby gem for managing and synchronizing your dotfiles across machines. Whether you're setting up a new development environment or keeping configurations in sync, Dotsync makes it effortless.
|
|
14
|
+
|
|
15
|
+
**Key Features:**
|
|
16
|
+
- **Bidirectional Sync**: Push local dotfiles to your repository or pull from repository to local machine
|
|
17
|
+
- **Preview Mode**: See what changes would be made before applying them (dry-run by default)
|
|
18
|
+
- **Smart Filtering**: Use `force`, `only`, and `ignore` options to precisely control what gets synced
|
|
19
|
+
- **Automatic Backups**: Pull operations create timestamped backups for easy recovery
|
|
20
|
+
- **Live Watching**: Continuously monitor and sync changes in real-time with `watch` command
|
|
21
|
+
- **Customizable Output**: Control verbosity and customize icons to match your preferences
|
|
22
|
+
- **Auto-Updates**: Get notified when new versions are available
|
|
23
|
+
|
|
24
|
+
## Table of Contents
|
|
25
|
+
|
|
26
|
+
- [Requirements](#requirements)
|
|
27
|
+
- [Installation](#installation)
|
|
28
|
+
- [Quick Start](#quick-start)
|
|
29
|
+
- [Usage](#usage)
|
|
30
|
+
- [Executable Commands](#executable-commands)
|
|
31
|
+
- [Configuration](#configuration)
|
|
32
|
+
- [Customizing Icons](#customizing-icons)
|
|
33
|
+
- [Automatic Update Checks](#automatic-update-checks)
|
|
34
|
+
- [Pro Tips](#pro-tips)
|
|
35
|
+
- [Common Use Cases](#common-use-cases)
|
|
36
|
+
- [Troubleshooting](#troubleshooting)
|
|
37
|
+
- [Development](#development)
|
|
38
|
+
- [Contributing](#contributing)
|
|
39
|
+
- [License](#license)
|
|
40
|
+
- [Code of Conduct](#code-of-conduct)
|
|
10
41
|
|
|
11
42
|

|
|
12
43
|
|
|
@@ -29,12 +60,48 @@ Or install it yourself as:
|
|
|
29
60
|
|
|
30
61
|
$ gem install dotsync
|
|
31
62
|
|
|
63
|
+
## Quick Start
|
|
64
|
+
|
|
65
|
+
Get started with Dotsync in just a few steps:
|
|
66
|
+
|
|
67
|
+
1. **Install the gem**:
|
|
68
|
+
```shell
|
|
69
|
+
gem install dotsync
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
2. **Generate a default configuration**:
|
|
73
|
+
```shell
|
|
74
|
+
dotsync setup
|
|
75
|
+
```
|
|
76
|
+
This creates `~/.config/dotsync.toml` with example mappings.
|
|
77
|
+
|
|
78
|
+
3. **Edit the configuration** (`~/.config/dotsync.toml`) to define your dotfile mappings:
|
|
79
|
+
```toml
|
|
80
|
+
[[pull.mappings]]
|
|
81
|
+
src = "$HOME/dotfiles/config"
|
|
82
|
+
dest = "$HOME/.config"
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
4. **Preview your changes** (dry-run mode):
|
|
86
|
+
```shell
|
|
87
|
+
dotsync pull
|
|
88
|
+
```
|
|
89
|
+
This shows what would be changed without modifying any files.
|
|
90
|
+
|
|
91
|
+
5. **Apply changes** when you're ready:
|
|
92
|
+
```shell
|
|
93
|
+
dotsync pull --apply
|
|
94
|
+
```
|
|
95
|
+
|
|
32
96
|
## Usage
|
|
33
97
|
|
|
34
98
|
### Executable Commands
|
|
35
99
|
|
|
36
100
|
Dotsync provides the following commands to manage your dotfiles:
|
|
37
101
|
|
|
102
|
+
> [!IMPORTANT]
|
|
103
|
+
> By default, both `push` and `pull` commands run in **preview mode** (dry-run). They will show you what changes would be made without actually modifying any files. To apply changes, you **must** use the `--apply` flag.
|
|
104
|
+
|
|
38
105
|
- **Push**: Transfer dotfiles from your local machine to the destination repository.
|
|
39
106
|
```shell
|
|
40
107
|
dotsync push --apply [OPTION]
|
|
@@ -108,7 +175,7 @@ dest = "$HOME"
|
|
|
108
175
|
|
|
109
176
|
[[push.mappings]]
|
|
110
177
|
src = "$HOME/.zshenv"
|
|
111
|
-
|
|
178
|
+
dest = "$HOME_MIRROR/.zshenv"
|
|
112
179
|
|
|
113
180
|
[[push.mappings]]
|
|
114
181
|
src = "$XDG_CONFIG_HOME/alacritty"
|
|
@@ -119,7 +186,7 @@ only = ["alacritty.toml", "rose-pine.toml"]
|
|
|
119
186
|
|
|
120
187
|
[[watch.mappings]]
|
|
121
188
|
src = "$HOME/.zshenv"
|
|
122
|
-
|
|
189
|
+
dest = "$HOME_MIRROR/.zshenv"
|
|
123
190
|
|
|
124
191
|
[[watch.mappings]]
|
|
125
192
|
src = "$XDG_CONFIG_HOME/alacritty"
|
|
@@ -133,7 +200,7 @@ dest = "$DOTFILES_DIR/config/alacritty"
|
|
|
133
200
|
> export XDG_CONFIG_HOME_MIRROR="$HOME/Code/dotfiles/xdg_config_home"
|
|
134
201
|
> ```
|
|
135
202
|
|
|
136
|
-
#### `force` and `ignore` Options in Mappings
|
|
203
|
+
#### `force`, `only`, and `ignore` Options in Mappings
|
|
137
204
|
|
|
138
205
|
Each mapping entry supports the following options:
|
|
139
206
|
|
|
@@ -150,34 +217,97 @@ Each mapping entry supports the following options:
|
|
|
150
217
|
|
|
151
218
|
These options apply when the source is a directory and are relevant for both `push` and `pull` operations.
|
|
152
219
|
|
|
153
|
-
###
|
|
220
|
+
### Customizing Icons
|
|
154
221
|
|
|
155
|
-
|
|
222
|
+
Dotsync allows you to customize the icons displayed in the console output by adding an `[icons]` section to your configuration file (`~/.config/dotsync.toml`). This is useful if you prefer different icons or need compatibility with terminals that don't support Nerd Fonts.
|
|
156
223
|
|
|
157
|
-
|
|
158
|
-
```
|
|
159
|
-
Mappings:
|
|
160
|
-
$DOTFILES_DIR/config/ → $XDG_CONFIG_HOME ⚡
|
|
161
|
-
```
|
|
162
|
-
The ⚡ icon (`Dotsync::Icons::FORCE`) indicates that the `force` option is enabled and the destination folder will be cleared before the transfer.
|
|
224
|
+
#### Available Icon Options
|
|
163
225
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
226
|
+
You can customize the following icons in your configuration:
|
|
227
|
+
|
|
228
|
+
**Mapping Status Icons** (shown next to each mapping):
|
|
229
|
+
- `force` - Indicates force deletion is enabled (clears destination before transfer)
|
|
230
|
+
- `only` - Indicates only specific files will be transferred
|
|
231
|
+
- `ignore` - Indicates files are being ignored during transfer
|
|
232
|
+
- `invalid` - Indicates the mapping is invalid (missing source/destination)
|
|
233
|
+
|
|
234
|
+
**Difference Status Icons** (shown in diff output):
|
|
235
|
+
- `diff_created` - Shows newly created/added files
|
|
236
|
+
- `diff_updated` - Shows updated/modified files
|
|
237
|
+
- `diff_removed` - Shows removed/deleted files
|
|
238
|
+
|
|
239
|
+
#### Example Configuration
|
|
240
|
+
|
|
241
|
+
Here's a complete example showing all customizable icons using UTF-8 emojis (works without Nerd Fonts):
|
|
242
|
+
|
|
243
|
+
```toml
|
|
244
|
+
[icons]
|
|
245
|
+
# Mapping status icons
|
|
246
|
+
force = "⚡" # Force deletion enabled
|
|
247
|
+
only = "📋" # Only specific files transferred
|
|
248
|
+
ignore = "🚫" # Files ignored during transfer
|
|
249
|
+
invalid = "❌" # Invalid mapping
|
|
250
|
+
|
|
251
|
+
# Diff status icons
|
|
252
|
+
diff_created = "✨" # New files created
|
|
253
|
+
diff_updated = "📝" # Files modified
|
|
254
|
+
diff_removed = "🗑️ " # Files deleted
|
|
255
|
+
|
|
256
|
+
# Example mappings section
|
|
257
|
+
[[pull.mappings]]
|
|
258
|
+
src = "$XDG_CONFIG_HOME_MIRROR"
|
|
259
|
+
dest = "$XDG_CONFIG_HOME"
|
|
260
|
+
ignore = ["cache"]
|
|
261
|
+
```
|
|
170
262
|
|
|
171
|
-
|
|
263
|
+
#### Default Icons
|
|
264
|
+
|
|
265
|
+
If you don't specify custom icons, Dotsync uses [Nerd Font](https://www.nerdfonts.com) icons by default. These icons will only display correctly if you're using a terminal with a patched Nerd Font installed.
|
|
266
|
+
|
|
267
|
+
| Icon | Default (Nerd Font) | Nerd Font Code | Purpose |
|
|
268
|
+
|------|---------------------|----------------|---------|
|
|
269
|
+
| `force` | ` ` | `nf-md-lightning_bolt` | Force deletion enabled |
|
|
270
|
+
| `only` | ` ` | `nf-md-filter` | Only mode active |
|
|
271
|
+
| `ignore` | ` ` | `nf-md-cancel` | Ignoring files |
|
|
272
|
+
| `invalid` | ` ` | `nf-md-alert_octagram` | Invalid mapping |
|
|
273
|
+
| `diff_created` | ` ` | `nf-md-plus` | File created |
|
|
274
|
+
| `diff_updated` | ` ` | `nf-md-pencil` | File updated |
|
|
275
|
+
| `diff_removed` | ` ` | `nf-md-minus` | File removed |
|
|
276
|
+
|
|
277
|
+
> [!NOTE]
|
|
278
|
+
> The icons in the "Default (Nerd Font)" column may not be visible unless you're viewing this with a Nerd Font. You can find these icons at [nerdfonts.com](https://www.nerdfonts.com/cheat-sheet) by searching for the Nerd Font Code.
|
|
279
|
+
|
|
280
|
+
> [!TIP]
|
|
281
|
+
> You can set any icon to an empty string (`""`) to hide it completely, or use any UTF-8 character or emoji. The `dotsync setup` command generates a configuration file with some example custom icons to get you started.
|
|
282
|
+
|
|
283
|
+
### Automatic Update Checks
|
|
284
|
+
|
|
285
|
+
Dotsync automatically checks for new versions once per day and notifies you if an update is available. This check is non-intrusive and will not interrupt your workflow.
|
|
286
|
+
|
|
287
|
+
To disable automatic update checks:
|
|
288
|
+
- Set environment variable: `export DOTSYNC_NO_UPDATE_CHECK=1`
|
|
289
|
+
|
|
290
|
+
The check runs after your command completes and uses a cached timestamp to avoid excessive API calls. The cache is stored in `~/.cache/dotsync/last_version_check` following the XDG Base Directory specification.
|
|
291
|
+
|
|
292
|
+
### Pro Tips
|
|
293
|
+
|
|
294
|
+
- **Preview Before Applying**: Always run commands without `--apply` first to preview changes:
|
|
295
|
+
```shell
|
|
296
|
+
dotsync pull # Preview changes
|
|
297
|
+
dotsync pull --apply # Apply after reviewing
|
|
172
298
|
```
|
|
173
|
-
|
|
174
|
-
|
|
299
|
+
|
|
300
|
+
- **Using Environment Variables**: Simplify your configuration with mirror environment variables:
|
|
301
|
+
```bash
|
|
302
|
+
# Add to your ~/.zshrc or ~/.bashrc
|
|
303
|
+
export DOTFILES_DIR="$HOME/dotfiles"
|
|
304
|
+
export XDG_CONFIG_HOME_MIRROR="$DOTFILES_DIR/config"
|
|
305
|
+
export HOME_MIRROR="$DOTFILES_DIR/home"
|
|
175
306
|
```
|
|
176
|
-
The ❌ icon (`Dotsync::Icons::INVALID`) indicates that the mapping is invalid due to missing source or destination paths.
|
|
177
307
|
|
|
178
|
-
|
|
308
|
+
- **Backup Location**: Pull operations automatically backup files to `~/.cache/dotsync/backups/` with timestamps. Only the 10 most recent backups are kept.
|
|
179
309
|
|
|
180
|
-
- **Using rbenv**: To ensure the gem uses the correct Ruby version managed by rbenv
|
|
310
|
+
- **Using rbenv**: To ensure the gem uses the correct Ruby version managed by rbenv:
|
|
181
311
|
```shell
|
|
182
312
|
RBENV_VERSION=3.2.0 dotsync push
|
|
183
313
|
```
|
|
@@ -187,6 +317,127 @@ When running `push` or `pull` actions, the mappings are rendered in the console
|
|
|
187
317
|
gem install dotsync
|
|
188
318
|
```
|
|
189
319
|
|
|
320
|
+
- **Disable Update Checks**: If you prefer not to see update notifications:
|
|
321
|
+
```shell
|
|
322
|
+
export DOTSYNC_NO_UPDATE_CHECK=1
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
- **Quiet Mode**: For use in scripts or when you only want to see errors:
|
|
326
|
+
```shell
|
|
327
|
+
dotsync pull --apply --quiet
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
## Common Use Cases
|
|
331
|
+
|
|
332
|
+
Here are some practical examples of how to use Dotsync for popular configuration files:
|
|
333
|
+
|
|
334
|
+
### Syncing Neovim Configuration
|
|
335
|
+
|
|
336
|
+
```toml
|
|
337
|
+
[[pull.mappings]]
|
|
338
|
+
src = "$HOME/dotfiles/config/nvim"
|
|
339
|
+
dest = "$HOME/.config/nvim"
|
|
340
|
+
force = true
|
|
341
|
+
ignore = ["lazy-lock.json", ".luarc.json"]
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
### Syncing Terminal Emulator (Alacritty)
|
|
345
|
+
|
|
346
|
+
```toml
|
|
347
|
+
[[push.mappings]]
|
|
348
|
+
src = "$HOME/.config/alacritty"
|
|
349
|
+
dest = "$HOME/dotfiles/config/alacritty"
|
|
350
|
+
only = ["alacritty.toml", "themes"]
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
### Syncing Shell Configuration
|
|
354
|
+
|
|
355
|
+
```toml
|
|
356
|
+
[[pull.mappings]]
|
|
357
|
+
src = "$HOME/dotfiles/shell/.zshrc"
|
|
358
|
+
dest = "$HOME"
|
|
359
|
+
|
|
360
|
+
[[pull.mappings]]
|
|
361
|
+
src = "$HOME/dotfiles/shell/.zshenv"
|
|
362
|
+
dest = "$HOME"
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### Syncing Multiple Config Directories
|
|
366
|
+
|
|
367
|
+
```toml
|
|
368
|
+
[[pull.mappings]]
|
|
369
|
+
src = "$HOME/dotfiles/config"
|
|
370
|
+
dest = "$HOME/.config"
|
|
371
|
+
ignore = ["nvim", "cache", "*.log"]
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
## Troubleshooting
|
|
375
|
+
|
|
376
|
+
### Icons Not Displaying Correctly
|
|
377
|
+
|
|
378
|
+
**Problem**: Icons appear as boxes, question marks, or strange characters.
|
|
379
|
+
|
|
380
|
+
**Solution**:
|
|
381
|
+
- Install a [Nerd Font](https://www.nerdfonts.com/) and configure your terminal to use it
|
|
382
|
+
- Or customize icons in `~/.config/dotsync.toml` using UTF-8 emojis or regular characters:
|
|
383
|
+
```toml
|
|
384
|
+
[icons]
|
|
385
|
+
force = "!"
|
|
386
|
+
only = "*"
|
|
387
|
+
ignore = "x"
|
|
388
|
+
invalid = "?"
|
|
389
|
+
diff_created = "+"
|
|
390
|
+
diff_updated = "~"
|
|
391
|
+
diff_removed = "-"
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
### Changes Not Being Applied
|
|
395
|
+
|
|
396
|
+
**Problem**: Running `dotsync push` or `dotsync pull` doesn't modify files.
|
|
397
|
+
|
|
398
|
+
**Solution**: Remember to use the `--apply` flag to apply changes. Without it, commands run in preview mode:
|
|
399
|
+
```shell
|
|
400
|
+
dotsync pull --apply
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
### Permission Denied Errors
|
|
404
|
+
|
|
405
|
+
**Problem**: Getting permission errors when syncing files.
|
|
406
|
+
|
|
407
|
+
**Solution**:
|
|
408
|
+
- Ensure you have write permissions for destination directories
|
|
409
|
+
- Check file ownership: `ls -la ~/.config`
|
|
410
|
+
- For system directories, you may need to adjust your mappings to use user-writable locations
|
|
411
|
+
|
|
412
|
+
### Source or Destination Not Found
|
|
413
|
+
|
|
414
|
+
**Problem**: Error messages about missing source or destination paths.
|
|
415
|
+
|
|
416
|
+
**Solution**:
|
|
417
|
+
- Verify environment variables are set correctly (e.g., `echo $XDG_CONFIG_HOME`)
|
|
418
|
+
- Use absolute paths in your configuration if environment variables aren't available
|
|
419
|
+
- Create destination directories before running pull: `mkdir -p ~/.config`
|
|
420
|
+
|
|
421
|
+
### Restoring from Backups
|
|
422
|
+
|
|
423
|
+
**Problem**: Need to restore files after a pull operation.
|
|
424
|
+
|
|
425
|
+
**Solution**: Pull operations create automatic backups in `~/.cache/dotsync/backups/`:
|
|
426
|
+
```shell
|
|
427
|
+
ls -la ~/.cache/dotsync/backups/
|
|
428
|
+
# Copy files from the timestamped backup directory
|
|
429
|
+
cp -r ~/.cache/dotsync/backups/YYYYMMDD_HHMMSS/* ~/.config/
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
### Watch Command Not Detecting Changes
|
|
433
|
+
|
|
434
|
+
**Problem**: `dotsync watch` doesn't sync changes automatically.
|
|
435
|
+
|
|
436
|
+
**Solution**:
|
|
437
|
+
- Verify your watch mappings are configured correctly in `~/.config/dotsync.toml`
|
|
438
|
+
- Ensure the source directories exist and are accessible
|
|
439
|
+
- Try stopping and restarting the watch command
|
|
440
|
+
|
|
190
441
|
## Development
|
|
191
442
|
|
|
192
443
|
- After checking out the repo, run `bin/setup` to install dependencies.
|
data/lib/dotsync/errors.rb
CHANGED
|
@@ -3,4 +3,9 @@
|
|
|
3
3
|
module Dotsync
|
|
4
4
|
class Error < StandardError; end
|
|
5
5
|
class ConfigError < StandardError; end
|
|
6
|
+
class FileTransferError < Error; end
|
|
7
|
+
class PermissionError < FileTransferError; end
|
|
8
|
+
class DiskFullError < FileTransferError; end
|
|
9
|
+
class SymlinkError < FileTransferError; end
|
|
10
|
+
class TypeConflictError < FileTransferError; end
|
|
6
11
|
end
|
data/lib/dotsync/icons.rb
CHANGED
|
@@ -58,11 +58,17 @@ module Dotsync
|
|
|
58
58
|
end
|
|
59
59
|
|
|
60
60
|
def valid?
|
|
61
|
+
return false unless paths_are_distinct?
|
|
62
|
+
return false unless paths_not_nested?
|
|
61
63
|
directories? || files? || file_present_in_src_only?
|
|
62
64
|
end
|
|
63
65
|
|
|
64
66
|
def file_changed?
|
|
65
|
-
|
|
67
|
+
return false unless files_present?
|
|
68
|
+
# Check size first for quick comparison
|
|
69
|
+
return true if File.size(src) != File.size(dest)
|
|
70
|
+
# If sizes match, compare content
|
|
71
|
+
FileUtils.compare_file(src, dest) == false
|
|
66
72
|
end
|
|
67
73
|
|
|
68
74
|
def backup_possible?
|
|
@@ -154,5 +160,16 @@ module Dotsync
|
|
|
154
160
|
end
|
|
155
161
|
[sanitized_src, sanitized_dest, sanitized_ignores, sanitized_only]
|
|
156
162
|
end
|
|
163
|
+
|
|
164
|
+
def paths_are_distinct?
|
|
165
|
+
src != dest
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def paths_not_nested?
|
|
169
|
+
# Check if dest is inside src or vice versa
|
|
170
|
+
return false if dest.start_with?("#{src}/")
|
|
171
|
+
return false if src.start_with?("#{dest}/")
|
|
172
|
+
true
|
|
173
|
+
end
|
|
157
174
|
end
|
|
158
175
|
end
|
data/lib/dotsync/runner.rb
CHANGED
|
@@ -33,6 +33,8 @@ module Dotsync
|
|
|
33
33
|
@logger.error("Error running '#{action_name}':")
|
|
34
34
|
@logger.info(e.message)
|
|
35
35
|
raise
|
|
36
|
+
ensure
|
|
37
|
+
check_for_updates
|
|
36
38
|
end
|
|
37
39
|
end
|
|
38
40
|
end
|
|
@@ -77,6 +79,17 @@ module Dotsync
|
|
|
77
79
|
@logger.info("Configuration file created at #{config_path}")
|
|
78
80
|
end
|
|
79
81
|
|
|
82
|
+
# Check for available updates
|
|
83
|
+
def check_for_updates
|
|
84
|
+
return if ENV["DOTSYNC_NO_UPDATE_CHECK"]
|
|
85
|
+
|
|
86
|
+
checker = Dotsync::VersionChecker.new(Dotsync::VERSION, logger: @logger)
|
|
87
|
+
checker.check_for_updates if checker.should_check?
|
|
88
|
+
rescue => e
|
|
89
|
+
# Silently fail - never break the tool
|
|
90
|
+
@logger.log("Debug: Version check failed - #{e.message}") if ENV["DEBUG"]
|
|
91
|
+
end
|
|
92
|
+
|
|
80
93
|
# Utility to convert 'pull' to 'Pull', 'sync' to 'Sync', etc.
|
|
81
94
|
def camelize(str)
|
|
82
95
|
str.split("_").map(&:capitalize).join
|
|
@@ -46,7 +46,7 @@ module Dotsync
|
|
|
46
46
|
if !File.exist?(dest_path)
|
|
47
47
|
additions << rel_path
|
|
48
48
|
elsif File.file?(src_path) && File.file?(dest_path)
|
|
49
|
-
if
|
|
49
|
+
if files_differ?(src_path, dest_path)
|
|
50
50
|
modifications << rel_path
|
|
51
51
|
end
|
|
52
52
|
end
|
|
@@ -92,5 +92,13 @@ module Dotsync
|
|
|
92
92
|
end
|
|
93
93
|
end
|
|
94
94
|
end
|
|
95
|
+
|
|
96
|
+
def files_differ?(src_path, dest_path)
|
|
97
|
+
# First check size for quick comparison
|
|
98
|
+
return true if File.size(src_path) != File.size(dest_path)
|
|
99
|
+
|
|
100
|
+
# If sizes match, compare content
|
|
101
|
+
FileUtils.compare_file(src_path, dest_path) == false
|
|
102
|
+
end
|
|
95
103
|
end
|
|
96
104
|
end
|
|
@@ -20,7 +20,28 @@ module Dotsync
|
|
|
20
20
|
|
|
21
21
|
def transfer
|
|
22
22
|
if File.file?(@src)
|
|
23
|
-
|
|
23
|
+
# Check if we're trying to overwrite a directory with a file
|
|
24
|
+
if File.exist?(@dest) && File.directory?(@dest) && !File.symlink?(@dest)
|
|
25
|
+
# If @dest is a directory and NOT just a parent directory for the file,
|
|
26
|
+
# this is a conflict. The check is: if @dest path exactly matches where
|
|
27
|
+
# we want the file to be (not a parent dir), then it's a conflict.
|
|
28
|
+
# We determine this by checking if File.basename(@src) already appears
|
|
29
|
+
# to be accounted for in @dest path.
|
|
30
|
+
dest_basename = File.basename(@dest)
|
|
31
|
+
src_basename = File.basename(@src)
|
|
32
|
+
|
|
33
|
+
if dest_basename == src_basename
|
|
34
|
+
raise Dotsync::TypeConflictError, "Cannot overwrite directory '#{@dest}' with file '#{@src}'"
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# If dest is a directory, compute the target file path
|
|
39
|
+
target_dest = if File.directory?(@dest)
|
|
40
|
+
File.join(@dest, File.basename(@src))
|
|
41
|
+
else
|
|
42
|
+
@dest
|
|
43
|
+
end
|
|
44
|
+
transfer_file(@src, target_dest)
|
|
24
45
|
else
|
|
25
46
|
cleanup_folder(@dest) if @force
|
|
26
47
|
transfer_folder(@src, @dest)
|
|
@@ -31,8 +52,29 @@ module Dotsync
|
|
|
31
52
|
attr_reader :mapping, :ignores
|
|
32
53
|
|
|
33
54
|
def transfer_file(file_src, file_dest)
|
|
55
|
+
# Check for type conflicts before transfer
|
|
56
|
+
if File.exist?(file_dest) && File.directory?(file_dest)
|
|
57
|
+
raise Dotsync::TypeConflictError, "Cannot overwrite directory '#{file_dest}' with file '#{file_src}'"
|
|
58
|
+
end
|
|
59
|
+
|
|
34
60
|
FileUtils.mkdir_p(File.dirname(file_dest))
|
|
35
|
-
|
|
61
|
+
|
|
62
|
+
# Use atomic write: copy to temp file, then rename
|
|
63
|
+
# This prevents corruption if copy is interrupted
|
|
64
|
+
temp_file = "#{file_dest}.tmp.#{Process.pid}"
|
|
65
|
+
begin
|
|
66
|
+
FileUtils.cp(file_src, temp_file)
|
|
67
|
+
FileUtils.mv(temp_file, file_dest, force: true)
|
|
68
|
+
rescue Errno::EACCES, Errno::EPERM => e
|
|
69
|
+
FileUtils.rm_f(temp_file) if File.exist?(temp_file)
|
|
70
|
+
raise Dotsync::PermissionError, "Permission denied: #{e.message}"
|
|
71
|
+
rescue Errno::ENOSPC => e
|
|
72
|
+
FileUtils.rm_f(temp_file) if File.exist?(temp_file)
|
|
73
|
+
raise Dotsync::DiskFullError, "Disk full: #{e.message}"
|
|
74
|
+
rescue StandardError => e
|
|
75
|
+
FileUtils.rm_f(temp_file) if File.exist?(temp_file)
|
|
76
|
+
raise Dotsync::FileTransferError, "Transfer failed: #{e.message}"
|
|
77
|
+
end
|
|
36
78
|
end
|
|
37
79
|
|
|
38
80
|
def transfer_folder(folder_src, folder_dest)
|
|
@@ -53,14 +95,42 @@ module Dotsync
|
|
|
53
95
|
next if mapping.ignore?(full_path)
|
|
54
96
|
|
|
55
97
|
target = File.join(folder_dest, File.basename(path))
|
|
56
|
-
if File.
|
|
57
|
-
|
|
58
|
-
|
|
98
|
+
if File.symlink?(full_path)
|
|
99
|
+
transfer_symlink(full_path, target)
|
|
100
|
+
elsif File.file?(full_path)
|
|
101
|
+
transfer_file(full_path, target)
|
|
102
|
+
elsif File.directory?(full_path)
|
|
59
103
|
transfer_folder(full_path, target)
|
|
60
104
|
end
|
|
61
105
|
end
|
|
62
106
|
end
|
|
63
107
|
|
|
108
|
+
def transfer_symlink(symlink_src, symlink_dest)
|
|
109
|
+
# Check if we're trying to overwrite a regular file or directory with a symlink
|
|
110
|
+
if File.exist?(symlink_dest) && !File.symlink?(symlink_dest)
|
|
111
|
+
if File.directory?(symlink_dest)
|
|
112
|
+
raise Dotsync::TypeConflictError, "Cannot overwrite directory '#{symlink_dest}' with symlink '#{symlink_src}'"
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
FileUtils.mkdir_p(File.dirname(symlink_dest))
|
|
117
|
+
|
|
118
|
+
# Get the target the symlink points to
|
|
119
|
+
link_target = File.readlink(symlink_src)
|
|
120
|
+
|
|
121
|
+
begin
|
|
122
|
+
# Remove existing symlink if present
|
|
123
|
+
FileUtils.rm(symlink_dest) if File.exist?(symlink_dest) || File.symlink?(symlink_dest)
|
|
124
|
+
|
|
125
|
+
# Create the new symlink
|
|
126
|
+
File.symlink(link_target, symlink_dest)
|
|
127
|
+
rescue Errno::EACCES, Errno::EPERM => e
|
|
128
|
+
raise Dotsync::PermissionError, "Permission denied creating symlink: #{e.message}"
|
|
129
|
+
rescue StandardError => e
|
|
130
|
+
raise Dotsync::SymlinkError, "Failed to create symlink: #{e.message}"
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
64
134
|
def cleanup_folder(target_dir)
|
|
65
135
|
target_dir = File.expand_path(target_dir)
|
|
66
136
|
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "net/http"
|
|
4
|
+
require "json"
|
|
5
|
+
require "time"
|
|
6
|
+
require "fileutils"
|
|
7
|
+
|
|
8
|
+
module Dotsync
|
|
9
|
+
class VersionChecker
|
|
10
|
+
include Dotsync::XDGBaseDirectory
|
|
11
|
+
|
|
12
|
+
RUBYGEMS_API_URL = "https://rubygems.org/api/v1/versions/dotsync/latest.json"
|
|
13
|
+
CHECK_INTERVAL = 86400 # 24 hours in seconds
|
|
14
|
+
REQUEST_TIMEOUT = 3 # seconds
|
|
15
|
+
|
|
16
|
+
def initialize(current_version, logger: nil)
|
|
17
|
+
@current_version = current_version
|
|
18
|
+
@logger = logger
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Returns true if we should check for updates (cache expired or doesn't exist)
|
|
22
|
+
def should_check?
|
|
23
|
+
return false if ENV["DOTSYNC_NO_UPDATE_CHECK"]
|
|
24
|
+
return true unless File.exist?(cache_file_path)
|
|
25
|
+
|
|
26
|
+
Time.now - last_check_time > CHECK_INTERVAL
|
|
27
|
+
rescue => e
|
|
28
|
+
# If we can't determine, be conservative and don't check
|
|
29
|
+
debug_log("Error checking if should check: #{e.message}")
|
|
30
|
+
false
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Main method to check for updates and display message if needed
|
|
34
|
+
def check_for_updates
|
|
35
|
+
return unless should_check?
|
|
36
|
+
|
|
37
|
+
latest_version = fetch_latest_version
|
|
38
|
+
return unless latest_version
|
|
39
|
+
|
|
40
|
+
update_cache
|
|
41
|
+
|
|
42
|
+
display_update_message(latest_version) if version_outdated?(@current_version, latest_version)
|
|
43
|
+
rescue => e
|
|
44
|
+
# Silently fail - never break the application
|
|
45
|
+
debug_log("Error checking for updates: #{e.message}")
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
def cache_file_path
|
|
50
|
+
@cache_file_path ||= File.join(xdg_cache_home, "dotsync", "last_version_check")
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def last_check_time
|
|
54
|
+
return Time.at(0) unless File.exist?(cache_file_path)
|
|
55
|
+
|
|
56
|
+
Time.parse(File.read(cache_file_path).strip)
|
|
57
|
+
rescue => e
|
|
58
|
+
debug_log("Error reading cache time: #{e.message}")
|
|
59
|
+
Time.at(0)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def update_cache
|
|
63
|
+
FileUtils.mkdir_p(File.dirname(cache_file_path))
|
|
64
|
+
File.write(cache_file_path, Time.now.iso8601)
|
|
65
|
+
rescue => e
|
|
66
|
+
debug_log("Error updating cache: #{e.message}")
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def fetch_latest_version
|
|
70
|
+
uri = URI(RUBYGEMS_API_URL)
|
|
71
|
+
|
|
72
|
+
response = Net::HTTP.start(uri.host, uri.port, use_ssl: true, open_timeout: REQUEST_TIMEOUT, read_timeout: REQUEST_TIMEOUT) do |http|
|
|
73
|
+
request = Net::HTTP::Get.new(uri)
|
|
74
|
+
http.request(request)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
return nil unless response.is_a?(Net::HTTPSuccess)
|
|
78
|
+
|
|
79
|
+
data = JSON.parse(response.body)
|
|
80
|
+
data["version"]
|
|
81
|
+
rescue => e
|
|
82
|
+
debug_log("Error fetching latest version: #{e.message}")
|
|
83
|
+
nil
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def version_outdated?(current, latest)
|
|
87
|
+
Gem::Version.new(current) < Gem::Version.new(latest)
|
|
88
|
+
rescue => e
|
|
89
|
+
debug_log("Error comparing versions: #{e.message}")
|
|
90
|
+
false
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def display_update_message(latest_version)
|
|
94
|
+
msg = "\n"
|
|
95
|
+
msg += "\e[38;5;226m" # Yellow color
|
|
96
|
+
msg += "A new version of dotsync is available: #{latest_version} "
|
|
97
|
+
msg += "(current: #{@current_version})\n"
|
|
98
|
+
msg += "Run 'gem update dotsync' to upgrade"
|
|
99
|
+
msg += "\e[0m\n" # Reset color
|
|
100
|
+
|
|
101
|
+
$stderr.puts msg
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def debug_log(message)
|
|
105
|
+
return unless ENV["DEBUG"]
|
|
106
|
+
|
|
107
|
+
if @logger
|
|
108
|
+
@logger.log("Debug: #{message}")
|
|
109
|
+
else
|
|
110
|
+
$stderr.puts "Debug: #{message}"
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
data/lib/dotsync/version.rb
CHANGED
data/lib/dotsync.rb
CHANGED
|
@@ -17,19 +17,20 @@ require_relative "dotsync/colors"
|
|
|
17
17
|
require_relative "dotsync/runner"
|
|
18
18
|
require_relative "dotsync/version"
|
|
19
19
|
|
|
20
|
+
# Config Concerns (loaded early as they're used by other modules)
|
|
21
|
+
require_relative "dotsync/config/concerns/xdg_base_directory"
|
|
22
|
+
|
|
20
23
|
# Utils
|
|
21
24
|
require_relative "dotsync/utils/path_utils"
|
|
22
25
|
require_relative "dotsync/utils/logger"
|
|
23
26
|
require_relative "dotsync/utils/file_transfer"
|
|
24
27
|
require_relative "dotsync/utils/directory_differ"
|
|
28
|
+
require_relative "dotsync/utils/version_checker"
|
|
25
29
|
|
|
26
30
|
# Models
|
|
27
31
|
require_relative "dotsync/models/mapping"
|
|
28
32
|
require_relative "dotsync/models/diff"
|
|
29
33
|
|
|
30
|
-
# Config Concerns
|
|
31
|
-
require_relative "dotsync/config/concerns/xdg_base_directory"
|
|
32
|
-
|
|
33
34
|
# Config
|
|
34
35
|
require_relative "dotsync/config/base_config"
|
|
35
36
|
require_relative "dotsync/config/pull_action_config"
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dotsync
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.20
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- David Sáenz
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2025-11-
|
|
11
|
+
date: 2025-11-10 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: toml-rb
|
|
@@ -262,6 +262,7 @@ files:
|
|
|
262
262
|
- ".rspec"
|
|
263
263
|
- ".rubocop.yml"
|
|
264
264
|
- ".ruby-version"
|
|
265
|
+
- AGENTS.md
|
|
265
266
|
- CHANGELOG.md
|
|
266
267
|
- CODE_OF_CONDUCT.md
|
|
267
268
|
- Gemfile
|
|
@@ -301,6 +302,7 @@ files:
|
|
|
301
302
|
- lib/dotsync/utils/file_transfer.rb
|
|
302
303
|
- lib/dotsync/utils/logger.rb
|
|
303
304
|
- lib/dotsync/utils/path_utils.rb
|
|
305
|
+
- lib/dotsync/utils/version_checker.rb
|
|
304
306
|
- lib/dotsync/version.rb
|
|
305
307
|
homepage: https://github.com/dsaenztagarro/dotsync
|
|
306
308
|
licenses:
|