clinode 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in clinode.gemspec
4
+ gemspec
data/README.txt ADDED
@@ -0,0 +1,23 @@
1
+ Command Linode control over Linode thru the Linode API.
2
+
3
+ Here's the expected command line interface
4
+
5
+ API Key is read from
6
+ - ENV["LINODE_API_KEY"]
7
+ - ~/.linode.yml's api_token key
8
+
9
+ linode stackscript list
10
+ - Lists all your stackscripts
11
+
12
+ linode stackscript <stackscript_id> [-o] [-u update_stackscript_script]
13
+ - Shows content with meta data of given stackscript
14
+ - -o Outputs the stackscipt text only, good with redirection to file of your choice
15
+ - -u Updates stackscript by reading from specified file
16
+ - -e name:value pair of attributes to be updated for the given stackscript
17
+
18
+ linode stackscript download [--dir=<dir>]
19
+ - Downloads all your stackscripts in the format <stackscript_id>.stack.sh in the current directory or a directory of your choosing
20
+
21
+ linode stackscript upload [-dir=<dir>]
22
+ - Uploads all files in the format <stackscript_id>.stack.sh in the current directory or a directory of your choosing onto linode.
23
+
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
data/bin/clinode ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift(File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')))
4
+ require 'clinode'
5
+
6
+ Clinode.activate ARGV
data/clinode.gemspec ADDED
@@ -0,0 +1,29 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "clinode/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "clinode"
7
+ s.version = Clinode::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Aditya Sanghi"]
10
+ s.email = ["asanghi@me.com"]
11
+ s.homepage = "http://me.adityasanghi.com"
12
+ s.summary = %q{Command Line Control over your Linodes}
13
+ s.description = %q{Extensive control of your linode(s) using a fully featured command line tool}
14
+
15
+ s.rubyforge_project = "clinode"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_dependency "linode"
23
+ s.add_dependency "text-hyphen", "1.0.0"
24
+ s.add_dependency "text-format", "1.0.0"
25
+ s.add_dependency "highline", "~> 1.5.1"
26
+ s.add_dependency "json_pure", "~> 1.5.1"
27
+
28
+ s.add_development_dependency "rspec"
29
+ end
@@ -0,0 +1,103 @@
1
+ require 'fileutils'
2
+
3
+ if RUBY_PLATFORM =~ /mswin|mingw/
4
+ begin
5
+ require 'win32/open3'
6
+ rescue LoadError
7
+ warn "You must 'gem install win32-open3' to use the github command on Windows"
8
+ exit 1
9
+ end
10
+ else
11
+ require 'open3'
12
+ end
13
+
14
+ module Clinode
15
+ class Command
16
+ include FileUtils
17
+
18
+ def initialize(block)
19
+ (class << self;self end).send :define_method, :command, &block
20
+ end
21
+
22
+ def call(*args)
23
+ arity = method(:command).arity
24
+ args << nil while args.size < arity
25
+ send :command, *args
26
+ end
27
+
28
+ def helper
29
+ @helper ||= Helper.new
30
+ end
31
+
32
+ def options
33
+ Clinode.options
34
+ end
35
+
36
+ def run(method, command)
37
+ if command.is_a? Array
38
+ command = [ 'git', command ].flatten
39
+ else
40
+ command = 'git ' + command
41
+ end
42
+
43
+ send method, *command
44
+ end
45
+
46
+ def sh(*command)
47
+ Shell.new(*command).run
48
+ end
49
+
50
+ def die(message)
51
+ puts "=> #{message}"
52
+ exit!
53
+ end
54
+
55
+ def highline
56
+ @highline ||= HighLine.new
57
+ end
58
+
59
+ def shell_user
60
+ ENV['USER']
61
+ end
62
+
63
+ def current_user?(user)
64
+ user == shell_user
65
+ end
66
+
67
+ class Shell < String
68
+ attr_reader :error
69
+ attr_reader :out
70
+
71
+ def initialize(*command)
72
+ @command = command
73
+ end
74
+
75
+ def run
76
+ Clinode.debug "sh: #{command}"
77
+
78
+ out = err = nil
79
+ Open3.popen3(*@command) do |_, pout, perr|
80
+ out = pout.read.strip
81
+ err = perr.read.strip
82
+ end
83
+
84
+ replace @error = err unless err.empty?
85
+ replace @out = out unless out.empty?
86
+
87
+ self
88
+ end
89
+
90
+ def command
91
+ @command.join(' ')
92
+ end
93
+
94
+ def error?
95
+ !!@error
96
+ end
97
+
98
+ def out?
99
+ !!@out
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,39 @@
1
+ # define #try
2
+ class Object
3
+ def try
4
+ self
5
+ end
6
+ end
7
+
8
+ class NilClass
9
+ klass = Class.new
10
+ klass.class_eval do
11
+ def method_missing(*args)
12
+ self
13
+ end
14
+ end
15
+ NilProxy = klass.new
16
+ def try
17
+ NilProxy
18
+ end
19
+ end
20
+
21
+ # define #tap
22
+ class Object
23
+ def tap(&block)
24
+ block.call(self)
25
+ self
26
+ end
27
+ end
28
+
29
+ # cute
30
+ module Color
31
+ COLORS = { :clear => 0, :red => 31, :green => 32, :yellow => 33 }
32
+ def self.method_missing(color_name, *args)
33
+ color(color_name) + args.first + color(:clear)
34
+ end
35
+ def self.color(color)
36
+ "\e[#{COLORS[color.to_sym]}m"
37
+ end
38
+ end
39
+
@@ -0,0 +1,4 @@
1
+ module Clinode
2
+ class Helper
3
+ end
4
+ end
data/lib/clinode/ui.rb ADDED
@@ -0,0 +1,20 @@
1
+ require 'rubygems'
2
+ require "readline"
3
+ require "highline"
4
+ module Clinode
5
+ module UI
6
+ extend self
7
+ # Take a list of items, including optional ' # some description' on each and
8
+ # return the selected item (without the description)
9
+ def display_select_list(list)
10
+ HighLine.track_eof = false
11
+ long_result = HighLine.new.choose do |menu|
12
+ list.each_with_index do |item, i|
13
+ menu.choice((i < 9) ? " #{item}" : item)
14
+ end
15
+ menu.header = "Select a repository to clone"
16
+ end
17
+ long_result && long_result.gsub(/\s+#.*$/,'').gsub(/^\ /,'')
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,3 @@
1
+ module Clinode
2
+ VERSION = "0.0.1"
3
+ end
data/lib/clinode.rb ADDED
@@ -0,0 +1,168 @@
1
+ require 'rubygems'
2
+ require 'linode'
3
+
4
+ $:.unshift File.dirname(__FILE__)
5
+ require 'clinode/extensions'
6
+ require 'clinode/command'
7
+ require 'clinode/helper'
8
+ require 'clinode/ui'
9
+ require 'fileutils'
10
+ require 'rubygems'
11
+ require 'open-uri'
12
+ require 'json'
13
+ require 'yaml'
14
+ require 'text/format'
15
+
16
+ module Clinode
17
+ extend self
18
+
19
+ BasePath = File.expand_path(File.dirname(__FILE__))
20
+
21
+ def command(command, options = {}, &block)
22
+ command = command.to_s
23
+ debug "Registered `#{command}`"
24
+ descriptions[command] = @next_description if @next_description
25
+ @next_description = nil
26
+ flag_descriptions[command].update @next_flags if @next_flags
27
+ usage_descriptions[command] = @next_usage if @next_usage
28
+ @next_flags = nil
29
+ @next_usage = []
30
+ commands[command] = Command.new(block)
31
+ Array(options[:alias] || options[:aliases]).each do |command_alias|
32
+ commands[command_alias.to_s] = commands[command.to_s]
33
+ end
34
+ end
35
+
36
+ def desc(str)
37
+ @next_description = str
38
+ end
39
+
40
+ def flags(hash)
41
+ @next_flags ||= {}
42
+ @next_flags.update hash
43
+ end
44
+
45
+ def usage(string)
46
+ @next_usage ||= []
47
+ @next_usage << string
48
+ end
49
+
50
+ def helper(command, &block)
51
+ debug "Helper'd `#{command}`"
52
+ Helper.send :define_method, command, &block
53
+ end
54
+
55
+ def debug(*messages)
56
+ puts *messages.map { |m| "== #{m}" } if debug?
57
+ end
58
+
59
+ def debug?
60
+ !!@debug
61
+ end
62
+
63
+ def descriptions
64
+ @descriptions ||= {}
65
+ end
66
+
67
+ def flag_descriptions
68
+ @flagdescs ||= Hash.new { |h, k| h[k] = {} }
69
+ end
70
+
71
+ def usage_descriptions
72
+ @usage_descriptions ||= Hash.new { |h, k| h[k] = [] }
73
+ end
74
+
75
+ def options
76
+ @options
77
+ end
78
+
79
+ def original_args
80
+ @@original_args ||= []
81
+ end
82
+
83
+ def parse_options(args)
84
+ idx = 0
85
+ args.clone.inject({}) do |memo, arg|
86
+ case arg
87
+ when /^--(.+?)=(.*)/
88
+ args.delete_at(idx)
89
+ memo.merge($1.to_sym => $2)
90
+ when /^--(.+)/
91
+ args.delete_at(idx)
92
+ memo.merge($1.to_sym => true)
93
+ when "--"
94
+ args.delete_at(idx)
95
+ return memo
96
+ else
97
+ idx += 1
98
+ memo
99
+ end
100
+ end
101
+ end
102
+
103
+ def activate(args)
104
+ @@original_args = args.clone
105
+ @options = parse_options(args)
106
+ @debug = @options.delete(:debug)
107
+ Dir[BasePath + '/commands/*.rb'].each do |command|
108
+ load command
109
+ end
110
+ invoke(args.shift, *args)
111
+ end
112
+
113
+ def invoke(command, *args)
114
+ block = find_command(command)
115
+ debug "Invoking `#{command}`"
116
+ block.call(*args)
117
+ end
118
+
119
+ def find_command(name)
120
+ name = name.to_s
121
+ commands[name] || (commands[name] = Command.new(name)) || commands['default']
122
+ end
123
+
124
+ def commands
125
+ @commands ||= {}
126
+ end
127
+
128
+ def load(file)
129
+ file[0] =~ /^\// ? path = file : path = BasePath + "/commands/#{File.basename(file)}"
130
+ data = File.read(path)
131
+ Clinode.module_eval data, path
132
+ end
133
+
134
+ end
135
+
136
+ Clinode.command :default, :aliases => ['', '-h', 'help', '-help', '--help'] do
137
+ message = []
138
+ message << "Usage: clinode command <space separated arguments>"
139
+ message << "Available commands:"
140
+ longest = Clinode.descriptions.map { |d,| d.to_s.size }.max
141
+ indent = longest + 6 # length of " " + " => "
142
+ fmt = Text::Format.new(
143
+ :first_indent => indent,
144
+ :body_indent => indent,
145
+ :columns => 79 # be a little more lenient than the default
146
+ )
147
+ sorted = Clinode.descriptions.keys.sort
148
+ sorted.each do |command|
149
+ desc = Clinode.descriptions[command]
150
+ cmdstr = "%-#{longest}s" % command
151
+ desc = fmt.format(desc).strip # strip to eat first "indent"
152
+ message << " #{cmdstr} => #{desc}"
153
+ flongest = Clinode.flag_descriptions[command].map { |d,| "--#{d}".size }.max
154
+ ffmt = fmt.clone
155
+ ffmt.body_indent += 2 # length of "% " and/or "--"
156
+ Clinode.usage_descriptions[command].each do |usage_descriptions|
157
+ usage_descriptions.split("\n").each do |usage|
158
+ usage_str = "%% %-#{flongest}s" % usage
159
+ message << ffmt.format(usage_str)
160
+ end
161
+ end
162
+ Clinode.flag_descriptions[command].sort {|a,b| a.to_s <=> b.to_s }.each do |flag, fdesc|
163
+ flagstr = "#{" " * longest} %-#{flongest}s" % "--#{flag}"
164
+ message << ffmt.format(" #{flagstr}: #{fdesc}")
165
+ end
166
+ end
167
+ puts message.map { |m| m.gsub(/\n$/,'') }.join("\n") + "\n"
168
+ end
@@ -0,0 +1,16 @@
1
+ helper :linode_config do
2
+ config_file = "#{ENV['HOME']}/.linode.yml"
3
+ if File.exists?(config_file)
4
+ config = YAML::load_file(config_file)
5
+ config.keys.each do |k|
6
+ Clinode.options[k] = config[k]
7
+ end
8
+ end
9
+ end
10
+
11
+ helper :linode do
12
+ linode_config
13
+ if Clinode.options[:api_token]
14
+ Linode.new(:api_key => Clinode.options[:api_token])
15
+ end
16
+ end
@@ -0,0 +1,85 @@
1
+ # This shouldnt be required if we get the patch into rick's linode api gem
2
+ helper :stackscript_linode do
3
+ Linode::Stackscript.new(:api_key => Clinode.options[:api_token])
4
+ end
5
+
6
+ helper :print_stackscript do |script|
7
+ if Clinode.options[:output]
8
+ puts script.script
9
+ else
10
+ puts script.to_yaml
11
+ end
12
+ end
13
+
14
+ helper :stackscript_list do |ls|
15
+ Clinode.debug "listing"
16
+ ls.list.each do |stackscript|
17
+ print_stackscript(stackscript)
18
+ end
19
+ end
20
+
21
+ helper :stackscript_meta_update do |ls,stackscript_id,opts|
22
+ params = opts
23
+ params[:stackscriptid] = stackscript_id
24
+ ls.update(params)
25
+ end
26
+
27
+ helper :stackscript_update do |ls,stackscript_id,filename|
28
+ if File.exists?(filename)
29
+ script = File.read(filename)
30
+ ls.update(:stackscriptid => stackscript_id,:script => script)
31
+ puts "Stack Script #{stackscript_id} uploaded."
32
+ end
33
+ end
34
+
35
+ helper :stackscript_upload do |ls|
36
+ Clinode.debug "uploading"
37
+ Dir["#{Clinode.options[:dir]}/*_stack.sh"].each do |filename|
38
+ if (filename =~ /(\d+)\_stack\.sh$/)
39
+ stackscript_update(ls,$1,filename)
40
+ end
41
+ end
42
+ end
43
+
44
+ helper :stackscript_download do |ls|
45
+ ls.list.each do |stackscript|
46
+ filename = "#{Clinode.options[:dir]}/#{stackscript.stackscriptid}_stack.sh"
47
+ File.open(filename,"w+"){|f|f.write(stackscript.script)}
48
+ Clinode.debug "Writing Script #{stackscript.stackscriptid} #{stackscript.label} into #{filename}"
49
+ end
50
+ end
51
+
52
+ helper :stackscript_process do |ls,stackscript_id|
53
+ Clinode.debug "Fetching StackScript #{stackscript_id}"
54
+ stackscript = ls.list(:stackscript => stackscript_id)
55
+ print_stackscript(stackscript[0])
56
+ end
57
+
58
+ desc "List your stackscripts"
59
+ usage "--dir=<directory> stackscript directory to upload from/download to"
60
+ flags :output => "Output the content of the stackscript only"
61
+ flags :update => "Update the content of the stackscript"
62
+ command :stackscript do |arg|
63
+ helper.linode_config
64
+ ls = helper.stackscript_linode
65
+ return if !ls
66
+
67
+ options[:dir] ||= "."
68
+
69
+ case arg
70
+ when "list"
71
+ helper.stackscript_list(ls)
72
+ when "upload"
73
+ helper.stackscript_upload(ls)
74
+ when "download"
75
+ helper.stackscript_download(ls)
76
+ when /^\d+$/
77
+ if options[:update]
78
+ filename = "#{options[:dir]}/#{arg}_stack.sh"
79
+ helper.stackscript_update(ls,arg,filename)
80
+ else
81
+ helper.stackscript_process(ls,arg)
82
+ end
83
+ end
84
+
85
+ end
metadata ADDED
@@ -0,0 +1,170 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: clinode
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Aditya Sanghi
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-07-16 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: linode
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 3
29
+ segments:
30
+ - 0
31
+ version: "0"
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: text-hyphen
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - "="
41
+ - !ruby/object:Gem::Version
42
+ hash: 23
43
+ segments:
44
+ - 1
45
+ - 0
46
+ - 0
47
+ version: 1.0.0
48
+ type: :runtime
49
+ version_requirements: *id002
50
+ - !ruby/object:Gem::Dependency
51
+ name: text-format
52
+ prerelease: false
53
+ requirement: &id003 !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - "="
57
+ - !ruby/object:Gem::Version
58
+ hash: 23
59
+ segments:
60
+ - 1
61
+ - 0
62
+ - 0
63
+ version: 1.0.0
64
+ type: :runtime
65
+ version_requirements: *id003
66
+ - !ruby/object:Gem::Dependency
67
+ name: highline
68
+ prerelease: false
69
+ requirement: &id004 !ruby/object:Gem::Requirement
70
+ none: false
71
+ requirements:
72
+ - - ~>
73
+ - !ruby/object:Gem::Version
74
+ hash: 1
75
+ segments:
76
+ - 1
77
+ - 5
78
+ - 1
79
+ version: 1.5.1
80
+ type: :runtime
81
+ version_requirements: *id004
82
+ - !ruby/object:Gem::Dependency
83
+ name: json_pure
84
+ prerelease: false
85
+ requirement: &id005 !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ~>
89
+ - !ruby/object:Gem::Version
90
+ hash: 1
91
+ segments:
92
+ - 1
93
+ - 5
94
+ - 1
95
+ version: 1.5.1
96
+ type: :runtime
97
+ version_requirements: *id005
98
+ - !ruby/object:Gem::Dependency
99
+ name: rspec
100
+ prerelease: false
101
+ requirement: &id006 !ruby/object:Gem::Requirement
102
+ none: false
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ hash: 3
107
+ segments:
108
+ - 0
109
+ version: "0"
110
+ type: :development
111
+ version_requirements: *id006
112
+ description: Extensive control of your linode(s) using a fully featured command line tool
113
+ email:
114
+ - asanghi@me.com
115
+ executables:
116
+ - clinode
117
+ extensions: []
118
+
119
+ extra_rdoc_files: []
120
+
121
+ files:
122
+ - .gitignore
123
+ - Gemfile
124
+ - README.txt
125
+ - Rakefile
126
+ - bin/clinode
127
+ - clinode.gemspec
128
+ - lib/clinode.rb
129
+ - lib/clinode/command.rb
130
+ - lib/clinode/extensions.rb
131
+ - lib/clinode/helper.rb
132
+ - lib/clinode/ui.rb
133
+ - lib/clinode/version.rb
134
+ - lib/commands/helpers.rb
135
+ - lib/commands/stackscript.rb
136
+ homepage: http://me.adityasanghi.com
137
+ licenses: []
138
+
139
+ post_install_message:
140
+ rdoc_options: []
141
+
142
+ require_paths:
143
+ - lib
144
+ required_ruby_version: !ruby/object:Gem::Requirement
145
+ none: false
146
+ requirements:
147
+ - - ">="
148
+ - !ruby/object:Gem::Version
149
+ hash: 3
150
+ segments:
151
+ - 0
152
+ version: "0"
153
+ required_rubygems_version: !ruby/object:Gem::Requirement
154
+ none: false
155
+ requirements:
156
+ - - ">="
157
+ - !ruby/object:Gem::Version
158
+ hash: 3
159
+ segments:
160
+ - 0
161
+ version: "0"
162
+ requirements: []
163
+
164
+ rubyforge_project: clinode
165
+ rubygems_version: 1.8.5
166
+ signing_key:
167
+ specification_version: 3
168
+ summary: Command Line Control over your Linodes
169
+ test_files: []
170
+