dottor 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +20 -0
- data/LICENSE.md +7 -0
- data/README.md +85 -0
- data/bin/dottor +4 -0
- data/dottor.gemspec +23 -0
- data/lib/dottor.rb +70 -0
- data/lib/dottor/dotfile.rb +39 -0
- data/lib/dottor/version.rb +3 -0
- data/spec/app_spec.rb +26 -0
- data/spec/fixtures/dottor_rules.yml +4 -0
- data/spec/helpers/utils.rb +13 -0
- data/spec/spec_helper.rb +15 -0
- metadata +88 -0
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
*.gem
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
diff-lcs (1.1.3)
|
5
|
+
rspec (2.9.0)
|
6
|
+
rspec-core (~> 2.9.0)
|
7
|
+
rspec-expectations (~> 2.9.0)
|
8
|
+
rspec-mocks (~> 2.9.0)
|
9
|
+
rspec-core (2.9.0)
|
10
|
+
rspec-expectations (2.9.1)
|
11
|
+
diff-lcs (~> 1.1.3)
|
12
|
+
rspec-mocks (2.9.0)
|
13
|
+
thor (0.14.6)
|
14
|
+
|
15
|
+
PLATFORMS
|
16
|
+
ruby
|
17
|
+
|
18
|
+
DEPENDENCIES
|
19
|
+
rspec
|
20
|
+
thor
|
data/LICENSE.md
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
Copyright (c) 2012 Marco Campana
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
4
|
+
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
6
|
+
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
Dottor
|
2
|
+
======
|
3
|
+
|
4
|
+
Description
|
5
|
+
-----------
|
6
|
+
Dottor is an unobtrusive command line tool for easily managing your dotfiles,
|
7
|
+
without assumptions on how your dotfiles repository should be organized.
|
8
|
+
|
9
|
+
Why Dottor?
|
10
|
+
-----------
|
11
|
+
I designed dottor so that it would be easy to setup and use, reliable and work
|
12
|
+
with existing dotfiles repos.
|
13
|
+
|
14
|
+
With Dottor you can:
|
15
|
+
|
16
|
+
1. Get started with yout current dotfils repo, without changing anything.
|
17
|
+
2. Specify different profiles, so that you can use it to symlink files in your
|
18
|
+
dev machine as well as in your production boxes.
|
19
|
+
|
20
|
+
How it works?
|
21
|
+
-------------
|
22
|
+
|
23
|
+
Dottor expect to find in your repo a YAML file named dottor_rules.yml (or you
|
24
|
+
can specify a different path) with the following format
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
profile_name:
|
28
|
+
- source: <dotffile or directory>
|
29
|
+
target: <where do you want the file to be symlinked to>
|
30
|
+
- source: <dotffile or directory>
|
31
|
+
target: <where do you want the file to be symlinked to>
|
32
|
+
```
|
33
|
+
|
34
|
+
All the actions performed by Dottor are based on the dottor_rules.yml file.
|
35
|
+
Check my [dotfiles repo][dotfiles_repo] for a working example.
|
36
|
+
|
37
|
+
|
38
|
+
Getting started
|
39
|
+
---------------
|
40
|
+
|
41
|
+
```
|
42
|
+
gem install dottor
|
43
|
+
```
|
44
|
+
|
45
|
+
### Create a dottor_rules.yml inside your dotfiles repo
|
46
|
+
|
47
|
+
```
|
48
|
+
dottor init
|
49
|
+
```
|
50
|
+
|
51
|
+
### Create symlinks based on dottor_rules.yml file in current directory
|
52
|
+
|
53
|
+
```
|
54
|
+
dottor symlink <profile_name>
|
55
|
+
```
|
56
|
+
|
57
|
+
### Specify a dottor_rules.yml file in another directory
|
58
|
+
|
59
|
+
```
|
60
|
+
dottor symlink <profile_name> -f <custom_path>
|
61
|
+
```
|
62
|
+
|
63
|
+
### Delete all the symlinks
|
64
|
+
|
65
|
+
```
|
66
|
+
dottor symlink -d
|
67
|
+
```
|
68
|
+
|
69
|
+
Submitting a Pull Request
|
70
|
+
-------------------------
|
71
|
+
|
72
|
+
1. Fork the project.
|
73
|
+
2. Create a topic branch.
|
74
|
+
3. Implement your feature or bug fix.
|
75
|
+
4. Add documentation for your feature or bug fix.
|
76
|
+
6. Add specs for your feature or bug fix.
|
77
|
+
8. Commit and push your changes.
|
78
|
+
|
79
|
+
License
|
80
|
+
-------
|
81
|
+
Released under the MIT License. See the [LICENSE][license] file for further
|
82
|
+
details.
|
83
|
+
|
84
|
+
[license]: https://github.com/marcocampana/dottor/blob/master/LICENSE.md
|
85
|
+
[dotfiles_repo]: https://github.com/marcocampana/dotfiles
|
data/bin/dottor
ADDED
data/dottor.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "dottor/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "dottor"
|
7
|
+
s.version = Dottor::VERSION
|
8
|
+
s.authors = ["Marco Campana"]
|
9
|
+
s.email = ["m.campana@gmail.com"]
|
10
|
+
s.homepage = 'http://github.com/marcocampana/dottor'
|
11
|
+
s.summary = %q{Command line tool to manage dotfiles the easy way}
|
12
|
+
s.description = %q{Unobtrusive command line tool for easily managing your dotfiles, without assumptions on how your dotfiles repository should be organized.}
|
13
|
+
|
14
|
+
s.rubyforge_project = "dottor"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_dependency 'thor'
|
22
|
+
s.add_development_dependency 'rspec'
|
23
|
+
end
|
data/lib/dottor.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'thor'
|
4
|
+
require 'dottor/dotfile'
|
5
|
+
|
6
|
+
module Dottor
|
7
|
+
class App < Thor
|
8
|
+
desc "symlink <profile_name>", "Symlink dotfiles defined in specified profile name"
|
9
|
+
method_option :file, :aliases => "-f", :desc => "Use specified rules yaml file instead of the default dottor_rules.yml"
|
10
|
+
method_option :delete, :aliases => "-d", :desc => "Delete existing symlinks added by dottor"
|
11
|
+
def symlink(profile_name)
|
12
|
+
yaml_rules = options[:file] ? File.open(options[:file]) : File.open('dottor_rules.yml')
|
13
|
+
|
14
|
+
say("Loading rules YAML file")
|
15
|
+
rules = YAML::load(yaml_rules)
|
16
|
+
|
17
|
+
rules[profile_name].each do |mapping|
|
18
|
+
dotfile = Dotfile.new(mapping)
|
19
|
+
if options[:delete]
|
20
|
+
dotfile.delete_symlink
|
21
|
+
else
|
22
|
+
dotfile.create_symlink
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
desc "init", "Create dottor_rule.yml file"
|
28
|
+
method_option :force, :desc => "Overwrite existing dottor_rules.yml file"
|
29
|
+
def init
|
30
|
+
if File.exists?('dottor_rules.yml')
|
31
|
+
if options[:force]
|
32
|
+
FileUtils.rm 'dottor_rules.yml'
|
33
|
+
else
|
34
|
+
say("Abort: dottor_rules.yml already exist. Use the --force to overwrite.")
|
35
|
+
exit(1)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
rules_hash = {"profile_name" => []}
|
40
|
+
|
41
|
+
exclude_files = ['.gitignore', 'README', 'README.md']
|
42
|
+
if git_repo?
|
43
|
+
files_in_current_dir = `git ls-files`.split("\n") - exclude_files
|
44
|
+
else
|
45
|
+
files_in_current_dir = Dir["*"] - exclude_files
|
46
|
+
end
|
47
|
+
|
48
|
+
if files_in_current_dir.empty?
|
49
|
+
rules_hash["profile_name"] = [{"source" => ".dotfile", "target" => "target_path/.dotfile"}]
|
50
|
+
else
|
51
|
+
files_in_current_dir.each do |file_name|
|
52
|
+
rules_hash["profile_name"] << {"source" => file_name, "target" => "target_path/#{file_name}"}
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
File.open('dottor_rules.yml', 'w') do |file|
|
57
|
+
file.write(YAML.dump(rules_hash))
|
58
|
+
end
|
59
|
+
|
60
|
+
say("dottor_rules.yml file created. Modify it and run 'dottor symlink <profile_name>'")
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
# TODO move into an helper module
|
66
|
+
def git_repo?
|
67
|
+
File.exists? '.git'
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Dottor
|
2
|
+
class Dotfile
|
3
|
+
attr_accessor :source, :target
|
4
|
+
|
5
|
+
def initialize(hash)
|
6
|
+
@source = hash["source"]
|
7
|
+
@target = hash["target"]
|
8
|
+
end
|
9
|
+
|
10
|
+
def create_symlink
|
11
|
+
# If file exists rename it to .old
|
12
|
+
# TODO check if .old file already exists
|
13
|
+
if File.exists?(target)
|
14
|
+
old_file_name = "#{target}.old"
|
15
|
+
FileUtils.mv target, old_file_name
|
16
|
+
end
|
17
|
+
|
18
|
+
# If symlink exists, remove it
|
19
|
+
if File.symlink?(target)
|
20
|
+
FileUtils.rm target
|
21
|
+
end
|
22
|
+
|
23
|
+
$stdout.puts("Create symlink #{File.join(current_path, source)} -> #{target}")
|
24
|
+
FileUtils.symlink File.join(current_path, source), target
|
25
|
+
end
|
26
|
+
|
27
|
+
def delete_symlink
|
28
|
+
if File.symlink?(target)
|
29
|
+
FileUtils.rm target
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def current_path
|
36
|
+
Dir.pwd
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/spec/app_spec.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "Dottor::App" do
|
4
|
+
describe "symlink" do
|
5
|
+
it "should use the dottor_rules.yml in current directory by default" do
|
6
|
+
stub_dottor_rules_file('dottor_rules.yml')
|
7
|
+
stub_dotfile
|
8
|
+
|
9
|
+
Dottor::App.start(['symlink', 'development'])
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should use the specified dottor_rules file with -f option" do
|
13
|
+
stub_dottor_rules_file('../my_custom_dottor_rules.yml')
|
14
|
+
stub_dotfile
|
15
|
+
|
16
|
+
Dottor::App.start(['symlink', 'development', '-f', '../my_custom_dottor_rules.yml'])
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should call the create_symlink method" do
|
20
|
+
stub_dottor_rules_file('dottor_rules.yml')
|
21
|
+
stub_dotfile(:create_symlink)
|
22
|
+
|
23
|
+
Dottor::App.start(['symlink', 'development'])
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Utils
|
2
|
+
def stub_dottor_rules_file(file_name)
|
3
|
+
dottor_rules_file = File.open(File.expand_path(File.dirname(__FILE__) + '/../fixtures/dottor_rules.yml'))
|
4
|
+
File.should_receive(:open).with(file_name).and_return(dottor_rules_file)
|
5
|
+
end
|
6
|
+
|
7
|
+
def stub_dotfile(method=nil)
|
8
|
+
dotfile_mock = mock(:delete_symlink => nil, :create_symlink => nil)
|
9
|
+
Dottor::Dotfile.should_receive(:new).and_return(dotfile_mock)
|
10
|
+
|
11
|
+
dotfile_mock.should_receive(method) if method
|
12
|
+
end
|
13
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
|
3
|
+
$:.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
|
4
|
+
require 'dottor'
|
5
|
+
require 'helpers/utils'
|
6
|
+
|
7
|
+
RSpec.configure do |c|
|
8
|
+
c.include Utils
|
9
|
+
|
10
|
+
c.mock_with :rspec
|
11
|
+
|
12
|
+
c.before(:each) do
|
13
|
+
STDOUT.should_receive(:puts).and_return("")
|
14
|
+
end
|
15
|
+
end
|
metadata
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dottor
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Marco Campana
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-07-15 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: thor
|
16
|
+
requirement: &70257029527160 !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: *70257029527160
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rspec
|
27
|
+
requirement: &70257029524660 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70257029524660
|
36
|
+
description: Unobtrusive command line tool for easily managing your dotfiles, without
|
37
|
+
assumptions on how your dotfiles repository should be organized.
|
38
|
+
email:
|
39
|
+
- m.campana@gmail.com
|
40
|
+
executables:
|
41
|
+
- dottor
|
42
|
+
extensions: []
|
43
|
+
extra_rdoc_files: []
|
44
|
+
files:
|
45
|
+
- .gitignore
|
46
|
+
- Gemfile
|
47
|
+
- Gemfile.lock
|
48
|
+
- LICENSE.md
|
49
|
+
- README.md
|
50
|
+
- bin/dottor
|
51
|
+
- dottor.gemspec
|
52
|
+
- lib/dottor.rb
|
53
|
+
- lib/dottor/dotfile.rb
|
54
|
+
- lib/dottor/version.rb
|
55
|
+
- spec/app_spec.rb
|
56
|
+
- spec/fixtures/dottor_rules.yml
|
57
|
+
- spec/helpers/utils.rb
|
58
|
+
- spec/spec_helper.rb
|
59
|
+
homepage: http://github.com/marcocampana/dottor
|
60
|
+
licenses: []
|
61
|
+
post_install_message:
|
62
|
+
rdoc_options: []
|
63
|
+
require_paths:
|
64
|
+
- lib
|
65
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ! '>='
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
requirements: []
|
78
|
+
rubyforge_project: dottor
|
79
|
+
rubygems_version: 1.8.15
|
80
|
+
signing_key:
|
81
|
+
specification_version: 3
|
82
|
+
summary: Command line tool to manage dotfiles the easy way
|
83
|
+
test_files:
|
84
|
+
- spec/app_spec.rb
|
85
|
+
- spec/fixtures/dottor_rules.yml
|
86
|
+
- spec/helpers/utils.rb
|
87
|
+
- spec/spec_helper.rb
|
88
|
+
has_rdoc:
|