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