clinode 0.0.1
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/.gitignore +4 -0
- data/Gemfile +4 -0
- data/README.txt +23 -0
- data/Rakefile +2 -0
- data/bin/clinode +6 -0
- data/clinode.gemspec +29 -0
- data/lib/clinode/command.rb +103 -0
- data/lib/clinode/extensions.rb +39 -0
- data/lib/clinode/helper.rb +4 -0
- data/lib/clinode/ui.rb +20 -0
- data/lib/clinode/version.rb +3 -0
- data/lib/clinode.rb +168 -0
- data/lib/commands/helpers.rb +16 -0
- data/lib/commands/stackscript.rb +85 -0
- metadata +170 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
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
data/bin/clinode
ADDED
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
|
+
|
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
|
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
|
+
|