Class: Geist

Inherits:
Object
  • Object
show all
Defined in:
lib/geist.rb,
lib/geist/version.rb

Overview

This code is free software; you can redistribute it and/or modify it under the terms of the new BSD License.

Copyright © 2011, Sebastian Staudt

Constant Summary collapse

VERSION =

This is the current version of the Geist gem

'0.1.0'

Instance Method Summary collapse

Constructor Details

#initialize(path) ⇒ Geist

Create a new Geist instance storing into the given Git repository

Parameters:

  • path (String)

    The path of the Git repository to store objects into

Raises:

  • (RuntimeError)

    if the directory is not empty and not a Git repository



20
21
22
23
24
25
26
27
28
29
# File 'lib/geist.rb', line 20

def initialize(path)
  @path = File.expand_path path

  if !File.exist? @path
    FileUtils.mkdir_p @path
    cmd 'init'
  elsif !cmd('ls-files').success?
    raise "#{@path} is not a Git repository."
  end
end

Instance Method Details

#cmd(git_cmd, &block) ⇒ Process::Status (private)

Execute a Git command in the path of the Git repository of the current Geist instance

Parameters:

  • git_cmd (String)

    The Git command to execute

  • block (Proc)

    A block that can be used to read and write to and from the Git process’ STDOUT and STDIN.

Returns:

  • (Process::Status)

    The exit status of the Git process



126
127
128
129
130
131
132
133
134
135
136
# File 'lib/geist.rb', line 126

def cmd(git_cmd, &block)
  cmd = "git --git-dir #{@path} #{git_cmd}"
  status = Open4::popen4 cmd do |pid, stdin, stdout, stderr|
    block.call stdin, stdout if block_given?

    stdin.close unless stdin.closed?
    stdout.close
    stderr.close
  end
  status
end

#delete(*keys) ⇒ Boolean

TODO:

This does not really remove the objects from the repository but only the tags. This should also trigger Git’s garbage collection to remove the objects completely.

Delete the objects with the given keys from the storage

Parameters:

  • keys (#to_s, ...)

    One or more keys where the corresponding values should be removed from the storage

Returns:

  • (Boolean)

    ‘true` if the objects have been removed from the repository



40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/geist.rb', line 40

def delete(*keys)
  success = true

  keys.each do |key|
    if id_for(key).nil?
      success = false
    else
      cmd "tag -d '#{key}'"
    end
  end

  success
end

#get(*keys) ⇒ Object+

Retrieve the objects with the given keys from the storage

Parameters:

  • keys (#to_s, ...)

    One or more keys where the corresponding values should be loaded from the storage

Returns:

  • (Object, Array<Object>)

    One or more objects that belong to the given keys



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/geist.rb', line 60

def get(*keys)
  return nil if keys.empty?

  values = []
  keys.each do |key|
    value = nil
    status = cmd "show '#{key}'" do |stdin, stdout|
      if select [stdout]
        blob = stdout.read.strip
        value = Marshal.load blob unless blob.empty?
      end
    end
    values << (status.success? ? value : nil)
  end

  keys.size == 1 ? values.first : values
end

#id_for(key) ⇒ String? (private)

Returns the Git SHA ID of the blob where the value for the given key is stored

Parameters:

  • key (String, #to_s)

    The key for which the Git SHA ID should be returned

Returns:

  • (String, nil)

    The SHA ID of the value’s Git blob or ‘nil` if no such object exists



145
146
147
148
149
150
151
# File 'lib/geist.rb', line 145

def id_for(key)
  id = nil
  status = cmd "rev-parse '#{key}'" do |stdin, stdout|
    id = stdout.read.strip if select [stdout]
  end
  status.success? ? id : nil
end

#keysArray<String>

Returns all keys which have objects available in the storage

Returns:

  • (Array<String>)

    The keys available in the storage



81
82
83
84
85
86
87
# File 'lib/geist.rb', line 81

def keys
  keys = nil
  cmd 'tag -l' do |stdin, stdout|
    keys = stdout.lines.to_a.map(&:strip) if select [stdout]
  end
  keys
end

#set(keys, value = nil) ⇒ Object

Saves one ore more values into the storage

Parameters:

  • keys (#to_s, Hash<#to_s, Object>)

    The key to use to store the value or a hash of multiple keys and values to store

  • value (Object) (defaults to: nil)

    The object to store as a value (only if a single key is given)



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/geist.rb', line 95

def set(keys, value = nil)
  keys = { keys => value } unless keys.is_a? Hash

  keys.each do |key, val|
    if key.to_s.match(/(?:[\s^~:?*\[\\]|\.\.|@\{|(?:\/|\.|\.lock)$|^$)/)
      warn "Warning: Invalid key '#{key}'"
      return
    end

    delete key unless id_for(key).nil?

    id = nil
    cmd 'hash-object --stdin -w' do |stdin, stdout|
      stdin.write Marshal.dump(val)
      stdin.close
      id = stdout.read.strip if select [stdout]
    end

    cmd "tag -f '#{key}' #{id}"
  end
end