mclone 0.2.1 → 0.3.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.
Files changed (7) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +16 -8
  3. data/README.md +409 -409
  4. data/bin/mclone +1 -157
  5. data/lib/mclone/cli.rb +157 -0
  6. data/lib/mclone.rb +752 -745
  7. metadata +4 -3
data/bin/mclone CHANGED
@@ -1,159 +1,3 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- # frozen_string_literal: true
4
-
5
- require 'clamp'
6
- require 'mclone'
7
-
8
- include Mclone
9
-
10
- begin
11
-
12
- Clamp do
13
-
14
- using Refinements
15
-
16
- self.default_subcommand = 'info'
17
-
18
- option ['-f', '--force'], :flag, 'Insist on potentially dangerous actions', default: false
19
- option ['-n', '--dry-run'], :flag, 'Simulation mode with no on-disk modifications', default: false
20
- option ['-v', '--verbose'], :flag, 'Verbose operation', default: false
21
-
22
- option ['-V', '--version'], :flag, 'Show version' do
23
- puts VERSION
24
- exit(true)
25
- end
26
-
27
- def session
28
- session = Mclone::Session.new
29
- session.force = force?
30
- session.simulate = dry_run?
31
- session.verbose = verbose?
32
- session.restore_volumes!
33
- session
34
- end
35
-
36
- def resolve_mode(mode)
37
- case (m = Task::MODES.resolve(mode)).size
38
- when 0 then raise(Task::Error, %(no modes matching pattern "#{mode}"))
39
- when 1 then m.first
40
- else raise(Task::Error, %(ambiguous mode pattern "#{mode}"))
41
- end
42
- end
43
-
44
- subcommand 'info', 'Output information on volumes & tasks' do
45
- def execute
46
- s = session
47
- $stdout.puts "# Mclone version #{Mclone::VERSION}"
48
- $stdout.puts
49
- $stdout.puts '## Volumes'
50
- $stdout.puts
51
- s.volumes.each { |volume| $stdout.puts "* [#{volume.id}] :: (#{volume.root})" }
52
- stales = []
53
- intacts = []
54
- intact_tasks = s.intact_tasks
55
- s.tasks.each do |task|
56
- ts = (t = intact_tasks[task]).nil? ? "<#{task.id}>" : "[#{task.id}]"
57
- svs = s.volumes.volume(task.source_id).nil? ? "<#{task.source_id}>" : "[#{task.source_id}]"
58
- dvs = s.volumes.volume(task.destination_id).nil? ? "<#{task.destination_id}>" : "[#{task.destination_id}]"
59
- crypter_mode = task.crypter_mode.nil? ? nil : "#{task.crypter_mode}+"
60
- xs = ["* #{ts} :: #{crypter_mode}#{task.mode} #{svs}(#{task.source_root}) -> #{dvs}(#{task.destination_root})"]
61
- xs << "include #{task.include}" unless task.include.nil? || task.include.empty?
62
- xs << "exclude #{task.exclude}" unless task.exclude.nil? || task.exclude.empty?
63
- (t.nil? ? stales : intacts) << xs.join(' :: ')
64
- end
65
- unless intacts.empty?
66
- $stdout.puts
67
- $stdout.puts '## Intact tasks'
68
- $stdout.puts
69
- intacts.each { |x| $stdout.puts x }
70
- end
71
- unless stales.empty?
72
- $stdout.puts
73
- $stdout.puts '## Stale tasks'
74
- $stdout.puts
75
- stales.each { |x| $stdout.puts x }
76
- end
77
- end
78
- end
79
-
80
- subcommand 'volume', 'Volume operations' do
81
-
82
- subcommand ['new', 'create'], 'Create new volume' do
83
- parameter 'DIRECTORY', 'Directory to become a Mclone volume'
84
- def execute
85
- session.format_volume!(directory)
86
- end
87
- end
88
-
89
- subcommand 'delete', 'Delete existing volume' do
90
- parameter 'VOLUME', 'Volume ID pattern'
91
- def execute
92
- session.delete_volume!(volume).commit!
93
- end
94
- end
95
-
96
- end
97
-
98
- subcommand 'task', 'Task operations' do
99
-
100
- def self.set_task_opts
101
- modes = Task::MODES.collect(&:to_s).join(' | ')
102
- option ['-m', '--mode'], 'MODE', "Operation mode (#{modes})", default: Task::MODES.first.to_s
103
- option ['-i', '--include'], 'PATTERN', 'Include paths pattern'
104
- option ['-x', '--exclude'], 'PATTERN', 'Exclude paths pattern'
105
- end
106
-
107
- subcommand ['new', 'create'], 'Create new SOURCE -> DESTINATION task' do
108
- set_task_opts
109
- option ['-d', '--decrypt'], :flag, 'Decrypt source'
110
- option ['-e', '--encrypt'], :flag, 'Encrypt destination'
111
- option ['-p', '--password'], 'PASSWORD', 'Plain text password'
112
- option ['-t', '--token'], 'TOKEN', 'Rclone crypt token (obscured password)'
113
- parameter 'SOURCE', 'Source path'
114
- parameter 'DESTINATION', 'Destination path'
115
- def execute
116
- crypter_mode = nil
117
- signal_usage_error 'choose either encryption or decryption mode, not both' if decrypt? && encrypt?
118
- signal_usage_error 'specify either plain text password or Rclone crypt token, not both' if !password.nil? && !token.nil?
119
- crypter_mode = :encrypt if encrypt?
120
- crypter_mode = :decrypt if decrypt?
121
- session.create_task!(
122
- resolve_mode(mode),
123
- source,
124
- destination,
125
- include: include, exclude: exclude, crypter_mode: crypter_mode, crypter_password: password, crypter_token: token
126
- ).commit!
127
- end
128
- end
129
-
130
- subcommand 'modify', 'Modify existing task' do
131
- set_task_opts
132
- parameter 'TASK', 'Task ID pattern'
133
- def execute
134
- session.modify_task!(task, mode: resolve_mode(mode), include: include, exclude: exclude).commit!
135
- end
136
- end
137
-
138
- subcommand 'delete', 'Delete existing task' do
139
- parameter 'TASK', 'Task ID pattern'
140
- def execute
141
- session.delete_task!(task).commit!
142
- end
143
- end
144
-
145
- subcommand 'process', 'Process specified tasks' do
146
- parameter '[TASK] ...', 'Task ID pattern(s)', attribute_name: :tasks
147
- def execute
148
- session.process_tasks!(*tasks)
149
- end
150
- end
151
-
152
- end
153
-
154
- end
155
-
156
- rescue Mclone::Error
157
- $stderr.puts "ERROR: #{$!.message}"
158
- exit(false)
159
- end
3
+ require 'mclone/cli'
data/lib/mclone/cli.rb ADDED
@@ -0,0 +1,157 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'clamp'
4
+ require 'mclone'
5
+
6
+ include Mclone
7
+
8
+ begin
9
+
10
+ Clamp do
11
+
12
+ using Refinements
13
+
14
+ self.default_subcommand = 'info'
15
+
16
+ option ['-f', '--force'], :flag, 'Insist on potentially dangerous actions', default: false
17
+ option ['-n', '--dry-run'], :flag, 'Simulation mode with no on-disk modifications', default: false
18
+ option ['-v', '--verbose'], :flag, 'Verbose operation', default: false
19
+
20
+ option ['-V', '--version'], :flag, 'Show version' do
21
+ puts VERSION
22
+ exit(true)
23
+ end
24
+
25
+ def session
26
+ session = Mclone::Session.new
27
+ session.force = force?
28
+ session.simulate = dry_run?
29
+ session.verbose = verbose?
30
+ session.restore_volumes!
31
+ session
32
+ end
33
+
34
+ def resolve_mode(mode)
35
+ case (m = Task::MODES.resolve(mode)).size
36
+ when 0 then raise(Task::Error, %(no modes matching pattern "#{mode}"))
37
+ when 1 then m.first
38
+ else raise(Task::Error, %(ambiguous mode pattern "#{mode}"))
39
+ end
40
+ end
41
+
42
+ subcommand 'info', 'Output information on volumes & tasks' do
43
+ def execute
44
+ s = session
45
+ $stdout.puts "# Mclone version #{Mclone::VERSION}"
46
+ $stdout.puts
47
+ $stdout.puts '## Volumes'
48
+ $stdout.puts
49
+ s.volumes.each { |volume| $stdout.puts "* [#{volume.id}] :: (#{volume.root})" }
50
+ stales = []
51
+ intacts = []
52
+ intact_tasks = s.intact_tasks
53
+ s.tasks.each do |task|
54
+ ts = (t = intact_tasks[task]).nil? ? "<#{task.id}>" : "[#{task.id}]"
55
+ svs = s.volumes.volume(task.source_id).nil? ? "<#{task.source_id}>" : "[#{task.source_id}]"
56
+ dvs = s.volumes.volume(task.destination_id).nil? ? "<#{task.destination_id}>" : "[#{task.destination_id}]"
57
+ crypter_mode = task.crypter_mode.nil? ? nil : "#{task.crypter_mode}+"
58
+ xs = ["* #{ts} :: #{crypter_mode}#{task.mode} #{svs}(#{task.source_root}) -> #{dvs}(#{task.destination_root})"]
59
+ xs << "include #{task.include}" unless task.include.nil? || task.include.empty?
60
+ xs << "exclude #{task.exclude}" unless task.exclude.nil? || task.exclude.empty?
61
+ (t.nil? ? stales : intacts) << xs.join(' :: ')
62
+ end
63
+ unless intacts.empty?
64
+ $stdout.puts
65
+ $stdout.puts '## Intact tasks'
66
+ $stdout.puts
67
+ intacts.each { |x| $stdout.puts x }
68
+ end
69
+ unless stales.empty?
70
+ $stdout.puts
71
+ $stdout.puts '## Stale tasks'
72
+ $stdout.puts
73
+ stales.each { |x| $stdout.puts x }
74
+ end
75
+ end
76
+ end
77
+
78
+ subcommand 'volume', 'Volume operations' do
79
+
80
+ subcommand ['new', 'create'], 'Create new volume' do
81
+ parameter 'DIRECTORY', 'Directory to become a Mclone volume'
82
+ def execute
83
+ session.format_volume!(directory)
84
+ end
85
+ end
86
+
87
+ subcommand 'delete', 'Delete existing volume' do
88
+ parameter 'VOLUME', 'Volume ID pattern'
89
+ def execute
90
+ session.delete_volume!(volume).commit!
91
+ end
92
+ end
93
+
94
+ end
95
+
96
+ subcommand 'task', 'Task operations' do
97
+
98
+ def self.set_task_opts
99
+ modes = Task::MODES.collect(&:to_s).join(' | ')
100
+ option ['-m', '--mode'], 'MODE', "Operation mode (#{modes})", default: Task::MODES.first.to_s
101
+ option ['-i', '--include'], 'PATTERN', 'Include paths pattern'
102
+ option ['-x', '--exclude'], 'PATTERN', 'Exclude paths pattern'
103
+ end
104
+
105
+ subcommand ['new', 'create'], 'Create new SOURCE -> DESTINATION task' do
106
+ set_task_opts
107
+ option ['-d', '--decrypt'], :flag, 'Decrypt source'
108
+ option ['-e', '--encrypt'], :flag, 'Encrypt destination'
109
+ option ['-p', '--password'], 'PASSWORD', 'Plain text password'
110
+ option ['-t', '--token'], 'TOKEN', 'Rclone crypt token (obscured password)'
111
+ parameter 'SOURCE', 'Source path'
112
+ parameter 'DESTINATION', 'Destination path'
113
+ def execute
114
+ crypter_mode = nil
115
+ signal_usage_error 'choose either encryption or decryption mode, not both' if decrypt? && encrypt?
116
+ signal_usage_error 'specify either plain text password or Rclone crypt token, not both' if !password.nil? && !token.nil?
117
+ crypter_mode = :encrypt if encrypt?
118
+ crypter_mode = :decrypt if decrypt?
119
+ session.create_task!(
120
+ resolve_mode(mode),
121
+ source,
122
+ destination,
123
+ include: include, exclude: exclude, crypter_mode: crypter_mode, crypter_password: password, crypter_token: token
124
+ ).commit!
125
+ end
126
+ end
127
+
128
+ subcommand 'modify', 'Modify existing task' do
129
+ set_task_opts
130
+ parameter 'TASK', 'Task ID pattern'
131
+ def execute
132
+ session.modify_task!(task, mode: resolve_mode(mode), include: include, exclude: exclude).commit!
133
+ end
134
+ end
135
+
136
+ subcommand 'delete', 'Delete existing task' do
137
+ parameter 'TASK', 'Task ID pattern'
138
+ def execute
139
+ session.delete_task!(task).commit!
140
+ end
141
+ end
142
+
143
+ subcommand 'process', 'Process specified tasks' do
144
+ parameter '[TASK] ...', 'Task ID pattern(s)', attribute_name: :tasks
145
+ def execute
146
+ session.process_tasks!(*tasks)
147
+ end
148
+ end
149
+
150
+ end
151
+
152
+ end
153
+
154
+ rescue Mclone::Error
155
+ $stderr.puts "ERROR: #{$!.message}"
156
+ exit(false)
157
+ end