dotmation 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +14 -0
- data/LICENSE +21 -0
- data/README.md +107 -0
- data/Rakefile +44 -0
- data/VERSION +1 -0
- data/bin/dotmation +33 -0
- data/dotmation.gemspec +67 -0
- data/lib/dotmation.rb +96 -0
- data/lib/dotmation/config_reader.rb +30 -0
- data/lib/dotmation/repo.rb +134 -0
- data/script/bootstrap-ruby-env.sh +79 -0
- data/spec/dotmation/repo_spec.rb +87 -0
- data/spec/dotmation_spec.rb +65 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/testfiles/config +29 -0
- metadata +146 -0
data/Gemfile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
# Add dependencies required to use your gem here.
|
3
|
+
# Example:
|
4
|
+
# gem "activesupport", ">= 2.3.5"
|
5
|
+
|
6
|
+
# Add dependencies to develop your gem here.
|
7
|
+
# Include everything needed to run rake, tests, features, etc.
|
8
|
+
group :development do
|
9
|
+
gem "rspec", "~> 2.13.0"
|
10
|
+
gem "rdoc", "~> 4.0.0"
|
11
|
+
gem "bundler", "~> 1.3.5"
|
12
|
+
gem "jeweler", "~> 1.8.4"
|
13
|
+
gem "simplecov", "~> 0.7.1"
|
14
|
+
end
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright (c) 2013 Brigham Young University
|
2
|
+
Authored by John T. Prince
|
3
|
+
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
a copy of this software and associated documentation files (the
|
6
|
+
"Software"), to deal in the Software without restriction, including
|
7
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
## dotmation
|
2
|
+
|
3
|
+
Github aware manager for environment files (e.g. dotfiles) inspired by fresh.
|
4
|
+
It has far fewer features than fresh and is written in ruby (taken together it
|
5
|
+
means it *may* be easier to extend).
|
6
|
+
|
7
|
+
This is *alpha* software -- use at your own risk!
|
8
|
+
|
9
|
+
Features
|
10
|
+
* depends on ruby
|
11
|
+
* ruby dsl config file
|
12
|
+
* not yet as full featured as fresh but easy to customize if you write ruby
|
13
|
+
|
14
|
+
## Installation
|
15
|
+
|
16
|
+
gem install dotmation
|
17
|
+
|
18
|
+
### Usage
|
19
|
+
|
20
|
+
Assuming your dotmation file resides or is linked where expected
|
21
|
+
(~/.config/dotmation/config), then usage is trivial:
|
22
|
+
|
23
|
+
dotmation update
|
24
|
+
|
25
|
+
The first time you run dotmation, you will need to give it the filename or URI
|
26
|
+
to your dotmation file, or a github username (assuming it is in
|
27
|
+
<user>/dotfiles/master/config/dotmation/config)
|
28
|
+
|
29
|
+
dotmation update --config your_github_username
|
30
|
+
# --OR--
|
31
|
+
dotmation update --config path/to/your/dotmation/config
|
32
|
+
# --OR--
|
33
|
+
dotmation update --config https://url/to/your/dotmation/config
|
34
|
+
|
35
|
+
### Configuration
|
36
|
+
|
37
|
+
A dotmation config file is pure ruby code, so anything you can do in ruby you
|
38
|
+
can do in your config file.
|
39
|
+
```ruby
|
40
|
+
|
41
|
+
repo_cache "~/dotrepos" # where to stash github repos
|
42
|
+
|
43
|
+
github "jtprince/dotfiles/config" do
|
44
|
+
cfg 'dotmation' # symlink ~/.config/dotmation directory
|
45
|
+
|
46
|
+
dot 'Xresources' # symlink ~/.Xresources
|
47
|
+
dot 'Xresources', '.Xdefaults' # symlink ~/.Xdefaults -> Xresources
|
48
|
+
|
49
|
+
dot 'zsh/zshenv', '.zshenv' # symlink ~/.zshenv
|
50
|
+
cfg 'zsh' # symlink ~/.config/zsh directory
|
51
|
+
|
52
|
+
cfg 'dunstrc' # symlink ~/.config/dunstrc
|
53
|
+
cfg 'i3/config', 'i3/' # symlink ~/.config/i3/config inside i3 dir
|
54
|
+
|
55
|
+
# Trailing slash -> the file is to go under the given directory.
|
56
|
+
end
|
57
|
+
|
58
|
+
github "jtprince/dotfiles/bin" do
|
59
|
+
ln '.'
|
60
|
+
end
|
61
|
+
|
62
|
+
github "robbyrussell/oh-my-zsh" do
|
63
|
+
cfg '.' # symlink ~/.config/oh-my-zsh
|
64
|
+
end
|
65
|
+
|
66
|
+
```
|
67
|
+
|
68
|
+
See a [real world example](https://github.com/jtprince/dotfiles/blob/master/config/dotmation/config).
|
69
|
+
|
70
|
+
The config file will be read in context of Dotmation::ConfigReader which is
|
71
|
+
responsible for creating repo objects and populating them with link objects.
|
72
|
+
All objects are created before being used to make links, so they can be easily
|
73
|
+
inspected.
|
74
|
+
|
75
|
+
## Bootstrap an Installation
|
76
|
+
|
77
|
+
There are several chicken and egg problems with setting up an evironment
|
78
|
+
without an environment. This shell script initializes an environment to work
|
79
|
+
with dotmation(for debian systems).
|
80
|
+
|
81
|
+
bash -c `curl -sL https://raw.github.com/jtprince/dotmation/master/script/bootstrap-ruby-env.sh`
|
82
|
+
|
83
|
+
This will install:
|
84
|
+
|
85
|
+
* rbenv
|
86
|
+
* ruby-build
|
87
|
+
* critical deb packages for building:
|
88
|
+
* git curl zlib1g-dev build-essential libssl-dev libreadline-dev
|
89
|
+
* the latest stable ruby
|
90
|
+
* dotmation
|
91
|
+
|
92
|
+
Beware, it will write to (or create) ~/.profile, remove .bash_profile, and
|
93
|
+
write to ~/.bashrc. Of course, all of these changes will be clobbered with
|
94
|
+
your own fresh symlinks (assuming you use these files) once you run dotmation
|
95
|
+
update. The bootstrap supports the bash shell only (but you're smart enough
|
96
|
+
to drop down to bash to run the initial update if you're using a different
|
97
|
+
shell)
|
98
|
+
|
99
|
+
## todo
|
100
|
+
|
101
|
+
* Add bitbucket support.
|
102
|
+
* work out kinks with more complicated destinations
|
103
|
+
* use git@github instead of https:// for read/write access
|
104
|
+
|
105
|
+
## Copying
|
106
|
+
|
107
|
+
MIT license
|
data/Rakefile
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
17
|
+
gem.name = "dotmation"
|
18
|
+
gem.homepage = "http://github.com/jtprince/dotmation"
|
19
|
+
gem.license = "MIT"
|
20
|
+
gem.summary = %Q{ruby dsl/config to softlink dotfiles}
|
21
|
+
gem.description = %Q{ruby dsl/config to softlink dotfiles that is somewhat github aware}
|
22
|
+
gem.email = "jtprince@gmail.com"
|
23
|
+
gem.authors = ["John T. Prince"]
|
24
|
+
# dependencies defined in Gemfile
|
25
|
+
end
|
26
|
+
Jeweler::RubygemsDotOrgTasks.new
|
27
|
+
|
28
|
+
require 'rspec/core'
|
29
|
+
require 'rspec/core/rake_task'
|
30
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
31
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
32
|
+
end
|
33
|
+
|
34
|
+
task :default => :spec
|
35
|
+
|
36
|
+
require 'rdoc/task'
|
37
|
+
Rake::RDocTask.new do |rdoc|
|
38
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
39
|
+
|
40
|
+
rdoc.rdoc_dir = 'rdoc'
|
41
|
+
rdoc.title = "dotmation #{version}"
|
42
|
+
rdoc.rdoc_files.include('README*')
|
43
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
44
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
data/bin/dotmation
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'dotmation'
|
4
|
+
require 'optparse'
|
5
|
+
require 'open-uri'
|
6
|
+
|
7
|
+
progname = File.basename(__FILE__)
|
8
|
+
|
9
|
+
opt = {}
|
10
|
+
opts = OptionParser.new do |op|
|
11
|
+
op.banner = "usage: #{progname} <cmd>"
|
12
|
+
op.separator ""
|
13
|
+
op.separator "commands:"
|
14
|
+
op.separator " update"
|
15
|
+
op.separator ""
|
16
|
+
op.separator "options:"
|
17
|
+
op.on("--config <arg>", "arg may be a url or file", "may also be a github user name", "expects: #{Dotmation::DEFAULT_CONFIG_GITHUB_PATH}") do |v|
|
18
|
+
opt[:config] = v
|
19
|
+
end
|
20
|
+
end
|
21
|
+
opts.parse!
|
22
|
+
|
23
|
+
if ARGV.size == 0
|
24
|
+
puts opts
|
25
|
+
exit
|
26
|
+
end
|
27
|
+
|
28
|
+
(methd, *args) = ARGV
|
29
|
+
|
30
|
+
methd=methd.to_sym
|
31
|
+
|
32
|
+
args = [opt[:config]].compact
|
33
|
+
Dotmation.new(*args).send(methd)
|
data/dotmation.gemspec
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "dotmation"
|
8
|
+
s.version = "0.0.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["John T. Prince"]
|
12
|
+
s.date = "2013-05-09"
|
13
|
+
s.description = "ruby dsl/config to softlink dotfiles that is somewhat github aware"
|
14
|
+
s.email = "jtprince@gmail.com"
|
15
|
+
s.executables = ["dotmation"]
|
16
|
+
s.extra_rdoc_files = [
|
17
|
+
"LICENSE",
|
18
|
+
"README.md"
|
19
|
+
]
|
20
|
+
s.files = [
|
21
|
+
"Gemfile",
|
22
|
+
"LICENSE",
|
23
|
+
"README.md",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"bin/dotmation",
|
27
|
+
"dotmation.gemspec",
|
28
|
+
"lib/dotmation.rb",
|
29
|
+
"lib/dotmation/config_reader.rb",
|
30
|
+
"lib/dotmation/repo.rb",
|
31
|
+
"script/bootstrap-ruby-env.sh",
|
32
|
+
"spec/dotmation/repo_spec.rb",
|
33
|
+
"spec/dotmation_spec.rb",
|
34
|
+
"spec/spec_helper.rb",
|
35
|
+
"spec/testfiles/config"
|
36
|
+
]
|
37
|
+
s.homepage = "http://github.com/jtprince/dotmation"
|
38
|
+
s.licenses = ["MIT"]
|
39
|
+
s.require_paths = ["lib"]
|
40
|
+
s.rubygems_version = "1.8.23"
|
41
|
+
s.summary = "ruby dsl/config to softlink dotfiles"
|
42
|
+
|
43
|
+
if s.respond_to? :specification_version then
|
44
|
+
s.specification_version = 3
|
45
|
+
|
46
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
47
|
+
s.add_development_dependency(%q<rspec>, ["~> 2.13.0"])
|
48
|
+
s.add_development_dependency(%q<rdoc>, ["~> 4.0.0"])
|
49
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.3.5"])
|
50
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.8.4"])
|
51
|
+
s.add_development_dependency(%q<simplecov>, ["~> 0.7.1"])
|
52
|
+
else
|
53
|
+
s.add_dependency(%q<rspec>, ["~> 2.13.0"])
|
54
|
+
s.add_dependency(%q<rdoc>, ["~> 4.0.0"])
|
55
|
+
s.add_dependency(%q<bundler>, ["~> 1.3.5"])
|
56
|
+
s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
|
57
|
+
s.add_dependency(%q<simplecov>, ["~> 0.7.1"])
|
58
|
+
end
|
59
|
+
else
|
60
|
+
s.add_dependency(%q<rspec>, ["~> 2.13.0"])
|
61
|
+
s.add_dependency(%q<rdoc>, ["~> 4.0.0"])
|
62
|
+
s.add_dependency(%q<bundler>, ["~> 1.3.5"])
|
63
|
+
s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
|
64
|
+
s.add_dependency(%q<simplecov>, ["~> 0.7.1"])
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
data/lib/dotmation.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'dotmation/config_reader'
|
4
|
+
require 'dotmation/repo'
|
5
|
+
|
6
|
+
class Dotmation
|
7
|
+
|
8
|
+
CONFIG_HOME = ENV['XDG_CONFIG_HOME'] || "#{ENV['HOME']}/.config"
|
9
|
+
DEFAULT_CONFIG_PATH = CONFIG_HOME + '/dotmation/config'
|
10
|
+
DEFAULT_CONFIG_GITHUB_REPO = "dotfiles"
|
11
|
+
DEFAULT_CONFIG_GITHUB_PATH = "config/dotmation/config"
|
12
|
+
GITHUB_REPO_BASE = "https://github.com"
|
13
|
+
DEFAULT_REPO_CACHE_DIR = "~/dotfile_repo"
|
14
|
+
|
15
|
+
attr_accessor :config_data
|
16
|
+
|
17
|
+
attr_accessor :data
|
18
|
+
attr_accessor :repos
|
19
|
+
|
20
|
+
# quick check to see if this looks like a dotmation config file
|
21
|
+
def is_config?
|
22
|
+
@config_data.match(/dot|xdg/)
|
23
|
+
end
|
24
|
+
|
25
|
+
# arg is the path to the config file (checks for existence first), a url or
|
26
|
+
# a github name. If given a file then it can give line number error
|
27
|
+
# messages.
|
28
|
+
def initialize(arg=DEFAULT_CONFIG_PATH)
|
29
|
+
@config_data =
|
30
|
+
if File.exist?(arg)
|
31
|
+
@config_filename = arg
|
32
|
+
IO.read(arg)
|
33
|
+
else # url or github name
|
34
|
+
uri =
|
35
|
+
if arg.include?("://")
|
36
|
+
arg
|
37
|
+
else
|
38
|
+
"https://raw.github.com/#{arg}/#{DEFAULT_CONFIG_GITHUB_REPO}/master/#{DEFAULT_CONFIG_GITHUB_PATH}"
|
39
|
+
end
|
40
|
+
open(uri) {|io| io.read }
|
41
|
+
end
|
42
|
+
warn "couldn't find config file locally or on github" unless is_config?
|
43
|
+
read_config!
|
44
|
+
end
|
45
|
+
|
46
|
+
def repo_cache
|
47
|
+
if @repo_cache
|
48
|
+
@repo_cache
|
49
|
+
else
|
50
|
+
@repo_cache =
|
51
|
+
if @data[:repo_cache]
|
52
|
+
File.expand_path(@data[:repo_cache])
|
53
|
+
else
|
54
|
+
File.expand_path(DEFAULT_REPO_CACHE_DIR)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def update(opts={})
|
60
|
+
unless opts[:no_update_github]
|
61
|
+
update_github_repos!
|
62
|
+
end
|
63
|
+
link!
|
64
|
+
end
|
65
|
+
|
66
|
+
def link!
|
67
|
+
repos.each(&:link!)
|
68
|
+
end
|
69
|
+
|
70
|
+
def update_github_repos!
|
71
|
+
FileUtils.mkpath(repo_cache) unless File.directory?(repo_cache)
|
72
|
+
Dir.chdir(repo_cache) do
|
73
|
+
repos_grouped_by_name(:github).each do |user_repo, repos|
|
74
|
+
repos.each {|r| r.cache_dir = repo_cache }
|
75
|
+
(user, repo) = user_repo.split('/')
|
76
|
+
FileUtils.mkdir(user) unless File.directory?(user)
|
77
|
+
Dir.chdir(user) do
|
78
|
+
if File.directory?(repo)
|
79
|
+
Dir.chdir(repo) { print `git pull` }
|
80
|
+
else
|
81
|
+
print `git clone #{GITHUB_REPO_BASE}/#{user}/#{repo}.git`
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def repos_grouped_by_name(type=:github)
|
89
|
+
repos.select {|r| r.type == type }.group_by {|r| r.repo_name }
|
90
|
+
end
|
91
|
+
|
92
|
+
def read_config!
|
93
|
+
(@data, @repos) = ConfigReader.new.read(@config_data, @config_filename)
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'dotmation/repo'
|
2
|
+
|
3
|
+
class Dotmation
|
4
|
+
|
5
|
+
class ConfigReader
|
6
|
+
# returns a list of links and a hash of any other values given outside
|
7
|
+
# standard blocks
|
8
|
+
def read(config_data, config_filename=nil)
|
9
|
+
@available_repos = Repo.classes_as_lc_symbols
|
10
|
+
@data = {}
|
11
|
+
@repos = []
|
12
|
+
args = [config_filename].compact
|
13
|
+
eval( config_data, binding, *args )
|
14
|
+
[@data, @repos]
|
15
|
+
end
|
16
|
+
|
17
|
+
def method_missing(methd, *argv, &block)
|
18
|
+
if Dotmation::Repo::Link::METHODS.include?(methd)
|
19
|
+
@repos.last.links << Dotmation::Repo::Link.new(methd, *argv)
|
20
|
+
elsif @available_repos.include?(methd) && block
|
21
|
+
@repos << Repo.const_get(methd.to_s.capitalize).new( *argv )
|
22
|
+
instance_eval(&block)
|
23
|
+
else
|
24
|
+
arg = (argv.size==1 ? argv.first : argv)
|
25
|
+
@data[methd] = arg
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
class Dotmation
|
4
|
+
module Repo
|
5
|
+
Sys = FileUtils
|
6
|
+
|
7
|
+
Link = Struct.new(:methd, :file, :linkname)
|
8
|
+
class Link
|
9
|
+
METHODS = [:dot, :cfg, :ln]
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.classes_as_lc_symbols
|
13
|
+
self.constants.map {|v| v.to_s.downcase.to_sym }
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_accessor :path
|
17
|
+
attr_accessor :links
|
18
|
+
|
19
|
+
def initialize(path)
|
20
|
+
@path = path
|
21
|
+
@links = []
|
22
|
+
end
|
23
|
+
|
24
|
+
def type
|
25
|
+
self.class.to_s.downcase.split('::').last.to_sym
|
26
|
+
end
|
27
|
+
|
28
|
+
class Local
|
29
|
+
include Repo
|
30
|
+
end
|
31
|
+
|
32
|
+
class Github
|
33
|
+
include Repo
|
34
|
+
attr_accessor :cache_dir
|
35
|
+
|
36
|
+
def path_parts
|
37
|
+
@path_parts ||= path.split('/')
|
38
|
+
end
|
39
|
+
|
40
|
+
def repo_name
|
41
|
+
path_parts[0,2].join('/')
|
42
|
+
end
|
43
|
+
|
44
|
+
def user
|
45
|
+
path_parts.first
|
46
|
+
end
|
47
|
+
|
48
|
+
def project
|
49
|
+
path_parts[1]
|
50
|
+
end
|
51
|
+
|
52
|
+
def extra_path
|
53
|
+
path_parts[2..-1].join('/')
|
54
|
+
end
|
55
|
+
|
56
|
+
# makes sure the directory exists. If it is a file, deletes the file
|
57
|
+
# and makes a directory
|
58
|
+
def ensure_dir(dir)
|
59
|
+
if File.exist?(dir)
|
60
|
+
unless File.directory?(dir)
|
61
|
+
File.rm_f(dir)
|
62
|
+
ensure_dir(dir)
|
63
|
+
end
|
64
|
+
else
|
65
|
+
Sys.mkpath(dir)
|
66
|
+
end
|
67
|
+
true
|
68
|
+
end
|
69
|
+
|
70
|
+
def no_trailing_slash(dir)
|
71
|
+
(dir[-1] == '/') ? dir[0...-1] : dir
|
72
|
+
end
|
73
|
+
|
74
|
+
# returns true if defined and there is a trailing slash
|
75
|
+
def target_is_dir?(dir)
|
76
|
+
dir && (dir[-1] == '/')
|
77
|
+
end
|
78
|
+
|
79
|
+
def ensure_underdir( link )
|
80
|
+
dir = File.dirname(link)
|
81
|
+
Sys.mkpath(dir)
|
82
|
+
end
|
83
|
+
|
84
|
+
def link!(opts={})
|
85
|
+
opts[:home] ||= ENV['HOME']
|
86
|
+
opts[:config_home] ||= Dotmation::CONFIG_HOME
|
87
|
+
[:home, :config_home].each {|sym| opts[sym] = no_trailing_slash(opts[sym]) }
|
88
|
+
|
89
|
+
ensure_dir( opts[:config_home] )
|
90
|
+
ensure_dir( opts[:home] )
|
91
|
+
|
92
|
+
Dir.chdir(cache_dir) do
|
93
|
+
Dir.chdir(self.path) do
|
94
|
+
@links.each do |link|
|
95
|
+
target_is_dir = target_is_dir?(link.linkname)
|
96
|
+
symlink =
|
97
|
+
case link.methd
|
98
|
+
when :cfg
|
99
|
+
File.join( opts[:config_home], link.linkname || '' )
|
100
|
+
when :dot
|
101
|
+
if link.linkname
|
102
|
+
File.join( opts[:home], link.linkname )
|
103
|
+
else
|
104
|
+
File.join( opts[:home], (link.file[0]=='.') ? link.file : ".#{link.file}" )
|
105
|
+
end
|
106
|
+
when :ln
|
107
|
+
if link.linkname
|
108
|
+
File.join( opts[:home], link.linkname )
|
109
|
+
else
|
110
|
+
File.join( opts[:home], link.file )
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
if link.linkname && link.linkname.include?('/')
|
115
|
+
ensure_underdir( symlink )
|
116
|
+
end
|
117
|
+
ensure_dir( symlink ) if target_is_dir
|
118
|
+
if File.exist?(symlink) && !File.directory?(symlink)
|
119
|
+
File.unlink(symlink)
|
120
|
+
end
|
121
|
+
file_to_link = File.expand_path(link.file)
|
122
|
+
#puts "TO LINK AN D SYMLINK:"
|
123
|
+
#p File.exist?(file_to_link)
|
124
|
+
#p file_to_link
|
125
|
+
#p symlink
|
126
|
+
Sys.ln_sf(file_to_link, symlink)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
# ensures that we have a recent version of ruby installed
|
4
|
+
# and kicks things over to initialize.rb
|
5
|
+
|
6
|
+
set -o pipefail
|
7
|
+
|
8
|
+
pushd $HOME
|
9
|
+
|
10
|
+
if [ -f /etc/debian_version ]; then
|
11
|
+
RBENV_PREREQS="git curl zlib1g-dev build-essential libssl-dev libreadline-dev"
|
12
|
+
echo "debian based system"
|
13
|
+
echo "going to install prereqs: $RBENV_PREREQS"
|
14
|
+
sudo apt-get install $RBENV_PREREQS
|
15
|
+
fi
|
16
|
+
|
17
|
+
# rbenv
|
18
|
+
if [ ! -d ~/.rbenv ]; then
|
19
|
+
git clone git://github.com/sstephenson/rbenv.git .rbenv
|
20
|
+
export PATH="$HOME/.rbenv/bin:$PATH"
|
21
|
+
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.profile
|
22
|
+
if [ -f ~/.bash_profile ]; then
|
23
|
+
mv -f ~/.bash_profile ~/dot-bash_profile.orig
|
24
|
+
fi
|
25
|
+
eval "$(rbenv init -)"
|
26
|
+
fi
|
27
|
+
|
28
|
+
# ruby-build
|
29
|
+
if [ ! -d ~/.rbenv/plugins/ruby-build ]; then
|
30
|
+
git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
|
31
|
+
fi
|
32
|
+
export PATH="$HOME/.rbenv/plugins/ruby-build/bin:$PATH"
|
33
|
+
|
34
|
+
# what is the latest stable ruby build?
|
35
|
+
latest_ruby=`rbenv install --list | grep 'p[0-9]\+' | tail -1`
|
36
|
+
|
37
|
+
# install it if we don't have it
|
38
|
+
our_ruby=`rbenv versions | grep -o '[0-9\.]\+-p[0-9]\+' | tail -1`
|
39
|
+
|
40
|
+
if [ "$our_ruby" == "$latest_ruby" ]; then
|
41
|
+
rbenv install "$latest_ruby"
|
42
|
+
rbenv rehash
|
43
|
+
fi
|
44
|
+
|
45
|
+
gem install dotmation
|
46
|
+
|
47
|
+
cat <<-MESSAGE
|
48
|
+
___ ___ ___
|
49
|
+
/\ \ /\ \ /\ \
|
50
|
+
/::\ \ /::\ \ \:\ \
|
51
|
+
/:/\:\__\ /:/\:\__\ /::\__\
|
52
|
+
\:\/:/ / \:\/:/ / /:/\/__/
|
53
|
+
\::/ / \::/ / \/__/
|
54
|
+
\/__/ \/__/
|
55
|
+
___ ___ ___ ___ ___ ___
|
56
|
+
/\__\ /\ \ /\ \ /\ \ /\ \ /\__\
|
57
|
+
/::L_L_ /::\ \ \:\ \ _\:\ \ /::\ \ /:| _|_
|
58
|
+
/:/L:\__\ /::\:\__\ /::\__\ /\/::\__\ /:/\:\__\ /::|/\__\
|
59
|
+
\/_/:/ / \/\::/ / /:/\/__/ \::/\/__/ \:\/:/ / \/|::/ /
|
60
|
+
/:/ / /:/ / \/__/ \:\__\ \::/ / |:/ /
|
61
|
+
\/__/ \/__/ \/__/ \/__/ \/__/
|
62
|
+
|
63
|
+
If you already have a dotmation config file in the expected location
|
64
|
+
(~/.config/dotmation/config) then just:
|
65
|
+
|
66
|
+
dotmation update
|
67
|
+
|
68
|
+
If you don't have thinks linked up yet, you need to initialize:
|
69
|
+
|
70
|
+
dotmation init <path/to/dotmation/config>
|
71
|
+
|
72
|
+
# or, if you have the file on github: (dotfiles/config/dotmation/config)
|
73
|
+
dotmation init <github-user-name>
|
74
|
+
|
75
|
+
[Many thanks to the excellent programmers of 'fresh' for inspiration]
|
76
|
+
MESSAGE
|
77
|
+
|
78
|
+
popd
|
79
|
+
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'fileutils'
|
4
|
+
require 'dotmation'
|
5
|
+
|
6
|
+
describe Dotmation::Repo do
|
7
|
+
|
8
|
+
describe 'making cfg links' do
|
9
|
+
|
10
|
+
before do
|
11
|
+
@preval = ENV['XDG_CONFIG_HOME']
|
12
|
+
@cache_dir = File.expand_path(TESTFILES + '/tmp_github')
|
13
|
+
@internal_git_dir = @cache_dir + '/user/project'
|
14
|
+
FileUtils.mkpath @internal_git_dir
|
15
|
+
@file = @internal_git_dir + "/myfile"
|
16
|
+
File.write(@file, 'hiya')
|
17
|
+
end
|
18
|
+
|
19
|
+
specify 'cfg makes proper links to xdg spec' do
|
20
|
+
cfg_dir = File.expand_path(TESTFILES + '/tmp_cfg')
|
21
|
+
|
22
|
+
repo = Dotmation::Repo::Github.new('user/project')
|
23
|
+
repo.cache_dir = @cache_dir
|
24
|
+
|
25
|
+
repo.links << Dotmation::Repo::Link.new(:cfg, "myfile")
|
26
|
+
repo.links << Dotmation::Repo::Link.new(:cfg, "myfile", "diff-name")
|
27
|
+
repo.links << Dotmation::Repo::Link.new(:cfg, "myfile", "indir/")
|
28
|
+
|
29
|
+
repo.link!(config_home: cfg_dir)
|
30
|
+
|
31
|
+
%w(myfile diff-name indir/myfile).each do |linkname|
|
32
|
+
link = cfg_dir + '/' + linkname
|
33
|
+
File.symlink?(link).should be_true
|
34
|
+
IO.read(link).should == 'hiya'
|
35
|
+
end
|
36
|
+
FileUtils.rm_rf cfg_dir
|
37
|
+
end
|
38
|
+
|
39
|
+
specify 'dot makes proper links to home dir' do
|
40
|
+
home_dir = File.expand_path(TESTFILES + '/tmp_home')
|
41
|
+
repo = Dotmation::Repo::Github.new('user/project')
|
42
|
+
repo.cache_dir = @cache_dir
|
43
|
+
|
44
|
+
repo.links << Dotmation::Repo::Link.new(:dot, "myfile")
|
45
|
+
repo.links << Dotmation::Repo::Link.new(:dot, "myfile", ".AnotherName")
|
46
|
+
repo.links << Dotmation::Repo::Link.new(:dot, "myfile", "subdir/AnotherNameLower")
|
47
|
+
repo.links << Dotmation::Repo::Link.new(:dot, "myfile", "NoLeadingDot")
|
48
|
+
repo.links << Dotmation::Repo::Link.new(:dot, "myfile", "subdir2/")
|
49
|
+
|
50
|
+
repo.link!(home: home_dir)
|
51
|
+
|
52
|
+
%w(.myfile .AnotherName subdir/AnotherNameLower NoLeadingDot subdir2/myfile).each do |linkname|
|
53
|
+
link = home_dir + '/' + linkname
|
54
|
+
File.symlink?(link).should be_true
|
55
|
+
IO.read(link).should == 'hiya'
|
56
|
+
end
|
57
|
+
FileUtils.rm_rf home_dir
|
58
|
+
end
|
59
|
+
|
60
|
+
specify 'ln just makes the link to home dir' do
|
61
|
+
home_dir = File.expand_path(TESTFILES + '/tmp_home')
|
62
|
+
repo = Dotmation::Repo::Github.new('user/project')
|
63
|
+
repo.cache_dir = @cache_dir
|
64
|
+
|
65
|
+
repo.links << Dotmation::Repo::Link.new(:ln, "myfile")
|
66
|
+
repo.links << Dotmation::Repo::Link.new(:ln, "myfile", ".AnotherName")
|
67
|
+
repo.links << Dotmation::Repo::Link.new(:ln, "myfile", "subdir/AnotherNameLower")
|
68
|
+
repo.links << Dotmation::Repo::Link.new(:ln, "myfile", "NoLeadingDot")
|
69
|
+
repo.links << Dotmation::Repo::Link.new(:ln, "myfile", "subdir2/")
|
70
|
+
|
71
|
+
repo.link!(home: home_dir)
|
72
|
+
|
73
|
+
%w(myfile .AnotherName subdir/AnotherNameLower NoLeadingDot subdir2/myfile).each do |linkname|
|
74
|
+
link = home_dir + '/' + linkname
|
75
|
+
File.symlink?(link).should be_true
|
76
|
+
IO.read(link).should == 'hiya'
|
77
|
+
end
|
78
|
+
FileUtils.rm_rf home_dir
|
79
|
+
end
|
80
|
+
|
81
|
+
after do
|
82
|
+
ENV['XDG_CONFIG_HOME'] = @preval
|
83
|
+
FileUtils.rm_rf @cache_dir
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'dotmation'
|
4
|
+
|
5
|
+
describe Dotmation do
|
6
|
+
describe 'reading a config file' do
|
7
|
+
before do
|
8
|
+
@config = TESTFILES + "/config"
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'can read it' do
|
12
|
+
dotmation = Dotmation.new(@config)
|
13
|
+
end
|
14
|
+
|
15
|
+
describe 'the data' do
|
16
|
+
|
17
|
+
let(:dotmation) { Dotmation.new(@config) }
|
18
|
+
|
19
|
+
it 'knows data' do
|
20
|
+
data = dotmation.data
|
21
|
+
data.should be_an(Hash)
|
22
|
+
data[:repo_cache].should == "spec/testfiles/tmprepos"
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'has repos with links' do
|
26
|
+
repos = dotmation.repos
|
27
|
+
repos.size.should == 4
|
28
|
+
repos.map(&:type).partition.to_a.should == [:github, :github, :local, :github]
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'knows which git repos it needs to get' do
|
32
|
+
dotmation.repos_grouped_by_name.keys.should == ["jtprince/dotfiles", "robbyrussell/oh-my-zsh"]
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
describe 'an update' do
|
38
|
+
#describe 'an update', :pending => 'only run occasionally -- requires internet' do
|
39
|
+
let(:dotmation) { Dotmation.new(@config) }
|
40
|
+
|
41
|
+
before(:all) do
|
42
|
+
@tmprepos_dir = TESTFILES + "/tmprepos"
|
43
|
+
end
|
44
|
+
|
45
|
+
# turn on when you want to test github download
|
46
|
+
it 'downloads github repos' do
|
47
|
+
dotmation.update
|
48
|
+
["jtprince/dotfiles", "robbyrussell/oh-my-zsh"].each do |path|
|
49
|
+
base = @tmprepos_dir + "/" + path
|
50
|
+
git_file = base + "/.git"
|
51
|
+
File.exist?( git_file ).should be_true
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'updates existing repos' do
|
56
|
+
dotmation.update
|
57
|
+
end
|
58
|
+
|
59
|
+
after(:all) do
|
60
|
+
FileUtils.rm_rf(@tmprepos_dir) if File.directory?(@tmprepos_dir)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
SimpleCov.start
|
3
|
+
|
4
|
+
require 'rspec'
|
5
|
+
|
6
|
+
# Requires supporting files with custom matchers and macros, etc,
|
7
|
+
# in ./support/ and its subdirectories.
|
8
|
+
#Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
9
|
+
|
10
|
+
RSpec.configure do |config|
|
11
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
12
|
+
end
|
13
|
+
|
14
|
+
TESTFILES = File.expand_path(File.dirname(__FILE__) + "/testfiles")
|
@@ -0,0 +1,29 @@
|
|
1
|
+
|
2
|
+
repo_cache "spec/testfiles/tmprepos" # where to put all the github repos
|
3
|
+
|
4
|
+
github "jtprince/dotfiles/config" do # stored in ~/dotrepos/jtprince/dotfiles
|
5
|
+
cfg 'dotmation' # symlink ~/.config/dotmation
|
6
|
+
cfg 'dunstrc' # symlink ~/.config/dunstrc
|
7
|
+
cfg 'zsh' # symlink ~/.config/zsh
|
8
|
+
cfg 'i3/config', 'i3/' # symlink ~/.config/i3/config
|
9
|
+
|
10
|
+
dot 'Xresources' # symlink ~/.Xresources
|
11
|
+
dot 'Xresources', '.Xdefaults' # symlink ~/.Xdefaults -> Xresources
|
12
|
+
dot 'zsh/zshenv' # symlink ~/.zshenv
|
13
|
+
end
|
14
|
+
|
15
|
+
github "jtprince/dotfiles" do
|
16
|
+
ln 'bin'
|
17
|
+
ln 'bin', '~/local/'
|
18
|
+
ln 'bin', '~/local/bin' # same as directly above
|
19
|
+
ln 'bin', '~/local' # would link to local if not exist or local/bin if local existed
|
20
|
+
end
|
21
|
+
|
22
|
+
# always interpreted from $HOME
|
23
|
+
local "Dropbox/special_stash" do
|
24
|
+
dot "dot-fonts", ".fonts"
|
25
|
+
end
|
26
|
+
|
27
|
+
github "robbyrussell/oh-my-zsh" do
|
28
|
+
cfg '.' # symlink ~/.config/oh-my-zsh
|
29
|
+
end
|
metadata
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dotmation
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- John T. Prince
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-05-09 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 2.13.0
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 2.13.0
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rdoc
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 4.0.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: 4.0.0
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: bundler
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 1.3.5
|
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: 1.3.5
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: jeweler
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 1.8.4
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 1.8.4
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: simplecov
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ~>
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 0.7.1
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ~>
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 0.7.1
|
94
|
+
description: ruby dsl/config to softlink dotfiles that is somewhat github aware
|
95
|
+
email: jtprince@gmail.com
|
96
|
+
executables:
|
97
|
+
- dotmation
|
98
|
+
extensions: []
|
99
|
+
extra_rdoc_files:
|
100
|
+
- LICENSE
|
101
|
+
- README.md
|
102
|
+
files:
|
103
|
+
- Gemfile
|
104
|
+
- LICENSE
|
105
|
+
- README.md
|
106
|
+
- Rakefile
|
107
|
+
- VERSION
|
108
|
+
- bin/dotmation
|
109
|
+
- dotmation.gemspec
|
110
|
+
- lib/dotmation.rb
|
111
|
+
- lib/dotmation/config_reader.rb
|
112
|
+
- lib/dotmation/repo.rb
|
113
|
+
- script/bootstrap-ruby-env.sh
|
114
|
+
- spec/dotmation/repo_spec.rb
|
115
|
+
- spec/dotmation_spec.rb
|
116
|
+
- spec/spec_helper.rb
|
117
|
+
- spec/testfiles/config
|
118
|
+
homepage: http://github.com/jtprince/dotmation
|
119
|
+
licenses:
|
120
|
+
- MIT
|
121
|
+
post_install_message:
|
122
|
+
rdoc_options: []
|
123
|
+
require_paths:
|
124
|
+
- lib
|
125
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
126
|
+
none: false
|
127
|
+
requirements:
|
128
|
+
- - ! '>='
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '0'
|
131
|
+
segments:
|
132
|
+
- 0
|
133
|
+
hash: 2585038009321147917
|
134
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
135
|
+
none: false
|
136
|
+
requirements:
|
137
|
+
- - ! '>='
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: '0'
|
140
|
+
requirements: []
|
141
|
+
rubyforge_project:
|
142
|
+
rubygems_version: 1.8.23
|
143
|
+
signing_key:
|
144
|
+
specification_version: 3
|
145
|
+
summary: ruby dsl/config to softlink dotfiles
|
146
|
+
test_files: []
|