[ostree] contrib/golang: Initial golang bindings
- From: Colin Walters <walters src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [ostree] contrib/golang: Initial golang bindings
- Date: Thu, 17 Mar 2016 13:02:42 +0000 (UTC)
commit 8057254b0b582f226718558222b1e9e6efe14ad1
Author: Colin Walters <walters verbum org>
Date: Fri Feb 19 15:52:49 2016 -0500
contrib/golang: Initial golang bindings
We were considering using this for Docker integration, but we may end
up going a different architectural path. Anyways, it doesn't hurt to
have the bindings in here - they can do a few things.
I decided to fork some of the core code from
https://github.com/dradtke/gotk3 because...well, what we really need a
GIR-based core generator but I didn't want to start on the fully
correct thing until we knew we wanted it, and this was a quick hack.
Also, let's make a `contrib/` directory for things like this.
contrib/golang/COPYING | 17 ++++
contrib/golang/README.md | 2 +
contrib/golang/glibobject.go | 201 ++++++++++++++++++++++++++++++++++++++++
contrib/golang/glibobject.go.h | 17 ++++
contrib/golang/ostree.go | 94 +++++++++++++++++++
contrib/golang/ostree.go.h | 21 ++++
contrib/golang/ostree_test.go | 55 +++++++++++
7 files changed, 407 insertions(+), 0 deletions(-)
---
diff --git a/contrib/golang/COPYING b/contrib/golang/COPYING
new file mode 100644
index 0000000..aa93b4d
--- /dev/null
+++ b/contrib/golang/COPYING
@@ -0,0 +1,17 @@
+Portions of this code are derived from:
+
+https://github.com/dradtke/gotk3
+
+Copyright (c) 2013 Conformal Systems LLC.
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/contrib/golang/README.md b/contrib/golang/README.md
new file mode 100644
index 0000000..60a4856
--- /dev/null
+++ b/contrib/golang/README.md
@@ -0,0 +1,2 @@
+This file contains demonstration FFI bindings for using `-lostree-1`
+and `-larchive` from golang.
diff --git a/contrib/golang/glibobject.go b/contrib/golang/glibobject.go
new file mode 100644
index 0000000..585ccd7
--- /dev/null
+++ b/contrib/golang/glibobject.go
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2013 Conformal Systems <info conformal com>
+ *
+ * This file originated from: http://opensource.conformal.com/
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+package ostree
+
+// #cgo pkg-config: glib-2.0 gobject-2.0
+// #include <glib.h>
+// #include <glib-object.h>
+// #include <gio/gio.h>
+// #include "glibobject.go.h"
+// #include <stdlib.h>
+import "C"
+import (
+ "unsafe"
+ "runtime"
+ "fmt"
+ "errors"
+)
+
+func GBool(b bool) C.gboolean {
+ if b {
+ return C.gboolean(1)
+ }
+ return C.gboolean(0)
+}
+
+func GoBool(b C.gboolean) bool {
+ if b != 0 {
+ return true
+ }
+ return false
+}
+
+type GError struct {
+ ptr unsafe.Pointer
+}
+
+func NewGError() GError {
+ return GError{nil}
+}
+
+func (e *GError) Native() *C.GError {
+ if e == nil {
+ return nil
+ }
+ return (*C.GError)(e.ptr)
+}
+
+func ConvertGError(e *C.GError) error {
+ defer C.g_error_free(e)
+ return errors.New(C.GoString((*C.char)(C._g_error_get_message(e))))
+}
+
+type GType uint
+
+func (t GType) Name() string {
+ return C.GoString((*C.char)(C.g_type_name(C.GType(t))))
+}
+
+type GVariant struct {
+ ptr unsafe.Pointer
+}
+
+func GVariantNew(p unsafe.Pointer) *GVariant {
+ o := &GVariant{p}
+ runtime.SetFinalizer(o, (*GVariant).Unref)
+ return o;
+}
+
+func GVariantNewSink(p unsafe.Pointer) *GVariant {
+ o := &GVariant{p}
+ runtime.SetFinalizer(o, (*GVariant).Unref)
+ o.RefSink()
+ return o;
+}
+
+func (v *GVariant) native() *C.GVariant {
+ return (*C.GVariant)(v.ptr);
+}
+
+func (v *GVariant) Ref() {
+ C.g_variant_ref(v.native())
+}
+
+func (v *GVariant) Unref() {
+ C.g_variant_unref(v.native())
+}
+
+func (v *GVariant) RefSink() {
+ C.g_variant_ref_sink(v.native())
+}
+
+func (v *GVariant) TypeString() string {
+ cs := (*C.char)(C.g_variant_get_type_string(v.native()))
+ return C.GoString(cs)
+}
+
+func (v *GVariant) GetChildValue(i int) *GVariant {
+ cchild := C.g_variant_get_child_value(v.native(), C.gsize(i))
+ return GVariantNew(unsafe.Pointer(cchild));
+}
+
+func (v *GVariant) LookupString(key string) (string, error) {
+ ckey := C.CString(key)
+ defer C.free(unsafe.Pointer(ckey))
+ // TODO: Find a way to have constant C strings in golang
+ cstr := C._g_variant_lookup_string(v.native(), ckey)
+ if cstr == nil {
+ return "", fmt.Errorf("No such key: %s", key)
+ }
+ return C.GoString(cstr), nil
+}
+
+/*
+ * GObject
+ */
+
+// IObject is an interface type implemented by Object and all types which embed
+// an Object. It is meant to be used as a type for function arguments which
+// require GObjects or any subclasses thereof.
+type IObject interface {
+ toGObject() *C.GObject
+ ToObject() *GObject
+}
+
+// Object is a representation of GLib's GObject.
+type GObject struct {
+ ptr unsafe.Pointer
+}
+
+func GObjectNew(p unsafe.Pointer) *GObject {
+ o := &GObject{p}
+ runtime.SetFinalizer(o, (*GObject).Unref)
+ return o;
+}
+
+func (v *GObject) Ptr() unsafe.Pointer {
+ return v.ptr
+}
+
+func (v *GObject) Native() *C.GObject {
+ if v == nil || v.ptr == nil {
+ return nil
+ }
+ return (*C.GObject)(v.ptr)
+}
+
+func (v *GObject) toGObject() *C.GObject {
+ if v == nil {
+ return nil
+ }
+ return v.Native()
+}
+
+func (v *GObject) Ref() {
+ C.g_object_ref(C.gpointer(v.ptr))
+}
+
+func (v *GObject) Unref() {
+ C.g_object_unref(C.gpointer(v.ptr))
+}
+
+func (v *GObject) RefSink() {
+ C.g_object_ref_sink(C.gpointer(v.ptr))
+}
+
+func (v *GObject) IsFloating() bool {
+ c := C.g_object_is_floating(C.gpointer(v.ptr))
+ return GoBool(c)
+}
+
+func (v *GObject) ForceFloating() {
+ C.g_object_force_floating((*C.GObject)(v.ptr))
+}
+
+// GIO types
+
+type GCancellable struct {
+ *GObject
+}
+
+func (self *GCancellable) native() *C.GCancellable {
+ return (*C.GCancellable)(self.ptr)
+}
+
+// At the moment, no cancellable API, just pass nil
diff --git a/contrib/golang/glibobject.go.h b/contrib/golang/glibobject.go.h
new file mode 100644
index 0000000..a55bd24
--- /dev/null
+++ b/contrib/golang/glibobject.go.h
@@ -0,0 +1,17 @@
+#include <glib.h>
+
+static char *
+_g_error_get_message (GError *error)
+{
+ g_assert (error != NULL);
+ return error->message;
+}
+
+static const char *
+_g_variant_lookup_string (GVariant *v, const char *key)
+{
+ const char *r;
+ if (g_variant_lookup (v, key, "&s", &r))
+ return r;
+ return NULL;
+}
diff --git a/contrib/golang/ostree.go b/contrib/golang/ostree.go
new file mode 100644
index 0000000..0a60ef6
--- /dev/null
+++ b/contrib/golang/ostree.go
@@ -0,0 +1,94 @@
+// +build linux
+
+// Public API specification for libostree Go bindings
+
+package ostree
+
+import (
+ "unsafe"
+)
+
+// #cgo pkg-config: ostree-1
+// #include <stdlib.h>
+// #include <glib.h>
+// #include <ostree.h>
+// #include "ostree.go.h"
+import "C"
+
+type Repo struct {
+ *GObject
+}
+
+func RepoGetType() GType {
+ return GType(C.ostree_repo_get_type())
+}
+
+func (r *Repo) native() *C.OstreeRepo {
+ return (*C.OstreeRepo)(r.ptr)
+}
+
+func repoFromNative(p *C.OstreeRepo) *Repo {
+ if p == nil {
+ return nil
+ }
+ o := GObjectNew(unsafe.Pointer(p))
+ r := &Repo{o}
+ return r
+}
+
+func RepoNewOpen(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 := repoFromNative(crepo);
+ r := GoBool(C.ostree_repo_open(repo.native(), nil, &cerr))
+ if !r {
+ return nil, ConvertGError(cerr)
+ }
+ return repo, nil
+}
+
+func (r *Repo) GetParent() *Repo {
+ return repoFromNative(C.ostree_repo_get_parent(r.native()))
+}
+
+type ObjectType int
+
+const (
+ OBJECT_TYPE_FILE ObjectType = C.OSTREE_OBJECT_TYPE_FILE
+ OBJECT_TYPE_DIR_TREE = C.OSTREE_OBJECT_TYPE_DIR_TREE
+ OBJECT_TYPE_DIR_META = C.OSTREE_OBJECT_TYPE_DIR_META
+ OBJECT_TYPE_COMMIT = C.OSTREE_OBJECT_TYPE_COMMIT
+ OBJECT_TYPE_TOMBSTONE_COMMIT = C.OSTREE_OBJECT_TYPE_TOMBSTONE_COMMIT
+)
+
+func (repo *Repo) LoadVariant(t ObjectType, checksum string) (*GVariant, error) {
+ var cerr *C.GError = nil
+ var cvariant *C.GVariant = nil
+
+ r := GoBool(C.ostree_repo_load_variant(repo.native(), C.OstreeObjectType(t), C.CString(checksum),
&cvariant, &cerr))
+ if !r {
+ return nil, ConvertGError(cerr)
+ }
+ variant := GVariantNew(unsafe.Pointer(cvariant))
+ return variant, nil
+}
+
+func (repo *Repo) ResolveRev(ref string) (string, error) {
+ var cerr *C.GError = nil
+ var crev *C.char = nil
+
+ r := GoBool(C.ostree_repo_resolve_rev(repo.native(), C.CString(ref), GBool(true), &crev, &cerr))
+ if !r {
+ return "", ConvertGError(cerr)
+ }
+ defer C.free(unsafe.Pointer(crev))
+ return C.GoString(crev), nil
+}
+
+func (commit *GVariant) CommitGetMetadataKeyString(key string) (string, error) {
+ cmeta := GVariantNew(unsafe.Pointer(C.g_variant_get_child_value(commit.native(), 0)))
+ return cmeta.LookupString(key)
+}
diff --git a/contrib/golang/ostree.go.h b/contrib/golang/ostree.go.h
new file mode 100644
index 0000000..b1a1551
--- /dev/null
+++ b/contrib/golang/ostree.go.h
@@ -0,0 +1,21 @@
+#include <ostree.h>
+#include <string.h>
+
+static void
+_ostree_repo_checkout_options_init_docker_union (OstreeRepoCheckoutOptions *opts)
+{
+ memset (opts, 0, sizeof (*opts));
+ opts->mode = OSTREE_REPO_CHECKOUT_MODE_USER;
+ opts->overwrite_mode = OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES;
+ opts->disable_fsync = 1;
+ opts->process_whiteouts = 1;
+}
+
+static const char *
+_g_variant_lookup_string (GVariant *v, const char *key)
+{
+ const char *r;
+ if (g_variant_lookup (v, key, "&s", &r))
+ return r;
+ return NULL;
+}
diff --git a/contrib/golang/ostree_test.go b/contrib/golang/ostree_test.go
new file mode 100644
index 0000000..6b687d8
--- /dev/null
+++ b/contrib/golang/ostree_test.go
@@ -0,0 +1,55 @@
+// +build linux
+
+// Public API specification for libostree Go bindings
+
+package ostree
+
+import (
+ "testing"
+)
+
+func TestTypeName(t *testing.T) {
+ name := RepoGetType().Name();
+ if name != "OstreeRepo" {
+ t.Errorf("%s != OstreeRepo");
+ }
+}
+
+func TestRepoNew(t *testing.T) {
+ r, err := RepoNewOpen("/ostree/repo")
+ if err != nil {
+ t.Errorf("%s", err);
+ return
+ }
+ parent := r.GetParent()
+ if parent != nil {
+ t.Errorf("Expected no parent")
+ return
+ }
+}
+
+func TestRepoGetMetadataVersion(t *testing.T) {
+ r, err := RepoNewOpen("/ostree/repo")
+ if err != nil {
+ t.Errorf("%s", err);
+ return
+ }
+ commit,err := r.ResolveRev("rhel-atomic-host/7/x86_64/standard")
+ if err != nil {
+ t.Errorf("%s", err)
+ return
+ }
+ commitv,err := r.LoadVariant(OBJECT_TYPE_COMMIT, commit)
+ if err != nil {
+ t.Errorf("%s", err)
+ return
+ }
+ ver, err := commitv.CommitGetMetadataKeyString("version")
+ if err != nil {
+ t.Errorf("%s", err)
+ return
+ }
+ if ver != "7.1.3" {
+ t.Errorf("expected 7.1.3")
+ }
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]