Skip to content

Instantly share code, notes, and snippets.

@seki
Created July 7, 2019 09:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save seki/9a7cda3e189e888ce4bfb07eeb36211e to your computer and use it in GitHub Desktop.
Save seki/9a7cda3e189e888ce4bfb07eeb36211e to your computer and use it in GitHub Desktop.
a simple kvs using git (rugged)
require 'rugged'
require 'cgi'
class Grip
def initialize(dir)
@dir = dir
@git = Rugged::Repository.new(@dir) rescue git_init
@author = {email: 'seki@ruby-lang.org', name: 'seki'}
@message = 'via grip'
end
attr_reader :git
def git_init
Rugged::Repository.init_at(@dir)
end
def to_path(key)
CGI.escape(key)
end
def to_key(path)
CGI.unescape(path)
end
def store(key, value, mtime=Time.now)
oid = @git.write(value, :blob)
index = @git.index
tree = @git.head.target.tree rescue []
index.read_tree(tree) rescue nil
path = to_path(key)
index.add(path: path, oid: oid, mode: 0100644)
author = {time: mtime}.update(@author)
parents = @git.empty? ? [] : [@git.head.target].compact
Rugged::Commit.create(
@git,
tree: index.write_tree(@git),
author: author,
committer: author,
parents: parents,
update_ref: 'HEAD',
message: "via grip"
)
oid
end
def []=(key, value)
store(key, value, Time.now)
end
def [](key)
fetch(key)&.force_encoding("UTF-8")
end
def fetch(key)
path = to_path(key)
sha = @git.head.target.tree.get_entry(path)&.dig(:oid)
return nil unless sha
@git.lookup(sha).content
end
def keys
each_key.to_a
end
def each_key
return to_enum(:each_key) unless block_given?
@git.head.target.tree.each {|e| yield(to_key(e[:name]))}
end
def each
return to_enum(:each) unless block_given?
@git.head.target.tree.each {|e|
yield(to_key(e[:name]),
@git.lookup(e[:oid]).content.force_encoding("UTF-8"))
}
end
def history
w = Rugged::Walker.new(@git)
w.push(@git.head.target.oid)
w.each do |commit|
yield(commit)
end
w.reset
nil
end
end
if __FILE__ == $0
g = Grip.new('tmp/grip')
name = "NS1-5000"
s = Time.now
30000.times do |x|
if x % 100 == 0
p [x, Time.now - s]
s = Time.now
end
name = name.succ
g[name] = <<EOS
= #{name}
empty item
== status
* 種類: task / story / bug
* イテレーション:
* サイン: ((<rwiki>))
* 状態: open
* 見積: 0 / 0
* テスト分類:
* テストレート:
== description
== test
* Q: test..
* A: answer..
== history
* #{Time.now.strftime("%Y-%m-%d")} rwiki: open
EOS
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment