shaddox 0.0.30 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 46fa597ccc0b93dcbbdf658a5d0e25b6e70e877a
4
- data.tar.gz: 8f4864ce6dc4971389e1eba700ce177a466cb133
3
+ metadata.gz: 10d9d20d568a9f429430855db8652655b78908c9
4
+ data.tar.gz: 7aa5c9f137fb1fa95201e7825a0e9bf3d8f4cd78
5
5
  SHA512:
6
- metadata.gz: 49fab60501a5f1c8d838a78c6632ee709ff92ef385bef45a1a39021991065ae3ba8fd19f327b6457f797a87d059eaad65f3f31e67dde40e79c399572d5d00721
7
- data.tar.gz: 7899e6f5689f2a0ccd2280783d4ad08a2709da58a9055031ac807f63533409f58e812d77419425dcfe1a1ab5a127a0fa1ff184a06fbb35b801d0deb0bcb52a10
6
+ metadata.gz: 48760f0b6cdbd5e4b9f539116499c32bd270da4f22127853bc2b4dffc5a8a898e09341da25e758764c91936ced54a01ddb46fc3502c529948c5a19ea5eefe257
7
+ data.tar.gz: 858f39652d4be97f7a856180030ec98820aaf95a50dfa794bb9988ac144c7cbab5c433435a6b43572c80750c0485f904259a4d848132b268bae1a06c381813ea
data/Doxfile CHANGED
@@ -1,36 +1,19 @@
1
- server :vagrant, {
2
- :host => "localhost",
3
- :user => 'vagrant',
4
- :ssh => {
5
- :port => 2222,
6
- :password => 'vagrant'
7
- },
8
- :installer => :apt
9
- }
10
-
11
- repo :profile, {
12
- :url => "https://github.com/joshglendenning/profile.git",
13
- :shared => 'tmp'
14
- }
15
-
16
1
  task :foo do
17
- sh "echo 'foo'"
2
+ exec "echo 'foo'"
18
3
  end
19
4
 
20
5
  task :foobar => :foo do
21
- sh "echo 'bar'"
22
- end
23
-
24
- task :install do
25
- repo_deploy :profile, "~/repo_test/profile" do
26
- ln_s './current', '/var/www/profile'
27
- end
6
+ exec "echo 'bar'"
28
7
  end
29
8
 
30
9
  task :broken => :foo do
31
- sh "notacommand"
10
+ exec "notacommand"
32
11
  end
33
12
 
34
13
  task :sudo do
35
- sh "sudo echo 'this is a sudo echo'"
14
+ exec "sudo echo 'this is a sudo echo'"
15
+ end
16
+
17
+ task :install do
18
+ install "git"
36
19
  end
data/bin/shaddox CHANGED
@@ -10,25 +10,13 @@ options = {
10
10
 
11
11
  OptionParser.new do |opts|
12
12
 
13
- opts.banner = "Usage: shaddox [task] [target] [options]"
13
+ opts.banner = "Usage: shaddox [task] [options]"
14
14
 
15
- opts.on("--debug", "Run verbosely") do |v|
16
- options[:debug] = v
15
+ opts.on('-v', '--verboase', "Run verbosely") do
16
+ options[:verbose] = true
17
17
  end
18
18
 
19
- opts.on("--force", "Override lock on target") do |b|
20
- options[:force] = b
21
- end
22
-
23
- opts.on("--keep-tmp-dir", "Don't remove the tmpdir after deployment") do |b|
24
- options[:keep_tmp_dir] = b
25
- end
26
-
27
- opts.on("--tmpdir PATH", "Specify the tmp directory to use (default '/tmp/shaddox')") do |dir|
28
- options[:tmpdir] = dir
29
- end
30
-
31
- opts.on('-f PATH', '--doxfile', "Specify doxfile") do |f|
19
+ opts.on('--doxfile', "Specify doxfile") do |f|
32
20
  @doxfile = f
33
21
  end
34
22
 
@@ -39,8 +27,7 @@ OptionParser.new do |opts|
39
27
 
40
28
  end.parse!
41
29
 
42
- task = ARGV[0]
43
- target = ARGV[1] || 'localhost'
30
+ task = ARGV[0] || :default
44
31
 
45
32
  config = Shaddox::Config.new(@doxfile)
46
- config.invoke(task.to_sym, target.to_sym, options)
33
+ config.invoke(task, options)
@@ -1,6 +1,10 @@
1
1
  module Shaddox
2
2
  class Config
3
- attr_accessor :servers, :targets, :repos, :tasks
3
+
4
+ # Init ==============================================
5
+
6
+ attr_accessor :tasks
7
+
4
8
  def initialize(doxfile)
5
9
  doxfile = './Doxfile' unless doxfile
6
10
  if !File.exists?(doxfile)
@@ -8,83 +12,32 @@ module Shaddox
8
12
  exit(1)
9
13
  end
10
14
 
11
- @servers = Hash.new
12
- @targets = Hash.new {|hsh, key| @servers[key]} # Fall back on @servers hash for missing targets
13
15
  @tasks = Hash.new
14
- @repos = Hash.new
15
-
16
- # :local and :localhost point to local by default
17
- @targets[:localhost] = Localhost.new
18
- @targets[:local] = :localhost
19
16
 
20
17
  instance_eval(File.read(doxfile), doxfile)
21
18
  end
22
19
 
23
- def explode_target(target_key)
24
- exploded = []
25
- [@targets[target_key]].flatten.each do |target|
26
- if target.is_a? Symbol
27
- exploded += explode_target(target)
28
- else
29
- exploded.push(target)
30
- end
31
- end
32
- exploded
33
- end
34
-
35
- def invoke(task_key, target_key, opts = {})
36
- explode_target(target_key).each do |target|
37
- raise "The target :#{target_key} could not be found. Please check your Doxfile.".red unless target
38
- info "Deploying to #{target_key}..."
39
- begin
40
- script_opts = {}
41
- script_opts[:installer] = target.installer if target.respond_to? :installer
42
- script_opts[:debug] = opts[:debug] if opts[:debug]
43
- script = ShadowScript.new(self, task_key, script_opts)
44
- target.deploy(script, opts)
45
- info "Provisioning on :#{target_key} complete.".green
46
- rescue TargetError => e
47
- err "Provisioning on :#{target_key} failed:".red
48
- puts e.message.red
49
- rescue => e
50
- err "Provisioning on :#{target_key} failed:".red
51
- puts e.message.red
52
- e.backtrace.each { |line| puts line }
53
- end
20
+ # Methods ============================================
21
+
22
+ def invoke(task_key, opts)
23
+ begin
24
+ task = @tasks[task_key.to_sym]
25
+ return if task.done
26
+ task.deps.each { |dep| invoke(dep, opts) }
27
+ info "[#{task_key}] Starting..."
28
+ Provisioner.new(task.block, opts)
29
+ task.done = true
30
+ info "[#{task_key}] Done".green
31
+ rescue => e
32
+ err "[#{task_key}] Failed".red
33
+ puts e.message.red
34
+ e.backtrace.each { |line| puts line }
54
35
  end
55
36
  end
56
37
 
57
38
  ## DSL Methods ##
58
39
 
59
- # ### Add a server
60
- # info: A hash containing the server's info. Allowed keys:
61
- # :address (required)
62
- # :user
63
- # :port
64
- # :identity_file
65
- # :ssh_options
66
- def server(key, info)
67
- @servers[key] = Server.new(info)
68
- end
69
-
70
- # ### Add a target
71
- # linked_target: A symbol or Array of symbols representing
72
- # the other targets/servers that this target invokes
73
- def target(key, linked_target)
74
- @targets[key] = linked_target
75
- end
76
-
77
- # ### Add a repo
78
- # info: A hash containing the repo's info. Allowed keys:
79
- # :repository (required)
80
- # :branch
81
- def repo(key, info)
82
- @repos[key] = Repo.new(info)
83
- end
84
-
85
- # ### Add a package
86
- # blk: A block of code to be executed in the context of the target[s]
87
- # specified when running Shaddox
40
+ # ### Add a task
88
41
  # key can be bound to a list to define dependencies, like with Rake
89
42
  # task :example => :some_dep do ...
90
43
  # task :example => [:dep1, :dep2] do ...
@@ -0,0 +1,74 @@
1
+ module Shaddox
2
+
3
+ class Installer
4
+ def self.autodetect(pvr)
5
+ return AptInstaller.new(pvr) if pvr.availiable? "apt-get"
6
+ return BrewInstaller.new(pvr) if pvr.availiable? "brew"
7
+ return PacmanInstaller.new(pvr) if pvr.availiable? "pacman"
8
+ warn "Installer could not be automatically identified.", 1
9
+ require 'highline/import'
10
+ choose do |menu|
11
+ menu.prompt = "Please select a package manager to use:"
12
+
13
+ menu.choice(:manual) { return ManualInstaller.new(pvr) }
14
+ menu.choice(:apt) { return AptInstaller.new(pvr) }
15
+ menu.choice(:brew) { return BrewInstaller.new(pvr) }
16
+ end
17
+ end
18
+ def initialize(pvr)
19
+ @pvr = pvr
20
+ end
21
+ def install(package)
22
+ raise "This should be implemented by subclass."
23
+ end
24
+ def installed?(cmd)
25
+ @pvr.availiable?(cmd)
26
+ end
27
+ end
28
+
29
+ class ManualInstaller < Installer
30
+ def install(package)
31
+ return if installed?(package)
32
+ puts "Please install '#{package}' manually."
33
+ gets
34
+ raise "Could not install #{package}" unless installed?(package)
35
+ end
36
+ end
37
+
38
+ class AptInstaller < Installer
39
+ # def initialize(pvr)
40
+ # super(pvr)
41
+ # @pvr.exec("sudo apt-get update")
42
+ # end
43
+ def install(package)
44
+ return if installed?(package)
45
+ @pvr.exec("sudo apt-get install #{package}")
46
+ raise "Could not install #{package}" unless installed?(package)
47
+ end
48
+ end
49
+
50
+ class BrewInstaller < Installer
51
+ # def initialize(pvr)
52
+ # super(pvr)
53
+ # @pvr.exec("brew update")
54
+ # end
55
+ def install(package)
56
+ return if installed?(package)
57
+ @pvr.exec("brew install #{package}")
58
+ raise "Could not install #{package}" unless installed?(package)
59
+ end
60
+ end
61
+
62
+ class PacmanInstaller < Installer
63
+ # def initialize(pvr)
64
+ # super(pvr)
65
+ # @pvr.exec("pacman -Sy")
66
+ # end
67
+ def install(package)
68
+ return if installed?(package)
69
+ @pvr.exec("pacman -S #{package}")
70
+ raise "Could not install #{package}" unless installed?(package)
71
+ end
72
+ end
73
+
74
+ end
@@ -0,0 +1,89 @@
1
+ class String
2
+ def exp_path
3
+ File.expand_path(self)
4
+ end
5
+ def parent
6
+ File.split(self)[0]
7
+ end
8
+ end
9
+
10
+ module Shaddox
11
+
12
+ class Provisioner
13
+
14
+ require 'fileutils'
15
+
16
+ # Init ====================================================
17
+
18
+ def initialize(block, opts = {:verbose => false})
19
+ @verbose = opts[:verbose]
20
+ @required = true
21
+ instance_eval(&block) unless !block
22
+ end
23
+
24
+ # Methods =================================================
25
+
26
+ def optional(&block)
27
+ @required = false
28
+ instance_eval(&block)
29
+ @required = true
30
+ end
31
+
32
+ def exists(path)
33
+ system("test -e #{path.exp_path}")
34
+ end
35
+
36
+ def exists_d(path)
37
+ system("test -d #{path.exp_path}")
38
+ end
39
+
40
+ def exists_f(path)
41
+ system("test -f #{path.exp_path}")
42
+ end
43
+
44
+ def exec(command, args = nil)
45
+ cmd = "#{command}"
46
+ cmd += " #{args.join(" ")}" if args
47
+ info "Running '#{cmd}' in '#{Dir.pwd}'", 1 if @verbose
48
+ system(cmd)
49
+ raise "'#{cmd}' failed" unless $? == 0 or !@required
50
+ end
51
+
52
+ def cd(path, &block)
53
+ mkdir(path)
54
+ FileUtils.cd(path.exp_path) do
55
+ instance_eval(&block)
56
+ end
57
+ end
58
+
59
+ def ln_s(source, dest, opts = {})
60
+ mkdir(dest.exp_path.parent)
61
+ Dir.glob(source.exp_path).each { |src|
62
+ info "Linking '#{source.exp_path}' to '#{dest.exp_path}'", 1 if @verbose
63
+ FileUtils::ln_s(src, dest.exp_path, opts)
64
+ }
65
+ end
66
+
67
+ def mkdir(path)
68
+ info "Ensuring directory '#{path}' exists", 1 if @verbose
69
+ FileUtils::mkdir_p(path.exp_path)
70
+ end
71
+
72
+ def availiable?(cmd)
73
+ exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
74
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
75
+ exts.each { |ext|
76
+ exe = File.join(path, "#{cmd}#{ext}")
77
+ return true if File.executable?(exe) && !File.directory?(exe)
78
+ }
79
+ end
80
+ return false
81
+ end
82
+
83
+ def install(package)
84
+ @installer ||= Installer.autodetect(self);
85
+ info "Ensuring #{package} is installed", 1 if @verbose
86
+ @installer.install(package)
87
+ end
88
+ end
89
+ end
data/lib/shaddox/task.rb CHANGED
@@ -1,18 +1,10 @@
1
1
  module Shaddox
2
2
  class Task
3
- attr_accessor :block, :deps
3
+ attr_accessor :block, :deps, :done
4
4
  def initialize(block, deps)
5
5
  @block = block
6
6
  @deps = [deps].flatten
7
- end
8
-
9
- def to_source
10
- require 'sourcify'
11
- if @block
12
- @block.to_source(:strip_enclosure => true)
13
- else
14
- "# Empty block #"
15
- end
7
+ @done = false
16
8
  end
17
9
  end
18
10
  end
@@ -1,3 +1,3 @@
1
1
  module Shaddox
2
- VERSION = "0.0.30"
2
+ VERSION = "0.1.0"
3
3
  end
data/lib/shaddox.rb CHANGED
@@ -1,9 +1,6 @@
1
1
  require "shaddox/version"
2
2
  require "shaddox/ui"
3
- require "shaddox/settings"
4
- require "shaddox/target"
3
+ require "shaddox/installer"
4
+ require "shaddox/provisioner"
5
5
  require "shaddox/task"
6
- require "shaddox/repo"
7
- require "shaddox/shadow"
8
- require "shaddox/shadow_script"
9
6
  require "shaddox/config"
data/shaddox.gemspec CHANGED
@@ -18,9 +18,5 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_dependency "sourcify", "~> 0.6.0.rc4"
22
- spec.add_dependency "net-ssh", "~> 2.9"
23
- spec.add_dependency "highline", "~> 1.6"
24
- spec.add_development_dependency "bundler", "~> 1.6"
25
- spec.add_development_dependency "rake", "~> 10.0"
21
+ spec.add_dependency 'highline', '~> 1.7'
26
22
  end
metadata CHANGED
@@ -1,85 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shaddox
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.30
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - joshglendenning
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-17 00:00:00.000000000 Z
11
+ date: 2015-06-23 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: sourcify
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: 0.6.0.rc4
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: 0.6.0.rc4
27
- - !ruby/object:Gem::Dependency
28
- name: net-ssh
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '2.9'
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '2.9'
41
13
  - !ruby/object:Gem::Dependency
42
14
  name: highline
43
15
  requirement: !ruby/object:Gem::Requirement
44
16
  requirements:
45
17
  - - "~>"
46
18
  - !ruby/object:Gem::Version
47
- version: '1.6'
19
+ version: '1.7'
48
20
  type: :runtime
49
21
  prerelease: false
50
22
  version_requirements: !ruby/object:Gem::Requirement
51
23
  requirements:
52
24
  - - "~>"
53
25
  - !ruby/object:Gem::Version
54
- version: '1.6'
55
- - !ruby/object:Gem::Dependency
56
- name: bundler
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: '1.6'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: '1.6'
69
- - !ruby/object:Gem::Dependency
70
- name: rake
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
74
- - !ruby/object:Gem::Version
75
- version: '10.0'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
81
- - !ruby/object:Gem::Version
82
- version: '10.0'
26
+ version: '1.7'
83
27
  description: Ruby-based system provisioning tool.
84
28
  email:
85
29
  - joshglendenning@gmail.com
@@ -93,20 +37,14 @@ files:
93
37
  - Gemfile
94
38
  - LICENSE.txt
95
39
  - README.md
96
- - Vagrantfile
97
40
  - bin/shaddox
98
41
  - lib/shaddox.rb
99
42
  - lib/shaddox/config.rb
100
- - lib/shaddox/repo.rb
101
- - lib/shaddox/settings.rb
102
- - lib/shaddox/shadow.rb
103
- - lib/shaddox/shadow_script.rb
104
- - lib/shaddox/target.rb
43
+ - lib/shaddox/installer.rb
44
+ - lib/shaddox/provisioner.rb
105
45
  - lib/shaddox/task.rb
106
46
  - lib/shaddox/ui.rb
107
47
  - lib/shaddox/version.rb
108
- - push.sh
109
- - scripts/bootstrap.sh
110
48
  - shaddox.gemspec
111
49
  homepage: http://nominaltech.com
112
50
  licenses:
data/Vagrantfile DELETED
@@ -1,122 +0,0 @@
1
- # -*- mode: ruby -*-
2
- # vi: set ft=ruby :
3
-
4
- # Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
5
- VAGRANTFILE_API_VERSION = "2"
6
-
7
- Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
8
- # All Vagrant configuration is done here. The most common configuration
9
- # options are documented and commented below. For a complete reference,
10
- # please see the online documentation at vagrantup.com.
11
-
12
- # Every Vagrant virtual environment requires a box to build off of.
13
- config.vm.box = "chef/debian-7.4"
14
-
15
- # Disable automatic box update checking. If you disable this, then
16
- # boxes will only be checked for updates when the user runs
17
- # `vagrant box outdated`. This is not recommended.
18
- # config.vm.box_check_update = false
19
-
20
- # Create a forwarded port mapping which allows access to a specific port
21
- # within the machine from a port on the host machine. In the example below,
22
- # accessing "localhost:8080" will access port 80 on the guest machine.
23
- # config.vm.network "forwarded_port", guest: 80, host: 8080
24
-
25
- # Create a private network, which allows host-only access to the machine
26
- # using a specific IP.
27
- # config.vm.network "private_network", ip: "192.168.33.10"
28
-
29
- # Create a public network, which generally matched to bridged network.
30
- # Bridged networks make the machine appear as another physical device on
31
- # your network.
32
- # config.vm.network "public_network"
33
-
34
- # If true, then any SSH connections made will enable agent forwarding.
35
- # Default value: false
36
- # config.ssh.forward_agent = true
37
-
38
- # Share an additional folder to the guest VM. The first argument is
39
- # the path on the host to the actual folder. The second argument is
40
- # the path on the guest to mount the folder. And the optional third
41
- # argument is a set of non-required options.
42
- # config.vm.synced_folder "../data", "/vagrant_data"
43
-
44
- # Provider-specific configuration so you can fine-tune various
45
- # backing providers for Vagrant. These expose provider-specific options.
46
- # Example for VirtualBox:
47
- #
48
- # config.vm.provider "virtualbox" do |vb|
49
- # # Don't boot with headless mode
50
- # vb.gui = true
51
- #
52
- # # Use VBoxManage to customize the VM. For example to change memory:
53
- # vb.customize ["modifyvm", :id, "--memory", "1024"]
54
- # end
55
- #
56
- # View the documentation for the provider you're using for more
57
- # information on available options.
58
-
59
- # Enable provisioning with CFEngine. CFEngine Community packages are
60
- # automatically installed. For example, configure the host as a
61
- # policy server and optionally a policy file to run:
62
- #
63
- # config.vm.provision "cfengine" do |cf|
64
- # cf.am_policy_hub = true
65
- # # cf.run_file = "motd.cf"
66
- # end
67
- #
68
- # You can also configure and bootstrap a client to an existing
69
- # policy server:
70
- #
71
- # config.vm.provision "cfengine" do |cf|
72
- # cf.policy_server_address = "10.0.2.15"
73
- # end
74
-
75
- # Enable provisioning with Puppet stand alone. Puppet manifests
76
- # are contained in a directory path relative to this Vagrantfile.
77
- # You will need to create the manifests directory and a manifest in
78
- # the file default.pp in the manifests_path directory.
79
- #
80
- # config.vm.provision "puppet" do |puppet|
81
- # puppet.manifests_path = "manifests"
82
- # puppet.manifest_file = "site.pp"
83
- # end
84
-
85
- # Enable provisioning with chef solo, specifying a cookbooks path, roles
86
- # path, and data_bags path (all relative to this Vagrantfile), and adding
87
- # some recipes and/or roles.
88
- #
89
- # config.vm.provision "chef_solo" do |chef|
90
- # chef.cookbooks_path = "../my-recipes/cookbooks"
91
- # chef.roles_path = "../my-recipes/roles"
92
- # chef.data_bags_path = "../my-recipes/data_bags"
93
- # chef.add_recipe "mysql"
94
- # chef.add_role "web"
95
- #
96
- # # You may also specify custom JSON attributes:
97
- # chef.json = { mysql_password: "foo" }
98
- # end
99
-
100
- # Enable provisioning with chef server, specifying the chef server URL,
101
- # and the path to the validation key (relative to this Vagrantfile).
102
- #
103
- # The Opscode Platform uses HTTPS. Substitute your organization for
104
- # ORGNAME in the URL and validation key.
105
- #
106
- # If you have your own Chef Server, use the appropriate URL, which may be
107
- # HTTP instead of HTTPS depending on your configuration. Also change the
108
- # validation key to validation.pem.
109
- #
110
- # config.vm.provision "chef_client" do |chef|
111
- # chef.chef_server_url = "https://api.opscode.com/organizations/ORGNAME"
112
- # chef.validation_key_path = "ORGNAME-validator.pem"
113
- # end
114
- #
115
- # If you're using the Opscode platform, your validator client is
116
- # ORGNAME-validator, replacing ORGNAME with your organization name.
117
- #
118
- # If you have your own Chef Server, the default validation client name is
119
- # chef-validator, unless you changed the configuration.
120
- #
121
- # chef.validation_client_name = "ORGNAME-validator"
122
- end
data/lib/shaddox/repo.rb DELETED
@@ -1,16 +0,0 @@
1
- module Shaddox
2
- class Repo
3
- attr_reader :url, :branch, :vcs, :shared
4
- def initialize(info)
5
- @info = info
6
- @url = info[:url]
7
- @branch = info[:branch] || 'master'
8
- @vcs = info[:vcs] || :git
9
- @shared = [info[:shared]].flatten || []
10
- end
11
-
12
- def to_source
13
- "Shaddox::Repo.new(#{@info.inspect})"
14
- end
15
- end
16
- end
@@ -1,42 +0,0 @@
1
- module Shaddox
2
- class Settings < Hash
3
- def method_missing(meth, *args, &blk)
4
- name = meth.to_s
5
-
6
- return evaluate(self[meth]) if name.size == 1
7
-
8
- # Ruby 1.8.7 doesn't let you do string[-1]
9
- key, suffix = name[0..-2].to_sym, name[-1..-1]
10
-
11
- case suffix
12
- when '='
13
- self[key] = args.first
14
- when '?'
15
- include? key
16
- when '!'
17
- raise Error, "Setting :#{key} is not set" unless include?(key)
18
- evaluate self[key]
19
- else
20
- evaluate self[meth]
21
- end
22
- end
23
-
24
- def evaluate(value)
25
- if value.is_a?(Proc)
26
- value.call
27
- else
28
- value
29
- end
30
- end
31
- end
32
- module SettingContainer
33
- def init_settings(default_settings = {})
34
- @settings = Settings.new.update(default_settings)
35
- end
36
-
37
- # Hook to loop up values in @info
38
- def method_missing(meth, *args, &blk)
39
- @settings.send meth, *args
40
- end
41
- end
42
- end
@@ -1,160 +0,0 @@
1
- class String
2
- def exp_path
3
- File.expand_path(self)
4
- end
5
- end
6
-
7
- module Shaddox
8
-
9
- class Shadow
10
- require 'fileutils'
11
- #include FileUtils
12
- def initialize(options, &block)
13
- @debug = options[:debug] || true # TODO: change to false for actual release
14
- @installer = options[:installer]
15
- @tmppath = options[:tmppath] || '/tmp/shaddox/'
16
- @required = true
17
- instance_eval(&block)
18
- end
19
-
20
- def optional(&block)
21
- @required = false
22
- instance_eval(&block)
23
- @required = true
24
- end
25
-
26
- def sh(command, args = nil)
27
- line = "#{command}"
28
- line += " #{args.join(" ")}" if args
29
- exec(line, :verbose => true)
30
- end
31
-
32
- def exec(command, opts = {:verbose => false})
33
- info "Running '#{command}' in '#{Dir.pwd}'", 1 if opts[:verbose] or @debug
34
- system(command)
35
- raise "#{line} failed" unless $? == 0 or !@required
36
- end
37
-
38
- def cd(path, &block)
39
- mkdir(path)
40
- FileUtils.cd(path.exp_path) do
41
- instance_eval(&block)
42
- end
43
- end
44
-
45
- def exists(path)
46
- system("test -e #{path.exp_path}")
47
- end
48
-
49
- def exists_d(path)
50
- system("test -d #{path.exp_path}")
51
- end
52
-
53
- def exists_f(path)
54
- system("test -f #{path.exp_path}")
55
- end
56
-
57
- def ln_s(source, dest, opts = {})
58
- ensure_parent_dir(source)
59
- ensure_parent_dir(dest)
60
- info "Linking '#{source.exp_path}' to '#{dest.exp_path}'", 1 if @debug
61
- FileUtils::ln_s(source.exp_path, dest.exp_path, opts)
62
- end
63
-
64
- def mkdir(path)
65
- info "Ensuring directory '#{path}' exists", 1 if @debug
66
- FileUtils::mkdir_p(path.exp_path)
67
- end
68
-
69
- def ensure_parent_dir(path)
70
- dir, base = File.split(path.exp_path)
71
- mkdir(dir)
72
- end
73
-
74
- def ensure_git()
75
- unless @git_installed
76
- install 'git'
77
- @git_installed = true
78
- end
79
- end
80
-
81
- def repo_deploy(repo_key, deploy_path, opts ={}, &in_deploy_path_block)
82
- keep_releases = opts[:keep_releases] || 5
83
- repo = @repos[repo_key]
84
-
85
- ensure_git()
86
- ensure_parent_dir(deploy_path)
87
- deploy_path = deploy_path.exp_path
88
-
89
- cd deploy_path do
90
-
91
- # Get the current release number
92
- release = 0
93
- cd 'releases' do
94
- current_max = Dir.entries('.').select { |e| e =~ /\d+/ }.max
95
- release = current_max.to_i + 1 if current_max
96
- end
97
-
98
- # Make a new release dir
99
- release_path = "./releases/#{release}"
100
-
101
- case repo.vcs
102
- when :git
103
- # Clone/update repo in vcs:
104
- info 'Updating the repository', 1 if @debug
105
- if exists_d('vcs')
106
- cd 'vcs' do
107
- exec "git fetch #{repo.url} #{repo.branch}:#{repo.branch} --force"
108
- end
109
- else
110
- exec "git clone #{repo.url} vcs --bare"
111
- end
112
- exec "git clone ./vcs #{release_path} --recursive --branch #{repo.branch}"
113
- end
114
-
115
- # Link shared paths
116
- info 'Linking shared paths', 1 if @debug
117
- repo.shared.each do |shared_path|
118
- ln_s "./shared/#{shared_path}", "#{release_path}/#{shared_path}"
119
- end
120
-
121
- # Link ./current to the latest release
122
- info 'Linking current to latest release', 1 if @debug
123
- ln_s release_path, './current'
124
- end
125
-
126
- cd deploy_path, &in_deploy_path_block if block_given?
127
- end
128
-
129
- def install(package)
130
- unless @installer
131
- # TODO: Try to autodetect package manager
132
- warn "No installer is specified for this target.", 1
133
- puts "-------------------"
134
- require 'highline/import'
135
- choose do |menu|
136
- menu.prompt = "Please select a package manager to use:"
137
-
138
- menu.choice(:apt) { @installer = :apt }
139
- menu.choice(:brew) { @installer = :brew }
140
- menu.choice(:pacman) { @installer = :pacman }
141
- end
142
- puts "-------------------"
143
- end
144
- raise "No installer specified for this target!" unless @installer
145
- info "Ensuring #{package} is installed with #{@installer}", 1 if @debug
146
- package_installed = lambda { system("type #{package} >/dev/null 2>&1") }
147
- unless package_installed.call()
148
- case @installer
149
- when :apt
150
- exec "sudo apt-get install -y #{package}"
151
- when :brew
152
- exec "brew install #{package}"
153
- when :pacman
154
- exec "pacman -S --noconfirm #{package}"
155
- end
156
- end
157
- raise "#{package} could not be installed." unless package_installed.call()
158
- end
159
- end
160
- end
@@ -1,61 +0,0 @@
1
- module Shaddox
2
- class ShadowScript
3
- attr_reader :script
4
- def initialize(config, task_key, opts = {})
5
- # Initialize properties
6
- @installer = opts[:installer]
7
- @debug = opts[:debug]
8
-
9
- @config = config
10
- @cast_tasks = []
11
-
12
- # Generate script
13
- params = []
14
- params.push(":installer => :#{@installer}") if @installer
15
- params.push(":debug => #{@debug}") if @debug
16
-
17
- @script = %Q{
18
- require 'shaddox'
19
- Shaddox::Shadow.new({#{params.join(',')}}) do
20
- ## begin generated shadow ##
21
- }
22
- add_repos
23
- cast(task_key)
24
- @script += %Q{
25
- ## end generated shadow ##
26
- end
27
- }
28
- end
29
-
30
- ## cast
31
- # Retrieves a task from the @config and ensures all of its dependencies
32
- # have been added to the script before adding itself. Tasks are only cast
33
- # once to elimate redundency.
34
- def cast(task_key)
35
- task = @config.tasks[task_key]
36
- if !task
37
- raise "The task :#{task_key} could not be found. Please check your Doxfile and try again.".red
38
- end
39
- task.deps.each do |dep_key|
40
- cast(dep_key) if !@cast_tasks.include? dep_key
41
- end
42
- @script += %Q{
43
- ## #{task_key} ##
44
- #{task.to_source}
45
- }
46
- @cast_tasks.push(task_key)
47
- end
48
-
49
- ## add_repos
50
- # Retrieves all repos from the @config and ensures their data is copied
51
- # to the script for use by tasks.
52
- def add_repos
53
- @script += %Q(
54
- @repos = {)
55
- @config.repos.each do |key, repo|
56
- @script += ":#{key} => #{repo.to_source}"
57
- end
58
- @script += %Q(})
59
- end
60
- end
61
- end
@@ -1,154 +0,0 @@
1
- module Shaddox
2
- class TargetError < StandardError ; end
3
- class Target
4
- def new_actor
5
- raise "new_actor method must be implemented by Target subclass"
6
- end
7
- def deploy(shadow_script, opts)
8
- tmpdir = opts[:tmpdir] || '/tmp/shaddox'
9
- shadow_script_path = "#{tmpdir}/shadow_script.rb"
10
- # Everything inside this block is handled by the target's actor (typically an SSH session)
11
- new_actor do
12
-
13
- rm_tmpdir = lambda {
14
- unless !exec("test -e #{tmpdir} >/dev/null")
15
- info "Removing #{tmpdir}", 1
16
- exec("rm -r #{tmpdir}")
17
- end
18
- }
19
-
20
- rm_tmpdir.call() if opts[:force]
21
-
22
- # Try to create tmpdir:
23
- info "Creating #{tmpdir}", 1
24
- unlocked = exec "mkdir #{tmpdir}"
25
-
26
- # Abort if the tmpdir already exists
27
- raise TargetError, "A shadow script is already running on this machine. Try again later." unless unlocked
28
-
29
- begin
30
- # Initial provisioning to ensure that we have everyting we need to execute a shadow script:
31
- ruby_installed = exec 'type ruby >/dev/null'
32
- raise TargetError, "Ruby is required to use shaddox. Please install it manually." unless ruby_installed
33
- gem_installed = exec 'type gem >/dev/null'
34
- raise TargetError, "Gem is required to use shaddox. Please install it manually." unless gem_installed
35
- shaddox_installed = lambda { exec 'gem list shaddox -i >/dev/null' }
36
- if shaddox_installed.call()
37
- info "Updating shaddox...", 1
38
- updated = exec "gem update shaddox", :verbose => false
39
- updated = exec "sudo gem update shaddox" unless updated
40
- warn "Shaddox could not be automatically updated. Please update it manually with 'gem update shaddox'.", 1 unless updated
41
- else
42
- info "Installing shaddox...", 1
43
- installed = exec "gem install shaddox", :verbose => false
44
- installed = exec "sudo gem install shaddox" unless installed
45
- warn "Shaddox could not be automatically installed. Please update it manually with 'gem update shaddox'.", 1 unless installed
46
- end
47
- unless shaddox_installed.call()
48
- raise TargetError, "Shaddox was not found on this target."
49
- end
50
-
51
- # Push the shadow script to tmpdir:
52
- info "Writing shadow script", 1
53
- write_file(shadow_script.script, shadow_script_path)
54
-
55
- # Execute the shadow script:
56
- info "Executing shadow script", 1
57
- raise TargetError, "Shadow script was not executed successfully." unless exec "ruby #{shadow_script_path}"
58
-
59
- rm_tmpdir.call() unless opts[:keep_tmp_dir]
60
- rescue Exception => e
61
- # Make sure the tmpdir is removed even if the provisioning fails:
62
- rm_tmpdir.call() unless opts[:keep_tmp_dir]
63
- raise e
64
- end
65
- end
66
- end
67
- end
68
-
69
- class Actor
70
- def initialize(&block)
71
- instance_eval(&block)
72
- end
73
- def exec(command, opts = {})
74
- raise "exec method must be implemented by Actor subclass"
75
- end
76
- def write_file(content, dest_path)
77
- raise "write_file method must be implemented by Actor subclass"
78
- end
79
- end
80
-
81
- class Localhost < Target
82
- def new_actor(&block)
83
- LocalActor.new(&block)
84
- end
85
- class LocalActor < Actor
86
- def exec(command, opts = {})
87
- system(command)
88
- end
89
- def write_file(content, dest_path)
90
- File.open(dest_path, 'w') { |f| f.write(content) }
91
- end
92
- end
93
- end
94
-
95
- class Server < Target
96
- include SettingContainer
97
- require 'net/ssh'
98
- # ###
99
- # Constructor for Server
100
- # @info param A hash containing the server's info. Allowed keys:
101
- # :host (required)
102
- # :user (required)
103
- # :ssh (required for authentication)
104
- # :installer
105
- #
106
- attr_reader :host, :user, :ssh, :installer
107
- def initialize(info)
108
- @host = info[:host]
109
- @user = info[:user]
110
- @ssh = info[:ssh]
111
- @installer = info[:installer]
112
- end
113
- def new_actor(&block)
114
- SSHActor.new(host, user, ssh, &block)
115
- end
116
- class SSHActor < Actor
117
- def initialize(host, user, ssh_opts, &block)
118
- Net::SSH.start(host, user, ssh_opts) do |ssh|
119
- @ssh = ssh
120
- super(&block)
121
- end
122
- end
123
- def exec(command, opts = {:verbose => true})
124
- require 'highline/import'
125
- exit_code = nil
126
- @ssh.open_channel do |channel|
127
- channel.request_pty do |c, success|
128
- raise "SSH could not obtain a pty." unless success
129
- channel.exec(command)
130
- channel.on_data do |c_, data|
131
- if data =~ /\[sudo\]/ || data =~ /Password/i
132
- warn "Target is asking for password: ", 1
133
- $stdout.print data
134
- pass = ask("") { |q| q.echo = false }
135
- channel.send_data "#{pass}\n"
136
- else
137
- $stdout.print data if opts[:verbose]
138
- end
139
- end
140
- channel.on_request('exit-status') do |ch, data|
141
- exit_code = data.read_long
142
- end
143
- end
144
- end
145
- @ssh.loop
146
- exit_code == 0 ? true : false
147
- end
148
- def write_file(content, dest_path)
149
- require 'shellwords'
150
- exec "echo #{Shellwords.shellescape(content)} > #{dest_path}"
151
- end
152
- end
153
- end
154
- end
data/push.sh DELETED
@@ -1,13 +0,0 @@
1
- #! /bin/sh
2
- #
3
- # install.sh
4
- # Copyright (C) 2014 joshglendenning <joshglendenning@Q.local>
5
- #
6
- # Distributed under terms of the MIT license.
7
- #
8
-
9
-
10
- gem build shaddox.gemspec
11
- gem push shaddox-*
12
- sudo gem install shaddox-*
13
- rm shaddox-*
data/scripts/bootstrap.sh DELETED
@@ -1,18 +0,0 @@
1
- #! /bin/bash
2
- #
3
- # bootstrap.sh
4
- # Copyright (C) 2014 josh <josh@ubuntu>
5
- #
6
- # Distributed under terms of the MIT license.
7
- #
8
-
9
- ensure_installed() {
10
- type $1 >/dev/null 2>&1 || { echo >&2 "$1 is required to use shaddox. Please install it manually."; exit 1; }
11
- }
12
-
13
- ensure_installed(ruby)
14
- ensure_installed(gem)
15
-
16
- if ! gem list shaddox -i; then
17
- gem install shaddox
18
- fi