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 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
+