dutiful 0.0.9 → 0.0.10

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c6accd15285afd3686ae7f9734291ed27ffd6409
4
- data.tar.gz: 180766e86e1aa148189557e706168bc16c237d4a
3
+ metadata.gz: 77661dc7c89c798e383b4866921f2d12d10e4c63
4
+ data.tar.gz: 4e7a2cc9951499ab8761dbd8547a56bd1e1f50d6
5
5
  SHA512:
6
- metadata.gz: defc3556e4b1652c792fb7a9e8a0da99d085d6c9e291e1857fe7bbc03c9902dd31243ff20636a188ca637ba0e288406574b648375dfad59e3b83d73b0ecb3217
7
- data.tar.gz: e5b1708c80fe35343b227b75141c3ef7a6627f4b54afdfe9bbf5868b293a99cddae5bfda251b843ae610f6b9f688df0daa591869498837faecb6c82325364900
6
+ metadata.gz: e3febcb417b4a94930ddad87562e7d013481848eaa2ae6f83e9a822a39a76bcdf905f7e722ab8d5fbfa80212066b1608dd6d36f6ef5e4ba6e4eae8db5601df49
7
+ data.tar.gz: 60f80377d514e640f756b942901a6f8ccd2d8fbc869d9fa5f0e69347c18f6922fce176ce9eab9a2e1279d84a4b14ccb598e2e3aa91197f9436e33cdbbfe060c5
@@ -0,0 +1,7 @@
1
+ [application]
2
+ name = 'OSX Screencapture'
3
+
4
+ [[default]]
5
+ description = 'Change where screenshots are saved to'
6
+ domain = 'com.apple.screencapture'
7
+ key = 'location'
@@ -3,8 +3,14 @@ class Dutiful::Application
3
3
  @path = path
4
4
  end
5
5
 
6
+ def defaults
7
+ return [] unless Dutiful::Config.osx?
8
+
9
+ Array(content[:default]).map { |default| Dutiful::ApplicationDefault.new default }
10
+ end
11
+
6
12
  def files
7
- content[:file].map { |file| Dutiful::ApplicationFile.new file[:path], file[:condition] }
13
+ Array(content[:file]).map { |file| Dutiful::ApplicationFile.new file[:path], file[:condition] }
8
14
  end
9
15
 
10
16
  def name
@@ -12,25 +18,19 @@ class Dutiful::Application
12
18
  end
13
19
 
14
20
  def backup(&block)
15
- sync backup_only: true, &block
21
+ (files + defaults).each do |file|
22
+ if file.exist?
23
+ yield file, file.backup if block_given?
24
+ else
25
+ yield file if block_given?
26
+ end
27
+ end
16
28
  end
17
29
 
18
30
  def restore(&block)
19
- sync restore_only: true, &block
20
- end
21
-
22
- def sync(backup_only: false, restore_only: false)
23
- files.each do |file|
24
- if file.should_sync?
25
- result = if backup_only && file.exist?
26
- Dutiful::Config.storage.backup(file)
27
- elsif restore_only && file.has_backup?
28
- Dutiful::Config.storage.restore(file)
29
- else
30
- Dutiful::Config.storage.sync(file)
31
- end
32
-
33
- yield file, result if block_given?
31
+ (files + defaults).each do |file|
32
+ if file.has_backup?
33
+ yield file, file.restore if block_given?
34
34
  else
35
35
  yield file if block_given?
36
36
  end
@@ -38,21 +38,17 @@ class Dutiful::Application
38
38
  end
39
39
 
40
40
  def exist?
41
- files.any? &:exist?
41
+ files.any?(&:exist?) || defaults.any?(&:exist?)
42
42
  end
43
43
 
44
44
  def has_backup?
45
- files.any? &:has_backup?
45
+ files.any?(&:has_backup?) || defaults.any?(&:has_backup?)
46
46
  end
47
47
 
48
- def should_sync?
48
+ def tracked?
49
49
  exist? || has_backup?
50
50
  end
51
51
 
52
- def synced?
53
- files.all? &:synced?
54
- end
55
-
56
52
  def self.all
57
53
  Dir["#{Dutiful.dir}/db/*.toml"].map do |filename|
58
54
  Dutiful::Application.new filename
@@ -0,0 +1,83 @@
1
+ class Dutiful::ApplicationDefault
2
+ Result = Struct.new(:error, :success?)
3
+
4
+ def initialize(hash)
5
+ @description = hash[:description]
6
+ @domain = hash[:domain]
7
+ @key = hash[:key]
8
+ end
9
+
10
+ def backup
11
+ FileUtils.mkdir_p File.dirname "#{backup_path}"
12
+ File.open(backup_path, 'w') { |file| file << value }
13
+
14
+ Result.new nil, true
15
+ rescue => ex
16
+ Result.new ex.message, false
17
+ end
18
+
19
+ def backup_value
20
+ value = nil
21
+ File.open(backup_path) { |file| value = file.read }
22
+
23
+ value
24
+ end
25
+
26
+ def restore
27
+ `defaults write #{@domain} #{@key} #{backup_value}`
28
+ Result.new nil, true
29
+ rescue => ex
30
+ Result.new ex.message, false
31
+ end
32
+
33
+ def name
34
+ "#{@domain} #{@key}"
35
+ end
36
+
37
+ def value
38
+ @value ||= `defaults read #{@domain} #{@key} 2>/dev/null`
39
+ end
40
+
41
+ def exist?
42
+ @exists ||= begin
43
+ @value = `defaults read #{@domain} #{@key} 2>/dev/null`
44
+ $?.success?
45
+ end
46
+ end
47
+
48
+ def has_backup?
49
+ File.exist? backup_path
50
+ end
51
+
52
+ def tracked?
53
+ exist? || has_backup?
54
+ end
55
+
56
+ def in_sync?
57
+ value == backup_value
58
+ end
59
+
60
+ def to_s
61
+ if exist?
62
+ if has_backup?
63
+ if in_sync?
64
+ "#{name} ✔".green
65
+ else
66
+ "#{name} (modified)".yellow
67
+ end
68
+ else
69
+ "#{name} (pending backup)".yellow
70
+ end
71
+ elsif has_backup?
72
+ "#{name} (pending restore)".yellow
73
+ else
74
+ "#{name} does not exist (skipping)".light_black
75
+ end
76
+ end
77
+
78
+ private
79
+
80
+ def backup_path
81
+ Dutiful::Config.storage.path "defaults/#{@domain}/#{@key}"
82
+ end
83
+ end
@@ -1,17 +1,16 @@
1
1
  class Dutiful::ApplicationFile
2
- attr_reader :full_path, :path
2
+ attr_reader :path
3
3
 
4
4
  def initialize(path, condition)
5
- @command = condition[:command] if condition
6
- @expected_output = condition[:expected_output] if condition
7
- @expected_status = condition[:expected_status] if condition
8
- @path = path
5
+ @condition, @path = condition, path
6
+ end
9
7
 
10
- if directory?
11
- @full_path = "#{File.expand_path "~/#{path}"}/"
12
- else
13
- @full_path = File.expand_path "~/#{path}"
14
- end
8
+ def backup
9
+ Dutiful::Config.storage.backup self
10
+ end
11
+
12
+ def restore
13
+ Dutiful::Config.storage.restore self
15
14
  end
16
15
 
17
16
  def backup_path
@@ -22,46 +21,70 @@ class Dutiful::ApplicationFile
22
21
  File.mtime backup_path if has_backup?
23
22
  end
24
23
 
25
- def timestamp
26
- File.mtime full_path if exist?
24
+ def command
25
+ @condition[:command] if has_condition?
27
26
  end
28
27
 
29
- def meets_conditions?
30
- if has_condition?
31
- output = `#{@command}`
28
+ def expected_output
29
+ @condition[:expected_output] if has_condition?
30
+ end
32
31
 
33
- if @expected_status
34
- $?.exitstatus == @expected_status
35
- else
36
- $?.success? && output.strip == @expected_output
37
- end
32
+ def expected_status
33
+ @condition[:expected_status] if has_condition?
34
+ end
35
+
36
+ def full_path
37
+ if directory?
38
+ "#{File.expand_path "~/#{path}"}/"
38
39
  else
39
- true
40
+ File.expand_path "~/#{path}"
40
41
  end
41
42
  end
42
43
 
44
+ def name
45
+ path
46
+ end
47
+
48
+ def timestamp
49
+ File.mtime full_path if exist?
50
+ end
51
+
43
52
  def directory?
44
53
  path.chars.last == '/'
45
54
  end
46
55
 
47
56
  def exist?
48
- File.exist? full_path
57
+ File.exist?(full_path) && meets_conditions?
49
58
  end
50
59
 
51
60
  def has_backup?
52
- Dutiful::Config.storage.exist? self
61
+ Dutiful::Config.storage.exist?(self) && meets_conditions?
53
62
  end
54
63
 
55
64
  def has_condition?
56
- @command
65
+ @condition
66
+ end
67
+
68
+ def meets_conditions?
69
+ if has_condition?
70
+ output = `#{command}`
71
+
72
+ if expected_status
73
+ $?.exitstatus == expected_status
74
+ else
75
+ $?.success? && output.strip == expected_output
76
+ end
77
+ else
78
+ true
79
+ end
57
80
  end
58
81
 
59
- def should_sync?
60
- (exist? || has_backup?) && meets_conditions?
82
+ def tracked?
83
+ exist? || has_backup?
61
84
  end
62
85
 
63
- def synced?
64
- has_backup? && Dutiful::Config.storage.synced?(self)
86
+ def in_sync?
87
+ has_backup? && Dutiful::Config.storage.in_sync?(self)
65
88
  end
66
89
 
67
90
  def to_s
@@ -69,7 +92,7 @@ class Dutiful::ApplicationFile
69
92
 
70
93
  if exist?
71
94
  if has_backup?
72
- if synced?
95
+ if in_sync?
73
96
  "#{path} ✔".green
74
97
  else
75
98
  "#{path} (modified)".yellow
@@ -80,7 +103,7 @@ class Dutiful::ApplicationFile
80
103
  elsif has_backup?
81
104
  "#{path} (pending restore)".yellow
82
105
  else
83
- "#{path} does not exist (skipping)".yellow
106
+ "#{path} does not exist (skipping)".light_black
84
107
  end
85
108
  end
86
109
  end
@@ -1,21 +1,23 @@
1
1
  class Dutiful::Command::Backup < Clamp::Command
2
+ option ['-q', '--quiet'], :flag, 'Quiet mode'
2
3
  option ['-v', '--verbose'], :flag, 'Verbose mode'
3
4
 
4
5
  def execute
5
- puts "Storage: #{Dutiful::Config.storage.name}\n\n"
6
+ Dutiful::Logger.set quiet?, verbose?
7
+ Dutiful::Logger.info "Storage: #{Dutiful::Config.storage.name}\n\n"
6
8
 
7
9
  Dutiful::Application.each do |application|
8
- puts "#{application.name}:\n" if application.should_sync? && application.exist? || verbose?
10
+ Dutiful::Logger.info "#{application.name}:\n" if application.exist? || verbose?
9
11
 
10
12
  application.backup do |file, result|
11
13
  if result
12
14
  if result.success?
13
- puts " #{file.path} ✔".green
15
+ Dutiful::Logger.success " #{file.name} ✔"
14
16
  else
15
- puts " #{file.path} ✖ - #{result.error}".red
17
+ Dutiful::Logger.error " #{file.name} ✖ - #{result.error}"
16
18
  end
17
19
  elsif verbose?
18
- puts " #{file}"
20
+ Dutiful::Logger.info " #{file}"
19
21
  end
20
22
  end
21
23
  end
@@ -2,13 +2,18 @@ class Dutiful::Command::List < Clamp::Command
2
2
  option ['-v', '--verbose'], :flag, 'Verbose mode'
3
3
 
4
4
  def execute
5
- puts "Storage: #{Dutiful::Config.storage.name}\n\n"
5
+ Dutiful::Logger.set false, verbose?
6
+ Dutiful::Logger.info "Storage: #{Dutiful::Config.storage.name}\n\n"
6
7
 
7
8
  Dutiful::Application.each do |application|
8
- puts "#{application.name}:\n" if application.should_sync? || verbose?
9
+ Dutiful::Logger.info "#{application.name}:\n" if application.tracked? || verbose?
9
10
 
10
11
  application.files.map do |file|
11
- puts " #{file}" if (file.should_sync?) || verbose?
12
+ Dutiful::Logger.info " #{file}" if file.tracked? || verbose?
13
+ end.compact.join("\n")
14
+
15
+ application.defaults.map do |default|
16
+ Dutiful::Logger.info " #{default}" if default.tracked? || verbose?
12
17
  end.compact.join("\n")
13
18
  end
14
19
  end
@@ -1,11 +1,23 @@
1
1
  class Dutiful::Command::Main < Clamp::Command
2
2
  option ['-v', '--version'], :flag, 'Show version' do
3
- puts "dutiful #{Dutiful::VERSION}"
3
+ Dutiful::Logger.info "dutiful #{Dutiful::VERSION}"
4
+ exit 0
5
+ end
6
+
7
+ option ['--init'], :flag, 'Initialize your computer with dutiful.' do
8
+ if File.exist? Dutiful::Config::PATH
9
+ Dutiful::Logger.warning "Configuration file already exist: '~/.dutiful/config.toml'."
10
+ exit 1
11
+ end
12
+
13
+ FileUtils.mkdir_p Dutiful.dir
14
+ FileUtils.cp File.expand_path("#{Dutiful.dir}/template/config.toml"), Dutiful::Config::PATH
15
+
16
+ Dutiful::Logger.success "Configuration file successfully created: '~/.dutiful/config.toml'."
4
17
  exit 0
5
18
  end
6
19
 
7
20
  subcommand 'backup', 'Backup all preference files', Dutiful::Command::Backup
8
21
  subcommand 'list', 'List all preference files', Dutiful::Command::List
9
22
  subcommand 'restore', 'Restore all preference files', Dutiful::Command::Restore
10
- subcommand 'sync', 'Sync all preference files', Dutiful::Command::Sync
11
23
  end
@@ -1,21 +1,23 @@
1
1
  class Dutiful::Command::Restore < Clamp::Command
2
+ option ['-q', '--quiet'], :flag, 'Quiet mode'
2
3
  option ['-v', '--verbose'], :flag, 'Verbose mode'
3
4
 
4
5
  def execute
5
- puts "Storage: #{Dutiful::Config.storage.name}\n\n"
6
+ Dutiful::Logger.set quiet?, verbose?
7
+ Dutiful::Logger.info "Storage: #{Dutiful::Config.storage.name}\n\n"
6
8
 
7
9
  Dutiful::Application.each do |application|
8
- puts "#{application.name}:\n" if application.should_sync? && application.has_backup? || verbose?
10
+ Dutiful::Logger.info "#{application.name}:\n" if application.has_backup? || verbose?
9
11
 
10
12
  application.restore do |file, result|
11
13
  if result
12
14
  if result.success?
13
- puts " #{file.path} ✔".green
15
+ Dutiful::Logger.success " #{file.name} ✔"
14
16
  else
15
- puts " #{file.path} ✖ - #{result.error}".red
17
+ Dutiful::Logger.error " #{file.name} ✖ - #{result.error}"
16
18
  end
17
19
  elsif verbose?
18
- puts " #{file}"
20
+ Dutiful::Logger.info " #{file}"
19
21
  end
20
22
  end
21
23
  end
@@ -4,5 +4,4 @@ require 'clamp'
4
4
  require 'dutiful/commands/backup'
5
5
  require 'dutiful/commands/list'
6
6
  require 'dutiful/commands/restore'
7
- require 'dutiful/commands/sync'
8
7
  require 'dutiful/commands/main'
@@ -12,6 +12,10 @@ class Dutiful::Config
12
12
  end
13
13
  end
14
14
 
15
+ def self.osx?
16
+ `uname -s`.strip == 'Darwin'
17
+ end
18
+
15
19
  private
16
20
 
17
21
  def self.content
@@ -0,0 +1,22 @@
1
+ class Dutiful::Logger
2
+ def self.set(quiet, verbose)
3
+ @quiet = quiet
4
+ @verbose = verbose
5
+ end
6
+
7
+ def self.info(message)
8
+ puts message unless @quiet
9
+ end
10
+
11
+ def self.success(message)
12
+ puts message.green unless @quiet
13
+ end
14
+
15
+ def self.warning(message)
16
+ puts message.yellow unless @quiet
17
+ end
18
+
19
+ def self.error(message)
20
+ puts message.red unless @quiet
21
+ end
22
+ end
@@ -56,7 +56,7 @@ class Dutiful::Storage
56
56
  end
57
57
  end
58
58
 
59
- def synced?(file)
59
+ def in_sync?(file)
60
60
  if file.directory?
61
61
  Dir.glob("#{file.full_path}*").all? do |file_path|
62
62
  filename = File.basename(file_path)
@@ -1,3 +1,3 @@
1
1
  module Dutiful
2
- VERSION = '0.0.9'
2
+ VERSION = '0.0.10'
3
3
  end
data/lib/dutiful.rb CHANGED
@@ -5,9 +5,11 @@ module Dutiful
5
5
  end
6
6
 
7
7
  require 'dutiful/application'
8
+ require 'dutiful/application_default'
8
9
  require 'dutiful/application_file'
9
10
  require 'dutiful/commands'
10
11
  require 'dutiful/config'
12
+ require 'dutiful/logger'
11
13
  require 'dutiful/storage'
12
14
  require 'colorize'
13
15
  require 'rsync'
@@ -0,0 +1,6 @@
1
+ [storage]
2
+ # If the storage name is either iCloud or Dropbox, the storage path will default to
3
+ # '~/Dropbox' and '~/Library/Mobile Documents' respectively.
4
+
5
+ name = 'iCloud' # The storage name is going to be printed when running the dutiful commands.
6
+ #path = '~/custom-folder' # The folder where your preference files are synced to.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dutiful
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9
4
+ version: 0.0.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bruno Pinto
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-02 00:00:00.000000000 Z
11
+ date: 2015-08-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: clamp
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0.6'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '10'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '10'
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: rspec
85
99
  requirement: !ruby/object:Gem::Requirement
@@ -113,6 +127,7 @@ files:
113
127
  - db/git.toml
114
128
  - db/iterm2.toml
115
129
  - db/oh-my-zsh.toml
130
+ - db/osx-screencapture.toml
116
131
  - db/popcorn-time.toml
117
132
  - db/rubymine.toml
118
133
  - db/the_silver_searcher.toml
@@ -123,16 +138,18 @@ files:
123
138
  - db/zsh.toml
124
139
  - lib/dutiful.rb
125
140
  - lib/dutiful/application.rb
141
+ - lib/dutiful/application_default.rb
126
142
  - lib/dutiful/application_file.rb
127
143
  - lib/dutiful/commands.rb
128
144
  - lib/dutiful/commands/backup.rb
129
145
  - lib/dutiful/commands/list.rb
130
146
  - lib/dutiful/commands/main.rb
131
147
  - lib/dutiful/commands/restore.rb
132
- - lib/dutiful/commands/sync.rb
133
148
  - lib/dutiful/config.rb
149
+ - lib/dutiful/logger.rb
134
150
  - lib/dutiful/storage.rb
135
151
  - lib/dutiful/version.rb
152
+ - template/config.toml
136
153
  homepage: http://github.com/bpinto/dutiful
137
154
  licenses:
138
155
  - MIT
@@ -156,5 +173,5 @@ rubyforge_project:
156
173
  rubygems_version: 2.4.5
157
174
  signing_key:
158
175
  specification_version: 4
159
- summary: dutiful-0.0.9
176
+ summary: dutiful-0.0.10
160
177
  test_files: []
@@ -1,23 +0,0 @@
1
- class Dutiful::Command::Sync < Clamp::Command
2
- option ['-v', '--verbose'], :flag, 'Verbose mode'
3
-
4
- def execute
5
- puts "Storage: #{Dutiful::Config.storage.name}\n\n"
6
-
7
- Dutiful::Application.each do |application|
8
- puts "#{application.name}:\n" if application.should_sync? || verbose?
9
-
10
- application.sync do |file, result|
11
- if result
12
- if result.success?
13
- puts " #{file.path} ✔".green
14
- else
15
- puts " #{file.path} ✖ - #{result.error}".red
16
- end
17
- elsif verbose?
18
- puts " #{file}"
19
- end
20
- end
21
- end
22
- end
23
- end