entangler 1.0.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: c37e01ff82caac966cc6914e8ce9b3ae76820106
4
- data.tar.gz: eb49a80d236d3a4ea41aae48b354de2be624e567
2
+ SHA256:
3
+ metadata.gz: 04a6d5ab6db60640272b7acd3922ba845d2ab171ee4001f4be0b753b7d151c28
4
+ data.tar.gz: 962a2ab010fffe236dea92a6f5eba83d0ade41ce4edb9af0f867054d2923279c
5
5
  SHA512:
6
- metadata.gz: e652cb24a4724fa59c4c68f687a7e36cb5a63ecf4f59fa23ab42563fefd0e6e2c500c0f2a55ebfa9aca01b4fb4908443b093d3f63a2188198aeefd392997a36e
7
- data.tar.gz: b0f8dd950f5a0946f9738db12f43a41a44b313034ec4bc0b13362cdce3c3b04a638ea908b0a730d735b3fa4533d271eb6a1b8095308069a4220d1569728a3763
6
+ metadata.gz: 3db61680fd1d006a4ce4dd9a1559c95090c74c898e8c4668378eb4ee5e440f919960104b1d97a62e14846214619e825f16f00385a72fdc4aae05b70dc565ad34
7
+ data.tar.gz: 65567038136a7bb19280347c8f1a82a59e5b40e0627d4be1ac79f54057c73f00a34b0a91ac8c81e2996a1e646e5649b989122a013db2aaf6377a4109ff333743
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source 'https://rubygems.org'
2
4
 
3
5
  # Specify your gem's dependencies in entangler.gemspec
data/README.md CHANGED
@@ -1,4 +1,5 @@
1
- # Entangler
1
+ <p align="center" style="width: 50px;"><img src="https://vignette1.wikia.nocookie.net/pokemon/images/e/ef/114Tangela_Dream.png/revision/latest/scale-to-width-down/185?cb=20141203054028"/></p>
2
+ <h1 align="center">Entangler</h1>
2
3
 
3
4
  [![Build Status](https://travis-ci.org/daveallie/entangler.svg?branch=master)](https://travis-ci.org/daveallie/entangler)
4
5
 
@@ -18,7 +19,7 @@ $ entangler master /some/base/path user@remote:/some/remote/path
18
19
 
19
20
  ```
20
21
  $ entangler -h
21
- Entangler v1.0.1
22
+ Entangler v1.2.0
22
23
 
23
24
  Usage:
24
25
  entangler master <base_dir> <remote_user>@<remote_host>:<remote_base_dir> [options]
@@ -30,14 +31,15 @@ Options:
30
31
  -p, --port PORT Overwrite the SSH port (usually 22)
31
32
  (doesn't do anything in slave mode)
32
33
  -v, --verbose Log Debug lines
34
+ -q, --quiet Don't log to stdout in master process
33
35
  --version Show version number
34
36
  -h, --help Show this message
35
37
  ```
36
38
 
37
39
  ### Ignoring files and folders
38
40
 
39
- If you specify a string, instead of a regex, it will match any path starting with that string, i.e. `-i '.git'` will ignore the `.git`
40
- folder and all its sub-directories. If you want to just ignore the the `.git` sub-directories but not the content in the git folder, you'll
41
+ If you specify a string, instead of a regex, it will match any path starting with that string, i.e. `-i '.git'` will ignore the `.git`
42
+ folder and all its sub-directories. If you want to just ignore the the `.git` sub-directories but not the content in the git folder, you'll
41
43
  have to use regex. `-i '/^\.git(?:\/[^\/]+){2,}$/'` will match all sub-directories of `.git/`, but not the files in `.git`.
42
44
 
43
45
  You can specify multiple `-i` or `--ignore` flags to ignore multiple paths.
@@ -1,5 +1,6 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
3
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
5
  require 'entangler/version'
5
6
 
@@ -14,15 +15,19 @@ Gem::Specification.new do |spec|
14
15
  spec.homepage = 'https://github.com/daveallie/entangler'
15
16
  spec.license = 'MIT'
16
17
 
17
- spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.files = Dir['lib/**/*'] + Dir['exe/**/*'] + %w[CODE_OF_CONDUCT.md LICENSE.txt README.md
19
+ Gemfile entangler.gemspec]
18
20
  spec.bindir = 'exe'
19
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
+ spec.executables = ['entangler']
20
22
  spec.require_paths = ['lib']
23
+ spec.required_ruby_version = '>= 2.5'
21
24
 
22
- spec.add_development_dependency 'bundler', '~> 1.12'
23
- spec.add_development_dependency 'rake', '~> 10.0'
24
- spec.add_development_dependency 'rspec', '~> 3.0'
25
- spec.add_development_dependency 'rubocop', '~> 0.46'
26
- spec.add_dependency 'listen', '~> 3.1'
27
- spec.add_dependency 'to_regexp', '~> 0.2'
25
+ spec.add_development_dependency 'bundler', '>= 2.1'
26
+ spec.add_development_dependency 'rake', '>= 13.0.1'
27
+ spec.add_development_dependency 'rspec', '>= 3.9'
28
+ spec.add_development_dependency 'rubocop', '~> 1.6'
29
+ spec.add_development_dependency 'rubocop-rake', '~> 0.5.1'
30
+ spec.add_development_dependency 'rubocop-rspec', '~> 2.0'
31
+ spec.add_dependency 'listen', '~> 3.3'
32
+ spec.add_dependency 'to_regexp', '~> 0.2.1'
28
33
  end
@@ -1,8 +1,22 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
2
4
  require 'entangler'
3
5
  require 'optparse'
4
6
  require 'to_regexp'
5
7
 
8
+ def bool_opt(options, opts, key, *args)
9
+ opts.on(*args) do
10
+ options[key] = true
11
+ end
12
+ end
13
+
14
+ def value_opt(options, opts, key, *args)
15
+ opts.on(*args) do |val|
16
+ options[key] = val
17
+ end
18
+ end
19
+
6
20
  options = {}
7
21
  OptionParser.new do |opts|
8
22
  opts.banner = %(Entangler v#{Entangler::VERSION}
@@ -20,13 +34,10 @@ Usage:
20
34
  options[:ignore] << ignore
21
35
  end
22
36
 
23
- opts.on('-p', '--port PORT', 'Overwrite the SSH port (usually 22)', "(doesn't do anything in slave mode)") do |port|
24
- options[:port] = port
25
- end
26
-
27
- opts.on('-v', '--verbose', 'Log Debug lines') do
28
- options[:verbose] = true
29
- end
37
+ value_opt(options, opts, :port, '-p', '--port PORT', 'Overwrite the SSH port (usually 22)',
38
+ "(doesn't do anything in slave mode)")
39
+ bool_opt(options, opts, :verbose, '-v', '--verbose', 'Log Debug lines')
40
+ bool_opt(options, opts, :quiet, '-q', '--quiet', "Don't log to stdout in master process")
30
41
 
31
42
  opts.on_tail('--version', 'Show version number') do
32
43
  puts Entangler::VERSION
@@ -40,7 +51,7 @@ Usage:
40
51
  end.parse!
41
52
 
42
53
  mode = ARGV.shift
43
- unless mode && %w(master slave).include?(mode)
54
+ unless mode && %w[master slave].include?(mode)
44
55
  puts "Mode unknown, please read help:\nentangler -h"
45
56
  exit 1
46
57
  end
@@ -90,9 +101,7 @@ end
90
101
 
91
102
  if options[:ignore]
92
103
  opts[:ignore] = options[:ignore].map do |opt|
93
- if opt.start_with?('"') && opt.end_with?('"') || opt.start_with?("'") && opt.end_with?("'")
94
- opt = opt[1..-2]
95
- end
104
+ opt = opt[1..-2] if opt.start_with?('"') && opt.end_with?('"') || opt.start_with?("'") && opt.end_with?("'")
96
105
 
97
106
  if ToRegexp::String.literal? opt
98
107
  source, *rest = opt.as_regexp(detect: true)
@@ -103,6 +112,12 @@ if options[:ignore]
103
112
  end
104
113
  end
105
114
 
115
+ opts[:quiet] = options[:quiet]
106
116
  opts[:verbose] = options[:verbose]
107
117
 
108
- Entangler.run(base_dir, opts)
118
+ begin
119
+ Entangler.run(base_dir, opts)
120
+ rescue Entangler::EntanglerError => e
121
+ puts e.message
122
+ exit 1
123
+ end
@@ -1,5 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'entangler/version'
2
4
  require_relative 'entangler/errors'
5
+ require_relative 'entangler/logger'
3
6
  require_relative 'entangler/entangled_file'
4
7
 
5
8
  module Entangler
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'fileutils'
2
4
 
3
5
  module Entangler
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Entangler
2
4
  class EntanglerError < StandardError; end
3
5
  class ValidationError < EntanglerError; end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'listen'
2
4
  require 'entangler/entangled_file'
3
5
  require 'benchmark'
@@ -56,6 +58,7 @@ module Entangler
56
58
  def remove_recently_changed_files(entangled_files)
57
59
  @recently_received_paths.select! { |_, time| Time.now.to_f < time + 0.5 }
58
60
  paths = @recently_received_paths.map(&:first)
61
+ logger.debug("Skipping paths #{paths.join(', ')} as they have changed recently") if paths.any?
59
62
  entangled_files.reject { |ef| paths.include?(ef.path) }
60
63
  end
61
64
 
@@ -75,6 +78,7 @@ module Entangler
75
78
  def process_remote_changes(changes)
76
79
  with_listener_pause(1) do
77
80
  return if changes.nil?
81
+
78
82
  logger.info("Processing - #{changes.length} remote changes")
79
83
  logger.debug("File List:\n#{changes.map(&:path).join("\n")}")
80
84
  with_log_time("Completed - #{changes.length} remote changes") do
@@ -97,9 +101,9 @@ module Entangler
97
101
 
98
102
  def with_kill_threads_rescue
99
103
  yield
100
- rescue => e
101
- $stderr.puts e.message
102
- $stderr.puts e.backtrace.join("\n")
104
+ rescue StandardError => e
105
+ warn e.message
106
+ warn e.backtrace.join("\n")
103
107
  kill_off_threads
104
108
  end
105
109
 
@@ -107,6 +111,7 @@ module Entangler
107
111
  @listener_pauses[idx] = true
108
112
  listener.pause
109
113
  yield
114
+ ensure
110
115
  @listener_pauses[idx] = false
111
116
  listener.start if @listener_pauses.none?
112
117
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'open3'
2
4
 
3
5
  module Entangler
@@ -21,7 +23,7 @@ module Entangler
21
23
  super
22
24
  begin
23
25
  Process.wait @remote_thread[:pid]
24
- rescue
26
+ rescue StandardError
25
27
  nil
26
28
  end
27
29
  end
@@ -1,12 +1,15 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'logger'
2
4
  require 'fileutils'
3
- require 'thread'
4
5
  require_relative 'background/base'
6
+ require_relative 'validation/base'
5
7
 
6
8
  module Entangler
7
9
  module Executor
8
10
  class Base
9
11
  include Entangler::Executor::Background::Base
12
+ include Entangler::Executor::Validation::Base
10
13
 
11
14
  attr_reader :base_dir
12
15
 
@@ -20,6 +23,7 @@ module Entangler
20
23
  @opts[:ignore] << /^\.entangler.*/
21
24
 
22
25
  validate_opts
26
+ Entangler::Logger.create_log_dir(base_dir)
23
27
  end
24
28
 
25
29
  def generate_abs_path(rel_path)
@@ -44,36 +48,16 @@ module Entangler
44
48
 
45
49
  protected
46
50
 
47
- def validate_opts; end
48
-
49
51
  def send_to_remote(msg = {})
50
52
  Marshal.dump(msg, @remote_writer)
51
53
  end
52
54
 
53
55
  def logger
54
- FileUtils.mkdir_p log_dir
55
- @logger ||= begin
56
- l = Logger.new(File.join(log_dir, 'entangler.log'))
57
- l.level = @opts[:verbose] ? Logger::DEBUG : Logger::INFO
58
- l.formatter = logger_formatter
59
- l
60
- end
61
- end
62
-
63
- def logger_formatter
64
- proc do |severity, datetime, _, msg|
65
- date_format = datetime.strftime('%Y-%m-%d %H:%M:%S')
66
- "[#{date_format}] #{severity.rjust(5)}: #{msg}\n"
67
- end
68
- end
69
-
70
- def log_dir
71
- File.join(base_dir, '.entangler', 'log')
56
+ @logger ||= Entangler::Logger.new(log_outputs, @opts[:verbose])
72
57
  end
73
58
 
74
- def validate_base_dir(base_dir)
75
- raise Entangler::ValidationError, "Base directory doesn't exist" unless File.exist?(base_dir)
76
- raise Entangler::ValidationError, 'Base directory is a file' unless File.directory?(base_dir)
59
+ def log_outputs
60
+ [Entangler::Logger.log_file_path(base_dir)]
77
61
  end
78
62
  end
79
63
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Entangler
4
+ module Helper
5
+ def self.with_temp_file(name: 'tmp_file', contents: nil)
6
+ require 'tempfile'
7
+
8
+ t = Tempfile.new(name)
9
+ t.puts(contents) unless contents.nil?
10
+ t.close
11
+ yield t
12
+ t.unlink
13
+ end
14
+ end
15
+ end
@@ -1,9 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'helpers'
1
4
  require_relative 'background/master'
5
+ require_relative 'validation/master'
2
6
 
3
7
  module Entangler
4
8
  module Executor
5
9
  class Master < Base
6
10
  include Entangler::Executor::Background::Master
11
+ include Entangler::Executor::Validation::Master
7
12
 
8
13
  def run
9
14
  perform_initial_rsync
@@ -16,64 +21,17 @@ module Entangler
16
21
 
17
22
  private
18
23
 
19
- def validate_opts
20
- super
21
- if @opts[:remote_mode]
22
- @opts[:remote_port] ||= '22'
23
- validate_remote_opts
24
- else
25
- validate_local_opts
26
- end
27
- end
28
-
29
- def validate_local_opts
30
- unless File.exist?(@opts[:remote_base_dir])
31
- raise Entangler::ValidationError, "Destination directory doesn't exist"
32
- end
33
- unless File.directory?(@opts[:remote_base_dir])
34
- raise Entangler::ValidationError, 'Destination directory is a file'
35
- end
36
- @opts[:remote_base_dir] = File.realpath(File.expand_path(@opts[:remote_base_dir]))
37
- return unless @opts[:remote_base_dir] == base_dir
38
- raise Entangler::ValidationError, "Destination directory can't be the same as the base directory"
39
- end
40
-
41
- def validate_remote_opts
42
- keys = @opts.keys
43
- raise Entangler::ValidationError, 'Missing remote base dir' unless keys.include?(:remote_base_dir)
44
- raise Entangler::ValidationError, 'Missing remote user' unless keys.include?(:remote_user)
45
- raise Entangler::ValidationError, 'Missing remote host' unless keys.include?(:remote_host)
46
- validate_remote_base_dir
47
- validate_remote_entangler_version
48
- end
49
-
50
- def validate_remote_base_dir
51
- res = `#{generate_ssh_command("[[ -d '#{@opts[:remote_base_dir]}' ]] && echo 'ok' || echo 'missing'")}`
52
- raise Entangler::ValidationError, 'Cannot connect to remote' if res.empty?
53
- raise Entangler::ValidationError, 'Remote base dir invalid' unless res.strip == 'ok'
54
- end
55
-
56
- def validate_remote_entangler_version
57
- return unless @opts[:remote_mode]
58
- res = `#{generate_ssh_command('source ~/.rvm/environments/default && entangler --version')}`
59
- remote_version = Gem::Version.new(res.strip)
60
- local_version = Gem::Version.new(Entangler::VERSION)
61
- return unless major_version_mismatch?(local_version, remote_version)
62
- msg = 'Entangler version too far apart, please update either local or remote Entangler.' \
63
- " Local version is #{local_version} and remote version is #{remote_version}."
64
- raise Entangler::VersionMismatchError, msg
65
- end
66
-
67
- def major_version_mismatch?(version1, version2)
68
- version1.segments[0] != version2.segments[0] ||
69
- (version1.segments[0].zero? && version1 != version2) ||
70
- ((version1.prerelease? || version2.prerelease?) && version1 != version2)
24
+ def log_outputs
25
+ outs = [Entangler::Logger.log_file_path(base_dir)]
26
+ outs << $stdout unless @opts[:quiet]
71
27
  end
72
28
 
73
29
  def perform_initial_rsync
74
30
  logger.info 'Running initial sync'
75
- IO.popen(rsync_cmd_string).each do |line|
76
- logger.debug line.chomp
31
+ with_temp_rsync_ignores do |file_path|
32
+ IO.popen(rsync_cmd_string(file_path)).each do |line|
33
+ logger.debug line.chomp
34
+ end
77
35
  end
78
36
  logger.debug 'Initial sync complete'
79
37
  end
@@ -107,12 +65,17 @@ module Entangler
107
65
  "#{@opts[:remote_user]}@#{@opts[:remote_host]}"
108
66
  end
109
67
 
110
- def rsync_cmd_string
111
- exclude_args = find_rsync_ignore_folders.map { |path| "--exclude #{path}" }.join(' ')
68
+ def with_temp_rsync_ignores
69
+ Entangler::Helper.with_temp_file(name: 'rsync_ignores', contents: find_rsync_ignore_folders.join("\n")) do |f|
70
+ yield f.path
71
+ end
72
+ end
73
+
74
+ def rsync_cmd_string(rsync_ignores_file_path)
112
75
  remote_path = @opts[:remote_mode] ? "#{@opts[:remote_user]}@#{@opts[:remote_host]}:" : ''
113
76
  remote_path += "#{@opts[:remote_base_dir]}/"
114
77
 
115
- cmd = "rsync -azv #{exclude_args}"
78
+ cmd = "rsync -azv --exclude-from #{rsync_ignores_file_path}"
116
79
  cmd += " -e \"ssh -p #{@opts[:remote_port]}\"" if @opts[:remote_mode]
117
80
  cmd + " --delete #{base_dir}/ #{remote_path}"
118
81
  end
@@ -1,16 +1,18 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Entangler
2
4
  module Executor
3
5
  class Slave < Base
4
6
  def initialize(base_dir, opts = {})
5
7
  super(base_dir, opts)
6
- STDIN.binmode
7
- STDOUT.binmode
8
- STDIN.sync = true
9
- STDOUT.sync = true
8
+ $stdin.binmode
9
+ $stdout.binmode
10
+ $stdin.sync = true
11
+ $stdout.sync = true
10
12
 
11
- @remote_reader = STDIN
12
- @remote_writer = STDOUT
13
- $stderr.reopen(File.join(log_dir, 'entangler.err'), 'w')
13
+ @remote_reader = $stdin
14
+ @remote_writer = $stdout
15
+ $stderr.reopen(File.join(Entangler::Logger.log_file_path(base_dir, 'entangler.err')), 'w')
14
16
  end
15
17
  end
16
18
  end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Entangler
4
+ module Executor
5
+ module Validation
6
+ module Base
7
+ protected
8
+
9
+ def validate_opts; end
10
+
11
+ def validate_base_dir(base_dir)
12
+ raise Entangler::ValidationError, "Base directory doesn't exist" unless File.exist?(base_dir)
13
+ raise Entangler::ValidationError, 'Base directory is a file' unless File.directory?(base_dir)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Entangler
4
+ module Executor
5
+ module Validation
6
+ module Master
7
+ private
8
+
9
+ def validate_opts
10
+ super
11
+ if @opts[:remote_mode]
12
+ @opts[:remote_port] ||= '22'
13
+ validate_remote_opts
14
+ else
15
+ validate_local_opts
16
+ end
17
+ end
18
+
19
+ def validate_local_opts
20
+ unless File.exist?(@opts[:remote_base_dir])
21
+ raise Entangler::ValidationError, "Destination directory doesn't exist"
22
+ end
23
+ unless File.directory?(@opts[:remote_base_dir])
24
+ raise Entangler::ValidationError, 'Destination directory is a file'
25
+ end
26
+
27
+ @opts[:remote_base_dir] = File.realpath(File.expand_path(@opts[:remote_base_dir]))
28
+ return unless @opts[:remote_base_dir] == base_dir
29
+
30
+ raise Entangler::ValidationError, "Destination directory can't be the same as the base directory"
31
+ end
32
+
33
+ def validate_remote_opts
34
+ keys = @opts.keys
35
+ raise Entangler::ValidationError, 'Missing remote base dir' unless keys.include?(:remote_base_dir)
36
+ raise Entangler::ValidationError, 'Missing remote user' unless keys.include?(:remote_user)
37
+ raise Entangler::ValidationError, 'Missing remote host' unless keys.include?(:remote_host)
38
+
39
+ validate_remote_base_dir
40
+ validate_remote_entangler_version
41
+ end
42
+
43
+ def validate_remote_base_dir
44
+ res = `#{generate_ssh_command("[[ -d '#{@opts[:remote_base_dir]}' ]] && echo 'ok' || echo 'missing'")}`
45
+ raise Entangler::ValidationError, 'Cannot connect to remote' if res.empty?
46
+ raise Entangler::ValidationError, 'Remote base dir invalid' unless res.strip == 'ok'
47
+ end
48
+
49
+ def validate_remote_entangler_version
50
+ return unless @opts[:remote_mode]
51
+
52
+ res = `#{generate_ssh_command('source ~/.rvm/environments/default && entangler --version')}`
53
+ remote_version = Gem::Version.new(res.strip)
54
+ local_version = Gem::Version.new(Entangler::VERSION)
55
+ return unless major_version_mismatch?(local_version, remote_version)
56
+
57
+ msg = 'Entangler version too far apart, please update either local or remote Entangler.' \
58
+ " Local version is #{local_version} and remote version is #{remote_version}."
59
+ raise Entangler::VersionMismatchError, msg
60
+ end
61
+
62
+ def major_version_mismatch?(version1, version2)
63
+ version1.segments[0] != version2.segments[0] ||
64
+ (version1.segments[0].zero? && version1 != version2) ||
65
+ ((version1.prerelease? || version2.prerelease?) && version1 != version2)
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fileutils'
4
+ require 'logger'
5
+
6
+ module Entangler
7
+ class Logger
8
+ def self.create_log_dir(base_dir)
9
+ FileUtils.mkdir_p(File.dirname(log_file_path(base_dir)))
10
+ end
11
+
12
+ def self.log_file_path(base_dir, log_file_name = 'entangler.log')
13
+ File.join(base_dir, '.entangler', 'log', log_file_name)
14
+ end
15
+
16
+ def initialize(outputs, verbose: false)
17
+ @loggers = Array(outputs).map do |output|
18
+ logger = ::Logger.new(output)
19
+
20
+ logger.level = verbose ? ::Logger::DEBUG : ::Logger::INFO
21
+ logger.formatter = proc do |severity, datetime, _, msg|
22
+ date_format = datetime.strftime('%Y-%m-%d %H:%M:%S')
23
+ "[#{date_format}] #{severity.rjust(5)}: #{msg}\n"
24
+ end
25
+
26
+ logger
27
+ end
28
+ end
29
+
30
+ def level=(level)
31
+ @loggers.each { |logger| logger.level = level }
32
+ end
33
+
34
+ ::Logger::Severity.constants.each do |level|
35
+ define_method(level.downcase) do |*args|
36
+ @loggers.each { |logger| logger.send(level.downcase, *args) }
37
+ end
38
+ end
39
+ end
40
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Entangler
2
- VERSION = '1.0.1'.freeze
4
+ VERSION = '1.2.0'
3
5
  end
metadata CHANGED
@@ -1,99 +1,127 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: entangler
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dave Allie
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-12-21 00:00:00.000000000 Z
11
+ date: 2020-12-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '1.12'
19
+ version: '2.1'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '1.12'
26
+ version: '2.1'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 13.0.1
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 13.0.1
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '3.9'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '3.9'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubocop
29
57
  requirement: !ruby/object:Gem::Requirement
30
58
  requirements:
31
59
  - - "~>"
32
60
  - !ruby/object:Gem::Version
33
- version: '10.0'
61
+ version: '1.6'
34
62
  type: :development
35
63
  prerelease: false
36
64
  version_requirements: !ruby/object:Gem::Requirement
37
65
  requirements:
38
66
  - - "~>"
39
67
  - !ruby/object:Gem::Version
40
- version: '10.0'
68
+ version: '1.6'
41
69
  - !ruby/object:Gem::Dependency
42
- name: rspec
70
+ name: rubocop-rake
43
71
  requirement: !ruby/object:Gem::Requirement
44
72
  requirements:
45
73
  - - "~>"
46
74
  - !ruby/object:Gem::Version
47
- version: '3.0'
75
+ version: 0.5.1
48
76
  type: :development
49
77
  prerelease: false
50
78
  version_requirements: !ruby/object:Gem::Requirement
51
79
  requirements:
52
80
  - - "~>"
53
81
  - !ruby/object:Gem::Version
54
- version: '3.0'
82
+ version: 0.5.1
55
83
  - !ruby/object:Gem::Dependency
56
- name: rubocop
84
+ name: rubocop-rspec
57
85
  requirement: !ruby/object:Gem::Requirement
58
86
  requirements:
59
87
  - - "~>"
60
88
  - !ruby/object:Gem::Version
61
- version: '0.46'
89
+ version: '2.0'
62
90
  type: :development
63
91
  prerelease: false
64
92
  version_requirements: !ruby/object:Gem::Requirement
65
93
  requirements:
66
94
  - - "~>"
67
95
  - !ruby/object:Gem::Version
68
- version: '0.46'
96
+ version: '2.0'
69
97
  - !ruby/object:Gem::Dependency
70
98
  name: listen
71
99
  requirement: !ruby/object:Gem::Requirement
72
100
  requirements:
73
101
  - - "~>"
74
102
  - !ruby/object:Gem::Version
75
- version: '3.1'
103
+ version: '3.3'
76
104
  type: :runtime
77
105
  prerelease: false
78
106
  version_requirements: !ruby/object:Gem::Requirement
79
107
  requirements:
80
108
  - - "~>"
81
109
  - !ruby/object:Gem::Version
82
- version: '3.1'
110
+ version: '3.3'
83
111
  - !ruby/object:Gem::Dependency
84
112
  name: to_regexp
85
113
  requirement: !ruby/object:Gem::Requirement
86
114
  requirements:
87
115
  - - "~>"
88
116
  - !ruby/object:Gem::Version
89
- version: '0.2'
117
+ version: 0.2.1
90
118
  type: :runtime
91
119
  prerelease: false
92
120
  version_requirements: !ruby/object:Gem::Requirement
93
121
  requirements:
94
122
  - - "~>"
95
123
  - !ruby/object:Gem::Version
96
- version: '0.2'
124
+ version: 0.2.1
97
125
  description: Two way file syncer using platform native notify.
98
126
  email:
99
127
  - dave@daveallie.com
@@ -102,17 +130,10 @@ executables:
102
130
  extensions: []
103
131
  extra_rdoc_files: []
104
132
  files:
105
- - ".gitignore"
106
- - ".rspec"
107
- - ".rubocop.yml"
108
- - ".travis.yml"
109
133
  - CODE_OF_CONDUCT.md
110
134
  - Gemfile
111
135
  - LICENSE.txt
112
136
  - README.md
113
- - Rakefile
114
- - bin/console
115
- - bin/setup
116
137
  - entangler.gemspec
117
138
  - exe/entangler
118
139
  - lib/entangler.rb
@@ -121,8 +142,12 @@ files:
121
142
  - lib/entangler/executor/background/base.rb
122
143
  - lib/entangler/executor/background/master.rb
123
144
  - lib/entangler/executor/base.rb
145
+ - lib/entangler/executor/helpers.rb
124
146
  - lib/entangler/executor/master.rb
125
147
  - lib/entangler/executor/slave.rb
148
+ - lib/entangler/executor/validation/base.rb
149
+ - lib/entangler/executor/validation/master.rb
150
+ - lib/entangler/logger.rb
126
151
  - lib/entangler/version.rb
127
152
  homepage: https://github.com/daveallie/entangler
128
153
  licenses:
@@ -136,15 +161,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
136
161
  requirements:
137
162
  - - ">="
138
163
  - !ruby/object:Gem::Version
139
- version: '0'
164
+ version: '2.5'
140
165
  required_rubygems_version: !ruby/object:Gem::Requirement
141
166
  requirements:
142
167
  - - ">="
143
168
  - !ruby/object:Gem::Version
144
169
  version: '0'
145
170
  requirements: []
146
- rubyforge_project:
147
- rubygems_version: 2.4.8
171
+ rubygems_version: 3.1.2
148
172
  signing_key:
149
173
  specification_version: 4
150
174
  summary: Two way file syncer using platform native notify.
data/.gitignore DELETED
@@ -1,11 +0,0 @@
1
- /.bundle/
2
- /.yardoc
3
- /Gemfile.lock
4
- /_yardoc/
5
- /coverage/
6
- /doc/
7
- /pkg/
8
- /spec/reports/
9
- /tmp/
10
- /log/
11
- *.gem
data/.rspec DELETED
@@ -1,2 +0,0 @@
1
- --format documentation
2
- --color
@@ -1,9 +0,0 @@
1
- AllCops:
2
- DisplayCopNames: true
3
- ExtraDetails: true
4
-
5
- Metrics/LineLength:
6
- Max: 120
7
-
8
- Style/Documentation:
9
- Enabled: false
@@ -1,20 +0,0 @@
1
- sudo: false
2
- language: ruby
3
- os:
4
- - linux
5
- - osx
6
- rvm:
7
- - 2.3.3
8
- - ruby-head
9
- matrix:
10
- include:
11
- - os: osx
12
- rvm: 2.2.5
13
- - os: linux
14
- rvm: 2.2.6
15
- allow_failures:
16
- - rvm: ruby-head
17
- before_install:
18
- - gem install bundler -v 1.13.6
19
- install:
20
- - bundle install --jobs=3 --retry=3
data/Rakefile DELETED
@@ -1,8 +0,0 @@
1
- require 'bundler/gem_tasks'
2
- require 'rspec/core/rake_task'
3
- require 'rubocop/rake_task'
4
-
5
- RuboCop::RakeTask.new(:rubocop)
6
- RSpec::Core::RakeTask.new(:spec)
7
-
8
- task default: [:rubocop, :spec]
@@ -1,14 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'bundler/setup'
4
- require 'entangler'
5
-
6
- # You can add fixtures and/or initialization code here to make experimenting
7
- # with your gem easier. You can also use a different console, if you like.
8
-
9
- # (If you use this, don't forget to add pry to your Gemfile!)
10
- # require "pry"
11
- # Pry.start
12
-
13
- require 'irb'
14
- IRB.start
data/bin/setup DELETED
@@ -1,8 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
- IFS=$'\n\t'
4
- set -vx
5
-
6
- bundle install
7
-
8
- # Do any other automated setup that you need to do here