dotfu 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: cfd33a64430a135ebb5e9d655946cc5075c3e857
4
+ data.tar.gz: 8b5ea0b776586d28228074c837cfc2bf0694b050
5
+ SHA512:
6
+ metadata.gz: 7bd34205b448adfc2293bf0d3eb7e924f0868e32b62049b1ac98caca400f19b593c4ed8e411ad6efea90beb58a511dd19461577961a8261f8132d8fc00b668af
7
+ data.tar.gz: d69cccac6a0472eb8d6bf1e20a65ccdb1f6055381c2d435dc1037bd73370e044536e4da9c9b6f8344a837af17ab301cd36792283d6a6e5910e45767e4518ecca
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/.travis.yml ADDED
@@ -0,0 +1,11 @@
1
+ bundler_args: --without development
2
+
3
+ rvm:
4
+ - 1.9.2
5
+ - 1.9.3
6
+ - rbx-19mode
7
+
8
+ branches:
9
+ only:
10
+ - master
11
+ - development
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --no-private - LICENSE.txt CHANGELOG.md
data/CHANGELOG.md ADDED
File without changes
data/Gemfile ADDED
@@ -0,0 +1,29 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ group :development do
6
+ gem "bundler"
7
+ gem "rake"
8
+ gem "pry"
9
+ gem "pry-debugger"
10
+ gem "redcarpet"
11
+ gem "guard"
12
+ gem "guard-bundler"
13
+ gem "guard-rspec"
14
+ gem "guard-yard"
15
+ gem "guard-shell"
16
+ gem 'libnotify', :require => false
17
+ gem 'growl', :require => false
18
+ gem 'rb-inotify', :require => false
19
+ gem 'rb-fsevent', :require => false
20
+ gem 'rb-fchange', :require => false
21
+ end
22
+
23
+ group :test do
24
+ gem "rspec"
25
+ gem "webmock"
26
+ gem 'simplecov', :require => false
27
+ gem 'simplecov-rcov', :require => false
28
+ end
29
+
data/Guardfile ADDED
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/ruby
2
+
3
+ # Must be an array
4
+ test_cmd = [
5
+ "bundle exec dotfu install zsh",
6
+ "bundle exec dotfu uninstall zsh"
7
+ ]
8
+
9
+ guard :bundler do
10
+ watch 'Gemfile'
11
+ watch '*.gemspec'
12
+ end
13
+
14
+ guard :rspec do
15
+ watch(%r{^spec/.+_spec\.rb$})
16
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec spec/lib/#{m[1]}_spec.rb" }
17
+ watch(%r{^bin/(.+)\.rb$}) { |m| "spec/bin/#{m[1]}_spec.rb" }
18
+ watch('spec/spec_helper.rb') { "spec" }
19
+ end
20
+
21
+ # guard :yard do
22
+ # watch(%r{^lib/(.+)\.rb$})
23
+ # end
24
+
25
+ guard :shell do
26
+ watch /.*/ do |m|
27
+ puts "Time: #{Time.now}, file saved: #{m}"
28
+ test_cmd.each do |cmd|
29
+
30
+ puts "=" * 80
31
+ puts "cmd: #{cmd}"
32
+ puts `#{cmd}`
33
+ end
34
+ end
35
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,36 @@
1
+ All software in this package is covered by the MIT license and beerware (rev42).
2
+
3
+ Copyright (c) 2011 Ernie Brodeur
4
+
5
+ Permission is hereby granted, free of charge, to any person
6
+ obtaining a copy of this software and associated documentation
7
+ files (the "Software"), to deal in the Software without
8
+ restriction, including without limitation the rights to use,
9
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the
11
+ Software is furnished to do so, subject to the following
12
+ conditions:
13
+
14
+ The above copyright notice and this permission notice shall be
15
+ included in all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24
+ OTHER DEALINGS IN THE SOFTWARE.
25
+
26
+ /*
27
+ * ----------------------------------------------------------------------------
28
+ * "THE BEER-WARE LICENSE" (Revision 42):
29
+ * Ernie Brodeur wrote this package. As long as you retain this notice you
30
+ * can do whatever you want with this stuff. If we meet some day, and you think
31
+ * this stuff is worth it, you can buy me a beer in return.
32
+ * ----------------------------------------------------------------------------
33
+ */
34
+
35
+ All contributed code is licensed accordingly and accredited whenever possible.
36
+ If I make any mistake about this, please feel free to contact me at ebrodeur@ujami.net.
data/README.md ADDED
@@ -0,0 +1,73 @@
1
+ # Description
2
+
3
+ Dotfu is a shell command to help all of us manage our dotfiles. It is designed
4
+ to clone dotfiles from github and install them into your home directory in one command.
5
+
6
+ It will also allow you to manage/switch/test other peoples dotfiles on the fly.
7
+
8
+ Right now it will install/uninstall/fetch files. It will not overwrite your current files, it will abort and let you move them.
9
+
10
+ Later backup originals, generate repo, search, ...
11
+
12
+ # Usage
13
+
14
+ Dotfu is a subcommand based cli like git. It supplies various subcommands that do
15
+ the tasks for you. ```--help``` works, but it is rough.
16
+
17
+ ## Arguments
18
+
19
+ Before we go over the commands, it is important to understand the repo format you use.
20
+ I don't know of a github uri, so we will use some shorthand like this ```user@repo:branch```. Even if we do switch to a uri, I will leave this shorthand.
21
+
22
+ More about the fields:
23
+
24
+ * user: optional, if it's not supplied we try the config file for github.user
25
+ * repo: required, can be in the form of ```dotfiles-zsh``` or ```zsh```.
26
+ * branch: optional, if you want to specify the branch to use. Will switch on install, not fetch.
27
+
28
+ ## Commands
29
+
30
+ ### Currently working:
31
+
32
+ * list: list all dotfiles-* directores
33
+ * fetch: Pull down a dotfiles-<n> repo into the cache.
34
+ * install: implies fetch, then installs dotfiles-<n> based on the dotfiles.json
35
+ * uninstall: remove the contents of a repo.
36
+ * search: search github for repo's based on <pattern>.
37
+
38
+ ### Still to build
39
+
40
+ * clean: clean unused items from the cache.
41
+ * status: List which df repos that need to get updated.
42
+ * update: update repos.
43
+
44
+ ## Configfile
45
+
46
+ The config file will be a json blob. It will be named ```dotfu.json``` and
47
+ should be present at the base of the repo.
48
+
49
+ ## Fields
50
+
51
+ Currently only target_directory works.
52
+
53
+ * target_directory (optional): if not your home dir, where?
54
+ * ignore_patterns (optional): files in the repo to never install (good for readmes).
55
+ * segments (optional): see below
56
+
57
+ # Segments
58
+
59
+ Segments are labeled selections of files in a repo to install selectively.
60
+
61
+ * pre_install_script
62
+ * post_install_script
63
+ * routes
64
+
65
+ Routes are glob patterns and a target directory for them.
66
+
67
+ ## Contributing
68
+
69
+ 1. Fork it
70
+ 2. Create your feature branch (`git checkout -b feature-something`)
71
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
72
+ 4. Push to the branch (`git push origin feature-something`)
73
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require 'rspec/core/rake_task'
2
+
3
+ RSpec::Core::RakeTask.new(:spec)
4
+
5
+ task :default => :spec
6
+
7
+ require "bundler/gem_tasks"
data/bin/dotfu ADDED
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'dotfu'
4
+ require 'yaml'
5
+
6
+
7
+ require 'slop'
8
+
9
+ if !Dotfu.installed?
10
+ puts "Git does not appear to be installed, aporting."
11
+ exit 1
12
+ end
13
+
14
+ opts = Slop.parse(help:true) do
15
+ banner "Dotfu:\n"\
16
+ "DOTFILES is a string that can be user:repo or user@repo. If no user is "\
17
+ "provided, it will attempt to look one up from the git config file.\n"
18
+
19
+ on(:v, :verbose, 'Enable verbose mode')
20
+ on(:version, 'Print the version') {puts "Version #{Dotfu::VERSION}" }
21
+ on(:data_directory, "Root directory to fetch into (default: #{Bini.data_dir}/repos)")
22
+ on(:target_directory, "Change the default target directory from your home: #{Dir.home}")
23
+
24
+ # not sure that this is the right dir after install. Need to determine that.
25
+ Dir.glob("commands/*.rb").each do |file|
26
+ instance_eval open(file).read
27
+ end
28
+
29
+ command 'search' do
30
+ banner "Search for a repo globally or in a user's directory."
31
+ end
32
+ command 'clean' do
33
+ banner "Purge any unused files from the cached repos."
34
+ end
35
+ command 'status' do
36
+ banner "Spit out various stats about the cached/installed repos."
37
+ end
38
+ end
data/commands/fetch.rb ADDED
@@ -0,0 +1,16 @@
1
+ command 'fetch' do
2
+ banner "Fetch a repo into it's cache dir.\n"\
3
+ "Usage: dotfu fetch [options] DOTFILES\n"
4
+
5
+ run do |opts, args|
6
+ return nil if !args
7
+
8
+ # POC only, it still needs to check for output errors and a few other things.
9
+ args.each do |a|
10
+ repo = Dotfu::Repos.new a
11
+ output = repo.fetch
12
+ puts "Repo #{repo.repo} from: #{repo.user}:\n#{output[1]}"
13
+ end
14
+ end
15
+ end
16
+
@@ -0,0 +1,20 @@
1
+ command 'install' do
2
+ banner "Install a dotfiles from Github into your home directory."
3
+
4
+ run do |opts, args|
5
+ unless args.any?
6
+ puts 'install what?'
7
+ exit 1
8
+ end
9
+
10
+ args.each do |target|
11
+ repo = Dotfu::Repos.new target
12
+
13
+ puts "Fetching repo #{target}"
14
+ puts repo.fetch[:out]
15
+ puts "Installing #{target} to #{repo.target_dir}"
16
+ repo.install
17
+ end
18
+ puts "Complete."
19
+ end
20
+ end
data/commands/list.rb ADDED
@@ -0,0 +1,26 @@
1
+ command 'list' do
2
+ banner "List the repos of a given user."
3
+ run do |opts, args|
4
+ if args.any?
5
+ username = args.first
6
+ else
7
+ username = Dotfu.config_user
8
+ end
9
+
10
+ begin
11
+ results = Dotfu::GITHUB.repos.list(user:username).select {|r| r.name.start_with? 'dotfiles' };
12
+ rescue Exception => e
13
+ puts e
14
+ end
15
+
16
+ unless results && results.any?
17
+ puts "No suitable repositories found."
18
+ else
19
+ puts "Repositories for #{username}:"
20
+ results.each do |repo|
21
+ puts " #{repo.name}"
22
+ end
23
+ end
24
+ end
25
+ end
26
+
@@ -0,0 +1,23 @@
1
+ command 'uninstall' do
2
+ banner "Uninstall dotfiles from your home directory."
3
+
4
+ run do |opts, args|
5
+ unless args.any?
6
+ puts 'install what?'
7
+ exit 1
8
+ end
9
+
10
+ args.each do |target|
11
+ repo = Dotfu::Repos.new target
12
+
13
+ unless repo.installed?
14
+ puts "#{target} is not installed."
15
+ exit
16
+ end
17
+ puts "Uninstalling #{target} from #{repo.target_dir}"
18
+ repo.uninstall
19
+ end
20
+ puts "Complete."
21
+ end
22
+ end
23
+
@@ -0,0 +1,26 @@
1
+ // General options
2
+ // Everything is relative to this directory.
3
+ // There are no directories past this point, only files.
4
+ {
5
+ "target_directory":"/home/ebrodeur/.config/powerline",
6
+
7
+ // Ignore Patterns (optional)
8
+ // Takes an array or entry, if array it is a collection of glob or regex.
9
+ // Regex is stored in a string and detection done in application.
10
+
11
+ "ignore_patterns":["README.md", "**/*.md", "/.*/" ],
12
+
13
+ // Segments (optional)
14
+ // Segments allow for smaller parts to be installed as needed/requested.
15
+ // Each segment is a named object with a collection of pattern/location pairs.
16
+ "segments":{
17
+ "zsh":{
18
+ "pre_install_script":"filename",
19
+ "post_install_script":"filename",
20
+ "routes":{
21
+ ".zshrc":"/",
22
+ "zsh":"/"
23
+ }
24
+ }
25
+ }
26
+ }
data/dotfu.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'dotfu/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "dotfu"
8
+ spec.version = Dotfu::VERSION
9
+ spec.authors = ["Ernie Brodeur"]
10
+ spec.email = ["ebrodeur@ujami.net"]
11
+ spec.description = "Manage/sync/share dotfiles via github."
12
+ spec.summary = "More to come . . . "
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_runtime_dependency "bini"
22
+ spec.add_runtime_dependency "git"
23
+ spec.add_runtime_dependency "github_api"
24
+ spec.add_runtime_dependency "slop"
25
+ spec.add_runtime_dependency "yajl-ruby"
26
+ end
@@ -0,0 +1,9 @@
1
+ module Dotfu
2
+ module ConfigParser
3
+ def load(filename)
4
+
5
+ end
6
+
7
+ def
8
+ end
9
+ end
@@ -0,0 +1,199 @@
1
+ module Dotfu
2
+ class Repos
3
+ attr_accessor :repo
4
+ attr_accessor :branch
5
+ attr_accessor :user
6
+ attr_accessor :config_file
7
+ attr_accessor :working_dir
8
+ attr_accessor :target_dir
9
+
10
+ # r can be either a repo, or a user:repo pair.
11
+ def initialize(arg = nil)
12
+ parse_arg arg if arg
13
+ parse_config
14
+ end
15
+
16
+ ### Specialized attribute methods
17
+ def config_file
18
+ return @config_file ? @config_file : "dotfu.json"
19
+ end
20
+
21
+ # prepend repo with dotfiles- if it doesn't exist as it is set.
22
+ def repo=(word)
23
+ return @repo = word.start_with?('dotfiles-') ? word : "dotfiles-#{word}"
24
+ end
25
+
26
+ # target_dir should always return something.
27
+ def target_dir
28
+ return @target_dir ? @target_dir : Dir.home
29
+ end
30
+
31
+ # return user or the user in the config file.
32
+ def user
33
+ return @user ? @user : Dotfu.config_user
34
+ end
35
+
36
+ # return the explicit directory this repo is cloned into.
37
+ def working_dir
38
+ return nil if !repo || !user
39
+ return "#{Bini.data_dir}/repos/#{user}/#{repo}"
40
+ end
41
+
42
+ ### Work methods
43
+
44
+ # initial clone
45
+ def clone
46
+ return nil if !repo || !user
47
+ return git_cmd "clone git://github.com/#{user}/#{repo}.git #{working_dir}", false
48
+ end
49
+
50
+ # A wrapper method to clone or update a repo.
51
+ def fetch
52
+ return nil if !repo || !user
53
+ if fetched?
54
+ pull
55
+ else
56
+ clone
57
+ end
58
+ end
59
+
60
+
61
+ def install
62
+ result = git_cmd "checkout #{branch}" if branch
63
+
64
+ raise RuntimeError.new result unless result[:status].success?
65
+
66
+ # lets check if we have anything in the way, and abort instead of partially
67
+ # installing
68
+ existing_files = target_files.select {|f| File.exist? f}
69
+ raise NotImplementedError.new "File(s) exist: #{existing_files}" if existing_files.any?
70
+
71
+ # And now that we are ok with everything, lets make some fucking files.
72
+ # TODO: add deep linking (mkdir + ln_s for each target) or shallow (just the first directory)
73
+ FileUtils.mkdir_p target_dir
74
+ files.each {|file| FileUtils.ln_s working_file(file), target_file(file)}
75
+
76
+ return true
77
+ end
78
+
79
+ def pull
80
+ return nil if !repo || !user
81
+ return git_cmd "pull"
82
+ end
83
+
84
+ def uninstall
85
+ raise RuntimeError.new "Not installed." unless installed?
86
+
87
+ # ok we are not installed, lets clear the links. Later, this will restore
88
+ # the backups (or something similiar).
89
+ target_files.each {|f| FileUtils.rm f}
90
+ return true
91
+ end
92
+
93
+ ### Helper methods
94
+
95
+ # I need to make this more sophisticated. Or make a like updated? method.
96
+ def fetched?
97
+ return nil if !repo
98
+ return false if !working_dir
99
+ files = Dir.glob("#{working_dir}/**/*")
100
+
101
+ return true if files.any?
102
+ return false
103
+ end
104
+
105
+ # does it have a config file? Must be fetched or will return nil.
106
+ def config_file?
107
+ return false unless fetched?
108
+
109
+ return File.exist? "#{working_dir}/#{config_file}"
110
+ end
111
+
112
+ # returns true if every file is installed. I need to make this more indepth,
113
+ # but it will at lease ensure all files are linked to something in the working dir.
114
+ def installed?
115
+ results = target_files.map {|f| is_my_file?(f) }
116
+ return false if results.include? false
117
+ return true
118
+ end
119
+
120
+ # Return true if this file was installed from our repo.
121
+ def is_my_file?(file)
122
+ return true if File.exist?(file) && File.symlink?(file) && File.readlink(file).start_with?(working_dir)
123
+ return false
124
+ end
125
+ # return an [Array] of base filenames.
126
+ def files
127
+ if !@files
128
+ files = Dir.glob("#{working_dir}/*").map {|f| f.split(working_dir)[1][1..-1]}
129
+ files.delete config_file
130
+ @files = files
131
+ end
132
+ return @files
133
+ end
134
+
135
+ # Return the target file.
136
+ # Takes a [String] (explicit conversion) or [Array] for index lookup.
137
+ def target_file(file)
138
+ "#{target_dir}/.#{file_string(file)}"
139
+ end
140
+
141
+ # Return an [Array] of target files.
142
+ def target_files
143
+ files.map {|f| target_file f}
144
+ end
145
+
146
+ # return the working file.
147
+ # Takes a [String] (explicit conversion) or [Array] for index lookup.
148
+ def working_file(file)
149
+ "#{working_dir}/#{file_string(file)}"
150
+ end
151
+
152
+ # Return an [Array] of working files.
153
+ def working_files
154
+ files.map {|f| working_file f}
155
+ end
156
+
157
+
158
+ private
159
+ # So our input is now username@repo:branch
160
+ # Repo is the only one required.
161
+ def parse_arg(word)
162
+ if word.include? "@"
163
+ self.name,word = word.split("@")
164
+ end
165
+
166
+ if word.include? ":"
167
+ self.repo, self.branch = word.split(":")
168
+ end
169
+
170
+ self.repo = word if !self.repo
171
+ end
172
+
173
+ def parse_config
174
+ return nil unless config_file?
175
+
176
+ content = Yajl.load open("#{working_dir}/#{config_file}")
177
+ @target_dir = content["target_directory"] if content["target_directory"]
178
+ end
179
+
180
+ # Accepts a string or fixnum. Returns either the string or the files[fixnum]
181
+ # TODO: figure out a better fucking name for this.
182
+ def file_string(file)
183
+ return file.class == Fixnum ? files[file] : file
184
+ end
185
+ def git_cmd(cmd, cd = true)
186
+ if cd
187
+ pwd = Dir.pwd
188
+ Dir.chdir working_dir
189
+ end
190
+
191
+ out, err, status = Open3.capture3 "git #{cmd}"
192
+
193
+ Dir.chdir pwd if cd
194
+
195
+ return {status:status, out:out, err:err}
196
+ end
197
+
198
+ end
199
+ end
@@ -0,0 +1,3 @@
1
+ module Dotfu
2
+ VERSION = "0.1.0"
3
+ end
data/lib/dotfu.rb ADDED
@@ -0,0 +1,49 @@
1
+ require 'open3'
2
+ require 'yajl'
3
+ require 'bini'
4
+ require 'bini/config'
5
+ require 'bini/optparser'
6
+ require 'bini/sash'
7
+ require 'github_api'
8
+
9
+ require "dotfu/version"
10
+ require "dotfu/repos"
11
+
12
+ module Dotfu
13
+ extend self
14
+
15
+ # what does the config say our user is?
16
+ def config_user
17
+ if !instance_variables.include? "@config_user"
18
+ if installed?
19
+ output = `git config github.user`.chomp!
20
+ if output.empty?
21
+ @config_user = nil
22
+ else
23
+ @config_user = output
24
+ end
25
+ end
26
+ end
27
+
28
+ return @config_user
29
+ end
30
+
31
+ # Is git installed in the system?
32
+ def installed?
33
+ if !@git_installed
34
+ results = ENV["PATH"].split(":").map do |path|
35
+ File.exist?("#{path}/git")
36
+ end
37
+
38
+ @git_installed = results.include? true
39
+ end
40
+ return @git_installed
41
+ end
42
+
43
+ Bini.long_name = "dotfu"
44
+ GITHUB ||= Github.new user_agent:"Dotfu: #{Dotfu::VERSION}", auto_pagination:true
45
+ end
46
+
47
+
48
+
49
+
data/roadmap.md ADDED
@@ -0,0 +1,3 @@
1
+ ## 0.1.0
2
+
3
+ *
@@ -0,0 +1,99 @@
1
+ # Ripped without remorse from: https://github.com/cucumber/aruba/blob/master/lib/aruba/process.rb
2
+ # slightly modified for my purposes.
3
+ require 'childprocess'
4
+ require 'tempfile'
5
+ require 'shellwords'
6
+
7
+ class CLIProcess
8
+ include Shellwords
9
+
10
+ def initialize(cmd, exit_timeout = 0, io_wait = 1)
11
+ @exit_timeout = exit_timeout
12
+ @io_wait = io_wait
13
+ @io_waited = false
14
+
15
+ @cmd = cmd
16
+ @process = nil
17
+ @exit_code = nil
18
+ end
19
+
20
+ def run!(&block)
21
+ @process = ChildProcess.build(*shellwords(@cmd))
22
+ @out = Tempfile.new("binary-out")
23
+ @err = Tempfile.new("binary-err")
24
+ @process.io.stdout = @out
25
+ @process.io.stderr = @err
26
+ @process.duplex = true
27
+ @exit_code = nil
28
+ begin
29
+ @process.start
30
+ rescue ChildProcess::LaunchError => e
31
+ raise LaunchError.new(e.message)
32
+ end
33
+ yield self if block_given?
34
+ end
35
+
36
+ def stdin
37
+ @process.io.stdin
38
+ end
39
+
40
+ def output(keep_ansi = false)
41
+ stdout(keep_ansi) + stderr(keep_ansi)
42
+ end
43
+
44
+ def stdout(keep_ansi = false)
45
+ wait_for_io do
46
+ @out.rewind
47
+ filter_ansi(@out.read, keep_ansi)
48
+ end
49
+ end
50
+
51
+ def stderr(keep_ansi = false)
52
+ wait_for_io do
53
+ @err.rewind
54
+ filter_ansi(@err.read, keep_ansi)
55
+ end
56
+ end
57
+
58
+ def read_stdout(keep_ansi = false)
59
+ wait_for_io do
60
+ @process.io.stdout.flush
61
+ content = filter_ansi(open(@out.path).read, keep_ansi)
62
+ end
63
+ end
64
+
65
+ def stop(reader, keep_ansi)
66
+ return @exit_code unless @process
67
+ unless @process.exited?
68
+ @process.poll_for_exit(@exit_timeout)
69
+ end
70
+ reader.stdout stdout(keep_ansi)
71
+ reader.stderr stderr(keep_ansi)
72
+ @exit_code = @process.exit_code
73
+ @process = nil
74
+ @exit_code
75
+ end
76
+
77
+ def terminate(keep_ansi = false)
78
+ if @process
79
+ stdout(keep_ansi = false) && stderr(keep_ansi) # flush output
80
+ @process.stop
81
+ stdout(keep_ansi) && stderr(keep_ansi) # flush output
82
+ end
83
+ end
84
+
85
+ private
86
+
87
+ def wait_for_io(&block)
88
+ if @process && !@io_waited
89
+ sleep @io_wait
90
+ @io_waited = true
91
+ end
92
+ yield
93
+ end
94
+
95
+ def filter_ansi(string, keep_ansi)
96
+ keep_ansi ? string : string.gsub(/\e\[\d+(?>(;\d+)*)m/, '')
97
+ end
98
+
99
+ end
@@ -0,0 +1,8 @@
1
+ require 'spec_helper'
2
+
3
+ describe Dotfu do
4
+ describe 'Backup' do
5
+ it "will backup a file"
6
+ it "will restore a file"
7
+ end
8
+ end
@@ -0,0 +1,13 @@
1
+ if ENV["COVERAGE"] == 'true'
2
+ require 'simplecov'
3
+ require 'simplecov-rcov'
4
+
5
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
6
+ SimpleCov::Formatter::HTMLFormatter,
7
+ SimpleCov::Formatter::RcovFormatter
8
+ ]
9
+ SimpleCov.start do
10
+ add_filter "/spec/"
11
+ end
12
+ end
13
+
metadata ADDED
@@ -0,0 +1,144 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dotfu
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ernie Brodeur
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-05-31 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bini
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: git
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: github_api
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: slop
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: yajl-ruby
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: Manage/sync/share dotfiles via github.
84
+ email:
85
+ - ebrodeur@ujami.net
86
+ executables:
87
+ - dotfu
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - .gitignore
92
+ - .rspec
93
+ - .travis.yml
94
+ - .yardopts
95
+ - CHANGELOG.md
96
+ - Gemfile
97
+ - Guardfile
98
+ - LICENSE.txt
99
+ - README.md
100
+ - Rakefile
101
+ - bin/dotfu
102
+ - commands/fetch.rb
103
+ - commands/install.rb
104
+ - commands/list.rb
105
+ - commands/uninstall.rb
106
+ - config_example.json
107
+ - dotfu.gemspec
108
+ - lib/dotfu.rb
109
+ - lib/dotfu/config_parser.rb
110
+ - lib/dotfu/repos.rb
111
+ - lib/dotfu/version.rb
112
+ - roadmap.md
113
+ - spec/cli_spec_helper.rb
114
+ - spec/dotfu_spec.rb
115
+ - spec/spec_helper.rb
116
+ homepage: ''
117
+ licenses:
118
+ - MIT
119
+ metadata: {}
120
+ post_install_message:
121
+ rdoc_options: []
122
+ require_paths:
123
+ - lib
124
+ required_ruby_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - '>='
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ required_rubygems_version: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - '>='
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ requirements: []
135
+ rubyforge_project:
136
+ rubygems_version: 2.0.0
137
+ signing_key:
138
+ specification_version: 4
139
+ summary: More to come . . .
140
+ test_files:
141
+ - spec/cli_spec_helper.rb
142
+ - spec/dotfu_spec.rb
143
+ - spec/spec_helper.rb
144
+ has_rdoc: