dotsync 0.1.26 → 0.1.27

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 89c25a6529e3557dc1383f3facf677f0775053d7db53863b7cc61a5b44d13b11
4
- data.tar.gz: 1cfadbe1c539923fb6bf9c27eafde24beeab527feeaadf2b88d997d762f972b4
3
+ metadata.gz: 6d2cef06dff635c8202f87424d1532d0db5cfdf7e26e1c0c98daee44acdd12e4
4
+ data.tar.gz: 38484cab4e99854a8b54259e222ace225834000c9d9a6df8005dff8b1baa228c
5
5
  SHA512:
6
- metadata.gz: 2b7012240c48cd7b9d84cf8e20d54efa913fd08324720b08d270db0c39e46f87a1f63f124e6d562d06ab2bef7f0fd017bb686e666b40866fc89eceae831de1bf
7
- data.tar.gz: 87f03124b8dc8cad8c3588d3391858414ac0a577416c7a227465702a081c8de9fa36648e5eb5c642ba9b6beae81c19043259c25b536a634cd3bfcd3b83a7cfc9
6
+ metadata.gz: 22d5fe759b17a723377363c22f05f77cedf57fd6ac41b4c8d379c2f2b2bf4fb42022a0c92707083356a096385fe51b1175c9865fb1f78fde58ba41b94be9fa17
7
+ data.tar.gz: 3fb40ad4ac4835cf0c3a45e8bb3d872197dc60bb79d04b8a6ff09d5626d6b92f63865b035d5eb7cc923f12319b4651e08ffe36e808296d002f88712e5bc54730
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- dotsync (0.1.26)
4
+ dotsync (0.1.27)
5
5
  fileutils (~> 1.7.3)
6
6
  find (~> 0.2.0)
7
7
  listen (~> 3.9.0)
data/exe/dotsync CHANGED
@@ -51,6 +51,7 @@ opt_parser = OptionParser.new do |opts|
51
51
  --only-config Show only the config section
52
52
  --only-mappings Show only the mappings section
53
53
  -v, --verbose Force showing all available information
54
+ --diff-content Show git-like content diff for modified files
54
55
  --trace Show full error backtraces (for debugging)
55
56
  --version Show version number
56
57
  -h, --help Show this help message
@@ -112,6 +113,10 @@ opt_parser = OptionParser.new do |opts|
112
113
  options[:verbose] = true
113
114
  end
114
115
 
116
+ opts.on("--diff-content", "Show git-like content diff for modified files") do
117
+ options[:diff_content] = true
118
+ end
119
+
115
120
  opts.on("--trace", "Show full error backtraces (for debugging)") do
116
121
  options[:trace] = true
117
122
  end
@@ -62,7 +62,7 @@ module Dotsync
62
62
  logger.log("")
63
63
  end
64
64
 
65
- def show_differences
65
+ def show_differences(diff_content: false)
66
66
  info("Differences:", icon: :diff)
67
67
  differs.flat_map(&:additions).sort.each do |path|
68
68
  logger.log("#{Icons.diff_created}#{path}", color: Colors.diff_additions)
@@ -75,6 +75,15 @@ module Dotsync
75
75
  end
76
76
  logger.log(" No differences") unless has_differences?
77
77
  logger.log("")
78
+
79
+ show_content_diffs if diff_content && has_modifications?
80
+ end
81
+
82
+ def show_content_diffs
83
+ info("Content Differences:", icon: :diff)
84
+ modification_pairs.each do |pair|
85
+ Dotsync::ContentDiff.new(pair[:src], pair[:dest], logger).display
86
+ end
78
87
  end
79
88
 
80
89
  def transfer_mappings
@@ -108,6 +117,14 @@ module Dotsync
108
117
  differs.any? { |differ| differ.any? }
109
118
  end
110
119
 
120
+ def has_modifications?
121
+ differs.any? { |differ| differ.modifications.any? }
122
+ end
123
+
124
+ def modification_pairs
125
+ differs.flat_map(&:modification_pairs)
126
+ end
127
+
111
128
  def confirm_action
112
129
  total_changes = differs.sum { |diff| diff.additions.size + diff.modifications.size + diff.removals.size }
113
130
  logger.log("")
@@ -12,7 +12,8 @@ module Dotsync
12
12
  mappings_legend: !(quiet || options[:no_legend] || options[:no_mappings] || options[:only_diff]),
13
13
  mappings: !(quiet || options[:no_mappings] || options[:only_diff]),
14
14
  differences_legend: !(quiet || options[:no_legend] || options[:no_diff_legend] || options[:no_diff] || options[:only_config] || options[:only_mappings]),
15
- differences: !(quiet || options[:no_diff] || options[:only_mappings] || options[:only_config])
15
+ differences: !(quiet || options[:no_diff] || options[:only_mappings] || options[:only_config]),
16
+ diff_content: options[:diff_content] || false
16
17
  }
17
18
 
18
19
  if verbose
@@ -15,7 +15,7 @@ module Dotsync
15
15
  show_mappings_legend if output_sections[:mappings_legend]
16
16
  show_mappings if output_sections[:mappings]
17
17
  show_differences_legend if has_differences? && output_sections[:differences_legend]
18
- show_differences if output_sections[:differences]
18
+ show_differences(diff_content: output_sections[:diff_content]) if output_sections[:differences]
19
19
 
20
20
  return unless options[:apply]
21
21
 
@@ -13,7 +13,7 @@ module Dotsync
13
13
  show_mappings_legend if output_sections[:mappings_legend]
14
14
  show_mappings if output_sections[:mappings]
15
15
  show_differences_legend if has_differences? && output_sections[:differences_legend]
16
- show_differences if output_sections[:differences]
16
+ show_differences(diff_content: output_sections[:diff_content]) if output_sections[:differences]
17
17
 
18
18
  return unless options[:apply]
19
19
 
@@ -11,6 +11,7 @@ require "terminal-table"
11
11
  require_relative "../utils/file_transfer"
12
12
  require_relative "../utils/directory_differ"
13
13
  require_relative "../utils/config_cache"
14
+ require_relative "../utils/content_diff"
14
15
 
15
16
  # Models
16
17
  require_relative "../models/mapping"
@@ -11,6 +11,7 @@ require "terminal-table"
11
11
  require_relative "../utils/file_transfer"
12
12
  require_relative "../utils/directory_differ"
13
13
  require_relative "../utils/config_cache"
14
+ require_relative "../utils/content_diff"
14
15
 
15
16
  # Models
16
17
  require_relative "../models/mapping"
@@ -3,12 +3,13 @@
3
3
  module Dotsync
4
4
  # Represents the differences between two directories
5
5
  class Diff
6
- attr_reader :additions, :modifications, :removals
6
+ attr_reader :additions, :modifications, :removals, :modification_pairs
7
7
 
8
- def initialize(additions: [], modifications: [], removals: [])
8
+ def initialize(additions: [], modifications: [], removals: [], modification_pairs: [])
9
9
  @additions = additions
10
10
  @modifications = modifications
11
11
  @removals = removals
12
+ @modification_pairs = modification_pairs
12
13
  end
13
14
 
14
15
  def any?
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dotsync
4
+ class ContentDiff
5
+ COLORS = {
6
+ header: 103, # Purple for file headers
7
+ hunk: 36, # Cyan for @@ lines
8
+ addition: 34, # Blue for added lines (consistent with diff_additions)
9
+ deletion: 88, # Red for removed lines (consistent with diff_removals)
10
+ context: 240 # Gray for context lines
11
+ }.freeze
12
+
13
+ def initialize(src_path, dest_path, logger)
14
+ @src_path = src_path
15
+ @dest_path = dest_path
16
+ @logger = logger
17
+ end
18
+
19
+ def display
20
+ return unless displayable?
21
+
22
+ diff_output = generate_diff
23
+ return if diff_output.empty?
24
+
25
+ display_header
26
+ colorize_and_display(diff_output)
27
+ end
28
+
29
+ private
30
+ def displayable?
31
+ text_file?(@src_path) && text_file?(@dest_path)
32
+ end
33
+
34
+ def text_file?(path)
35
+ return false unless File.file?(path)
36
+
37
+ # Check if file appears to be text by reading first few bytes
38
+ begin
39
+ sample = File.read(path, 8192) || ""
40
+ # Binary files typically contain null bytes
41
+ !sample.include?("\x00")
42
+ rescue StandardError
43
+ false
44
+ end
45
+ end
46
+
47
+ def generate_diff
48
+ # Use system diff with unified format
49
+ # diff returns exit code 1 when files differ, so we can't use backticks directly
50
+ output = `diff -u "#{@dest_path}" "#{@src_path}" 2>/dev/null`
51
+ output.lines.drop(2).join # Drop the first two header lines, we'll add our own
52
+ rescue StandardError
53
+ ""
54
+ end
55
+
56
+ def display_header
57
+ @logger.log("--- #{@dest_path}", color: COLORS[:header])
58
+ @logger.log("+++ #{@src_path}", color: COLORS[:header])
59
+ end
60
+
61
+ def colorize_and_display(diff_output)
62
+ diff_output.each_line do |line|
63
+ color = line_color(line)
64
+ @logger.log(line.chomp, color: color)
65
+ end
66
+ @logger.log("")
67
+ end
68
+
69
+ def line_color(line)
70
+ case line[0]
71
+ when "+"
72
+ COLORS[:addition]
73
+ when "-"
74
+ COLORS[:deletion]
75
+ when "@"
76
+ COLORS[:hunk]
77
+ else
78
+ COLORS[:context]
79
+ end
80
+ end
81
+ end
82
+ end
@@ -31,6 +31,7 @@ module Dotsync
31
31
  def diff_mapping_directories
32
32
  additions = []
33
33
  modifications = []
34
+ modification_pairs = []
34
35
  removals = []
35
36
 
36
37
  Find.find(mapping_src) do |src_path|
@@ -48,6 +49,7 @@ module Dotsync
48
49
  elsif File.file?(src_path) && File.file?(dest_path)
49
50
  if files_differ?(src_path, dest_path)
50
51
  modifications << rel_path
52
+ modification_pairs << { rel_path: rel_path, src: src_path, dest: dest_path }
51
53
  end
52
54
  end
53
55
  end
@@ -67,21 +69,29 @@ module Dotsync
67
69
  end
68
70
  end
69
71
 
72
+ filtered_modifications = filter_ignores(modifications)
73
+ modification_pairs = modification_pairs.select { |pair| filtered_modifications.include?(pair[:rel_path]) }
74
+
70
75
  additions = relative_to_absolute(filter_ignores(additions), mapping_original_dest)
71
- modifications = relative_to_absolute(filter_ignores(modifications), mapping_original_dest)
76
+ modifications = relative_to_absolute(filtered_modifications, mapping_original_dest)
72
77
  removals = relative_to_absolute(filter_ignores(removals), mapping_original_dest)
73
78
 
74
- Dotsync::Diff.new(additions: additions, modifications: modifications, removals: removals)
79
+ Dotsync::Diff.new(additions: additions, modifications: modifications, removals: removals, modification_pairs: modification_pairs)
75
80
  end
76
81
 
77
82
  def diff_mapping_files
78
- Dotsync::Diff.new.tap do |diff|
79
- if @mapping.file_present_in_src_only?
80
- diff.additions << @mapping.original_dest
81
- elsif @mapping.file_changed?
82
- diff.modifications << @mapping.original_dest
83
- end
83
+ additions = []
84
+ modifications = []
85
+ modification_pairs = []
86
+
87
+ if @mapping.file_present_in_src_only?
88
+ additions << @mapping.original_dest
89
+ elsif @mapping.file_changed?
90
+ modifications << @mapping.original_dest
91
+ modification_pairs << { rel_path: File.basename(@mapping.original_dest), src: @mapping.src, dest: @mapping.dest }
84
92
  end
93
+
94
+ Dotsync::Diff.new(additions: additions, modifications: modifications, modification_pairs: modification_pairs)
85
95
  end
86
96
 
87
97
  def filter_ignores(all_paths)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Dotsync
4
- VERSION = "0.1.26"
4
+ VERSION = "0.1.27"
5
5
  end
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.1.26
4
+ version: 0.1.27
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Sáenz
@@ -334,6 +334,7 @@ files:
334
334
  - lib/dotsync/runner.rb
335
335
  - lib/dotsync/tasks/actions.rake
336
336
  - lib/dotsync/utils/config_cache.rb
337
+ - lib/dotsync/utils/content_diff.rb
337
338
  - lib/dotsync/utils/directory_differ.rb
338
339
  - lib/dotsync/utils/file_transfer.rb
339
340
  - lib/dotsync/utils/logger.rb