multisync 0.3.7 → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0f5ccf30a0608eca5f17002de411dc941cb90d192c5343863a8b7898d2ab3270
4
- data.tar.gz: 94d44b2c52223526c379112fa756249ebc0da3b1a61f77413c70229b95fe4525
3
+ metadata.gz: e799810bb5e357087f31733c9b885581a349832f6806a94e726d581c49e044b6
4
+ data.tar.gz: b2682c3578aa9381ee3e3b0b36fc6d4566462cea8c1c10a5458ae6951f959c87
5
5
  SHA512:
6
- metadata.gz: 841ef74fc08150c9c639551a6b7fe84a2f1c941f77cea8cb10dfe56d0447709f8fc5a992afe7b4d217e76d9ab78248ac81f5859b323b1de0c8d25b26cb6c43de
7
- data.tar.gz: e77a0e739af5df1530487d035c51ad6c8cc853e6d783a17207d63fae20e2253fe6098b54f5f5cf77c025f8fb48868a337d05c5417f3352176367ac90d9ec6e9f
6
+ metadata.gz: f9fbf97fda456b7d7f29f5822321960e1eab877d609c6456905039b05d8908010faae42967d1cd2e2644b1196611fcea0cabf5198247372d439aeece761bc827
7
+ data.tar.gz: 457c9cbf9c5c4a8ed1c06574594dc348e2d1fdf2febf75372ba96adbf31c76bb3734a87165cc30ca3a1825f8ab8c159691bef641a242686f5cb5a7dbc5d98089
data/.standard.yml ADDED
@@ -0,0 +1,3 @@
1
+ # For available configuration options, see:
2
+ # https://github.com/standardrb/standard
3
+ ruby_version: 3.1
data/CHANGELOG.md CHANGED
@@ -1,101 +1,111 @@
1
- ## Release v0.3.7 (2021-10-28)
1
+ ## [0.4.0] - 2025-11-02
2
2
 
3
- * Add grand total to summary
3
+ - New CLI
4
+ - List and start accept the same query argument to select the catalog tasks
5
+ - New option to omit summary
6
+ - New failure summary after task summary
7
+ - Adjustment in output colors
8
+ - Breaking change: to run tasks you must call multisync start
4
9
 
5
10
 
6
- ## Release v0.3.6 (2019-08-20)
11
+ ## [0.3.7] - 2021-10-28
7
12
 
8
- * Tweak output when specifing --print and/or --quiet
13
+ - Add grand total to summary
9
14
 
10
15
 
11
- ## Release v0.3.5 (2019-08-13)
16
+ ## [0.3.6] - 2019-08-20
12
17
 
13
- * Fix option quiet
14
- * Catch SIGINT and print a summary after an interrupt
18
+ - Tweak output when specifing --print and/or --quiet
15
19
 
16
20
 
17
- ## Release v0.3.4 (2019-07-23)
21
+ ## [0.3.5] - 2019-08-13
18
22
 
19
- * Update help
20
- * Update readme
21
- * Update sample file
23
+ - Fix option quiet
24
+ - Catch SIGINT and print a summary after an interrupt
22
25
 
23
26
 
24
- ## Release v0.3.3 (2019-07-23)
27
+ ## [0.3.4] - 2019-07-23
25
28
 
26
- * Update gem description
29
+ - Update help
30
+ - Update readme
31
+ - Update sample file
27
32
 
28
33
 
29
- ## Release v0.3.2 (2019-07-23)
34
+ ## [0.3.3] - 2019-07-23
30
35
 
31
- * First public release
36
+ - Update gem description
32
37
 
33
38
 
34
- ## Release v0.3.1 (2018-06-01)
39
+ ## [0.3.2] - 2019-07-23
40
+
41
+ - First public release
42
+
43
+
44
+ ## [0.3.1] - 2018-06-01
35
45
 
36
46
  Changes in DSL
37
- * removed "desc"
38
- * "from" accepts a description option
39
- * "to"" accepts a description option
40
- * New: "template" and "include"
47
+ - removed "desc"
48
+ - "from" accepts a description option
49
+ - "to"" accepts a description option
50
+ - New: "template" and "include"
41
51
 
42
52
  Changes in CLI
43
- * New: timeout option
44
- * New: quiet option
45
- * polished output
53
+ - New: timeout option
54
+ - New: quiet option
55
+ - polished output
46
56
 
47
57
 
48
- ## Release v0.2.4 (2017-09-23)
58
+ ## [0.2.4] - 2017-09-23
49
59
 
50
- * Fix: check command
60
+ - Fix: check command
51
61
 
52
62
 
53
- ## Release v0.2.3 (2017-09-23)
63
+ ## [0.2.3] - 2017-09-23
54
64
 
55
- * Fix: check remote path
65
+ - Fix: check remote path
56
66
 
57
67
 
58
- ## Release v0.2.2 (2017-09-23)
68
+ ## [0.2.2] - 2017-09-23
59
69
 
60
- * replaced shell_cmd gem with mixlib-shellout
61
- * Fix: check path for paths containing spaces
70
+ - replaced shell_cmd gem with mixlib-shellout
71
+ - Fix: check path for paths containing spaces
62
72
 
63
73
 
64
- ## Release v0.2.1 (2017-09-22)
74
+ ## [0.2.1] - 2017-09-22
65
75
 
66
- * New: option "check_from" and "check_to" to let check host or path before sync
67
- * New: "from" and "to" accept an optional check: true|false parameter
68
- * Change summery output to a more compact tabular form
69
- * Use rainbow for colorization
70
- * Move "only_if" checks to runtime
76
+ - New: option "check_from" and "check_to" to let check host or path before sync
77
+ - New: "from" and "to" accept an optional check: true|false parameter
78
+ - Change summery output to a more compact tabular form
79
+ - Use rainbow for colorization
80
+ - Move "only_if" checks to runtime
71
81
 
72
82
 
73
- ## Release v0.2.0 (2016-03-22)
83
+ ## [0.2.0] - 2016-03-22
74
84
 
75
- * New: option only_if for preflight checks, prior to sync
76
- * Command line option -p/--print changed to --show
85
+ - New: option only_if for preflight checks, prior to sync
86
+ - Command line option -p/--print changed to --show
77
87
 
78
88
 
79
- ## Release v0.1.2 (2014-08-29)
89
+ ## [0.1.2] - 2014-08-29
80
90
 
81
- * Mark default sets with an * when listing
91
+ - Mark default sets with an * when listing
82
92
 
83
93
 
84
- ## Release v0.1.1 (2014-08-28)
94
+ ## [0.1.1] - 2014-08-28
85
95
 
86
- * Add gem dependecy 'text-highlight'
96
+ - Add gem dependecy 'text-highlight'
87
97
 
88
98
 
89
- ## Release v0.1.0 (2014-07-18)
99
+ ## [0.1.0] - 2014-07-18
90
100
 
91
- * New: define one or more groups/syncs as default, to run when no sets have been given as args
101
+ - New: define one or more groups/syncs as default, to run when no sets have been given as args
92
102
 
93
103
 
94
- ## Release v0.0.2 (2014-07-17)
104
+ ## [0.0.2] - 2014-07-17
95
105
 
96
- * Fix: do no escape option strings
106
+ - Fix: do no escape option strings
97
107
 
98
108
 
99
- ## Release v0.0.1 (2014-07-11)
109
+ ## [0.0.1] - 2014-07-11
100
110
 
101
- * First release
111
+ - First release
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2021 Patrick Marchi
3
+ Copyright (c) 2025 Patrick Marchi
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -7,9 +7,17 @@ Multisync offers a DSL to organize sets of rsync tasks. It takes advantage of te
7
7
 
8
8
  ## Installation
9
9
 
10
- Install multisync with:
10
+ Install the gem and add to the application's Gemfile by executing:
11
11
 
12
- $ gem install multisync
12
+ ```bash
13
+ bundle add multisync
14
+ ```
15
+
16
+ If bundler is not being used to manage dependencies, install the gem by executing:
17
+
18
+ ```bash
19
+ gem install multisync
20
+ ```
13
21
 
14
22
 
15
23
  ## Usage
@@ -18,24 +26,19 @@ In order to run multisync you first need a catalog file (default: `~/.multisync.
18
26
 
19
27
  List your configuration (and check your catalog file for errors):
20
28
 
21
- $ multisync -l
22
-
23
-
24
- Print out the rsync commands without executing them:
25
-
26
- $ multisync -p
29
+ $ multisync list [QUERY ...]
27
30
 
28
31
 
29
- Run a group or task defined in your catalog file:
32
+ Run the tasks defined in your catalog file:
30
33
 
31
- $ multisync nas
34
+ $ multisync start [QUERY ...]
32
35
 
33
36
 
34
37
  ## Development
35
38
 
36
39
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
37
40
 
38
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
41
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
39
42
 
40
43
 
41
44
  ## Contributing
data/Rakefile CHANGED
@@ -5,4 +5,6 @@ require "rspec/core/rake_task"
5
5
 
6
6
  RSpec::Core::RakeTask.new(:spec)
7
7
 
8
- task default: :spec
8
+ require "standard/rake"
9
+
10
+ task default: %i[spec standard]
data/exe/multisync CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'multisync'
3
+ require "multisync"
4
4
 
5
- Multisync::Cli.start
5
+ Multisync::Cli.start ARGV
@@ -1,29 +1,26 @@
1
-
2
1
  class Multisync::Catalog
3
- # top entity of definition
4
- attr_reader :definition
5
-
6
2
  def initialize path
7
3
  @path = File.expand_path(path)
8
4
  end
9
-
5
+
6
+ # top entity of definition
10
7
  def definition
11
- @_definition ||= Multisync::Definition::Entity.new(Multisync::Definition::Null.new, '__MAIN__').tap do |e|
12
- e.instance_eval File.read(path)
13
- end
8
+ @definition ||= Multisync::Definition::Entity
9
+ .new(Multisync::Definition::Null.new, "")
10
+ .tap { _1.instance_eval File.read(path) }
14
11
  end
15
-
12
+
16
13
  def traverse visitor
17
14
  definition.accept visitor
18
15
  end
19
-
16
+
20
17
  def path
21
18
  return @path if File.exist? @path
22
- sample_path = File.expand_path('../../../sample/multisync.rb', __FILE__)
19
+ sample_path = File.expand_path("../../../sample/multisync.rb", __FILE__)
23
20
  raise RuntimeError.new, "No catalog found at #{@path}. Copy sample from #{sample_path} to #{@path} and adjust to your needs."
24
21
  end
25
-
22
+
26
23
  def self.default_catalog_path
27
- '~/.multisync.rb'
24
+ "~/.multisync.rb"
28
25
  end
29
26
  end
data/lib/multisync/cli.rb CHANGED
@@ -1,100 +1,72 @@
1
+ require "thor"
2
+ require "rainbow"
3
+ require "terminal-table"
1
4
 
2
- require 'optparse'
3
- require 'rainbow/ext/string'
4
- require 'terminal-table'
5
+ class Multisync::Cli < Thor
6
+ include Thor::Actions
7
+ include Multisync::Colors
5
8
 
6
- class Multisync::Cli
7
-
8
- def self.start
9
- new.start
10
- end
11
-
12
- # Given sets to run or empty
13
- attr_reader :sets
14
-
15
- def parser
16
- OptionParser.new do |o|
17
- o.banner = "\nRun rsync jobs defined in the catalog file '#{options[:file]}'.\n\n" +
18
- "Usage: #{File.basename $0} [options] [SET] [...]\n\n" +
19
- " SET selects a section from the catalog (see option -l)\n" +
20
- " use / as a group/task separator.\n" +
21
- " e.g. #{File.basename $0} nas/userdata"
22
- o.separator ''
23
- o.on('-l', '--list', "List the catalog") do
24
- options[:list] = true
25
- end
26
- o.on('-p', '--print', "Print the commands without executing them") do
27
- options[:print] = true
28
- end
29
- o.on('-q', '--quiet', "Show only rsync summary") do
30
- options[:quiet] = true
31
- end
32
- o.on('--catalog FILE', "Specify a catalog", "Default is #{options[:file]}") do |file|
33
- options[:file] = file
34
- end
35
- o.on('--timeout SECS', Integer, "Timeout for rsync job", "Default is #{options[:timeout]}") do |timeout|
36
- options[:timeout] = timeout
37
- end
38
- o.on('-n', '--dryrun', "Run rsync in dry-run mode") do
39
- options[:dryrun] = true
40
- end
41
- o.separator ''
42
- end
9
+ def self.exit_on_failure? = true
10
+
11
+ class_option :catalog, aliases: "-f", default: Multisync::Catalog.default_catalog_path, desc: "Specify a custom catalog file"
12
+
13
+ desc "list [QUERY ...]", "List catalog tasks"
14
+ long_desc <<~LONGDESC
15
+ List catalog tasks
16
+
17
+ QUERY selects a section from the catalog (see list)
18
+ \x05use / as a group/task separator.
19
+ \x05e.g. #{File.basename $0} nas/userdata"
20
+ LONGDESC
21
+ method_option :all, aliases: "-a", type: :boolean, desc: "List all tasks"
22
+ def list *queries
23
+ queries = ["."] if options[:all]
24
+ tasks = Multisync::Selector.new(catalog, queries).tasks(parents: true)
25
+
26
+ puts "Catalog file: #{as_main(options[:catalog])}"
27
+ puts Multisync::List.new(tasks)
43
28
  end
44
-
45
- def start
46
- parser.parse!
47
- options[:quiet] = false if options[:print]
48
-
49
- @sets = ARGV
50
29
 
51
- if options[:list]
52
- # List tasks
53
- puts "Catalog: #{options[:file].color(:cyan)}"
54
- puts
55
- puts Multisync::List.new catalog
30
+ desc "start [QUERY ...]", "Run catalog tasks"
31
+ long_desc <<~LONGDESC
32
+ Run catalog tasks
56
33
 
57
- else
58
- # Run tasks
59
- return if tasks.empty?
60
- begin
61
- tasks.each do |task|
62
- runtime.run task
63
- end
64
- rescue Interrupt => e
65
- $stderr.puts "\nAborted!".color(:red)
66
- end
67
- unless options[:print]
68
- puts
69
- puts
70
- puts Multisync::Summary.new tasks
71
- end
72
- end
34
+ QUERY selects a section from the catalog (see list)
35
+ \x05use / as a group/task separator.
36
+ \x05e.g. #{File.basename $0} nas/userdata"
37
+ LONGDESC
38
+ method_option :timeout, aliases: "-t", type: :numeric, default: 31536000, desc: "Timeout for single rsync task" # 1 year
39
+ method_option :print, aliases: "-p", type: :boolean, desc: "Print commands without executing"
40
+ method_option :quiet, aliases: "-q", type: :boolean, desc: "Run tasks quietly"
41
+ method_option :summary, type: :boolean, default: true, desc: "Show summary"
42
+ method_option :dryrun, aliases: "-n", type: :boolean, desc: "Run jobs in dry-run, don't make any changes"
43
+ def start *queries
44
+ tasks = Multisync::Selector.new(catalog, queries)
45
+ .tasks
46
+ # only leafs of the task tree can be executed
47
+ .select(&:executeable?)
73
48
 
74
- puts
49
+ # Run
50
+ tasks.each { runtime.run _1 }
51
+ rescue Interrupt
52
+ warn as_fail("\nAborted!")
53
+ ensure
54
+ # Summarize
55
+ puts Multisync::Summary.new(tasks) if options[:summary] && !options[:print]
75
56
  end
76
-
77
- def tasks
78
- @_tasks ||= Multisync::Selector.new(catalog, sets).tasks
79
- # @_tasks ||= catalog.filter sets
57
+
58
+ desc "version", "Print version information"
59
+ def version
60
+ puts "multisync v#{Multisync::VERSION}"
80
61
  end
81
-
62
+
63
+ private
64
+
82
65
  def catalog
83
- @_catalog ||= Multisync::Catalog.new options[:file]
66
+ @catalog ||= Multisync::Catalog.new options[:catalog]
84
67
  end
85
-
68
+
86
69
  def runtime
87
- @_runtime ||= Multisync::Runtime.new(options)
88
- end
89
-
90
- def options
91
- @_options ||= {
92
- list: false,
93
- print: false,
94
- dryrun: false,
95
- quiet: false,
96
- file: Multisync::Catalog.default_catalog_path,
97
- timeout: 31536000, # 1 year
98
- }
70
+ @runtime ||= Multisync::Runtime.new(options)
99
71
  end
100
- end
72
+ end
@@ -0,0 +1,23 @@
1
+ require "rainbow"
2
+
3
+ module Multisync::Colors
4
+ def as_note x
5
+ Rainbow(x).faint
6
+ end
7
+
8
+ def as_main x
9
+ Rainbow(x).color(:aqua)
10
+ end
11
+
12
+ def as_skipped x
13
+ Rainbow(x).color(:yellow)
14
+ end
15
+
16
+ def as_success x
17
+ Rainbow(x).color(:green)
18
+ end
19
+
20
+ def as_fail x
21
+ Rainbow(x).color(:red)
22
+ end
23
+ end
@@ -1,61 +1,59 @@
1
-
2
1
  module Multisync::Definition::Dsl
3
-
4
2
  # The DSL methods
5
3
  def group name, &block
6
4
  Multisync::Definition::Entity.new self, name, &block
7
5
  end
8
-
6
+
9
7
  def sync name, &block
10
8
  Multisync::Definition::Entity.new self, name, &block
11
9
  end
12
-
10
+
13
11
  def template name, &block
14
12
  Multisync::Definition::Template.new name, &block
15
13
  end
16
-
14
+
17
15
  def include name
18
16
  template = Multisync::Definition::Template.lookup name
19
- instance_eval &template.block
17
+ instance_eval(&template.block)
20
18
  end
21
-
22
- def from value, options={}
19
+
20
+ def from value, options = {}
23
21
  @from_value = value
24
22
  # Check source's host or path before sync
25
23
  @from_check = options[:check]
26
24
  @from_description = options[:description]
27
25
  end
28
-
29
- def to value, options={}
26
+
27
+ def to value, options = {}
30
28
  @to_value = value
31
29
  # Check destination's host or path before sync
32
30
  @to_check = options[:check]
33
31
  @to_description = options[:description]
34
32
  end
35
-
36
- def options rsync_options, mode=:append
33
+
34
+ def options rsync_options, mode = :append
37
35
  @rsync_options_mode = mode
38
36
  @rsync_options = Array(rsync_options)
39
37
  end
40
-
38
+
41
39
  def default
42
40
  @default = true
43
41
  end
44
-
42
+
45
43
  # Defines a check, that should pass in order to invoke the sync
46
- def only_if cmd, options={}
47
- @check = { cmd: cmd, message: options.fetch(:message, cmd) }
44
+ def only_if cmd, options = {}
45
+ @check = {cmd: cmd, message: options.fetch(:message, cmd)}
48
46
  end
49
-
47
+
50
48
  # Check source's host or path before sync
51
49
  # can also be set as option of "from"
52
- def check_from flag=true
50
+ def check_from flag = true
53
51
  @from_check = flag
54
52
  end
55
-
53
+
56
54
  # Check destination's host or path before sync
57
55
  # can also be set as option of "to"
58
- def check_to flag=true
56
+ def check_to flag = true
59
57
  @to_check = flag
60
58
  end
61
- end
59
+ end