gfspark 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,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in gfspark.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Tomohito Ozaki
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,50 @@
1
+ # gfspark
2
+
3
+ Growth Forecast on Terminal.
4
+
5
+ gfspark is CLI graph viewer for Growth Forecast.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'gfspark'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install gfspark
20
+
21
+ ## Usage
22
+
23
+ usage: gfspark <url|path|service_name> [section_name] [graph_name]
24
+
25
+ Examples:
26
+ gfspark http://your.gf.com/view_graph/your_service/your_section/your_graph?t=h
27
+ gfspark your_service/your_section/your_graph h --url=http://your.gf.com/view_graph
28
+ gfspark your_service your_section your_graph h --url=http://your.gf.com/view_graph
29
+
30
+ Options:
31
+ --url=VALUE Your GrowthForecast URL
32
+ -u, --user=USER
33
+ -p, --pass=PASS
34
+ -t=VALUE Range of Graph
35
+ --from=VALUE Start date of graph.(2011/12/08 12:10:00) required if t=c or sc
36
+ --to=VALUE End date of graph.(2011/12/08 12:10:00) required if t=c or sc
37
+ -h, --height=VALUE graph height.(default 10
38
+ -w, --width=VALUE graph width.(default is deteced from $COLUMNS
39
+ -c, --color=VALUE Color of graph bar
40
+ --sslnoverify don't verify SSL
41
+ --sslcacert=v SSL CA CERT
42
+ --debug debug print
43
+
44
+ ## Contributing
45
+
46
+ 1. Fork it
47
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
48
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
49
+ 4. Push to the branch (`git push origin my-new-feature`)
50
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/gfspark ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+
4
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
5
+ require 'gfspark'
6
+
7
+ Gfspark.main(ARGV)
data/gfspark.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'gfspark/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "gfspark"
8
+ gem.version = Gfspark::VERSION
9
+ gem.authors = ["Tomohito Ozaki"]
10
+ gem.email = ["ozaki@yuroyoro.com"]
11
+ gem.description = %q{GrowthForecast on Terminal}
12
+ gem.summary = %q{GrowthForecast Graph viewer on Terminal}
13
+ gem.homepage = "http://yuroyoro.github.io/gfspark/"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_dependency 'json'
21
+ gem.add_dependency 'term-ansicolor'
22
+ gem.add_development_dependency 'rake'
23
+ end
data/lib/gfspark.rb ADDED
@@ -0,0 +1,52 @@
1
+ require "gfspark/version"
2
+ # -*- coding: utf-8 -*-
3
+
4
+ if RUBY_VERSION < '1.9.0'
5
+ $KCODE = "UTF8"
6
+ else
7
+ Encoding.default_external = Encoding.find('UTF-8')
8
+ end
9
+
10
+ require 'pp'
11
+ require 'rubygems'
12
+ require 'uri'
13
+ require 'open-uri'
14
+ require "net/http"
15
+ require "net/https"
16
+ require "uri"
17
+ require 'fileutils'
18
+ require 'json'
19
+ require 'optparse'
20
+ require 'yaml'
21
+ require 'term/ansicolor'
22
+
23
+ module Gfspark
24
+ def self.main(argv)
25
+ status = true
26
+
27
+ app = nil
28
+ begin
29
+ app = Gfspark::App.new(argv)
30
+ if app.valid
31
+ status = app.execute
32
+ else
33
+ app.help
34
+ return false
35
+ end
36
+ rescue => e
37
+ puts e
38
+ if app && app.debug
39
+ puts e.backtrace.join("\n")
40
+ pp app.options
41
+ end
42
+ status = false
43
+ end
44
+
45
+ exit(status)
46
+ end
47
+ end
48
+
49
+ require File.dirname(__FILE__) + '/gfspark/config'
50
+ require File.dirname(__FILE__) + '/gfspark/connection'
51
+ require File.dirname(__FILE__) + '/gfspark/graph'
52
+ require File.dirname(__FILE__) + '/gfspark/app'
@@ -0,0 +1,48 @@
1
+ class Gfspark::App
2
+ include Term::ANSIColor
3
+ include ::Gfspark::Config
4
+ include ::Gfspark::Connection
5
+ include ::Gfspark::Graph
6
+
7
+ attr_accessor :debug, :options, :valid
8
+
9
+ def initialize(args)
10
+ @opt_parse_obj = opt_parser
11
+
12
+ if args.nil? || args.empty?
13
+ @valid = false
14
+ return
15
+ end
16
+
17
+ @options = load_default_settings
18
+ try_url(args) || try_path(args) || try_default(args)
19
+
20
+ unless @url && @service && @section && @graph
21
+ puts "Invalid Arguments"
22
+ @valid = false
23
+ return
24
+ end
25
+
26
+ detect_width_and_height!
27
+ set_ssl_options!
28
+ end
29
+
30
+ def execute
31
+ json = fetch(:xport)
32
+ summary = fetch(:summary)
33
+
34
+ render(json, summary)
35
+ true
36
+ end
37
+
38
+ def fetch(api)
39
+ url = "#{@url}/#{api.to_s}/#{@service}/#{@section}/#{@graph}"
40
+ queries = {}
41
+ queries[:t] = @options[:t] || "d"
42
+ queries[:width] = @width
43
+ queries[:from] = @options[:from] if @options[:from].nil?
44
+ queries[:to] = @options[:to] if @options[:to].nil?
45
+
46
+ json = fetch_json(url, {}, queries)
47
+ end
48
+ end
@@ -0,0 +1,123 @@
1
+ module Gfspark::Config
2
+
3
+ def try_url(args)
4
+ return false unless args.first =~ /http?/
5
+
6
+ u = URI.parse(args.shift)
7
+ @url = u.to_s.gsub(u.request_uri, '')
8
+ @graph, @section, @service = u.path.split('/').reverse
9
+ if u.query
10
+ queries = Hash[*u.query.split("&").map{|_| k,v = _.split("=");[k.to_sym, v]}.flatten]
11
+ @options.merge!(queries)
12
+ end
13
+ parse_options(args)
14
+ true
15
+ end
16
+
17
+ def try_path(args)
18
+ return false unless args.first=~ %r(^([^/]+)/([^/]+)/([^/]+)$)
19
+ @service = $1
20
+ @section = $2
21
+ @graph = $3
22
+
23
+ args.shift
24
+ @options[:t] = args.shift if range_arg?(args.first)
25
+
26
+ parse_options(args)
27
+ true
28
+ end
29
+
30
+ def try_default(args)
31
+ @service = args.shift
32
+ @section = args.shift
33
+ @graph = args.shift
34
+
35
+ @options[:t] = args.shift if range_arg?(args.first)
36
+
37
+ parse_options(args)
38
+ true
39
+ end
40
+
41
+ def set_ssl_options!
42
+ @ssl_options = {}
43
+ if @options.key?(:sslNoVerify) && RUBY_VERSION < "1.9.0"
44
+ @ssl_options[:ssl_verify_mode] = OpenSSL::SSL::VERIFY_NONE
45
+ end
46
+ if @options.key?(:sslCaCert)
47
+ @ssl_options[:ssl_ca_cert] = @options[:sslCaCert]
48
+ end
49
+ end
50
+
51
+ def help(options = {})
52
+ puts @opt_parse_obj.banner
53
+ puts <<-MSG
54
+
55
+ Examples:
56
+ gfspark http://your.gf.com/view_graph/your_service/your_section/your_graph?t=h
57
+ gfspark your_service/your_section/your_graph h --url=http://your.gf.com/view_graph
58
+ gfspark your_service your_section your_graph h --url=http://your.gf.com/view_graph
59
+
60
+ MSG
61
+ puts " Options:"
62
+ puts @opt_parse_obj.summarize
63
+ end
64
+
65
+ def parse_options(args)
66
+ @opt_parse_obj.parse!(args)
67
+ args
68
+ end
69
+
70
+ def detect_width_and_height!
71
+ @stty_height, @stty_width = `stty size`.split.map(&:to_i)
72
+
73
+ width = ((@stty_width - 12) / 2).floor
74
+ @options[:width] ||= width
75
+ @width = @options[:width].to_i
76
+ height = @options[:height].to_i
77
+ @height = height.zero? ? 10 : height
78
+ end
79
+
80
+ def load_default_settings
81
+ settings = load_default_settings_with_traversing_to_root ||
82
+ load_default_settings_from_home || {}
83
+
84
+ settings = Hash[*settings.map{|k,v| [k.to_sym, v]}.flatten]
85
+ @url = settings[:url] if settings[:url]
86
+ @service = settings[:service] if settings[:service]
87
+ @section = settings[:section] if settings[:section]
88
+ @graph = settings[:graph] if settings[:graph]
89
+ settings
90
+ end
91
+
92
+ def load_default_settings_with_traversing_to_root(dir = Dir::pwd)
93
+ filename = File.join(dir, '.gfspark')
94
+ return YAML.load_file filename if File.exists? filename
95
+
96
+ parent = File.dirname dir
97
+ load_default_settings_with_traversing_to_root(parent) unless dir == parent
98
+ end
99
+
100
+ def load_default_settings_from_home
101
+ filename = File.join("~/", ".gfspark")
102
+ return YAML.load_file filename if File.exists? filename
103
+ end
104
+
105
+
106
+ def opt_parser
107
+ OptionParser.new{|opts|
108
+ opts.banner = "gfspark : Growth Forecast on Terminal\n\nusage: gfspark <url|path|service_name> [section_name] [graph_name]"
109
+ opts.on("--url=VALUE", "Your GrowthForecast URL"){|v| @options[:url] = v}
110
+ opts.on('-u=USER', '--user=USER'){|v| @options[:username] = v }
111
+ opts.on('-p=PASS', '--pass=PASS'){|v| @options[:password] = v }
112
+ opts.on("-t=VALUE", "Range of Graph"){|v| @options[:t] = v}
113
+ opts.on("--from=VALUE", "Start date of graph.(2011/12/08 12:10:00) required if t=c or sc"){|v| @options[:from] = v}
114
+ opts.on("--to=VALUE", "End date of graph.(2011/12/08 12:10:00) required if t=c or sc"){|v| @options[:to] = v}
115
+ opts.on("-h=VALUE", "--height=VALUE", "graph height.(default 10"){|v| @options[:height] = v}
116
+ opts.on("-w=VALUE", "--width=VALUE", "graph width.(default is deteced from $COLUMNS"){|v| @options[:width] = v}
117
+ opts.on("-c=VALUE", "--color=VALUE", "Color of graph bar"){|v| @options[:color] = v}
118
+ opts.on("--sslnoverify", "don't verify SSL"){|v| @options[:sslNoVerify] = true}
119
+ opts.on("--sslcacert=v", "SSL CA CERT"){|v| @options[:sslCaCert] = v}
120
+ opts.on("--debug", "debug print"){@debug= true }
121
+ }
122
+ end
123
+ end
@@ -0,0 +1,94 @@
1
+ module Gfspark::Connection
2
+ @ssl_options = {}
3
+
4
+ def connection(host, port)
5
+ env = ENV['http_proxy'] || ENV['HTTP_PROXY']
6
+ if env
7
+ uri = URI(env)
8
+ proxy_host, proxy_port = uri.host, uri.port
9
+ Net::HTTP::Proxy(proxy_host, proxy_port).new(host, port)
10
+ else
11
+ Net::HTTP.new(host, port)
12
+ end
13
+ end
14
+
15
+ def fetch_json(url, options = {}, params = {})
16
+ response = send_request(url, {},options, params, :get)
17
+ raise response.code unless response_success?(response)
18
+ json = JSON.parse(response.body)
19
+
20
+ if @debug
21
+ puts '-' * 80
22
+ puts url
23
+ pp json
24
+ puts '-' * 80
25
+ end
26
+
27
+ json
28
+ end
29
+
30
+ def send_request(url, json = {}, options = {}, params = {}, method = :post)
31
+ url = "#{url}"
32
+ uri = URI.parse(url)
33
+
34
+ if @debug
35
+ puts '-' * 80
36
+ puts url
37
+ pp json
38
+ puts '-' * 80
39
+ end
40
+
41
+ https = connection(uri.host, uri.port)
42
+ https.use_ssl = true
43
+ https.verify_mode = @ssl_options[:ssl_verify_mode] || OpenSSL::SSL::VERIFY_NONE
44
+
45
+ store = OpenSSL::X509::Store.new
46
+ unless @ssl_options[:ssl_ca_cert].nil?
47
+ if File.directory? @ssl_options[:ssl_ca_cert]
48
+ store.add_path @ssl_options[:ssl_ca_cert]
49
+ else
50
+ store.add_file @ssl_options[:ssl_ca_cert]
51
+ end
52
+ http.cert_store = store
53
+ else
54
+ store.set_default_paths
55
+ end
56
+ https.cert_store = store
57
+
58
+ https.set_debug_output $stderr if @debug && https.respond_to?(:set_debug_output)
59
+
60
+ https.start{|http|
61
+
62
+ path = "#{uri.path}"
63
+ path += "?" + params.map{|k,v| "#{k}=#{v}"}.join("&") unless params.empty?
64
+
65
+ request = case method
66
+ when :post then Net::HTTP::Post.new(path)
67
+ when :put then Net::HTTP::Put.new(path)
68
+ when :get then Net::HTTP::Get.new(path)
69
+ else raise "unknown method #{method}"
70
+ end
71
+
72
+ # add basic auth header...
73
+ if @options[:username] && @options[:password]
74
+ request.basic_auth @options[:username], @options[:password]
75
+ end
76
+
77
+ request.set_content_type("application/json")
78
+ request.body = json.to_json unless json.nil?
79
+
80
+ response = http.request(request)
81
+ if @debug
82
+ puts "#{response.code}: #{response.msg}"
83
+ puts response.body
84
+ end
85
+
86
+ response
87
+ }
88
+ end
89
+
90
+ def response_success?(response)
91
+ code = response.code.to_i
92
+ code >= 200 && code < 300
93
+ end
94
+ end
@@ -0,0 +1,74 @@
1
+ module Gfspark::Graph
2
+ @height = 20
3
+
4
+ BARS = [" ", "▁", "▂", "▃", "▄", "▅", "▆", "▇", "█" ]
5
+ def bar(val, unit)
6
+ n = (val.to_f/unit).ceil
7
+ @height.times.map{|i|
8
+ x = n - (i * 8)
9
+ (x > 0) ? (x < 8) ? BARS[x] : BARS.last : " "
10
+ }
11
+ end
12
+
13
+ def render(json, summary)
14
+ rows = json['rows']
15
+ max = rows.flatten.compact.max
16
+ max_val = (max / 8).ceil * 8
17
+ unit = max_val / (@height * 8).to_f
18
+
19
+ s = Time.at(json["start_timestamp"].to_i).strftime("%Y-%m-%d %H:%M:%S")
20
+ e = Time.at(json["end_timestamp"].to_i).strftime("%Y-%m-%d %H:%M:%S")
21
+
22
+ puts " #{blue(json["column_names"].first)}"
23
+ puts ""
24
+ puts " #{period_title} #{s} - #{e}"
25
+ puts ""
26
+
27
+ result = []
28
+ rows.flatten.map{|row| bar(row, unit)}.transpose.reverse.each_with_index do |row, i|
29
+ i = (@height- i)
30
+ label = i.even? ? sprintf("%.1f", unit * i * 8) : ""
31
+ line = row.join
32
+ if color = @options[:color]
33
+ line = Term::ANSIColor.send(color, line)
34
+ end
35
+ result << "#{sprintf("%10s", label)} | #{line} |"
36
+ end
37
+ puts result.join("\n")
38
+ puts ""
39
+
40
+ sums = summary.first.last
41
+ puts " #{sprintf("cur: %.1f ave: %.1f max: %.1f min %.1f", *sums)}"
42
+ end
43
+
44
+ def period_title
45
+ case @options[:t]
46
+ when "c", "sc" then sprintf(RANGES[@options[:t]], @options[:from], @options[:to])
47
+ else RANGES[@options[:t]]
48
+ end
49
+ end
50
+
51
+ RANGES = {
52
+ "y" => 'Year (1day avg)',
53
+ "m" => 'Month (2hour avg)',
54
+ "w" => 'Week (30min avg)',
55
+ "3d" => '3 Days (5min avg)',
56
+ "s3d" => '3 Days (5min avg)',
57
+ "d" => 'Day (5min avg)',
58
+ "sd" => 'Day (1min avg)' ,
59
+ "8h" => '8 Hours (5min avg)',
60
+ "s8h" => '8 Hours (1min avg)' ,
61
+ "4h" => '4 Hours (5min avg)',
62
+ "s4h" => '4 Hours (1min avg)' ,
63
+ "h" => 'Hour (5min avg), ',
64
+ "sh" => 'Hour (1min avg)' ,
65
+ "n" => 'Half Day (5min avg)',
66
+ "sn" => 'Half Day (1min avg)',
67
+ "c" => "%s to $s",
68
+ "sc" => "%s to $s"
69
+ }
70
+
71
+ def range_arg?(t)
72
+ RANGES.keys.include? t
73
+ end
74
+ end
@@ -0,0 +1,3 @@
1
+ module Gfspark
2
+ VERSION = "0.0.1"
3
+ end
metadata ADDED
@@ -0,0 +1,121 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gfspark
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
+ - Tomohito Ozaki
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2013-05-28 00:00:00 +09:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ prerelease: false
23
+ name: json
24
+ type: :runtime
25
+ requirement: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ hash: 3
31
+ segments:
32
+ - 0
33
+ version: "0"
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ prerelease: false
37
+ name: term-ansicolor
38
+ type: :runtime
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ hash: 3
45
+ segments:
46
+ - 0
47
+ version: "0"
48
+ version_requirements: *id002
49
+ - !ruby/object:Gem::Dependency
50
+ prerelease: false
51
+ name: rake
52
+ type: :development
53
+ requirement: &id003 !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ hash: 3
59
+ segments:
60
+ - 0
61
+ version: "0"
62
+ version_requirements: *id003
63
+ description: GrowthForecast on Terminal
64
+ email:
65
+ - ozaki@yuroyoro.com
66
+ executables:
67
+ - gfspark
68
+ extensions: []
69
+
70
+ extra_rdoc_files: []
71
+
72
+ files:
73
+ - .gitignore
74
+ - Gemfile
75
+ - LICENSE.txt
76
+ - README.md
77
+ - Rakefile
78
+ - bin/gfspark
79
+ - gfspark.gemspec
80
+ - lib/gfspark.rb
81
+ - lib/gfspark/app.rb
82
+ - lib/gfspark/config.rb
83
+ - lib/gfspark/connection.rb
84
+ - lib/gfspark/graph.rb
85
+ - lib/gfspark/version.rb
86
+ has_rdoc: true
87
+ homepage: http://yuroyoro.github.io/gfspark/
88
+ licenses: []
89
+
90
+ post_install_message:
91
+ rdoc_options: []
92
+
93
+ require_paths:
94
+ - lib
95
+ required_ruby_version: !ruby/object:Gem::Requirement
96
+ none: false
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ hash: 3
101
+ segments:
102
+ - 0
103
+ version: "0"
104
+ required_rubygems_version: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ hash: 3
110
+ segments:
111
+ - 0
112
+ version: "0"
113
+ requirements: []
114
+
115
+ rubyforge_project:
116
+ rubygems_version: 1.5.2
117
+ signing_key:
118
+ specification_version: 3
119
+ summary: GrowthForecast Graph viewer on Terminal
120
+ test_files: []
121
+