zeiger 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.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.zeiger.yml +9 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +63 -0
- data/Rakefile +2 -0
- data/bin/zeiger +25 -0
- data/lib/zeiger/file_info.rb +23 -0
- data/lib/zeiger/file_list_client.rb +12 -0
- data/lib/zeiger/index.rb +50 -0
- data/lib/zeiger/line.rb +17 -0
- data/lib/zeiger/monitor.rb +44 -0
- data/lib/zeiger/query_client.rb +12 -0
- data/lib/zeiger/server.rb +41 -0
- data/lib/zeiger/version.rb +3 -0
- data/lib/zeiger.rb +27 -0
- data/zeiger.gemspec +23 -0
- metadata +92 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c01cd920ba6af86d17bd79b07e648d5e1bb37ad2
|
4
|
+
data.tar.gz: d90ce8ed808e1853aad0175d6fa862d0b3ff2a29
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5c24d14cba4ac6840aa2ec817c22a608bc98a476289643bdaa6b06fcd50649f82a189f45fdc5c14ef882a7cb815bdcd900c4f387d2d3baa2f4ffeb8edb90b223
|
7
|
+
data.tar.gz: 491a7131fc1f5b5ba29b207d31d2c5b232ed9307650a17aecd6d9383f101debefd6f7e5366c79a2e8e456e82f3d52b3fa6c799a7282b64b4ff5ab2bd683e9aff
|
data/.gitignore
ADDED
data/.zeiger.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2017 conanite
|
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,63 @@
|
|
1
|
+
# Zeiger
|
2
|
+
|
3
|
+
Zeiger is the German word for "pointer", "indicator", "index", "locator". This gem is built in the "index" sense : run
|
4
|
+
|
5
|
+
```
|
6
|
+
cd myproject
|
7
|
+
zeiger server
|
8
|
+
```
|
9
|
+
|
10
|
+
and this gem will create an in-memory index of all text in the filesystem subtree rooted in the current directory.
|
11
|
+
|
12
|
+
Query the index thus:
|
13
|
+
|
14
|
+
```
|
15
|
+
cd myproject
|
16
|
+
zeiger search "muppets"
|
17
|
+
```
|
18
|
+
|
19
|
+
This example returns one line for each line in your projects containing the word "muppets". Output is in the same format as `grep` (so you can hook it up with your emacs for quick project browsing).
|
20
|
+
|
21
|
+
## Installation
|
22
|
+
|
23
|
+
```
|
24
|
+
gem install 'zeiger'
|
25
|
+
```
|
26
|
+
|
27
|
+
This is built as a standalone commandline tool ; I don't have any use-cases for integrating it directly into a larger project. But if you do, I'm all ears.
|
28
|
+
|
29
|
+
## Usage
|
30
|
+
|
31
|
+
`zeiger server` runs the server and opens a unix filesystem socket called `zeiger-index` in the current directory.
|
32
|
+
|
33
|
+
`zeiger search "foo"` writes the query to the socket and displays the result
|
34
|
+
|
35
|
+
`zeiger files "xed"` asks for the list of filenames corresponding to the argument ("xed"). With no argument, return all filenames.
|
36
|
+
|
37
|
+
By default, Zeiger searches only in these subdirectories : %w{ app bin config lib spec test }, and excludes filenames matching these patterns: %w{ .gz$ .png$ .jpg$ .pdf$ }.
|
38
|
+
|
39
|
+
To override, create a file in your working directory with the following format:
|
40
|
+
|
41
|
+
```yaml
|
42
|
+
search:
|
43
|
+
- bin
|
44
|
+
- lib
|
45
|
+
- config.rb
|
46
|
+
ignore:
|
47
|
+
- .gz$
|
48
|
+
- .png$
|
49
|
+
- .gif$
|
50
|
+
- .zip$
|
51
|
+
- .jpg$
|
52
|
+
- .xcf$
|
53
|
+
- .mpg$
|
54
|
+
```
|
55
|
+
|
56
|
+
|
57
|
+
## Contributing
|
58
|
+
|
59
|
+
1. Fork it ( https://github.com/conanite/zeiger/fork )
|
60
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
61
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
62
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
63
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/bin/zeiger
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'socket'
|
4
|
+
require 'zeiger'
|
5
|
+
|
6
|
+
SOCKET_NAME = "./zeiger-index"
|
7
|
+
|
8
|
+
command = $*[0]
|
9
|
+
|
10
|
+
case command
|
11
|
+
when "server" ; Zeiger::Server.run *$*
|
12
|
+
when "search" ; Zeiger::QueryClient.run *$*
|
13
|
+
when "files" ; Zeiger::FileListClient.run *$*
|
14
|
+
end
|
15
|
+
|
16
|
+
# define file groups
|
17
|
+
|
18
|
+
# file_group :app, patterns: [/^app/ ]
|
19
|
+
# file_group :helpers, patterns: [/^app\/helpers/ ]
|
20
|
+
# file_group :spec, patterns: [/^spec/ ]
|
21
|
+
# file_group :sass, patterns: [/\.sass$/ ]
|
22
|
+
# file_group :all, groups: %w{app spec sass}
|
23
|
+
|
24
|
+
|
25
|
+
# writing to socket: nc -U /tmp/uss
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module Zeiger
|
4
|
+
class FileInfo
|
5
|
+
attr_accessor :dir, :filename, :ngrams
|
6
|
+
|
7
|
+
def initialize dir, filename
|
8
|
+
@dir, @filename, @ngrams = dir, filename, Set.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def local_filename
|
12
|
+
filename.gsub(/^#{Regexp.escape dir}\//, "")
|
13
|
+
end
|
14
|
+
|
15
|
+
def match regex
|
16
|
+
local_filename.match regex
|
17
|
+
end
|
18
|
+
|
19
|
+
def add_ngram ngram
|
20
|
+
@ngrams << ngram
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/zeiger/index.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
module Zeiger
|
2
|
+
class Index
|
3
|
+
NGRAM_SIZE = 3
|
4
|
+
|
5
|
+
attr_accessor :index, :dir, :includes, :ignore, :files
|
6
|
+
|
7
|
+
def initialize dir
|
8
|
+
attrs = File.exist?(".zeiger.yml") ? YAML.load(File.read ".zeiger.yml") : { }
|
9
|
+
self.dir = File.expand_path dir
|
10
|
+
self.index = Hash.new { |h, k| h[k] = [] }
|
11
|
+
self.files = Hash.new
|
12
|
+
end
|
13
|
+
|
14
|
+
def remove_from_index file
|
15
|
+
info = files[file]
|
16
|
+
if info
|
17
|
+
info.ngrams.each { |ngram|
|
18
|
+
index[ngram].reject! { |line| line.file == info }
|
19
|
+
}
|
20
|
+
end
|
21
|
+
files.delete file
|
22
|
+
end
|
23
|
+
|
24
|
+
def add_to_index file
|
25
|
+
info = files[file] = FileInfo.new(dir, file)
|
26
|
+
|
27
|
+
File.read(file).split(/\n/).each_with_index { |txt, line|
|
28
|
+
Line.new(info, line + 1, txt).ngrams(NGRAM_SIZE) do |trig, line|
|
29
|
+
index[trig] << line
|
30
|
+
info.add_ngram trig
|
31
|
+
end
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
def exec_query regex, ngrams
|
36
|
+
ngrams.map { |ngram| index[ngram] }.reduce(&:&).select { |line| line.matches? regex }
|
37
|
+
end
|
38
|
+
|
39
|
+
def query txt
|
40
|
+
puts "got query #{txt.inspect}"
|
41
|
+
exec_query Regexp.compile(txt), txt.ngrams(NGRAM_SIZE)
|
42
|
+
end
|
43
|
+
|
44
|
+
def file_list name
|
45
|
+
r = Regexp.compile name
|
46
|
+
puts "file names matching #{r.inspect}"
|
47
|
+
files.values.select { |f| f.match r }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/lib/zeiger/line.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
module Zeiger
|
2
|
+
class Line
|
3
|
+
attr_accessor :file, :line_number, :content
|
4
|
+
attr_reader :hash
|
5
|
+
|
6
|
+
def initialize file, line_number, content
|
7
|
+
@file, @line_number, @content = file, line_number, content
|
8
|
+
@hash = "#{file.filename}##{line_number}".hash
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_s ; "#{file.local_filename}:#{line_number}:#{content}" ; end
|
12
|
+
def matches? regex ; content.match regex ; end
|
13
|
+
def ngram_list size ; @ngrams ||= content.ngrams(size) ; end
|
14
|
+
def ngrams size ; ngram_list(size).each { |ngram| yield ngram, self } ; end
|
15
|
+
def == other ; self.file == other.file && self.line_number == other.line_number ; end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Zeiger
|
2
|
+
class Monitor
|
3
|
+
attr_accessor :dir, :index, :stat, :includes, :ignore
|
4
|
+
|
5
|
+
def initialize dir, index
|
6
|
+
@dir, @index, @stat = dir, index, Hash.new
|
7
|
+
attrs = File.exist?(".zeiger.yml") ? YAML.load(File.read ".zeiger.yml") : { }
|
8
|
+
@includes = attrs["includes"] || %w{ app bin config lib spec test }
|
9
|
+
@ignore = attrs["ignore"] || %w{ .gz$ .png$ .jpg$ .pdf$ }
|
10
|
+
end
|
11
|
+
|
12
|
+
def ignore? filename
|
13
|
+
ignore.any? { |ig| filename.match ig }
|
14
|
+
end
|
15
|
+
|
16
|
+
def uptodate? filename, mtime
|
17
|
+
stat.include?(filename) && stat[filename] == mtime
|
18
|
+
end
|
19
|
+
|
20
|
+
def build_index
|
21
|
+
started = Time.now
|
22
|
+
files = Set.new
|
23
|
+
includes.each do |inc|
|
24
|
+
Dir.glob(File.join(dir, inc, "**", "*")).sort.each do |file|
|
25
|
+
if File.file?(file) && !ignore?(file)
|
26
|
+
files << file
|
27
|
+
mtime = File.stat(file).mtime
|
28
|
+
if !uptodate?(file, mtime)
|
29
|
+
puts "re-indexing #{file}"
|
30
|
+
index.remove_from_index file
|
31
|
+
index.add_to_index file
|
32
|
+
stat[file] = mtime
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
(Set.new(stat.keys) - files).each { |f| index.remove_from_index f }
|
38
|
+
finished = Time.now
|
39
|
+
puts "ngrams : #{index.index.length}"
|
40
|
+
puts "files : #{index.files.length}"
|
41
|
+
puts "#build_index : #{(finished - started)} sec"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Zeiger
|
2
|
+
class Server
|
3
|
+
def self.run command, *args
|
4
|
+
dir = File.expand_path(".")
|
5
|
+
z = Zeiger::Index.new dir
|
6
|
+
|
7
|
+
Thread.new do
|
8
|
+
begin
|
9
|
+
puts "monitor thread"
|
10
|
+
monitor = Zeiger::Monitor.new dir, z
|
11
|
+
puts "created monitor"
|
12
|
+
while true do
|
13
|
+
puts "scanning..."
|
14
|
+
monitor.build_index
|
15
|
+
sleep 10
|
16
|
+
end
|
17
|
+
rescue Exception => e
|
18
|
+
puts e.message
|
19
|
+
puts e.backtrace
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
puts "query thread..."
|
24
|
+
|
25
|
+
Socket.unix_server_loop(SOCKET_NAME) { |sock, client|
|
26
|
+
puts "query thread: server loop"
|
27
|
+
begin
|
28
|
+
incoming = sock.readline.strip.split(/:/, 2).map &:strip
|
29
|
+
case incoming[0]
|
30
|
+
when "SEARCH"
|
31
|
+
z.query(incoming[1]).each { |res| sock.puts res.to_s }
|
32
|
+
when "FILES"
|
33
|
+
z.file_list(incoming[1]).each { |f| sock.puts f.local_filename }
|
34
|
+
end
|
35
|
+
ensure
|
36
|
+
sock.close
|
37
|
+
end
|
38
|
+
}
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/zeiger.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require "set"
|
2
|
+
require 'yaml'
|
3
|
+
require 'zeiger/query_client'
|
4
|
+
require 'zeiger/file_list_client'
|
5
|
+
require 'zeiger/server'
|
6
|
+
require "zeiger/version"
|
7
|
+
require 'zeiger/monitor'
|
8
|
+
require 'zeiger/file_info'
|
9
|
+
require 'zeiger/index'
|
10
|
+
require 'zeiger/line'
|
11
|
+
|
12
|
+
class String
|
13
|
+
def ngrams size
|
14
|
+
padding = " " * (size - 1)
|
15
|
+
txt = self
|
16
|
+
ngrams = Hash.new { |h,k| h[k] = 0 }
|
17
|
+
regex = Regexp.compile("." * size)
|
18
|
+
|
19
|
+
result = []
|
20
|
+
|
21
|
+
(txt.length - 2).times do |i|
|
22
|
+
result << txt[i..(i + 2)]
|
23
|
+
end
|
24
|
+
|
25
|
+
result
|
26
|
+
end
|
27
|
+
end
|
data/zeiger.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'zeiger/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "zeiger"
|
8
|
+
spec.version = Zeiger::VERSION
|
9
|
+
spec.authors = ["conanite"]
|
10
|
+
spec.email = ["conan@conandalton.net"]
|
11
|
+
spec.summary = %q{Provide text index of files in current directory tree and a unix socket to query on}
|
12
|
+
spec.description = %q{Maintain an in-memory text index of files in current directory tree, allow querying via unix socket in current directory }
|
13
|
+
spec.homepage = "https://github.com/conanite/zeiger"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
22
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
23
|
+
end
|
metadata
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: zeiger
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- conanite
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-05-25 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.7'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
description: 'Maintain an in-memory text index of files in current directory tree,
|
42
|
+
allow querying via unix socket in current directory '
|
43
|
+
email:
|
44
|
+
- conan@conandalton.net
|
45
|
+
executables:
|
46
|
+
- zeiger
|
47
|
+
extensions: []
|
48
|
+
extra_rdoc_files: []
|
49
|
+
files:
|
50
|
+
- ".gitignore"
|
51
|
+
- ".zeiger.yml"
|
52
|
+
- Gemfile
|
53
|
+
- LICENSE.txt
|
54
|
+
- README.md
|
55
|
+
- Rakefile
|
56
|
+
- bin/zeiger
|
57
|
+
- lib/zeiger.rb
|
58
|
+
- lib/zeiger/file_info.rb
|
59
|
+
- lib/zeiger/file_list_client.rb
|
60
|
+
- lib/zeiger/index.rb
|
61
|
+
- lib/zeiger/line.rb
|
62
|
+
- lib/zeiger/monitor.rb
|
63
|
+
- lib/zeiger/query_client.rb
|
64
|
+
- lib/zeiger/server.rb
|
65
|
+
- lib/zeiger/version.rb
|
66
|
+
- zeiger.gemspec
|
67
|
+
homepage: https://github.com/conanite/zeiger
|
68
|
+
licenses:
|
69
|
+
- MIT
|
70
|
+
metadata: {}
|
71
|
+
post_install_message:
|
72
|
+
rdoc_options: []
|
73
|
+
require_paths:
|
74
|
+
- lib
|
75
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
80
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
requirements: []
|
86
|
+
rubyforge_project:
|
87
|
+
rubygems_version: 2.2.2
|
88
|
+
signing_key:
|
89
|
+
specification_version: 4
|
90
|
+
summary: Provide text index of files in current directory tree and a unix socket to
|
91
|
+
query on
|
92
|
+
test_files: []
|