dotsync 0.1.2 → 0.1.4

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: '08b051bb2f245604662fd3f8347c70152dffb43d243d96bef919c38433a53124'
4
- data.tar.gz: 79c2af0084417ad7c8253deac085b0466bbfd5d3c7b0c20054e92899907921b9
3
+ metadata.gz: 77103d8c8a478216d16d1dcafe30fb6e6db158df43da7749245b55b8066c2d8c
4
+ data.tar.gz: 87762883d28d5afa94020faec9f9fad6d681345872e8dfed92234ded3d0816a4
5
5
  SHA512:
6
- metadata.gz: 21107170e600b1649aebdf5c5b4a2b4750c796c6800684a3a9bf3bf32eac88c6ea3a55056c7bab5a910b4a244aa95bae56627d222f56756f376704992a3bbdd7
7
- data.tar.gz: 4b920346a4a3dd410e35374678a957517a53d3dbcbe4fff737c7a0e88040c842e0a526728d923bd471b85c5660a5505ea0eeb4e5fe7dd22734b45e7b4c6d1d63
6
+ metadata.gz: fc405ffb5b91817d04bd3cb956afa5072775ae8553ba52560e4c6a4cf769ad8d51c0e3a3a8b7b27b486b7f894cd305a6a2c35d6372c1f7a14fed838353a283cd
7
+ data.tar.gz: 809db157e89fd45045a80d75fe55775677efa9b7ebda413f4bfd5e95f765769a3447afbf7edd839f2a68d481e569fe33f59c06e2679ab08b4b097b423023cba3
data/CHANGELOG.md CHANGED
@@ -1,3 +1,18 @@
1
+ # 0.1.4
2
+
3
+ Colorized environment variables
4
+ Fixed colorized mapping entries
5
+
6
+ # 0.1.3
7
+
8
+ PushAction: Avoid error on missing destination
9
+ Unify mappings print. Use icon for ignores presence.
10
+ Extracted icons to its own module
11
+ Reviewed icons
12
+ Updated README with existing mapping entries icons
13
+ Customizable icons
14
+ Logger review
15
+
1
16
  # 0.1.2
2
17
 
3
18
  Add gem version on usage banner
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- dotsync (0.1.2)
4
+ dotsync (0.1.4)
5
5
  fileutils (~> 1.7.3)
6
6
  listen (~> 3.9.0)
7
7
  logger (~> 1.7.0)
@@ -26,7 +26,7 @@ GEM
26
26
  ffi (1.17.2-x86_64-linux-gnu)
27
27
  ffi (1.17.2-x86_64-linux-musl)
28
28
  fileutils (1.7.3)
29
- json (2.15.0)
29
+ json (2.15.2)
30
30
  language_server-protocol (3.17.0.5)
31
31
  lint_roller (1.1.0)
32
32
  listen (3.9.0)
@@ -38,7 +38,7 @@ GEM
38
38
  parser (3.3.9.0)
39
39
  ast (~> 2.4.1)
40
40
  racc
41
- prism (1.5.1)
41
+ prism (1.6.0)
42
42
  racc (1.8.1)
43
43
  rainbow (3.1.1)
44
44
  rake (13.3.0)
@@ -48,20 +48,20 @@ GEM
48
48
  rbs (3.9.5)
49
49
  logger
50
50
  regexp_parser (2.11.3)
51
- rspec (3.13.1)
51
+ rspec (3.13.2)
52
52
  rspec-core (~> 3.13.0)
53
53
  rspec-expectations (~> 3.13.0)
54
54
  rspec-mocks (~> 3.13.0)
55
- rspec-core (3.13.5)
55
+ rspec-core (3.13.6)
56
56
  rspec-support (~> 3.13.0)
57
57
  rspec-expectations (3.13.5)
58
58
  diff-lcs (>= 1.2.0, < 2.0)
59
59
  rspec-support (~> 3.13.0)
60
- rspec-mocks (3.13.5)
60
+ rspec-mocks (3.13.6)
61
61
  diff-lcs (>= 1.2.0, < 2.0)
62
62
  rspec-support (~> 3.13.0)
63
63
  rspec-support (3.13.6)
64
- rubocop (1.81.1)
64
+ rubocop (1.81.6)
65
65
  json (~> 2.3)
66
66
  language_server-protocol (~> 3.17.0.2)
67
67
  lint_roller (~> 1.1.0)
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # Dotsync
2
2
 
3
+ **⚠️ Warning: This gem is under active development. You can expect new changes that may not be backward-compatible.**
4
+
3
5
  [![Ruby Gem Test Status](https://github.com/dsaenztagarro/dotsync/actions/workflows/gem-push.yml/badge.svg)](https://github.com/dsaenztagarro/dotsync/actions)
4
6
 
5
7
  Welcome to Dotsync! This gem helps you manage and synchronize your dotfiles effortlessly. Below you'll find information on installation, usage, and some tips for getting started.
@@ -72,6 +74,40 @@ mappings = [
72
74
  ]
73
75
  ```
74
76
 
77
+ #### `force` and `ignore` Options in Mappings
78
+
79
+ Each mapping entry supports the following options:
80
+
81
+ - **`force`**: A boolean (true/false) value. When set to `true`, it forces deletion of the destination folder before transferring files from the source. This is particularly useful when you need to ensure that the destination is clean before a transfer.
82
+ - **`ignore`**: An array of patterns or file names to exclude during the transfer. This allows you to specify files or folders that should not be copied from the source to the destination.
83
+
84
+ These options apply when the source is a directory and are relevant for both `push` and `pull` operations.
85
+
86
+ ### Rendering Mappings with Icons
87
+
88
+ When running `push` or `pull` actions, the mappings are rendered in the console with relevant icons to provide visual feedback on the status of each mapping. To correctly view these icons, ensure you are using a terminal that supports a patched [Nerd Font](https://www.nerdfonts.com). Below are some examples of how the mappings are displayed:
89
+
90
+ - **Force Icon**:
91
+ ```
92
+ Mappings:
93
+ $DOTFILES_DIR/config/ → $XDG_CONFIG_HOME ⚡
94
+ ```
95
+ The ⚡ icon (`Dotsync::Icons::FORCE`) indicates that the `force` option is enabled and the destination folder will be cleared before the transfer.
96
+
97
+ - **Ignore Icon**:
98
+ ```
99
+ Mappings:
100
+ $DOTFILES_DIR/home/.zshenv → $HOME 🚫
101
+ ```
102
+ The 🚫 icon (`Dotsync::Icons::IGNORE`) indicates that certain files or patterns are being ignored during the transfer.
103
+
104
+ - **Invalid Icon**:
105
+ ```
106
+ Mappings:
107
+ $DOTFILES_DIR/home/.vimrc → $HOME ❌
108
+ ```
109
+ The ❌ icon (`Dotsync::Icons::INVALID`) indicates that the mapping is invalid due to missing source or destination paths.
110
+
75
111
  ### Pro Tips
76
112
 
77
113
  - **Using rbenv**: To ensure the gem uses the correct Ruby version managed by rbenv, you can run:
@@ -9,35 +9,12 @@ module Dotsync
9
9
  def_delegator :logger, :action
10
10
 
11
11
  def initialize(config, logger)
12
- @log_queue = Queue.new
13
12
  @config = config
14
13
  @logger = logger
15
- setup_logger_thread
16
- setup_signal_trap
17
14
  end
18
15
 
19
16
  def execute
20
17
  raise NotImplementedError
21
18
  end
22
-
23
- private
24
-
25
- def setup_signal_trap
26
- Signal.trap("INT") do
27
- @log_queue << { type: :info, message: "Shutting down gracefully...", icon: :bell }
28
- exit
29
- end
30
- end
31
-
32
- def setup_logger_thread
33
- return if ENV['TEST_ENV'] == 'true'
34
-
35
- Thread.new do
36
- loop do
37
- log_entry = @log_queue.pop
38
- @logger.info(log_entry[:message], icon: log_entry[:icon])
39
- end
40
- end
41
- end
42
19
  end
43
20
  end
@@ -0,0 +1,25 @@
1
+ module Dotsync
2
+ module MappingsTransfer
3
+ extend Forwardable # def_delegator
4
+
5
+ def_delegator :@config, :mappings
6
+
7
+ def show_mappings
8
+ info("Mappings:", icon: :config, )
9
+
10
+ mappings.each do |mapping|
11
+ logger.log(" #{mapping}")
12
+ end
13
+ end
14
+
15
+ def transfer_mappings
16
+ valid_mappings.each do |mapping|
17
+ Dotsync::FileTransfer.new(mapping).transfer
18
+ end
19
+ end
20
+
21
+ def valid_mappings
22
+ mappings.select(&:valid?)
23
+ end
24
+ end
25
+ end
@@ -32,12 +32,17 @@ module Dotsync
32
32
  end
33
33
 
34
34
  def valid?
35
- File.exist?(@sanitized_src) && File.exist?(@sanitized_dest)
35
+ File.exist?(@sanitized_src) && File.exist?(File.dirname(@sanitized_dest))
36
36
  end
37
37
 
38
38
  def to_s
39
- force_icon = force? ? " #{icon_delete}" : ""
40
- "#{original_src} #{original_dest}#{force_icon}"
39
+ colorized_src = colorize_env_vars(original_src)
40
+ colorized_dest = colorize_env_vars(original_dest)
41
+ msg = ["#{colorized_src} → #{colorized_dest}"]
42
+ msg << Icons.force if force?
43
+ msg << Icons.ignore if ignores?
44
+ msg << Icons.invalid unless valid?
45
+ msg.join(" ")
41
46
  end
42
47
 
43
48
  def applied_to(path)
@@ -57,8 +62,8 @@ module Dotsync
57
62
 
58
63
  private
59
64
 
60
- def icon_delete
61
- Dotsync::Logger::ICONS[:delete]
65
+ def ignores?
66
+ @original_ignores.any?
62
67
  end
63
68
  end
64
69
  end
@@ -1,6 +1,7 @@
1
1
  module Dotsync
2
2
  class PullAction < BaseAction
3
- def_delegator :@config, :mappings
3
+ include MappingsTransfer
4
+
4
5
  def_delegator :@config, :backups_root
5
6
 
6
7
  def execute
@@ -15,17 +16,18 @@ module Dotsync
15
16
  private
16
17
 
17
18
  def show_config
18
- info("Mappings:", icon: :source_dest)
19
- mappings.each do |mapping|
20
- force_icon = mapping.force? ? " #{icon_delete}" : ""
21
- info(" src: #{mapping.original_src} -> dest: #{mapping.original_dest}#{force_icon}", icon: :copy)
22
- info(" ignores: #{mapping.ignores.join(', ')}", icon: :exclude) if mapping.ignores.any?
23
- end
19
+ show_mappings
20
+ end
21
+
22
+ def pull_dotfiles
23
+ transfer_mappings
24
+
25
+ action("Dotfiles pulled", icon: :copy)
24
26
  end
25
27
 
26
28
  def show_backup
27
29
  action("Backup created:", icon: :backup)
28
- info(" #{backup_path}")
30
+ logger.log(" #{backup_path}")
29
31
  end
30
32
 
31
33
  def timestamp
@@ -37,7 +39,7 @@ module Dotsync
37
39
  end
38
40
 
39
41
  def create_backup
40
- return false unless mappings.any? { |mapping| File.exist?(mapping.dest) }
42
+ return false unless valid_mappings.any?
41
43
  FileUtils.mkdir_p(backup_path)
42
44
  mappings.each do |mapping|
43
45
  next unless File.exist?(mapping.dest)
@@ -61,14 +63,5 @@ module Dotsync
61
63
  end
62
64
  end
63
65
  end
64
-
65
- def pull_dotfiles
66
- mappings.each { |mapping| Dotsync::FileTransfer.new(mapping).transfer }
67
- action("Dotfiles pulled", icon: :copy)
68
- end
69
-
70
- def icon_delete
71
- Dotsync::Logger::ICONS[:delete]
72
- end
73
66
  end
74
67
  end
@@ -1,6 +1,6 @@
1
1
  module Dotsync
2
2
  class PushAction < BaseAction
3
- def_delegator :@config, :mappings
3
+ include MappingsTransfer
4
4
 
5
5
  def execute
6
6
  show_config
@@ -10,21 +10,13 @@ module Dotsync
10
10
  private
11
11
 
12
12
  def show_config
13
- info("Mappings:", icon: :source_dest)
14
- mappings.each do |mapping|
15
- force_icon = mapping.force? ? " #{icon_delete}" : ""
16
- info(" src: #{mapping.original_src} -> dest: #{mapping.original_dest}#{force_icon}", icon: :copy)
17
- info(" ignores: #{mapping.original_ignores.join(', ')}", icon: :exclude) if mapping.ignores.any?
18
- end
13
+ show_mappings
19
14
  end
20
15
 
21
16
  def push_dotfiles
22
- mappings.each { |mapping| Dotsync::FileTransfer.new(mapping).transfer }
23
- action("Dotfiles pushed", icon: :copy)
24
- end
17
+ transfer_mappings
25
18
 
26
- def icon_delete
27
- Dotsync::Logger::ICONS[:delete]
19
+ action("Dotfiles pushed", icon: :copy)
28
20
  end
29
21
  end
30
22
  end
@@ -5,7 +5,6 @@ module Dotsync
5
5
  def initialize(config, logger)
6
6
  super
7
7
  setup_listeners
8
- setup_logger_thread
9
8
  setup_signal_trap
10
9
  end
11
10
 
@@ -14,19 +13,16 @@ module Dotsync
14
13
 
15
14
  @listeners.each(&:start)
16
15
 
17
- logger.action("Listening for changes...", icon: :listen)
18
- info("Press Ctrl+C to exit.")
16
+ logger.action("Listening for changes...")
17
+ logger.action("Press Ctrl+C to exit.")
19
18
  sleep
20
19
  end
21
20
 
22
21
  private
23
22
 
24
23
  def show_config
25
- info("Mappings:", icon: :watch)
26
- mappings.each do |mapping|
27
- info(" #{mapping}", icon: :copy)
28
- info(" Excludes: #{mapping.ignores.join(', ')}", icon: :exclude) if mapping.ignores.any?
29
- end
24
+ logger.info("Mappings:", icon: :config)
25
+ mappings.each { |mapping| logger.log(" #{mapping}") }
30
26
  end
31
27
 
32
28
  def setup_listeners
@@ -51,22 +47,22 @@ module Dotsync
51
47
  def handle_file_changes(mapping, modified, added, removed)
52
48
  (modified + added).each do |path|
53
49
  new_mapping = mapping.applied_to(path)
54
- logger.info("Copied file: #{new_mapping.original_src}", icon: :copy)
50
+ logger.info("Copied file: #{new_mapping}", icon: :copy)
55
51
  Dotsync::FileTransfer.new(new_mapping).transfer
56
52
  end
57
53
  removed.each do |path|
58
- logger.info("File removed: #{path}", icon: :delete)
54
+ logger.info("File removed: #{path}", icon: :delete, bold: false)
59
55
  end
60
56
  end
61
57
 
62
58
  def setup_signal_trap
63
- listeners = @listeners.dup
64
59
  Signal.trap("INT") do
65
60
  # Using a new thread to handle the signal trap context,
66
61
  # as Signal.trap runs in a more restrictive environment
67
62
  Thread.new do
68
- logger.action("Shutting down listeners...", icon: :bell)
69
- listeners.each(&:stop)
63
+ logger.log("")
64
+ logger.action("Shutting down listeners...")
65
+ @listeners.each(&:stop)
70
66
  exit
71
67
  end
72
68
  end
@@ -0,0 +1,74 @@
1
+ module Dotsync
2
+ module Icons
3
+ # Log level icons
4
+ INFO = " "
5
+ ERROR = " "
6
+
7
+ # Configuration icon
8
+ CONFIG = " "
9
+
10
+ # Default MappingEntry icons
11
+ DEFAULT_FORCE = "󰁪 "
12
+ DEFAULT_IGNORE = "󰈉 "
13
+ DEFAULT_INVALID = "󱏏 "
14
+
15
+ # Action icons
16
+ PULL = " "
17
+ PUSH = " "
18
+ WATCH = "󰛐 "
19
+
20
+ # TODO: review icons needed
21
+ CONSOLE = "󰆍 "
22
+ LISTEN = " "
23
+ SOURCE = " " #  "
24
+ DEST = " " # " "
25
+ BELL = " "
26
+ COPY = " "
27
+ SKIP = " "
28
+ DONE = " "
29
+ BACKUP = " "
30
+
31
+ @custom_icons = {}
32
+
33
+ def self.load_custom_icons(config)
34
+ @custom_icons = {
35
+ force: config.dig("icons", "force") || DEFAULT_FORCE,
36
+ ignore: config.dig("icons", "ignore") || DEFAULT_IGNORE,
37
+ invalid: config.dig("icons", "invalid") || DEFAULT_INVALID
38
+ }
39
+ end
40
+
41
+ def self.force
42
+ @custom_icons[:force] || DEFAULT_FORCE
43
+ end
44
+
45
+ def self.ignore
46
+ @custom_icons[:ignore] || DEFAULT_IGNORE
47
+ end
48
+
49
+ def self.invalid
50
+ @custom_icons[:invalid] || DEFAULT_INVALID
51
+ end
52
+
53
+ # https://www.nerdfonts.com
54
+ MAPPINGS = {
55
+ info: INFO,
56
+ error: ERROR,
57
+ config: CONFIG,
58
+ force: -> { force },
59
+ ignore: -> { ignore },
60
+ pull: PULL,
61
+ push: PUSH,
62
+ watch: WATCH,
63
+ console: CONSOLE,
64
+ listen: LISTEN,
65
+ source: SOURCE,
66
+ dest: DEST,
67
+ bell: BELL,
68
+ copy: COPY,
69
+ skip: SKIP,
70
+ done: DONE,
71
+ backup: BACKUP
72
+ }
73
+ end
74
+ end
@@ -2,60 +2,36 @@ module Dotsync
2
2
  class Logger
3
3
  attr_accessor :output
4
4
 
5
- # 🎨 Nerd Font Icons
6
- ICONS = {
7
- info: " ",
8
- listen: " ",
9
- error: " ",
10
- watch: " ",
11
- source: " ", #  ",
12
- dest: " ", # " ",
13
- delete: " ",
14
- bell: " ",
15
- copy: " ",
16
- skip: " ",
17
- done: " ",
18
- backup: " ",
19
- clean: " ",
20
- }
5
+ # NOTE: use Rake tasks "palette:fg" and "palette:bg" to select a proper ASCII color code
21
6
 
22
7
  def initialize(output = $stdout)
23
8
  @output = output
24
9
  end
25
10
 
26
- def info(message, options = {})
27
- log(:info, message, options)
11
+ def action(message, color: 153, bold: true, icon: :console)
12
+ log(message, color: color, bold: bold, icon: icon)
28
13
  end
29
14
 
30
- def action(message, options = {})
31
- log(:action, message, options)
15
+ def info(message, color: 103, bold: true, icon: :info)
16
+ log(message, color: color, bold: bold, icon: icon)
32
17
  end
33
18
 
34
- def success(message)
35
- log(:success, message, icon: :done)
19
+ def error(message, color: 196, bold: true, icon: :error)
20
+ log(message, color: color, bold: bold, icon: icon)
36
21
  end
37
22
 
38
- def error(message)
39
- log(:error, message, icon: :error)
40
- end
23
+ def log(message, color: 0, bold: false, icon: nil)
24
+ mapped_icon = Dotsync::Icons::MAPPINGS[icon] if icon
41
25
 
42
- def warning(message, options = {})
43
- log(:warning, message, options)
44
- end
26
+ msg = []
27
+ msg << "\e[38;5;#{color}m" if color > 0
28
+ msg << "\e[1m" if bold
29
+ msg << mapped_icon if mapped_icon
30
+ msg << message
31
+ msg << "\e[0m" if color > 0 # reset color
32
+ msg = msg.join("")
45
33
 
46
- def log(type, message, options = {})
47
- icon = options[:icon]
48
- color = {
49
- info: 103, action: 153, error: 196, event: 141, warning: 31, copy: 32,
50
- skip: 33, done: 32, backup: 35,
51
- clean: 34
52
- }[type] || 0
53
-
54
- if icon.nil?
55
- @output.puts message
56
- else
57
- @output.puts "\e[38;5;#{color}m\e[1m#{ICONS[icon]}#{message}\e[0m"
58
- end
34
+ @output.puts msg
59
35
  end
60
36
  end
61
37
  end
@@ -1,9 +1,15 @@
1
1
  module Dotsync
2
2
  module PathUtils
3
+ ENV_VARS_COLOR = 104
4
+
3
5
  def expand_env_vars(path)
4
6
  path.gsub(/\$(\w+)/) { ENV[$1] }
5
7
  end
6
8
 
9
+ def colorize_env_vars(path)
10
+ path.gsub(/\$(\w+)/) { "\e[38;5;#{ENV_VARS_COLOR}m$#{$1}\e[0m" }
11
+ end
12
+
7
13
  # Translates /tmp paths to /private/tmp paths on macOS
8
14
  # Retains other paths as-is
9
15
  # @param [String] path The input path to translate
@@ -1,3 +1,3 @@
1
1
  module Dotsync
2
- VERSION = "0.1.2"
2
+ VERSION = "0.1.4"
3
3
  end
data/lib/dotsync.rb CHANGED
@@ -10,6 +10,7 @@ require 'ostruct'
10
10
  require_relative "dotsync/errors"
11
11
 
12
12
  # Utils
13
+ require_relative 'dotsync/icons'
13
14
  require_relative 'dotsync/logger'
14
15
  require_relative 'dotsync/file_transfer'
15
16
  require_relative 'dotsync/path_utils'
@@ -22,6 +23,9 @@ require_relative "dotsync/actions/config/pull_action_config"
22
23
  require_relative "dotsync/actions/config/push_action_config"
23
24
  require_relative "dotsync/actions/config/watch_action_config"
24
25
 
26
+ # Concerns
27
+ require_relative "dotsync/actions/concerns/mappings_transfer"
28
+
25
29
  # Actions
26
30
  require_relative "dotsync/actions/base_action"
27
31
  require_relative "dotsync/actions/pull_action"
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.2
4
+ version: 0.1.4
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-10-22 00:00:00.000000000 Z
11
+ date: 2025-10-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: toml-rb
@@ -179,6 +179,7 @@ files:
179
179
  - exe/setup
180
180
  - lib/dotsync.rb
181
181
  - lib/dotsync/actions/base_action.rb
182
+ - lib/dotsync/actions/concerns/mappings_transfer.rb
182
183
  - lib/dotsync/actions/config/base_config.rb
183
184
  - lib/dotsync/actions/config/mapping_entry.rb
184
185
  - lib/dotsync/actions/config/pull_action_config.rb
@@ -190,6 +191,7 @@ files:
190
191
  - lib/dotsync/actions/watch_action.rb
191
192
  - lib/dotsync/errors.rb
192
193
  - lib/dotsync/file_transfer.rb
194
+ - lib/dotsync/icons.rb
193
195
  - lib/dotsync/logger.rb
194
196
  - lib/dotsync/path_utils.rb
195
197
  - lib/dotsync/runner.rb