dotstrap 0.1.0

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,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 13228e7638010414944c3e805f6d4811dca803e1
4
+ data.tar.gz: 1e4669204ab6d0ef4477de3abad526647c21b7e0
5
+ SHA512:
6
+ metadata.gz: 391562df75f5595bc22723ccf8ae3a687ff036eca55292e74dd019fe6a2ba388acc2a60269d92a2282d27041fee6f92d6ca5c5906ca9adce157362b824bcbd09
7
+ data.tar.gz: 368eada68300c2001e80bb60f5e5b4f3e2657697ae92b93e6a12d3ca43315d71128103ee7f5c8d8844c2a1202d77286b459f70b6e17e8c509166733a6cb1b198
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,11 @@
1
+ # Contributing to dotstrap
2
+
3
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
4
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
5
+ * Fork the project.
6
+ * Start a feature/bugfix branch.
7
+ * Commit and push until you are happy with your contribution.
8
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
9
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
10
+
11
+
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'colorize', '~> 0.7'
4
+ gem 'parallel', '~> 1.6'
5
+ gem 'thor', '~> 0.19'
6
+
7
+ group :development do
8
+ gem 'rspec', '~> 3.3'
9
+ gem 'yard', '~> 0.7'
10
+ gem 'rdoc', '~> 3.12'
11
+ gem 'bundler', '~> 1.0'
12
+ gem 'jeweler', '~> 2.0'
13
+ gem 'simplecov', '~> 0.10'
14
+ gem 'factory_girl', '~> 4.0'
15
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2015 William Myers
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,97 @@
1
+ # dotstrap
2
+ [![Gem Version](https://badge.fury.io/rb/dotstrap.svg)](https://badge.fury.io/rb/dotstrap)
3
+ [![Build Status](https://travis-ci.org/mkwmms/dotstrap.svg)](https://travis-ci.org/mkwmms/dotstrap)
4
+ [![Code Climate](https://codeclimate.com/github/mkwmms/dotstrap/badges/gpa.svg)](https://codeclimate.com/github/mkwmms/dotstrap)
5
+ [![Inline docs](http://inch-ci.org/github/mkwmms/dotstrap.svg?branch=master)](http://inch-ci.org/github/mkwmms/dotstrap)
6
+ [![Dependency Status](https://gemnasium.com/mkwmms/dotstrap.svg)](https://gemnasium.com/mkwmms/dotstrap)
7
+
8
+ Downloads repositories from GitHub in parallel and symbolically links and/or
9
+ creates a file to be sourced in your `~/.zshrc`, `~/.bash_profile`, or `~/.config/fish/config.fish`
10
+
11
+ ## get it
12
+
13
+ ```bash
14
+ gem install dotstrap
15
+ ```
16
+
17
+ __or stay on the bleeding edge:__
18
+
19
+ requires [bundler]
20
+
21
+ ```bash
22
+ git clone https://github.com/mkwmms/dotstrap.git
23
+ ```
24
+
25
+ ```bash
26
+ rake install
27
+ ```
28
+
29
+ ## use it
30
+
31
+ download (or update) and configure `REPOs`:
32
+ ```bash
33
+ ds install REPO|FILE
34
+ ```
35
+
36
+ completely remove any symbolic links, `source` statements from dotstrap's config file, & the repository itself:
37
+ ```bash
38
+ ds uninstall REPO
39
+ ```
40
+
41
+ list the URL and install path for all currently installed repositories:
42
+ ```bash
43
+ ds list [REPO]
44
+ ```
45
+
46
+ `REPO` is a GitHub repository slug like `mkwmms/dotstrap-osx`
47
+
48
+ `FILE` is a newline separated list of `REPOS`
49
+
50
+ ## how it works
51
+
52
+ #### bash
53
+
54
+ add `source "$XDG_CONFIG_HOME/dotstrap/config.bash"` to your `~/.bash_profile` or similar
55
+
56
+ - `*.bash` files' paths are written to: `$XDG_CONFIG_HOME/dotstrap/config.bash`
57
+ - `*.sh` files' paths are written to: `$XDG_CONFIG_HOME/dotstrap/config.bash`
58
+
59
+ #### zsh
60
+
61
+ add `source "$XDG_CONFIG_HOME/dotstrap/dotstrap.zsh"` to your `~/.zshrc`
62
+
63
+ - `*.zsh` files' paths are written to: `$XDG_CONFIG_HOME/dotstrap/config.zsh`
64
+ - `*.sh` files' paths are written to: `$XDG_CONFIG_HOME/dotstrap/config.zsh`
65
+
66
+ #### fish
67
+
68
+ add `source "$XDG_CONFIG_HOME/dotstrap/config.fish"` to your `~/.config/fish/config.fish`
69
+
70
+ - `./functions/*.fish` are symbolically linked under `~/.config/fish/functions/`
71
+ - `./completions/*.fish` are symbolically linked under `~/.config/fish/completions/`
72
+ - all other `*.fish` files' paths are written to: `$XDG_CONFIG_HOME/dotstrap/config.fish`
73
+
74
+ _Note_: if `$XDG_CONFIG_HOME` is not set, it defaults to `~/.config`. Read about the [XDG] base directory spec.
75
+
76
+ ## in the wild
77
+ The entire purpose of `dotstrap` is to help you make your dotfiles modular while still keeping your prompt speedy. I also wanted to be able to use my [dotfiles] on bash, [zsh] and [fish] (yes I use all three on a daily basis).
78
+
79
+ There are many repositories out there that will work out of the box with `dotstrap` and many more that would only require minimal tweaking to get them to work.
80
+
81
+ Check out the [wiki] for a good list of repos to get you started.
82
+
83
+ ## similar projects
84
+ - [antibody]: super fast, great app written in go. It only does ZSH and it is dynamic (it doesn't create a static file that can be sourced from your shell's init file), but man those microseconds are precious when it comes to loading my shell prompt. I still use it sometimes though because it is pretty dang cool.
85
+
86
+
87
+ [dotfiles]: https://github.com/mkwmms/dotfiles
88
+ [wiki]: https://github.com/mkwmms/dotstrap/wiki
89
+
90
+ [XDG]: http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
91
+
92
+ [homebrew]: https://github.com/Homebrew/homebrew
93
+ [bundler]: https://github.com/bundler/bundler/
94
+ [antibody]: https://github.com/caarlos0/antibody
95
+ [zsh]: http://zsh.sourceforge.net
96
+ [fish]: http://fishshell.com/
97
+ [fasd]: https://github.com/clvv/fasd
data/Rakefile ADDED
@@ -0,0 +1,49 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ require_relative 'lib/dotstrap'
4
+
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.name = Dotstrap::NAME
17
+ gem.version = Dotstrap::VERSION
18
+ gem.homepage = Dotstrap::HOMEPAGE
19
+ gem.license = 'MIT'
20
+ gem.summary = Dotstrap::SUMMARY
21
+ gem.description = Dotstrap::DESCRIPTION
22
+ # gem.email = Dotstrap::EMAIL
23
+ gem.authors = Dotstrap::AUTHOR
24
+ gem.require_paths = ['lib']
25
+ gem.executables = ['ds']
26
+ gem.required_ruby_version = '>=1.9.2'
27
+ gem.metadata = { 'source_code' => Dotstrap::SOURCE_URL,
28
+ 'documentation' => Dotstrap::DOC_URL
29
+ }
30
+ # dependencies defined in Gemfile
31
+ end
32
+ Jeweler::RubygemsDotOrgTasks.new
33
+
34
+ require 'rspec/core'
35
+ require 'rspec/core/rake_task'
36
+ RSpec::Core::RakeTask.new(:spec) do |spec|
37
+ spec.pattern = FileList['spec/**/*_spec.rb']
38
+ end
39
+
40
+ desc 'Code coverage detail'
41
+ task :simplecov do
42
+ ENV['COVERAGE'] = 'true'
43
+ Rake::Task['spec'].execute
44
+ end
45
+
46
+ task default: :spec
47
+
48
+ require 'yard'
49
+ YARD::Rake::YardocTask.new
data/bin/ds ADDED
@@ -0,0 +1,176 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'logger'
4
+ require 'thor'
5
+ require 'dotstrap'
6
+ require 'colorize'
7
+
8
+ # Initialize logging
9
+ $LOG = Logger.new(STDOUT)
10
+ $LOG.level = Logger::WARN
11
+ $LOG.formatter = proc do |severity, datetime, progname, msg|
12
+ case (severity)
13
+ when 'ANY'
14
+ "#{msg}\n"
15
+ when 'DEBUG'
16
+ "#{'Debug'.underline}: #{datetime}: #{msg}\n"
17
+ when 'INFO'
18
+ "#{msg}\n"
19
+ when 'WARN'
20
+ "#{'Warning'.colorize(:yellow).underline}: #{msg}\n"
21
+ else
22
+ "#{severity.colorize(:red).underline}: #{datetime} #{msg}\n"
23
+ end
24
+ end
25
+
26
+ def __repo_format_desc; <<-DESC
27
+ REPO is a GitHub repository slug in the form: `username/repository`
28
+
29
+ If REPO is a file: read a newline seperated list of repositories
30
+ (in the form specified above)
31
+ \x5Lines starting with `#` are treated as comments and are ignored.
32
+ DESC
33
+ end
34
+
35
+ module Dotstrap
36
+ class Dotstrap::Cli < Thor
37
+ class_option 'verbose', type: :boolean, aliases: '-v',
38
+ desc: 'Enable verbose output mode'
39
+ class_option 'debug', type: :boolean, aliases: '-d',
40
+ desc: 'Enable debug output mode'
41
+ # class_option "quiet", :type => :boolean, :aliases => "-q",
42
+ # :desc => "Supress all output"
43
+ map %w[--version -V] => :__print_version
44
+
45
+ desc "--version, -V", "Print the version and exit"
46
+ def __print_version
47
+ puts "#{Dotstrap::NAME.colorize(:blue)} #{Dotstrap::VERSION}"
48
+ exit
49
+ end
50
+
51
+ desc 'install REPO...', 'Download and configure REPO'
52
+ long_desc <<-LONGDESC
53
+ Download REPO(s) & set up the configuration file(s) so they can
54
+ be loaded by the shell environment
55
+ by creating a file to be sourced from within your shell startup file
56
+ and/or symbolically linking relevant files.
57
+
58
+ #{__repo_format_desc}
59
+
60
+ Remember to source dotstrap's config file in your shell's startup file:
61
+ \x5 `echo "source #{Dotstrap.config_file}" >> #{Dotstrap.shell_profile}`
62
+
63
+ Examples:
64
+ \x5 Download https://github.com/mkwmms/dotstrap-osx to
65
+ #{Dotstrap.config_home}
66
+ and creates #{Dotstrap.config_file} with commands to
67
+ source all relevant configure files
68
+ \x5 $ ds install mkwmms/dotstrap-osx
69
+
70
+ Download all the repositories listed in the file ~/.config/repos.txt
71
+ \x5 $ ds install ~/.config/repos.txt
72
+ LONGDESC
73
+ def install(repo, *args)
74
+ args << repo # so thor will complain when you call `install` with no args
75
+ repos = []
76
+ args.each do |repo|
77
+ if File.exist?(repo)
78
+ File.open(repo).each do |line|
79
+ # FIXME: strip everything afer '#' until newline (repo # comment)
80
+ repos << line.strip unless line.start_with?('#')
81
+ end
82
+ else
83
+ repos << repo
84
+ end
85
+ end
86
+ repos = repos.reject(&:empty?)
87
+
88
+ __set_log_level
89
+ $LOG.debug { "REPO ARGS:#{repos}" }
90
+ Dotstrap::Configuration.new(repos).configure
91
+ end
92
+
93
+ desc 'uninstall REPO...', 'Remove specified REPO'
94
+ long_desc <<-LONGDESC
95
+ Removes REPO's shell configuration file(s) and
96
+ lines from dotstraps's config file.
97
+
98
+ #{__repo_format_desc}
99
+ LONGDESC
100
+ def uninstall(repo, *args)
101
+ args << repo # so thor will complain when you call `uninstall` with no args
102
+ repos = []
103
+ args.each do |repo|
104
+ if File.exist?(repo)
105
+ File.open(repo).each do |line|
106
+ args << line.strip unless line.start_with?('#')
107
+ end
108
+ else
109
+ repos << repo
110
+ end
111
+ end
112
+ repos = repos.reject(&:empty?)
113
+
114
+ __set_log_level
115
+ $LOG.debug { "REPO ARGS:#{repos}" }
116
+ Dotstrap::Configuration.new(repos).remove
117
+ end
118
+
119
+ desc 'list [REPO...]',
120
+ 'Print directory path & URL for currently installed REPO'
121
+ long_desc <<-LONGDESC
122
+ Print directory path & URL for currently installed REPO OR
123
+ print directory path & URL for all currently installed repositories
124
+ if REPO is not specified
125
+
126
+ #{__repo_format_desc}
127
+ LONGDESC
128
+ def list(*args)
129
+ repos = []
130
+ if args.empty?
131
+ Dotstrap::Configuration.new(Dotstrap.installed_repos).list
132
+ return
133
+ end
134
+
135
+ args.each do |repo|
136
+ if File.exist?(repo)
137
+ File.open(repo).each do |line|
138
+ args << line.strip unless line.start_with?('#')
139
+ end
140
+ else
141
+ repos << repo
142
+ end
143
+ end
144
+ repos = repos.reject(&:empty?)
145
+
146
+ __set_log_level
147
+ $LOG.debug { "REPO ARGS:#{repos}" }
148
+ Dotstrap::Configuration.new(repos).list
149
+ end
150
+
151
+ private
152
+
153
+ def __set_log_level(level = nil)
154
+ # $LOG.close; return if options[:quiet]
155
+ unless level
156
+ level =
157
+ if options[:verbose]
158
+ Logger::INFO
159
+ elsif options[:debug]
160
+ Logger::DEBUG
161
+ else
162
+ Logger::WARN
163
+ end
164
+ end
165
+ $LOG.level = level
166
+ # $LOG.warn { __garbled_output_warning_string } if $LOG.info?
167
+ end
168
+
169
+ def __garbled_output_warning_string
170
+ 'Output might be slightly out of order because' \
171
+ ' thread synchronization is expensive just for pretty output.'
172
+ end
173
+ end
174
+ end
175
+
176
+ Dotstrap::Cli.start(ARGV)
data/dotstrap.gemspec ADDED
@@ -0,0 +1,84 @@
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
+ # stub: dotstrap 0.1.0 ruby lib
6
+
7
+ Gem::Specification.new do |s|
8
+ s.name = "dotstrap"
9
+ s.version = "0.1.0"
10
+
11
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
+ s.metadata = { "documentation" => "http://www.rubydoc.info/github/mkwmms/dotstrap/master/Dotstrap", "source_code" => "http://github.com/mkwmms/dotstrap" } if s.respond_to? :metadata=
13
+ s.require_paths = ["lib"]
14
+ s.authors = ["William Myers"]
15
+ s.date = "2015-11-04"
16
+ s.description = "bootstrap your shell dotfiles in parallel from GitHub repos"
17
+ s.executables = ["ds"]
18
+ s.extra_rdoc_files = [
19
+ "LICENSE.txt",
20
+ "README.md"
21
+ ]
22
+ s.files = [
23
+ ".document",
24
+ ".rspec",
25
+ "CONTRIBUTING.md",
26
+ "Gemfile",
27
+ "LICENSE.txt",
28
+ "README.md",
29
+ "Rakefile",
30
+ "bin/ds",
31
+ "dotstrap.gemspec",
32
+ "lib/dotstrap.rb",
33
+ "lib/dotstrap/git.rb",
34
+ "lib/dotstrap/shell.rb",
35
+ "spec/bundle_spec.rb",
36
+ "spec/shell_spec.rb",
37
+ "spec/spec_helper.rb"
38
+ ]
39
+ s.homepage = "http://github.com/mkwmms/dotstrap"
40
+ s.licenses = ["MIT"]
41
+ s.required_ruby_version = Gem::Requirement.new(">= 1.9.2")
42
+ s.rubygems_version = "2.4.5.1"
43
+ s.summary = "bootstrap your shell dotfiles in parallel from GitHub repos"
44
+
45
+ if s.respond_to? :specification_version then
46
+ s.specification_version = 4
47
+
48
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
49
+ s.add_runtime_dependency(%q<colorize>, ["~> 0.7"])
50
+ s.add_runtime_dependency(%q<parallel>, ["~> 1.6"])
51
+ s.add_runtime_dependency(%q<thor>, ["~> 0.19"])
52
+ s.add_development_dependency(%q<rspec>, ["~> 3.3"])
53
+ s.add_development_dependency(%q<yard>, ["~> 0.7"])
54
+ s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
55
+ s.add_development_dependency(%q<bundler>, ["~> 1.0"])
56
+ s.add_development_dependency(%q<jeweler>, ["~> 2.0"])
57
+ s.add_development_dependency(%q<simplecov>, ["~> 0.10"])
58
+ s.add_development_dependency(%q<factory_girl>, ["~> 4.0"])
59
+ else
60
+ s.add_dependency(%q<colorize>, ["~> 0.7"])
61
+ s.add_dependency(%q<parallel>, ["~> 1.6"])
62
+ s.add_dependency(%q<thor>, ["~> 0.19"])
63
+ s.add_dependency(%q<rspec>, ["~> 3.3"])
64
+ s.add_dependency(%q<yard>, ["~> 0.7"])
65
+ s.add_dependency(%q<rdoc>, ["~> 3.12"])
66
+ s.add_dependency(%q<bundler>, ["~> 1.0"])
67
+ s.add_dependency(%q<jeweler>, ["~> 2.0"])
68
+ s.add_dependency(%q<simplecov>, ["~> 0.10"])
69
+ s.add_dependency(%q<factory_girl>, ["~> 4.0"])
70
+ end
71
+ else
72
+ s.add_dependency(%q<colorize>, ["~> 0.7"])
73
+ s.add_dependency(%q<parallel>, ["~> 1.6"])
74
+ s.add_dependency(%q<thor>, ["~> 0.19"])
75
+ s.add_dependency(%q<rspec>, ["~> 3.3"])
76
+ s.add_dependency(%q<yard>, ["~> 0.7"])
77
+ s.add_dependency(%q<rdoc>, ["~> 3.12"])
78
+ s.add_dependency(%q<bundler>, ["~> 1.0"])
79
+ s.add_dependency(%q<jeweler>, ["~> 2.0"])
80
+ s.add_dependency(%q<simplecov>, ["~> 0.10"])
81
+ s.add_dependency(%q<factory_girl>, ["~> 4.0"])
82
+ end
83
+ end
84
+
@@ -0,0 +1,52 @@
1
+ require 'colorize'
2
+ require 'logger'
3
+
4
+ module Dotstrap
5
+ # TODO: split this into Git < Downloader class
6
+ class Dotstrap::Git
7
+ attr_accessor :url, :repo,
8
+ :repo_path, :repo_name,
9
+ :github_user, :github_project
10
+
11
+ def initialize(repo, dest_dir = Dotstrap.config_home)
12
+ @repo = repo
13
+ # TODO: allow an option to specify to download with SSH or HTTPs from Git
14
+ @url = "https://github.com/#{@repo}"
15
+ partition = @repo.partition("/")
16
+ @github_user = partition[0]
17
+ @github_project = @repo_name = partition[2]
18
+ @repo_path = File.join(dest_dir, "#{@github_user}-#{@repo_name}")
19
+ # @repo_path = File.join(dest_dir, @github_user, @repo_name)
20
+ end
21
+
22
+ # FIXME: if user is not logged in to Git the prompt for username/password
23
+ # is mangled because the threads are not synchronized
24
+ def clone(url = @url, repo_path = @repo_path, repo = @repo)
25
+ if Dir.exist?(repo_path)
26
+ return pull(repo_path)
27
+ end
28
+ return false unless system('git', 'clone', *git_verbosity, url, repo_path)
29
+ $LOG.debug { "CLONE #{repo} #{url} #{repo_path}" }
30
+ $LOG.unknown { "#{'=> '.colorize(:blue)}#{repo}\nupdated" }
31
+ repo_path
32
+ end
33
+
34
+ def pull(repo_path = @repo_path, repo = @repo)
35
+ Dir.chdir(repo_path)
36
+ return false unless system('git', 'pull', *git_verbosity, repo_path)
37
+ $LOG.debug { "PULL #{repo} #{url} #{repo_path}" }
38
+ $LOG.unknown { "#{'=> '.colorize(:blue)}#{repo}\nupdated" }
39
+ repo_path
40
+ end
41
+
42
+ private
43
+
44
+ def git_verbosity
45
+ if $LOG.debug?
46
+ '--verbose'
47
+ else
48
+ return '--quiet'
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,177 @@
1
+ require 'logger'
2
+
3
+ module Dotstrap
4
+ class Dotstrap::Shell
5
+ # TODO: cleanup shell class & split it into 3+ classes with inheritence
6
+ attr_accessor :repo_path
7
+
8
+ # TODO: how to handle load order? ie. load path.fish first
9
+ def initialize(repo_path)
10
+ @repo_path = repo_path
11
+ end
12
+
13
+ def configure(repo_dir = @repo_path)
14
+ configure_fish(repo_dir) if should_configure_fish?
15
+ configure_zsh(repo_dir)
16
+ configure_bash(repo_dir)
17
+ $LOG.unknown { "configuration complete" }
18
+ end
19
+
20
+ def unconfigure(repo_dir = @repo_path)
21
+ return unless Dir.exist?(repo_dir)
22
+ unconfigure_fish(repo_dir) if should_configure_fish?
23
+ unconfigure_zsh(repo_dir)
24
+ unconfigure_bash(repo_dir)
25
+ FileUtils.rm_r(repo_dir, force: true, secure: true)
26
+ $LOG.unknown { "removed: #{repo_dir}\n" }
27
+ end
28
+
29
+ def configure_fish(repo_dir)
30
+ fish_functions(repo_dir).each do |f|
31
+ link_config_file(f, File.join(Dotstrap.shell_config_home('fish'),
32
+ 'functions'))
33
+ end
34
+
35
+ fish_completions(repo_dir).each do |f|
36
+ link_config_file(f, File.join(Dotstrap.shell_config_home('fish'),
37
+ 'completions'))
38
+ end
39
+
40
+ write_config_file(fish_configs(repo_dir), config_file('fish'))
41
+ end
42
+
43
+ def unconfigure_fish(repo_dir)
44
+ fish_functions(repo_dir).each do |f|
45
+ file = File.join(Dotstrap.shell_config_home('fish'), 'functions',
46
+ File.basename(f))
47
+ rm_config_file(file)
48
+ end
49
+
50
+ fish_completions(repo_dir).each do |f|
51
+ file = File.join(Dotstrap.shell_config_home('fish'), 'completions',
52
+ File.basename(f))
53
+ rm_config_file(file)
54
+ end
55
+
56
+ unwrite_config_file(fish_configs(repo_dir), config_file('fish'))
57
+ end
58
+
59
+ def configure_zsh(repo_dir)
60
+ write_config_file(zsh_configs(repo_dir), config_file('zsh'))
61
+ end
62
+
63
+ def unconfigure_zsh(repo_dir)
64
+ unwrite_config_file(zsh_configs(repo_dir), config_file('zsh'))
65
+ end
66
+
67
+ def configure_bash(repo_dir)
68
+ write_config_file(bash_configs(repo_dir), config_file('bash'))
69
+ end
70
+
71
+ def unconfigure_bash(repo_dir)
72
+ unwrite_config_file(bash_configs(repo_dir), config_file('bash'))
73
+ end
74
+
75
+ def rm_config_file(file)
76
+ FileUtils.rm_rf file
77
+ end
78
+
79
+ def config_file(sh, dir = Dotstrap.config_home)
80
+ File.join(dir, "config.#{sh}")
81
+ end
82
+
83
+ private
84
+
85
+ def write_config_file(repo_config_files, dotstrap_config_file)
86
+ return if repo_config_files.empty?
87
+ repo_config_files.each do |file|
88
+ append_config_file(file, dotstrap_config_file)
89
+ $LOG.info { "configured: #{file}" }
90
+ end
91
+ end
92
+
93
+ def unwrite_config_file(repo_config_files, dotstrap_config_file)
94
+ return if repo_config_files.empty?
95
+ repo_config_files.each do |file|
96
+ unappend_config_file(file, dotstrap_config_file)
97
+ $LOG.info { "removed: #{file}" }
98
+ end
99
+ end
100
+
101
+ # TODO: only open config file once, write all source strings at once
102
+ def append_config_file(file_to_source, config_file)
103
+ source_str = "source \"#{file_to_source}\"\n"
104
+ if File.exist?(config_file)
105
+ # Do not write source_str if we have already written it before
106
+ return if File.readlines(config_file).grep(source_str).any?
107
+ end
108
+ File.open(config_file, 'a') { |f| f.write source_str }
109
+ end
110
+
111
+ def unappend_config_file(file_to_unsource, config_file)
112
+ return unless File.exist?(config_file)
113
+ Dir.mktmpdir do |tmp_dir|
114
+ source_str = "source \"#{file_to_unsource}\""
115
+ tmp_config_file = File.join(tmp_dir, File.basename(config_file))
116
+ File.open(tmp_config_file, 'w') do |tmp_file|
117
+ File.foreach(file_to_unsource) do |line|
118
+ tmp_file.write line unless line.chomp == source_str
119
+ end
120
+ end
121
+ FileUtils.mv(tmp_config_file, config_file)
122
+ end
123
+ end
124
+
125
+ def link_config_file(src, dest_dir)
126
+ return unless File.exist?(src)
127
+ $LOG.debug { "LINK_CONFIG_FILE:#{src} to #{dest_dir}" }
128
+ dst = File.join(dest_dir, File.basename(src))
129
+ # FIXME: fails if dest_dir for link is a broken symbolic link
130
+ # parent = Pathname.new(dest_dir).parent
131
+ # FileUtils.mkdir parent unless Dir.exist? parent
132
+ FileUtils.mkdir_p dest_dir unless Dir.exist? dest_dir
133
+ FileUtils.ln_s src, dst, force: true
134
+ $LOG.info { "linked: #{src} to #{dst}" }
135
+ end
136
+
137
+ def fish_configs(dir, excl = 'fish_prompt.fish')
138
+ c = []
139
+ Dir.glob(File.join(dir, '*.fish')) { |f| c << f unless f.end_with?(excl) }
140
+ $LOG.debug { "FISH_CONFIGS:#{c}" }
141
+ c
142
+ end
143
+
144
+ def fish_functions(dir, incl = ['fish_prompt.fish'])
145
+ funcs = []
146
+ funcs << Dir.glob(File.join(dir, 'functions', '*.fish'))
147
+ incl.each do |f|
148
+ f = File.join(dir, f)
149
+ funcs << f if File.exist?(f)
150
+ end
151
+ $LOG.debug { "FISH_FUNCTIONS:#{funcs.flatten}" }
152
+ funcs.flatten
153
+ end
154
+
155
+ def fish_completions(dir)
156
+ c = Dir.glob(File.join(dir, 'completions', '*.fish'))
157
+ $LOG.debug { "FISH_COMPLETIONS:#{c}" }
158
+ c
159
+ end
160
+
161
+ def bash_configs(dir)
162
+ c = Dir.glob(File.join(dir, '**', '*.{sh,bash}'))
163
+ $LOG.debug { "BASH_CONFIGS:#{c}" }
164
+ c
165
+ end
166
+
167
+ def zsh_configs(dir)
168
+ c = Dir.glob(File.join(dir, '**', '*.{sh,zsh}'))
169
+ $LOG.debug { "ZSH_CONFIGS:#{c}" }
170
+ c
171
+ end
172
+
173
+ def should_configure_fish?
174
+ Dir.exist?(Dotstrap.shell_config_home('fish'))
175
+ end
176
+ end
177
+ end
data/lib/dotstrap.rb ADDED
@@ -0,0 +1,151 @@
1
+ require 'rubygems'
2
+ require 'fileutils'
3
+ require 'parallel'
4
+ require 'pathname'
5
+ require_relative 'dotstrap/git'
6
+ require_relative 'dotstrap/shell'
7
+
8
+ module Dotstrap
9
+ NAME = 'dotstrap'
10
+ EXE_NAME = 'ds'
11
+ VERSION = '0.1.0'
12
+ AUTHOR = 'William Myers'
13
+ HOMEPAGE = 'http://github.com/mkwmms/dotstrap'
14
+ SOURCE_URL = 'http://github.com/mkwmms/dotstrap'
15
+ DOC_URL = 'http://www.rubydoc.info/github/mkwmms/dotstrap/master/Dotstrap'
16
+ SUMMARY = 'bootstrap your shell dotfiles in parallel from GitHub repos'
17
+ DESCRIPTION = 'bootstrap your shell dotfiles in parallel from GitHub repos'
18
+ # DESCRIPTION = 'downloads repositories from GitHub in parallel and ' \
19
+ # 'symbolically links and/or creates a file to be sourced ' \
20
+ # 'according to your shell (fish, zsh, bash)'
21
+
22
+ class << self
23
+ require 'pathname'
24
+
25
+ def config_home
26
+ return ENV['DOTSTRAP_CONFIG_HOME'] if ENV.has_key?('DOTSTRAP_CONFIG_HOME')
27
+
28
+ config_dir = ENV.fetch('XDG_CONFIG_HOME', Dir.home)
29
+ if config_dir == Dir.home
30
+ File.join(config_dir, '.config', 'dotstrap')
31
+ else
32
+ File.join(config_dir, 'dotstrap')
33
+ end
34
+ end
35
+
36
+ def shell_name
37
+ # FIXME: bad to rely on SHELL environment variable to determine shell?
38
+ shell =
39
+ case ENV['SHELL']
40
+ when %r{/(ba)?sh} then
41
+ 'bash'
42
+ when %r{/zsh} then
43
+ 'zsh'
44
+ when %r{/fish} then
45
+ 'fish'
46
+ else
47
+ raise RuntimeError, ENV['SHELL']
48
+ end
49
+ $LOG.debug { "SHELL_NAME:#{shell}" }
50
+ shell
51
+ end
52
+
53
+ def shell_profile(shell = shell_name)
54
+ profile =
55
+ case shell
56
+ when 'bash' then
57
+ bash_profile = ''
58
+ ['.bash_profile' '.profile'].each do |file|
59
+ bash_profile = File.join(Dir.home, file)
60
+ break if File.exist?(bash_profile)
61
+ end
62
+ bash_profile
63
+ when 'zsh' then
64
+ File.join(Dir.home, '.zshrc')
65
+ when 'fish' then
66
+ File.join(Dir.home, '.config', 'fish', 'config.fish')
67
+ # File.exist?(file) ? file : fail ShellProfileError, "Fish shell config file not found
68
+ end
69
+ $LOG.debug { "SHELL_PROFILE:#{profile}" }
70
+ profile.strip unless profile.nil?
71
+ end
72
+
73
+ def shell_config_home(shell = shell_name)
74
+ h = Pathname.new(shell_profile(shell)).parent
75
+ $LOG.debug { "SHELL_CONFIG_HOME:#{h}" }
76
+ h
77
+ end
78
+
79
+ def config_file(shell = shell_name)
80
+ File.join(config_home, "config.#{shell}")
81
+ end
82
+
83
+ def installed_repo_paths
84
+ Dir[File.join(config_home, '**')]
85
+ end
86
+
87
+ def installed_repos
88
+ repos = []
89
+ installed_repo_paths.each do |repo_path|
90
+ # next unless repo_path.include?('-') && File.directory?(repo_path)
91
+ repo = File.basename(repo_path)
92
+ repos << repo.sub(/-/,'/')
93
+ end
94
+ repos
95
+ end
96
+ end
97
+
98
+ class Dotstrap::Configuration
99
+ require 'fileutils'
100
+
101
+ attr_accessor :repos
102
+
103
+ def initialize(repos = nil)
104
+ @repos = repos unless repos.nil?
105
+ FileUtils.mkdir_p(Dotstrap.config_home)
106
+ end
107
+
108
+ def configure(dest_dir = Dotstrap.config_home, repos = @repos)
109
+ if Dotstrap.shell_name == 'fish'
110
+ FileUtils.mkdir_p(File.join(fish_config_home, 'functions'))
111
+ FileUtils.mkdir_p(File.join(fish_config_home, 'completions'))
112
+ end
113
+
114
+ Parallel.map(repos, in_threads: 16) do |r|
115
+ bundle = Dotstrap::Git.new(r, dest_dir)
116
+ path = bundle.clone
117
+ puts path
118
+ load_configs([path]) if path
119
+ end
120
+ end
121
+
122
+ def remove(repos = @repos)
123
+ repos.each do |repo|
124
+ bundle = Dotstrap::Git.new(repo)
125
+ repo_path = bundle.repo_path
126
+ shell = Dotstrap::Shell.new(repo_path)
127
+ shell.unconfigure(repo_path)
128
+ end
129
+ end
130
+
131
+ # TODO: return a data-structure from `list`, do not print out
132
+ def list(repos = @repos)
133
+ repos.each do |repo|
134
+ bundle = Dotstrap::Git.new(repo)
135
+ next unless Dir.exist?(bundle.repo_path)
136
+ puts "#{'=>'.colorize(:blue)} #{repo}"
137
+ puts bundle.url
138
+ puts bundle.repo_path
139
+ # TODO: only output all associated files on --verbose
140
+ puts "\n"
141
+ end
142
+ end
143
+
144
+ def load_configs(repo_path)
145
+ repo_path.each do |r|
146
+ shell = Dotstrap::Shell.new(r)
147
+ shell.configure(repo_path)
148
+ end
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,34 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+ require 'dotstrap/bundle'
3
+
4
+ describe Dotstrap::Bundle do
5
+ before :all do
6
+ @repos = { 'mkwmms/fish-osx' => %w(ql.fish),
7
+ 'mkwmms/fish-basic' =>
8
+ %w(clear.fish mkcd.fish port_kill.fish port_top.fish td.fish)
9
+ }
10
+ @dotstrap_config_home = Dir.mktmpdir('test_dotstrap_config_home_')
11
+ # @bundle = FactoryGirl.create :bundle(@config_home, @repos)
12
+ @bundle = Dotstrap::Bundle.new(@dotstrap_config_home, @repos.keys)
13
+ end
14
+
15
+ describe '#download' do
16
+ it 'can download real life repos' do
17
+ @bundle.download(@repos.keys)
18
+ @repos.each do |repo, expected_files|
19
+ # TODO: or should I uses checksums or something?
20
+ actual_files = []
21
+ Dir.glob(@dotstrap_config_home + repo + '**/*.{fish,sh,zsh}') do |f|
22
+ actual_files.push File.basename(f)
23
+ end
24
+ actual_files.each { |actual| expect(actual).to eql(expected_files) }
25
+ end
26
+ end
27
+ end
28
+
29
+ # TODO: write test for load_configs
30
+
31
+ after :all do
32
+ FileUtils.rm_r @dotstrap_config_home, force: true
33
+ end
34
+ end
@@ -0,0 +1,71 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+ require 'dotstrap/shell'
3
+
4
+ describe Dotstrap::Shell do
5
+ before :all do
6
+ # FIXME: decouple test config_files and define in each test
7
+ @config_files = { 'mkwmms/fish-osx' => %w(ql.fish),
8
+ # 'mkwmms/fish-basic/functions' =>
9
+ # %w(clear.fish mkcd.fish port_kill.fish port_top.fish td.fish)
10
+ }
11
+ @dotstrap_config_home = Dir.mktmpdir('test_dotstrap_config_home_')
12
+ @shell_config_home = Dir.mktmpdir('test_dotstrap_shell_config_home_')
13
+ # @bundle = FactoryGirl.create :bundle(@config_home, @repos)
14
+ @shell = Dotstrap::Shell.new(@dotstrap_config_home, @config_files.keys)
15
+
16
+ @config_files.each do |repo, files|
17
+ dir = File.join(@dotstrap_config_home, repo, 'functions')
18
+ FileUtils.mkdir_p dir
19
+ files.each do |f|
20
+ File.write(File.join(dir, f), 'TEST CONFIG')
21
+ end
22
+ end
23
+ end
24
+
25
+ describe 'array test' do
26
+ # This will fail if we are not using rspec >= 3.0
27
+ it 'simple match_array' do
28
+ expect([1, 2, 3]).to match_array [2, 3, 1]
29
+ end
30
+ end
31
+
32
+ describe '#fish_config_home' do
33
+ # ENV['XDG_CONFIG_HOME']
34
+ it 'gets the correct fish_config_home' do
35
+ expect(@shell.fish_config_home).to eql(File.expand_path('~/.config/fish'))
36
+ end
37
+ end
38
+
39
+ describe '#fish_functions' do
40
+ # ENV['XDG_CONFIG_HOME']
41
+ it 'gets the correct fish function files before linking' do
42
+ actual_files = []
43
+ expected_files = []
44
+ @config_files.each do |repo, files|
45
+ dir = File.join(@dotstrap_config_home, repo)
46
+ actual_files.push @shell.fish_functions(dir)
47
+ files.each do |f|
48
+ expected_files.push File.join(dir, 'functions', f)
49
+ end
50
+ end
51
+ # FIXME: worry about the fact that I need to call flatten on arrays?
52
+ expect(actual_files.flatten).to match_array(expected_files.flatten)
53
+ end
54
+ end
55
+
56
+ # describe '#configure' do
57
+ # it 'can configure 1 repo' do
58
+ # actual_files = []
59
+ # Dir.glob(@shell_config_home + 'functions/*.fish') do |f|
60
+ # actual_files.push File.basename(f)
61
+ # end
62
+ # expect(actual_files).to match_array(@config_files.values)
63
+ # end
64
+ # end
65
+
66
+ after :all do
67
+ [@dotstrap_config_home, @shell_config_home].each do |dir|
68
+ FileUtils.rm_r dir, force: true
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,33 @@
1
+ require 'simplecov'
2
+
3
+ module SimpleCov::Configuration
4
+ def clean_filters
5
+ @filters = []
6
+ end
7
+ end
8
+
9
+ SimpleCov.configure do
10
+ clean_filters
11
+ load_profile 'test_frameworks'
12
+ end
13
+
14
+ ENV["COVERAGE"] && SimpleCov.start do
15
+ add_filter "/.rvm/"
16
+ end
17
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
18
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
19
+ # Dir["#{File.dirname(__FILE__)}/../lib/**/*.rb"].each {|f| puts f; require f}
20
+
21
+ require 'rspec'
22
+ # require 'factory_girl'
23
+
24
+ # Requires supporting files with custom matchers and macros, etc,
25
+ # in ./support/ and its subdirectories.
26
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
27
+
28
+ RSpec.configure do |config|
29
+ # config.include FactoryGirl::Syntax::Methods
30
+ # config.before(:suite) do
31
+ # FactoryGirl.lint
32
+ # end
33
+ end
metadata ADDED
@@ -0,0 +1,203 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dotstrap
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - William Myers
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-11-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: colorize
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.7'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: parallel
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.6'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.6'
41
+ - !ruby/object:Gem::Dependency
42
+ name: thor
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.19'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.19'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.3'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.3'
69
+ - !ruby/object:Gem::Dependency
70
+ name: yard
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.7'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.7'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rdoc
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '3.12'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '3.12'
97
+ - !ruby/object:Gem::Dependency
98
+ name: bundler
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '1.0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '1.0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: jeweler
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '2.0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '2.0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: simplecov
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '0.10'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '0.10'
139
+ - !ruby/object:Gem::Dependency
140
+ name: factory_girl
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '4.0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '4.0'
153
+ description: bootstrap your shell dotfiles in parallel from GitHub repos
154
+ email:
155
+ executables:
156
+ - ds
157
+ extensions: []
158
+ extra_rdoc_files:
159
+ - LICENSE.txt
160
+ - README.md
161
+ files:
162
+ - ".document"
163
+ - ".rspec"
164
+ - CONTRIBUTING.md
165
+ - Gemfile
166
+ - LICENSE.txt
167
+ - README.md
168
+ - Rakefile
169
+ - bin/ds
170
+ - dotstrap.gemspec
171
+ - lib/dotstrap.rb
172
+ - lib/dotstrap/git.rb
173
+ - lib/dotstrap/shell.rb
174
+ - spec/bundle_spec.rb
175
+ - spec/shell_spec.rb
176
+ - spec/spec_helper.rb
177
+ homepage: http://github.com/mkwmms/dotstrap
178
+ licenses:
179
+ - MIT
180
+ metadata:
181
+ documentation: http://www.rubydoc.info/github/mkwmms/dotstrap/master/Dotstrap
182
+ source_code: http://github.com/mkwmms/dotstrap
183
+ post_install_message:
184
+ rdoc_options: []
185
+ require_paths:
186
+ - lib
187
+ required_ruby_version: !ruby/object:Gem::Requirement
188
+ requirements:
189
+ - - ">="
190
+ - !ruby/object:Gem::Version
191
+ version: 1.9.2
192
+ required_rubygems_version: !ruby/object:Gem::Requirement
193
+ requirements:
194
+ - - ">="
195
+ - !ruby/object:Gem::Version
196
+ version: '0'
197
+ requirements: []
198
+ rubyforge_project:
199
+ rubygems_version: 2.4.5.1
200
+ signing_key:
201
+ specification_version: 4
202
+ summary: bootstrap your shell dotfiles in parallel from GitHub repos
203
+ test_files: []