dirwatch 0.0.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
+ SHA1:
3
+ metadata.gz: 28e52feff4b1a4dc37784ad8068a61045bba844f
4
+ data.tar.gz: 54355f3b6eb1102921ecd050103fff6efddb3331
5
+ SHA512:
6
+ metadata.gz: a3f8a0c321dea9d1bf37ef79ca92cb8d23e3a2338a32ec571d08a9c762eb8c7b27b7426ca5314b08f1f70057bd96b3e24abb5741a8ccf4ddd66a673840de5083
7
+ data.tar.gz: 78150645c779c24cef4af453487f6dfb3458b0a569340eb1cc167a8e365e4b7828c7b24f10c83cadbaf7d0c93172b939a05328db3b2db6c6a41d4dd15bc2c3f9
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2017 Nicolas
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 all
13
+ 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 THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,2 @@
1
+ # dirwatch
2
+ A ruby gem to watch specific files and execute commands when any of the files change
data/bin/dirwatch ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #require 'dirwatch'
4
+ require_relative '../lib/dirwatch'
5
+ watcher = Dirwatch::Watcher.from_args ARGV
6
+ watcher.start
7
+
8
+ begin
9
+ sleep
10
+ rescue Interrupt
11
+ ensure
12
+ puts "shutting down..."
13
+ watcher.stop
14
+ end
@@ -0,0 +1,54 @@
1
+ module Dirwatch
2
+ class Options
3
+ def self.from_args args
4
+ require 'optparse'
5
+ require 'ostruct'
6
+
7
+ show_help = false
8
+ options = OpenStruct.new
9
+ options.directory = './'
10
+ parser = OptionParser.new do |opts|
11
+ opts.banner = "Usage: #{$0} [options] [directory]"
12
+
13
+ opts.on('-f', '--file-match MATCH', 'The bash match for the file. Default: *.tex') do |match|
14
+ options.file_match = match
15
+ end
16
+
17
+ opts.on('-i', '--interval INTERVAL', OptionParser::DecimalNumeric, 'The number of seconds to wait unitl the next check. Default: 1') do |interval|
18
+ options.interval = interval
19
+ end
20
+
21
+ opts.on('-d', '--daemonize', 'Run the programm as a daemon') do
22
+ options.daemonize = true
23
+ end
24
+
25
+ opts.on('-h', '--help', 'Show this help') do
26
+ puts opts
27
+ exit
28
+ end
29
+ end
30
+ parser.parse! args
31
+
32
+ unless args.empty?
33
+ if args.size > 1
34
+ puts 'Too many arguments'
35
+ puts parser
36
+ exit
37
+ end
38
+ options.directory = args.first
39
+ end
40
+
41
+ new options.to_h
42
+ end
43
+
44
+ attr_reader :directory, :file_match, :interval, :daemonize
45
+
46
+ def initialize directory: nil, file_match: nil, interval: nil, daemonize: nil
47
+ raise 'The directory is required' unless directory
48
+ @directory = directory
49
+ @file_match = file_match || '*.tex'
50
+ @interval = interval || 1
51
+ @daemonize = !!daemonize
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,45 @@
1
+ module Dirwatch
2
+ class Settings
3
+ class WatchSetting
4
+ attr_reader :interval, :scripts
5
+
6
+ def initialize directory:, file_match:, interval:, scripts:
7
+ @directory = directory
8
+ raise 'directory must be set' if @directory.nil? || @directory.empty?
9
+ @file_match = file_match
10
+ raise 'file_match must be set' if @file_match.nil? || @file_match.empty?
11
+ @interval = interval || raise('interval must be set')
12
+ raise 'the interval must be greater than 0' if @interval <= 0
13
+ if scripts.is_a? String
14
+ scripts = [scripts]
15
+ elsif !scripts.is_a?(Array) || scripts.any? {|s| !s.is_a? String }
16
+ raise "the scripts need to be either one string or a list of strings. Not: #{scripts.insepct}"
17
+ end
18
+ @scripts = scripts
19
+ end
20
+
21
+ def files_path
22
+ File.join @directory, '**', @file_match
23
+ end
24
+
25
+ def files
26
+ Dir[files_path]
27
+ end
28
+
29
+ def exec_scripts
30
+ @scripts.each do |script|
31
+ if script =~ / & *\z/
32
+ system script
33
+ else
34
+ output = %x(#{script})
35
+ raise "The command \"#{script}\" failed with: #{output}" if $? != 0
36
+ end
37
+ end
38
+ end
39
+
40
+ def to_s
41
+ "#<#{self.class} files_path=#{files_path} interval=#{interval.inspect} scripts=#{scripts.inspect}>"
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,58 @@
1
+ require_relative 'settings/watch_setting'
2
+
3
+ module Dirwatch
4
+ class Settings
5
+ def self.from_options options
6
+ Settings.from_file(File.join(options.directory, 'dirwatch.yml'), options)
7
+ end
8
+
9
+ def self.from_file filename, options
10
+ settings = new
11
+ config = symbolize YAML.load_file(filename)
12
+ watch_data = {}
13
+ defaults = {}
14
+ config.each do |key, watch_setting|
15
+ if key == :defaults
16
+ defaults.merge! watch_setting
17
+ else
18
+ watch_data[key] = watch_setting
19
+ end
20
+ end
21
+ watch_data.each do |key, watch_setting|
22
+ settings << WatchSetting.new(
23
+ directory: options.directory,
24
+ file_match: watch_setting[:file_match] || defaults[:file_match],
25
+ interval: watch_setting[:interval] || defaults[:interval],
26
+ scripts: watch_setting[:script] || defaults[:script],
27
+ )
28
+ end
29
+ settings
30
+ end
31
+
32
+ attr_reader :watch_settings
33
+
34
+ def initialize
35
+ @watch_settings = []
36
+ end
37
+
38
+ def << watch_setting
39
+ add watch_setting
40
+ end
41
+
42
+ def add watch_setting
43
+ @watch_settings << watch_setting
44
+ end
45
+
46
+ def by_interval &block
47
+ @watch_settings.group_by(&:interval).each(&block)
48
+ end
49
+
50
+ private
51
+
52
+ def self.symbolize(obj)
53
+ return obj.inject({}){|memo,(k,v)| memo[k.to_sym] = symbolize(v); memo} if obj.is_a? Hash
54
+ return obj.inject([]){|memo,v | memo << symbolize(v); memo} if obj.is_a? Array
55
+ return obj
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,3 @@
1
+ module Dirwatch
2
+ VERSION = '0.0.0'
3
+ end
@@ -0,0 +1,56 @@
1
+ module Dirwatch
2
+ class Watcher
3
+ def self.from_args args
4
+ new Options.from_args(args)
5
+ end
6
+
7
+ attr_reader :options
8
+
9
+ def initialize options
10
+ @options = options
11
+ @settings = Settings.from_options @options
12
+
13
+ if options.daemonize
14
+ Process.daemon true, true
15
+ puts "running in the background... [#{Process.pid}]"
16
+ end
17
+ end
18
+
19
+ def start
20
+ raise 'already started' if @threads
21
+ @threads = []
22
+ @stop = false
23
+
24
+ Thread.abort_on_exception = true
25
+ @settings.by_interval do |interval, watch_settings|
26
+ watch_settings.each {|ws| puts "Watching #{ws}" }
27
+ @threads << Thread.new do
28
+ change_times = []
29
+ loop do
30
+ break if @stop
31
+ watch_settings.each.with_index do |ws, i|
32
+ change_time = ws.files.map {|f| File.ctime f }.max
33
+ if change_time != change_times[i]
34
+ change_times[i] = change_time
35
+ ws.exec_scripts
36
+ end
37
+ end
38
+
39
+ break if @stop
40
+ sleep interval
41
+ end
42
+ end
43
+ end
44
+ end
45
+
46
+ def stop
47
+ raise 'not started' unless @threads
48
+ @stop = true
49
+ @threads.each {|t| t.join }
50
+ end
51
+
52
+ def files
53
+ Dir[File.join options.directory, '**', options.file_match]
54
+ end
55
+ end
56
+ end
data/lib/dirwatch.rb ADDED
@@ -0,0 +1,7 @@
1
+ require 'yaml'
2
+ require_relative 'dirwatch/watcher'
3
+ require_relative 'dirwatch/options'
4
+ require_relative 'dirwatch/settings'
5
+
6
+ module Dirwatch
7
+ end
metadata ADDED
@@ -0,0 +1,53 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dirwatch
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Nicolas Ganz
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-09-19 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email: nicolas@keltec.ch
15
+ executables:
16
+ - dirwatch
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - LICENSE
21
+ - README.md
22
+ - bin/dirwatch
23
+ - lib/dirwatch.rb
24
+ - lib/dirwatch/options.rb
25
+ - lib/dirwatch/settings.rb
26
+ - lib/dirwatch/settings/watch_setting.rb
27
+ - lib/dirwatch/version.rb
28
+ - lib/dirwatch/watcher.rb
29
+ homepage: https://github.com/ThunderKey/dirwatch
30
+ licenses:
31
+ - MIT
32
+ metadata: {}
33
+ post_install_message:
34
+ rdoc_options: []
35
+ require_paths:
36
+ - lib
37
+ required_ruby_version: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ required_rubygems_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ requirements: []
48
+ rubyforge_project:
49
+ rubygems_version: 2.5.1
50
+ signing_key:
51
+ specification_version: 4
52
+ summary: Watch specific files and execute commands when any of them change
53
+ test_files: []