ruby_clone 1.0.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.
- 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
|