backsum 0.0.1
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.
- 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
|