cached 0.2
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/.gitignore +5 -0
- data/Rakefile +15 -0
- data/bin/cached +27 -0
- data/bin/kvstore +74 -0
- data/gem.yml +11 -0
- data/hooks/post_install.rb +1 -0
- data/hooks/pre_uninstall.rb +1 -0
- data/lib/cached.rb +84 -0
- data/lib/db.rb +40 -0
- data/lib/fast_gem.rb +56 -0
- data/script/console +19 -0
- data/test/test.rb +5 -0
- data/vex/gem.rake +36 -0
- data/vex/gem.rb +95 -0
- metadata +95 -0
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
load "#{File.dirname __FILE__}/vex/gem.rake"
|
2
|
+
|
3
|
+
task :default => :test
|
4
|
+
|
5
|
+
task :test do
|
6
|
+
sh "ruby test/test.rb"
|
7
|
+
end
|
8
|
+
|
9
|
+
task :rcov do
|
10
|
+
sh "cd test; rcov -o ../coverage -x ruby/.*/gems -x ^test.rb test.rb"
|
11
|
+
end
|
12
|
+
|
13
|
+
task :rdoc do
|
14
|
+
sh "rdoc -o doc/rdoc"
|
15
|
+
end
|
data/bin/cached
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
if ARGV == %w(--install)
|
4
|
+
require "fileutils"
|
5
|
+
|
6
|
+
FileUtils.rm($0)
|
7
|
+
FileUtils.symlink(__FILE__, $0)
|
8
|
+
exit
|
9
|
+
elsif defined?(Gem)
|
10
|
+
STDERR.puts "Note: please run improved installation via\n\n\tsudo #{$0} --install"
|
11
|
+
end
|
12
|
+
|
13
|
+
begin
|
14
|
+
path = File.readlink(__FILE__)
|
15
|
+
rescue Errno::EINVAL
|
16
|
+
path = __FILE__
|
17
|
+
end
|
18
|
+
|
19
|
+
$: << File.expand_path(File.dirname(path) + "/../lib")
|
20
|
+
|
21
|
+
require "cached"
|
22
|
+
|
23
|
+
load "db.rb"
|
24
|
+
|
25
|
+
Db.database ||= "#{ENV["HOME"]}/.cached.sql"
|
26
|
+
|
27
|
+
puts Cached.exec *ARGV
|
data/bin/kvstore
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
if ARGV == %w(--install)
|
4
|
+
require "fileutils"
|
5
|
+
|
6
|
+
FileUtils.rm($0)
|
7
|
+
FileUtils.symlink(__FILE__, $0)
|
8
|
+
exit
|
9
|
+
elsif defined?(Gem)
|
10
|
+
STDERR.puts "Note: please run improved installation via\n\n\tsudo #{$0} --install"
|
11
|
+
end
|
12
|
+
|
13
|
+
begin
|
14
|
+
path = File.readlink(__FILE__)
|
15
|
+
rescue Errno::EINVAL
|
16
|
+
path = __FILE__
|
17
|
+
end
|
18
|
+
|
19
|
+
$: << File.expand_path(File.dirname(path) + "/../lib")
|
20
|
+
|
21
|
+
require "db"
|
22
|
+
|
23
|
+
Db.database = "#{ENV["HOME"]}/.kvstore.sql"
|
24
|
+
|
25
|
+
class App
|
26
|
+
include Db
|
27
|
+
|
28
|
+
def initialize
|
29
|
+
unless ask "SELECT name FROM sqlite_master WHERE type='table' AND name='kvstore'"
|
30
|
+
ask "CREATE TABLE kvstore(key, value)"
|
31
|
+
ask "CREATE UNIQUE INDEX IF NOT EXISTS kvstore_key ON kvstore(key)"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def set(key, value)
|
36
|
+
ask("INSERT OR REPLACE INTO kvstore VALUES(?, ?)", key, value)
|
37
|
+
end
|
38
|
+
|
39
|
+
def get(key)
|
40
|
+
puts ask("SELECT value FROM kvstore WHERE key=?", key)
|
41
|
+
end
|
42
|
+
|
43
|
+
def delete(key)
|
44
|
+
ask("DELETE FROM kvstore WHERE key=?", key)
|
45
|
+
end
|
46
|
+
|
47
|
+
def list
|
48
|
+
sql("SELECT key, value FROM kvstore") do |row|
|
49
|
+
puts row.first
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def help(*args)
|
54
|
+
STDERR.puts <<-MSG
|
55
|
+
|
56
|
+
Usage:
|
57
|
+
|
58
|
+
#{$0} set key value
|
59
|
+
#{$0} get key
|
60
|
+
#{$0} delete key
|
61
|
+
#{$0} list
|
62
|
+
MSG
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
app = App.new
|
67
|
+
|
68
|
+
cmd = ARGV.shift || "help"
|
69
|
+
begin
|
70
|
+
app.send cmd, *ARGV
|
71
|
+
rescue NoMethodError, ArgumentError
|
72
|
+
puts $!
|
73
|
+
app.help
|
74
|
+
end
|
data/gem.yml
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
#
|
2
|
+
# A vex/gem config file.
|
3
|
+
version: 0.2
|
4
|
+
authors: ["radiospiel"]
|
5
|
+
email: eno@open-lab.org
|
6
|
+
homepage: http://radiospiel.org
|
7
|
+
summary: cached command line tool
|
8
|
+
description: |
|
9
|
+
The 'cached' command line tool provides an easy to use *nix caching tool.
|
10
|
+
|
11
|
+
dependencies: sqlite3
|
@@ -0,0 +1 @@
|
|
1
|
+
STDERR.puts "*** THIS IS THE POST INSTALL SCRIPT"
|
@@ -0,0 +1 @@
|
|
1
|
+
STDERR.puts "*** THIS IS THE PRE UNINSTALL SCRIPT"
|
data/lib/cached.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
load "db.rb"
|
2
|
+
Db.database ||= "#{ENV["HOME"]}/.cached.sql"
|
3
|
+
|
4
|
+
require 'digest/sha1'
|
5
|
+
|
6
|
+
class Entry
|
7
|
+
extend Db
|
8
|
+
|
9
|
+
def self.init
|
10
|
+
unless ask "SELECT name FROM sqlite_master WHERE type='table' AND name='cached'"
|
11
|
+
ask "CREATE TABLE cached(key, value, valid_until)"
|
12
|
+
end
|
13
|
+
|
14
|
+
ask "CREATE UNIQUE INDEX IF NOT EXISTS cached_key ON cached(key)"
|
15
|
+
ask "CREATE INDEX IF NOT EXISTS cached_valid_until ON cached(valid_until)"
|
16
|
+
end
|
17
|
+
|
18
|
+
init
|
19
|
+
|
20
|
+
def self.cleanup
|
21
|
+
ask "DELETE FROM cached WHERE valid_until < ?", now
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.now
|
25
|
+
Time.now.to_i
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.get(key)
|
29
|
+
value, valid_until = *row("SELECT value, valid_until FROM cached WHERE key=?", key)
|
30
|
+
return value if value && valid_until.to_i >= now
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.set(key, value, options)
|
34
|
+
ask "INSERT OR REPLACE INTO cached (key, value, valid_until) VALUES(?, ?, ?)", key, value, now + options[:ttl]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
module Cached
|
39
|
+
def self.exec(*args)
|
40
|
+
ttl = 3600
|
41
|
+
|
42
|
+
case args.first
|
43
|
+
when /^--ttl=([0-9]+)$/
|
44
|
+
args.shift
|
45
|
+
ttl = $1.to_i
|
46
|
+
end
|
47
|
+
|
48
|
+
key = Digest::SHA1.hexdigest(Dir.getwd + ":" + args.inspect)
|
49
|
+
Entry.get(key) || begin
|
50
|
+
value = run(*args)
|
51
|
+
Entry.set(key, value, :ttl => ttl)
|
52
|
+
value
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.shell_escape(*args)
|
57
|
+
args.map do |str|
|
58
|
+
if str.empty?
|
59
|
+
"''"
|
60
|
+
elsif %r{\A[0-9A-Za-z+,./:=@_-]+\z} =~ str
|
61
|
+
str
|
62
|
+
else
|
63
|
+
result = ''
|
64
|
+
str.scan(/('+)|[^']+/) {
|
65
|
+
if $1
|
66
|
+
result << %q{\'} * $1.length
|
67
|
+
else
|
68
|
+
result << "'#{$&}'"
|
69
|
+
end
|
70
|
+
}
|
71
|
+
result
|
72
|
+
end
|
73
|
+
end.join(" ")
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.run(*args)
|
77
|
+
command = args.join(" ")
|
78
|
+
# command = shell_escape args
|
79
|
+
`#{command}`
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
#
|
84
|
+
# TODO: start cleanup in background... Entry.cleanup
|
data/lib/db.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
load "fast_gem.rb"
|
2
|
+
|
3
|
+
FastGem.load "sqlite3"
|
4
|
+
|
5
|
+
module Db
|
6
|
+
def self.database=(database)
|
7
|
+
@database = database
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.database
|
11
|
+
@database
|
12
|
+
end
|
13
|
+
|
14
|
+
def db
|
15
|
+
@db ||= SQLite3::Database.new(Db.database)
|
16
|
+
end
|
17
|
+
|
18
|
+
def log(query, *args)
|
19
|
+
# STDERR.puts "[sqlite] #{query}"
|
20
|
+
end
|
21
|
+
|
22
|
+
def sql(query, *args, &block)
|
23
|
+
log query, *args
|
24
|
+
r = db.execute query, *args, &block
|
25
|
+
return r if r
|
26
|
+
return [ db.changes ] if query =~ /^\s*(DELETE|INSERT)\b/i
|
27
|
+
end
|
28
|
+
|
29
|
+
def ask(query, *args)
|
30
|
+
log query, *args
|
31
|
+
r = db.get_first_value(query, *args)
|
32
|
+
return r if r
|
33
|
+
return db.changes if query =~ /^\s*(DELETE|INSERT)\b/i
|
34
|
+
end
|
35
|
+
|
36
|
+
def row(query, *args)
|
37
|
+
log query, *args
|
38
|
+
db.get_first_row(query, *args)
|
39
|
+
end
|
40
|
+
end
|
data/lib/fast_gem.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
module Gem
|
2
|
+
require 'rbconfig'
|
3
|
+
|
4
|
+
if !defined?(ConfigMap)
|
5
|
+
|
6
|
+
ConfigMap = {
|
7
|
+
:EXEEXT => RbConfig::CONFIG["EXEEXT"],
|
8
|
+
:RUBY_SO_NAME => RbConfig::CONFIG["RUBY_SO_NAME"],
|
9
|
+
:arch => RbConfig::CONFIG["arch"],
|
10
|
+
:bindir => RbConfig::CONFIG["bindir"],
|
11
|
+
:datadir => RbConfig::CONFIG["datadir"],
|
12
|
+
:libdir => RbConfig::CONFIG["libdir"],
|
13
|
+
:ruby_install_name => RbConfig::CONFIG["ruby_install_name"],
|
14
|
+
:ruby_version => RbConfig::CONFIG["ruby_version"],
|
15
|
+
:rubylibprefix => RbConfig::CONFIG["rubylibprefix"],
|
16
|
+
:sitedir => RbConfig::CONFIG["sitedir"],
|
17
|
+
:sitelibdir => RbConfig::CONFIG["sitelibdir"],
|
18
|
+
:vendordir => RbConfig::CONFIG["vendordir"] ,
|
19
|
+
:vendorlibdir => RbConfig::CONFIG["vendorlibdir"]
|
20
|
+
}
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.user_home
|
25
|
+
ENV["HOME"]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
require 'rubygems/defaults'
|
30
|
+
|
31
|
+
module FastGem
|
32
|
+
extend self
|
33
|
+
|
34
|
+
def gem_paths
|
35
|
+
[ Gem.default_dir, Gem.user_dir ]
|
36
|
+
end
|
37
|
+
|
38
|
+
#
|
39
|
+
# Try ro find the file "name" in any of the available paths, and return the path
|
40
|
+
def find(name)
|
41
|
+
# look into each gempath for a matching file, sort by version (roughly),
|
42
|
+
# and return the last hit
|
43
|
+
gem_paths.
|
44
|
+
map { |gem_path| Dir.glob("#{gem_path}/gems/#{name}-[0-9]*") }.
|
45
|
+
flatten.
|
46
|
+
sort_by { |gem_path| gem_path.gsub(/.*\/gems\/[^-]+-/, "") }.
|
47
|
+
last
|
48
|
+
end
|
49
|
+
|
50
|
+
def load(name)
|
51
|
+
path = find(name)
|
52
|
+
# STDERR.puts "Load #{name} from #{path}"
|
53
|
+
$: << "#{path}/lib"
|
54
|
+
require name
|
55
|
+
end
|
56
|
+
end
|
data/script/console
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Start a console that initializes the gem
|
4
|
+
#
|
5
|
+
require "irb"
|
6
|
+
require "rubygems"
|
7
|
+
|
8
|
+
begin
|
9
|
+
require 'wirble'
|
10
|
+
Wirble.init
|
11
|
+
Wirble.colorize
|
12
|
+
rescue LoadError
|
13
|
+
STDERR.puts "To enable colorized and tab completed run 'gem install wirble'"
|
14
|
+
end
|
15
|
+
|
16
|
+
$: << "#{File.dirname(__FILE__)}/../lib"
|
17
|
+
$: << "#{File.dirname(__FILE__)}/../init.rb"
|
18
|
+
|
19
|
+
IRB.start
|
data/test/test.rb
ADDED
data/vex/gem.rake
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
def sys(*args)
|
2
|
+
STDERR.puts "#{args.join(" ")}"
|
3
|
+
system *args
|
4
|
+
end
|
5
|
+
|
6
|
+
namespace :gem do
|
7
|
+
task :build => :spec do
|
8
|
+
options = []
|
9
|
+
sys "gem build .gemspec #{options.join(" ")} && mkdir -p pkg && mv *.gem pkg"
|
10
|
+
end
|
11
|
+
|
12
|
+
task :spec do
|
13
|
+
File.open ".gemspec", "w" do |file|
|
14
|
+
file.write <<-TXT
|
15
|
+
require "vex/gem"
|
16
|
+
Gem.spec File.dirname(__FILE__)
|
17
|
+
TXT
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
task :install => :build do
|
22
|
+
file = Dir.glob("pkg/*.gem").sort.last
|
23
|
+
sys "gem install #{file}"
|
24
|
+
end
|
25
|
+
|
26
|
+
task :push => :build do
|
27
|
+
file = Dir.glob("pkg/*.gem").sort.last
|
28
|
+
puts "To push the gem to gemcutter please run"
|
29
|
+
puts
|
30
|
+
puts "\tgem push #{file}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
desc "Build gem"
|
35
|
+
# task :gem => %w(test gem:install)
|
36
|
+
task :gem => %w(gem:install gem:push)
|
data/vex/gem.rb
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
module Gem
|
2
|
+
(class << self; self; end).class_eval do
|
3
|
+
def default_attributes
|
4
|
+
%w(name version date files executables)
|
5
|
+
end
|
6
|
+
|
7
|
+
def set_root(root)
|
8
|
+
@root = File.expand_path(root)
|
9
|
+
@name = File.basename(@root)
|
10
|
+
@conf ||= YAML.load File.read("#{@root}/gem.yml")
|
11
|
+
@attributes ||= (default_attributes + @conf.keys.map(&:to_s)).uniq
|
12
|
+
end
|
13
|
+
|
14
|
+
# attr_reader :root, :conf, :attributes,
|
15
|
+
attr_reader :name
|
16
|
+
|
17
|
+
def attribute(name)
|
18
|
+
if @conf.key?(name) && !%w(dependencies).include?(name)
|
19
|
+
@conf[name]
|
20
|
+
else
|
21
|
+
self.send(name)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
#
|
26
|
+
# create a new Gem::Specification object for this gem.
|
27
|
+
def spec(root)
|
28
|
+
self.set_root root
|
29
|
+
|
30
|
+
Gem::Specification.new do |s|
|
31
|
+
@attributes.each do |attr|
|
32
|
+
v = attribute(attr)
|
33
|
+
next if v.nil?
|
34
|
+
|
35
|
+
log attr, v
|
36
|
+
|
37
|
+
s.send attr + "=", v
|
38
|
+
end
|
39
|
+
|
40
|
+
%w(pre_uninstall post_install).each do |hook|
|
41
|
+
next unless File.exists?("#{root}/hooks/#{hook}.rb")
|
42
|
+
log hook, "yes"
|
43
|
+
Gem.send(hook) {
|
44
|
+
load "hooks/#{hook}.rb"
|
45
|
+
}
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def log(attr, v)
|
51
|
+
v = case attr
|
52
|
+
when "files" then "#{v.length} files"
|
53
|
+
else v.inspect
|
54
|
+
end
|
55
|
+
|
56
|
+
STDERR.puts "#{"%20s" % attr}:\t#{v}"
|
57
|
+
end
|
58
|
+
|
59
|
+
def dependencies
|
60
|
+
return nil unless @conf["dependencies"]
|
61
|
+
|
62
|
+
@conf["dependencies"].map do |d|
|
63
|
+
Gem::Dependency.new d, ">= 0"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def head(file)
|
68
|
+
File.open(file) do |f|
|
69
|
+
f.readline
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def executables
|
74
|
+
r = Dir.glob("#{@root}/bin/**/*").map do |file|
|
75
|
+
next unless head(file) =~ /^#!/
|
76
|
+
file[@root.length + 5 .. -1]
|
77
|
+
end.compact
|
78
|
+
|
79
|
+
return nil if r.empty?
|
80
|
+
r
|
81
|
+
end
|
82
|
+
|
83
|
+
#
|
84
|
+
# get files from git
|
85
|
+
def files
|
86
|
+
r = `git ls-files`.split("\n")
|
87
|
+
end
|
88
|
+
|
89
|
+
#
|
90
|
+
# return the date
|
91
|
+
def date
|
92
|
+
Date.today.to_s
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
metadata
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cached
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 15
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 2
|
9
|
+
version: "0.2"
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- radiospiel
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2011-06-16 00:00:00 +02:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: sqlite3
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
hash: 3
|
29
|
+
segments:
|
30
|
+
- 0
|
31
|
+
version: "0"
|
32
|
+
type: :runtime
|
33
|
+
version_requirements: *id001
|
34
|
+
description: |
|
35
|
+
The 'cached' command line tool provides an easy to use *nix caching tool.
|
36
|
+
|
37
|
+
email: eno@open-lab.org
|
38
|
+
executables:
|
39
|
+
- cached
|
40
|
+
- kvstore
|
41
|
+
extensions: []
|
42
|
+
|
43
|
+
extra_rdoc_files: []
|
44
|
+
|
45
|
+
files:
|
46
|
+
- .gitignore
|
47
|
+
- Rakefile
|
48
|
+
- bin/cached
|
49
|
+
- bin/kvstore
|
50
|
+
- gem.yml
|
51
|
+
- hooks/post_install.rb
|
52
|
+
- hooks/pre_uninstall.rb
|
53
|
+
- lib/cached.rb
|
54
|
+
- lib/db.rb
|
55
|
+
- lib/fast_gem.rb
|
56
|
+
- script/console
|
57
|
+
- test/test.rb
|
58
|
+
- vex/gem.rake
|
59
|
+
- vex/gem.rb
|
60
|
+
has_rdoc: true
|
61
|
+
homepage: http://radiospiel.org
|
62
|
+
licenses: []
|
63
|
+
|
64
|
+
post_install_message:
|
65
|
+
rdoc_options: []
|
66
|
+
|
67
|
+
require_paths:
|
68
|
+
- lib
|
69
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
70
|
+
none: false
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
hash: 3
|
75
|
+
segments:
|
76
|
+
- 0
|
77
|
+
version: "0"
|
78
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
79
|
+
none: false
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
hash: 3
|
84
|
+
segments:
|
85
|
+
- 0
|
86
|
+
version: "0"
|
87
|
+
requirements: []
|
88
|
+
|
89
|
+
rubyforge_project:
|
90
|
+
rubygems_version: 1.3.7
|
91
|
+
signing_key:
|
92
|
+
specification_version: 3
|
93
|
+
summary: cached command line tool
|
94
|
+
test_files: []
|
95
|
+
|