Skip to content

Commit

Permalink
implement git commit
Browse files Browse the repository at this point in the history
  • Loading branch information
tengyifei committed May 2, 2018
1 parent 25f3ecc commit b193c80
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 4 deletions.
23 changes: 23 additions & 0 deletions SwiftGit2/Objects.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import Foundation
import libgit2
import Result

/// A git object.
public protocol ObjectType {
Expand Down Expand Up @@ -36,6 +37,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) {
Expand All @@ -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 {
Expand Down
89 changes: 85 additions & 4 deletions SwiftGit2/Repository.swift
Original file line number Diff line number Diff line change
Expand Up @@ -593,23 +593,104 @@ final public class Repository {
}
return .success(index!)
}

/// Stage the file(s) under the specified path.
public func add(path: String) -> Result<(), NSError> {
let dir = path
var dirPointer = UnsafeMutablePointer<Int8>(mutating: (dir as NSString).utf8String)
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> {
Expand Down

0 comments on commit b193c80

Please sign in to comment.