// Package otbuiltin contains all of the basic commands for creating and // interacting with an ostree repository package otbuiltin import ( "errors" "fmt" "runtime" "unsafe" glib "github.com/sjoerdsimons/ostree-go/pkg/glibobject" ) // #cgo pkg-config: ostree-1 // #include // #include // #include // #include "builtin.go.h" import "C" type Repo struct { *glib.Object } func cCancellable(c *glib.GCancellable) *C.GCancellable { return (*C.GCancellable)(unsafe.Pointer(c.Native())) } // Converts an ostree repo struct to its C equivalent func (r *Repo) native() *C.OstreeRepo { if r == nil || r.GObject == nil { return nil } return (*C.OstreeRepo)(unsafe.Pointer(r.GObject)) } // Takes a C ostree repo and converts it to a Go struct func wrapRepo(p *C.OstreeRepo) *Repo { g := glib.ToGObject(unsafe.Pointer(p)) obj := &glib.Object{g} repo := &Repo{obj} runtime.SetFinalizer(repo, (*Repo).Unref) return repo } // Checks if the repo has been initialized func (r *Repo) isInitialized() bool { if r.GObject != nil { return true } return false } func (repo *Repo) ResolveRev(refspec string, allowNoent bool) (string, error) { var cerr *C.GError = nil var coutrev *C.char = nil crefspec := C.CString(refspec) defer C.free(unsafe.Pointer(crefspec)) r := C.ostree_repo_resolve_rev(repo.native(), crefspec, (C.gboolean)(glib.GBool(allowNoent)), &coutrev, &cerr) if !gobool(r) { return "", generateError(cerr) } outrev := C.GoString(coutrev) C.free(unsafe.Pointer(coutrev)) return outrev, nil } // Attempts to open the repo at the given path func OpenRepo(path string) (*Repo, error) { var cerr *C.GError = nil cpath := C.CString(path) pathc := C.g_file_new_for_path(cpath) defer C.g_object_unref(C.gpointer(pathc)) crepo := C.ostree_repo_new(pathc) repo := wrapRepo(crepo) r := glib.GoBool(glib.GBoolean(C.ostree_repo_open(crepo, nil, &cerr))) if !r { return nil, generateError(cerr) } return repo, nil } type PullOptions struct { OverrideRemoteName string Refs []string } func (repo *Repo) PullWithOptions(remoteName string, options PullOptions, progress *AsyncProgress, cancellable *glib.GCancellable) error { var cerr *C.GError = nil cremoteName := C.CString(remoteName) defer C.free(unsafe.Pointer(cremoteName)) builder := C.g_variant_builder_new(C._g_variant_type(C.CString("a{sv}"))) if options.OverrideRemoteName != "" { cstr := C.CString(options.OverrideRemoteName) v := C.g_variant_new_take_string((*C.gchar)(cstr)) k := C.CString("override-remote-name") defer C.free(unsafe.Pointer(k)) C._g_variant_builder_add_twoargs(builder, C.CString("{sv}"), k, v) } if len(options.Refs) != 0 { crefs := make([]*C.gchar, len(options.Refs)) for i, s := range options.Refs { crefs[i] = (*C.gchar)(C.CString(s)) } v := C.g_variant_new_strv((**C.gchar)(&crefs[0]), (C.gssize)(len(crefs))) for i, s := range crefs { crefs[i] = nil C.free(unsafe.Pointer(s)) } k := C.CString("refs") defer C.free(unsafe.Pointer(k)) C._g_variant_builder_add_twoargs(builder, C.CString("{sv}"), k, v) } coptions := C.g_variant_builder_end(builder) r := C.ostree_repo_pull_with_options(repo.native(), cremoteName, coptions, progress.native(), cCancellable(cancellable), &cerr) if !gobool(r) { return generateError(cerr) } return nil } // Enable support for tombstone commits, which allow the repo to distinguish between // commits that were intentionally deleted and commits that were removed accidentally func enableTombstoneCommits(repo *Repo) error { var tombstoneCommits bool var config *C.GKeyFile = C.ostree_repo_get_config(repo.native()) var cerr *C.GError tombstoneCommits = glib.GoBool(glib.GBoolean(C.g_key_file_get_boolean(config, (*C.gchar)(C.CString("core")), (*C.gchar)(C.CString("tombstone-commits")), nil))) //tombstoneCommits is false only if it really is false or if it is set to FALSE in the config file if !tombstoneCommits { C.g_key_file_set_boolean(config, (*C.gchar)(C.CString("core")), (*C.gchar)(C.CString("tombstone-commits")), C.TRUE) if !glib.GoBool(glib.GBoolean(C.ostree_repo_write_config(repo.native(), config, &cerr))) { return generateError(cerr) } } return nil } func generateError(err *C.GError) error { goErr := glib.ConvertGError(glib.ToGError(unsafe.Pointer(err))) _, file, line, ok := runtime.Caller(1) if ok { return errors.New(fmt.Sprintf("%s:%d - %s", file, line, goErr)) } else { return goErr } } func gobool(b C.gboolean) bool { return b != C.FALSE } type AsyncProgress struct { *glib.Object } func (a *AsyncProgress) native() *C.OstreeAsyncProgress { if a == nil { return nil } return (*C.OstreeAsyncProgress)(unsafe.Pointer(a.Native())) }