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 +4 -4
- data/.standard.yml +3 -0
- data/CHANGELOG.md +59 -49
- data/LICENSE.txt +1 -1
- data/README.md +14 -11
- data/Rakefile +3 -1
- data/exe/multisync +2 -2
- data/lib/multisync/catalog.rb +10 -13
- data/lib/multisync/cli.rb +60 -88
- data/lib/multisync/colors.rb +23 -0
- data/lib/multisync/definition/dsl.rb +19 -21
- data/lib/multisync/definition/entity.rb +34 -47
- data/lib/multisync/definition/null.rb +11 -13
- data/lib/multisync/definition/template.rb +8 -9
- data/lib/multisync/definition.rb +5 -6
- data/lib/multisync/list.rb +29 -26
- data/lib/multisync/rsync_stat.rb +12 -13
- data/lib/multisync/runtime.rb +43 -48
- data/lib/multisync/selector.rb +44 -22
- data/lib/multisync/summary.rb +55 -18
- data/lib/multisync/version.rb +3 -1
- data/lib/multisync.rb +14 -9
- data/sample/multisync.rb +10 -18
- metadata +22 -14
- data/.gitignore +0 -13
- data/Gemfile +0 -10
- data/bin/console +0 -14
- data/bin/setup +0 -8
- data/multisync.gemspec +0 -41
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e799810bb5e357087f31733c9b885581a349832f6806a94e726d581c49e044b6
|
|
4
|
+
data.tar.gz: b2682c3578aa9381ee3e3b0b36fc6d4566462cea8c1c10a5458ae6951f959c87
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f9fbf97fda456b7d7f29f5822321960e1eab877d609c6456905039b05d8908010faae42967d1cd2e2644b1196611fcea0cabf5198247372d439aeece761bc827
|
|
7
|
+
data.tar.gz: 457c9cbf9c5c4a8ed1c06574594dc348e2d1fdf2febf75372ba96adbf31c76bb3734a87165cc30ca3a1825f8ab8c159691bef641a242686f5cb5a7dbc5d98089
|
data/.standard.yml
ADDED
data/CHANGELOG.md
CHANGED
|
@@ -1,101 +1,111 @@
|
|
|
1
|
-
##
|
|
1
|
+
## [0.4.0] - 2025-11-02
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
##
|
|
11
|
+
## [0.3.7] - 2021-10-28
|
|
7
12
|
|
|
8
|
-
|
|
13
|
+
- Add grand total to summary
|
|
9
14
|
|
|
10
15
|
|
|
11
|
-
##
|
|
16
|
+
## [0.3.6] - 2019-08-20
|
|
12
17
|
|
|
13
|
-
|
|
14
|
-
* Catch SIGINT and print a summary after an interrupt
|
|
18
|
+
- Tweak output when specifing --print and/or --quiet
|
|
15
19
|
|
|
16
20
|
|
|
17
|
-
##
|
|
21
|
+
## [0.3.5] - 2019-08-13
|
|
18
22
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
* Update sample file
|
|
23
|
+
- Fix option quiet
|
|
24
|
+
- Catch SIGINT and print a summary after an interrupt
|
|
22
25
|
|
|
23
26
|
|
|
24
|
-
##
|
|
27
|
+
## [0.3.4] - 2019-07-23
|
|
25
28
|
|
|
26
|
-
|
|
29
|
+
- Update help
|
|
30
|
+
- Update readme
|
|
31
|
+
- Update sample file
|
|
27
32
|
|
|
28
33
|
|
|
29
|
-
##
|
|
34
|
+
## [0.3.3] - 2019-07-23
|
|
30
35
|
|
|
31
|
-
|
|
36
|
+
- Update gem description
|
|
32
37
|
|
|
33
38
|
|
|
34
|
-
##
|
|
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
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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
|
-
|
|
44
|
-
|
|
45
|
-
|
|
53
|
+
- New: timeout option
|
|
54
|
+
- New: quiet option
|
|
55
|
+
- polished output
|
|
46
56
|
|
|
47
57
|
|
|
48
|
-
##
|
|
58
|
+
## [0.2.4] - 2017-09-23
|
|
49
59
|
|
|
50
|
-
|
|
60
|
+
- Fix: check command
|
|
51
61
|
|
|
52
62
|
|
|
53
|
-
##
|
|
63
|
+
## [0.2.3] - 2017-09-23
|
|
54
64
|
|
|
55
|
-
|
|
65
|
+
- Fix: check remote path
|
|
56
66
|
|
|
57
67
|
|
|
58
|
-
##
|
|
68
|
+
## [0.2.2] - 2017-09-23
|
|
59
69
|
|
|
60
|
-
|
|
61
|
-
|
|
70
|
+
- replaced shell_cmd gem with mixlib-shellout
|
|
71
|
+
- Fix: check path for paths containing spaces
|
|
62
72
|
|
|
63
73
|
|
|
64
|
-
##
|
|
74
|
+
## [0.2.1] - 2017-09-22
|
|
65
75
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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
|
-
##
|
|
83
|
+
## [0.2.0] - 2016-03-22
|
|
74
84
|
|
|
75
|
-
|
|
76
|
-
|
|
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
|
-
##
|
|
89
|
+
## [0.1.2] - 2014-08-29
|
|
80
90
|
|
|
81
|
-
|
|
91
|
+
- Mark default sets with an * when listing
|
|
82
92
|
|
|
83
93
|
|
|
84
|
-
##
|
|
94
|
+
## [0.1.1] - 2014-08-28
|
|
85
95
|
|
|
86
|
-
|
|
96
|
+
- Add gem dependecy 'text-highlight'
|
|
87
97
|
|
|
88
98
|
|
|
89
|
-
##
|
|
99
|
+
## [0.1.0] - 2014-07-18
|
|
90
100
|
|
|
91
|
-
|
|
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
|
-
##
|
|
104
|
+
## [0.0.2] - 2014-07-17
|
|
95
105
|
|
|
96
|
-
|
|
106
|
+
- Fix: do no escape option strings
|
|
97
107
|
|
|
98
108
|
|
|
99
|
-
##
|
|
109
|
+
## [0.0.1] - 2014-07-11
|
|
100
110
|
|
|
101
|
-
|
|
111
|
+
- First release
|
data/LICENSE.txt
CHANGED
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
|
|
10
|
+
Install the gem and add to the application's Gemfile by executing:
|
|
11
11
|
|
|
12
|
-
|
|
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
|
|
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
|
|
32
|
+
Run the tasks defined in your catalog file:
|
|
30
33
|
|
|
31
|
-
$ multisync
|
|
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
|
|
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
data/exe/multisync
CHANGED
data/lib/multisync/catalog.rb
CHANGED
|
@@ -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
|
-
@
|
|
12
|
-
|
|
13
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
+
class Multisync::Cli < Thor
|
|
6
|
+
include Thor::Actions
|
|
7
|
+
include Multisync::Colors
|
|
5
8
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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
|
-
|
|
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
|
-
|
|
78
|
-
|
|
79
|
-
|
|
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
|
-
@
|
|
66
|
+
@catalog ||= Multisync::Catalog.new options[:catalog]
|
|
84
67
|
end
|
|
85
|
-
|
|
68
|
+
|
|
86
69
|
def runtime
|
|
87
|
-
@
|
|
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
|
|
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
|
|
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 = {
|
|
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
|