process-query-language 0.1.0

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/LICENSE ADDED
@@ -0,0 +1,2 @@
1
+
2
+ You may not use this software. At all.
data/README.md ADDED
@@ -0,0 +1,54 @@
1
+
2
+ Process Query Language
3
+ ----------------------
4
+
5
+ PQL is a query language for processes running on a system. The syntax
6
+ is closely related to the one used in MongoDB. This is because at heart, PQL
7
+ uses Plucky. But instead of sending the queries to a MongoDB server, they
8
+ are intercepted and processed by PQL.
9
+
10
+ PQL extends the Process class with four new methods:
11
+
12
+ * find - find a process by PID
13
+ * where - find processes which match a query
14
+ * remove - remove (kill) processes
15
+ * count - count processes
16
+
17
+ These `where` method returns a Plucky::Query object. This object
18
+ can be used to further refine the query by chaining additional methods.
19
+ Consult the Plucky documentation to see which methods are available.
20
+
21
+
22
+ Supported fields
23
+ ----------------
24
+
25
+ There is a limited number of fields which can be used in queries. The
26
+ following fields are supported:
27
+
28
+ :pid, :rss, :command
29
+
30
+ The following operators are supported
31
+
32
+ gt, gte, lt, lte, in, nin
33
+
34
+ Use of an unknown field or unknown operator will raise an exception.
35
+
36
+
37
+ Example
38
+ -------
39
+
40
+ This will print the number of unicorn rails workers which use more than
41
+ 20MB of RSS:
42
+
43
+ require 'rubygems'
44
+ require 'process-query-language'
45
+
46
+ query = Process.where(:rss.gt => 20_000_000)
47
+ query.where(:command => /unicorn_rails.worker/)
48
+ puts query.count
49
+
50
+
51
+ License
52
+ -------
53
+
54
+ Copyright (c) 2010 by Tomas "wereHamster" Carnecky (tomas.carnecky@gmail.com)
@@ -0,0 +1,34 @@
1
+
2
+ require 'plucky'
3
+
4
+ module ProcessQueryLanguage
5
+
6
+ autoload :Version, 'process-query-language/version'
7
+ autoload :Collection, 'process-query-language/collection'
8
+ autoload :Matcher, 'process-query-language/matcher'
9
+
10
+ module Backend
11
+ autoload :ProcessStatus, 'process-query-language/backend/process-status'
12
+ end
13
+
14
+ end
15
+
16
+
17
+ module Process
18
+
19
+ def self.pql(backend)
20
+ klass = ProcessQueryLanguage::Backend.const_get(backend)
21
+ @@pql = ProcessQueryLanguage::Collection.new(klass.new)
22
+ end
23
+
24
+ # Only expose selected methods from the Plucky::Query object
25
+ %w{ find remove count where }.each do |method|
26
+ module_eval <<-eval
27
+ def Process.#{method}(*args)
28
+ @@pql ||= ProcessQueryLanguage::Collection.new(ProcessQueryLanguage::Backend::ProcessStatus.new)
29
+ Plucky::Query.new(@@pql).#{method}(*args)
30
+ end
31
+ eval
32
+ end
33
+
34
+ end
@@ -0,0 +1,47 @@
1
+
2
+ module ProcessQueryLanguage
3
+
4
+ module Backend
5
+
6
+ # This backend uses the `ps` utility and parses its output. Because
7
+ # `ps` uses whitespace as the delimiter (and truncates too wide fields)
8
+ # except the last, we need to sort the fields so that :command is
9
+ # the last.
10
+ class ProcessStatus
11
+
12
+ FIELDS = %w{ pid rss command }.map(&:to_sym)
13
+
14
+ def scan(fields)
15
+ result = []
16
+ %x[ps -Aco #{FIELDS.join(',')}].lines.to_a[1..-1].each do |line|
17
+ values = line.split(' ')
18
+ process = {}
19
+ FIELDS.each_with_index do |value, i|
20
+ next unless fields.include?(FIELDS[i])
21
+ process[FIELDS[i]] = convert(FIELDS[i], values[i])
22
+ end
23
+ result << process
24
+ end
25
+
26
+ return result
27
+ end
28
+
29
+ private
30
+
31
+ def convert(field, value)
32
+ case field
33
+ when :rss, :pid
34
+ return value.to_i
35
+ when :command
36
+ return value.to_s
37
+ else
38
+ return nil
39
+ raise Exception.new("Don't know how to convert #{field}")
40
+ end
41
+ end
42
+
43
+ end
44
+
45
+ end
46
+
47
+ end
@@ -0,0 +1,42 @@
1
+
2
+ module ProcessQueryLanguage
3
+
4
+ class Collection
5
+
6
+ def initialize(backend)
7
+ @backend = backend
8
+ end
9
+
10
+ def find(query, options)
11
+ query[:pid] = query.delete(:_id) if query[:_id]
12
+
13
+ keys = query.keys
14
+ keys = keys + options[:fields] if options[:fields]
15
+
16
+ matcher = ProcessQueryLanguage::Matcher.new(query)
17
+ result = []
18
+ @backend.scan(keys.uniq).each do |process|
19
+ if matcher.match(process)
20
+ result << process
21
+ end
22
+ end
23
+
24
+ return result
25
+ end
26
+
27
+ def find_one(query, options)
28
+ find(query, options).first
29
+ end
30
+
31
+ def remove(query)
32
+ find(query, { :fields => [ :pid ] }).each do |process|
33
+ Process.kill(process[:pid])
34
+ end
35
+ end
36
+
37
+ def insert
38
+ end
39
+
40
+ end
41
+
42
+ end
@@ -0,0 +1,56 @@
1
+
2
+ module ProcessQueryLanguage
3
+
4
+ class Matcher
5
+
6
+ attr_reader :pattern
7
+
8
+ # pattern: { a => { $gt => 100 }, b => { $in => [ 1,2,3 ] } }
9
+ def initialize(pattern)
10
+ @pattern = pattern
11
+ end
12
+
13
+ def apply(op, value, pattern)
14
+ case op
15
+ when "$gt"
16
+ return value > pattern
17
+ when "$gte"
18
+ return value >= pattern
19
+ when "$lt"
20
+ return value < pattern
21
+ when "$lte"
22
+ return value <= pattern
23
+ when "$in"
24
+ return pattern.include?(value)
25
+ when "$nin"
26
+ return !pattern.include?(value)
27
+ else
28
+ raise Exception.new("Unknown operator: #{op}")
29
+ end
30
+ end
31
+
32
+ # object: { a => 200, b => 2 }
33
+ def match(object)
34
+ pattern.each do |key, value|
35
+ return false if object[key].nil?
36
+
37
+ case value
38
+ when Regexp
39
+ return false if !value.match(object[key])
40
+ when Hash
41
+ value.each do |op, value|
42
+ return false if !apply(op, object[key], value)
43
+ end
44
+ when object[key]
45
+ return false if object[key] != value
46
+ else
47
+ return false
48
+ end
49
+ end
50
+
51
+ return true
52
+ end
53
+
54
+ end
55
+
56
+ end
@@ -0,0 +1,6 @@
1
+
2
+ module ProcessQueryLanguage
3
+
4
+ Version = '0.1.0'
5
+
6
+ end
metadata ADDED
@@ -0,0 +1,101 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: process-query-language
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Tomas Carnecky
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-10-31 01:00:00 +02:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: plucky
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: shoulda
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 0
46
+ version: "0"
47
+ type: :development
48
+ version_requirements: *id002
49
+ description:
50
+ email:
51
+ - tomas.carnecky@gmail.com
52
+ executables: []
53
+
54
+ extensions: []
55
+
56
+ extra_rdoc_files: []
57
+
58
+ files:
59
+ - lib/process-query-language/backend/process-status.rb
60
+ - lib/process-query-language/collection.rb
61
+ - lib/process-query-language/matcher.rb
62
+ - lib/process-query-language/version.rb
63
+ - lib/process-query-language.rb
64
+ - LICENSE
65
+ - README.md
66
+ has_rdoc: true
67
+ homepage: http://github.com/wereHamster/process-query-language
68
+ licenses: []
69
+
70
+ post_install_message:
71
+ rdoc_options: []
72
+
73
+ require_paths:
74
+ - lib
75
+ required_ruby_version: !ruby/object:Gem::Requirement
76
+ none: false
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ hash: 3
81
+ segments:
82
+ - 0
83
+ version: "0"
84
+ required_rubygems_version: !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ hash: 3
90
+ segments:
91
+ - 0
92
+ version: "0"
93
+ requirements: []
94
+
95
+ rubyforge_project:
96
+ rubygems_version: 1.3.7
97
+ signing_key:
98
+ specification_version: 3
99
+ summary: Process query language (based on plucky)
100
+ test_files: []
101
+