summaryrefslogtreecommitdiff
path: root/lib/gall/object.lua
blob: d6b90089bd39c0062102de34b9552b48c67682ec (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
-- gall.object
--
-- Git Abstraction Layer for Lua -- Generic object interface
--
-- Copyright 2012 Daniel Silverstone <dsilvers@digital-scurf.org>
--
--

---
-- Generic object interface
--
-- @module gall.object

local ll = require "gall.ll"
local commit = require "gall.commit"
local tree = require "gall.tree"
local tag = require "gall.tag"

local repos = setmetatable({}, {__mode="k"})
local blobs = setmetatable({}, {__mode="k"})

local known_types = {
   blob = true, commit = true, tree = true, tag = true,
}

local function _objectindex(obj, field)
   local ok, ret
   local blob = blobs[obj]
   if field == "type" then
      if blob then
	 ok, ret = 0, ll.git2.get_object_type(blob)
      else
	 ok, ret = repos[obj]:gather("cat-file", "-t", obj.sha)
      end
   elseif field == "size" then
      if blob then
	 ok, ret = 0, ll.git2.get_object_size(blob)
      else
	 ok, ret = repos[obj]:gather("cat-file", "-s", obj.sha)
      end
   elseif field == "raw" then
      if blob and obj.type ~= "tree" then
	 ok, ret = 0, ll.git2.get_object_raw(blob)
      else
	 ok, ret = repos[obj]:rawgather("cat-file", (obj.type == "tag" and "tag" or "-p"), obj.sha)
      end
   elseif field == "content" then
      assert(known_types[obj.type], "Unknown type: " .. obj.type)
      if obj.type == "blob" then
	 ok, ret = 0, obj.raw
      elseif obj.type == "commit" then
	 ok, ret = 0, commit.new(repos[obj], obj)
      elseif obj.type == "tree" then
	 ok, ret = 0, tree.new(repos[obj], obj)
      elseif obj.type == "tag" then
	 ok, ret = 0, tag.new(repos[obj], obj)
      end
   else
      error("Unknown field <" .. tostring(field) .. ">")
   end

   assert(ok == 0, "Unable to retrieve " .. field)

   if field == "size" then ret = tonumber(ret) end

   rawset(obj, field, ret)

   return ret
end

function _objecttostring(obj)
   return "<GitObject(" .. tostring(obj.sha)..") in " .. tostring(repos[obj]) .. ">"
end

local objectmeta = {
   __index = _objectindex,
   __tostring = _objecttostring
}

---
-- Low level git object
--
-- @type object

---
-- The type of the object
--
-- @field type

---
-- The size of the object
--
-- @field size

---
-- The object's raw content
--
-- @field raw

---
-- The object's processed content.
--
-- * If the object is a commit, then this will be a @{commit} instance.
-- * If the object is a tree, then this will be a @{tree} instance.
-- * If the object is a tag, then this will be a @{tag} instance.
--
-- @field content

---
-- The object's OID (SHA1)
--
-- @field sha

--- @section end

---
-- Create a new raw object.
--
-- Create a new instance of @{object} referring to the given SHA1 OID.
--
-- @function new
-- @tparam repository repo The repository within which the object resides.
-- @tparam string sha The SHA1 OID of the object in the repository.
-- @treturn object The object instance encapsulating the given object.

local function _new(repo, sha)
   local ret = setmetatable({sha=sha}, objectmeta)
   repos[ret] = repo
   if ll.git2 then
      blobs[ret] = ll.git2.get_object(repo.git2.repo, sha)
   end
   return ret
end

---
-- Create a new raw object.
--
-- Create a new raw object and insert it into the given repository.  This will
-- not only create the @{object} instance but also insert it into the
-- repository storage.
--
-- @function create
-- @tparam repository repo The repository within which the object resides.
-- @tparam string type The type of the object (e.g. blob or commit)
-- @tparam string content The content to insert as the object's content.
-- @treturn[1] object The object instance encapsulating the given object.
-- @treturn[2] nil Nil on error
-- @treturn[2] string The error message

local function _create(repo, type, content)
   local why, sha = 
      repo:_run_with_input(content, ll.chomp, 
			   "hash-object", "-t", type, "-w", "--stdin")
   if why ~= 0 then
      return nil, "hash-object returned " .. tostring(why)
   end

   return _new(repo, sha)
end

return {
   new = _new,
   create = _create,
}