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
data/lib/multisync/summary.rb
CHANGED
|
@@ -1,53 +1,90 @@
|
|
|
1
1
|
class Multisync::Summary
|
|
2
|
-
|
|
2
|
+
include Multisync::Colors
|
|
3
|
+
|
|
3
4
|
# All tasks to include in the summary
|
|
4
5
|
attr_reader :tasks
|
|
5
|
-
|
|
6
|
+
|
|
6
7
|
def initialize tasks
|
|
7
8
|
@tasks = tasks
|
|
8
9
|
end
|
|
9
|
-
|
|
10
|
+
|
|
10
11
|
def to_s
|
|
11
|
-
table.to_s
|
|
12
|
+
["", as_main("Summary"), table.to_s, failures].compact.join("\n")
|
|
12
13
|
end
|
|
13
|
-
|
|
14
|
+
|
|
14
15
|
def table
|
|
15
16
|
Terminal::Table.new(headings: headings, rows: data, style: table_style)
|
|
16
17
|
end
|
|
17
|
-
|
|
18
|
+
|
|
18
19
|
def headings
|
|
19
|
-
%w
|
|
20
|
+
%w[SOURCE DESTINATION FILES + - → ∑ ↑]
|
|
21
|
+
.map(&method(:as_note))
|
|
22
|
+
.zip(%i[left left right right right right right right])
|
|
23
|
+
.map { |v, a| {value: v, alignment: a} }
|
|
20
24
|
end
|
|
21
|
-
|
|
25
|
+
|
|
22
26
|
def data
|
|
23
27
|
tasks.map do |task|
|
|
24
28
|
result = task.result
|
|
25
|
-
desc = [task.source_description,
|
|
29
|
+
desc = [task.source_description, task.destination_description]
|
|
26
30
|
|
|
27
31
|
case result[:action]
|
|
28
32
|
when :run
|
|
29
|
-
if result[:status]
|
|
33
|
+
if result[:status]&.success?
|
|
30
34
|
# successfull run
|
|
31
35
|
stats = Multisync::RsyncStat.new(result[:stdout])
|
|
32
|
-
[*desc, *stats.formatted_values.map{
|
|
36
|
+
[*desc, *stats.formatted_values.map { {value: as_success(_1), alignment: :right} }]
|
|
33
37
|
else
|
|
34
38
|
# failed or interrupted run
|
|
35
|
-
[*desc,
|
|
39
|
+
[*desc, as_message(as_fail("Failed, for more information see details below"))]
|
|
40
|
+
# [*desc, as_message(as_fail(result[:stderr] || "n/a").strip)]
|
|
36
41
|
end
|
|
37
42
|
|
|
38
43
|
when :skip
|
|
39
44
|
# skiped sync
|
|
40
|
-
[*desc,
|
|
45
|
+
[*desc, as_message(as_skipped(result[:skip_message]))]
|
|
41
46
|
|
|
42
47
|
else
|
|
43
48
|
# not executed
|
|
44
|
-
[*desc,
|
|
49
|
+
[*desc, as_message(as_note("not executed"))]
|
|
45
50
|
end
|
|
46
|
-
end.push
|
|
51
|
+
end.push(
|
|
52
|
+
[
|
|
53
|
+
as_note("Total"),
|
|
54
|
+
"",
|
|
55
|
+
*Multisync::RsyncStat
|
|
56
|
+
.formatted_totals
|
|
57
|
+
.map { {value: as_note(_1), alignment: :right} }
|
|
58
|
+
]
|
|
59
|
+
)
|
|
47
60
|
end
|
|
48
|
-
|
|
49
|
-
def
|
|
50
|
-
|
|
61
|
+
|
|
62
|
+
def failures
|
|
63
|
+
tasks
|
|
64
|
+
.select { _1.result[:action] == :run && !_1.result[:status]&.success? }
|
|
65
|
+
.flat_map do |task|
|
|
66
|
+
[
|
|
67
|
+
as_fail([task.source_description, task.destination_description].join(" --> ")),
|
|
68
|
+
message_or_nil(task.result[:stdout]),
|
|
69
|
+
message_or_nil(task.result[:stderr]),
|
|
70
|
+
""
|
|
71
|
+
].compact
|
|
72
|
+
end
|
|
73
|
+
# Add title if any failures
|
|
74
|
+
.tap { _1.unshift "\n#{as_main("Failures")}" if _1.any? }
|
|
75
|
+
# Return failures as string or nil
|
|
76
|
+
.then { _1.any? ? _1.join("\n") : nil }
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def as_message message
|
|
80
|
+
{value: message, colspan: 6}
|
|
51
81
|
end
|
|
52
82
|
|
|
83
|
+
def message_or_nil message
|
|
84
|
+
(message.nil? || message.empty?) ? nil : message
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def table_style
|
|
88
|
+
{border_x: as_note("─"), border_y: "", border_i: "", border_top: false, border_bottom: false, padding_left: 0, padding_right: 3}
|
|
89
|
+
end
|
|
53
90
|
end
|
data/lib/multisync/version.rb
CHANGED
data/lib/multisync.rb
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "multisync/version"
|
|
2
4
|
|
|
3
5
|
module Multisync
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
autoload :
|
|
7
|
-
autoload :
|
|
8
|
-
autoload :
|
|
9
|
-
autoload :
|
|
10
|
-
autoload :
|
|
11
|
-
autoload :
|
|
6
|
+
class Error < StandardError; end
|
|
7
|
+
|
|
8
|
+
autoload :Cli, "multisync/cli"
|
|
9
|
+
autoload :Colors, "multisync/colors"
|
|
10
|
+
autoload :Definition, "multisync/definition"
|
|
11
|
+
autoload :Catalog, "multisync/catalog"
|
|
12
|
+
autoload :Selector, "multisync/selector"
|
|
13
|
+
autoload :Runtime, "multisync/runtime"
|
|
14
|
+
autoload :RsyncStat, "multisync/rsync_stat"
|
|
15
|
+
autoload :Summary, "multisync/summary"
|
|
16
|
+
autoload :List, "multisync/list"
|
|
12
17
|
end
|
data/sample/multisync.rb
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
# Choose one of the section A), B) or C) as a starting point
|
|
3
3
|
# to adjust the configuration to your needs.
|
|
4
4
|
|
|
5
|
-
|
|
6
5
|
################################################################################
|
|
7
6
|
|
|
8
7
|
# A) Simple rsync task
|
|
@@ -10,26 +9,24 @@
|
|
|
10
9
|
sync :simple do
|
|
11
10
|
from "~/Documents"
|
|
12
11
|
to "/PathToExternalDisk"
|
|
13
|
-
options %w
|
|
12
|
+
options %w[--archive --exclude=.DS_Store] # as array
|
|
14
13
|
end
|
|
15
14
|
|
|
16
15
|
# This task can be run with: "multisync simple"
|
|
17
16
|
|
|
18
|
-
|
|
19
17
|
################################################################################
|
|
20
18
|
|
|
21
19
|
# B) Group of rsync tasks
|
|
22
20
|
|
|
23
21
|
group :userdata do
|
|
24
|
-
|
|
25
22
|
# Define the target path for the whole group and check the existance of the
|
|
26
23
|
# target path before running the rsync task.
|
|
27
24
|
# Also set an optional description for the target.
|
|
28
25
|
to "/PathToExternalDisk", description: "External HD", check: true
|
|
29
26
|
|
|
30
27
|
# Define rsync options for the whole group
|
|
31
|
-
options %w
|
|
32
|
-
|
|
28
|
+
options %w[--archive --exclude=.DS_Store]
|
|
29
|
+
|
|
33
30
|
sync :desktop do
|
|
34
31
|
# With optional description of the source
|
|
35
32
|
from "~/Desktop", description: "Desktop"
|
|
@@ -42,28 +39,25 @@ group :userdata do
|
|
|
42
39
|
sync :downloads do
|
|
43
40
|
from "~/Downloads", description: "Downloads"
|
|
44
41
|
# Add options specific to this task.
|
|
45
|
-
options %w
|
|
42
|
+
options %w[--exclude='*.download']
|
|
46
43
|
end
|
|
47
44
|
end
|
|
48
45
|
|
|
49
46
|
# Run the whole group with: "multisync userdata"
|
|
50
47
|
# Run a single taks with: "multisync userdata/downloads"
|
|
51
48
|
|
|
52
|
-
|
|
53
49
|
################################################################################
|
|
54
50
|
|
|
55
51
|
# C) Real world example using templates, defaults and options override
|
|
56
52
|
|
|
57
53
|
# rsync options for all tasks
|
|
58
|
-
options %w
|
|
59
|
-
|
|
54
|
+
options %w[--archive --delete --delete-excluded --delete-after --exclude=.DS_Store --exclude=.localized]
|
|
60
55
|
|
|
61
56
|
# Use templates to define a set of tasks that can be included later
|
|
62
57
|
template :data do
|
|
63
|
-
|
|
64
58
|
# Always check the existance of the source path
|
|
65
59
|
check_from true
|
|
66
|
-
|
|
60
|
+
|
|
67
61
|
# rsync tasks with uncomplete arguments:
|
|
68
62
|
# Define the target later where the template will be included.
|
|
69
63
|
# This can be used to sync multiple directories to different remote locations.
|
|
@@ -78,26 +72,25 @@ template :data do
|
|
|
78
72
|
sync :downloads do
|
|
79
73
|
from "~/Downloads", description: "Downloads"
|
|
80
74
|
# Don't merge options
|
|
81
|
-
options %w
|
|
75
|
+
options %w[--times --exclude='*.download'], :override
|
|
82
76
|
end
|
|
83
77
|
end
|
|
84
78
|
|
|
85
|
-
|
|
86
79
|
group :hd do
|
|
87
80
|
# Uncomment the following line to run this group by default
|
|
88
81
|
# default
|
|
89
|
-
|
|
82
|
+
|
|
90
83
|
# Define the target to be used by all tasks.
|
|
91
84
|
# The existance of the target path should be checked.
|
|
92
85
|
to "/TargetPathToBackupDisk/MyComputer", description: "External Disk", check: true
|
|
93
|
-
|
|
86
|
+
|
|
94
87
|
# Include the template with the task definitions
|
|
95
88
|
include :data
|
|
96
89
|
end
|
|
97
90
|
|
|
98
91
|
group :nas do
|
|
99
92
|
to "user@nas.local:/data/backup/my_computer", description: "NAS", check: true
|
|
100
|
-
|
|
93
|
+
|
|
101
94
|
# Include the template with the task definitions
|
|
102
95
|
include :data
|
|
103
96
|
end
|
|
@@ -106,7 +99,6 @@ end
|
|
|
106
99
|
# Sync "desktop" to "hd" and "nas": "multisync desktop"
|
|
107
100
|
# Sync "desktop" to "hd" only: "multisync hd/desktop"
|
|
108
101
|
|
|
109
|
-
|
|
110
102
|
################################################################################
|
|
111
103
|
|
|
112
104
|
# Additional notes
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: multisync
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Patrick Marchi
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: exe
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 2025-11-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: mixlib-shellout
|
|
@@ -66,6 +65,20 @@ dependencies:
|
|
|
66
65
|
- - ">="
|
|
67
66
|
- !ruby/object:Gem::Version
|
|
68
67
|
version: '0'
|
|
68
|
+
- !ruby/object:Gem::Dependency
|
|
69
|
+
name: thor
|
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - ">="
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '0'
|
|
75
|
+
type: :runtime
|
|
76
|
+
prerelease: false
|
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - ">="
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '0'
|
|
69
82
|
description: A DSL to organize sets of rsync tasks.
|
|
70
83
|
email:
|
|
71
84
|
- mail@patrickmarchi.ch
|
|
@@ -74,19 +87,17 @@ executables:
|
|
|
74
87
|
extensions: []
|
|
75
88
|
extra_rdoc_files: []
|
|
76
89
|
files:
|
|
77
|
-
- ".gitignore"
|
|
78
90
|
- ".rspec"
|
|
91
|
+
- ".standard.yml"
|
|
79
92
|
- CHANGELOG.md
|
|
80
|
-
- Gemfile
|
|
81
93
|
- LICENSE.txt
|
|
82
94
|
- README.md
|
|
83
95
|
- Rakefile
|
|
84
|
-
- bin/console
|
|
85
|
-
- bin/setup
|
|
86
96
|
- exe/multisync
|
|
87
97
|
- lib/multisync.rb
|
|
88
98
|
- lib/multisync/catalog.rb
|
|
89
99
|
- lib/multisync/cli.rb
|
|
100
|
+
- lib/multisync/colors.rb
|
|
90
101
|
- lib/multisync/definition.rb
|
|
91
102
|
- lib/multisync/definition/dsl.rb
|
|
92
103
|
- lib/multisync/definition/entity.rb
|
|
@@ -98,7 +109,6 @@ files:
|
|
|
98
109
|
- lib/multisync/selector.rb
|
|
99
110
|
- lib/multisync/summary.rb
|
|
100
111
|
- lib/multisync/version.rb
|
|
101
|
-
- multisync.gemspec
|
|
102
112
|
- sample/multisync.rb
|
|
103
113
|
homepage: https://github.com/pmarchi/multisync
|
|
104
114
|
licenses:
|
|
@@ -107,8 +117,7 @@ metadata:
|
|
|
107
117
|
allowed_push_host: https://rubygems.org
|
|
108
118
|
homepage_uri: https://github.com/pmarchi/multisync
|
|
109
119
|
source_code_uri: https://github.com/pmarchi/multisync
|
|
110
|
-
changelog_uri: https://github.com/pmarchi/multisync/blob/
|
|
111
|
-
post_install_message:
|
|
120
|
+
changelog_uri: https://github.com/pmarchi/multisync/blob/master/CHANGELOG.md
|
|
112
121
|
rdoc_options: []
|
|
113
122
|
require_paths:
|
|
114
123
|
- lib
|
|
@@ -116,15 +125,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
116
125
|
requirements:
|
|
117
126
|
- - ">="
|
|
118
127
|
- !ruby/object:Gem::Version
|
|
119
|
-
version:
|
|
128
|
+
version: 3.1.0
|
|
120
129
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
121
130
|
requirements:
|
|
122
131
|
- - ">="
|
|
123
132
|
- !ruby/object:Gem::Version
|
|
124
133
|
version: '0'
|
|
125
134
|
requirements: []
|
|
126
|
-
rubygems_version: 3.
|
|
127
|
-
signing_key:
|
|
135
|
+
rubygems_version: 3.6.6
|
|
128
136
|
specification_version: 4
|
|
129
|
-
summary: multisync-0.
|
|
137
|
+
summary: multisync-0.4.0
|
|
130
138
|
test_files: []
|
data/.gitignore
DELETED
data/Gemfile
DELETED
data/bin/console
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
|
|
3
|
-
require "bundler/setup"
|
|
4
|
-
require "multisync"
|
|
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(__FILE__)
|
data/bin/setup
DELETED
data/multisync.gemspec
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
require_relative "lib/multisync/version"
|
|
5
|
-
|
|
6
|
-
Gem::Specification.new do |spec|
|
|
7
|
-
spec.name = "multisync"
|
|
8
|
-
spec.version = Multisync::VERSION
|
|
9
|
-
spec.authors = ["Patrick Marchi"]
|
|
10
|
-
spec.email = ["mail@patrickmarchi.ch"]
|
|
11
|
-
|
|
12
|
-
spec.summary = [spec.name, spec.version].join("-")
|
|
13
|
-
spec.description = "A DSL to organize sets of rsync tasks."
|
|
14
|
-
spec.homepage = "https://github.com/pmarchi/multisync"
|
|
15
|
-
spec.license = "MIT"
|
|
16
|
-
spec.required_ruby_version = ">= 2.4.0"
|
|
17
|
-
|
|
18
|
-
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
|
19
|
-
|
|
20
|
-
spec.metadata["homepage_uri"] = spec.homepage
|
|
21
|
-
spec.metadata["source_code_uri"] = spec.homepage
|
|
22
|
-
spec.metadata["changelog_uri"] = File.join(spec.homepage, "blob/main/CHANGELOG.md")
|
|
23
|
-
|
|
24
|
-
# Specify which files should be added to the gem when it is released.
|
|
25
|
-
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
|
26
|
-
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
|
27
|
-
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
|
|
28
|
-
end
|
|
29
|
-
spec.bindir = "exe"
|
|
30
|
-
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
|
31
|
-
spec.require_paths = ["lib"]
|
|
32
|
-
|
|
33
|
-
# Uncomment to register a new dependency of your gem
|
|
34
|
-
spec.add_dependency "mixlib-shellout"
|
|
35
|
-
spec.add_dependency "filesize"
|
|
36
|
-
spec.add_dependency "rainbow"
|
|
37
|
-
spec.add_dependency "terminal-table"
|
|
38
|
-
|
|
39
|
-
# For more information and examples about making a new gem, checkout our
|
|
40
|
-
# guide at: https://bundler.io/guides/creating_gem.html
|
|
41
|
-
end
|