gene_system 0.3.2
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/.doxie.json +25 -0
- data/.github/workflows/build.yml +25 -0
- data/.gitignore +20 -0
- data/.rubocop.yml +20 -0
- data/.ruby-version +1 -0
- data/CONTRIBUTING.md +51 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +150 -0
- data/LICENSE +21 -0
- data/README.md +255 -0
- data/Rakefile +19 -0
- data/bin/genesystem +52 -0
- data/data/manifest.jsonnet +87 -0
- data/gene_system.gemspec +40 -0
- data/lib/gene_system.rb +9 -0
- data/lib/gene_system/cli.rb +76 -0
- data/lib/gene_system/cli/commands.rb +109 -0
- data/lib/gene_system/generators.rb +58 -0
- data/lib/gene_system/manifest.rb +127 -0
- data/lib/gene_system/platform.rb +55 -0
- data/lib/gene_system/step.rb +74 -0
- data/lib/gene_system/version.rb +3 -0
- data/spec/gene_system/cli/commands_spec.rb +230 -0
- data/spec/gene_system/cli_spec.rb +83 -0
- data/spec/gene_system/generators_spec.rb +65 -0
- data/spec/gene_system/manifest_spec.rb +239 -0
- data/spec/gene_system/platform_spec.rb +94 -0
- data/spec/gene_system/step_spec.rb +108 -0
- data/spec/spec_helper.rb +27 -0
- metadata +344 -0
data/Rakefile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'private_gem/tasks'
|
2
|
+
require 'bundler/gem_tasks'
|
3
|
+
require 'bump/tasks'
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
require 'rubocop/rake_task'
|
6
|
+
require 'rubycritic/rake_task'
|
7
|
+
require 'yard'
|
8
|
+
|
9
|
+
RSpec::Core::RakeTask.new(:spec)
|
10
|
+
RuboCop::RakeTask.new
|
11
|
+
|
12
|
+
RubyCritic::RakeTask.new do |task|
|
13
|
+
task.paths = FileList['lib/**/*.rb'] - FileList['spec/**/*_spec.rb']
|
14
|
+
task.options = '--no-browser --path ./target/reports/critique'
|
15
|
+
end
|
16
|
+
|
17
|
+
YARD::Rake::YardocTask.new
|
18
|
+
|
19
|
+
task default: %i[spec rubocop rubycritic yard]
|
data/bin/genesystem
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift(__dir__ + '/../lib')
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'optparse'
|
7
|
+
require 'highline'
|
8
|
+
|
9
|
+
require 'gene_system'
|
10
|
+
require 'gene_system/cli'
|
11
|
+
|
12
|
+
USAGE = "GeneSystem system configuration tool
|
13
|
+
|
14
|
+
Usage:\tgenesystem <command> <variables> <opts>
|
15
|
+
Options:
|
16
|
+
\s\s\s\s--trace\t\t trace mode on
|
17
|
+
-h, --help\t\t print usage
|
18
|
+
|
19
|
+
Commands:
|
20
|
+
new <rel>\t\t creates a new manifest
|
21
|
+
install <rel>\t\t applies install steps specified in manifest
|
22
|
+
remove <rel>\t\t applies remove steps specified in manifest
|
23
|
+
".freeze
|
24
|
+
|
25
|
+
@trace = false
|
26
|
+
@overwrite = false
|
27
|
+
|
28
|
+
OptionParser.new do |opts|
|
29
|
+
opts.banner = USAGE
|
30
|
+
opts.on('--trace') { @trace = true }
|
31
|
+
|
32
|
+
opts.on_tail('-h', '--help') do
|
33
|
+
GeneSystem::CLI.print_message_and_exit(USAGE)
|
34
|
+
end
|
35
|
+
end.parse!
|
36
|
+
|
37
|
+
begin
|
38
|
+
raise 'ERROR: no command provided' unless ARGV[0]
|
39
|
+
|
40
|
+
cmd = ARGV.shift
|
41
|
+
GeneSystem::CLI::Commands.public_send(
|
42
|
+
cmd.to_sym,
|
43
|
+
ARGV
|
44
|
+
)
|
45
|
+
rescue StandardError => e
|
46
|
+
GeneSystem::CLI.print_message(e)
|
47
|
+
GeneSystem::CLI.print_message(e.backtrace) if @trace
|
48
|
+
GeneSystem::CLI.print_message("\n")
|
49
|
+
GeneSystem::CLI.print_message_and_exit(USAGE)
|
50
|
+
end
|
51
|
+
|
52
|
+
exit(0)
|
@@ -0,0 +1,87 @@
|
|
1
|
+
local conf = {
|
2
|
+
variables: {
|
3
|
+
apps: [
|
4
|
+
{
|
5
|
+
"name": "virtualbox",
|
6
|
+
"version": "6.0.1",
|
7
|
+
},
|
8
|
+
{
|
9
|
+
"name": "vagrant",
|
10
|
+
"version": "9.0.2",
|
11
|
+
},
|
12
|
+
],
|
13
|
+
|
14
|
+
bins: [
|
15
|
+
"libc",
|
16
|
+
"libd",
|
17
|
+
"libe"
|
18
|
+
]
|
19
|
+
}
|
20
|
+
};
|
21
|
+
|
22
|
+
{
|
23
|
+
"name": "macos_ruby_dev",
|
24
|
+
"version": "0.1.1",
|
25
|
+
"platform": "macos",
|
26
|
+
"metadata": {
|
27
|
+
"gene_system": {
|
28
|
+
"version": "0.1.0"
|
29
|
+
},
|
30
|
+
},
|
31
|
+
"steps": [
|
32
|
+
// install apps
|
33
|
+
{
|
34
|
+
"name": "install " + app.name,
|
35
|
+
"exe": {
|
36
|
+
"install": {
|
37
|
+
"skip": "which yolo",
|
38
|
+
"cmd": [
|
39
|
+
"echo install " + app.name + app.version
|
40
|
+
],
|
41
|
+
},
|
42
|
+
"remove": {
|
43
|
+
"cmd": [
|
44
|
+
"echo remove " + app.name + app.version
|
45
|
+
],
|
46
|
+
},
|
47
|
+
},
|
48
|
+
"tags": "app " + app.name
|
49
|
+
} for app in conf.variables.apps
|
50
|
+
] + [
|
51
|
+
// install bins
|
52
|
+
{
|
53
|
+
"name": "install " + bin,
|
54
|
+
"exe": {
|
55
|
+
"install": {
|
56
|
+
"cmd": [
|
57
|
+
"echo install " + bin
|
58
|
+
],
|
59
|
+
},
|
60
|
+
"remove": {
|
61
|
+
"cmd": [
|
62
|
+
"echo remove " + bin
|
63
|
+
],
|
64
|
+
},
|
65
|
+
},
|
66
|
+
"tags": "app " + bin
|
67
|
+
} for bin in conf.variables.bins
|
68
|
+
] + [
|
69
|
+
{
|
70
|
+
"name": "ask for input",
|
71
|
+
"exe": {
|
72
|
+
"install": {
|
73
|
+
"prompts": [
|
74
|
+
{
|
75
|
+
"prompt": "Please enter your name",
|
76
|
+
"var": "name",
|
77
|
+
},
|
78
|
+
],
|
79
|
+
"cmd": [
|
80
|
+
"echo 'Hello {{name}}'"
|
81
|
+
],
|
82
|
+
},
|
83
|
+
},
|
84
|
+
"tags": "input"
|
85
|
+
},
|
86
|
+
],
|
87
|
+
}
|
data/gene_system.gemspec
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'gene_system/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = 'gene_system'
|
9
|
+
spec.version = GeneSystem::VERSION
|
10
|
+
spec.authors = ['Andrew Bigger']
|
11
|
+
spec.email = ['andrew.bigger@gmail.com']
|
12
|
+
spec.summary = 'System configuration tool for applying personal settings to a new machine.'
|
13
|
+
spec.homepage = 'https://github.com/andrewbigger/gene_system'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
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_dependency 'hashie'
|
22
|
+
spec.add_dependency 'highline', '~> 2.0'
|
23
|
+
spec.add_dependency 'jsonnet'
|
24
|
+
spec.add_dependency 'logger', '~> 1.4'
|
25
|
+
spec.add_dependency 'os'
|
26
|
+
spec.add_dependency 'ruby-handlebars', '~> 0.4'
|
27
|
+
|
28
|
+
spec.add_development_dependency 'bump', '~> 0.6'
|
29
|
+
spec.add_development_dependency 'byebug', '~> 11.0'
|
30
|
+
spec.add_development_dependency 'doxie'
|
31
|
+
spec.add_development_dependency 'private_gem', '~> 1.1'
|
32
|
+
spec.add_development_dependency 'pry', '~> 0.11'
|
33
|
+
spec.add_development_dependency 'puma', '~> 4.3'
|
34
|
+
spec.add_development_dependency 'rake', '~> 13.0'
|
35
|
+
spec.add_development_dependency 'rspec', '~> 3.7', '>= 3.7.0'
|
36
|
+
spec.add_development_dependency 'rubocop', '~> 0.58'
|
37
|
+
spec.add_development_dependency 'rubycritic', '~> 3.4', '>= 3.4.0'
|
38
|
+
spec.add_development_dependency 'simplecov', '~> 0.16'
|
39
|
+
spec.add_development_dependency 'yard', '~> 0.9'
|
40
|
+
end
|
data/lib/gene_system.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'gene_system/cli/commands'
|
2
|
+
|
3
|
+
require 'hashie'
|
4
|
+
|
5
|
+
module GeneSystem
|
6
|
+
# Command line interface helpers and actions
|
7
|
+
module CLI
|
8
|
+
# CLI Helpers
|
9
|
+
class <<self
|
10
|
+
##
|
11
|
+
# Creates logger for printing messages
|
12
|
+
#
|
13
|
+
# Sets the formatter to output only the provided message to the
|
14
|
+
# specified IO
|
15
|
+
#
|
16
|
+
# @param [IO] out - default: STDOUT
|
17
|
+
#
|
18
|
+
# @return [Logger]
|
19
|
+
#
|
20
|
+
def logger(out = STDOUT)
|
21
|
+
@logger ||= Logger.new(out)
|
22
|
+
@logger.formatter = proc do |_sev, _time, _prog, msg|
|
23
|
+
"#{msg}\n"
|
24
|
+
end
|
25
|
+
|
26
|
+
@logger
|
27
|
+
end
|
28
|
+
|
29
|
+
##
|
30
|
+
# Prints command line message to STDOUT
|
31
|
+
#
|
32
|
+
# For use when printing info messages for a user to STDOUT
|
33
|
+
#
|
34
|
+
# @param [String] message - message to be printed
|
35
|
+
#
|
36
|
+
def print_message(message)
|
37
|
+
logger.info(message)
|
38
|
+
end
|
39
|
+
|
40
|
+
##
|
41
|
+
# Prints warning to STDOUT
|
42
|
+
#
|
43
|
+
# For use when printing warn messages to STDOUT
|
44
|
+
#
|
45
|
+
# @param [String] message - message to be printed
|
46
|
+
#
|
47
|
+
def print_warning(message)
|
48
|
+
logger.warn(message)
|
49
|
+
end
|
50
|
+
|
51
|
+
##
|
52
|
+
# Prints error to STDERR
|
53
|
+
#
|
54
|
+
# For indicating fatal message to user
|
55
|
+
#
|
56
|
+
# @param [String] message - message to be printed
|
57
|
+
#
|
58
|
+
def print_error(message)
|
59
|
+
logger(STDERR).error(message)
|
60
|
+
end
|
61
|
+
|
62
|
+
##
|
63
|
+
# Prints a message and then exits with given status code
|
64
|
+
#
|
65
|
+
# This will terminate the program with the given status code
|
66
|
+
#
|
67
|
+
# @param [String] message - message to be printed
|
68
|
+
# @param [Integer] exit_code - exit status (default: 1)
|
69
|
+
#
|
70
|
+
def print_message_and_exit(message, exit_code = 1)
|
71
|
+
print_message(message)
|
72
|
+
exit(exit_code)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'highline'
|
2
|
+
|
3
|
+
module GeneSystem
|
4
|
+
module CLI
|
5
|
+
# CLI Actions
|
6
|
+
module Commands
|
7
|
+
class <<self
|
8
|
+
##
|
9
|
+
# Creates a new, blank manifest with at the specified
|
10
|
+
# destination with the given name
|
11
|
+
#
|
12
|
+
# It is expected that the first argument provided to the
|
13
|
+
# command will be the name of the manifest. If this is not
|
14
|
+
# provided then a RuntimeError will be raised.
|
15
|
+
#
|
16
|
+
# @param dest [String]
|
17
|
+
# @param args [Array]
|
18
|
+
#
|
19
|
+
def new(args = [])
|
20
|
+
manifest_name = args.shift
|
21
|
+
|
22
|
+
raise 'no manifest name provided' unless manifest_name
|
23
|
+
|
24
|
+
GeneSystem::Generators.render_empty_manifest(
|
25
|
+
manifest_name,
|
26
|
+
Dir.pwd
|
27
|
+
)
|
28
|
+
end
|
29
|
+
|
30
|
+
##
|
31
|
+
# Applies install instructions from a manifest to the host system
|
32
|
+
#
|
33
|
+
# @param args [Array]
|
34
|
+
#
|
35
|
+
def install(args = [])
|
36
|
+
manifest = load_manifest(args)
|
37
|
+
platform = GeneSystem::Platform.new
|
38
|
+
|
39
|
+
manifest.steps.each do |step|
|
40
|
+
next if skip?(step, platform)
|
41
|
+
|
42
|
+
vars = ask(step.install.prompts)
|
43
|
+
platform.execute_commands(step.install.cmd, vars)
|
44
|
+
end
|
45
|
+
|
46
|
+
GeneSystem::CLI.print_message("\nmanifest successfully installed")
|
47
|
+
end
|
48
|
+
|
49
|
+
##
|
50
|
+
# Asks for user input when given prompts
|
51
|
+
#
|
52
|
+
# @param prompts [Array]
|
53
|
+
#
|
54
|
+
# @return Hashie::Mash
|
55
|
+
#
|
56
|
+
def ask(prompts = [])
|
57
|
+
answers = Hashie::Mash.new
|
58
|
+
return answers if prompts.nil?
|
59
|
+
|
60
|
+
cli = HighLine.new
|
61
|
+
|
62
|
+
prompts.each do |prompt|
|
63
|
+
resp = cli.ask(prompt.prompt)
|
64
|
+
answers[prompt.var] = resp
|
65
|
+
end
|
66
|
+
|
67
|
+
answers
|
68
|
+
end
|
69
|
+
|
70
|
+
##
|
71
|
+
# Applies remove instructions from a manifest to the host system
|
72
|
+
#
|
73
|
+
# @param args [Array]
|
74
|
+
#
|
75
|
+
def remove(args = [])
|
76
|
+
manifest = load_manifest(args)
|
77
|
+
platform = GeneSystem::Platform.new
|
78
|
+
|
79
|
+
manifest.steps.each do |step|
|
80
|
+
platform.execute_commands(step.remove.cmd)
|
81
|
+
end
|
82
|
+
|
83
|
+
GeneSystem::CLI.print_message("\nmanifest successfully removed")
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
def load_manifest(args)
|
89
|
+
manifest_rel = args.shift
|
90
|
+
raise 'no manifest path provided' unless manifest_rel
|
91
|
+
|
92
|
+
manifest_path = File.join(Dir.pwd, manifest_rel)
|
93
|
+
|
94
|
+
unless File.exist?(manifest_path)
|
95
|
+
raise "cannot find manifest at #{manifest_path}"
|
96
|
+
end
|
97
|
+
|
98
|
+
GeneSystem::Manifest.new_from_file(manifest_path)
|
99
|
+
end
|
100
|
+
|
101
|
+
def skip?(step, platform)
|
102
|
+
return false if step.install.skip.nil?
|
103
|
+
|
104
|
+
platform.execute_command(step.install.skip).zero?
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module GeneSystem
|
4
|
+
# Generators create empty projects for the gene_system gem
|
5
|
+
module Generators
|
6
|
+
# Default sample step
|
7
|
+
DEFAULT_STEP = {
|
8
|
+
'name' => 'say hello',
|
9
|
+
'exe' => {
|
10
|
+
'install' => {
|
11
|
+
'cmd' => [
|
12
|
+
'echo hello'
|
13
|
+
]
|
14
|
+
},
|
15
|
+
'remove' => {
|
16
|
+
'cmd' => [
|
17
|
+
'echo goodbye'
|
18
|
+
]
|
19
|
+
}
|
20
|
+
},
|
21
|
+
'tags' => 'example step'
|
22
|
+
}.freeze
|
23
|
+
|
24
|
+
# Function that creates a named, empty manifest
|
25
|
+
TEMPLATE_MANIFEST = lambda do |name|
|
26
|
+
{
|
27
|
+
'name' => name,
|
28
|
+
'version' => '0.0.1',
|
29
|
+
'metadata' => {
|
30
|
+
'gene_system' => {
|
31
|
+
'version' => GeneSystem::VERSION
|
32
|
+
}
|
33
|
+
},
|
34
|
+
'steps' => [
|
35
|
+
DEFAULT_STEP
|
36
|
+
]
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
class <<self
|
41
|
+
##
|
42
|
+
# Renders empty manifest at specified path
|
43
|
+
#
|
44
|
+
# @param [String] name
|
45
|
+
# @param [String] path
|
46
|
+
#
|
47
|
+
def render_empty_manifest(name, path)
|
48
|
+
manifest_path = File.join(path, "#{name}.json")
|
49
|
+
|
50
|
+
File.open(manifest_path, 'w') do |f|
|
51
|
+
f.write(
|
52
|
+
TEMPLATE_MANIFEST.call(name).to_json
|
53
|
+
)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|