dotsync 0.1.27 → 0.2.0
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/CHANGELOG.md +20 -0
- data/Gemfile.lock +1 -1
- data/lib/dotsync/actions/concerns/mappings_transfer.rb +16 -11
- data/lib/dotsync/loaders/pull_loader.rb +1 -0
- data/lib/dotsync/loaders/push_loader.rb +1 -0
- data/lib/dotsync/models/mapping.rb +10 -0
- data/lib/dotsync/utils/directory_differ.rb +6 -0
- data/lib/dotsync/utils/parallel.rb +72 -0
- data/lib/dotsync/version.rb +1 -1
- data/lib/dotsync.rb +1 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 492eda1f730e490322f6ff7fe85fd3fb91a1bd337f191f13d9574d63a5a9a326
|
|
4
|
+
data.tar.gz: f797e4c6a06258d312c3264be88cda022cb02f8053ed31159de54ce585ef9e3a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0d9bd4948c5d7de46e30443ca19ae4fabfc8d0caf3410b2a5e8bb519c8dc27384e032c06db32bd2a9bad041f6642707e8223f4affad58aa540cde4e277663b77
|
|
7
|
+
data.tar.gz: f20438f023966222c67f1a5397dfa8110d0d1cf4985fe67a82f0f8cbe615a9b25bdb88db176db33f1a0bf5109dccb1c5cce4889d74ab259dbd8bdd6e1716c2cf
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,23 @@
|
|
|
1
|
+
## [0.2.0] - 2025-02-06
|
|
2
|
+
|
|
3
|
+
**New Features:**
|
|
4
|
+
- Add `--diff-content` CLI option to display git-like unified diff output for modified files
|
|
5
|
+
- Shows actual content changes without needing external tools like `nvim -d`
|
|
6
|
+
- Color-coded output: blue for additions, red for deletions, cyan for hunk headers
|
|
7
|
+
- Automatically skips binary files
|
|
8
|
+
- Works with both `push` and `pull` commands
|
|
9
|
+
|
|
10
|
+
**Performance Optimizations:**
|
|
11
|
+
- Add parallel processing for mapping operations
|
|
12
|
+
- New `Dotsync::Parallel` utility module with thread-pool based execution
|
|
13
|
+
- Diff computation runs in parallel across multiple mappings
|
|
14
|
+
- File transfers execute concurrently for independent mappings
|
|
15
|
+
- Thread-safe error collection and reporting
|
|
16
|
+
- Add directory pruning optimization
|
|
17
|
+
- New `should_prune_directory?` method for early-exit during traversal
|
|
18
|
+
- Skips entire directory subtrees that are ignored or outside inclusion lists
|
|
19
|
+
- Reduces filesystem operations for large excluded directories
|
|
20
|
+
|
|
1
21
|
## [0.1.26] - 2025-01-11
|
|
2
22
|
|
|
3
23
|
**Breaking Changes:**
|
data/Gemfile.lock
CHANGED
|
@@ -87,28 +87,33 @@ module Dotsync
|
|
|
87
87
|
end
|
|
88
88
|
|
|
89
89
|
def transfer_mappings
|
|
90
|
-
|
|
90
|
+
errors = []
|
|
91
|
+
mutex = Mutex.new
|
|
92
|
+
|
|
93
|
+
Dotsync::Parallel.each(valid_mappings) do |mapping|
|
|
91
94
|
Dotsync::FileTransfer.new(mapping).transfer
|
|
92
95
|
rescue Dotsync::PermissionError => e
|
|
93
|
-
|
|
94
|
-
logger.info("Try: chmod +w <path> or check file permissions")
|
|
96
|
+
mutex.synchronize { errors << ["Permission denied: #{e.message}", "Try: chmod +w <path> or check file permissions"] }
|
|
95
97
|
rescue Dotsync::DiskFullError => e
|
|
96
|
-
|
|
97
|
-
logger.info("Free up disk space and try again")
|
|
98
|
+
mutex.synchronize { errors << ["Disk full: #{e.message}", "Free up disk space and try again"] }
|
|
98
99
|
rescue Dotsync::SymlinkError => e
|
|
99
|
-
|
|
100
|
-
logger.info("Check that symlink target exists and is accessible")
|
|
100
|
+
mutex.synchronize { errors << ["Symlink error: #{e.message}", "Check that symlink target exists and is accessible"] }
|
|
101
101
|
rescue Dotsync::TypeConflictError => e
|
|
102
|
-
|
|
103
|
-
logger.info("Cannot overwrite directory with file or vice versa")
|
|
102
|
+
mutex.synchronize { errors << ["Type conflict: #{e.message}", "Cannot overwrite directory with file or vice versa"] }
|
|
104
103
|
rescue Dotsync::FileTransferError => e
|
|
105
|
-
|
|
104
|
+
mutex.synchronize { errors << ["File transfer failed: #{e.message}", nil] }
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Report all errors after parallel execution
|
|
108
|
+
errors.each do |error_msg, info_msg|
|
|
109
|
+
logger.error(error_msg)
|
|
110
|
+
logger.info(info_msg) if info_msg
|
|
106
111
|
end
|
|
107
112
|
end
|
|
108
113
|
|
|
109
114
|
private
|
|
110
115
|
def differs
|
|
111
|
-
@differs ||=
|
|
116
|
+
@differs ||= Dotsync::Parallel.map(valid_mappings) do |mapping|
|
|
112
117
|
Dotsync::DirectoryDiffer.new(mapping).diff
|
|
113
118
|
end
|
|
114
119
|
end
|
|
@@ -12,6 +12,7 @@ require_relative "../utils/file_transfer"
|
|
|
12
12
|
require_relative "../utils/directory_differ"
|
|
13
13
|
require_relative "../utils/config_cache"
|
|
14
14
|
require_relative "../utils/content_diff"
|
|
15
|
+
require_relative "../utils/parallel"
|
|
15
16
|
|
|
16
17
|
# Models
|
|
17
18
|
require_relative "../models/mapping"
|
|
@@ -12,6 +12,7 @@ require_relative "../utils/file_transfer"
|
|
|
12
12
|
require_relative "../utils/directory_differ"
|
|
13
13
|
require_relative "../utils/config_cache"
|
|
14
14
|
require_relative "../utils/content_diff"
|
|
15
|
+
require_relative "../utils/parallel"
|
|
15
16
|
|
|
16
17
|
# Models
|
|
17
18
|
require_relative "../models/mapping"
|
|
@@ -140,6 +140,16 @@ module Dotsync
|
|
|
140
140
|
ignore?(path) || !include?(path)
|
|
141
141
|
end
|
|
142
142
|
|
|
143
|
+
# Returns true if a directory can be entirely skipped during destination walks.
|
|
144
|
+
# A directory should be pruned if:
|
|
145
|
+
# 1. It's ignored, OR
|
|
146
|
+
# 2. It has inclusions AND the path is neither included nor a parent of any inclusion
|
|
147
|
+
def should_prune_directory?(path)
|
|
148
|
+
return true if ignore?(path)
|
|
149
|
+
return false unless has_inclusions?
|
|
150
|
+
!bidirectional_include?(path)
|
|
151
|
+
end
|
|
152
|
+
|
|
143
153
|
private
|
|
144
154
|
def has_ignores?
|
|
145
155
|
@original_ignores.any?
|
|
@@ -61,6 +61,12 @@ module Dotsync
|
|
|
61
61
|
|
|
62
62
|
src_path = File.join(mapping_src, rel_path)
|
|
63
63
|
|
|
64
|
+
# Prune entire directory trees that are outside the inclusion list or ignored
|
|
65
|
+
if File.directory?(dest_path) && @mapping.should_prune_directory?(src_path)
|
|
66
|
+
Find.prune
|
|
67
|
+
next
|
|
68
|
+
end
|
|
69
|
+
|
|
64
70
|
next if @mapping.skip?(src_path)
|
|
65
71
|
|
|
66
72
|
if !File.exist?(src_path)
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Dotsync
|
|
4
|
+
# Simple thread-based parallel execution for independent operations.
|
|
5
|
+
# Uses a configurable thread pool to process items concurrently.
|
|
6
|
+
module Parallel
|
|
7
|
+
# Default number of threads (matches typical CPU core count)
|
|
8
|
+
DEFAULT_THREADS = 4
|
|
9
|
+
|
|
10
|
+
# Executes a block for each item in the collection using parallel threads.
|
|
11
|
+
# Returns results in the same order as the input collection.
|
|
12
|
+
#
|
|
13
|
+
# @param items [Array] Collection of items to process
|
|
14
|
+
# @param threads [Integer] Number of parallel threads (default: 4)
|
|
15
|
+
# @yield [item] Block to execute for each item
|
|
16
|
+
# @return [Array] Results in same order as input
|
|
17
|
+
#
|
|
18
|
+
# @example
|
|
19
|
+
# results = Dotsync::Parallel.map(urls, threads: 8) do |url|
|
|
20
|
+
# fetch(url)
|
|
21
|
+
# end
|
|
22
|
+
def self.map(items, threads: DEFAULT_THREADS, &block)
|
|
23
|
+
return [] if items.empty?
|
|
24
|
+
return items.map(&block) if items.size == 1
|
|
25
|
+
|
|
26
|
+
# Limit threads to item count
|
|
27
|
+
thread_count = [threads, items.size].min
|
|
28
|
+
|
|
29
|
+
# Create indexed work items
|
|
30
|
+
work_queue = Queue.new
|
|
31
|
+
items.each_with_index { |item, idx| work_queue << [idx, item] }
|
|
32
|
+
|
|
33
|
+
# Results array (pre-sized for thread safety with index assignment)
|
|
34
|
+
results = Array.new(items.size)
|
|
35
|
+
mutex = Mutex.new
|
|
36
|
+
errors = []
|
|
37
|
+
|
|
38
|
+
# Spawn worker threads
|
|
39
|
+
workers = thread_count.times.map do
|
|
40
|
+
Thread.new do
|
|
41
|
+
loop do
|
|
42
|
+
idx, item = work_queue.pop(true) rescue break
|
|
43
|
+
begin
|
|
44
|
+
results[idx] = yield(item)
|
|
45
|
+
rescue => e
|
|
46
|
+
mutex.synchronize { errors << e }
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Wait for completion
|
|
53
|
+
workers.each(&:join)
|
|
54
|
+
|
|
55
|
+
# Re-raise first error if any occurred
|
|
56
|
+
raise errors.first unless errors.empty?
|
|
57
|
+
|
|
58
|
+
results
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Executes a block for each item in parallel, ignoring return values.
|
|
62
|
+
# Useful for side-effect operations like file transfers.
|
|
63
|
+
#
|
|
64
|
+
# @param items [Array] Collection of items to process
|
|
65
|
+
# @param threads [Integer] Number of parallel threads (default: 4)
|
|
66
|
+
# @yield [item] Block to execute for each item
|
|
67
|
+
def self.each(items, threads: DEFAULT_THREADS, &block)
|
|
68
|
+
map(items, threads: threads, &block)
|
|
69
|
+
nil
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
data/lib/dotsync/version.rb
CHANGED
data/lib/dotsync.rb
CHANGED
|
@@ -31,6 +31,7 @@ require_relative "dotsync/utils/file_transfer"
|
|
|
31
31
|
require_relative "dotsync/utils/directory_differ"
|
|
32
32
|
require_relative "dotsync/utils/version_checker"
|
|
33
33
|
require_relative "dotsync/utils/config_cache"
|
|
34
|
+
require_relative "dotsync/utils/parallel"
|
|
34
35
|
|
|
35
36
|
# Models
|
|
36
37
|
require_relative "dotsync/models/mapping"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dotsync
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- David Sáenz
|
|
@@ -338,6 +338,7 @@ files:
|
|
|
338
338
|
- lib/dotsync/utils/directory_differ.rb
|
|
339
339
|
- lib/dotsync/utils/file_transfer.rb
|
|
340
340
|
- lib/dotsync/utils/logger.rb
|
|
341
|
+
- lib/dotsync/utils/parallel.rb
|
|
341
342
|
- lib/dotsync/utils/path_utils.rb
|
|
342
343
|
- lib/dotsync/utils/version_checker.rb
|
|
343
344
|
- lib/dotsync/version.rb
|