mclone 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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