dotbox 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,2 @@
1
+ /pkg/
2
+ /tmp/
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
@@ -0,0 +1,43 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ backbox (1.0.0)
5
+ thor
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ aruba (0.5.1)
11
+ childprocess (~> 0.3.6)
12
+ cucumber (>= 1.1.1)
13
+ rspec-expectations (>= 2.7.0)
14
+ builder (3.2.0)
15
+ childprocess (0.3.8)
16
+ ffi (~> 1.0, >= 1.0.11)
17
+ cucumber (1.2.1)
18
+ builder (>= 2.1.2)
19
+ diff-lcs (>= 1.1.3)
20
+ gherkin (~> 2.11.0)
21
+ json (>= 1.4.6)
22
+ diff-lcs (1.2.1)
23
+ ffi (1.4.0)
24
+ gherkin (2.11.6)
25
+ json (>= 1.7.6)
26
+ json (1.7.7)
27
+ rspec (2.13.0)
28
+ rspec-core (~> 2.13.0)
29
+ rspec-expectations (~> 2.13.0)
30
+ rspec-mocks (~> 2.13.0)
31
+ rspec-core (2.13.0)
32
+ rspec-expectations (2.13.0)
33
+ diff-lcs (>= 1.1.3, < 2.0)
34
+ rspec-mocks (2.13.0)
35
+ thor (0.17.0)
36
+
37
+ PLATFORMS
38
+ ruby
39
+
40
+ DEPENDENCIES
41
+ aruba
42
+ backbox!
43
+ rspec
@@ -0,0 +1,41 @@
1
+ # Dotbox
2
+
3
+ Backup your dotfiles to dropbox and restore them easily.
4
+
5
+ ## Installation
6
+
7
+ ```
8
+ gem i dotbox
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```
14
+ $ dotbox -h
15
+ Tasks:
16
+ dotbox add # Backup the file
17
+ dotbox help [TASK] # Describe available tasks or one specific task
18
+ dotbox remove # Remove the backuped file
19
+ dotbox restore # Restore all backuped files
20
+ dotbox setup # Setup bakbox
21
+ ```
22
+
23
+ ## How does it works?
24
+
25
+ Assume that we have a file named `/home/meck/.zshrc`.
26
+
27
+ When you run `dotbox add .zshrc`, it equals running following commands:
28
+ ```
29
+ $ mv /home/meck/.zshrc /home/meck/Dropbox/Apps/Dotbox/.zshrc
30
+ $ ln -s /home/meck/Dropbox/Apps/Dotbox/.zshrc /home/meck/.zshrc
31
+ ```
32
+
33
+ When you run `dotbox remove .zshrc`, it equals running following commands:
34
+ ```
35
+ $ rm /home/meck/.zshrc
36
+ $ mv /home/meck/Dropbox/Apps/Dotbox/.zshrc /home/meck.zshrc
37
+ ```
38
+
39
+ When you run `dotbox restore` it will link all files in dropbox to their original postions.
40
+
41
+
@@ -0,0 +1,9 @@
1
+ require "bundler"
2
+ require "rspec/core/rake_task"
3
+
4
+ Bundler::GemHelper.install_tasks
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task :default => :spec
9
+ task :test => :spec
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.expand_path("../../lib", __FILE__)
4
+
5
+ require 'dotbox/cli'
6
+
7
+ Dotbox::CLI.start
@@ -0,0 +1,17 @@
1
+ require File.expand_path("../lib/dotbox/version", __FILE__)
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = "dotbox"
5
+ s.description = "Backup your dotfiles to dropbox and restore them easily."
6
+ s.summary = s.description
7
+ s.authors = ["Wei Zhu"]
8
+ s.email = ["yesmeck@gmail.com"]
9
+ s.files = `git ls-files`.split("\n")
10
+ s.homepage = "https://github.com/yesmeck/dotbox"
11
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
12
+ s.version = Dotbox::VERSION::STRING
13
+
14
+ s.add_dependency 'thor'
15
+ s.add_development_dependency 'aruba'
16
+ s.add_development_dependency 'rspec'
17
+ end
@@ -0,0 +1,29 @@
1
+ Feature: add file to dropbox
2
+
3
+ In order backup the file
4
+ As a user
5
+ I want to add the file to dropbox and link it back
6
+
7
+ @announce
8
+ Scenario: add a not exist file
9
+ When I run `dotbox add not_exist_file`
10
+ Then the stdout should contain "not exist"
11
+
12
+ @announce
13
+ Scenario: add a exists file
14
+ Given an empty file named "foo/bar"
15
+ When I run `dotbox add foo/bar`
16
+ Then a file named "dropbox/Apps/Dotbox/foo/bar" should exist
17
+ And the link named "foo/bar" should be a link of "dropbox/Apps/Dotbox/foo/bar"
18
+ And the record file should contain "foo/bar" => "file"
19
+
20
+ @announce
21
+ Scenario: add a directory
22
+ Given a directory named "foo/bar"
23
+ Given an empty file named "foo/bar/example"
24
+ When I run `dotbox add foo/bar`
25
+ Then a directory named "dropbox/Apps/Dotbox/foo/bar"
26
+ And a directory named "dropbox/Apps/Dotbox/foo/bar" should exist
27
+ And the link named "foo/bar" should be a link of "dropbox/Apps/Dotbox/foo/bar"
28
+ And the record file should contain "foo/bar" => "directory"
29
+
@@ -0,0 +1,48 @@
1
+ Feature: remove a file from dotbox
2
+
3
+ As a user
4
+ I want to remove a file from dotbox
5
+
6
+ @announce
7
+ Scenario: remove a not exist file
8
+ When I run `dotbox remove not_exist_file`
9
+ Then the stdout should contain "not exist"
10
+
11
+ @announce
12
+ Scenario: remove a not backuped file
13
+ Given an empty file named "foo/bar"
14
+ When I run `dotbox remove foo/bar`
15
+ Then the stdout should contain "not backuped"
16
+
17
+ @announce
18
+ Scenario: remove a backuped file
19
+ Given a backuped file named "foo/bar"
20
+ When I run `dotbox remove foo/bar`
21
+ Then a file named "dropbox/Apps/Dotbox/foo/bar" should not exist
22
+ And a file named "dropbox/Apps/Dotbox/foo" should not exist
23
+ And a file named "foo/bar" should exist
24
+ And the file named "foo/bar" should not be a link
25
+ And the record file should not contain "foo/bar"
26
+
27
+ @announce
28
+ Scenario: remove a backuped directory
29
+ Given a backuped directory named "foo/bar"
30
+ When I run `dotbox remove foo/bar`
31
+ Then a directory named "dropbox/Apps/Dotbox/foo/bar" should not exist
32
+ And a directory named "dropbox/Apps/Dotbox/foo" should not exist
33
+ And a directory named "foo/bar" should exist
34
+ And the directory named "foo/bar" should not be a link
35
+ And the record file should not contain "foo/bar"
36
+
37
+ @announce
38
+ Scenario: remove a backuped file in which directory has two files
39
+ Given a backuped file named "foo/bar"
40
+ And a backuped file named "foo/baz"
41
+ When I run `dotbox remove foo/bar`
42
+ Then a file named "dropbox/Apps/Dotbox/foo/bar" should not exist
43
+ And a file named "dropbox/Apps/Dotbox/foo/baz" should exist
44
+ And a file named "foo/bar" should exist
45
+ And the file named "foo/bar" should not be a link
46
+ And the record file should not contain "foo/bar"
47
+ And the record file should contain "foo/baz" => "file"
48
+
@@ -0,0 +1,16 @@
1
+ Feature: restore backuped files
2
+
3
+ I got a fresh system
4
+ In order to restore all my backuped files
5
+ I can use `dotbox restore`
6
+
7
+ @announce
8
+ Scenario: restore all backuped files
9
+ Given a backup file named "foo/bar"
10
+ Given a backup directory named "baz/bar"
11
+ When I run `dotbox restore`
12
+ Then a link named "foo/bar" should exist
13
+ And the link named "foo/bar" should be a link of "dropbox/Apps/Dotbox/foo/bar"
14
+ And a link named "baz/bar" should exist
15
+ And the link named "baz/bar" should be a link of "dropbox/Apps/Dotbox/baz/bar"
16
+
@@ -0,0 +1,15 @@
1
+ Feature: setup dotbox
2
+
3
+ This is my first time to use dotbox
4
+ So I want to setup it
5
+
6
+ @announce
7
+ Scenario: setup dotbox
8
+ Given a directory named "dropbox"
9
+ When I run `dotbox setup` interactively
10
+ And I type "dropbox"
11
+ Then a file named ".dotbox" should exist
12
+ And the file ".dotbox" should contain exactly:
13
+ """
14
+ dropbox
15
+ """
@@ -0,0 +1,65 @@
1
+ require 'dotbox'
2
+ require 'dotbox/config'
3
+ require 'dotbox/record'
4
+ require 'dotbox/api'
5
+
6
+ World(Aruba::Api)
7
+ World(Dotbox::Api)
8
+
9
+ Given /^a backuped file named "(.*?)"$/ do |path|
10
+ write_file(path, "")
11
+ in_current_dir do
12
+ create_backup(path)
13
+ end
14
+ end
15
+
16
+ Given /^a backuped directory named "(.*?)"$/ do |path|
17
+ in_current_dir do
18
+ _mkdir(path)
19
+ create_backup(path)
20
+ end
21
+ end
22
+
23
+ Given /^a backup file named "(.*?)"$/ do |path|
24
+ in_current_dir do
25
+ create_backup_file path
26
+ end
27
+ end
28
+
29
+ Given /^a backup directory named "(.*?)"$/ do |path|
30
+ in_current_dir do
31
+ create_backup_directory path
32
+ end
33
+ end
34
+
35
+
36
+ Then /^the link named "(.*?)" should be a link of "(.*?)"$/ do |link, file|
37
+ in_current_dir do
38
+ link_file = File.readlink(link) rescue nil
39
+ link_file.should == File.expand_path(file)
40
+ end
41
+ end
42
+
43
+ Then /^the (?:file|directory) named "(.*?)" should not be a link$/ do |path|
44
+ in_current_dir do
45
+ File.should_not be_symlink(path)
46
+ end
47
+ end
48
+
49
+ Then /^a link named "(.*?)" should exist$/ do |link|
50
+ in_current_dir do
51
+ File.should be_symlink(link)
52
+ end
53
+ end
54
+
55
+ Then /^the record file should contain "(.*?)" => "(.*?)"$/ do |path, type|
56
+ record = Dotbox::Record.new
57
+ record[path].should == type
58
+ end
59
+
60
+
61
+ Then /^the record file should not contain "(.*?)"$/ do |path|
62
+ record = Dotbox::Record.new
63
+ record[path].should be nil
64
+ end
65
+
@@ -0,0 +1,7 @@
1
+ require 'aruba/cucumber'
2
+ require 'cucumber/rspec/doubles'
3
+ require File.expand_path('../../../lib/dotbox/config.rb', __FILE__)
4
+
5
+ ENV['PATH'] = "#{File.expand_path('../../bin/dotbox', __FILE__)}#{File::PATH_SEPARATOR}#{ENV['PATH']}"
6
+ ENV['HOME'] = File.expand_path('../../../tmp/aruba', __FILE__)
7
+ ENV['DROPBOX_PATH'] = "#{ENV['HOME']}/dropbox"
@@ -0,0 +1,5 @@
1
+ require 'thor'
2
+
3
+ module Dotbox
4
+ CONFIG_FILE = "#{Thor::Util.user_home}/.dotbox"
5
+ end
@@ -0,0 +1,13 @@
1
+ module Dotbox
2
+ module Actions
3
+
4
+ def rm_empty_dir(path)
5
+ return nil if !::File.directory?(path)
6
+ if (Dir.entries(path) - %w{. ..}).empty?
7
+ FileUtils.rm_r path
8
+ rm_empty_dir ::File.dirname(path)
9
+ end
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,29 @@
1
+ require 'dotbox'
2
+ require 'dotbox/config'
3
+ require 'dotbox/record'
4
+ require 'dotbox/file'
5
+
6
+ module Dotbox
7
+ module Api
8
+
9
+ def create_backup(path)
10
+ file = Dotbox::File.new(path)
11
+ file.backup
12
+ Dotbox::Record.new.add file
13
+ end
14
+
15
+ def create_backup_file(path)
16
+ FileUtils.mkdir ::File.dirname(path)
17
+ FileUtils.touch path
18
+ create_backup path
19
+ FileUtils.rm path
20
+ end
21
+
22
+ def create_backup_directory(path)
23
+ FileUtils.mkdir_p path
24
+ create_backup path
25
+ FileUtils.rm_r path
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,75 @@
1
+ require 'dotbox'
2
+ require 'dotbox/config'
3
+ require 'dotbox/file'
4
+ require 'dotbox/record'
5
+
6
+ module Dotbox
7
+ class CLI < Thor
8
+
9
+ desc :setup, 'Setup bakbox'
10
+ def setup
11
+ dropbox_path = ask('Enter dropbox folder location:').strip
12
+ Dotbox::Config.new(Dotbox::CONFIG_FILE, dropbox_path)
13
+ end
14
+
15
+ desc :add, 'Backup the file'
16
+ def add(*pathes)
17
+ check_setup
18
+ @record = Record.new
19
+ pathes.each do |path|
20
+ path = ::File.expand_path(path)
21
+ if ::File.exists?(path)
22
+ file = File.new(path)
23
+ file.backup
24
+ @record.add file
25
+ else
26
+ say "#{path} not exists."
27
+ end
28
+ end
29
+ end
30
+
31
+ desc :remove, 'Remove the backuped file'
32
+ def remove(*pathes)
33
+ check_setup
34
+ @record = Record.new
35
+ pathes.each do |path|
36
+ path = ::File.expand_path(path)
37
+ file = File.new(path)
38
+ if !::File.exists?(path)
39
+ die "#{path} not exists."
40
+ elsif !file.backuped?
41
+ die "#{path} is not backuped."
42
+ end
43
+ file.remove
44
+ @record.remove file
45
+ end
46
+ end
47
+
48
+ desc :restore, 'Restore all backuped files'
49
+ def restore
50
+ check_setup
51
+ @record = Record.new
52
+ @record.each do |path|
53
+ file = File.new(path)
54
+ file.restore
55
+ end
56
+ end
57
+
58
+ def self.source_root
59
+ ::File.dirname(::File.expand_path('../../../bin/dotbox', __FILE__))
60
+ end
61
+
62
+ private
63
+ def check_setup
64
+ if !Config.new(Dotbox::CONFIG_FILE).setted?
65
+ die 'Use `bakbox setup` to setup dotbox first.'
66
+ end
67
+ end
68
+
69
+ def die(msg)
70
+ say msg
71
+ exit;
72
+ end
73
+
74
+ end
75
+ end
@@ -0,0 +1,31 @@
1
+ module Dotbox
2
+ class Config
3
+
4
+ def initialize(file, value = nil)
5
+ @file = file
6
+ if !value.nil?
7
+ save(value)
8
+ end
9
+ end
10
+
11
+ def value
12
+ if ENV['DROPBOX_PATH'].nil?
13
+ ::File.new(@file).read.strip.chomp('/')
14
+ else
15
+ ENV['DROPBOX_PATH']
16
+ end
17
+ end
18
+
19
+ def setted?
20
+ ::File.exists?(@file) || !ENV['DROPBOX_PATH'].nil?
21
+ end
22
+
23
+ private
24
+ def save(value)
25
+ f = ::File.new(@file, 'w+')
26
+ f.write(value)
27
+ f.close
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,63 @@
1
+ require 'dotbox/actions'
2
+
3
+ module Dotbox
4
+ class File
5
+
6
+ attr_reader :abs_path, :rel_path
7
+
8
+ include Dotbox::Actions
9
+
10
+ def initialize(path)
11
+ @abs_path = ::File.expand_path(path)
12
+ @rel_path = @abs_path.sub(/^#{Thor::Util.user_home}\//, '')
13
+ end
14
+
15
+ def directory?
16
+ ::File.directory?(@abs_path)
17
+ end
18
+
19
+ def backup_path
20
+ if @backup_path.nil?
21
+ backup_path = "#{Config.new(Dotbox::CONFIG_FILE).value}/Apps/Dotbox"
22
+ @backup_path = ::File.expand_path("#{backup_path}/#{@rel_path}")
23
+ end
24
+ @backup_path
25
+ end
26
+
27
+ def backup
28
+ FileUtils.mkdir_p ::File.dirname(backup_path)
29
+ FileUtils.mv @abs_path, backup_path
30
+ FileUtils.ln_s backup_path, @abs_path
31
+ end
32
+
33
+ def remove
34
+ # must get the backup path first
35
+ backup_path
36
+ FileUtils.rm @abs_path
37
+ FileUtils.mv backup_path, @abs_path
38
+ rm_empty_dir ::File.dirname(backup_path)
39
+ end
40
+
41
+ def restore
42
+ FileUtils.mkdir_p ::File.dirname(@abs_path)
43
+ FileUtils.ln_s backup_path, @abs_path
44
+ end
45
+
46
+ def backuped?
47
+ link? && link_of?(backup_path)
48
+ end
49
+
50
+ def link?
51
+ ::File.symlink? @abs_path
52
+ end
53
+
54
+ def link_of?(src)
55
+ ::File.readlink(@abs_path) == src
56
+ end
57
+
58
+ def type
59
+ @type = directory? ? 'directory' : 'file'
60
+ end
61
+
62
+ end
63
+ end
@@ -0,0 +1,43 @@
1
+ require 'yaml'
2
+ require 'dotbox/file'
3
+
4
+ module Dotbox
5
+ class Record
6
+
7
+ def initialize
8
+ @record_file_path = "#{Config.new(Dotbox::CONFIG_FILE).value}/Apps/Dotbox/.dotbox"
9
+ if !::File.exists?(@record_file_path)
10
+ FileUtils.mkdir_p(::File.dirname(@record_file_path))
11
+ FileUtils.touch(@record_file_path)
12
+ end
13
+ @records = YAML.load_file(@record_file_path) || {}
14
+ end
15
+
16
+ def add(file)
17
+ @records[file.rel_path] = file.type
18
+ save
19
+ end
20
+
21
+ def remove(file)
22
+ @records.delete file.rel_path
23
+ save
24
+ end
25
+
26
+ def save
27
+ record_file = ::File.new(@record_file_path, 'w+')
28
+ record_file.puts(YAML.dump(@records))
29
+ record_file.close
30
+ end
31
+
32
+ def [](path)
33
+ @records[path]
34
+ end
35
+
36
+ def each
37
+ @records.each do |path, type|
38
+ yield path
39
+ end
40
+ end
41
+
42
+ end
43
+ end
@@ -0,0 +1,10 @@
1
+ module Dotbox
2
+ module VERSION
3
+ MAJOR = 1
4
+ MINOR = 0
5
+ PATCH = 0
6
+ BUILD = nil
7
+
8
+ STRING = [MAJOR, MINOR, PATCH, BUILD].compact.join('.');
9
+ end
10
+ end
metadata ADDED
@@ -0,0 +1,121 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dotbox
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Wei Zhu
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-03-02 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: thor
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: aruba
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ description: Backup your dotfiles to dropbox and restore them easily.
63
+ email:
64
+ - yesmeck@gmail.com
65
+ executables: []
66
+ extensions: []
67
+ extra_rdoc_files: []
68
+ files:
69
+ - .gitignore
70
+ - Gemfile
71
+ - Gemfile.lock
72
+ - README.md
73
+ - Rakefile
74
+ - bin/dotbox
75
+ - dotbox.gemspec
76
+ - features/add.feature
77
+ - features/remove.feature
78
+ - features/restore.feature
79
+ - features/setup.feature
80
+ - features/step_definitions/file_steps.rb
81
+ - features/support/env.rb
82
+ - lib/dotbox.rb
83
+ - lib/dotbox/actions.rb
84
+ - lib/dotbox/api.rb
85
+ - lib/dotbox/cli.rb
86
+ - lib/dotbox/config.rb
87
+ - lib/dotbox/file.rb
88
+ - lib/dotbox/record.rb
89
+ - lib/dotbox/version.rb
90
+ homepage: https://github.com/yesmeck/dotbox
91
+ licenses: []
92
+ post_install_message:
93
+ rdoc_options: []
94
+ require_paths:
95
+ - lib
96
+ required_ruby_version: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ required_rubygems_version: !ruby/object:Gem::Requirement
103
+ none: false
104
+ requirements:
105
+ - - ! '>='
106
+ - !ruby/object:Gem::Version
107
+ version: '0'
108
+ requirements: []
109
+ rubyforge_project:
110
+ rubygems_version: 1.8.23
111
+ signing_key:
112
+ specification_version: 3
113
+ summary: Backup your dotfiles to dropbox and restore them easily.
114
+ test_files:
115
+ - features/add.feature
116
+ - features/remove.feature
117
+ - features/restore.feature
118
+ - features/setup.feature
119
+ - features/step_definitions/file_steps.rb
120
+ - features/support/env.rb
121
+ has_rdoc: