clockker 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 69851fff50f8e00c0fc78c209864330dee98e78130b7c982593545de6ad02687
4
+ data.tar.gz: 5850c706c8d88b03aa1f8c4acaf5e2a15eb3de7e53ac801d4f872591c3a35881
5
+ SHA512:
6
+ metadata.gz: 79acd1ea6482332e3bbfe521fe6c060366393f4953b3cbe16854d53b60d4e08844ea81024161a5b7f70ce6c25e0557651d11a49c4c9255e5e0584b609b9cfdc7
7
+ data.tar.gz: 0d53068a16887be5090b7083e987964f59571fecc1c665847aeff8dc1864257e6774e479104c64552918d82bc8c578d826ca0488d3d06fe20d5771eb04bb36bc
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at paul@liquidmedia.ca. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in clockker.gemspec
6
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Paul Doerwald
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.
data/README.md ADDED
@@ -0,0 +1,76 @@
1
+ # Clockker
2
+
3
+ Clockker watches your macOS file system and submits any file changes to the Clockk web service. Learn more about Clockk at http://clockk.com.
4
+
5
+ ## Installation
6
+
7
+ Install it with:
8
+
9
+ $ gem install clockker
10
+
11
+ ## Usage
12
+
13
+ Run it with:
14
+
15
+ $ clockker watch <path>
16
+
17
+ This will start the clockker executable in the foreground, and it will watch for file changes at <path>.
18
+
19
+ Clockker takes several command-line options:
20
+
21
+ `-t=x` / `--token=x`
22
+ : sets the token for communication, as provided by Clockk. REQUIRED.
23
+
24
+ `-v` / `--verbose`
25
+ : sets verbosity. Default: `info`. Options (with `-v=` or `--verbose=`): `debug`, `info`, `warn`, `error`, `fatal`
26
+
27
+ `-s=x` / `--submit-frequency=x`
28
+ : upload changed files list to Clockk server every <x> seconds. Default: 300 seconds.
29
+
30
+ `-w=x y z` / `--whitelist=x y z`
31
+ : Space-separated list of absolute paths to watch. Defaults to your home directory (~).
32
+
33
+ `-b=x y z` / `--blacklist=x y z`
34
+ : Space-separated list of absolute paths to ignore that are undeneath your whitelisted paths. Defaults to ~/Library.
35
+
36
+ Instead of using the command-line options, you can specify a default configuration in ~/.clockker, which is a JSON-formatted file. An example structure is:
37
+
38
+ ```json
39
+ {
40
+ "version": "0.1.0",
41
+ "token": "asdfasdf",
42
+ "whitelist": [
43
+ "/Users/paul",
44
+ "/web"
45
+ ],
46
+ "blacklist": [
47
+ "/Users/paul/Library",
48
+ "/web/nordia"
49
+ ]
50
+ }
51
+ ```
52
+
53
+
54
+ ## Development
55
+
56
+ After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
57
+
58
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
59
+
60
+ ## Contributing
61
+
62
+ Bug reports and pull requests are welcome on GitHub at https://github.com/liquidmedia/clockker. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
63
+
64
+ Please note that this software is intended for use with the Clockk web service. It is released as open source for the following reasons:
65
+
66
+ * To be as transparent as possible with software that runs on our users’ computers.
67
+ * To be open to bug fixes from our user community.
68
+ * To share some of the code (and the lessons we learn from it) that we develop internally with the wider community.
69
+
70
+ ## License
71
+
72
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
73
+
74
+ ## Code of Conduct
75
+
76
+ Everyone interacting in the Clockker project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/clockker/blob/master/CODE_OF_CONDUCT.md).
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "clockker"
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(__FILE__)
data/bin/setup ADDED
@@ -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
data/clockker.gemspec ADDED
@@ -0,0 +1,39 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "clockker/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "clockker"
8
+ spec.version = Clockker::VERSION
9
+ spec.authors = ["Paul Doerwald"]
10
+ spec.email = ["paul@clockk.com"]
11
+
12
+ spec.summary = %q{Clockker aggregates and submits file system changes to the clockk.com web service.}
13
+ spec.description = %q{Clockker aggregates and submits file system changes to the clockk.com web service.}
14
+ spec.homepage = "https://github.com/liquidmedia/clockker"
15
+ spec.license = "MIT"
16
+
17
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
19
+ # if spec.respond_to?(:metadata)
20
+ # spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
21
+ # else
22
+ # raise "RubyGems 2.0 or newer is required to protect against " \
23
+ # "public gem pushes."
24
+ # end
25
+
26
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
27
+ f.match(%r{^(test|spec|features)/})
28
+ end
29
+ spec.bindir = "exe"
30
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
31
+ spec.require_paths = ["lib"]
32
+
33
+ spec.add_dependency 'rb-fsevent', '>= 0.10.2'
34
+ spec.add_dependency 'thor'
35
+
36
+ spec.add_development_dependency "bundler", "~> 1.15"
37
+ spec.add_development_dependency "rake", "~> 10.0"
38
+
39
+ end
data/exe/clockker ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "clockker"
4
+ require "clockker/cli"
5
+
6
+ major, minor, patch = Clockker.macos_version
7
+ if minor < 12
8
+ puts "Clockker can only run on macOS 10.12 (Sierra) or newer."
9
+ exit
10
+ end
11
+
12
+ Clockker::CLI.start
@@ -0,0 +1,71 @@
1
+ require 'thor'
2
+ require 'logger'
3
+
4
+ module Clockker
5
+ class CLI < Thor
6
+ hostname = `hostname`.strip
7
+ macaddrpart = `ifconfig` =~ /en0.*?(([A-F0-9]{2}:){5}[A-F0-9]{2})/im
8
+ macaddrpart = $1[2..4]
9
+ identifier = hostname+macaddrpart
10
+
11
+ desc "watch", "Start the Clockker watcher"
12
+ method_option :token, aliases: '-t', type: :string, desc: "REQUIRED Token for communicating to Clockk server, provided by Clockk"
13
+ method_option :region, aliases: '-r', type: :string, desc: "REQUIRED server region. e.g. ca-central, us-east, eu-frankfurt"
14
+ method_option :whitelist, aliases: '-w', type: :array, desc: "Space-separated list of absolute paths to watch. Defaults to your home directory (~)."
15
+ method_option :blacklist, aliases: '-b', type: :array, desc: "Space-separated list of absolute paths to ignore that are undeneath your whitelisted paths. Defaults to ~/Library."
16
+ method_option :identifier, aliases: '-i', type: :string, desc: "The identifier for this computer.", default: identifier
17
+ method_option :submit_frequency, aliases: '-s', default: 300, desc: "Submit changeset to Clockk server every N seconds", type: :numeric
18
+ method_option :verbose, aliases: '-v', default: 'fatal', lazy_default: 'info', enum: %w{debug info warn error fatal}, desc: "Set verbosity (default: info)"
19
+ def watch
20
+ logger = Logger.new(STDERR)
21
+ case options[:verbose]
22
+ when 'debug'
23
+ logger.level = Logger::DEBUG
24
+ when 'info'
25
+ logger.level = Logger::INFO
26
+ when 'warn'
27
+ logger.level = Logger::WARN
28
+ when 'error'
29
+ logger.level = Logger::ERROR
30
+ else # fatal and no preference
31
+ logger.level = Logger::FATAL
32
+ end
33
+ logger.debug "Setting verbosity to #{options[:verbose]}"
34
+
35
+ # config_params = {}
36
+ # config_params[:submit_frequency] = options[:submit_frequency].to_i if options[:submit_frequency].present?
37
+ # config_params[:log_level] = options[:verbose] if options[:verbose].present?
38
+ # config_params[:token] = options[:token] if options[:token].present?
39
+ # config_params[:whitelist] = options[:whitelist] if options[:whitelist].present?
40
+ # config_params[:blacklist] = options[:blacklist] if options[:blacklist].present?
41
+
42
+ clockker_config = Clockker::Config.new(
43
+ submit_frequency: options[:submit_frequency].to_i,
44
+ log_level: options[:verbose],
45
+ identifier: options[:identifier]
46
+ )
47
+
48
+ clockker_config.token = options[:token] if options[:token]
49
+ clockker_config.region = options[:region] if options[:region]
50
+ clockker_config.whitelist = options[:whitelist] if options[:whitelist]
51
+ clockker_config.blacklist = options[:blacklist] if options[:blacklist]
52
+
53
+ if options[:token].nil? && clockker_config.token.nil?
54
+ puts "You must provide a value for the token, either as a parameter (--token=x) or in the ~/.clockker_config file."
55
+ exit
56
+ end
57
+
58
+ if options[:region].nil? && clockker_config.region.nil?
59
+ puts "You must provide a value for the server region (e.g. ca-central, us-east, eu-frankfurt, etc.), either as a parameter (--region=x) or in the ~/.clockker_config file."
60
+ exit
61
+ end
62
+
63
+ Clockker::Watcher.new(clockker_config, logger: logger)
64
+ end
65
+
66
+ desc "version", "Show Clockker version"
67
+ def version
68
+ puts Clockker.version_string
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,28 @@
1
+ require 'JSON'
2
+
3
+ module Clockker
4
+ class Config
5
+ attr_accessor :whitelist, :blacklist, :config_version, :token, :region, :identifier, :submit_frequency, :log_level
6
+ def initialize(overrides = {})
7
+ if File.exists?(File.join(Dir.home, '.clockker'))
8
+ clockker_config = JSON.parse(File.read(File.join(Dir.home, '.clockker')))
9
+ else
10
+ clockker_config = '{}'
11
+ end
12
+
13
+ # Set values from clockker_config
14
+ @whitelist = clockker_config["whitelist"]
15
+ @blacklist = clockker_config["blacklist"]
16
+ @config_version = clockker_config["version"]
17
+ @token = clockker_config["token"]
18
+ @region = clockker_config["region"]
19
+ @submit_frequency = clockker_config["submit_frequency"]
20
+ @log_level = clockker_config["log_level"]
21
+
22
+ # override values specified at the command line
23
+ overrides.each do |key, value|
24
+ instance_variable_set "@#{key}".to_sym, value
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,17 @@
1
+ module Clockker
2
+ VERSION = "0.1.0"
3
+
4
+ def self.macos_version
5
+ @mov ||= `sw_vers -productVersion`
6
+ major, minor, patch = @mov.split('.').map{|x| x.to_i}
7
+ return [major, minor, patch]
8
+ end
9
+
10
+ def self.version_string
11
+ "Clockker #{Clockker::VERSION} on macOS #{Clockker.macos_version.join('.')}"
12
+ end
13
+
14
+ def self.version
15
+ ["Clockker", Clockker::VERSION, "macOS", Clockker.macos_version.join('.')].join(' ')
16
+ end
17
+ end
@@ -0,0 +1,97 @@
1
+ require 'rb-fsevent'
2
+ require 'logger'
3
+ require 'net/http'
4
+
5
+ module Clockker
6
+ class Watcher
7
+ def initialize(config, logger: Logger.new)
8
+ Thread.abort_on_exception = true
9
+
10
+ trap "INT" do
11
+ @fsevent.stop
12
+ # @watcher.kill # this also works, but the former is a bit more elegant
13
+ @queue << :exit # this shuts down the submitter, first letting it submit its changeset
14
+ end
15
+
16
+ white_black_list = WhiteBlackList.new(config)
17
+
18
+ @queue = Queue.new
19
+ @watcher = Thread.new { create_watcher('/', white_black_list, logger) }
20
+ @submitter = Thread.new { create_submitter(config.submit_frequency, config.region, config.token, config.identifier, logger) }
21
+
22
+ @watcher.join
23
+ @submitter.join
24
+ end
25
+
26
+ def create_watcher(dir, white_black_list, logger)
27
+ @fsevent = FSEvent.new
28
+ @fsevent.watch dir, {file_events: true} do |directories, event_meta|
29
+ t = Time.now.utc
30
+ count = 0
31
+ event_meta['events'].each do |event|
32
+ next if white_black_list.ignore?(event['path'])
33
+ count += 1
34
+ @queue << {created_at: t, event_id: event['id'], filepath: event['path'], flags: event['flags']}
35
+ end
36
+ logger.debug "#{Time.now} checked #{event_meta['numEvents']} events and added #{count} to the queue"
37
+ end
38
+ logger.info "#{Time.now} now watching /"
39
+ logger.info "#{Time.now} whitelist paths: #{white_black_list.whitelist}"
40
+ logger.info "#{Time.now} blacklist paths: #{white_black_list.blacklist}"
41
+ @fsevent.run
42
+ logger.info "#{Time.now} fswatcher done"
43
+ end
44
+
45
+ def create_submitter(submit_frequency, region, token, identifier, logger)
46
+ logger.info "#{Time.now} submitting to clockk.com every #{submit_frequency} seconds with token #{token} from identifier #{identifier} with version #{Clockker.version}"
47
+ t_start = Time.now
48
+ clockk_agent_uri = URI("https://#{region}.clockk.io/api/v1/agent/artifacts")
49
+ @changeset = []
50
+ loop do
51
+ submit_now = false
52
+ exit_now = false
53
+
54
+ value = @queue.pop
55
+ case value
56
+ when :submit
57
+ submit_now = true
58
+ when :exit
59
+ submit_now = true
60
+ exit_now = true
61
+ else
62
+ @changeset << value
63
+ end
64
+
65
+ if Time.now - t_start > submit_frequency
66
+ submit_now = true
67
+ end
68
+
69
+ if exit_now
70
+ logger.info "#{Time.now} preparing to exit"
71
+ end
72
+
73
+ if submit_now
74
+ logger.info "#{Time.now} submitting #{@changeset.length} items to the Clockk server using token #{token}"
75
+ @changeset.each_with_index do |cs, idx|
76
+ logger.debug "#{Time.now} changeset #{idx}: #{cs.inspect}"
77
+ end
78
+
79
+ begin
80
+ res = Net::HTTP.post(clockk_agent_uri, {artifacts: @changeset.map{|c| {file_path: c[:filepath], touched_at: c[:created_at].strftime("%Y-%m-%d %H:%M:%S"), identifier: identifier, agent: Clockker.version}}}.to_json, {"Authorization" => "Bearer #{token}", "Content-Type" => "application/json"})
81
+ @changeset = []
82
+ rescue Exception => e
83
+ logger.info "#{Time.now} Reached exception #{e}"
84
+ end
85
+
86
+ t_start = Time.now
87
+ end
88
+
89
+ if exit_now
90
+ logger.info "#{Time.now} exiting"
91
+ break
92
+ end
93
+ end
94
+ end
95
+
96
+ end
97
+ end
@@ -0,0 +1,28 @@
1
+ require 'JSON'
2
+
3
+ module Clockker
4
+ class WhiteBlackList
5
+ # whitelist_path should return an array of absolute paths that are to be watched and reported to the clockk server.
6
+
7
+ # blacklist_path should return an array of absolute paths that are to be ignored. Implicitly any path that isn't whitelisted is blacklisted; this method is only useful if it returns subpaths of whitelisted paths. i.e. /Users/paul/Documents is whitelisted, but /Users/paul/Documents/customers/Bell is blacklisted.
8
+ attr_accessor :whitelist, :blacklist
9
+
10
+ def initialize(clockker_config)
11
+ @whitelist = clockker_config.whitelist
12
+ @blacklist = clockker_config.blacklist
13
+
14
+ # Now set defaults in the absence of a config file
15
+ @whitelist ||= [ Pathname.new(Dir.home) ]
16
+ @blacklist ||= [ Pathname.new(File.join(Dir.home, 'Library')) ]
17
+ end
18
+
19
+ def ignore?(filepath)
20
+ file_matches_whitelist = @whitelist.any? {|wl| filepath =~ Regexp.new(wl)}
21
+ file_matches_blacklist = @blacklist.any? {|bl| filepath =~ Regexp.new(bl)}
22
+ return true if file_matches_blacklist
23
+ return false if file_matches_whitelist
24
+ return true
25
+ end
26
+
27
+ end
28
+ end
data/lib/clockker.rb ADDED
@@ -0,0 +1,9 @@
1
+ require "clockker/version"
2
+ require 'clockker/cli'
3
+ require 'clockker/watcher'
4
+ require 'clockker/config'
5
+ require 'clockker/white_black_list'
6
+
7
+ module Clockker
8
+ # Your code goes here...
9
+ end
metadata ADDED
@@ -0,0 +1,119 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: clockker
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Paul Doerwald
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-06-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rb-fsevent
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 0.10.2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 0.10.2
27
+ - !ruby/object:Gem::Dependency
28
+ name: thor
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.15'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.15'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.0'
69
+ description: Clockker aggregates and submits file system changes to the clockk.com
70
+ web service.
71
+ email:
72
+ - paul@clockk.com
73
+ executables:
74
+ - clockker
75
+ extensions: []
76
+ extra_rdoc_files: []
77
+ files:
78
+ - ".gitignore"
79
+ - CODE_OF_CONDUCT.md
80
+ - Gemfile
81
+ - LICENSE.txt
82
+ - README.md
83
+ - Rakefile
84
+ - bin/console
85
+ - bin/setup
86
+ - clockker.gemspec
87
+ - exe/clockker
88
+ - lib/clockker.rb
89
+ - lib/clockker/cli.rb
90
+ - lib/clockker/config.rb
91
+ - lib/clockker/version.rb
92
+ - lib/clockker/watcher.rb
93
+ - lib/clockker/white_black_list.rb
94
+ homepage: https://github.com/liquidmedia/clockker
95
+ licenses:
96
+ - MIT
97
+ metadata: {}
98
+ post_install_message:
99
+ rdoc_options: []
100
+ require_paths:
101
+ - lib
102
+ required_ruby_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ required_rubygems_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ requirements: []
113
+ rubyforge_project:
114
+ rubygems_version: 2.7.6
115
+ signing_key:
116
+ specification_version: 4
117
+ summary: Clockker aggregates and submits file system changes to the clockk.com web
118
+ service.
119
+ test_files: []