cronbox 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 344b223d39b260d6f3197c8dc6d98686d7171955
4
+ data.tar.gz: 4980b00c568b679f1e4efe53e5aecbafcd294179
5
+ SHA512:
6
+ metadata.gz: 3b676ba4b02121ed2e8cb43579ccf851c1f5f20fb14506aa9ce066c9393d1a1aafd10fa5a978b7ea8a610971585ce3b98f607773b70a9dad409500dda6cf655b
7
+ data.tar.gz: 7b5c9b99eaf732da774d166f914c1d864d21487f2af44c0c4286205e413a9df91025c8770773a92399797751e1caa7629a5fcf7c9589e41ebf9cb03b17e30b1b
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /version.lock
@@ -0,0 +1,8 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.3.1
5
+ - 1.9.2
6
+
7
+ notifications:
8
+ email: false
@@ -0,0 +1,8 @@
1
+ # Versioneer Project Configuration
2
+ # https://git.io/versioneer-help
3
+
4
+ type: Git
5
+ bump_segment: minor
6
+ prereleases:
7
+ - alpha
8
+ - beta
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in cronbox.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 BinaryBabel OSS
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,71 @@
1
+ # Cronbox
2
+
3
+ **Command line inbox and timecard for scheduled job status and output.**
4
+
5
+ Run any scheduled command through Cronbox to store its exit status and output for later review and diagnostics. Data is stored as simple JSON in the default location of `$HOME/.cronbox`
6
+
7
+ ```
8
+ | Cronbox | *=Output
9
+ =====================================================================
10
+ | ID | COMMAND | EXIT | WHEN |
11
+ =====================================================================
12
+ | 1 | /usr/local/bin/task sync | 0 | 12 minutes ago |
13
+ ---------------------------------------------------------------------
14
+ | 2 | ~/Dropbox/bin/run-daily-backup | *0 | 20 minutes ago |
15
+ ---------------------------------------------------------------------
16
+ ```
17
+
18
+ ## Installation
19
+
20
+ $ gem install cronbox
21
+
22
+ ## Usage
23
+
24
+ For complete usage options, please consult `cb --help`
25
+
26
+ $ cb # Query cronbox index timecard
27
+ $ cb CMD [ARGS] # Run and record output of command
28
+ $ cb -o ID # Review full-output of entry
29
+
30
+ ### CRONTAB USAGE WITH RVM
31
+
32
+ If you're using RVM to manage Ruby, Cronbox may not be available to crontab due to missing paths. Try adding the following two options to the top of your file:
33
+
34
+ ```
35
+ SHELL=/bin/bash
36
+ BASH_ENV=$HOME/.profile
37
+ * * * * * cb true # Cronbox testing
38
+ ```
39
+
40
+ * Depending on your OS/Environment you might require `.bash_profile` instead.
41
+ * The `cb true` test line should show up on your Cronbox timecard.
42
+ * Once it does you'll know you have everything working correctly and can remove it.
43
+
44
+ ## Contributing
45
+
46
+ Bug reports and pull requests are welcome on GitHub at https://github.com/binarybabel/cronbox.
47
+
48
+ * After checking out the repo, run `bin/setup` to install dependencies.
49
+ * Then, run `rake test` to run the tests.
50
+
51
+
52
+ ## Author & License
53
+
54
+ 0101010
55
+ 0010011
56
+ 110101
57
+ 0011
58
+ __ __ __ __ __ 0100010
59
+ / ` |__) / \ |\ | |__) / \ \_/ 1010 0010101000001
60
+ \__, | \ \__/ | \| |__) \__/ / \ 010101110100111101010010
61
+ 01 0011000100
62
+ A BinaryBabel OSS Project
63
+ 0100
64
+ 01001001 binarybabel.org
65
+ 0100111001 000001010001110
66
+ 101 0010010000010100100101
67
+ 00111 0010011110100011001010
68
+ 0110 10000010100111001000100
69
+
70
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
71
+
@@ -0,0 +1,18 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ end
9
+
10
+ task :default => :test
11
+
12
+ task :versioneer do
13
+ system './bin/versioneer relock'
14
+ end
15
+
16
+ Rake::Task[:build].enhance [:versioneer] do
17
+ system './bin/versioneer unlock -q'
18
+ end
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "cronbox"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+ #
4
+ # This file was generated by Bundler.
5
+ #
6
+ # The application 'versioneer' is installed as part of a gem, and
7
+ # this file is here to facilitate running it.
8
+ #
9
+
10
+ require "pathname"
11
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
12
+ Pathname.new(__FILE__).realpath)
13
+
14
+ require "rubygems"
15
+ require "bundler/setup"
16
+
17
+ load Gem.bin_path("versioneer", "versioneer")
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'cronbox/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'cronbox'
8
+ spec.version = Cronbox::VERSION
9
+ spec.authors = ['BinaryBabel OSS']
10
+ spec.email = ['oss@binarybabel.org']
11
+
12
+ spec.summary = 'Command line inbox and timecard for scheduled job status and output.'
13
+ spec.homepage = 'https://github.com/binarybabel/cronbox'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
17
+ f.match(%r{^(test|spec|features)/})
18
+ end
19
+ spec.bindir = 'exe'
20
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
+ spec.require_paths = ['lib']
22
+
23
+ spec.files += ['version.lock']
24
+ spec.add_runtime_dependency 'versioneer'
25
+
26
+ spec.add_development_dependency 'bundler', '~> 1.13'
27
+ spec.add_development_dependency 'rake', '~> 10.0'
28
+ spec.add_development_dependency 'minitest', '~> 5.0'
29
+ spec.add_development_dependency 'pry', '~> 0.10.0'
30
+ spec.add_development_dependency 'pry-byebug', '> 3'
31
+ end
data/exe/cb ADDED
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'optparse'
5
+ require 'cronbox'
6
+
7
+ options = {}
8
+
9
+ opparser = OptionParser.new do |opts|
10
+ opts.banner = [
11
+ '',
12
+ 'Cronbox Usage https://git.io/cronbox',
13
+ '---------------------------------------------',
14
+ ' Query: cb [-e]',
15
+ ' Run: cb [-l LABEL] RUN_CMD [CMD_ARGS]',
16
+ '---------------------------------------------',
17
+ '',
18
+ ' Options:'
19
+ ].join("\n")
20
+ opts.on('-f DATA_FILE', '--file DATA_FILE', 'Data file, default: $HOME/.cronbox') do |v|
21
+ options[:file] = v
22
+ end
23
+ opts.on('-e', '--errors', 'Report errors only, with log output') do
24
+ options[:report] = 'errors'
25
+ end
26
+ opts.on('-l LABEL', '--label NAME', 'Store run-command with label') do |v|
27
+ options[:label] = v
28
+ end
29
+ opts.on('-o ID_OR_NAME', '--output ID_OR_NAME', 'Report command full output') do |v|
30
+ options[:output] = v
31
+ end
32
+ opts.on('-d ID_OR_NAME', '--delete ID_OR_NAME', 'Remove cronbox entry') do |v|
33
+ options[:delete] = v
34
+ end
35
+ end
36
+ opparser.parse!
37
+
38
+ file = options[:file]
39
+ options.delete(:file)
40
+
41
+ @app = Cronbox.new(file)
42
+ @cli = Cronbox::CliWrapper.new(@app)
43
+
44
+ if ARGV.empty? and (options.empty? or options[:report])
45
+ @cli.report(options[:report])
46
+ elsif ARGV.size > 0
47
+ @app.execute(options[:label], ARGV.shift, *ARGV)
48
+ elsif options[:output]
49
+ @cli.report(true, [options[:output]])
50
+ elsif options[:delete]
51
+ @cli.delete(options[:delete])
52
+ else
53
+ puts opparser.help
54
+ end
@@ -0,0 +1,96 @@
1
+ require 'open3'
2
+ require 'cronbox/version'
3
+ require 'cronbox/data_file'
4
+ require 'cronbox/cli_wrapper'
5
+
6
+ class Cronbox
7
+
8
+ def initialize(file=nil)
9
+ file ||= File.join(Dir.home, '.cronbox')
10
+ @data = Cronbox::DataFile.new(file)
11
+ end
12
+
13
+ attr_reader :data
14
+
15
+ def report(errors_only=false)
16
+ entries = @data.entries.sort_by { |e| e['ts'] }
17
+ report = {
18
+ count: 0,
19
+ errors: 0,
20
+ entries: [],
21
+ }
22
+ entries.reverse.each do |e|
23
+ e = e.clone
24
+ e['is_error'] = e['status'].to_i > 0
25
+ e['when'] = self.class.time_delta_string(e['ts'])
26
+ e['has_output'] = (e['output'].respond_to?(:size) && e['output'].size > 0)
27
+ next if errors_only and not e['is_error']
28
+ report[:count] += 1
29
+ report[:errors] += 1 if e['is_error']
30
+ report[:entries].push e
31
+ end
32
+ report
33
+ end
34
+
35
+ def execute(label, cmd, *args)
36
+ e = Hash.new
37
+ e['command'] = ([cmd] + args).join(' ')
38
+ e['status'] = nil
39
+ e['output'] = []
40
+ e['label'] = label.to_s unless label.to_s.empty?
41
+ begin
42
+ e['ts'] = Time.now.to_i
43
+ Open3.popen3(cmd, *args) do |stdin, stdout, stderr, thread|
44
+ e['status'] = thread.value.to_i
45
+ e['output'] = stderr.readlines + stdout.readlines
46
+ end
47
+ rescue => ex
48
+ e['status'] = 1
49
+ e['output'] = [ex.message]
50
+ end
51
+
52
+ existing = @data.find_entry(label: e['label']) if e['label']
53
+ existing ||= @data.find_entry(command: e['command'])
54
+
55
+ if existing
56
+ e['label'] ||= existing['label']
57
+ existing.merge!(e)
58
+ else
59
+ @data.add_entry(e)
60
+ end
61
+
62
+ @data.save!
63
+ end
64
+
65
+ def delete(id_or_label)
66
+ if id_or_label.to_i > 0
67
+ e = @data.find_entry(id: id_or_label.to_i)
68
+ else
69
+ e = @data.find_entry(label: id_or_label)
70
+ end
71
+ if e
72
+ @data.del_entry(e)
73
+ @data.save!
74
+ e
75
+ else
76
+ nil
77
+ end
78
+ end
79
+
80
+ def self.time_delta_string(time)
81
+ d = Time.now.to_i - time.to_i
82
+ case d
83
+ when 0 then 'just now'
84
+ when 1 then 'a second ago'
85
+ when 2..59 then d.to_s+' seconds ago'
86
+ when 60..119 then 'a minute ago' #120 = 2 minutes
87
+ when 120..3540 then (d/60).to_i.to_s+' minutes ago'
88
+ when 3541..7100 then 'an hour ago' # 3600 = 1 hour
89
+ when 7101..82800 then ((d+99)/3600).to_i.to_s+' hours ago'
90
+ when 82801..172000 then 'a day ago' # 86400 = 1 day
91
+ when 172001..518400 then ((d+800)/(60*60*24)).to_i.to_s+' days ago'
92
+ when 518400..1036800 then 'a week ago'
93
+ else ((d+180000)/(60*60*24*7)).to_i.to_s+' weeks ago'
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,112 @@
1
+ class Cronbox
2
+ class CliWrapper
3
+ def initialize(app)
4
+ @app = app
5
+ end
6
+
7
+ def report(type=nil, include_only=nil)
8
+ if include_only
9
+ include_ids = include_only.map(&:to_i)
10
+ include_labels = include_only.map(&:to_s)
11
+ end
12
+
13
+ any_output = false
14
+
15
+ report = @app.report(type.eql? 'errors')
16
+ report[:entries].each do |e|
17
+ if e['label'].to_s.empty?
18
+ e['f_label'] = e['id'].to_s
19
+ else
20
+ e['f_label'] = %("#{e['label']}" #{e['id']})
21
+ end
22
+ if e['has_output']
23
+ any_output = true
24
+ e['f_status'] = '*' + e['status'].to_s
25
+ else
26
+ e['f_status'] = e['status'].to_s
27
+ end
28
+ end
29
+
30
+ fw = self.class.calc_widths_of_fields(report[:entries], {
31
+ f_label: [2], command: [10, 70], f_status: [4], when: [4]
32
+ })
33
+ w = fw.values.reduce(:+) + fw.size*3 + 1
34
+
35
+ ## BRAND
36
+ puts ''
37
+ brand = '| Cronbox |'
38
+ if any_output
39
+ puts "%s%#{w-brand.length}s" % [brand, '*=Output']
40
+ else
41
+ puts brand
42
+ end
43
+ puts '=' * w
44
+
45
+ ## HEADER ROW
46
+ tpl = [nil,
47
+ "%#{fw[:f_label]}s",
48
+ "%-#{fw[:command]}s",
49
+ "%#{fw[:f_status]}s",
50
+ "%#{fw[:when]}s",
51
+ nil].join(' | ').strip
52
+ puts tpl % %w(ID COMMAND EXIT WHEN)
53
+ puts '=' * w
54
+
55
+ ## ENTRY ROWS
56
+ report[:entries].each do |e|
57
+ if include_only
58
+ next unless include_ids.include? e['id'] or include_labels.include? e['label']
59
+ end
60
+ puts tpl % [
61
+ e['f_label'],
62
+ e['command'],
63
+ e['f_status'],
64
+ e['when']
65
+ ]
66
+ if type == 'errors' or type === true
67
+ if e['has_output']
68
+ puts 'v' * w
69
+ puts ''
70
+ puts e['output'].join("\n").sub(/\s*\z/, '')
71
+ puts ''
72
+ end
73
+ puts '-' * w
74
+ else
75
+ puts '-' * w
76
+ end
77
+ end
78
+ puts ''
79
+ end
80
+
81
+ def delete(entry)
82
+ if (entry = @app.delete(entry))
83
+ STDERR.write("Deleted entry ##{entry['id']}\n")
84
+ end
85
+ end
86
+
87
+ def self.calc_widths_of_fields(table, fields_with_opts)
88
+ result = Hash.new
89
+ fields = fields_with_opts.keys
90
+ table.each do |e|
91
+ fields.each do |f|
92
+ w = e[f.to_s].to_s.length
93
+ result[f] = [result[f].to_i, w].max
94
+ end
95
+ end
96
+ fields_with_opts.each do |f, opts|
97
+ opts = [0, 99] unless opts
98
+ opts.push(99) unless opts.length > 1
99
+ result[f] = [[result[f].to_i, opts[0]].max, opts[1]].min
100
+ end
101
+ result
102
+ end
103
+
104
+ def self.calc_width_of_field(table, field, min=0, max=99)
105
+ field = field.to_s
106
+ width = table.inject(0) do |w, e|
107
+ [w, e[field].to_s.length].max
108
+ end
109
+ [[width, min].max, max].min
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,84 @@
1
+ require 'json'
2
+
3
+ class Cronbox
4
+ class DataFile
5
+ def initialize(file)
6
+ @file = file
7
+ reset
8
+ reload if File.exist?(@file)
9
+ end
10
+
11
+ def reset
12
+ @config ||= Hash.new
13
+ @entries = Array.new
14
+ end
15
+
16
+ def reload
17
+ import_text(File.read(@file))
18
+ end
19
+
20
+ def save!
21
+ save_dir = File.dirname(@file)
22
+ unless Dir.exist?(save_dir)
23
+ raise "Directory does not exist, #{save_dir}"
24
+ end
25
+ File.open(@file, 'w') { |file| file.write(export_text) }
26
+ end
27
+
28
+ def empty!
29
+ reset
30
+ save!
31
+ end
32
+
33
+ attr_accessor :config, :entries
34
+
35
+ def find_entry(query)
36
+ k = query.keys.first
37
+ v = query[k]
38
+ return nil unless v
39
+ @entries.each do |e|
40
+ if e[k.to_s] == v
41
+ return e
42
+ end
43
+ end
44
+ nil
45
+ end
46
+
47
+ def add_entry(entry)
48
+ entry['id'] = next_id
49
+ @entries.push entry
50
+ end
51
+
52
+ def del_entry(entry)
53
+ @entries.delete(entry)
54
+ end
55
+
56
+ protected
57
+
58
+ def import_text(input)
59
+ data = JSON.parse(input)
60
+ @config = data['config'] || Hash.new
61
+ @entries = data['entries'] || Array.new
62
+ end
63
+
64
+ def export_text
65
+ JSON.pretty_generate({
66
+ :'config' => @config,
67
+ :'entries' => @entries.sort_by { |e| e['id'] }
68
+ })
69
+ end
70
+
71
+ def next_id
72
+ ni = 1
73
+ indexes = @entries.map { |e| e['id'].to_i }
74
+ indexes.sort.each do |i|
75
+ if i > ni
76
+ return ni
77
+ elsif i == ni
78
+ ni += 1
79
+ end
80
+ end
81
+ ni
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,5 @@
1
+ require 'versioneer'
2
+
3
+ class Cronbox
4
+ VERSION = ::Versioneer::Config.new(::File.expand_path('../../../', __FILE__))
5
+ end
metadata ADDED
@@ -0,0 +1,146 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cronbox
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - BinaryBabel OSS
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-01-31 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: versioneer
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.13'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.13'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '5.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '5.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.10.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 0.10.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: pry-byebug
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">"
88
+ - !ruby/object:Gem::Version
89
+ version: '3'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">"
95
+ - !ruby/object:Gem::Version
96
+ version: '3'
97
+ description:
98
+ email:
99
+ - oss@binarybabel.org
100
+ executables:
101
+ - cb
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - ".gitignore"
106
+ - ".travis.yml"
107
+ - ".versioneer.yml"
108
+ - Gemfile
109
+ - LICENSE.txt
110
+ - README.md
111
+ - Rakefile
112
+ - bin/console
113
+ - bin/setup
114
+ - bin/versioneer
115
+ - cronbox.gemspec
116
+ - exe/cb
117
+ - lib/cronbox.rb
118
+ - lib/cronbox/cli_wrapper.rb
119
+ - lib/cronbox/data_file.rb
120
+ - lib/cronbox/version.rb
121
+ - version.lock
122
+ homepage: https://github.com/binarybabel/cronbox
123
+ licenses:
124
+ - MIT
125
+ metadata: {}
126
+ post_install_message:
127
+ rdoc_options: []
128
+ require_paths:
129
+ - lib
130
+ required_ruby_version: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ required_rubygems_version: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ requirements: []
141
+ rubyforge_project:
142
+ rubygems_version: 2.5.1
143
+ signing_key:
144
+ specification_version: 4
145
+ summary: Command line inbox and timecard for scheduled job status and output.
146
+ test_files: []