mirror of
https://github.com/vbatts/persistent-shell-history.git
synced 2024-11-21 23:25:40 +00:00
rearranging classes and beginning to enable the history to have various
datastore types (not just GDBM)
This commit is contained in:
parent
eb3cdd71c8
commit
7f97ccc568
8 changed files with 164 additions and 89 deletions
|
@ -29,7 +29,7 @@ OptionParser.new do |opts|
|
||||||
end
|
end
|
||||||
end.parse!(ARGV)
|
end.parse!(ARGV)
|
||||||
|
|
||||||
bh = BashHistory.new(bh_options)
|
bh = Persistent::Shell::DataStore.new(bh_options)
|
||||||
|
|
||||||
if options[:inspect]
|
if options[:inspect]
|
||||||
p bh
|
p bh
|
||||||
|
@ -61,3 +61,4 @@ elsif options[:list]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# vim: set sts=2 sw=2 et ai:
|
||||||
|
|
|
@ -3,8 +3,7 @@ require 'persistent-shell-history/bash-history'
|
||||||
|
|
||||||
module Persistent
|
module Persistent
|
||||||
module Shell
|
module Shell
|
||||||
module History
|
|
||||||
# Your code goes here...
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# vim: set sts=2 sw=2 et ai:
|
||||||
|
|
17
lib/persistent-shell-history/abstract-history-store.rb
Normal file
17
lib/persistent-shell-history/abstract-history-store.rb
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
|
||||||
|
module Persistent
|
||||||
|
module Shell
|
||||||
|
|
||||||
|
class AbstractHistoryStore
|
||||||
|
SCHEMA_VERSION = "1"
|
||||||
|
|
||||||
|
def commands; end
|
||||||
|
def db; end
|
||||||
|
def shema_match?; db.has_key? "schema_version" and db["schema_version"] == SCHEMA_VERSION; end
|
||||||
|
def shema_version; db["schema_version"] if db.has_key? "schema_version" ; end
|
||||||
|
end # class AbstractHistoryStore
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# vim: set sts=2 sw=2 et ai:
|
|
@ -3,92 +3,101 @@ require 'digest/md5'
|
||||||
require 'gdbm'
|
require 'gdbm'
|
||||||
require 'yaml'
|
require 'yaml'
|
||||||
|
|
||||||
class BashHistory
|
require 'persistent-shell-history/abstract-history-store'
|
||||||
attr_reader :db
|
|
||||||
OPTIONS = {
|
|
||||||
:file => File.expand_path("~/.bash_history"),
|
|
||||||
:archive_file => File.expand_path("~/.bash_history.db"),
|
|
||||||
:time_format => "%F %T",
|
|
||||||
}
|
|
||||||
def initialize(opts = {})
|
|
||||||
@options = OPTIONS.merge(opts)
|
|
||||||
_parse
|
|
||||||
end
|
|
||||||
def time_format; @options[:time_format]; end
|
|
||||||
def time_format=(tf); @options[:time_format] = tf; end
|
|
||||||
def db
|
|
||||||
@db ||= GDBM.new(@options[:archive_file])
|
|
||||||
end
|
|
||||||
def keys; db.keys; end
|
|
||||||
def keys_to_i; keys.map {|i| i.to_i }; end
|
|
||||||
def values; db.map {|k,v| _yl(v) }; end
|
|
||||||
def values_by_time
|
|
||||||
return db.map {|k,v|
|
|
||||||
data = _yl(v)
|
|
||||||
data[:time].map {|t|
|
|
||||||
data.merge(:time => t)
|
|
||||||
}
|
|
||||||
}.flatten.sort_by {|x|
|
|
||||||
x[:time]
|
|
||||||
}
|
|
||||||
end
|
|
||||||
def commands; values.map {|v| v[:cmd] }; end
|
|
||||||
def _yd(data); YAML.dump(data); end
|
|
||||||
def _yl(data); YAML.load(data); end
|
|
||||||
def _md5(data); Digest::MD5.hexdigest(data); end
|
|
||||||
def _f(v); " %s %s" % [v[:time].strftime(@options[:time_format]), v[:cmd]]; end
|
|
||||||
|
|
||||||
def find(pat)
|
module Persistent
|
||||||
return values.select {|v|
|
module Shell
|
||||||
v if v[:cmd] =~ /#{pat}/
|
class HistoryStore < AbstractHistoryStore
|
||||||
}.map {|v|
|
SCHEMA_VERSION = "1"
|
||||||
v[:time].map {|t|
|
OPTIONS = {
|
||||||
v.merge(:time => t)
|
:file => File.expand_path("~/.bash_history"),
|
||||||
|
:archive_file => File.expand_path("~/.bash_history.db"),
|
||||||
|
:time_format => "%F %T",
|
||||||
}
|
}
|
||||||
}.flatten
|
def initialize(opts = {})
|
||||||
end
|
@options = OPTIONS.merge(opts)
|
||||||
|
_load if schema_match?
|
||||||
def _parse
|
end
|
||||||
open(@options[:file]) do |f|
|
def time_format; @options[:time_format]; end
|
||||||
f.each_line do |line|
|
def time_format=(tf); @options[:time_format] = tf; end
|
||||||
if line =~ /^#(.*)$/
|
def db
|
||||||
l = f.readline.chomp
|
@db ||= GDBM.new(@options[:archive_file])
|
||||||
key = _md5(l)
|
end
|
||||||
if db.has_key?(key)
|
def keys; db.keys; end
|
||||||
times = _yl(db[key])[:time]
|
def keys_to_i; keys.map {|i| i.to_i }; end
|
||||||
if times.kind_of? Array
|
def values; db.map {|k,v| _yl(v) }; end
|
||||||
times.push(Time.at($1.to_i))
|
def values_by_time
|
||||||
|
return db.map {|k,v|
|
||||||
|
data = _yl(v)
|
||||||
|
data[:time].map {|t|
|
||||||
|
data.merge(:time => t)
|
||||||
|
}
|
||||||
|
}.flatten.sort_by {|x|
|
||||||
|
x[:time]
|
||||||
|
}
|
||||||
|
end
|
||||||
|
def commands; values.map {|v| v[:cmd] }; end
|
||||||
|
def _yd(data); YAML.dump(data); end
|
||||||
|
def _yl(data); YAML.load(data); end
|
||||||
|
def _md5(data); Digest::MD5.hexdigest(data); end
|
||||||
|
def _f(v); " %s %s" % [v[:time].strftime(@options[:time_format]), v[:cmd]]; end
|
||||||
|
|
||||||
|
def find(pat)
|
||||||
|
return values.select {|v|
|
||||||
|
v if v[:cmd] =~ /#{pat}/
|
||||||
|
}.map {|v|
|
||||||
|
v[:time].map {|t|
|
||||||
|
v.merge(:time => t)
|
||||||
|
}
|
||||||
|
}.flatten
|
||||||
|
end
|
||||||
|
|
||||||
|
def _load(filename = @options[:file])
|
||||||
|
#History.new(file).parse
|
||||||
|
open(filename) do |f|
|
||||||
|
f.each_line do |line|
|
||||||
|
if line =~ /^#(.*)$/
|
||||||
|
l = f.readline.chomp
|
||||||
|
key = _md5(l)
|
||||||
|
if db.has_key?(key)
|
||||||
|
times = _yl(db[key])[:time]
|
||||||
|
if times.kind_of? Array
|
||||||
|
times.push(Time.at($1.to_i))
|
||||||
|
else
|
||||||
|
times = [times]
|
||||||
|
end
|
||||||
|
db[key] = _yd({:cmd => l, :time => times.uniq })
|
||||||
|
else
|
||||||
|
db[key] = _yd({:cmd => l, :time => [Time.at($1.to_i)] })
|
||||||
|
end
|
||||||
else
|
else
|
||||||
times = [times]
|
key = _md5(line.chomp)
|
||||||
|
if db.has_key?(key)
|
||||||
|
times = _yl(db[key])[:time]
|
||||||
|
if times.kind_of? Array
|
||||||
|
times.push(Time.at($1.to_i))
|
||||||
|
else
|
||||||
|
times = [times]
|
||||||
|
end
|
||||||
|
db[key] = _yd({:cmd => l, :time => times.uniq })
|
||||||
|
else
|
||||||
|
db[key] = _yd({:cmd => line.chomp, :time => [Time.at(0)] })
|
||||||
|
end
|
||||||
end
|
end
|
||||||
db[key] = _yd({:cmd => l, :time => times.uniq })
|
|
||||||
else
|
|
||||||
db[key] = _yd({:cmd => l, :time => [Time.at($1.to_i)] })
|
|
||||||
end
|
|
||||||
else
|
|
||||||
key = _md5(line.chomp)
|
|
||||||
if db.has_key?(key)
|
|
||||||
times = _yl(db[key])[:time]
|
|
||||||
if times.kind_of? Array
|
|
||||||
times.push(Time.at($1.to_i))
|
|
||||||
else
|
|
||||||
times = [times]
|
|
||||||
end
|
|
||||||
db[key] = _yd({:cmd => l, :time => times.uniq })
|
|
||||||
else
|
|
||||||
db[key] = _yd({:cmd => line.chomp, :time => [Time.at(0)] })
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
end
|
|
||||||
def render(file)
|
|
||||||
File.open(file,'w+') do |f|
|
|
||||||
values.each do |v|
|
|
||||||
f.write("#" + v[:time].to_i.to_s + "\n") if v[:time] and not (v[:time].to_i == 0)
|
|
||||||
f.write(v[:cmd] + "\n")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
def render(file)
|
||||||
|
File.open(file,'w+') do |f|
|
||||||
|
values.each do |v|
|
||||||
|
f.write("#" + v[:time].to_i.to_s + "\n") if v[:time] and not (v[:time].to_i == 0)
|
||||||
|
f.write(v[:cmd] + "\n")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end # class DataStore
|
||||||
|
end # module Shell
|
||||||
|
end # module Persistent
|
||||||
|
|
||||||
|
# vim: set sts=2 sw=2 et ai:
|
||||||
|
|
16
lib/persistent-shell-history/command.rb
Normal file
16
lib/persistent-shell-history/command.rb
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
|
||||||
|
require 'digest/md5'
|
||||||
|
module Persistent
|
||||||
|
module Shell
|
||||||
|
class Command < Struct.new(:cmd, :time)
|
||||||
|
def md5
|
||||||
|
Digest::MD5.hexdigest(cmd)
|
||||||
|
end
|
||||||
|
def to_h
|
||||||
|
{ :cmd => cmd, :time => time, }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# vim: set sts=2 sw=2 et ai:
|
33
lib/persistent-shell-history/history.rb
Normal file
33
lib/persistent-shell-history/history.rb
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
|
||||||
|
require 'persistent-shell-history/command'
|
||||||
|
|
||||||
|
module Persistent
|
||||||
|
module Shell
|
||||||
|
class History
|
||||||
|
def initialize(filename = '~/.bash_history')
|
||||||
|
@filename = File.expand_path(filename)
|
||||||
|
end
|
||||||
|
def file; @filename; end
|
||||||
|
def file=(filename); @filename = File.expand_path(filename); end
|
||||||
|
def commands
|
||||||
|
@cmds ||= parse
|
||||||
|
end
|
||||||
|
def parse(filename = @filename)
|
||||||
|
cmds = Array.new
|
||||||
|
open(filename) do |f|
|
||||||
|
f.each_line do |line|
|
||||||
|
if line =~ /^#(.*)$/
|
||||||
|
l = f.readline.chomp
|
||||||
|
cmds << Command.new(l, $1)
|
||||||
|
else
|
||||||
|
cmds << Command.new(line, "0")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return cmds
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# vim: set sts=2 sw=2 et ai:
|
|
@ -1,7 +1,7 @@
|
||||||
module Persistent
|
module Persistent
|
||||||
module Shell
|
module Shell
|
||||||
module History
|
VERSION = "0.0.1"
|
||||||
VERSION = "0.0.1"
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# vim: set sts=2 sw=2 et ai:
|
||||||
|
|
|
@ -4,7 +4,7 @@ require "persistent-shell-history/version"
|
||||||
|
|
||||||
Gem::Specification.new do |s|
|
Gem::Specification.new do |s|
|
||||||
s.name = "persistent-shell-history"
|
s.name = "persistent-shell-history"
|
||||||
s.version = Persistent::Shell::History::VERSION
|
s.version = Persistent::Shell::VERSION
|
||||||
s.authors = ["Vincent Batts"]
|
s.authors = ["Vincent Batts"]
|
||||||
s.email = ["vbatts@hashbangbash.com"]
|
s.email = ["vbatts@hashbangbash.com"]
|
||||||
s.homepage = ""
|
s.homepage = ""
|
||||||
|
|
Loading…
Reference in a new issue