bashman 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 +7 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.travis.yml +7 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +53 -0
- data/Rakefile +6 -0
- data/bashman.gemspec +41 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/exe/bashman +82 -0
- data/lib/bashman/homebrew.rb +35 -0
- data/lib/bashman/shell.rb +132 -0
- data/lib/bashman/version.rb +3 -0
- data/lib/bashman.rb +157 -0
- metadata +130 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 4406bc629855c0f569157e3d2e64541d461d9578199624f1c2fb4f2c8bfa39fc
|
4
|
+
data.tar.gz: 2d8913b0a9ab19edfc13033de62c5260606bb4d2b5db61612822efaaac11e049
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3ce0ffd9156b146c180e948c795c597a203c5132e07e6ee224adf19fe19033f472a2f1f808c02a9ec30278d6bac354b791b14c1ee68ff0fcbc99c18806843be3
|
7
|
+
data.tar.gz: 7c099849c04b62733c695108f4bf630e85198c00286b616e32a56f657843bc513aa5f2aa1c287628cdf8956fd9c615359a61c127f14c0cc6be39cc7dfd3bb9cd
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2019 David Bayer
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# Bashman
|
2
|
+
|
3
|
+
A Ruby gem and executable for *nix profile backup.
|
4
|
+
|
5
|
+
## Usage
|
6
|
+
|
7
|
+
This gem includes the `bashman` executable for managing profiles.
|
8
|
+
|
9
|
+
```
|
10
|
+
$ bashman -h
|
11
|
+
Usage: bashman [OPTIONS]
|
12
|
+
|
13
|
+
-a, --apply Apply saved profile
|
14
|
+
-i, --items homebrew,shell Shell components to apply or save. Defaults to 'all'.
|
15
|
+
-p, --profile PROFILE Profile name. Set to 'default' if not specified.
|
16
|
+
-s, --save Save profile settings.
|
17
|
+
-v, --verbose Turn on verbose messages.
|
18
|
+
-V, --version Show version
|
19
|
+
-y, --yes Do not ask for confirmation
|
20
|
+
-h, --help Show this help message
|
21
|
+
```
|
22
|
+
|
23
|
+
For script development, the gem provides the following classes:
|
24
|
+
|Class Name|Purpose|
|
25
|
+
|---|---|
|
26
|
+
|Profile|Overall user profile container|
|
27
|
+
|Profile::HomeBrew|Homebrew information for Mac users|
|
28
|
+
|Profile::Shell|General shell items like .profile, .bashrc, etc.|
|
29
|
+
|
30
|
+
## Configuration
|
31
|
+
Bashman looks for the `~/.bashman/config` file for configuration information. At present the only configuration is for `[shell]` and controls which shell files to include/exclude from the profile backup. Useful for limiting backup to desired configuration items and omitting sensitive and/or unnecessary components like SSH keys.
|
32
|
+
|
33
|
+
```
|
34
|
+
[shell]
|
35
|
+
exclude = .vim/bundle
|
36
|
+
include = .bash*, .git* .irb*, .iterm2*, .profile*, .vim*
|
37
|
+
```
|
38
|
+
|
39
|
+
## Development
|
40
|
+
|
41
|
+
This is still in very early stages of development and is likely to be buggy.
|
42
|
+
|
43
|
+
This was built as a learning experience that results in something useful at least to me. Because of this I'm sure there is a lot missing that should probably be included, not the least of which would be code tests. If all goes well that will be included in the not too distant future.
|
44
|
+
|
45
|
+
There are plans for adding more functionality, including applying saved profiles back to the current user.
|
46
|
+
|
47
|
+
## Contributing
|
48
|
+
|
49
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/drbayer/bashman.
|
50
|
+
|
51
|
+
## License
|
52
|
+
|
53
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/bashman.gemspec
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "bashman/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "bashman"
|
8
|
+
spec.version = Bashman::VERSION
|
9
|
+
spec.authors = ["David Bayer"]
|
10
|
+
spec.email = ["drbayer@eternalstench.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{Bash Profile Manager}
|
13
|
+
spec.description = %q{Record bash profile files and settings}
|
14
|
+
spec.homepage = "https://github.com/drbayer/bashman"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
18
|
+
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
19
|
+
# if spec.respond_to?(:metadata)
|
20
|
+
# spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
|
21
|
+
# else
|
22
|
+
# raise "RubyGems 2.0 or newer is required to protect against " \
|
23
|
+
# "public gem pushes."
|
24
|
+
# end
|
25
|
+
|
26
|
+
# Specify which files should be added to the gem when it is released.
|
27
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
28
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
29
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
30
|
+
end
|
31
|
+
spec.bindir = "exe"
|
32
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
33
|
+
spec.require_paths = ["lib"]
|
34
|
+
|
35
|
+
spec.add_development_dependency "bundler", "~> 1.16"
|
36
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
37
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
38
|
+
|
39
|
+
spec.add_runtime_dependency "json"
|
40
|
+
spec.add_runtime_dependency "parseconfig"
|
41
|
+
end
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "bashman"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/exe/bashman
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'bashman'
|
4
|
+
require 'optparse'
|
5
|
+
|
6
|
+
options = {
|
7
|
+
apply: false,
|
8
|
+
items: ['all'],
|
9
|
+
profile: 'default',
|
10
|
+
save: false,
|
11
|
+
savedir: '~/.bashman/profiles',
|
12
|
+
verbose: false,
|
13
|
+
yes: false
|
14
|
+
}
|
15
|
+
|
16
|
+
all_items = ['homebrew', 'shell']
|
17
|
+
|
18
|
+
opts = OptionParser.new do |o|
|
19
|
+
o.banner = "Usage: #{$0} [OPTIONS]"
|
20
|
+
o.separator ""
|
21
|
+
o.on("-a", "--apply", "Apply saved profile") {|v| options[:apply] = v}
|
22
|
+
o.on("-i", "--items #{all_items.join(',')}", Array, "Shell components to apply or save. Defaults to 'all'.") {|v| options[:items] = v}
|
23
|
+
o.on("-p", "--profile PROFILE", "Profile name. Set to 'default' if not specified.") {|v| options[:profile] = v}
|
24
|
+
o.on("-s", "--save", "Save profile settings.") {|v| options[:save] = v}
|
25
|
+
o.on("-v", "--verbose", "Turn on verbose messages.") {|v| options[:verbose] = v}
|
26
|
+
o.on("-V", "--version", "Show version") do
|
27
|
+
puts Bashman.version
|
28
|
+
exit
|
29
|
+
end
|
30
|
+
o.on("-y", "--yes", "Do not ask for confirmation") {|v| options[:yes] = v}
|
31
|
+
o.on_tail("-h", "--help", "Show this help message") do
|
32
|
+
puts o
|
33
|
+
exit
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
begin
|
38
|
+
opts.parse! ARGV
|
39
|
+
raise OptionParser::MissingArgument, 'PROFILE' if options[:profile].nil?
|
40
|
+
raise OptionParser::InvalidOption, "Exactly one of (--apply, --save) required." if options[:apply] == options[:save]
|
41
|
+
|
42
|
+
options[:items] = all_items if options[:items] == ['all']
|
43
|
+
items = options[:items].dup
|
44
|
+
n = items.count
|
45
|
+
1.upto(n) do
|
46
|
+
item = items.pop
|
47
|
+
if items.include?(item) or not all_items.include?(item)
|
48
|
+
raise OptionParser::InvalidArgument, 'ITEMS'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
rescue => arg_err
|
52
|
+
puts "#{arg_err.message}"
|
53
|
+
puts opts
|
54
|
+
exit
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
profile = Profile.new
|
59
|
+
|
60
|
+
### Save profile
|
61
|
+
|
62
|
+
if options[:save] then
|
63
|
+
if options[:items].include?('homebrew')
|
64
|
+
profile.add_homebrew(options[:verbose])
|
65
|
+
end
|
66
|
+
|
67
|
+
if options[:items].include?('shell')
|
68
|
+
profile.add_shell(options[:verbose])
|
69
|
+
end
|
70
|
+
|
71
|
+
if not options[:yes] then
|
72
|
+
puts "Record profile? [Y/n] "
|
73
|
+
resp = gets.strip.downcase
|
74
|
+
options[:yes] = true if ['y', 'yes', ''].include?(resp)
|
75
|
+
end
|
76
|
+
|
77
|
+
if options[:yes]
|
78
|
+
profile.save(options[:savedir], options[:overwrite], options[:verbose])
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
|
@@ -0,0 +1,35 @@
|
|
1
|
+
|
2
|
+
class Profile::HomeBrew < JSONable
|
3
|
+
|
4
|
+
include Bashman
|
5
|
+
|
6
|
+
attr_reader :casks
|
7
|
+
attr_reader :formulae
|
8
|
+
|
9
|
+
def get_installed
|
10
|
+
@installed = self.installed? if @installed.nil?
|
11
|
+
|
12
|
+
if @installed
|
13
|
+
@casks = self.get_casks
|
14
|
+
@formulae = self.get_formulae
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def installed?
|
19
|
+
path = Profile::HomeBrew.which('brew')
|
20
|
+
@installed = path.empty? ? false : true
|
21
|
+
@installed
|
22
|
+
end
|
23
|
+
|
24
|
+
protected
|
25
|
+
|
26
|
+
def get_casks
|
27
|
+
%x(brew cask list).split("\n")
|
28
|
+
end
|
29
|
+
|
30
|
+
def get_formulae
|
31
|
+
%x(brew list).split("\n")
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
@@ -0,0 +1,132 @@
|
|
1
|
+
|
2
|
+
class Profile::Shell < JSONable
|
3
|
+
include Bashman
|
4
|
+
|
5
|
+
CONFIG = self.get_config('shell')
|
6
|
+
BASEPATH = CONFIG.key?("basepath") ? File.expand_path(CONFIG["basepath"]) : File.expand_path("~/")
|
7
|
+
BLOCKSIZE = 1024
|
8
|
+
|
9
|
+
attr_reader :shell
|
10
|
+
attr_reader :dotfiles
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@shell = self.get_current
|
14
|
+
end
|
15
|
+
|
16
|
+
def get_dotfiles
|
17
|
+
exc = []
|
18
|
+
inc = []
|
19
|
+
|
20
|
+
if CONFIG.include?('exclude')
|
21
|
+
exc = CONFIG['exclude'].split(',').map {|x| x.strip}
|
22
|
+
end
|
23
|
+
|
24
|
+
if CONFIG.include?('include')
|
25
|
+
inc = CONFIG['include'].split(',').map {|x| x.strip}
|
26
|
+
else
|
27
|
+
inc = ["\.[a-zA-Z0-9-_]*"]
|
28
|
+
end
|
29
|
+
|
30
|
+
files = self.add_includes(inc)
|
31
|
+
files = self.remove_excludes(exc, files)
|
32
|
+
files.delete_if {|f| /\.bashman\/profiles/ =~ f}
|
33
|
+
|
34
|
+
@dotfiles = files
|
35
|
+
end
|
36
|
+
|
37
|
+
def save_dotfiles(tarfile, timestamp = nil, overwrite = false)
|
38
|
+
require 'fileutils'
|
39
|
+
|
40
|
+
savefile = File.expand_path(tarfile)
|
41
|
+
|
42
|
+
if File.exists?(savefile)
|
43
|
+
if not overwrite
|
44
|
+
timestamp = File.mtime(savefile).to_i if timestamp.nil?
|
45
|
+
bakfile = "#{savefile}.#{timestamp}"
|
46
|
+
File.delete(bakfile) if File.exists?(bakfile)
|
47
|
+
FileUtils.mv(savefile, bakfile)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
begin
|
52
|
+
self.tar_gz(BASEPATH, savefile, *@dotfiles)
|
53
|
+
rescue => e
|
54
|
+
puts "Error saving dotfiles: #{e.message}"
|
55
|
+
puts e.backtrace
|
56
|
+
File.delete(savefile) if File.exists?(savefile)
|
57
|
+
if not bakfile.nil? and File.exists?(bakfile)
|
58
|
+
FileUtils.mv(bakfile, savefile)
|
59
|
+
end
|
60
|
+
return 1
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
protected
|
65
|
+
|
66
|
+
def get_current
|
67
|
+
ENV['SHELL']
|
68
|
+
end
|
69
|
+
|
70
|
+
def remove_excludes(excludes, files)
|
71
|
+
excludes.each do |e|
|
72
|
+
e.gsub!('.', '\.')
|
73
|
+
e.gsub!('*', '.*')
|
74
|
+
files.delete_if {|f| /#{e}/ =~ f}
|
75
|
+
end
|
76
|
+
files
|
77
|
+
end
|
78
|
+
|
79
|
+
def add_includes(includes)
|
80
|
+
files = []
|
81
|
+
includes.each do |i|
|
82
|
+
files.concat Dir.glob(i, base: BASEPATH)
|
83
|
+
end
|
84
|
+
|
85
|
+
files.dup.each do |f|
|
86
|
+
if File.directory?("#{BASEPATH}/#{f}")
|
87
|
+
files.concat Dir.glob("#{f}/**/*", base: BASEPATH)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
files
|
91
|
+
end
|
92
|
+
|
93
|
+
def tar_gz(path, tarfile, *src)
|
94
|
+
require 'rubygems/package'
|
95
|
+
require 'find'
|
96
|
+
require 'pathname'
|
97
|
+
|
98
|
+
basepath = Pathname.new(BASEPATH)
|
99
|
+
path = Pathname.new(path)
|
100
|
+
|
101
|
+
raise ArgumentError, "Path #{path} should be an absolute path" unless path.absolute?
|
102
|
+
raise ArgumentError, "Path #{path} should be a directory" unless File.directory?(path)
|
103
|
+
raise ArgumentError, "No files/directories found to tar" if !src or src.length == 0
|
104
|
+
|
105
|
+
src.each {|p| p.sub!(/^/, "#{basepath.to_s}/")}
|
106
|
+
File.open(tarfile, "wb") do |tf|
|
107
|
+
Zlib::GzipWriter.wrap(tf) do |gz|
|
108
|
+
Gem::Package::TarWriter.new(gz) do |tar|
|
109
|
+
src.each do |f|
|
110
|
+
next if not File.file?(f)
|
111
|
+
file = Pathname.new(f)
|
112
|
+
relpath = file.relative_path_from(basepath).to_s
|
113
|
+
mode = File.stat(f).mode
|
114
|
+
size = File.stat(f).size
|
115
|
+
if File.directory?(f)
|
116
|
+
tar.mkdir(relpath, mode)
|
117
|
+
else
|
118
|
+
tar.add_file_simple(relpath, mode, size) do |tio|
|
119
|
+
File.open(f, "rb") do |rio|
|
120
|
+
while buffer = rio.read(BLOCKSIZE)
|
121
|
+
tio.write(buffer)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
data/lib/bashman.rb
ADDED
@@ -0,0 +1,157 @@
|
|
1
|
+
|
2
|
+
module Bashman
|
3
|
+
require "bashman/version"
|
4
|
+
|
5
|
+
CONFIG_PATH = File.expand_path('~/.bashman')
|
6
|
+
CONFIG = File.expand_path("#{CONFIG_PATH}/config")
|
7
|
+
|
8
|
+
FileUtils.mkdir_p(CONFIG_PATH) if not Dir.exists?(CONFIG_PATH)
|
9
|
+
FileUtils.touch(CONFIG) if not File.exists?(CONFIG)
|
10
|
+
|
11
|
+
def self.included(base)
|
12
|
+
base.extend(ClassMethods)
|
13
|
+
end
|
14
|
+
|
15
|
+
# make the following functions available in every class
|
16
|
+
module ClassMethods
|
17
|
+
def which(binary)
|
18
|
+
ret = ''
|
19
|
+
possibles = ENV["PATH"].split(File::PATH_SEPARATOR)
|
20
|
+
possibles.map {|p| File.join(p, binary)}.find {|p| ret = p if File.executable?(p)}
|
21
|
+
ret
|
22
|
+
end
|
23
|
+
|
24
|
+
def get_config(section)
|
25
|
+
require 'parseconfig'
|
26
|
+
|
27
|
+
fullconfig = ParseConfig.new(CONFIG)
|
28
|
+
config = {}
|
29
|
+
config = fullconfig[section] if fullconfig.get_params.include?(section)
|
30
|
+
config
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def Bashman.version
|
35
|
+
puts Bashman::VERSION
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
class JSONable
|
42
|
+
require 'json'
|
43
|
+
|
44
|
+
def to_hash
|
45
|
+
hash = {}
|
46
|
+
self.instance_variables.each do |var|
|
47
|
+
hash[var] = self.instance_variable_get(var)
|
48
|
+
end
|
49
|
+
hash
|
50
|
+
end
|
51
|
+
|
52
|
+
def to_json
|
53
|
+
hash = self.to_hash
|
54
|
+
hash.to_json
|
55
|
+
end
|
56
|
+
|
57
|
+
def from_json!(string)
|
58
|
+
JSON.load(string).each do |var, val|
|
59
|
+
self.instance_variable_set(var, val)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
# this is me learning how to write ruby gems
|
66
|
+
# no idea why, but if I don't put the Profile class
|
67
|
+
# in this file things break in spectacular ways
|
68
|
+
|
69
|
+
class Profile < JSONable
|
70
|
+
require "bashman/homebrew"
|
71
|
+
require "bashman/shell"
|
72
|
+
|
73
|
+
include Bashman
|
74
|
+
|
75
|
+
attr_reader :homebrew
|
76
|
+
attr_reader :shell
|
77
|
+
attr_reader :name
|
78
|
+
|
79
|
+
def initialize(profile_name = 'default')
|
80
|
+
@name = profile_name
|
81
|
+
end
|
82
|
+
|
83
|
+
def add_homebrew(verbose = false)
|
84
|
+
@homebrew = Profile::HomeBrew.new
|
85
|
+
puts "Looking for Homebrew" if verbose
|
86
|
+
if @homebrew.installed?
|
87
|
+
puts "Homebrew executable found" if verbose
|
88
|
+
puts "Getting installed homebrew packages and casks"
|
89
|
+
@homebrew.get_installed
|
90
|
+
if verbose
|
91
|
+
puts "Found formulae:"
|
92
|
+
@homebrew.formulae.each {|f| puts " #{f}"}
|
93
|
+
puts "Found casks:"
|
94
|
+
@homebrew.casks.each {|c| puts " #{c}"}
|
95
|
+
end
|
96
|
+
else
|
97
|
+
puts "Homebrew executable not found"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def add_shell(verbose = false)
|
102
|
+
@shell = Profile::Shell.new
|
103
|
+
puts "Gathering shell components" if verbose
|
104
|
+
puts "Found shell #{@shell.shell}" if verbose
|
105
|
+
puts "Getting files to save" if verbose
|
106
|
+
@shell.get_dotfiles
|
107
|
+
if verbose
|
108
|
+
puts "Found shell files to save:"
|
109
|
+
@shell.dotfiles.each {|d| puts " #{d}"}
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def save(dir = '~/.bashman/profiles', overwrite = false, verbose = false)
|
114
|
+
dir = File.expand_path(dir)
|
115
|
+
FileUtils.mkdir_p(dir) if not Dir.exists?(dir)
|
116
|
+
|
117
|
+
# get the current unix timestamp for later use when
|
118
|
+
# creating new saved profiles
|
119
|
+
@timestamp = Time.now.to_i
|
120
|
+
|
121
|
+
# get timestamp from manifest in the event we need to back up files
|
122
|
+
manifest = "#{dir}/#{name}.json"
|
123
|
+
puts "Saving manifest file #{manifest}" if verbose
|
124
|
+
timestamp = nil
|
125
|
+
if not overwrite
|
126
|
+
if File.exists?(manifest)
|
127
|
+
begin
|
128
|
+
timestamp = JSON.parse(File.read(manifest))['@timestamp']
|
129
|
+
rescue
|
130
|
+
timestamp = File.mtime(manifest).to_i if timestamp.nil?
|
131
|
+
end
|
132
|
+
FileUtils.mv(manifest, "#{manifest}.#{timestamp}")
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# now save shell files and write manifest
|
137
|
+
if instance_variable_defined?("@shell")
|
138
|
+
shell = @shell.to_hash
|
139
|
+
@shell.save_dotfiles("#{dir}/#{name}.tar.gz", timestamp, overwrite)
|
140
|
+
@shell = shell
|
141
|
+
end
|
142
|
+
|
143
|
+
if instance_variable_defined?("@homebrew")
|
144
|
+
homebrew = @homebrew.to_hash
|
145
|
+
@homebrew = homebrew
|
146
|
+
end
|
147
|
+
|
148
|
+
manifest_content = self.to_json
|
149
|
+
File.open(manifest, 'w') do |file|
|
150
|
+
file.write(manifest_content)
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
156
|
+
|
157
|
+
|
metadata
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bashman
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- David Bayer
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-04-08 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.16'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.16'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: json
|
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: parseconfig
|
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: Record bash profile files and settings
|
84
|
+
email:
|
85
|
+
- drbayer@eternalstench.com
|
86
|
+
executables:
|
87
|
+
- bashman
|
88
|
+
extensions: []
|
89
|
+
extra_rdoc_files: []
|
90
|
+
files:
|
91
|
+
- ".gitignore"
|
92
|
+
- ".rspec"
|
93
|
+
- ".travis.yml"
|
94
|
+
- Gemfile
|
95
|
+
- LICENSE.txt
|
96
|
+
- README.md
|
97
|
+
- Rakefile
|
98
|
+
- bashman.gemspec
|
99
|
+
- bin/console
|
100
|
+
- bin/setup
|
101
|
+
- exe/bashman
|
102
|
+
- lib/bashman.rb
|
103
|
+
- lib/bashman/homebrew.rb
|
104
|
+
- lib/bashman/shell.rb
|
105
|
+
- lib/bashman/version.rb
|
106
|
+
homepage: https://github.com/drbayer/bashman
|
107
|
+
licenses:
|
108
|
+
- MIT
|
109
|
+
metadata: {}
|
110
|
+
post_install_message:
|
111
|
+
rdoc_options: []
|
112
|
+
require_paths:
|
113
|
+
- lib
|
114
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - ">="
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - ">="
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '0'
|
124
|
+
requirements: []
|
125
|
+
rubyforge_project:
|
126
|
+
rubygems_version: 2.7.3
|
127
|
+
signing_key:
|
128
|
+
specification_version: 4
|
129
|
+
summary: Bash Profile Manager
|
130
|
+
test_files: []
|