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 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
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,16 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ backup_demon (0.0.1)
5
+ thor (~> 0.18)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ thor (0.18.1)
11
+
12
+ PLATFORMS
13
+ ruby
14
+
15
+ DEPENDENCIES
16
+ backup_demon!
@@ -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,5 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift 'lib'
3
+ require 'backup_demon/cli'
4
+
5
+ BackupDemon::CLI.start(ARGV)
@@ -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,12 @@
1
+ class Hash
2
+ def symbolize_keys
3
+ inject({}) do |options, (key, value)|
4
+ options[(key.to_sym rescue key) || key] = value
5
+ options
6
+ end
7
+ end
8
+
9
+ def symbolize_keys!
10
+ self.replace(self.symbolize_keys)
11
+ end
12
+ 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
@@ -0,0 +1,8 @@
1
+ module BackupDemon
2
+ class Sync
3
+ def self.start(source, destination)
4
+ puts "Syncing #{source} to #{destination}"
5
+ sleep 2
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,3 @@
1
+ module BackupDemon
2
+ Version = VERSION = '0.0.1'
3
+ end
@@ -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: []