backup_demon 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 +15 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +16 -0
- data/backup_demon.gemspec +24 -0
- data/bin/backup_demon +5 -0
- data/lib/backup_demon/cli.rb +68 -0
- data/lib/backup_demon/config.rb +39 -0
- data/lib/backup_demon/core_ext/hash.rb +12 -0
- data/lib/backup_demon/daemon.rb +42 -0
- data/lib/backup_demon/device.rb +61 -0
- data/lib/backup_demon/sync.rb +8 -0
- data/lib/backup_demon/version.rb +3 -0
- data/lib/backup_demon.rb +22 -0
- metadata +71 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
Y2M0Nzk4YzkwOGI1OWVkZmVjNzFlMmQ1NDMwOGY3YTJlMmFkZTE4OA==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
ZDViNGE3NzcyN2MwMTE1MTcwZTgxYzU4MzFiZjA4NTVmODg5YmI1NA==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
Y2E0YTljNGFiYzMwZmU3MzNkYTU3OWQ1YmE5YWE2ZmM5MmVjMTYxZGUwMTlh
|
10
|
+
OWU3ZTIzOTBhNTBkYTk1Yzk2N2VmZjYzZDEwODU5NWU4ZGZjNThhZWE2ZDY1
|
11
|
+
ZDU1NDcxMDFhOGM4YmZiN2RkOGFlZDE2Njk5NDEzOTUyYmRhYWU=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ZGFlNTgzNzkzOGRlYjAxMjQ5NzAxMDdlZDdmMjRhYmMzMGQ4YWY1NjJiMmFi
|
14
|
+
YzdmNWFjODgxMjM5MjAwMWJiMTc2ZDRlYjdhMDk2ZjE2MGUwMjViNWNkZDdl
|
15
|
+
NWEyYzBhOGFlODU5ZGY2YzIxN2FiNTg2MGVkMjZmNWE2NTFkNWQ=
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
$LOAD_PATH.unshift 'lib'
|
2
|
+
require 'backup_demon/version'
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "backup_demon"
|
6
|
+
s.version = BackupDemon::Version
|
7
|
+
s.summary = "BackupDemon backs up to external drives"
|
8
|
+
s.homepage = "https://github.com/ryanfaerman"
|
9
|
+
s.email = ["ry@nwitty.com"]
|
10
|
+
s.authors = ["Ryan Faerman"]
|
11
|
+
|
12
|
+
s.files = `git ls-files`.split($/).reject{ |f| f =~ /^examples/ }
|
13
|
+
s.executables = s.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
14
|
+
# s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
15
|
+
s.require_paths = ["lib"]
|
16
|
+
|
17
|
+
# s.extra_rdoc_files = [ "LICENSE.txt", "CHANGELOG.md", "README.md", "CONTRIBUTING.md" ]
|
18
|
+
# s.rdoc_options = ["--charset=UTF-8"]
|
19
|
+
|
20
|
+
s.add_dependency "thor", "~> 0.18"
|
21
|
+
|
22
|
+
s.description = %s{
|
23
|
+
BackupDemon is a daemon for backing up directories to an external drive}
|
24
|
+
end
|
data/bin/backup_demon
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'backup_demon'
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
module BackupDemon
|
6
|
+
class CLI < Thor
|
7
|
+
|
8
|
+
class_option :config, :aliases => ["-c"], :type => :string
|
9
|
+
|
10
|
+
desc "start", "run the BackupDemon Daemon"
|
11
|
+
option :daemon, aliases: ["-d"], type: :boolean, default: false
|
12
|
+
option :interval, aliases: ["-i"], type: :numeric
|
13
|
+
option :pid, aliases: ["-p"], type: :string
|
14
|
+
option :device, aliases: ["-s"], type: :string
|
15
|
+
option :mount, aliases: ["-m"], type: :string
|
16
|
+
option :directories, type: :string
|
17
|
+
|
18
|
+
def start(directories = nil)
|
19
|
+
load_config
|
20
|
+
|
21
|
+
directories = directories.to_s.split(',').map(&:strip) unless directories.nil?
|
22
|
+
|
23
|
+
daemon = BackupDemon::Daemon.new(
|
24
|
+
directories || BackupDemon.config.directories,
|
25
|
+
BackupDemon.config.device,
|
26
|
+
BackupDemon.config.mount
|
27
|
+
)
|
28
|
+
|
29
|
+
if BackupDemon.config.daemon
|
30
|
+
Process.daemon(true)
|
31
|
+
end
|
32
|
+
|
33
|
+
if BackupDemon.config.pid
|
34
|
+
File.open(BackupDemon.config.pid, 'w') { |f| f << daemon.pid }
|
35
|
+
end
|
36
|
+
|
37
|
+
daemon.run!(BackupDemon.config.interval)
|
38
|
+
end
|
39
|
+
|
40
|
+
desc "stop", "stop the BackupDemon Daemon"
|
41
|
+
option :pid, aliases: ["-p"], type: :string
|
42
|
+
def stop(pid = nil)
|
43
|
+
load_config
|
44
|
+
pidfile = BackupDemon.config.pid
|
45
|
+
|
46
|
+
if pidfile && File.exists?(pidfile)
|
47
|
+
File.foreach(pidfile) do |pid|
|
48
|
+
begin
|
49
|
+
Process.kill("KILL", pid.to_i)
|
50
|
+
rescue
|
51
|
+
puts "Nothing to stop"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
protected
|
58
|
+
def load_config
|
59
|
+
opts = {}
|
60
|
+
if options[:config]
|
61
|
+
opts = YAML.load_file(File.expand_path(options[:config]))
|
62
|
+
end
|
63
|
+
|
64
|
+
BackupDemon.config = opts.merge!(options)
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require "ostruct"
|
2
|
+
require "backup_demon/core_ext/hash"
|
3
|
+
|
4
|
+
module BackupDemon
|
5
|
+
class Config
|
6
|
+
attr_accessor :options
|
7
|
+
|
8
|
+
def initialize(options = {})
|
9
|
+
@options = {
|
10
|
+
daemon: false,
|
11
|
+
interval: 5,
|
12
|
+
pid: nil,
|
13
|
+
device: "/dev/sdb1",
|
14
|
+
mount: "/mnt/backuphdd",
|
15
|
+
directories: ""
|
16
|
+
}.merge!(options.symbolize_keys!)
|
17
|
+
end
|
18
|
+
|
19
|
+
def timeout
|
20
|
+
@options[:timeout].to_f
|
21
|
+
end
|
22
|
+
|
23
|
+
def interval
|
24
|
+
@options[:interval].to_f
|
25
|
+
end
|
26
|
+
|
27
|
+
def directories
|
28
|
+
@options[:directories]
|
29
|
+
end
|
30
|
+
|
31
|
+
def method_missing(name)
|
32
|
+
name = name.to_sym
|
33
|
+
if @options.has_key?(name)
|
34
|
+
@options[name]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module BackupDemon
|
2
|
+
class Daemon
|
3
|
+
def initialize(directories, device_path, mount_point = "/mnt/backuphdd")
|
4
|
+
@directories = [directories].flatten
|
5
|
+
@drive = Device.new(device_path)
|
6
|
+
@mount_point = mount_point
|
7
|
+
end
|
8
|
+
|
9
|
+
def run(interval = 5.0)
|
10
|
+
interval = Float(interval)
|
11
|
+
procline 'waiting for drive...'
|
12
|
+
|
13
|
+
# puts "#{@drive.exists?} && #{@drive.different?} (#{@drive.exists? && @drive.different?})"
|
14
|
+
# puts "#{@drive.previous.inspect} != #{@drive.current.inspect} || #{@drive.current.nil?}"
|
15
|
+
if @drive.exists? && @drive.different?
|
16
|
+
procline 'Found Drive'
|
17
|
+
if @drive.mount(@mount_point)
|
18
|
+
@directories.each do |source|
|
19
|
+
procline "Backing up #{source}"
|
20
|
+
Sync.start(source, @drive.mount_point)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
Kernel.sleep(interval)
|
26
|
+
end
|
27
|
+
|
28
|
+
def run!(interval = 5.0)
|
29
|
+
loop do
|
30
|
+
run(interval)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def procline(string)
|
35
|
+
$0 = "backup-demon: #{string}"
|
36
|
+
end
|
37
|
+
|
38
|
+
def pid
|
39
|
+
@pid ||= Process.pid
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module BackupDemon
|
4
|
+
class Device
|
5
|
+
attr_reader :device, :mounted, :mount_point
|
6
|
+
def initialize(device)
|
7
|
+
@device = device
|
8
|
+
@mounted = false
|
9
|
+
@previous = nil
|
10
|
+
end
|
11
|
+
|
12
|
+
def exists?
|
13
|
+
File.exists?(@device)
|
14
|
+
end
|
15
|
+
|
16
|
+
def different?
|
17
|
+
begin
|
18
|
+
@previous != File.stat(@device)
|
19
|
+
rescue
|
20
|
+
false
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.mounted
|
25
|
+
raw_mount_list = `mount`
|
26
|
+
mount_list = {}
|
27
|
+
raw_mount_list.split("\n").each do |line|
|
28
|
+
items = line.split(' ')
|
29
|
+
mount_list[items[0]] = items[2]
|
30
|
+
end
|
31
|
+
mount_list.select { |k, v| k =~ /^\/.*/} # only real devices
|
32
|
+
end
|
33
|
+
|
34
|
+
def mount(mount_point)
|
35
|
+
@mount_point = mount_point
|
36
|
+
FileUtils.mkdir_p(@mount_point) unless File.exists?(@mount_point)
|
37
|
+
puts "mount #{@device} #{@mount_point}"
|
38
|
+
|
39
|
+
if mounted?
|
40
|
+
@previous = File.stat(@device)
|
41
|
+
true
|
42
|
+
else
|
43
|
+
false
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def mounted?
|
48
|
+
Device.mounted.keys.include?(@device)
|
49
|
+
true
|
50
|
+
end
|
51
|
+
|
52
|
+
def unmount
|
53
|
+
puts "umount #{@device}"
|
54
|
+
end
|
55
|
+
|
56
|
+
def unmounted?
|
57
|
+
!mounted?
|
58
|
+
true
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/lib/backup_demon.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'backup_demon/sync'
|
2
|
+
require 'backup_demon/device'
|
3
|
+
require 'backup_demon/daemon'
|
4
|
+
require 'backup_demon/config'
|
5
|
+
|
6
|
+
module BackupDemon
|
7
|
+
|
8
|
+
def self.config=(options = {})
|
9
|
+
@config = Config.new(options)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.config
|
13
|
+
@config ||= Config.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.configure
|
17
|
+
yield config
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
# BackupDemon::Daemon.new(['tmp/banana', 'tmp/jones'], 'tmp/device', 'tmp/mount/point').run!
|
metadata
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: backup_demon
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ryan Faerman
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-03-31 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: thor
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.18'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.18'
|
27
|
+
description: ! "\n BackupDemon is a daemon for backing up directories to an external
|
28
|
+
drive"
|
29
|
+
email:
|
30
|
+
- ry@nwitty.com
|
31
|
+
executables:
|
32
|
+
- backup_demon
|
33
|
+
extensions: []
|
34
|
+
extra_rdoc_files: []
|
35
|
+
files:
|
36
|
+
- Gemfile
|
37
|
+
- Gemfile.lock
|
38
|
+
- backup_demon.gemspec
|
39
|
+
- bin/backup_demon
|
40
|
+
- lib/backup_demon.rb
|
41
|
+
- lib/backup_demon/cli.rb
|
42
|
+
- lib/backup_demon/config.rb
|
43
|
+
- lib/backup_demon/core_ext/hash.rb
|
44
|
+
- lib/backup_demon/daemon.rb
|
45
|
+
- lib/backup_demon/device.rb
|
46
|
+
- lib/backup_demon/sync.rb
|
47
|
+
- lib/backup_demon/version.rb
|
48
|
+
homepage: https://github.com/ryanfaerman
|
49
|
+
licenses: []
|
50
|
+
metadata: {}
|
51
|
+
post_install_message:
|
52
|
+
rdoc_options: []
|
53
|
+
require_paths:
|
54
|
+
- lib
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ! '>='
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '0'
|
60
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
61
|
+
requirements:
|
62
|
+
- - ! '>='
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: '0'
|
65
|
+
requirements: []
|
66
|
+
rubyforge_project:
|
67
|
+
rubygems_version: 2.0.3
|
68
|
+
signing_key:
|
69
|
+
specification_version: 4
|
70
|
+
summary: BackupDemon backs up to external drives
|
71
|
+
test_files: []
|