implement git commit

This commit is contained in:
Yifei Teng 2018-05-01 13:32:59 -05:00
parent 25f3ecc4e6
commit b193c80dc0
2 changed files with 108 additions and 4 deletions

View File

@ -8,6 +8,7 @@
import Foundation
import libgit2
import Result
/// A git object.
public protocol ObjectType {
@ -37,6 +38,14 @@ public struct Signature {
/// The time zone that `time` should be interpreted relative to.
public let timeZone: TimeZone
/// Create an instance with custom name, email, dates, etc.
public init(name: String, email: String, time: Date = Date.init(), timeZone: TimeZone = TimeZone.autoupdatingCurrent) {
self.name = name
self.email = email
self.time = time
self.timeZone = timeZone
}
/// Create an instance with a libgit2 `git_signature`.
public init(_ signature: git_signature) {
name = String(validatingUTF8: signature.name)!
@ -44,6 +53,20 @@ public struct Signature {
time = Date(timeIntervalSince1970: TimeInterval(signature.when.time))
timeZone = TimeZone(secondsFromGMT: 60 * Int(signature.when.offset))!
}
/// Return an unsafe pointer to the `git_signature` struct.
/// Caller is responsible for freeing it with `git_signature_free`.
var unsafeSignature: Result<UnsafeMutablePointer<git_signature>, NSError> {
var signature: UnsafeMutablePointer<git_signature>? = nil
let time = git_time_t(self.time.timeIntervalSince1970) // Unix epoch time
let offset: Int32 = 0
let signatureResult = git_signature_new(&signature, name, email, time, offset)
guard signatureResult == GIT_OK.rawValue, let signatureUnwrap = signature else {
let err = NSError(gitError: signatureResult, pointOfFailure: "git_signature_new")
return .failure(err)
}
return .success(signatureUnwrap)
}
}
extension Signature: Hashable {

View File

@ -601,15 +601,96 @@ final public class Repository {
var paths = git_strarray(strings: &dirPointer, count: 1)
return unsafeIndex().flatMap { index in
defer { git_index_free(index) }
let add_result = git_index_add_all(index, &paths, 0, nil, nil)
guard add_result == GIT_OK.rawValue else {
let err = NSError(gitError: add_result, pointOfFailure: "git_index_add_all")
let addResult = git_index_add_all(index, &paths, 0, nil, nil)
guard addResult == GIT_OK.rawValue else {
let err = NSError(gitError: addResult, pointOfFailure: "git_index_add_all")
return .failure(err)
}
return .success(())
}
}
/// Perform a commit with arbitrary numbers of parent commits.
public func commit(
tree treeOID: git_oid,
parents: [Commit],
message: String,
signature: Signature
) -> Result<Commit, NSError> {
return unsafeIndex().flatMap { index in
defer { git_index_free(index) }
// create commit signature
return signature.unsafeSignature.flatMap { signature in
defer { git_signature_free(signature) }
var tree: OpaquePointer? = nil
var treeOIDCopy = treeOID
let lookupResult = git_tree_lookup(&tree, self.pointer, &treeOIDCopy)
guard lookupResult == GIT_OK.rawValue else {
let err = NSError(gitError: lookupResult, pointOfFailure: "git_tree_lookup")
return .failure(err)
}
defer { git_tree_free(tree) }
var msgBuf = git_buf()
git_message_prettify(&msgBuf, message, 0, /* ascii for # */ 35)
defer { git_buf_free(&msgBuf) }
// use HEAD as parent
var parentC: [OpaquePointer?] = []
for parentCommit in parents {
var parent: OpaquePointer? = nil
var oid = parentCommit.oid.oid
git_commit_lookup(&parent, self.pointer, &oid)
parentC.append(parent!)
}
let parentsContiguous = ContiguousArray(parentC)
return parentsContiguous.withUnsafeBufferPointer { unsafeBuffer in
var commitOID = git_oid()
let parentsPtr = UnsafeMutablePointer(mutating: unsafeBuffer.baseAddress)
let result = git_commit_create(
&commitOID,
self.pointer,
"HEAD",
signature,
signature,
nil,
msgBuf.ptr,
tree,
parents.count,
parentsPtr
)
guard result == GIT_OK.rawValue else {
return .failure(NSError(gitError: result, pointOfFailure: "git_commit_create"))
}
return commit(OID(commitOID))
}
}
}
}
/// Perform a commit of the staged files with the specified message and signature,
/// assuming we are not doing a merge and using the current tip as the parent.
public func commit(message: String, signature: Signature) -> Result<Commit, NSError> {
return unsafeIndex().flatMap { index in
defer { git_index_free(index) }
var treeOID = git_oid()
let treeResult = git_index_write_tree(&treeOID, index)
guard treeResult == GIT_OK.rawValue else {
let err = NSError(gitError: treeResult, pointOfFailure: "git_index_write_tree")
return .failure(err)
}
var parentID = git_oid()
let nameToIDResult = git_reference_name_to_id(&parentID, self.pointer, "HEAD")
guard nameToIDResult == GIT_OK.rawValue else {
return .failure(NSError(gitError: nameToIDResult, pointOfFailure: "git_reference_name_to_id"))
}
return commit(OID(parentID)).flatMap { parentCommit in
commit(tree: treeOID, parents: [parentCommit], message: message, signature: signature)
}
}
}
// MARK: - Diffs
public func diff(for commit: Commit) -> Result<Diff, NSError> {