backsum 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +20 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/Guardfile +9 -0
- data/LICENSE.txt +22 -0
- data/README.md +51 -0
- data/Rakefile +5 -0
- data/backsum.gemspec +33 -0
- data/bin/backsum +4 -0
- data/lib/backsum.rb +14 -0
- data/lib/backsum/backup.rb +36 -0
- data/lib/backsum/cli.rb +97 -0
- data/lib/backsum/project.rb +109 -0
- data/lib/backsum/project_dsl.rb +45 -0
- data/lib/backsum/server.rb +89 -0
- data/lib/backsum/shell.rb +43 -0
- data/lib/backsum/version.rb +3 -0
- data/spec/lib/backsum/cli_spec.rb +118 -0
- data/spec/lib/backsum/cli_spec/all-projects/mh.rb +6 -0
- data/spec/lib/backsum/cli_spec/all-projects/uat.rb +7 -0
- data/spec/lib/backsum/project_dsl_spec.rb +70 -0
- data/spec/lib/backsum/project_spec.rb +86 -0
- data/spec/lib/backsum/project_spec/second_time/20131020T153839/host1/file1 +0 -0
- data/spec/lib/backsum/project_spec/second_time/20131020T153839/host2/file2 +0 -0
- data/spec/lib/backsum/server_spec.rb +63 -0
- data/spec/lib/backsum/server_spec/source_first/folder1/file1 +0 -0
- data/spec/lib/backsum/server_spec/source_first/folder2/file2 +0 -0
- data/spec/lib/backsum/server_spec/source_increment/file1 +0 -0
- data/spec/lib/backsum/server_spec/source_increment/file2 +0 -0
- data/spec/lib/backsum/server_spec/target_increment_latest/localhost/folder1/file1 +0 -0
- data/spec/lib/backsum_spec.rb +8 -0
- data/spec/spec_helper.rb +24 -0
- metadata +249 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d878b3d6463c6744afb48d6e8ff579db32e87b1e
|
4
|
+
data.tar.gz: b71480829efc739d4bf7342b1a8c2d77ccb2e6d7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c96af7d9f9b43fd4e59724907b740d9bcaf51d1095095b7572f12c12c6d2acc975ec5f509ee65bed927674b07b5a2fcba7345dc9b15e0b8794a11169ff2d20e0
|
7
|
+
data.tar.gz: 28ab1177d4f4daf44ae350752c8d204b68a86c0ee24bfe624e6fc8cc79c0caffc2f5bf84f0d657b7d92a606025f133b3f984919a24978b14c3c7e6bf04450823
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 sunteya
|
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,51 @@
|
|
1
|
+
# Backsum
|
2
|
+
|
3
|
+
backsum is unix base the file system backup tools, it will incremental backup remote file to local storage.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'backsum'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install backsum
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
First, you have to configure your backup tasks.
|
22
|
+
|
23
|
+
$ mkdir ./projects
|
24
|
+
$ vi ./projects/one_task.rb
|
25
|
+
|
26
|
+
Create a ruby file to configure your first task.
|
27
|
+
|
28
|
+
# one_task.rb
|
29
|
+
|
30
|
+
name "one_task_name"
|
31
|
+
|
32
|
+
server "remotehost", username: "www-data" do
|
33
|
+
folder "/var/www/demo/apps/one_web/shared"
|
34
|
+
folder "/var/www/demo/apps/two_web/shared", excluded: ["logs", "assets"], as: "two_web_backup"
|
35
|
+
end
|
36
|
+
|
37
|
+
server "localhost", local: true do
|
38
|
+
folder "/foo", excluded: ["bar"], as: "local_backup"
|
39
|
+
end
|
40
|
+
|
41
|
+
Here’s how you run a backup server.
|
42
|
+
|
43
|
+
$ backsum --all
|
44
|
+
|
45
|
+
## Contributing
|
46
|
+
|
47
|
+
1. Fork it
|
48
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
49
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
50
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
51
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/backsum.gemspec
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'backsum/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "backsum"
|
8
|
+
spec.version = Backsum::VERSION
|
9
|
+
spec.authors = [ "sunteya", "jyfcrw" ]
|
10
|
+
spec.email = [ "sunteya@gmail.com", "jyfcrw@gmail.com" ]
|
11
|
+
spec.description = %q{backsum is unix base the file system backup tools, it will incremental backup remote file to local storage.}
|
12
|
+
spec.summary = %q{remote incremental backup tools}
|
13
|
+
spec.homepage = "https://github.com/sunteya/backsum"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_runtime_dependency "cocaine", "~> 0.5.2"
|
22
|
+
spec.add_runtime_dependency "posix-spawn", "~> 0.3.6"
|
23
|
+
spec.add_runtime_dependency "virtus", "~> 1.0.0"
|
24
|
+
spec.add_runtime_dependency "activesupport", ">= 3.0.0"
|
25
|
+
spec.add_runtime_dependency "logging", "~> 1.6.2"
|
26
|
+
|
27
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
28
|
+
spec.add_development_dependency "rake"
|
29
|
+
spec.add_development_dependency "pry-nav"
|
30
|
+
spec.add_development_dependency "rspec", "~> 2.14.1"
|
31
|
+
spec.add_development_dependency "simplecov", "~> 0.7.1"
|
32
|
+
spec.add_development_dependency "guard-rspec", "~> 4.0.3"
|
33
|
+
end
|
data/bin/backsum
ADDED
data/lib/backsum.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require_relative "backsum/version"
|
2
|
+
require "active_support/core_ext/module"
|
3
|
+
require "logging"
|
4
|
+
|
5
|
+
module Backsum
|
6
|
+
mattr_accessor :verbose
|
7
|
+
@@verbose = false
|
8
|
+
|
9
|
+
mattr_accessor :logger
|
10
|
+
@@logger = Logging.logger($stdout).tap do |logger|
|
11
|
+
logger.level = :info
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require "virtus"
|
2
|
+
|
3
|
+
module Backsum
|
4
|
+
class Backup
|
5
|
+
include Virtus.model
|
6
|
+
NAME_PATTERN = "%Y%m%dT%H%M%S"
|
7
|
+
|
8
|
+
attribute :name
|
9
|
+
attribute :base_dir
|
10
|
+
attribute :outdated, Boolean
|
11
|
+
|
12
|
+
def <=>(other)
|
13
|
+
self.backup_at <=> other.backup_at
|
14
|
+
end
|
15
|
+
|
16
|
+
def backup_at
|
17
|
+
DateTime.strptime(self.name, NAME_PATTERN)
|
18
|
+
end
|
19
|
+
|
20
|
+
def backup_at=(datetime)
|
21
|
+
self.name = datetime.strftime(NAME_PATTERN)
|
22
|
+
end
|
23
|
+
|
24
|
+
def path
|
25
|
+
File.join(self.base_dir, self.name)
|
26
|
+
end
|
27
|
+
|
28
|
+
def cweek
|
29
|
+
self.backup_at.cweek
|
30
|
+
end
|
31
|
+
|
32
|
+
def day
|
33
|
+
self.backup_at.day
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/backsum/cli.rb
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
require_relative "../backsum"
|
2
|
+
require_relative "version"
|
3
|
+
require_relative "project_dsl"
|
4
|
+
|
5
|
+
require 'optparse'
|
6
|
+
require "virtus"
|
7
|
+
|
8
|
+
module Backsum
|
9
|
+
class Cli
|
10
|
+
attr_accessor :options, :action
|
11
|
+
|
12
|
+
def initialize(*args)
|
13
|
+
self.options = { projects_path: "./projects" }
|
14
|
+
self.action = nil
|
15
|
+
end
|
16
|
+
|
17
|
+
def execute(argv = [])
|
18
|
+
option_parser!(argv)
|
19
|
+
|
20
|
+
Backsum.logger.level = :debug if ::Backsum.verbose
|
21
|
+
|
22
|
+
if self.action
|
23
|
+
send self.action
|
24
|
+
else
|
25
|
+
self.show_usage
|
26
|
+
exit 1
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def option_parser!(argv)
|
31
|
+
@option_parser ||= OptionParser.new do |opts|
|
32
|
+
opts.banner = "Usage: #{File.basename($0)} [options] action ..."
|
33
|
+
|
34
|
+
opts.on("-V", "--version", "Display the Backsum version and exit.") do
|
35
|
+
self.action = :show_version
|
36
|
+
end
|
37
|
+
|
38
|
+
opts.on("--all[=PATH]", "excute all the files. default: '#{self.options[:projects_path]}'") do |path|
|
39
|
+
self.options[:projects_path] = path if path
|
40
|
+
self.action = :perform_by_dir
|
41
|
+
end
|
42
|
+
|
43
|
+
opts.on("-v", "--[no-]verbose", "increase verbosity. default: #{Backsum.verbose}") do |value|
|
44
|
+
Backsum.verbose = value
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
@option_parser.parse!(argv)
|
49
|
+
|
50
|
+
if !self.action && argv.any?
|
51
|
+
self.action = :perform_by_inputs
|
52
|
+
@input_files = argv
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def show_usage
|
57
|
+
stderr "Please specify one action to execute."
|
58
|
+
stderr @option_parser.help
|
59
|
+
end
|
60
|
+
|
61
|
+
def show_version
|
62
|
+
stdout "Backsum v#{Backsum::VERSION}"
|
63
|
+
end
|
64
|
+
|
65
|
+
def perform_by_dir
|
66
|
+
files = Dir[File.join(self.options[:projects_path], '*.rb')]
|
67
|
+
perform_files(files)
|
68
|
+
end
|
69
|
+
|
70
|
+
def perform_by_inputs
|
71
|
+
perform_files(@input_files)
|
72
|
+
end
|
73
|
+
|
74
|
+
protected
|
75
|
+
def perform_files(files)
|
76
|
+
files.each do |file|
|
77
|
+
if !File.exist?(file)
|
78
|
+
stderr "#{file} is not exist!"
|
79
|
+
exit 1
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
files.each do |file|
|
84
|
+
project = Backsum::Project.dsl(File.read(file), file)
|
85
|
+
project.perform
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def stdout(*args)
|
90
|
+
$stdout.puts(*args)
|
91
|
+
end
|
92
|
+
|
93
|
+
def stderr(*args)
|
94
|
+
$stderr.puts(*args)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require_relative "../backsum"
|
2
|
+
require_relative 'server'
|
3
|
+
require_relative 'backup'
|
4
|
+
require_relative 'shell'
|
5
|
+
|
6
|
+
require "fileutils"
|
7
|
+
require "virtus"
|
8
|
+
|
9
|
+
module Backsum
|
10
|
+
class Project
|
11
|
+
include Virtus.model
|
12
|
+
LATEST_LINK_NAME = "Latest"
|
13
|
+
|
14
|
+
attribute :name
|
15
|
+
attribute :servers
|
16
|
+
attribute :keep_days
|
17
|
+
attribute :keep_weeks
|
18
|
+
attribute :backup_to
|
19
|
+
|
20
|
+
def initialize(*args)
|
21
|
+
self.keep_days = 3
|
22
|
+
self.keep_weeks = 4
|
23
|
+
self.name = "default"
|
24
|
+
self.backup_to = Proc.new { "./backups/#{name}" }
|
25
|
+
self.servers = []
|
26
|
+
super
|
27
|
+
end
|
28
|
+
|
29
|
+
def backup_to
|
30
|
+
@backup_to.respond_to?(:call) ? instance_eval(&@backup_to) : @backup_to.to_s
|
31
|
+
end
|
32
|
+
|
33
|
+
def perform
|
34
|
+
build_target_backup_folder # prepare
|
35
|
+
sync_servers_data # execute
|
36
|
+
cleanup_outdate_backups # cleanup
|
37
|
+
end
|
38
|
+
|
39
|
+
def build_target_backup_folder
|
40
|
+
FileUtils.mkdir_p(self.backup_to)
|
41
|
+
FileUtils.mkdir_p(self.current_backup.path) if !self.latest_backup
|
42
|
+
end
|
43
|
+
|
44
|
+
def sync_servers_data
|
45
|
+
lastest_backup_path = self.latest_backup.path if self.latest_backup
|
46
|
+
|
47
|
+
self.servers.each do |server|
|
48
|
+
server.sync self.current_backup.path, lastest_backup_path
|
49
|
+
end
|
50
|
+
|
51
|
+
Dir.chdir self.backup_to do
|
52
|
+
FileUtils.rm_rf LATEST_LINK_NAME
|
53
|
+
FileUtils.ln_sf self.current_backup.name, LATEST_LINK_NAME
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def current_backup
|
58
|
+
@current_backup ||= Backup.new(backup_at: DateTime.now, base_dir: self.backup_to)
|
59
|
+
end
|
60
|
+
|
61
|
+
def latest_backup
|
62
|
+
path = File.join(self.backup_to, LATEST_LINK_NAME)
|
63
|
+
if File.exists?(path)
|
64
|
+
real_path = File.readlink(path)
|
65
|
+
Backup.new(name: File.basename(real_path), base_dir: self.backup_to)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def backups
|
70
|
+
self.backup_names.map { |backup_name| Backup.new(name: backup_name, base_dir: self.backup_to) }
|
71
|
+
end
|
72
|
+
|
73
|
+
def backup_names
|
74
|
+
Dir[File.join(self.backup_to, "*")].map do |backup_path|
|
75
|
+
next if File.basename(backup_path) == LATEST_LINK_NAME
|
76
|
+
File.basename(backup_path)
|
77
|
+
end.compact
|
78
|
+
end
|
79
|
+
|
80
|
+
def latest_link_name
|
81
|
+
LATEST_LINK_NAME
|
82
|
+
end
|
83
|
+
|
84
|
+
def cleanup_outdate_backups
|
85
|
+
backups = self.backups
|
86
|
+
|
87
|
+
backups.each { |b| b.outdated = true }
|
88
|
+
|
89
|
+
# keep weekly backups
|
90
|
+
cweeks_mapping = backups.group_by(&:cweek)
|
91
|
+
cweeks_mapping.keys.sort.reverse.slice(0, self.keep_weeks).each do |cweek|
|
92
|
+
cweeks_mapping[cweek].sort.last.outdated = false
|
93
|
+
end
|
94
|
+
|
95
|
+
# keep daily backups
|
96
|
+
days_mapping = backups.group_by(&:day)
|
97
|
+
days_mapping.keys.sort.reverse.slice(0, self.keep_days).each do |day|
|
98
|
+
days_mapping[day].sort.last.outdated = false
|
99
|
+
end
|
100
|
+
|
101
|
+
# keep latest backup
|
102
|
+
# skip, already keep by daily
|
103
|
+
|
104
|
+
backups.each do |backup|
|
105
|
+
FileUtils.rm_rf(backup.path) if backup.outdated?
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require_relative 'project'
|
2
|
+
require_relative 'server'
|
3
|
+
|
4
|
+
module Backsum
|
5
|
+
class Project
|
6
|
+
|
7
|
+
def self.dsl(*args, &block)
|
8
|
+
Dsl.new(*args, &block).instance
|
9
|
+
end
|
10
|
+
|
11
|
+
class Dsl
|
12
|
+
attr_accessor :instance
|
13
|
+
|
14
|
+
def initialize(content = nil, filename = nil, lineno = 0, &block)
|
15
|
+
self.instance = Project.new
|
16
|
+
self.instance.name = File.basename(filename, ".rb") if filename
|
17
|
+
|
18
|
+
instance_eval(content, filename, lineno) if content
|
19
|
+
instance_eval(&block) if block
|
20
|
+
end
|
21
|
+
|
22
|
+
def name(name)
|
23
|
+
self.instance.name = name
|
24
|
+
end
|
25
|
+
|
26
|
+
def server(*args, &block)
|
27
|
+
server = Server::Dsl.new(*args, &block).instance
|
28
|
+
self.instance.servers << server
|
29
|
+
end
|
30
|
+
|
31
|
+
def keep_days(days)
|
32
|
+
self.instance.keep_days = days
|
33
|
+
end
|
34
|
+
|
35
|
+
def keep_weeks(weeks)
|
36
|
+
self.instance.keep_weeks = weeks
|
37
|
+
end
|
38
|
+
|
39
|
+
def backup_to(path)
|
40
|
+
self.instance.backup_to = path
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require_relative "../backsum"
|
2
|
+
require_relative 'shell'
|
3
|
+
|
4
|
+
require "virtus"
|
5
|
+
require "fileutils"
|
6
|
+
require "shellwords"
|
7
|
+
|
8
|
+
module Backsum
|
9
|
+
class Server
|
10
|
+
include Virtus.model
|
11
|
+
|
12
|
+
attribute :host
|
13
|
+
attribute :username
|
14
|
+
attribute :local
|
15
|
+
attribute :folders, Hash
|
16
|
+
|
17
|
+
def connect
|
18
|
+
return nil if local
|
19
|
+
username ? "#{username}@#{host}" : host if host
|
20
|
+
end
|
21
|
+
|
22
|
+
def sync(backup_path, linkdest_path)
|
23
|
+
self.folders.each_pair do |folder, options|
|
24
|
+
execute_rsync(backup_path, linkdest_path, connect, folder, options)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def execute_rsync(backup_path, linkdest_path, connect, source, options)
|
29
|
+
arguments = [ "--archive", "--delete" ]
|
30
|
+
target_path = File.join(backup_path, self.host)
|
31
|
+
arguments << "--verbose" if Backsum.verbose
|
32
|
+
|
33
|
+
if linkdest_path
|
34
|
+
linkdest_abosulte_path = File.absolute_path(linkdest_path) # rsync link dest must be abosulte path.
|
35
|
+
linkdest_dir = File.join([linkdest_abosulte_path, self.host, options[:as], "/"].compact)
|
36
|
+
arguments << "--link-dest=#{linkdest_dir}" if File.exists?(linkdest_dir)
|
37
|
+
end
|
38
|
+
|
39
|
+
if options[:as]
|
40
|
+
target_path = File.join(target_path, options[:as])
|
41
|
+
else
|
42
|
+
arguments << "--relative"
|
43
|
+
end
|
44
|
+
|
45
|
+
FileUtils.mkdir_p target_path
|
46
|
+
|
47
|
+
(options[:excluded] || []).each do |pattern|
|
48
|
+
arguments << "--exclude=#{pattern}"
|
49
|
+
end
|
50
|
+
|
51
|
+
source = File.join(source, "/") if File.directory?(source)
|
52
|
+
if connect
|
53
|
+
arguments << "#{connect}:#{source}"
|
54
|
+
else
|
55
|
+
arguments << source
|
56
|
+
end
|
57
|
+
|
58
|
+
arguments << target_path
|
59
|
+
|
60
|
+
copy_command = Shell.new("rsync", arguments.map {|arg| shell_param_escape(arg) }.join(' '))
|
61
|
+
copy_command.run
|
62
|
+
end
|
63
|
+
|
64
|
+
def shell_param_escape(str)
|
65
|
+
if str.include? " "
|
66
|
+
"'" + str.gsub("'", "\\'") + "'"
|
67
|
+
else
|
68
|
+
str
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class Dsl
|
73
|
+
attr_accessor :instance
|
74
|
+
|
75
|
+
def initialize(host, options = {}, &block)
|
76
|
+
self.instance = Server.new
|
77
|
+
self.instance.host = host
|
78
|
+
self.instance.local = options[:local]
|
79
|
+
self.instance.username = options[:username]
|
80
|
+
|
81
|
+
instance_eval(&block) if block
|
82
|
+
end
|
83
|
+
|
84
|
+
def folder(path, options = {})
|
85
|
+
self.instance.folders[path] = options
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require_relative "../backsum"
|
2
|
+
|
3
|
+
require "cocaine"
|
4
|
+
require 'posix/spawn'
|
5
|
+
|
6
|
+
module Backsum
|
7
|
+
class Shell
|
8
|
+
def initialize(command, params = "", options = {})
|
9
|
+
options[:runner] ||= LoggablePosixRunner.new
|
10
|
+
@command_line = Cocaine::CommandLine.new(command, params, options)
|
11
|
+
end
|
12
|
+
|
13
|
+
def run(*args)
|
14
|
+
@command_line.run(*args)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class LoggablePosixRunner
|
19
|
+
def call(command, env = {})
|
20
|
+
input, output = IO.pipe
|
21
|
+
pid = spawn(env, command, :out => output)
|
22
|
+
output.close
|
23
|
+
result = ""
|
24
|
+
|
25
|
+
while line = input.readline
|
26
|
+
Backsum.logger.debug(line.chomp)
|
27
|
+
result << line
|
28
|
+
end rescue EOFError
|
29
|
+
|
30
|
+
waitpid(pid)
|
31
|
+
input.close
|
32
|
+
result
|
33
|
+
end
|
34
|
+
|
35
|
+
def spawn(*args)
|
36
|
+
::POSIX::Spawn.spawn(*args)
|
37
|
+
end
|
38
|
+
|
39
|
+
def waitpid(pid)
|
40
|
+
::Process.waitpid(pid)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
require "backsum/cli"
|
3
|
+
|
4
|
+
describe Backsum::Cli do
|
5
|
+
before(:each) do
|
6
|
+
@stdout, @stderr = capture_console_output
|
7
|
+
@fixture_dir = File.expand_path("../cli_spec", __FILE__)
|
8
|
+
@cli = Cli.new
|
9
|
+
@project = double("project")
|
10
|
+
|
11
|
+
Project.should respond_to(:dsl)
|
12
|
+
Project.stub(:dsl).with(any_args).and_return(@project)
|
13
|
+
end
|
14
|
+
|
15
|
+
after(:each) do
|
16
|
+
release_console_capture
|
17
|
+
end
|
18
|
+
|
19
|
+
it "can show corrent version" do
|
20
|
+
exit_code = run_command "-V"
|
21
|
+
exit_code.should == 0
|
22
|
+
@stdout.string.should include Backsum::VERSION
|
23
|
+
end
|
24
|
+
|
25
|
+
it "can show help with null arguments" do
|
26
|
+
exit_code = run_command
|
27
|
+
exit_code.should_not == 0
|
28
|
+
@stderr.string.should_not be_empty
|
29
|
+
end
|
30
|
+
|
31
|
+
it "have verbose option" do
|
32
|
+
exit_code = run_command "--verbose"
|
33
|
+
Backsum.verbose.should == true
|
34
|
+
Backsum.logger.level.should == Logging.level_num(:debug)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "can't recieve unexists file" do
|
38
|
+
exit_code = run_command "./unexists_file.rb"
|
39
|
+
exit_code.should_not == 0
|
40
|
+
@stderr.string.should_not be_empty
|
41
|
+
end
|
42
|
+
|
43
|
+
it "can execute perform method with existing file" do
|
44
|
+
@project.should receive(:perform).once
|
45
|
+
Dir.chdir(@fixture_dir) do
|
46
|
+
exit_code = run_command "all-projects/uat.rb"
|
47
|
+
exit_code.should == 0
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
it "the argument '--all' have default value" do
|
53
|
+
Dir.chdir(@fixture_dir) do
|
54
|
+
exit_code = run_command "--all"
|
55
|
+
end
|
56
|
+
@cli.options[:projects_path].should == "./projects"
|
57
|
+
end
|
58
|
+
|
59
|
+
it "can execute command with option --all" do
|
60
|
+
@project.should receive(:perform).twice
|
61
|
+
Dir.chdir(@fixture_dir) do
|
62
|
+
exit_code = run_command "--all=./all-projects"
|
63
|
+
exit_code.should == 0
|
64
|
+
end
|
65
|
+
|
66
|
+
@cli.options[:projects_path].should == "./all-projects"
|
67
|
+
end
|
68
|
+
|
69
|
+
it "can ignore FILE argument if have argument: '--all'" do
|
70
|
+
@project.should receive(:perform).twice
|
71
|
+
Dir.chdir(@fixture_dir) do
|
72
|
+
exit_code = run_command "--all=./all-projects" , "./ignore_file.rb"
|
73
|
+
exit_code.should == 0
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
protected
|
78
|
+
def run_command(*argv)
|
79
|
+
begin
|
80
|
+
@cli.execute(argv)
|
81
|
+
return 0
|
82
|
+
rescue SystemExit => e
|
83
|
+
return e.status
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def capture_console_output(&block)
|
88
|
+
@capture_console_output_start = true
|
89
|
+
@origin_stdout = $stdout
|
90
|
+
@origin_stderr = $stderr
|
91
|
+
|
92
|
+
stdout = StringIO.new
|
93
|
+
stderr = StringIO.new
|
94
|
+
|
95
|
+
$stdout = stdout
|
96
|
+
$stderr = stderr
|
97
|
+
|
98
|
+
if block_given?
|
99
|
+
begin
|
100
|
+
result = yield
|
101
|
+
[ stdout, stderr, result ]
|
102
|
+
ensure
|
103
|
+
release_console_capture
|
104
|
+
end
|
105
|
+
else
|
106
|
+
[ stdout, stderr ]
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def release_console_capture
|
111
|
+
if @capture_console_output_start
|
112
|
+
$stdout = @origin_stdout
|
113
|
+
$stderr = @origin_stderr
|
114
|
+
@capture_console_output_start = false
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
require "backsum/project_dsl"
|
3
|
+
|
4
|
+
describe Backsum::Project do
|
5
|
+
|
6
|
+
it "can create instance by dsl block" do
|
7
|
+
project = Backsum::Project::Dsl.new do
|
8
|
+
name "github.com"
|
9
|
+
end.instance
|
10
|
+
|
11
|
+
project.name.should == "github.com"
|
12
|
+
end
|
13
|
+
|
14
|
+
it "can create instance by dsl file" do
|
15
|
+
dsl = Backsum::Project::Dsl.new <<-end_eval, __FILE__, __LINE__
|
16
|
+
name "ooxx"
|
17
|
+
end_eval
|
18
|
+
|
19
|
+
dsl.instance.name.should == "ooxx"
|
20
|
+
end
|
21
|
+
|
22
|
+
it "can append a server" do
|
23
|
+
project = Backsum::Project::Dsl.new do
|
24
|
+
server "bstar-pro-uat", username: "root" do
|
25
|
+
end
|
26
|
+
end.instance
|
27
|
+
|
28
|
+
project.servers.size.should == 1
|
29
|
+
project.servers.first.should be_a Backsum::Server
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
it "can set default project name by config file basename" do
|
34
|
+
dsl = Backsum::Project::Dsl.new nil, "./projects/bak_balm.rb"
|
35
|
+
dsl.instance.name.should == "bak_balm"
|
36
|
+
end
|
37
|
+
|
38
|
+
it "can set default backup properties" do
|
39
|
+
dsl = Backsum::Project::Dsl.new nil, "./projects/bak_balm.rb"
|
40
|
+
|
41
|
+
dsl.instance.keep_days.should == 3
|
42
|
+
dsl.instance.keep_weeks.should == 4
|
43
|
+
dsl.instance.backup_to.should == "./backups/bak_balm"
|
44
|
+
end
|
45
|
+
|
46
|
+
it "can override default backup properties" do
|
47
|
+
dsl = Backsum::Project::Dsl.new do
|
48
|
+
keep_days 5
|
49
|
+
keep_weeks 8
|
50
|
+
backup_to "./baks/foo"
|
51
|
+
end
|
52
|
+
|
53
|
+
dsl.instance.keep_days.should == 5
|
54
|
+
dsl.instance.keep_weeks.should == 8
|
55
|
+
dsl.instance.backup_to.should == "./baks/foo"
|
56
|
+
end
|
57
|
+
|
58
|
+
it "can synchronize backup_to with project name" do
|
59
|
+
dsl = Backsum::Project::Dsl.new do
|
60
|
+
name "oox"
|
61
|
+
end
|
62
|
+
|
63
|
+
dsl.instance.backup_to.should == "./backups/oox"
|
64
|
+
end
|
65
|
+
|
66
|
+
it "can initial a Project::Dsl instance" do
|
67
|
+
project = Project.dsl
|
68
|
+
project.should be_a Project
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
require "backsum/project"
|
3
|
+
require "pathname"
|
4
|
+
|
5
|
+
describe Project do
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
@fixture_dir = Pathname.new("../project_spec").expand_path(__FILE__)
|
9
|
+
@autoremove_files = []
|
10
|
+
end
|
11
|
+
|
12
|
+
after(:each) do
|
13
|
+
@autoremove_files.each do |file|
|
14
|
+
FileUtils.rm_rf(file) if File.exist?(file)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
it "can build new target backup folders at first time" do
|
19
|
+
first_backup_dir = fixture_temp_dir("first_time")
|
20
|
+
|
21
|
+
project = Project.new(backup_to: first_backup_dir.to_s)
|
22
|
+
project.build_target_backup_folder
|
23
|
+
|
24
|
+
first_backup_dir.should be_exist
|
25
|
+
end
|
26
|
+
|
27
|
+
it "can cleanup outdated daily backups" do
|
28
|
+
deploy_dir = fixture_temp_dir("daliy_cleanup")
|
29
|
+
backup_names = {
|
30
|
+
"20131008T230000" => false,
|
31
|
+
"20131009T220000" => false,
|
32
|
+
"20131009T230000" => true,
|
33
|
+
"20131010T220000" => false,
|
34
|
+
"20131010T230000" => true
|
35
|
+
}.each_pair do |datetime, result|
|
36
|
+
FileUtils.mkdir_p deploy_dir.join(datetime)
|
37
|
+
end
|
38
|
+
|
39
|
+
project = Project.new(backup_to: deploy_dir, keep_days: 2, keep_weeks: 0)
|
40
|
+
project.cleanup_outdate_backups
|
41
|
+
|
42
|
+
backup_names.each_pair do |backup_name, result|
|
43
|
+
deploy_dir.join(backup_name).exist?.should eq(result), backup_name
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
it "can cleanup outdated weekly backups" do
|
48
|
+
deploy_dir = fixture_temp_dir("daliy_cleanup")
|
49
|
+
backup_names = {
|
50
|
+
"20131006T000000" => false, # sun
|
51
|
+
"20131009T000000" => false,
|
52
|
+
"20131013T000000" => true, # sun
|
53
|
+
"20131014T000000" => false, # mon
|
54
|
+
"20131020T000000" => true # sun
|
55
|
+
}.each_pair do |datetime, result|
|
56
|
+
FileUtils.mkdir_p deploy_dir.join(datetime)
|
57
|
+
end
|
58
|
+
|
59
|
+
project = Project.new(backup_to: deploy_dir, keep_days: 0, keep_weeks: 2)
|
60
|
+
project.cleanup_outdate_backups
|
61
|
+
|
62
|
+
backup_names.each_pair do |backup_name, result|
|
63
|
+
deploy_dir.join(backup_name).exist?.should == result
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
it "can regenerate sysmbol link after sync server" do
|
68
|
+
third_backup_dir = fixture_temp_dir("third_time")
|
69
|
+
backup_name = "20131020T153839"
|
70
|
+
project = Project.new(backup_to: @fixture_dir.join("third_time"))
|
71
|
+
|
72
|
+
FileUtils.mkdir_p File.join(project.backup_to, backup_name)
|
73
|
+
project.current_backup.name = backup_name
|
74
|
+
project.sync_servers_data
|
75
|
+
|
76
|
+
File.readlink(File.join(project.backup_to, project.latest_link_name)).should == backup_name
|
77
|
+
end
|
78
|
+
|
79
|
+
def fixture_temp_dir(*basenames)
|
80
|
+
path = @fixture_dir.join(*basenames)
|
81
|
+
path.should_not be_exist
|
82
|
+
@autoremove_files << path
|
83
|
+
path
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
File without changes
|
File without changes
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
require "backsum/server"
|
3
|
+
require "pathname"
|
4
|
+
|
5
|
+
describe Server do
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
@fixture_dir = Pathname.new("../server_spec").expand_path(__FILE__)
|
9
|
+
@autoremove_files = []
|
10
|
+
end
|
11
|
+
|
12
|
+
after(:each) do
|
13
|
+
@autoremove_files.each do |file|
|
14
|
+
FileUtils.rm_rf(file) if File.exist?(file)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
it "can create instance by dsl block" do
|
19
|
+
server = Server::Dsl.new "localhost", username: "root" do
|
20
|
+
folder "/balm/shared", excluded: [ "logs" ]
|
21
|
+
folder "/balm-games/shared"
|
22
|
+
end.instance
|
23
|
+
|
24
|
+
server.host.should == "localhost"
|
25
|
+
server.username.should == "root"
|
26
|
+
server.folders.size.should == 2
|
27
|
+
server.folders["/balm/shared"].should == {:excluded => ["logs"]}
|
28
|
+
server.folders["/balm-games/shared"].should == {}
|
29
|
+
end
|
30
|
+
|
31
|
+
it "can sync folder from localhost" do
|
32
|
+
source_dir = @fixture_dir.join("source_first/")
|
33
|
+
target_dir = @fixture_dir.join("target_first/")
|
34
|
+
@autoremove_files << target_dir.to_s
|
35
|
+
|
36
|
+
server = Server::Dsl.new "localhost", local: true do
|
37
|
+
folder source_dir.to_s, excluded: [ "folder2" ]
|
38
|
+
end.instance
|
39
|
+
server.sync target_dir.to_s, nil
|
40
|
+
source_relative_dir = source_dir.relative_path_from(Pathname.new("/"))
|
41
|
+
target_dir.join(server.host, source_relative_dir, "folder1").should be_exist
|
42
|
+
target_dir.join(server.host, source_relative_dir, "folder2").should_not be_exist
|
43
|
+
end
|
44
|
+
|
45
|
+
it "can sync folder from localhost incrementally" do
|
46
|
+
source_dir = @fixture_dir.join("source_increment")
|
47
|
+
target_dir = @fixture_dir.join("target_increment")
|
48
|
+
linkdest_dir = @fixture_dir.join("target_increment_latest")
|
49
|
+
linkdest_path = "./spec/lib/backsum/server_spec/target_increment_latest"
|
50
|
+
@autoremove_files << target_dir.to_s
|
51
|
+
|
52
|
+
server = Server::Dsl.new "localhost", local: true do
|
53
|
+
folder source_dir.to_s #, as: "folder1"
|
54
|
+
end.instance
|
55
|
+
|
56
|
+
server.sync target_dir.to_s, linkdest_path
|
57
|
+
|
58
|
+
target_dir.join(server.host, "folder1", "file1").should be_exist
|
59
|
+
File.identical?(target_dir.join(server.host, "folder1", "file1"), linkdest_dir.join(server.host, "folder1", "file1")).should be_true
|
60
|
+
target_dir.join(server.host, "folder1", "file2").should be_exist
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
2
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
3
|
+
# Require this file using `require "spec_helper"` to ensure that it is only
|
4
|
+
# loaded once.
|
5
|
+
#
|
6
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
7
|
+
require "pry-nav"
|
8
|
+
require 'simplecov'
|
9
|
+
SimpleCov.start
|
10
|
+
|
11
|
+
module Backsum; end
|
12
|
+
include Backsum
|
13
|
+
|
14
|
+
RSpec.configure do |config|
|
15
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
16
|
+
config.run_all_when_everything_filtered = true
|
17
|
+
# config.filter_run :focus
|
18
|
+
|
19
|
+
# Run specs in random order to surface order dependencies. If you find an
|
20
|
+
# order dependency and want to debug it, you can fix the order by providing
|
21
|
+
# the seed, which is printed after each run.
|
22
|
+
# --seed 1234
|
23
|
+
config.order = 'random'
|
24
|
+
end
|
metadata
ADDED
@@ -0,0 +1,249 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: backsum
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- sunteya
|
8
|
+
- jyfcrw
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-10-30 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: cocaine
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ~>
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: 0.5.2
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ~>
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: 0.5.2
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: posix-spawn
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ~>
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 0.3.6
|
35
|
+
type: :runtime
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ~>
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: 0.3.6
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: virtus
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ~>
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: 1.0.0
|
49
|
+
type: :runtime
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ~>
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: 1.0.0
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: activesupport
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: 3.0.0
|
63
|
+
type: :runtime
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 3.0.0
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: logging
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ~>
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: 1.6.2
|
77
|
+
type: :runtime
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ~>
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: 1.6.2
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: bundler
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ~>
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '1.3'
|
91
|
+
type: :development
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ~>
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '1.3'
|
98
|
+
- !ruby/object:Gem::Dependency
|
99
|
+
name: rake
|
100
|
+
requirement: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - '>='
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
type: :development
|
106
|
+
prerelease: false
|
107
|
+
version_requirements: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - '>='
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
- !ruby/object:Gem::Dependency
|
113
|
+
name: pry-nav
|
114
|
+
requirement: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - '>='
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
type: :development
|
120
|
+
prerelease: false
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: rspec
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - ~>
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: 2.14.1
|
133
|
+
type: :development
|
134
|
+
prerelease: false
|
135
|
+
version_requirements: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - ~>
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: 2.14.1
|
140
|
+
- !ruby/object:Gem::Dependency
|
141
|
+
name: simplecov
|
142
|
+
requirement: !ruby/object:Gem::Requirement
|
143
|
+
requirements:
|
144
|
+
- - ~>
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
version: 0.7.1
|
147
|
+
type: :development
|
148
|
+
prerelease: false
|
149
|
+
version_requirements: !ruby/object:Gem::Requirement
|
150
|
+
requirements:
|
151
|
+
- - ~>
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: 0.7.1
|
154
|
+
- !ruby/object:Gem::Dependency
|
155
|
+
name: guard-rspec
|
156
|
+
requirement: !ruby/object:Gem::Requirement
|
157
|
+
requirements:
|
158
|
+
- - ~>
|
159
|
+
- !ruby/object:Gem::Version
|
160
|
+
version: 4.0.3
|
161
|
+
type: :development
|
162
|
+
prerelease: false
|
163
|
+
version_requirements: !ruby/object:Gem::Requirement
|
164
|
+
requirements:
|
165
|
+
- - ~>
|
166
|
+
- !ruby/object:Gem::Version
|
167
|
+
version: 4.0.3
|
168
|
+
description: backsum is unix base the file system backup tools, it will incremental
|
169
|
+
backup remote file to local storage.
|
170
|
+
email:
|
171
|
+
- sunteya@gmail.com
|
172
|
+
- jyfcrw@gmail.com
|
173
|
+
executables:
|
174
|
+
- backsum
|
175
|
+
extensions: []
|
176
|
+
extra_rdoc_files: []
|
177
|
+
files:
|
178
|
+
- .gitignore
|
179
|
+
- .rspec
|
180
|
+
- Gemfile
|
181
|
+
- Guardfile
|
182
|
+
- LICENSE.txt
|
183
|
+
- README.md
|
184
|
+
- Rakefile
|
185
|
+
- backsum.gemspec
|
186
|
+
- bin/backsum
|
187
|
+
- lib/backsum.rb
|
188
|
+
- lib/backsum/backup.rb
|
189
|
+
- lib/backsum/cli.rb
|
190
|
+
- lib/backsum/project.rb
|
191
|
+
- lib/backsum/project_dsl.rb
|
192
|
+
- lib/backsum/server.rb
|
193
|
+
- lib/backsum/shell.rb
|
194
|
+
- lib/backsum/version.rb
|
195
|
+
- spec/lib/backsum/cli_spec.rb
|
196
|
+
- spec/lib/backsum/cli_spec/all-projects/mh.rb
|
197
|
+
- spec/lib/backsum/cli_spec/all-projects/uat.rb
|
198
|
+
- spec/lib/backsum/project_dsl_spec.rb
|
199
|
+
- spec/lib/backsum/project_spec.rb
|
200
|
+
- spec/lib/backsum/project_spec/second_time/20131020T153839/host1/file1
|
201
|
+
- spec/lib/backsum/project_spec/second_time/20131020T153839/host2/file2
|
202
|
+
- spec/lib/backsum/server_spec.rb
|
203
|
+
- spec/lib/backsum/server_spec/source_first/folder1/file1
|
204
|
+
- spec/lib/backsum/server_spec/source_first/folder2/file2
|
205
|
+
- spec/lib/backsum/server_spec/source_increment/file1
|
206
|
+
- spec/lib/backsum/server_spec/source_increment/file2
|
207
|
+
- spec/lib/backsum/server_spec/target_increment_latest/localhost/folder1/file1
|
208
|
+
- spec/lib/backsum_spec.rb
|
209
|
+
- spec/spec_helper.rb
|
210
|
+
homepage: https://github.com/sunteya/backsum
|
211
|
+
licenses:
|
212
|
+
- MIT
|
213
|
+
metadata: {}
|
214
|
+
post_install_message:
|
215
|
+
rdoc_options: []
|
216
|
+
require_paths:
|
217
|
+
- lib
|
218
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
219
|
+
requirements:
|
220
|
+
- - '>='
|
221
|
+
- !ruby/object:Gem::Version
|
222
|
+
version: '0'
|
223
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
224
|
+
requirements:
|
225
|
+
- - '>='
|
226
|
+
- !ruby/object:Gem::Version
|
227
|
+
version: '0'
|
228
|
+
requirements: []
|
229
|
+
rubyforge_project:
|
230
|
+
rubygems_version: 2.0.3
|
231
|
+
signing_key:
|
232
|
+
specification_version: 4
|
233
|
+
summary: remote incremental backup tools
|
234
|
+
test_files:
|
235
|
+
- spec/lib/backsum/cli_spec.rb
|
236
|
+
- spec/lib/backsum/cli_spec/all-projects/mh.rb
|
237
|
+
- spec/lib/backsum/cli_spec/all-projects/uat.rb
|
238
|
+
- spec/lib/backsum/project_dsl_spec.rb
|
239
|
+
- spec/lib/backsum/project_spec.rb
|
240
|
+
- spec/lib/backsum/project_spec/second_time/20131020T153839/host1/file1
|
241
|
+
- spec/lib/backsum/project_spec/second_time/20131020T153839/host2/file2
|
242
|
+
- spec/lib/backsum/server_spec.rb
|
243
|
+
- spec/lib/backsum/server_spec/source_first/folder1/file1
|
244
|
+
- spec/lib/backsum/server_spec/source_first/folder2/file2
|
245
|
+
- spec/lib/backsum/server_spec/source_increment/file1
|
246
|
+
- spec/lib/backsum/server_spec/source_increment/file2
|
247
|
+
- spec/lib/backsum/server_spec/target_increment_latest/localhost/folder1/file1
|
248
|
+
- spec/lib/backsum_spec.rb
|
249
|
+
- spec/spec_helper.rb
|