Skip to content
This repository was archived by the owner on Oct 17, 2021. It is now read-only.

Commit dc6d4d2

Browse files
committed
Refactor repository lookup
Add dwim subscript accessor to repository
1 parent 8bd943c commit dc6d4d2

File tree

10 files changed

+75
-26
lines changed

10 files changed

+75
-26
lines changed

Sources/Git/Object.swift

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@ public class Object {
2525

2626
required init(_ pointer: OpaquePointer) {
2727
self.pointer = pointer
28-
assert(Swift.type(of: self) == Object.self ||
29-
git_object_type(pointer) == Swift.type(of: self).type)
28+
assert(Swift.type(of: self) == Object.self || git_object_type(pointer) == Swift.type(of: self).type)
3029
}
3130

3231
deinit {
@@ -35,6 +34,15 @@ public class Object {
3534
}
3635
}
3736

37+
class func type(of object: Object) -> Object.Type? {
38+
return Object.type(of: object.pointer)
39+
}
40+
41+
class func type(of pointer: OpaquePointer?) -> Object.Type? {
42+
guard let pointer = pointer else { return nil }
43+
return Object.type(of: git_object_type(pointer))
44+
}
45+
3846
class func type(of value: git_object_t?) -> Object.Type? {
3947
switch value {
4048
case GIT_OBJECT_ANY?:

Sources/Git/Objects/Commit.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,15 @@ public final class Commit: Object {
1212
/// The tree containing the commit, if any.
1313
public var tree: Tree? {
1414
let id = Object.ID(rawValue: git_commit_tree_id(pointer).pointee)
15-
return try? owner.lookup(id)
15+
return try? owner.lookup(type: Tree.self, with: id)
1616
}
1717

1818
/// The parents of the commit.
1919
public var parents: [Commit] {
2020
var parents: [Commit] = []
2121
for n in 0..<git_commit_parentcount(pointer) {
2222
let id = Object.ID(rawValue: git_commit_parent_id(pointer, n).pointee)
23-
guard let commit = try? owner.lookup(id) as? Commit else { continue }
23+
guard let commit = try? owner.lookup(type: Commit.self, with: id) else { continue }
2424
parents.append(commit)
2525
}
2626

Sources/Git/Reference.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,21 @@ public class Reference/*: Identifiable */ {
8686
public var owner: Repository {
8787
return Repository(git_reference_owner(pointer))
8888
}
89+
90+
var target: Object? {
91+
let id: Object.ID
92+
switch git_reference_type(pointer) {
93+
case GIT_REFERENCE_SYMBOLIC:
94+
var resolved: OpaquePointer?
95+
guard case .success = result(of: { git_reference_resolve(&resolved, pointer) }) else { return nil }
96+
defer { git_reference_free(resolved) }
97+
id = Object.ID(rawValue: git_reference_target(resolved).pointee)
98+
default:
99+
id = Object.ID(rawValue: git_reference_target(pointer).pointee)
100+
}
101+
102+
return try? owner.lookup(type: Object.self, with: id)
103+
}
89104
}
90105

91106
// MARK: - Equatable

Sources/Git/References/Branch.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public final class Branch: Reference {
1515
id = Object.ID(rawValue: git_reference_target(pointer).pointee)
1616
}
1717

18-
return try? owner.lookup(id)
18+
return try? owner.lookup(type: Commit.self, with: id)
1919
}
2020

2121
/// The short name of the branch.

Sources/Git/References/Note.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ public final class Note: Reference {
1515
}
1616

1717
/// The target of the reference.
18-
public var target: Object? {
19-
try? owner.lookup(Object.ID { oid in
18+
public override var target: Object? {
19+
try? owner.lookup(type: Object.self, with: Object.ID { oid in
2020
git_note_id(pointer)
2121
})
2222
}

Sources/Git/References/Tag.swift

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,11 @@ public final class Tag: Reference {
88
}
99

1010
/// The target of the reference.
11-
public var target: Object? {
11+
public override var target: Object? {
1212
var target: OpaquePointer?
1313
guard case .success = result(of: { git_tag_target(&target, self.pointer) }) else { return nil }
1414
return Object.type(of: git_tag_target_type(self.pointer))?.init(target!)
1515
}
16-
17-
public func peel() throws -> Object? {
18-
var pointer: OpaquePointer?
19-
try attempt { git_tag_peel(&pointer, self.pointer) }
20-
return Object(pointer!)
21-
}
2216
}
2317

2418
// MARK: -
@@ -44,6 +38,12 @@ extension Tag {
4438
public var message: String? {
4539
return String(validatingUTF8: git_tag_message(pointer))
4640
}
41+
42+
public func peel<T: Object>() throws -> T? {
43+
var pointer: OpaquePointer?
44+
try attempt { git_tag_peel(&pointer, self.pointer) }
45+
return T(pointer!)
46+
}
4747
}
4848

4949
// /// The tag's annotation, if any.

Sources/Git/Repository.swift

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public final class Repository {
4545
public static func clone(from remoteURL: URL,
4646
to localURL: URL,
4747
configuration: Clone.Configuration = .default) throws -> Repository {
48-
var pointer: OpaquePointer? = nil
48+
var pointer: OpaquePointer?
4949

5050
var options = configuration.rawValue
5151
let remoteURLString = remoteURL.isFileURL ? remoteURL.path : remoteURL.absoluteString
@@ -58,6 +58,15 @@ public final class Repository {
5858

5959
// MARK: -
6060

61+
public subscript<T: Reference>(_ shorthand: String) -> T? {
62+
var pointer: OpaquePointer?
63+
guard case .success = result(of: { git_reference_dwim(&pointer, self.pointer, shorthand) }),
64+
pointer != nil
65+
else { return nil }
66+
67+
return T(pointer!)
68+
}
69+
6170
/**
6271
The repository's working directory.
6372

@@ -83,7 +92,8 @@ public final class Repository {
8392
public lazy var index: Index? = {
8493
var pointer: OpaquePointer?
8594
guard case .success = result(of: { git_repository_index(&pointer, self.pointer) }),
86-
pointer != nil else { return nil }
95+
pointer != nil
96+
else { return nil }
8797
let index = Index(pointer!)
8898
index.managed = true
8999

@@ -124,14 +134,26 @@ public final class Repository {
124134
- Throws: An error if no object exists for the
125135
- Returns: The corresponding object.
126136
*/
127-
public func lookup<T: Object>(_ id: Object.ID) throws -> T? {
128-
var result: OpaquePointer? = nil
137+
func lookup<T: Object>(type: T.Type, with id: Object.ID) throws -> T? {
138+
var pointer: OpaquePointer?
129139
var oid = id.rawValue
130-
try attempt { git_object_lookup(&result, self.pointer, &oid, T.type) }
140+
try attempt { git_object_lookup(&pointer, self.pointer, &oid, T.type) }
131141
// defer { git_object_free(pointer) }
132-
guard let pointer = result else { return nil }
133142

134-
return T(pointer)
143+
switch type {
144+
case is Blob.Type,
145+
is Commit.Type,
146+
is Tree.Type:
147+
return T(pointer!)
148+
default:
149+
return Object.type(of: pointer)?.init(pointer!) as? T
150+
}
151+
}
152+
153+
func lookup<T: Reference>(type: T.Type, named name: String) throws -> T? {
154+
var pointer: OpaquePointer?
155+
try attempt { git_reference_lookup(&pointer, self.pointer, name) }
156+
return T(pointer!)
135157
}
136158

137159
/**
@@ -170,16 +192,16 @@ public final class Repository {
170192

171193
@discardableResult
172194
public func createCommit(message: String, author: Signature? = nil, committer: Signature? = nil) throws -> Commit {
173-
let tree = try lookup(try Object.ID { oid in
195+
let tree = try lookup(type: Tree.self, with: try Object.ID { oid in
174196
try attempt { git_index_write_tree(oid, index?.pointer) }
175-
}) as Tree?
197+
})
176198

177199
var committer = (try committer ?? author ?? Signature.default(for: self)).rawValue
178200
var author = (try author ?? Signature.default(for: self)).rawValue
179201

180202
var parents = [head?.commit].compactMap { $0?.pointer } as [OpaquePointer?]
181203

182-
return try lookup(try Object.ID { oid in
204+
return try lookup(type: Commit.self, with: try Object.ID { oid in
183205
try attempt { git_commit_create(oid, pointer, "HEAD", &author, &committer, "UTF-8", message, tree?.pointer, parents.count, &parents) }
184206
})!
185207
}

Sources/Git/Repository/Index.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ extension Repository.Index {
174174
/// The blob object for the index entry, if any.
175175
public var blob: Blob? {
176176
let id = Object.ID(rawValue: rawValue.id)
177-
return try? index?.owner.lookup(id)
177+
return try? index?.owner.lookup(type: Blob.self, with: id)
178178
}
179179

180180
public var isConflict: Bool {

Sources/Git/RevisionWalker.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ extension Repository {
9494
defer { pointer.deallocate() }
9595
guard case .success = result(of: { git_revwalk_next(pointer, self.pointer) }) else { return nil }
9696
let id = Object.ID(rawValue: pointer.pointee)
97-
return try? repository.lookup(id)
97+
return try? repository.lookup(type: Commit.self, with: id)
9898
}
9999

100100
// MARK: - RevisionWalker

Tests/GitTests/GitTests.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,10 @@ final class GitTests: XCTestCase {
104104
try repository.createLightweightTag(named: "0.0.1", target: commit)
105105
let names = try repository.tagNames()
106106
XCTAssert(names.contains("0.0.1"))
107+
108+
XCTAssertEqual((repository["0.0.1"]?.target as? Commit)?.message, "Initial commit")
109+
XCTAssertEqual((repository["master"]?.target as? Commit)?.message, "Initial commit")
110+
XCTAssertEqual((repository["HEAD"]?.target as? Commit)?.message, "Initial commit")
107111
}
108112
}
109113

0 commit comments

Comments
 (0)