machines 0.5.4 → 0.5.6
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.
- data/.yardopts +7 -1
- data/CHANGELOG.md +16 -4
- data/INSTALL.md +3 -0
- data/LICENSE +1 -2
- data/README.md +47 -28
- data/Rakefile +0 -8
- data/TODO.md +66 -59
- data/bin/machines +1 -2
- data/lib/machines.rb +16 -1
- data/lib/machines/app_settings.rb +1 -1
- data/lib/machines/cloud_machine.rb +1 -1
- data/lib/machines/command.rb +0 -2
- data/lib/machines/commandline.rb +23 -29
- data/lib/machines/commands/checks.rb +67 -0
- data/lib/machines/commands/configuration.rb +50 -0
- data/lib/machines/commands/database.rb +18 -0
- data/lib/machines/commands/file_operations.rb +105 -0
- data/lib/machines/commands/installation.rb +184 -0
- data/lib/machines/commands/questions.rb +16 -0
- data/lib/machines/commands/services.rb +26 -0
- data/lib/machines/core.rb +55 -25
- data/lib/machines/logger.rb +0 -2
- data/lib/machines/named_buffer.rb +7 -6
- data/lib/machines/version.rb +1 -1
- data/lib/packages/awstats.rb +2 -2
- data/lib/packages/docky.rb +0 -1
- data/lib/packages/dwm.rb +5 -0
- data/lib/packages/nginx_logrotate.rb +2 -2
- data/lib/packages/timezone.rb +2 -4
- data/lib/template/Machinesfile +2 -1
- data/lib/template/config.yml +3 -0
- data/spec/lib/machines/app_settings_spec.rb +13 -12
- data/spec/lib/machines/cloud_machine_spec.rb +9 -8
- data/spec/lib/machines/commandline_spec.rb +69 -90
- data/spec/lib/machines/{checks_spec.rb → commands/checks_spec.rb} +1 -1
- data/spec/lib/machines/{configuration_spec.rb → commands/configuration_spec.rb} +2 -3
- data/spec/lib/machines/{database_spec.rb → commands/database_spec.rb} +4 -10
- data/spec/lib/machines/{file_operations_spec.rb → commands/file_operations_spec.rb} +3 -7
- data/spec/lib/machines/{installation_spec.rb → commands/installation_spec.rb} +10 -4
- data/spec/lib/machines/{questions_spec.rb → commands/questions_spec.rb} +1 -3
- data/spec/lib/machines/{services_spec.rb → commands/services_spec.rb} +1 -4
- data/spec/lib/machines/core_spec.rb +81 -65
- data/spec/lib/packages/abiword_spec.rb +1 -5
- data/spec/lib/packages/amazon_mp3_spec.rb +0 -4
- data/spec/lib/packages/awstats_spec.rb +3 -4
- data/spec/lib/packages/base_spec.rb +0 -1
- data/spec/lib/packages/chrome_spec.rb +0 -4
- data/spec/lib/packages/cruisecontrol_spec.rb +1 -2
- data/spec/lib/packages/dependencies_spec.rb +1 -2
- data/spec/lib/packages/docky_spec.rb +0 -4
- data/spec/lib/packages/dotfiles_spec.rb +5 -4
- data/spec/lib/packages/dwm_spec.rb +23 -0
- data/spec/lib/packages/file_roller_spec.rb +1 -5
- data/spec/lib/packages/firefox_spec.rb +0 -4
- data/spec/lib/packages/gedit_spec.rb +1 -5
- data/spec/lib/packages/git_spec.rb +0 -4
- data/spec/lib/packages/gmate_spec.rb +1 -5
- data/spec/lib/packages/gnome_spec.rb +0 -4
- data/spec/lib/packages/gnumeric_spec.rb +1 -5
- data/spec/lib/packages/hosts_spec.rb +0 -1
- data/spec/lib/packages/load_machines_spec.rb +16 -15
- data/spec/lib/packages/monit_spec.rb +0 -1
- data/spec/lib/packages/mysql_spec.rb +1 -3
- data/spec/lib/packages/nginx_logrotate_spec.rb +17 -18
- data/spec/lib/packages/nginx_spec.rb +0 -1
- data/spec/lib/packages/openbox_spec.rb +0 -4
- data/spec/lib/packages/passenger_nginx_spec.rb +0 -1
- data/spec/lib/packages/passenger_spec.rb +0 -1
- data/spec/lib/packages/postfix_spec.rb +1 -5
- data/spec/lib/packages/questions_spec.rb +3 -4
- data/spec/lib/packages/rbenv_spec.rb +1 -4
- data/spec/lib/packages/rvm_spec.rb +1 -4
- data/spec/lib/packages/save_machines_spec.rb +0 -1
- data/spec/lib/packages/slim_spec.rb +1 -2
- data/spec/lib/packages/sqlserver_spec.rb +0 -4
- data/spec/lib/packages/timezone_spec.rb +2 -3
- data/spec/lib/packages/unison_spec.rb +1 -2
- data/spec/lib/packages/virtualbox_guest_spec.rb +0 -4
- data/spec/lib/packages/virtualbox_spec.rb +1 -2
- data/spec/lib/packages/webapps_spec.rb +1 -3
- data/spec/spec_helper.rb +59 -61
- data/spec/support/minitest.rb +4 -62
- metadata +27 -28
- data/lib/machines/base.rb +0 -13
- data/lib/machines/checks.rb +0 -63
- data/lib/machines/configuration.rb +0 -49
- data/lib/machines/database.rb +0 -17
- data/lib/machines/file_operations.rb +0 -104
- data/lib/machines/installation.rb +0 -171
- data/lib/machines/machinesfile.rb +0 -25
- data/lib/machines/questions.rb +0 -15
- data/lib/machines/services.rb +0 -24
- data/spec/lib/machines/machinesfile_spec.rb +0 -34
data/lib/machines/command.rb
CHANGED
data/lib/machines/commandline.rb
CHANGED
@@ -1,13 +1,29 @@
|
|
1
1
|
module Machines
|
2
|
-
|
2
|
+
class Commandline
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@core = Core.new
|
6
|
+
end
|
7
|
+
|
8
|
+
# Execute a command (build dryrun generate htpasswd packages override tasks)
|
9
|
+
def self.execute options
|
10
|
+
help = Help.new
|
11
|
+
action = options.shift
|
12
|
+
if help.actions.include?(action)
|
13
|
+
new.send action.gsub('new', 'generate'), options
|
14
|
+
else
|
15
|
+
say help.syntax
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
3
19
|
# Loads Machinesfile, opens an SCP connection and runs all commands and file uploads
|
4
20
|
def build options
|
5
21
|
$conf.machine_name = options.shift
|
6
22
|
return say(Help.new.syntax) unless $conf.machine_name
|
7
23
|
init
|
8
|
-
|
24
|
+
@core.package 'Machinesfile'
|
9
25
|
|
10
|
-
task options if options.any?
|
26
|
+
@core.task options if options.any?
|
11
27
|
|
12
28
|
ssh_options = {:paranoid => false}
|
13
29
|
if $conf.machine.cloud
|
@@ -43,18 +59,6 @@ module Machines
|
|
43
59
|
build options
|
44
60
|
end
|
45
61
|
|
46
|
-
# Execute a given command e.g. dryrun, build, generate, htpasswd, packages, override, tasks
|
47
|
-
def execute options
|
48
|
-
help = Help.new
|
49
|
-
action = options.shift
|
50
|
-
if help.actions.include?(action)
|
51
|
-
action = 'generate' if action == 'new'
|
52
|
-
send action, options
|
53
|
-
else
|
54
|
-
say help.syntax
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
62
|
def generate options
|
59
63
|
dir = options.first || './'
|
60
64
|
if File.exists? dir
|
@@ -85,25 +89,15 @@ module Machines
|
|
85
89
|
$conf.tasks = {}
|
86
90
|
$conf.load('config.yml')
|
87
91
|
|
88
|
-
Command.file ||=
|
89
|
-
Command.debug ||=
|
90
|
-
Command.console ||=
|
92
|
+
Command.file ||= Logger.new File.open('log/output.log', 'w')
|
93
|
+
Command.debug ||= Logger.new File.open('log/debug.log', 'w')
|
94
|
+
Command.console ||= Logger.new STDOUT, :truncate => true
|
91
95
|
end
|
92
96
|
|
93
97
|
def list notused
|
94
98
|
say Help.new.machine_list
|
95
99
|
end
|
96
100
|
|
97
|
-
def load_machinesfile
|
98
|
-
eval File.read('Machinesfile'), nil, "eval: Machinesfile"
|
99
|
-
rescue LoadError => e
|
100
|
-
if e.message =~ /Machinesfile/
|
101
|
-
raise LoadError, "Machinesfile does not exist. Use `machines new <DIR>` to create a template."
|
102
|
-
else
|
103
|
-
raise
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
101
|
def packages notused
|
108
102
|
say 'Default packages'
|
109
103
|
Dir[File.join($conf.application_dir, 'packages', '**/*.rb')].each do |package|
|
@@ -136,7 +130,7 @@ module Machines
|
|
136
130
|
|
137
131
|
$conf.log_only = true
|
138
132
|
init
|
139
|
-
|
133
|
+
@core.package 'Machinesfile'
|
140
134
|
say 'Tasks'
|
141
135
|
$conf.tasks.each do |task_name, settings|
|
142
136
|
say " %-20s #{settings[:description]}" % task_name
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Machines
|
2
|
+
module Commands
|
3
|
+
# The `Checks` module is used to execute a command to check whether the
|
4
|
+
# previous command was successful. These methods are useful when writing
|
5
|
+
# your own custom commands.
|
6
|
+
module Checks
|
7
|
+
def echo_result
|
8
|
+
'&& echo CHECK PASSED || echo CHECK FAILED'
|
9
|
+
end
|
10
|
+
|
11
|
+
def check_package package, exists = true
|
12
|
+
"dpkg --get-selections | grep #{package}.*#{exists ? '' : 'de'}install #{echo_result}"
|
13
|
+
end
|
14
|
+
|
15
|
+
def check_gem gem, version = nil
|
16
|
+
version = " -v #{version}" if version
|
17
|
+
"gem search #{gem}#{version} --installed #{echo_result}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def check_file file, exists = true
|
21
|
+
"test #{exists ? '' : '! '}-s #{file} #{echo_result}"
|
22
|
+
end
|
23
|
+
|
24
|
+
def check_link link
|
25
|
+
"test -L #{link} #{echo_result}"
|
26
|
+
end
|
27
|
+
|
28
|
+
def check_dir dir, exists = true
|
29
|
+
"test #{exists ? '' : '! '}-d #{dir} #{echo_result}"
|
30
|
+
end
|
31
|
+
|
32
|
+
def check_perms perms, path
|
33
|
+
perms = perms.to_s
|
34
|
+
mods = %w(--- --x -w- -wx r-- r-x rw- rwx)
|
35
|
+
"ls -la #{path} | grep #{mods[perms[0..0].to_i]}#{mods[perms[1..1].to_i]}#{mods[perms[2..2].to_i]} #{echo_result}"
|
36
|
+
end
|
37
|
+
|
38
|
+
def check_owner user, path
|
39
|
+
"ls -la #{path} | grep \"#{user}.*#{user}\" #{echo_result}"
|
40
|
+
end
|
41
|
+
|
42
|
+
def check_string string, file
|
43
|
+
"grep \"#{string}\" #{file} #{echo_result}"
|
44
|
+
end
|
45
|
+
|
46
|
+
def check_daemon daemon, exists = true
|
47
|
+
command = 'ps aux'
|
48
|
+
search_for = "| grep #{daemon}"
|
49
|
+
remove_grep = '| grep -v grep'
|
50
|
+
negative = "| grep -v #{daemon} " unless exists
|
51
|
+
"#{command} #{search_for} #{remove_grep} #{negative}#{echo_result}"
|
52
|
+
end
|
53
|
+
|
54
|
+
def check_init_d name
|
55
|
+
"test -L /etc/rc0.d/K20#{name} #{echo_result}"
|
56
|
+
end
|
57
|
+
|
58
|
+
def check_command command, match = nil
|
59
|
+
if match
|
60
|
+
"#{command} | grep #{match} #{echo_result}"
|
61
|
+
else
|
62
|
+
"#{command} #{echo_result}"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Machines
|
2
|
+
module Commands
|
3
|
+
module Configuration
|
4
|
+
# Add a new user
|
5
|
+
# (uses the lowlevel useradd so doesn't set a password unless specified)
|
6
|
+
# @param [String] login User name to create
|
7
|
+
# @param [Hash] options
|
8
|
+
# @option options [String] :password
|
9
|
+
# @option options [Boolean] :admin Adds the user to the admin group when true
|
10
|
+
def add_user login, options = {}
|
11
|
+
password = "-p #{`openssl passwd #{options[:password]}`.gsub("\n", '')} " if options[:password]
|
12
|
+
admin = "-G admin " if options[:admin]
|
13
|
+
Command.new(
|
14
|
+
"useradd -s /bin/bash -d /home/#{login} -m #{password}#{admin}#{login}",
|
15
|
+
check_dir("/home/#{login}")
|
16
|
+
)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Add an existing user to a secondary group
|
20
|
+
# @param [Hash] options
|
21
|
+
# @option options [String] :user The user to add
|
22
|
+
# @option options [String] :to Adds an existing user to the specified group
|
23
|
+
def add options
|
24
|
+
required_options options, [:user, :to]
|
25
|
+
Command.new("usermod -a -G #{options[:to]} #{options[:user]}", check_command("groups #{options[:user]}", options[:to]))
|
26
|
+
end
|
27
|
+
|
28
|
+
# Sets gconf key value pairs
|
29
|
+
# @param [Hash] options One or many key/value pairs to set
|
30
|
+
def configure options
|
31
|
+
options.map do |key, value|
|
32
|
+
types = {String => 'string', Fixnum => 'int', TrueClass => 'bool',
|
33
|
+
FalseClass => 'bool', Float => 'float', Array => 'list --list-type=string'}
|
34
|
+
type = types[value.class]
|
35
|
+
raise 'Invalid type for configure' unless type
|
36
|
+
value = value.to_json if value.is_a?(Array)
|
37
|
+
value = %("#{value}") if type == 'string'
|
38
|
+
check = "gconftool-2 --get \"#{key}\" | grep #{value} #{echo_result}"
|
39
|
+
Command.new("gconftool-2 --set \"#{key}\" --type #{type} #{value}", check)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Removes a user, home and any other related files
|
44
|
+
# @param [String] login User name to remove
|
45
|
+
def del_user login
|
46
|
+
Command.new("deluser #{login} --remove-home -q", check_file('/home/login', false))
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Machines
|
2
|
+
module Commands
|
3
|
+
module Database
|
4
|
+
# Write the database.yml file from webapps.yml
|
5
|
+
# @param [AppBuilder] app
|
6
|
+
def write_database_yml app
|
7
|
+
yml = {$conf.environment.to_s => {
|
8
|
+
'adapter' => 'mysql',
|
9
|
+
'database' => app.database || app.name,
|
10
|
+
'username' => app.username || app.name,
|
11
|
+
'password' => app.password,
|
12
|
+
'host' => $conf.db_server.address,
|
13
|
+
'encoding' => 'utf8'}}.to_yaml
|
14
|
+
write yml, :to => File.join(app.path, 'shared/config/database.yml'), :name => 'database.yml'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
module Machines
|
2
|
+
module Commands
|
3
|
+
module FileOperations
|
4
|
+
# Add a line of text to the end of a file unless it already exists
|
5
|
+
# @param [String] text Text to add
|
6
|
+
# @param [Hash] options
|
7
|
+
# @option options [String] :to File to append to
|
8
|
+
def append text, options
|
9
|
+
text = text.gsub(/([\\$"`])/, '\\\\\1')
|
10
|
+
Command.new("grep \"#{text}\" #{options[:to]} || echo \"#{text}\" >> #{options[:to]}", check_string(text, options[:to]))
|
11
|
+
end
|
12
|
+
|
13
|
+
# Change permissions of a path
|
14
|
+
# @param [String, Integer] mode chmod permissions to set
|
15
|
+
# @param [String] path Path to set
|
16
|
+
def chmod mode, path
|
17
|
+
Command.new("chmod #{mode} #{path}", check_perms(mode, path))
|
18
|
+
end
|
19
|
+
|
20
|
+
# Change ownership of a path
|
21
|
+
# @param [String] user sets user and group unless user:group is specified
|
22
|
+
# @param [String] path Path to set
|
23
|
+
# @param [Hash] options
|
24
|
+
# @option options [String] :recursive Chowns recursively if true
|
25
|
+
def chown user, path, options = {}
|
26
|
+
recursive = '-R ' if options[:recursive]
|
27
|
+
user = "#{user}:#{user}" unless user.index(':')
|
28
|
+
Command.new("chown #{recursive}#{user} #{path}", check_owner(user, path))
|
29
|
+
end
|
30
|
+
|
31
|
+
# Copy a remote file or folder (will overwrite)
|
32
|
+
# @param [String] from Existing path
|
33
|
+
# @param [String] to Path to copy to
|
34
|
+
def copy from, to
|
35
|
+
Command.new("cp -rf #{from} #{to}", check_file(to))
|
36
|
+
end
|
37
|
+
|
38
|
+
# Write a file from an ERB template
|
39
|
+
# @param [String] erb_path Path to the ERB file to process
|
40
|
+
# @param [Hash] options
|
41
|
+
# @option options [AppBuilder] :settings Contains the settings as OpenStruct method calls for calling from the template
|
42
|
+
# @option options [String] :to File to write to
|
43
|
+
def create_from erb_path, options
|
44
|
+
erb = ERB.new(File.read(erb_path), nil, '<>')
|
45
|
+
binding = options[:settings] ? options[:settings].get_binding : nil
|
46
|
+
options[:name] = erb_path
|
47
|
+
write erb.result(binding), options
|
48
|
+
end
|
49
|
+
|
50
|
+
# Add a symlink
|
51
|
+
# @param [String] target Existing path to link
|
52
|
+
# @param [String] link_name path name for the link
|
53
|
+
def link target, link_name
|
54
|
+
Command.new("ln -sf #{target} #{link_name}", check_link(link_name))
|
55
|
+
end
|
56
|
+
|
57
|
+
# Create a path or paths on the remote host (Uses -p to be safe and create full path)
|
58
|
+
# @param [String, Array] dirs A single path, multiple paths or array of paths to create
|
59
|
+
def mkdir *dirs
|
60
|
+
dirs.flatten.map do |dir|
|
61
|
+
Command.new("mkdir -p #{dir}", check_dir(dir))
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Rename a remote file or folder
|
66
|
+
# @param [String] oldname Existing filename
|
67
|
+
# @param [String] newname Rename to this
|
68
|
+
def rename oldname, newname
|
69
|
+
Command.new("mv -f #{oldname} #{newname}", check_file(newname))
|
70
|
+
end
|
71
|
+
|
72
|
+
# Remove a remote file or folder
|
73
|
+
# @param [String] file or folder to remove (uses rm with -rf which ignores non-existent files and is recursive)
|
74
|
+
def remove file
|
75
|
+
Command.new("rm -rf #{file}", check_file(file, false))
|
76
|
+
end
|
77
|
+
|
78
|
+
# Take off the version numbers from a path name
|
79
|
+
# @param [String] name Name of the path to rename
|
80
|
+
def remove_version_info name
|
81
|
+
Command.new("find . -maxdepth 1 -name \"#{name}*\" -a -type d | xargs -I xxx mv xxx #{name}", check_file(name))
|
82
|
+
end
|
83
|
+
|
84
|
+
# Replace some text in a file
|
85
|
+
# @param [String] regex The expression to search for
|
86
|
+
# @param [Hash] options
|
87
|
+
# @option options [String] :with Text to use as the replacement
|
88
|
+
# @option options [String] :in Filename to replace text in
|
89
|
+
def replace regex, options
|
90
|
+
required_options options, [:with, :in]
|
91
|
+
with = options[:with].gsub(/([\n\/\\$"`])/, '\\\\\1')
|
92
|
+
Command.new("sed -i \"s/#{regex}/#{with}/\" #{options[:in]}", check_string(with, options[:in]))
|
93
|
+
end
|
94
|
+
|
95
|
+
# (Over)write a file with the specified content
|
96
|
+
# @param [String] text Text to add
|
97
|
+
# @param [Hash] options
|
98
|
+
# @option options [String] :to File to write to
|
99
|
+
# @option options [String] :name Give the buffer a displayable name (e.g. when generated from a template)
|
100
|
+
def write text, options
|
101
|
+
Upload.new(NamedBuffer.new(options[:name], text), options[:to], check_string(text, options[:to]))
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,184 @@
|
|
1
|
+
module Machines
|
2
|
+
module Commands
|
3
|
+
module Installation
|
4
|
+
include Commands::FileOperations
|
5
|
+
|
6
|
+
APTGET_QUIET = 'apt-get -q -y'
|
7
|
+
|
8
|
+
# Adds a PPA source and updates apt
|
9
|
+
# @param [String] name Name of the PPA
|
10
|
+
# @param [String] key_name What to check in apt-key list to ensure it installed
|
11
|
+
# @example
|
12
|
+
# add_ppa 'mozillateam/firefox-stable', 'mozilla'
|
13
|
+
def add_ppa name, key_name
|
14
|
+
[
|
15
|
+
Command.new("add-apt-repository ppa:#{name}", "apt-key list | grep -i #{key_name} #{echo_result}"),
|
16
|
+
update
|
17
|
+
]
|
18
|
+
end
|
19
|
+
|
20
|
+
# Adds a DEB source
|
21
|
+
# @param [String] source URL of the package. If `YOUR_UBUNTU_VERSION_HERE` is included then it
|
22
|
+
# is replaced by the Ubuntu version name
|
23
|
+
# @param [Hash] options
|
24
|
+
# @option options [String] :key URL of key
|
25
|
+
# @option options [String] :name Used to check `apt-key list` to ensure it installed
|
26
|
+
# @example
|
27
|
+
# sudo deb 'http://dl.google.com/linux/deb/ stable main',
|
28
|
+
# key: 'https://dl-ssl.google.com/linux/linux_signing_key.pub',
|
29
|
+
# name: 'Google'
|
30
|
+
def deb source, options
|
31
|
+
command = "echo deb #{source} >> /etc/apt/sources.list"
|
32
|
+
if source =~ /YOUR_UBUNTU_VERSION_HERE/
|
33
|
+
command = "expr substr `cat /etc/lsb-release | grep DISTRIB_CODENAME` 18 20 | xargs -I YOUR_UBUNTU_VERSION_HERE #{command}"
|
34
|
+
end
|
35
|
+
[
|
36
|
+
Command.new(command, check_string(source.gsub(/ .*$/, ''), '/etc/apt/sources.list')),
|
37
|
+
Command.new("wget -q #{options[:key]} -O - | apt-key add -", "apt-key list | grep -i #{options[:name]} #{echo_result}"),
|
38
|
+
update
|
39
|
+
]
|
40
|
+
end
|
41
|
+
|
42
|
+
# Preseed debconf to allow silent installs
|
43
|
+
# @param [String] app Name of application to configure
|
44
|
+
# @param [String] setting The setting to set
|
45
|
+
# @param [String] type Data type of the value
|
46
|
+
# @param value The value to set (Ruby types supported)
|
47
|
+
def debconf app, setting, type, value
|
48
|
+
command = "echo #{app} #{setting} #{type} #{value} | debconf-set-selections"
|
49
|
+
check = "debconf-get-selections | grep #{app} #{echo_result}"
|
50
|
+
Command.new(command, check)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Download, extract, and remove an archive. Currently supports `zip`, `tar.gz`, `tar.bz2`.
|
54
|
+
# @param [String] package Package name to extract
|
55
|
+
# @param [Hash] options
|
56
|
+
# @option options [Optional String] :to folder to clone or extract to (defaults to `/usr/local/src`)
|
57
|
+
# @example
|
58
|
+
# sudo extract 'http://dl.suckless.org/dwm/dwm-6.0.tar.gz'
|
59
|
+
def extract package, options = {}
|
60
|
+
name = File.basename(package)
|
61
|
+
if package[/.zip/]
|
62
|
+
cmd = 'unzip -qq'
|
63
|
+
elsif package[/.tar.gz/]
|
64
|
+
cmd = 'tar -zxf'
|
65
|
+
elsif package[/.tar.bz2/]
|
66
|
+
cmd = 'tar -jxf'
|
67
|
+
else
|
68
|
+
raise "extract: Unknown extension for #{package}"
|
69
|
+
end
|
70
|
+
dir = cmd =~ /unzip/ ? File.basename(name, '.zip') : File.basename(name).gsub(/\.tar.*/, '')
|
71
|
+
dest = options[:to] || '/usr/local/src'
|
72
|
+
Command.new("cd #{dest} && wget #{package} && #{cmd} #{name} && rm #{name} && cd -", check_dir("#{File.join(dest, dir)}"))
|
73
|
+
end
|
74
|
+
|
75
|
+
# Install a gem
|
76
|
+
# @param [String] package Name of the gem
|
77
|
+
# @param [Hash] options
|
78
|
+
# @option options [String] :version Optional version number
|
79
|
+
def gem package, options = {}
|
80
|
+
version = " -v \"#{options[:version]}\"" if options[:version]
|
81
|
+
Command.new("gem install #{package}#{version}", check_gem(package, options[:version]))
|
82
|
+
end
|
83
|
+
|
84
|
+
# Update gems
|
85
|
+
# @example Update Rubygems
|
86
|
+
# gem_update '--system'
|
87
|
+
def gem_update options = ''
|
88
|
+
Command.new("gem update #{options}", nil)
|
89
|
+
end
|
90
|
+
|
91
|
+
# Clone (or update) a project from a Git repository
|
92
|
+
# @param [String] url URL to clone
|
93
|
+
# @param [Hash] options
|
94
|
+
# @option options [Optional String] :to Folder to clone to
|
95
|
+
# @option options [Optional String] :tag Checkout this tag after cloning (requires :to)
|
96
|
+
# @option options [Optional String] :branch Switch this branch when cloning
|
97
|
+
def git_clone url, options = {}
|
98
|
+
raise ArgumentError.new('git_clone Must include a url and folder') if url.nil? || url.empty?
|
99
|
+
raise ArgumentError.new('specifying :tag also requires :to') if options[:tag] && options[:to].nil?
|
100
|
+
branch = "--branch #{options[:branch]} " if options[:branch]
|
101
|
+
dir = options[:to] || url.gsub(/^.*\/|.git/, '')
|
102
|
+
command = "test -d #{dir} && (cd #{dir} && git pull) || git clone --quiet #{branch}#{url}"
|
103
|
+
command << " #{options[:to]}" if options[:to]
|
104
|
+
command = Command.new(command, check_dir(options[:to]))
|
105
|
+
command = [command, Command.new("cd #{options[:to]} && git checkout #{options[:tag]}", "git name-rev --name-only HEAD | grep #{options[:tag]}")] if options[:tag]
|
106
|
+
command
|
107
|
+
end
|
108
|
+
|
109
|
+
# Installs one or more packages using apt, deb or git clone and install.sh
|
110
|
+
# (See `extract` to just uncompress tar.gz or zip files).
|
111
|
+
# Packages are installed separately to aid progress feedback.
|
112
|
+
# Ensure this is the main package as dpkg get-selections is used to validate installation.
|
113
|
+
# @param [Symbol, String, Array] packages URL to download and install, string or array of apt packages
|
114
|
+
# @param [Hash] options
|
115
|
+
# @option options [Optional Symbol] :as Specify `:dpkg` to download URL and run `dpkg`
|
116
|
+
# @option options [Optional String] :bin Specify the bin file to link to (e.g. '/bin/executable'
|
117
|
+
# will create a link /usr/local/bin/executable that points to /usr/local/lib/bin/executable)
|
118
|
+
# @option options [Optional Boolean] :make Set to true to run `sudo make clean install`
|
119
|
+
# @example Install apt packages
|
120
|
+
# install %w(build-essential libssl-dev mysql-server)
|
121
|
+
# @example Download and install a deb using dpkg then remove the deb
|
122
|
+
# install 'http://example.com/my_package.deb'
|
123
|
+
# @example Download and phantomjs to `/usr/local/lib` and add `bin/phantomjs` to `/usr/local/bin`
|
124
|
+
# install 'http://phantomjs.googlecode.com/files/phantomjs-1.7.0-linux-x86_64.tar.bz2', bin: 'bin/phantomjs'
|
125
|
+
# @example Download dwm into `/usr/local/src/dwm-6.0` and install
|
126
|
+
# install 'http://dl.suckless.org/dwm/dwm-6.0.tar.gz', make: true
|
127
|
+
def install packages, options = {}
|
128
|
+
if packages.is_a?(String)
|
129
|
+
if packages =~ /^http:\/\//
|
130
|
+
commands = []
|
131
|
+
if packages =~ /\.deb$/i
|
132
|
+
name = File.basename(packages)
|
133
|
+
commands << Command.new("cd /tmp && wget #{packages} && dpkg -i --force-architecture #{name} && rm #{name} && cd -", nil)
|
134
|
+
else
|
135
|
+
commands << extract(packages, :to => '/tmp')
|
136
|
+
name = File.basename(packages).gsub(/\.(tar|zip).*/, '')
|
137
|
+
|
138
|
+
if options[:as] == :dpkg
|
139
|
+
commands << Command.new("cd /tmp/#{name} && dpkg -i --force-architecture *.deb && cd - && rm -rf /tmp/#{name}", nil)
|
140
|
+
elsif options[:bin]
|
141
|
+
commands << rename("/tmp/#{name}", "/usr/local/lib")
|
142
|
+
commands << link("/usr/local/lib/#{name}/#{options[:bin]}", "/usr/local/bin/#{File.basename(options[:bin])}")
|
143
|
+
elsif options[:make]
|
144
|
+
commands << rename("/tmp/#{name}", "/usr/local/src")
|
145
|
+
commands << Command.new("cd /usr/local/src/#{name} && make clean install", nil)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
return commands
|
149
|
+
else
|
150
|
+
packages = [packages]
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
if packages.is_a?(Array)
|
155
|
+
commands = packages.map do |package|
|
156
|
+
Command.new("#{APTGET_QUIET} install #{package}", check_package(package))
|
157
|
+
end
|
158
|
+
end
|
159
|
+
commands
|
160
|
+
end
|
161
|
+
|
162
|
+
# Remove one or more Ubuntu packages
|
163
|
+
# @param [Array] packages Packages to remove
|
164
|
+
def uninstall packages
|
165
|
+
packages.map do |package|
|
166
|
+
Command.new("#{APTGET_QUIET} purge #{package}", check_package(package, false))
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
# Updates Ubuntu packages
|
171
|
+
def update
|
172
|
+
Command.new("#{APTGET_QUIET} update > /tmp/apt-update.log", check_string('Reading package lists', '/tmp/apt-update.log'))
|
173
|
+
end
|
174
|
+
|
175
|
+
# Update, upgrade, autoremove, autoclean apt packages
|
176
|
+
def upgrade
|
177
|
+
# TODO: Check that check_command really checks the correct command with `echo $?`
|
178
|
+
%w(update upgrade autoremove autoclean).map do |command|
|
179
|
+
Command.new("#{APTGET_QUIET} #{command}", check_command('echo $?', '0'))
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|