[ostree] contrib/golang: Initial golang bindings



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]