ruby_clone 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/Guardfile +10 -0
- data/LICENSE +22 -0
- data/README.md +329 -0
- data/Rakefile +2 -0
- data/bin/ruby_clone +16 -0
- data/lib/ruby_clone/backup_utils.rb +41 -0
- data/lib/ruby_clone/dsl.rb +79 -0
- data/lib/ruby_clone/options.rb +38 -0
- data/lib/ruby_clone/profile.rb +128 -0
- data/lib/ruby_clone/rsync.rb +94 -0
- data/lib/ruby_clone/version.rb +3 -0
- data/lib/ruby_clone.rb +11 -0
- data/ruby_clone.gemspec +21 -0
- data/spec/ruby_clone/backup_utils_spec.rb +82 -0
- data/spec/ruby_clone/dsl_spec.rb +259 -0
- data/spec/ruby_clone/options_spec.rb +60 -0
- data/spec/ruby_clone/profile_spec.rb +222 -0
- data/spec/ruby_clone/rsync_spec.rb +309 -0
- data/spec/spec_helper.rb +1 -0
- metadata +106 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
notification :off
|
5
|
+
|
6
|
+
guard 'rspec', :cli => "--colour" do
|
7
|
+
watch(%r{^spec/.+_spec\.rb$})
|
8
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
9
|
+
watch('spec/spec_helper.rb') { "spec" }
|
10
|
+
end
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Frederico Benevides
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,329 @@
|
|
1
|
+
# **RubyClone** - Simplifying the use of Rsync
|
2
|
+
|
3
|
+
**RubyClone** was designed to be simple, easy, clean and a high level script for RSync.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Install the gem:
|
8
|
+
|
9
|
+
gem install ruby_clone
|
10
|
+
|
11
|
+
Create a file that is named '.ruby_clone' in your home folder and set up a profile.
|
12
|
+
**NOTE**: Don't forget to use the dot in the file.
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
|
16
|
+
$ ruby_clone my_profile
|
17
|
+
|
18
|
+
You can also specify another path of your **RubyClone** file:
|
19
|
+
|
20
|
+
$ ruby_clone -b /my/ruby_clone_file my_profile
|
21
|
+
|
22
|
+
## Usage
|
23
|
+
|
24
|
+
### Basic Configuration
|
25
|
+
|
26
|
+
To start using it, you'll need to create the following configuration in your **RubyClone** file.
|
27
|
+
|
28
|
+
**NOTE**: The folder of from configurations needs to have the last slash. If it doesn't have, it will copy the
|
29
|
+
'source_folder' inside the 'destination_folder'. (This behaviour is from RSync)
|
30
|
+
|
31
|
+
**NOTE 2**: If your source folder/destination_folder has spaces as "My Source Folder", you need to set up it as
|
32
|
+
"My\\ Source\\ Folder" with **two back slashes** for **each space**. Spaces and only one back slash will not work.
|
33
|
+
|
34
|
+
|
35
|
+
profile :my_profile do
|
36
|
+
from "/my/source_folder/"
|
37
|
+
to "/my/destination_folder"
|
38
|
+
end
|
39
|
+
|
40
|
+
If you set up this configuration in your $HOME/.ruby_clone, you can run with:
|
41
|
+
|
42
|
+
$ ruby_clone my_profile
|
43
|
+
|
44
|
+
If is in another path, run with:
|
45
|
+
|
46
|
+
$ ruby_clone -b /my/backup_file my_profile
|
47
|
+
|
48
|
+
**NOTE**: This basic setup doesn't sync deleted files from the source folder. If you want to delete them, you need
|
49
|
+
to setup the option 'delete: true'.
|
50
|
+
|
51
|
+
### SSH
|
52
|
+
|
53
|
+
**RubyClone** offers the option to use SSH in a easy way. You just need to use the option ':ssh' with the 'user@host'.
|
54
|
+
Example for SSH that is on source folder.
|
55
|
+
|
56
|
+
profile :my_profile do
|
57
|
+
from "/my/source_folder/", ssh: "user@source_server"
|
58
|
+
to "/my/destination_folder"
|
59
|
+
end
|
60
|
+
|
61
|
+
Example for SSH that is on destination folder:
|
62
|
+
|
63
|
+
profile :my_profile do
|
64
|
+
from "/my/source_folder/"
|
65
|
+
to "/my/destination_folder", ssh: "user@destination_server"
|
66
|
+
end
|
67
|
+
|
68
|
+
After running one of theses profiles, you just need to type the password.
|
69
|
+
|
70
|
+
## Improving your **RubyClone** file
|
71
|
+
|
72
|
+
**RubyClone** aims to be simple and be readable for you when you set up it. All the new configurations that you
|
73
|
+
can set up was created with this in mind.
|
74
|
+
|
75
|
+
Here is all the configuration you can set up and improve your **RubyClone** file.
|
76
|
+
|
77
|
+
### Excluding a Pattern - exclude_pattern "pattern"
|
78
|
+
|
79
|
+
If you need to exclude folders or files matching a pattern, use the 'exclude_pattern command.
|
80
|
+
This command can be used in two ways: On the top of **RubyClone** file and/or inside the 'from'.
|
81
|
+
Here a complete example:
|
82
|
+
|
83
|
+
exclude_pattern "top_pattern"
|
84
|
+
|
85
|
+
profile :my_profile1 do
|
86
|
+
from "/my/source_folder/"
|
87
|
+
to "/my/destination_folder"
|
88
|
+
end
|
89
|
+
|
90
|
+
profile :my_profile2 do
|
91
|
+
from "/my/source_folder/" do
|
92
|
+
exclude_pattern "from_pattern"
|
93
|
+
end
|
94
|
+
to "/my/destination_folder"
|
95
|
+
end
|
96
|
+
|
97
|
+
1. 'my_profile1' will exclude only the "top_pattern".
|
98
|
+
2. 'my_profile2' will exclude the "top_pattern" and "from_pattern"
|
99
|
+
|
100
|
+
### Including a Pattern - include_pattern "pattern"
|
101
|
+
|
102
|
+
Same as the exclude_pattern. If you need to include folders or files matching a pattern, use the
|
103
|
+
include_pattern command. This command can be use in two ways: On the top of **RubyClone** file and/or
|
104
|
+
inside the 'from' block. Example:
|
105
|
+
|
106
|
+
include_pattern "top_pattern"
|
107
|
+
|
108
|
+
profile :my_profile1 do
|
109
|
+
from "/my/source_folder/"
|
110
|
+
to "/my/destination_folder"
|
111
|
+
end
|
112
|
+
|
113
|
+
profile :my_profile2 do
|
114
|
+
from "/my/source_folder/" do
|
115
|
+
include_pattern "from_pattern"
|
116
|
+
end
|
117
|
+
to "/my/destination_folder"
|
118
|
+
end
|
119
|
+
|
120
|
+
1. 'my_profile1' will include only the "top_pattern".
|
121
|
+
2. 'my_profile2' will include the "top_pattern" and "from_pattern"
|
122
|
+
|
123
|
+
Here an example using exclude_pattern and include_pattern together. In this example, :my_profile will exclude
|
124
|
+
all folders and will sync/include only the 'from_pattern'
|
125
|
+
|
126
|
+
profile :my_profile do
|
127
|
+
from "/my/source_folder/" do
|
128
|
+
exclude_pattern "*"
|
129
|
+
include_pattern "from_pattern"
|
130
|
+
end
|
131
|
+
to "/my/destination_folder"
|
132
|
+
end
|
133
|
+
|
134
|
+
### Deleting files
|
135
|
+
|
136
|
+
1. Deleting files that don't exist in source_folder but in destination folder - delete: true
|
137
|
+
|
138
|
+
The basic configuration was created to be a secure configuration. So if you really want to delete files/folders
|
139
|
+
in your destination folder that doesn't exist anymore in your source folder, you'll need to set up 'delete: true' in
|
140
|
+
your **RubyClone** file. Below an example how to do it:
|
141
|
+
|
142
|
+
profile :my_profile do
|
143
|
+
from "/my/source_folder/"
|
144
|
+
to "/my/destination_folder", delete: true
|
145
|
+
end
|
146
|
+
|
147
|
+
Now all files that exists in "/my/destination_folder/" but "/my/source_folder" will be deleted. If for some
|
148
|
+
reason you want to keep some files and delete others, just set up the exclude_pattern inside 'from' block.
|
149
|
+
|
150
|
+
2. Deleting files that are excluded from source folder to destination folder - delete_excluded: true
|
151
|
+
|
152
|
+
If you decided to exclude files from the syncronization but they still in your destination folder, you can use
|
153
|
+
the 'delete_excluded' to delete this files inside destination folder that are excluded from the source_folder.
|
154
|
+
Example:
|
155
|
+
|
156
|
+
profile :my_profile do
|
157
|
+
from "/my/source_folder/" do
|
158
|
+
exclude_pattern "my_pattern"
|
159
|
+
end
|
160
|
+
to "/my/destination_folder", delete_excluded: true
|
161
|
+
end
|
162
|
+
|
163
|
+
Now all files that are inside destination_folder that have the pattern 'my_pattern' will be deleted.
|
164
|
+
|
165
|
+
**NOTE**: When you use 'delete_excluded :true' you don't need to set up 'delete: true' even the from
|
166
|
+
configuration doesn't have the 'exclude_pattern'
|
167
|
+
|
168
|
+
### Backuping files - backup "folder"
|
169
|
+
|
170
|
+
1. If you want to save all the files that get **updated** and **deleted**, you need to set up the 'backup'
|
171
|
+
configuration inside the 'to' block. Example:
|
172
|
+
|
173
|
+
profile :my_profile do
|
174
|
+
from "/my/source_folder/"
|
175
|
+
to "/my/destination_folder", delete: true do
|
176
|
+
backup "/my/backup_folder"
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
Now all the folders/files that get **updated** or **deleted** in the "/my/destination_folder" will be moved to
|
181
|
+
"/my/backup_folder". The files moved to "/my/destination_folder" will have a default suffix that is a **RubyClone**
|
182
|
+
control key plus the Date with the format: "yyyyMMdd".
|
183
|
+
|
184
|
+
All files that are saved in the "/my/backup_folder" will have a limit of 5 files. So if any file that passed this
|
185
|
+
limit, the old file will be deleted. You can change this limit using the option "limit".
|
186
|
+
|
187
|
+
**NOTE**: The **RubyClone** control key is a special key to use as a control to remove old duplicated files.
|
188
|
+
|
189
|
+
2. Changing the suffix of the files inside the backup folder - backup "folder", suffix: "my_suffix"
|
190
|
+
|
191
|
+
If you want to change the Date suffix for the files that you backup, you need to set the 'suffix' as a parameter to 'backup'.
|
192
|
+
Example:
|
193
|
+
|
194
|
+
profile :my_profile do
|
195
|
+
from "/my/source_folder/"
|
196
|
+
to "/my/destination_folder", delete: true do
|
197
|
+
backup "/my/backup_folder", suffix: "my_suffix"
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
Another example using suffix with the Time class of Ruby to generate the date with timestamp "yyyyMMdd_hhmmss" :
|
202
|
+
|
203
|
+
profile :my_profile do
|
204
|
+
from "/my/source_folder/"
|
205
|
+
to "/my/destination_folder", delete: true do
|
206
|
+
backup "/my/backup_folder", suffix: "_#{Time.now.strftime("%Y%m%d_%H%M%S")}"
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
**NOTE**: Changing the suffix will not change the **RubyClone** control key. Since this key control how to remove the
|
211
|
+
old duplicated files.
|
212
|
+
|
213
|
+
3. Disabling the default suffix - backup "folder", disable_suffix: true
|
214
|
+
|
215
|
+
If for some reason you want to disable the file suffix in the backup folder you can set true for 'default_true'. Doing
|
216
|
+
that all the files that are moved to "/my/backup_folder" will have the same name and it will get override by a new file.
|
217
|
+
Example:
|
218
|
+
|
219
|
+
profile :my_profile do
|
220
|
+
from "/my/source_folder/"
|
221
|
+
to "/my/destination_folder", delete: true do
|
222
|
+
backup "/my/backup_folder", disable_suffix: true
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
**NOTE**: This kind of setup will **backup only one file** and nothing more.
|
227
|
+
|
228
|
+
4. Changing how many files you want to backup - backup "folder", limit: 10
|
229
|
+
|
230
|
+
**RubyClone** have a default to save 5 files "/my/backup_folder" that have the same name. If you want to change the
|
231
|
+
limit you just need to set up the option limit with the number of files to save.
|
232
|
+
Example:
|
233
|
+
|
234
|
+
profile :my_profile do
|
235
|
+
from "/my/source_folder/"
|
236
|
+
to "/my/destination_folder", delete: true do
|
237
|
+
backup "/my/backup_folder", limit: 20
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
Now "/my/backup_folder" will save 20 files with the same name.
|
242
|
+
|
243
|
+
5. Disabling the limit of files to save. Save unlimited files - backup "folder", limit: :unlimited
|
244
|
+
|
245
|
+
If for some reason you want to backup all files that are **updated** or **deleted** you need to set up the 'limit'
|
246
|
+
option with ':unlimited'
|
247
|
+
Example:
|
248
|
+
|
249
|
+
profile :my_profile do
|
250
|
+
from "/my/source_folder/"
|
251
|
+
to "/my/destination_folder", delete: true do
|
252
|
+
backup "/my/backup_folder", limit: :unlimited
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
Now all files will be saved, until you change the 'limit' to a specific number to erased all the old files that passed
|
257
|
+
the new limit.
|
258
|
+
|
259
|
+
### Disabling the output commands of RSync - config options
|
260
|
+
|
261
|
+
1. **RubyClone** offers the possibility to not show the rsync command generated (show_command) and rsync output
|
262
|
+
(show_output). To use it, you need to set up in the top of your **RubyClone** file the 'config' and the commands you
|
263
|
+
want to disable. Example:
|
264
|
+
|
265
|
+
config show_command: false, show_output: false
|
266
|
+
|
267
|
+
profile :my_profile do
|
268
|
+
from "/my/source_folder/"
|
269
|
+
to "/my/destination_folder"
|
270
|
+
end
|
271
|
+
|
272
|
+
The above config will not show anymore the rsync command and rsync outputs. But errors will keep showing if
|
273
|
+
happen.
|
274
|
+
|
275
|
+
2. Overriding the default configuration of Rsync command - config options: 'override_options'
|
276
|
+
|
277
|
+
If you need to override the default configurations for RSync you can set up the "config options: 'my_options'".
|
278
|
+
Example:
|
279
|
+
|
280
|
+
config options: '-Cav --stats'
|
281
|
+
|
282
|
+
profile :my_profile do
|
283
|
+
from "/my/source_folder/"
|
284
|
+
to "/my/destination_folder"
|
285
|
+
end
|
286
|
+
|
287
|
+
## Running
|
288
|
+
|
289
|
+
**RubyClone** as default will try to read the **RubyClone** file in your home folder: $HOME/.ruby_clone. If you
|
290
|
+
need to specify another path of your **RubyClone** file don't forget to add the option -b
|
291
|
+
|
292
|
+
$ ruby_clone -b /my/ruby_clone_file profile
|
293
|
+
|
294
|
+
RSync offers the options to dry-run the command and just run the sincronization as a simulation. You can do this
|
295
|
+
too with **RubyClone**. Just pass the option '-d' to ruby_clone
|
296
|
+
|
297
|
+
$ ruby_clone -d profile
|
298
|
+
|
299
|
+
## More interesting **RubyClone** file
|
300
|
+
|
301
|
+
Here a interesting **RubyClone** file that you can improve.
|
302
|
+
|
303
|
+
**NOTE**: Don't forget that the folder of from configuration needs to have the last slash. If it doesn't have,
|
304
|
+
it will copy the 'source_folder' inside the 'destination_folder. (This behaviour is from RSync)
|
305
|
+
|
306
|
+
**NOTE 2**: If your source folder/destination_folder has spaces as "/My Source Folder", you need to set up it as
|
307
|
+
"My\\ Source\\ Folder" with **two back slashes** for **each space**. Spaces and only one back slash will not work.
|
308
|
+
|
309
|
+
profile :my_profile do
|
310
|
+
from "/my/source_folder/" do
|
311
|
+
exclude_pattern "pattern"
|
312
|
+
end
|
313
|
+
to "/my/destination_folder", delete_excluded: true do
|
314
|
+
backup "/my/backup"
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
## **WARNINGS**
|
319
|
+
|
320
|
+
Even this script were has been tested many times, you run this script entirely at your own risk.
|
321
|
+
**RubyClone** accepts no responsibility for any damage this script may cause.
|
322
|
+
|
323
|
+
## Contributing to **RubyClone**
|
324
|
+
|
325
|
+
* Fork, fix, then send me a pull request.
|
326
|
+
|
327
|
+
## Copyright
|
328
|
+
|
329
|
+
Copyright (c) 2012 Frederico Benevides. See MIT-LICENSE for further details.
|
data/Rakefile
ADDED
data/bin/ruby_clone
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'ruby_clone'
|
4
|
+
|
5
|
+
extend RubyClone::DSL
|
6
|
+
|
7
|
+
options = RubyClone::Options.new(STDOUT)
|
8
|
+
options.parse(ARGV)
|
9
|
+
|
10
|
+
if !ARGV.empty?
|
11
|
+
load File.expand_path options.configurations[:backup_file]
|
12
|
+
|
13
|
+
rsync = current_rsync
|
14
|
+
rsync.dry_run = options.configurations[:dry_run]
|
15
|
+
run_backup ARGV[0]
|
16
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'find'
|
3
|
+
|
4
|
+
module RubyClone
|
5
|
+
|
6
|
+
module BackupUtils
|
7
|
+
|
8
|
+
def self.delete_files(path, ruby_clone_suffix, limit)
|
9
|
+
|
10
|
+
if File.exists?(path)
|
11
|
+
paths = find_files_with_same_name path, ruby_clone_suffix
|
12
|
+
delete_files_reached_the_limit paths, limit
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.find_files_with_same_name(path, ruby_clone_suffix)
|
17
|
+
paths = {}
|
18
|
+
|
19
|
+
Find.find(path) do |path|
|
20
|
+
path_without_suffix = path.sub(/#{ruby_clone_suffix}.*/, '')
|
21
|
+
|
22
|
+
if FileTest.file? path
|
23
|
+
paths[path_without_suffix] ||= []
|
24
|
+
paths[path_without_suffix] << path
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
paths
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.delete_files_reached_the_limit(paths, limit)
|
32
|
+
paths.each_value do |files|
|
33
|
+
if files.size > limit
|
34
|
+
files.slice(0, files.size - limit).each do |file|
|
35
|
+
FileUtils.remove_entry file
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module RubyClone
|
2
|
+
|
3
|
+
module DSL
|
4
|
+
|
5
|
+
lambda {
|
6
|
+
|
7
|
+
rsync = RubyClone::RSync.new(STDOUT)
|
8
|
+
current_object = rsync
|
9
|
+
|
10
|
+
define_method :current_rsync do
|
11
|
+
rsync
|
12
|
+
end
|
13
|
+
|
14
|
+
define_method :rsync_new_instance do
|
15
|
+
rsync = RubyClone::RSync.new(STDOUT)
|
16
|
+
current_object = rsync
|
17
|
+
end
|
18
|
+
|
19
|
+
define_method :run_backup do |profile|
|
20
|
+
rsync.run profile
|
21
|
+
end
|
22
|
+
|
23
|
+
define_method :profile do |name, &block|
|
24
|
+
profile = Profile.new(name)
|
25
|
+
current_object = profile
|
26
|
+
|
27
|
+
if block
|
28
|
+
rsync.profiles = profile
|
29
|
+
called_block = block.call
|
30
|
+
|
31
|
+
raise SyntaxError, 'Empty Profile not allowed' if not called_block
|
32
|
+
else
|
33
|
+
raise SyntaxError, 'Empty Profile not allowed'
|
34
|
+
end
|
35
|
+
|
36
|
+
current_object = rsync
|
37
|
+
end
|
38
|
+
|
39
|
+
define_method :from do |folder, options = {}, &block|
|
40
|
+
from_folder = FromFolder.new(folder, options)
|
41
|
+
current_object = from_folder
|
42
|
+
|
43
|
+
rsync.last_profile.from_folder = from_folder
|
44
|
+
|
45
|
+
block.call if block
|
46
|
+
current_object = rsync
|
47
|
+
end
|
48
|
+
|
49
|
+
define_method :to do |folder, options = {}, &block|
|
50
|
+
to_folder = ToFolder.new(folder, options)
|
51
|
+
current_object = to_folder
|
52
|
+
|
53
|
+
rsync.last_profile.to_folder = to_folder
|
54
|
+
|
55
|
+
block.call if block
|
56
|
+
current_object = rsync
|
57
|
+
end
|
58
|
+
|
59
|
+
define_method :backup do |path, options = {}|
|
60
|
+
backup = Backup.new(path, options)
|
61
|
+
current_object.backup = backup
|
62
|
+
end
|
63
|
+
|
64
|
+
define_method :exclude_pattern do |path|
|
65
|
+
current_object.exclude_pattern = path
|
66
|
+
end
|
67
|
+
|
68
|
+
define_method :include_pattern do |path|
|
69
|
+
current_object.include_pattern = path
|
70
|
+
end
|
71
|
+
|
72
|
+
define_method :config do |configurations|
|
73
|
+
current_object.update_configurations configurations
|
74
|
+
end
|
75
|
+
|
76
|
+
}.call
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
module RubyClone
|
4
|
+
|
5
|
+
class Options
|
6
|
+
attr_reader :configurations
|
7
|
+
attr_reader :profile
|
8
|
+
|
9
|
+
def initialize(output)
|
10
|
+
@output = output
|
11
|
+
@configurations = {}
|
12
|
+
@configurations[:backup_file] = '~/.ruby_clone'
|
13
|
+
end
|
14
|
+
|
15
|
+
def parse(argv)
|
16
|
+
opts = OptionParser.new do |opts|
|
17
|
+
opts.banner = "Usage: ruby_clone [options] profile"
|
18
|
+
|
19
|
+
opts.on("-b", "--backup-file path", String, "Change the path to backup file (default is #{ENV['HOME']}/.ruby_clone)") do |backup_file|
|
20
|
+
@configurations[:backup_file] = backup_file
|
21
|
+
end
|
22
|
+
|
23
|
+
opts.on("-d", "--dry-run", "Show what would have been transferred") do
|
24
|
+
@configurations[:dry_run] = true
|
25
|
+
end
|
26
|
+
|
27
|
+
opts.on("-h", "--help", "This message") do
|
28
|
+
@output.puts opts
|
29
|
+
end
|
30
|
+
|
31
|
+
argv = %w[-h] if argv.empty?
|
32
|
+
opts.parse!(argv)
|
33
|
+
end
|
34
|
+
opts
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
module RubyClone
|
2
|
+
|
3
|
+
class FromFolder
|
4
|
+
attr_accessor :path
|
5
|
+
|
6
|
+
def initialize(path, options = {})
|
7
|
+
@exclude_patterns = []
|
8
|
+
@include_patterns = []
|
9
|
+
@options = options
|
10
|
+
@path = path
|
11
|
+
end
|
12
|
+
|
13
|
+
def exclude_pattern=(path)
|
14
|
+
@exclude_patterns << path
|
15
|
+
end
|
16
|
+
|
17
|
+
def include_pattern=(path)
|
18
|
+
@include_patterns << path
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_command
|
22
|
+
command = ""
|
23
|
+
command << @include_patterns.map { |e| "--include=#{e}" }.join(" ") + " "
|
24
|
+
command << @exclude_patterns.map { |e| "--exclude=#{e}" }.join(" ")
|
25
|
+
command.strip
|
26
|
+
end
|
27
|
+
|
28
|
+
def ssh?
|
29
|
+
if @options[:ssh]
|
30
|
+
true
|
31
|
+
else
|
32
|
+
false
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_s
|
37
|
+
return "#{@options[:ssh]}:#{@path}" if @options[:ssh]
|
38
|
+
return @path if not @options[:ssh]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class ToFolder
|
43
|
+
attr_accessor :backup
|
44
|
+
attr_accessor :path
|
45
|
+
|
46
|
+
def initialize(path, options = {})
|
47
|
+
@path = path
|
48
|
+
@options = options
|
49
|
+
end
|
50
|
+
|
51
|
+
def delete_files
|
52
|
+
@backup.delete_files if @backup
|
53
|
+
end
|
54
|
+
|
55
|
+
def to_command
|
56
|
+
command = ""
|
57
|
+
command << "--delete " if @options[:delete]
|
58
|
+
command << "--delete-excluded " if @options[:delete_excluded]
|
59
|
+
|
60
|
+
command << backup.to_command if backup
|
61
|
+
command.strip
|
62
|
+
end
|
63
|
+
|
64
|
+
def ssh?
|
65
|
+
if @options[:ssh]
|
66
|
+
true
|
67
|
+
else
|
68
|
+
false
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def to_s
|
73
|
+
return "#{@options[:ssh]}:#{@path}" if @options[:ssh]
|
74
|
+
return @path if not @options[:ssh]
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
class Profile
|
79
|
+
attr_accessor :name
|
80
|
+
attr_accessor :from_folder
|
81
|
+
attr_accessor :to_folder
|
82
|
+
|
83
|
+
def initialize(name)
|
84
|
+
@name = name.to_s
|
85
|
+
end
|
86
|
+
|
87
|
+
def to_s
|
88
|
+
@name
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
class Backup
|
93
|
+
attr_accessor :path
|
94
|
+
|
95
|
+
def initialize(path, options = { })
|
96
|
+
@default_suffix = '_rbcl'
|
97
|
+
@options = { disable_suffix: false, limit: 5 }.merge(options)
|
98
|
+
@path = path
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
def delete_files
|
103
|
+
BackupUtils.delete_files @path, @default_suffix, @options[:limit] if @options[:limit] != :unlimited
|
104
|
+
end
|
105
|
+
|
106
|
+
def to_command
|
107
|
+
command = "-b "
|
108
|
+
command << "#{create_suffix} " if not @options[:disable_suffix]
|
109
|
+
command << "--backup-dir=#{path} "
|
110
|
+
command.strip
|
111
|
+
end
|
112
|
+
|
113
|
+
private
|
114
|
+
|
115
|
+
def create_suffix
|
116
|
+
time = @time || Time.now.strftime("%Y%m%d")
|
117
|
+
command = "--suffix="
|
118
|
+
command << "#{@default_suffix}_#{time}" if not @options[:suffix]
|
119
|
+
command << "#{@default_suffix}#{@options[:suffix]}" if @options[:suffix]
|
120
|
+
command
|
121
|
+
end
|
122
|
+
|
123
|
+
def to_s
|
124
|
+
@path
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|