Packbuilder: use a callback for ForEach instead of a channel
Channels provide no means to report an error. Closing a channel could mean anything. This is particularly important when dealing with IO, which we do quite often in the pack builder. Use ForEach which returns an error instead.
This commit is contained in:
parent
2594f3f889
commit
7e3c361ac4
|
@ -94,55 +94,51 @@ func (pb *Packbuilder) WriteToFile(name string, mode os.FileMode) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pb *Packbuilder) Write(w io.Writer) error {
|
func (pb *Packbuilder) Write(w io.Writer) error {
|
||||||
ch, stop := pb.ForEach()
|
return pb.ForEach(func(slice []byte) error {
|
||||||
for slice := range ch {
|
|
||||||
_, err := w.Write(slice)
|
_, err := w.Write(slice)
|
||||||
if err != nil {
|
|
||||||
close(stop)
|
|
||||||
return err
|
return err
|
||||||
}
|
})
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pb *Packbuilder) Written() uint32 {
|
func (pb *Packbuilder) Written() uint32 {
|
||||||
return uint32(C.git_packbuilder_written(pb.ptr))
|
return uint32(C.git_packbuilder_written(pb.ptr))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PackbuilderForeachCallback func([]byte) error
|
||||||
type packbuilderCbData struct {
|
type packbuilderCbData struct {
|
||||||
ch chan<- []byte
|
callback PackbuilderForeachCallback
|
||||||
stop <-chan bool
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
//export packbuilderForEachCb
|
//export packbuilderForEachCb
|
||||||
func packbuilderForEachCb(buf unsafe.Pointer, size C.size_t, payload unsafe.Pointer) int {
|
func packbuilderForEachCb(buf unsafe.Pointer, size C.size_t, payload unsafe.Pointer) int {
|
||||||
data := (*packbuilderCbData)(payload)
|
data := (*packbuilderCbData)(payload)
|
||||||
ch := data.ch
|
|
||||||
stop := data.stop
|
|
||||||
|
|
||||||
slice := C.GoBytes(buf, C.int(size))
|
slice := C.GoBytes(buf, C.int(size))
|
||||||
select {
|
|
||||||
case <- stop:
|
err := data.callback(slice)
|
||||||
return -1
|
if err != nil {
|
||||||
case ch <- slice:
|
data.err = err
|
||||||
|
return C.GIT_EUSER
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pb *Packbuilder) forEachWrap(data *packbuilderCbData) {
|
// ForEach repeatedly calls the callback with new packfile data until
|
||||||
C._go_git_packbuilder_foreach(pb.ptr, unsafe.Pointer(data))
|
// there is no more data or the callback returns an error
|
||||||
close(data.ch)
|
func (pb *Packbuilder) ForEach(callback PackbuilderForeachCallback) error {
|
||||||
|
data := packbuilderCbData{
|
||||||
|
callback: callback,
|
||||||
|
err: nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Foreach sends the packfile as slices through the "data" channel. If
|
err := C._go_git_packbuilder_foreach(pb.ptr, unsafe.Pointer(&data))
|
||||||
// you want to stop the pack-building process (e.g. there's an error
|
if err == C.GIT_EUSER {
|
||||||
// writing to the output), close or write a value into the "stop"
|
return data.err
|
||||||
// channel.
|
}
|
||||||
func (pb *Packbuilder) ForEach() (<-chan []byte, chan<- bool) {
|
if err < 0 {
|
||||||
ch := make(chan []byte)
|
return MakeGitError(err)
|
||||||
stop := make(chan bool)
|
}
|
||||||
data := packbuilderCbData{ch, stop}
|
|
||||||
go pb.forEachWrap(&data)
|
return nil
|
||||||
return ch, stop
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue