Merge pull request #351 from giuseppe/add-ostree-dep

vendor.conf: add ostree-go
This commit is contained in:
Miloslav Trmač 2017-06-14 17:18:51 +02:00 committed by GitHub
commit fe67466701
65 changed files with 2098 additions and 20 deletions

View File

@ -6,6 +6,7 @@ RUN dnf -y update && dnf install -y make git golang golang-github-cpuguy83-go-md
device-mapper-devel \
# gpgme bindings deps
libassuan-devel gpgme-devel \
ostree-devel \
gnupg
# Install two versions of the registry. The first is an older version that

View File

@ -31,6 +31,7 @@ github.com/xeipuuv/gojsonschema master
github.com/xeipuuv/gojsonreference master
github.com/xeipuuv/gojsonpointer master
go4.org master https://github.com/camlistore/go4
github.com/ostreedev/ostree-go 61532f383f1f48e5c27080b0b9c8b022c3706a97
# -- end OCI image validation requirements
github.com/mtrmac/gpgme master
# openshift/origin' k8s dependencies as of OpenShift v1.1.5

View File

@ -20,28 +20,50 @@ to another, for example docker container images to OCI images. It also allows
you to copy container images between various registries, possibly converting
them as necessary, and to sign and verify images.
## Command-line usage
The containers/image project is only a library with no user interface;
you can either incorporate it into your Go programs, or use the `skopeo` tool:
The [skopeo](https://github.com/projectatomic/skopeo) tool uses the
containers/image library and takes advantage of its many features.
containers/image library and takes advantage of many of its features,
e.g. `skopeo copy` exposes the `containers/image/copy.Image` functionality.
## Dependencies
Dependencies that this library prefers will not be found in the `vendor`
directory. This is so you can make well-informed decisions about which
libraries you should use with this package in your own projects.
This library does not ship a committed version of its dependencies in a `vendor`
subdirectory. This is so you can make well-informed decisions about which
libraries you should use with this package in your own projects, and because
types defined in the `vendor` directory would be impossible to use from your projects.
What this project tests against dependencies-wise is located
[here](https://github.com/containers/image/blob/master/vendor.conf).
[in vendor.conf](https://github.com/containers/image/blob/master/vendor.conf).
## Building
For ordinary use, `go build ./...` is sufficient.
If you want to see what the library can do, or an example of how it is called,
consider starting with the [skopeo](https://github.com/projectatomic/skopeo) tool
instead.
When developing this library, please use `make` to take advantage of the tests and validation.
To integrate this library into your project, put it into `$GOPATH` or use
your preferred vendoring tool to include a copy in your project.
Ensure that the dependencies documented [in vendor.conf](https://github.com/containers/image/blob/master/vendor.conf)
are also available
(using those exact versions or different versions of your choosing).
Optionally, you can use the `containers_image_openpgp` build tag (using `go build -tags …`, or `make … BUILDTAGS=…`).
This library, by default, also depends on the GpgME C library. Either install it:
```sh
Fedora$ dnf install gpgme-devel libassuan-devel
macOS$ brew install gpgme
```
or use the `containers_image_openpgp` build tag (e.g. using `go build -tags …`)
This will use a Golang-only OpenPGP implementation for signature verification instead of the default cgo/gpgme-based implementation;
the primary downside is that creating new signatures with the Golang-only implementation is not supported.
## Contributing
When developing this library, please use `make` (or `make … BUILDTAGS=…`) to take advantage of the tests and validation.
## License
ASL 2.0

View File

@ -11,12 +11,15 @@ import (
"path/filepath"
"strconv"
"strings"
"time"
"github.com/containers/image/manifest"
"github.com/containers/image/types"
"github.com/containers/storage/pkg/archive"
"github.com/opencontainers/go-digest"
"github.com/pkg/errors"
"github.com/ostreedev/ostree-go/pkg/otbuiltin"
)
type blobToImport struct {
@ -158,7 +161,17 @@ func fixFiles(dir string, usermode bool) error {
return nil
}
func (d *ostreeImageDestination) importBlob(blob *blobToImport) error {
func (d *ostreeImageDestination) ostreeCommit(repo *otbuiltin.Repo, branch string, root string, metadata []string) error {
opts := otbuiltin.NewCommitOptions()
opts.AddMetadataString = metadata
opts.Timestamp = time.Now()
// OCI layers have no parent OSTree commit
opts.Parent = "0000000000000000000000000000000000000000000000000000000000000000"
_, err := repo.Commit(root, branch, opts)
return err
}
func (d *ostreeImageDestination) importBlob(repo *otbuiltin.Repo, blob *blobToImport) error {
ostreeBranch := fmt.Sprintf("ociimage/%s", blob.Digest.Hex())
destinationPath := filepath.Join(d.tmpDirPath, blob.Digest.Hex(), "root")
if err := ensureDirectoryExists(destinationPath); err != nil {
@ -186,11 +199,7 @@ func (d *ostreeImageDestination) importBlob(blob *blobToImport) error {
return err
}
}
return exec.Command("ostree", "commit",
"--repo", d.ref.repo,
fmt.Sprintf("--add-metadata-string=docker.size=%d", blob.Size),
"--branch", ostreeBranch,
fmt.Sprintf("--tree=dir=%s", destinationPath)).Run()
return d.ostreeCommit(repo, ostreeBranch, destinationPath, []string{fmt.Sprintf("docker.size=%d", blob.Size)})
}
func (d *ostreeImageDestination) importConfig(blob *blobToImport) error {
@ -258,6 +267,16 @@ func (d *ostreeImageDestination) PutSignatures(signatures [][]byte) error {
}
func (d *ostreeImageDestination) Commit() error {
repo, err := otbuiltin.OpenRepo(d.ref.repo)
if err != nil {
return err
}
_, err = repo.PrepareTransaction()
if err != nil {
return err
}
for _, layer := range d.schema.LayersDescriptors {
hash := layer.Digest.Hex()
blob := d.blobs[hash]
@ -266,7 +285,7 @@ func (d *ostreeImageDestination) Commit() error {
if blob == nil {
continue
}
err := d.importBlob(blob)
err := d.importBlob(repo, blob)
if err != nil {
return err
}
@ -282,11 +301,11 @@ func (d *ostreeImageDestination) Commit() error {
}
manifestPath := filepath.Join(d.tmpDirPath, "manifest")
err := exec.Command("ostree", "commit",
"--repo", d.ref.repo,
fmt.Sprintf("--add-metadata-string=docker.manifest=%s", string(d.manifest)),
fmt.Sprintf("--branch=ociimage/%s", d.ref.branchName),
manifestPath).Run()
metadata := []string{fmt.Sprintf("docker.manifest=%s", string(d.manifest))}
err = d.ostreeCommit(repo, fmt.Sprintf("ociimage/%s", d.ref.branchName), manifestPath, metadata)
_, err = repo.CommitTransaction()
return err
}

17
vendor/github.com/ostreedev/ostree-go/LICENSE generated vendored Normal file
View File

@ -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.

4
vendor/github.com/ostreedev/ostree-go/README.md generated vendored Normal file
View File

@ -0,0 +1,4 @@
OSTree-Go
=========
Go bindings for OSTree. Find out more about OSTree [here](https://github.com/ostreedev/ostree)

View File

@ -0,0 +1,60 @@
/*
* 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 glibobject
import (
"unsafe"
)
// #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"
/*
* GBoolean
*/
// GBoolean is a Go representation of glib's gboolean
type GBoolean C.gboolean
func NewGBoolean() GBoolean {
return GBoolean(0)
}
func GBool(b bool) GBoolean {
if b {
return GBoolean(1)
}
return GBoolean(0)
}
func (b GBoolean) Ptr() unsafe.Pointer {
return unsafe.Pointer(&b)
}
func GoBool(b GBoolean) bool {
if b != 0 {
return true
}
return false
}

View File

@ -0,0 +1,47 @@
/*
* 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 glibobject
// #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"
)
// GIO types
type GCancellable struct {
*GObject
}
func (self *GCancellable) native() *C.GCancellable {
return (*C.GCancellable)(unsafe.Pointer(self))
}
func (self *GCancellable) Ptr() unsafe.Pointer {
return unsafe.Pointer(self)
}
// At the moment, no cancellable API, just pass nil

View File

@ -0,0 +1,71 @@
/*
* 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 glibobject
// #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 (
"errors"
"unsafe"
)
/*
* GError
*/
// GError is a representation of GLib's GError
type GError struct {
ptr unsafe.Pointer
}
func NewGError() GError {
return GError{nil}
}
func (e GError) Ptr() unsafe.Pointer {
if e.ptr == nil {
return nil
}
return e.ptr
}
func (e GError) Nil() {
e.ptr = nil
}
func (e *GError) native() *C.GError {
if e == nil || e.ptr == nil {
return nil
}
return (*C.GError)(e.ptr)
}
func ToGError(ptr unsafe.Pointer) GError {
return GError{ptr}
}
func ConvertGError(e GError) error {
defer C.g_error_free(e.native())
return errors.New(C.GoString((*C.char)(C._g_error_get_message(e.native()))))
}

View File

@ -0,0 +1,52 @@
/*
* 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 glibobject
// #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"
)
/*
* GFile
*/
type GFile struct {
ptr unsafe.Pointer
}
func (f GFile) Ptr() unsafe.Pointer {
return f.ptr
}
func NewGFile() *GFile {
return &GFile{nil}
}
func ToGFile(ptr unsafe.Pointer) *GFile {
gf := NewGFile()
gf.ptr = ptr
return gf
}

View File

@ -0,0 +1,53 @@
/*
* 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 glibobject
// #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"
)
/*
* GFileInfo
*/
type GFileInfo struct {
ptr unsafe.Pointer
}
func (fi GFileInfo) Ptr() unsafe.Pointer {
return fi.ptr
}
func NewGFileInfo() GFileInfo {
var fi GFileInfo = GFileInfo{nil}
return fi
}
func ToGFileInfo(p unsafe.Pointer) *GFileInfo {
var fi *GFileInfo = &GFileInfo{}
fi.ptr = p
return fi
}

View File

@ -0,0 +1,50 @@
/*
* 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 glibobject
import (
"unsafe"
)
// #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"
/*
* GHashTable
*/
type GHashTable struct {
ptr unsafe.Pointer
}
func (ht *GHashTable) Ptr() unsafe.Pointer {
return ht.ptr
}
func (ht *GHashTable) native() *C.GHashTable {
return (*C.GHashTable)(ht.ptr)
}
func ToGHashTable(ptr unsafe.Pointer) *GHashTable {
return &GHashTable{ptr}
}

View File

@ -0,0 +1,50 @@
/*
* 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 glibobject
import (
"unsafe"
)
// #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"
/*
* GHashTableIter
*/
type GHashTableIter struct {
ptr unsafe.Pointer
}
func (ht *GHashTableIter) Ptr() unsafe.Pointer {
return ht.ptr
}
func (ht *GHashTableIter) native() *C.GHashTableIter {
return (*C.GHashTableIter)(ht.ptr)
}
func ToGHashTableIter(ptr unsafe.Pointer) *GHashTableIter {
return &GHashTableIter{ptr}
}

View File

@ -0,0 +1,27 @@
/*
* 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 glibobject
// #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"

View File

@ -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;
}

View File

@ -0,0 +1,79 @@
/*
* 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 glibobject
// #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"
)
/*
* 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
}
// GObject is a representation of GLib's GObject.
type GObject struct {
ptr unsafe.Pointer
}
func (v *GObject) Ptr() unsafe.Pointer {
return v.ptr
}
func (v *GObject) native() *C.GObject {
if v == nil {
return nil
}
return (*C.GObject)(v.ptr)
}
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(v.native())
}
func (v *GObject) IsFloating() bool {
c := C.g_object_is_floating(v.native())
return GoBool(GBoolean(c))
}
func (v *GObject) ForceFloating() {
C.g_object_force_floating(v.native())
}

View File

@ -0,0 +1,51 @@
/*
* 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 glibobject
import (
"unsafe"
)
// #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"
/*
* GOptionContext
*/
type GOptionContext struct {
ptr unsafe.Pointer
}
func (oc *GOptionContext) Ptr() unsafe.Pointer {
return oc.ptr
}
func (oc *GOptionContext) native() *C.GOptionContext {
return (*C.GOptionContext)(oc.ptr)
}
func ToGOptionContext(ptr unsafe.Pointer) GOptionContext {
return GOptionContext{ptr}
}

View File

@ -0,0 +1,97 @@
/*
* 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 glibobject
// #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 (
"fmt"
"unsafe"
)
/*
* GVariant
*/
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) Ptr() unsafe.Pointer {
return 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 (*GVariant)(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
}
func ToGVariant(ptr unsafe.Pointer) *GVariant {
return &GVariant{ptr}
}

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

@ -0,0 +1,93 @@
// 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/ostreedev/ostree-go/pkg/glibobject"
)
// #cgo pkg-config: ostree-1
// #include <stdlib.h>
// #include <glib.h>
// #include <ostree.h>
// #include "builtin.go.h"
import "C"
type Repo struct {
//*glib.GObject
ptr unsafe.Pointer
}
// Converts an ostree repo struct to its C equivalent
func (r *Repo) native() *C.OstreeRepo {
//return (*C.OstreeRepo)(r.Ptr())
return (*C.OstreeRepo)(r.ptr)
}
// Takes a C ostree repo and converts it to a Go struct
func repoFromNative(p *C.OstreeRepo) *Repo {
if p == nil {
return nil
}
//o := (*glib.GObject)(unsafe.Pointer(p))
//r := &Repo{o}
r := &Repo{unsafe.Pointer(p)}
return r
}
// Checks if the repo has been initialized
func (r *Repo) isInitialized() bool {
if r.ptr != nil {
return true
}
return false
}
// 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 := repoFromNative(crepo)
r := glib.GoBool(glib.GBoolean(C.ostree_repo_open(crepo, nil, &cerr)))
if !r {
return nil, generateError(cerr)
}
return repo, 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
}
}

View File

@ -0,0 +1,191 @@
#ifndef BUILTIN_GO_H
#define BUILTIN_GO_H
#include <glib.h>
#include <ostree.h>
#include <string.h>
#include <fcntl.h>
static guint32 owner_uid;
static guint32 owner_gid;
static void
_ostree_repo_append_modifier_flags(OstreeRepoCommitModifierFlags *flags, int flag) {
*flags |= flag;
}
struct CommitFilterData {
GHashTable *mode_adds;
GHashTable *skip_list;
};
typedef struct CommitFilterData CommitFilterData;
static char* _gptr_to_str(gpointer p)
{
return (char*)p;
}
// The following 3 functions are wrapper functions for macros since CGO can't parse macros
static OstreeRepoFile*
_ostree_repo_file(GFile *file)
{
return OSTREE_REPO_FILE (file);
}
static guint
_gpointer_to_uint (gpointer ptr)
{
return GPOINTER_TO_UINT (ptr);
}
static gpointer
_guint_to_pointer (guint u)
{
return GUINT_TO_POINTER (u);
}
static void
_g_clear_object (volatile GObject **object_ptr)
{
g_clear_object(object_ptr);
}
static const GVariantType*
_g_variant_type (char *type)
{
return G_VARIANT_TYPE (type);
}
static int
_at_fdcwd ()
{
return AT_FDCWD;
}
static guint64
_guint64_from_be (guint64 val)
{
return GUINT64_FROM_BE (val);
}
// These functions are wrappers for variadic functions since CGO can't parse variadic functions
static void
_g_printerr_onearg (char* msg,
char* arg)
{
g_printerr("%s %s\n", msg, arg);
}
static void
_g_set_error_onearg (GError *err,
char* msg,
char* arg)
{
g_set_error(&err, G_IO_ERROR, G_IO_ERROR_FAILED, "%s %s", msg, arg);
}
static void
_g_variant_builder_add_twoargs (GVariantBuilder* builder,
const char *format_string,
char *arg1,
GVariant *arg2)
{
g_variant_builder_add(builder, format_string, arg1, arg2);
}
static GHashTable*
_g_hash_table_new_full ()
{
return g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
}
static void
_g_variant_get_commit_dump (GVariant *variant,
const char *format,
char **subject,
char **body,
guint64 *timestamp)
{
return g_variant_get (variant, format, NULL, NULL, NULL, subject, body, timestamp, NULL, NULL);
}
static guint32
_binary_or (guint32 a, guint32 b)
{
return a | b;
}
static void
_cleanup (OstreeRepo *self,
OstreeRepoCommitModifier *modifier,
GCancellable *cancellable,
GError **out_error)
{
if (self)
ostree_repo_abort_transaction(self, cancellable, out_error);
if (modifier)
ostree_repo_commit_modifier_unref (modifier);
}
// The following functions make up a commit_filter function that gets passed into
// another C function (and thus can't be a go function) as well as its helpers
static OstreeRepoCommitFilterResult
_commit_filter (OstreeRepo *self,
const char *path,
GFileInfo *file_info,
gpointer user_data)
{
struct CommitFilterData *data = user_data;
GHashTable *mode_adds = data->mode_adds;
GHashTable *skip_list = data->skip_list;
gpointer value;
if (owner_uid >= 0)
g_file_info_set_attribute_uint32 (file_info, "unix::uid", owner_uid);
if (owner_gid >= 0)
g_file_info_set_attribute_uint32 (file_info, "unix::gid", owner_gid);
if (mode_adds && g_hash_table_lookup_extended (mode_adds, path, NULL, &value))
{
guint current_mode = g_file_info_get_attribute_uint32 (file_info, "unix::mode");
guint mode_add = GPOINTER_TO_UINT (value);
g_file_info_set_attribute_uint32 (file_info, "unix::mode",
current_mode | mode_add);
g_hash_table_remove (mode_adds, path);
}
if (skip_list && g_hash_table_contains (skip_list, path))
{
g_hash_table_remove (skip_list, path);
return OSTREE_REPO_COMMIT_FILTER_SKIP;
}
return OSTREE_REPO_COMMIT_FILTER_ALLOW;
}
static void
_set_owner_uid (guint32 uid)
{
owner_uid = uid;
}
static void _set_owner_gid (guint32 gid)
{
owner_gid = gid;
}
// Wrapper function for a function that takes a C function as a parameter.
// That translation doesn't work in go
static OstreeRepoCommitModifier*
_ostree_repo_commit_modifier_new_wrapper (OstreeRepoCommitModifierFlags flags,
gpointer user_data,
GDestroyNotify destroy_notify)
{
return ostree_repo_commit_modifier_new(flags, _commit_filter, user_data, destroy_notify);
}
#endif

View File

@ -0,0 +1 @@
package otbuiltin

View File

@ -0,0 +1,102 @@
package otbuiltin
import (
"strings"
"unsafe"
glib "github.com/ostreedev/ostree-go/pkg/glibobject"
)
// #cgo pkg-config: ostree-1
// #include <stdlib.h>
// #include <glib.h>
// #include <ostree.h>
// #include "builtin.go.h"
import "C"
// Global variable for options
var checkoutOpts checkoutOptions
// Contains all of the options for checking commits out of
// an ostree repo
type checkoutOptions struct {
UserMode bool // Do not change file ownership or initialize extended attributes
Union bool // Keep existing directories and unchanged files, overwriting existing filesystem
AllowNoent bool // Do nothing if the specified filepath does not exist
DisableCache bool // Do not update or use the internal repository uncompressed object caceh
Whiteouts bool // Process 'whiteout' (docker style) entries
RequireHardlinks bool // Do not fall back to full copies if hard linking fails
Subpath string // Checkout sub-directory path
FromFile string // Process many checkouts from the given file
}
// Instantiates and returns a checkoutOptions struct with default values set
func NewCheckoutOptions() checkoutOptions {
return checkoutOptions{}
}
// Checks out a commit with the given ref from a repository at the location of repo path to to the destination. Returns an error if the checkout could not be processed
func Checkout(repoPath, destination, commit string, opts checkoutOptions) error {
checkoutOpts = opts
var cancellable *glib.GCancellable
ccommit := C.CString(commit)
defer C.free(unsafe.Pointer(ccommit))
var gerr = glib.NewGError()
cerr := (*C.GError)(gerr.Ptr())
defer C.free(unsafe.Pointer(cerr))
repoPathc := C.g_file_new_for_path(C.CString(repoPath))
defer C.g_object_unref(C.gpointer(repoPathc))
crepo := C.ostree_repo_new(repoPathc)
if !glib.GoBool(glib.GBoolean(C.ostree_repo_open(crepo, (*C.GCancellable)(cancellable.Ptr()), &cerr))) {
return generateError(cerr)
}
if strings.Compare(checkoutOpts.FromFile, "") != 0 {
err := processManyCheckouts(crepo, destination, cancellable)
if err != nil {
return err
}
} else {
var resolvedCommit *C.char
defer C.free(unsafe.Pointer(resolvedCommit))
if !glib.GoBool(glib.GBoolean(C.ostree_repo_resolve_rev(crepo, ccommit, C.FALSE, &resolvedCommit, &cerr))) {
return generateError(cerr)
}
err := processOneCheckout(crepo, resolvedCommit, checkoutOpts.Subpath, destination, cancellable)
if err != nil {
return err
}
}
return nil
}
// Processes one checkout from the repo
func processOneCheckout(crepo *C.OstreeRepo, resolvedCommit *C.char, subpath, destination string, cancellable *glib.GCancellable) error {
cdest := C.CString(destination)
defer C.free(unsafe.Pointer(cdest))
var gerr = glib.NewGError()
cerr := (*C.GError)(gerr.Ptr())
defer C.free(unsafe.Pointer(cerr))
var repoCheckoutAtOptions C.OstreeRepoCheckoutAtOptions
if checkoutOpts.UserMode {
repoCheckoutAtOptions.mode = C.OSTREE_REPO_CHECKOUT_MODE_USER
}
if checkoutOpts.Union {
repoCheckoutAtOptions.overwrite_mode = C.OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES
}
checkedOut := glib.GoBool(glib.GBoolean(C.ostree_repo_checkout_at(crepo, &repoCheckoutAtOptions, C._at_fdcwd(), cdest, resolvedCommit, nil, &cerr)))
if !checkedOut {
return generateError(cerr)
}
return nil
}
// process many checkouts
func processManyCheckouts(crepo *C.OstreeRepo, target string, cancellable *glib.GCancellable) error {
return nil
}

View File

@ -0,0 +1 @@
package otbuiltin

View File

@ -0,0 +1,482 @@
package otbuiltin
import (
"bytes"
"errors"
"fmt"
"strings"
"time"
"unsafe"
glib "github.com/ostreedev/ostree-go/pkg/glibobject"
)
// #cgo pkg-config: ostree-1
// #include <stdlib.h>
// #include <glib.h>
// #include <ostree.h>
// #include "builtin.go.h"
import "C"
// Declare global variable to store commitOptions
var options commitOptions
// Declare a function prototype for being passed into another function
type handleLineFunc func(string, *glib.GHashTable) error
// Contains all of the options for commmiting to an ostree repo. Initialize
// with NewCommitOptions()
type commitOptions struct {
Subject string // One line subject
Body string // Full description
Parent string // Parent of the commit
Tree []string // 'dir=PATH' or 'tar=TARFILE' or 'ref=COMMIT': overlay the given argument as a tree
AddMetadataString []string // Add a key/value pair to metadata
AddDetachedMetadataString []string // Add a key/value pair to detached metadata
OwnerUID int // Set file ownership to user id
OwnerGID int // Set file ownership to group id
NoXattrs bool // Do not import extended attributes
LinkCheckoutSpeedup bool // Optimize for commits of trees composed of hardlinks in the repository
TarAutoCreateParents bool // When loading tar archives, automatically create parent directories as needed
SkipIfUnchanged bool // If the contents are unchanged from a previous commit, do nothing
StatOverrideFile string // File containing list of modifications to make permissions
SkipListFile string // File containing list of file paths to skip
GenerateSizes bool // Generate size information along with commit metadata
GpgSign []string // GPG Key ID with which to sign the commit (if you have GPGME - GNU Privacy Guard Made Easy)
GpgHomedir string // GPG home directory to use when looking for keyrings (if you have GPGME - GNU Privacy Guard Made Easy)
Timestamp time.Time // Override the timestamp of the commit
Orphan bool // Commit does not belong to a branch
Fsync bool // Specify whether fsync should be used or not. Default to true
}
// Initializes a commitOptions struct and sets default values
func NewCommitOptions() commitOptions {
var co commitOptions
co.OwnerUID = -1
co.OwnerGID = -1
co.Fsync = true
return co
}
type OstreeRepoTransactionStats struct {
metadata_objects_total int32
metadata_objects_written int32
content_objects_total int32
content_objects_written int32
content_bytes_written uint64
}
func (repo *Repo) PrepareTransaction() (bool, error) {
var cerr *C.GError = nil
var resume C.gboolean
r := glib.GoBool(glib.GBoolean(C.ostree_repo_prepare_transaction(repo.native(), &resume, nil, &cerr)))
if !r {
return false, generateError(cerr)
}
return glib.GoBool(glib.GBoolean(resume)), nil
}
func (repo *Repo) CommitTransaction() (*OstreeRepoTransactionStats, error) {
var cerr *C.GError = nil
var stats OstreeRepoTransactionStats = OstreeRepoTransactionStats{}
statsPtr := (*C.OstreeRepoTransactionStats)(unsafe.Pointer(&stats))
r := glib.GoBool(glib.GBoolean(C.ostree_repo_commit_transaction(repo.native(), statsPtr, nil, &cerr)))
if !r {
return nil, generateError(cerr)
}
return &stats, nil
}
func (repo *Repo) TransactionSetRef(remote string, ref string, checksum string) {
var cRemote *C.char = nil
var cRef *C.char = nil
var cChecksum *C.char = nil
if remote != "" {
cRemote = C.CString(remote)
}
if ref != "" {
cRef = C.CString(ref)
}
if checksum != "" {
cChecksum = C.CString(checksum)
}
C.ostree_repo_transaction_set_ref(repo.native(), cRemote, cRef, cChecksum)
}
func (repo *Repo) AbortTransaction() error {
var cerr *C.GError = nil
r := glib.GoBool(glib.GBoolean(C.ostree_repo_abort_transaction(repo.native(), nil, &cerr)))
if !r {
return generateError(cerr)
}
return nil
}
func (repo *Repo) RegenerateSummary() error {
var cerr *C.GError = nil
r := glib.GoBool(glib.GBoolean(C.ostree_repo_regenerate_summary(repo.native(), nil, nil, &cerr)))
if !r {
return generateError(cerr)
}
return nil
}
// Commits a directory, specified by commitPath, to an ostree repo as a given branch
func (repo *Repo) Commit(commitPath, branch string, opts commitOptions) (string, error) {
options = opts
var err error
var modeAdds *glib.GHashTable
var skipList *glib.GHashTable
var objectToCommit *glib.GFile
var skipCommit bool = false
var ccommitChecksum *C.char
defer C.free(unsafe.Pointer(ccommitChecksum))
var flags C.OstreeRepoCommitModifierFlags = 0
var filter_data C.CommitFilterData
var cerr *C.GError
defer C.free(unsafe.Pointer(cerr))
var metadata *C.GVariant = nil
defer func(){
if metadata != nil {
defer C.g_variant_unref(metadata)
}
}()
var detachedMetadata *C.GVariant = nil
defer C.free(unsafe.Pointer(detachedMetadata))
var mtree *C.OstreeMutableTree
defer C.free(unsafe.Pointer(mtree))
var root *C.GFile
defer C.free(unsafe.Pointer(root))
var modifier *C.OstreeRepoCommitModifier
defer C.free(unsafe.Pointer(modifier))
var cancellable *C.GCancellable
defer C.free(unsafe.Pointer(cancellable))
cpath := C.CString(commitPath)
defer C.free(unsafe.Pointer(cpath))
csubject := C.CString(options.Subject)
defer C.free(unsafe.Pointer(csubject))
cbody := C.CString(options.Body)
defer C.free(unsafe.Pointer(cbody))
cbranch := C.CString(branch)
defer C.free(unsafe.Pointer(cbranch))
cparent := C.CString(options.Parent)
defer C.free(unsafe.Pointer(cparent))
if !glib.GoBool(glib.GBoolean(C.ostree_repo_is_writable(repo.native(), &cerr))) {
goto out
}
// If the user provided a stat override file
if strings.Compare(options.StatOverrideFile, "") != 0 {
modeAdds = glib.ToGHashTable(unsafe.Pointer(C._g_hash_table_new_full()))
if err = parseFileByLine(options.StatOverrideFile, handleStatOverrideLine, modeAdds, cancellable); err != nil {
goto out
}
}
// If the user provided a skiplist file
if strings.Compare(options.SkipListFile, "") != 0 {
skipList = glib.ToGHashTable(unsafe.Pointer(C._g_hash_table_new_full()))
if err = parseFileByLine(options.SkipListFile, handleSkipListline, skipList, cancellable); err != nil {
goto out
}
}
if options.AddMetadataString != nil {
metadata, err = parseKeyValueStrings(options.AddMetadataString)
if err != nil {
goto out
}
}
if options.AddDetachedMetadataString != nil {
_, err := parseKeyValueStrings(options.AddDetachedMetadataString)
if err != nil {
goto out
}
}
if strings.Compare(branch, "") == 0 && !options.Orphan {
err = errors.New("A branch must be specified or use commitOptions.Orphan")
goto out
}
if options.NoXattrs {
C._ostree_repo_append_modifier_flags(&flags, C.OSTREE_REPO_COMMIT_MODIFIER_FLAGS_SKIP_XATTRS)
}
if options.GenerateSizes {
C._ostree_repo_append_modifier_flags(&flags, C.OSTREE_REPO_COMMIT_MODIFIER_FLAGS_GENERATE_SIZES)
}
if !options.Fsync {
C.ostree_repo_set_disable_fsync(repo.native(), C.TRUE)
}
if flags != 0 || options.OwnerUID >= 0 || options.OwnerGID >= 0 || strings.Compare(options.StatOverrideFile, "") != 0 || options.NoXattrs {
filter_data.mode_adds = (*C.GHashTable)(modeAdds.Ptr())
filter_data.skip_list = (*C.GHashTable)(skipList.Ptr())
C._set_owner_uid((C.guint32)(options.OwnerUID))
C._set_owner_gid((C.guint32)(options.OwnerGID))
modifier = C._ostree_repo_commit_modifier_new_wrapper(flags, &filter_data, nil)
}
if strings.Compare(options.Parent, "") != 0 {
if strings.Compare(options.Parent, "none") == 0 {
options.Parent = ""
}
} else if !options.Orphan {
cerr = nil
if !glib.GoBool(glib.GBoolean(C.ostree_repo_resolve_rev(repo.native(), cbranch, C.TRUE, &cparent, &cerr))) {
goto out
}
}
if options.LinkCheckoutSpeedup && !glib.GoBool(glib.GBoolean(C.ostree_repo_scan_hardlinks(repo.native(), cancellable, &cerr))) {
goto out
}
mtree = C.ostree_mutable_tree_new()
if len(commitPath) == 0 && (len(options.Tree) == 0 || len(options.Tree[0]) == 0) {
currentDir := (*C.char)(C.g_get_current_dir())
objectToCommit = glib.ToGFile(unsafe.Pointer(C.g_file_new_for_path(currentDir)))
C.g_free(currentDir)
if !glib.GoBool(glib.GBoolean(C.ostree_repo_write_directory_to_mtree(repo.native(), (*C.GFile)(objectToCommit.Ptr()), mtree, modifier, cancellable, &cerr))) {
goto out
}
} else if len(options.Tree) != 0 {
var eq int = -1
cerr = nil
for tree := range options.Tree {
eq = strings.Index(options.Tree[tree], "=")
if eq == -1 {
C._g_set_error_onearg(cerr, C.CString("Missing type in tree specification"), C.CString(options.Tree[tree]))
goto out
}
treeType := options.Tree[tree][:eq]
treeVal := options.Tree[tree][eq+1:]
if strings.Compare(treeType, "dir") == 0 {
objectToCommit = glib.ToGFile(unsafe.Pointer(C.g_file_new_for_path(C.CString(treeVal))))
if !glib.GoBool(glib.GBoolean(C.ostree_repo_write_directory_to_mtree(repo.native(), (*C.GFile)(objectToCommit.Ptr()), mtree, modifier, cancellable, &cerr))) {
goto out
}
} else if strings.Compare(treeType, "tar") == 0 {
objectToCommit = glib.ToGFile(unsafe.Pointer(C.g_file_new_for_path(C.CString(treeVal))))
if !glib.GoBool(glib.GBoolean(C.ostree_repo_write_archive_to_mtree(repo.native(), (*C.GFile)(objectToCommit.Ptr()), mtree, modifier, (C.gboolean)(glib.GBool(opts.TarAutoCreateParents)), cancellable, &cerr))) {
fmt.Println("error 1")
goto out
}
} else if strings.Compare(treeType, "ref") == 0 {
if !glib.GoBool(glib.GBoolean(C.ostree_repo_read_commit(repo.native(), C.CString(treeVal), (**C.GFile)(objectToCommit.Ptr()), nil, cancellable, &cerr))) {
goto out
}
if !glib.GoBool(glib.GBoolean(C.ostree_repo_write_directory_to_mtree(repo.native(), (*C.GFile)(objectToCommit.Ptr()), mtree, modifier, cancellable, &cerr))) {
goto out
}
} else {
C._g_set_error_onearg(cerr, C.CString("Missing type in tree specification"), C.CString(treeVal))
goto out
}
}
} else {
objectToCommit = glib.ToGFile(unsafe.Pointer(C.g_file_new_for_path(cpath)))
cerr = nil
if !glib.GoBool(glib.GBoolean(C.ostree_repo_write_directory_to_mtree(repo.native(), (*C.GFile)(objectToCommit.Ptr()), mtree, modifier, cancellable, &cerr))) {
goto out
}
}
if modeAdds != nil && C.g_hash_table_size((*C.GHashTable)(modeAdds.Ptr())) > 0 {
var hashIter *C.GHashTableIter
var key, value C.gpointer
C.g_hash_table_iter_init(hashIter, (*C.GHashTable)(modeAdds.Ptr()))
for glib.GoBool(glib.GBoolean(C.g_hash_table_iter_next(hashIter, &key, &value))) {
C._g_printerr_onearg(C.CString("Unmatched StatOverride path: "), C._gptr_to_str(key))
}
err = errors.New("Unmatched StatOverride paths")
C.free(unsafe.Pointer(hashIter))
C.free(unsafe.Pointer(key))
C.free(unsafe.Pointer(value))
goto out
}
if skipList != nil && C.g_hash_table_size((*C.GHashTable)(skipList.Ptr())) > 0 {
var hashIter *C.GHashTableIter
var key, value C.gpointer
C.g_hash_table_iter_init(hashIter, (*C.GHashTable)(skipList.Ptr()))
for glib.GoBool(glib.GBoolean(C.g_hash_table_iter_next(hashIter, &key, &value))) {
C._g_printerr_onearg(C.CString("Unmatched SkipList path: "), C._gptr_to_str(key))
}
err = errors.New("Unmatched SkipList paths")
C.free(unsafe.Pointer(hashIter))
C.free(unsafe.Pointer(key))
C.free(unsafe.Pointer(value))
goto out
}
cerr = nil
if !glib.GoBool(glib.GBoolean(C.ostree_repo_write_mtree(repo.native(), mtree, &root, cancellable, &cerr))) {
goto out
}
if options.SkipIfUnchanged && strings.Compare(options.Parent, "") != 0 {
var parentRoot *C.GFile
cerr = nil
if !glib.GoBool(glib.GBoolean(C.ostree_repo_read_commit(repo.native(), cparent, &parentRoot, nil, cancellable, &cerr))) {
C.free(unsafe.Pointer(parentRoot))
goto out
}
if glib.GoBool(glib.GBoolean(C.g_file_equal(root, parentRoot))) {
skipCommit = true
}
C.free(unsafe.Pointer(parentRoot))
}
if !skipCommit {
var timestamp C.guint64
if options.Timestamp.IsZero() {
var now *C.GDateTime = C.g_date_time_new_now_utc()
timestamp = (C.guint64)(C.g_date_time_to_unix(now))
C.g_date_time_unref(now)
cerr = nil
ret := C.ostree_repo_write_commit(repo.native(), cparent, csubject, cbody, metadata, C._ostree_repo_file(root), &ccommitChecksum, cancellable, &cerr)
if !glib.GoBool(glib.GBoolean(ret)) {
goto out
}
} else {
timestamp = (C.guint64)(options.Timestamp.Unix())
if !glib.GoBool(glib.GBoolean(C.ostree_repo_write_commit_with_time(repo.native(), cparent, csubject, cbody,
metadata, C._ostree_repo_file(root), timestamp, &ccommitChecksum, cancellable, &cerr))) {
goto out
}
}
if detachedMetadata != nil {
C.ostree_repo_write_commit_detached_metadata(repo.native(), ccommitChecksum, detachedMetadata, cancellable, &cerr)
}
if len(options.GpgSign) != 0 {
for key := range options.GpgSign {
if !glib.GoBool(glib.GBoolean(C.ostree_repo_sign_commit(repo.native(), (*C.gchar)(ccommitChecksum), (*C.gchar)(C.CString(options.GpgSign[key])), (*C.gchar)(C.CString(options.GpgHomedir)), cancellable, &cerr))) {
goto out
}
}
}
if strings.Compare(branch, "") != 0 {
C.ostree_repo_transaction_set_ref(repo.native(), nil, cbranch, ccommitChecksum)
} else if !options.Orphan {
goto out
} else {
// TODO: Looks like I forgot to implement this.
}
} else {
ccommitChecksum = C.CString(options.Parent)
}
return C.GoString(ccommitChecksum), nil
out:
if repo.native() != nil {
C.ostree_repo_abort_transaction(repo.native(), cancellable, nil)
//C.free(unsafe.Pointer(repo.native()))
}
if modifier != nil {
C.ostree_repo_commit_modifier_unref(modifier)
}
if err != nil {
return "", err
}
return "", generateError(cerr)
}
// Parse an array of key value pairs of the format KEY=VALUE and add them to a GVariant
func parseKeyValueStrings(pairs []string) (*C.GVariant, error) {
builder := C.g_variant_builder_new(C._g_variant_type(C.CString("a{sv}")))
defer C.g_variant_builder_unref(builder)
for iter := range pairs {
index := strings.Index(pairs[iter], "=")
if index <= 0 {
var buffer bytes.Buffer
buffer.WriteString("Missing '=' in KEY=VALUE metadata '%s'")
buffer.WriteString(pairs[iter])
return nil, errors.New(buffer.String())
}
key := C.CString(pairs[iter][:index])
value := C.CString(pairs[iter][index+1:])
valueVariant := C.g_variant_new_string((*C.gchar)(value))
C._g_variant_builder_add_twoargs(builder, C.CString("{sv}"), key, valueVariant)
}
metadata := C.g_variant_builder_end(builder)
return C.g_variant_ref_sink(metadata), nil
}
// Parse a file linue by line and handle the line with the handleLineFunc
func parseFileByLine(path string, fn handleLineFunc, table *glib.GHashTable, cancellable *C.GCancellable) error {
var contents *C.char
var file *glib.GFile
var lines []string
var gerr = glib.NewGError()
cerr := (*C.GError)(gerr.Ptr())
file = glib.ToGFile(unsafe.Pointer(C.g_file_new_for_path(C.CString(path))))
if !glib.GoBool(glib.GBoolean(C.g_file_load_contents((*C.GFile)(file.Ptr()), cancellable, &contents, nil, nil, &cerr))) {
return generateError(cerr)
}
lines = strings.Split(C.GoString(contents), "\n")
for line := range lines {
if strings.Compare(lines[line], "") == 0 {
continue
}
if err := fn(lines[line], table); err != nil {
return generateError(cerr)
}
}
return nil
}
// Handle an individual line from a Statoverride file
func handleStatOverrideLine(line string, table *glib.GHashTable) error {
var space int
var modeAdd C.guint
if space = strings.IndexRune(line, ' '); space == -1 {
return errors.New("Malformed StatOverrideFile (no space found)")
}
modeAdd = (C.guint)(C.g_ascii_strtod((*C.gchar)(C.CString(line)), nil))
C.g_hash_table_insert((*C.GHashTable)(table.Ptr()), C.g_strdup((*C.gchar)(C.CString(line[space+1:]))), C._guint_to_pointer(modeAdd))
return nil
}
// Handle an individual line from a Skiplist file
func handleSkipListline(line string, table *glib.GHashTable) error {
C.g_hash_table_add((*C.GHashTable)(table.Ptr()), C.g_strdup((*C.gchar)(C.CString(line))))
return nil
}

View File

@ -0,0 +1 @@
package otbuiltin

View File

@ -0,0 +1 @@
package otbuiltin

View File

@ -0,0 +1 @@
package otbuiltin

View File

@ -0,0 +1 @@
package otbuiltin

View File

@ -0,0 +1 @@
package otbuiltin

View File

@ -0,0 +1,90 @@
package otbuiltin
import (
"errors"
"strings"
"unsafe"
glib "github.com/ostreedev/ostree-go/pkg/glibobject"
)
// #cgo pkg-config: ostree-1
// #include <stdlib.h>
// #include <glib.h>
// #include <ostree.h>
// #include "builtin.go.h"
import "C"
// Declare variables for options
var initOpts initOptions
// Contains all of the options for initializing an ostree repo
type initOptions struct {
Mode string // either bare, archive-z2, or bare-user
repoMode C.OstreeRepoMode
}
// Instantiates and returns an initOptions struct with default values set
func NewInitOptions() initOptions {
io := initOptions{}
io.Mode = "bare"
io.repoMode = C.OSTREE_REPO_MODE_BARE
return io
}
// Initializes a new ostree repository at the given path. Returns true
// if the repo exists at the location, regardless of whether it was initialized
// by the function or if it already existed. Returns an error if the repo could
// not be initialized
func Init(path string, options initOptions) (bool, error) {
initOpts = options
err := parseMode()
if err != nil {
return false, err
}
// Create a repo struct from the path
var cerr *C.GError
defer C.free(unsafe.Pointer(cerr))
cpath := C.CString(path)
defer C.free(unsafe.Pointer(cpath))
pathc := C.g_file_new_for_path(cpath)
defer C.g_object_unref(C.gpointer(pathc))
crepo := C.ostree_repo_new(pathc)
// If the repo exists in the filesystem, return an error but set exists to true
/* var exists C.gboolean = 0
success := glib.GoBool(glib.GBoolean(C.ostree_repo_exists(crepo, &exists, &cerr)))
if exists != 0 {
err = errors.New("repository already exists")
return true, err
} else if !success {
return false, generateError(cerr)
}*/
cerr = nil
created := glib.GoBool(glib.GBoolean(C.ostree_repo_create(crepo, initOpts.repoMode, nil, &cerr)))
if !created {
errString := generateError(cerr).Error()
if strings.Contains(errString, "File exists") {
return true, generateError(cerr)
}
return false, generateError(cerr)
}
return true, nil
}
// Converts the mode string to a C.OSTREE_REPO_MODE enum value
func parseMode() error {
if strings.EqualFold(initOpts.Mode, "bare") {
initOpts.repoMode = C.OSTREE_REPO_MODE_BARE
} else if strings.EqualFold(initOpts.Mode, "bare-user") {
initOpts.repoMode = C.OSTREE_REPO_MODE_BARE_USER
} else if strings.EqualFold(initOpts.Mode, "archive-z2") {
initOpts.repoMode = C.OSTREE_REPO_MODE_ARCHIVE_Z2
} else {
return errors.New("Invalid option for mode")
}
return nil
}

View File

@ -0,0 +1,167 @@
package otbuiltin
import (
"fmt"
"strings"
"time"
"unsafe"
glib "github.com/ostreedev/ostree-go/pkg/glibobject"
)
// #cgo pkg-config: ostree-1
// #include <stdlib.h>
// #include <glib.h>
// #include <ostree.h>
// #include "builtin.go.h"
import "C"
// Declare variables for options
var logOpts logOptions
// Set the format of the strings in the log
const formatString = "2006-01-02 03:04;05 -0700"
// Struct for the various pieces of data in a log entry
type LogEntry struct {
Checksum []byte
Variant []byte
Timestamp time.Time
Subject string
Body string
}
// Convert the log entry to a string
func (l LogEntry) String() string {
if len(l.Variant) == 0 {
return fmt.Sprintf("%s\n%s\n\n\t%s\n\n\t%s\n\n", l.Checksum, l.Timestamp, l.Subject, l.Body)
}
return fmt.Sprintf("%s\n%s\n\n", l.Checksum, l.Variant)
}
type OstreeDumpFlags uint
const (
OSTREE_DUMP_NONE OstreeDumpFlags = 0
OSTREE_DUMP_RAW OstreeDumpFlags = 1 << iota
)
// Contains all of the options for initializing an ostree repo
type logOptions struct {
Raw bool // Show raw variant data
}
//Instantiates and returns a logOptions struct with default values set
func NewLogOptions() logOptions {
return logOptions{}
}
// Show the logs of a branch starting with a given commit or ref. Returns a
// slice of log entries on success and an error otherwise
func Log(repoPath, branch string, options logOptions) ([]LogEntry, error) {
// attempt to open the repository
repo, err := OpenRepo(repoPath)
if err != nil {
return nil, err
}
cbranch := C.CString(branch)
defer C.free(unsafe.Pointer(cbranch))
var checksum *C.char
defer C.free(unsafe.Pointer(checksum))
var flags OstreeDumpFlags = OSTREE_DUMP_NONE
var cerr *C.GError
defer C.free(unsafe.Pointer(cerr))
if logOpts.Raw {
flags |= OSTREE_DUMP_RAW
}
if !glib.GoBool(glib.GBoolean(C.ostree_repo_resolve_rev(repo.native(), cbranch, C.FALSE, &checksum, &cerr))) {
return nil, generateError(cerr)
}
return logCommit(repo, checksum, false, flags)
}
func logCommit(repo *Repo, checksum *C.char, isRecursive bool, flags OstreeDumpFlags) ([]LogEntry, error) {
var variant *C.GVariant
var parent *C.char
defer C.free(unsafe.Pointer(parent))
var gerr = glib.NewGError()
var cerr = (*C.GError)(gerr.Ptr())
defer C.free(unsafe.Pointer(cerr))
entries := make([]LogEntry, 0, 1)
var err error
if !glib.GoBool(glib.GBoolean(C.ostree_repo_load_variant(repo.native(), C.OSTREE_OBJECT_TYPE_COMMIT, checksum, &variant, &cerr))) {
if isRecursive && glib.GoBool(glib.GBoolean(C.g_error_matches(cerr, C.g_io_error_quark(), C.G_IO_ERROR_NOT_FOUND))) {
return nil, nil
}
return entries, generateError(cerr)
}
nextLogEntry := dumpLogObject(C.OSTREE_OBJECT_TYPE_COMMIT, checksum, variant, flags)
// get the parent of this commit
parent = (*C.char)(C.ostree_commit_get_parent(variant))
defer C.free(unsafe.Pointer(parent))
if parent != nil {
entries, err = logCommit(repo, parent, true, flags)
if err != nil {
return nil, err
}
}
entries = append(entries, *nextLogEntry)
return entries, nil
}
func dumpLogObject(objectType C.OstreeObjectType, checksum *C.char, variant *C.GVariant, flags OstreeDumpFlags) *LogEntry {
objLog := new(LogEntry)
objLog.Checksum = []byte(C.GoString(checksum))
if (flags & OSTREE_DUMP_RAW) != 0 {
dumpVariant(objLog, variant)
return objLog
}
switch objectType {
case C.OSTREE_OBJECT_TYPE_COMMIT:
dumpCommit(objLog, variant, flags)
return objLog
default:
return objLog
}
}
func dumpVariant(log *LogEntry, variant *C.GVariant) {
var byteswappedVariant *C.GVariant
if C.G_BYTE_ORDER != C.G_BIG_ENDIAN {
byteswappedVariant = C.g_variant_byteswap(variant)
log.Variant = []byte(C.GoString((*C.char)(C.g_variant_print(byteswappedVariant, C.TRUE))))
} else {
log.Variant = []byte(C.GoString((*C.char)(C.g_variant_print(byteswappedVariant, C.TRUE))))
}
}
func dumpCommit(log *LogEntry, variant *C.GVariant, flags OstreeDumpFlags) {
var subject, body *C.char
defer C.free(unsafe.Pointer(subject))
defer C.free(unsafe.Pointer(body))
var timestamp C.guint64
C._g_variant_get_commit_dump(variant, C.CString("(a{sv}aya(say)&s&stayay)"), &subject, &body, &timestamp)
// Timestamp is now a Unix formatted timestamp as a guint64
timestamp = C._guint64_from_be(timestamp)
log.Timestamp = time.Unix((int64)(timestamp), 0)
if strings.Compare(C.GoString(subject), "") != 0 {
log.Subject = C.GoString(subject)
}
if strings.Compare(C.GoString(body), "") != 0 {
log.Body = C.GoString(body)
}
}

View File

@ -0,0 +1 @@
package otbuiltin

View File

@ -0,0 +1,217 @@
package otbuiltin
import (
"bytes"
"errors"
"strconv"
"strings"
"time"
"unsafe"
glib "github.com/ostreedev/ostree-go/pkg/glibobject"
)
// #cgo pkg-config: ostree-1
// #include <stdlib.h>
// #include <glib.h>
// #include <ostree.h>
// #include "builtin.go.h"
import "C"
// Declare gobal variable for options
var pruneOpts pruneOptions
// Contains all of the options for pruning an ostree repo. Use
// NewPruneOptions() to initialize
type pruneOptions struct {
NoPrune bool // Only display unreachable objects; don't delete
RefsOnly bool // Only compute reachability via refs
DeleteCommit string // Specify a commit to delete
KeepYoungerThan time.Time // All commits older than this date will be pruned
Depth int // Only traverse depths (integer) parents for each commit (default: -1=infinite)
StaticDeltasOnly int // Change the behavior of --keep-younger-than and --delete-commit to prune only the static delta files
}
// Instantiates and returns a pruneOptions struct with default values set
func NewPruneOptions() pruneOptions {
po := new(pruneOptions)
po.Depth = -1
return *po
}
// Search for unreachable objects in the repository given by repoPath. Removes the
// objects unless pruneOptions.NoPrune is specified
func Prune(repoPath string, options pruneOptions) (string, error) {
pruneOpts = options
// attempt to open the repository
repo, err := OpenRepo(repoPath)
if err != nil {
return "", err
}
var pruneFlags C.OstreeRepoPruneFlags
var numObjectsTotal int
var numObjectsPruned int
var objSizeTotal uint64
var gerr = glib.NewGError()
var cerr = (*C.GError)(gerr.Ptr())
defer C.free(unsafe.Pointer(cerr))
var cancellable *glib.GCancellable
if !pruneOpts.NoPrune && !glib.GoBool(glib.GBoolean(C.ostree_repo_is_writable(repo.native(), &cerr))) {
return "", generateError(cerr)
}
cerr = nil
if strings.Compare(pruneOpts.DeleteCommit, "") != 0 {
if pruneOpts.NoPrune {
return "", errors.New("Cannot specify both pruneOptions.DeleteCommit and pruneOptions.NoPrune")
}
if pruneOpts.StaticDeltasOnly > 0 {
if glib.GoBool(glib.GBoolean(C.ostree_repo_prune_static_deltas(repo.native(), C.CString(pruneOpts.DeleteCommit), (*C.GCancellable)(cancellable.Ptr()), &cerr))) {
return "", generateError(cerr)
}
} else if err = deleteCommit(repo, pruneOpts.DeleteCommit, cancellable); err != nil {
return "", err
}
}
if !pruneOpts.KeepYoungerThan.IsZero() {
if pruneOpts.NoPrune {
return "", errors.New("Cannot specify both pruneOptions.KeepYoungerThan and pruneOptions.NoPrune")
}
if err = pruneCommitsKeepYoungerThanDate(repo, pruneOpts.KeepYoungerThan, cancellable); err != nil {
return "", err
}
}
if pruneOpts.RefsOnly {
pruneFlags |= C.OSTREE_REPO_PRUNE_FLAGS_REFS_ONLY
}
if pruneOpts.NoPrune {
pruneFlags |= C.OSTREE_REPO_PRUNE_FLAGS_NO_PRUNE
}
formattedFreedSize := C.GoString((*C.char)(C.g_format_size_full((C.guint64)(objSizeTotal), 0)))
var buffer bytes.Buffer
buffer.WriteString("Total objects: ")
buffer.WriteString(strconv.Itoa(numObjectsTotal))
if numObjectsPruned == 0 {
buffer.WriteString("\nNo unreachable objects")
} else if pruneOpts.NoPrune {
buffer.WriteString("\nWould delete: ")
buffer.WriteString(strconv.Itoa(numObjectsPruned))
buffer.WriteString(" objects, freeing ")
buffer.WriteString(formattedFreedSize)
} else {
buffer.WriteString("\nDeleted ")
buffer.WriteString(strconv.Itoa(numObjectsPruned))
buffer.WriteString(" objects, ")
buffer.WriteString(formattedFreedSize)
buffer.WriteString(" freed")
}
return buffer.String(), nil
}
// Delete an unreachable commit from the repo
func deleteCommit(repo *Repo, commitToDelete string, cancellable *glib.GCancellable) error {
var refs *glib.GHashTable
var hashIter glib.GHashTableIter
var hashkey, hashvalue C.gpointer
var gerr = glib.NewGError()
var cerr = (*C.GError)(gerr.Ptr())
defer C.free(unsafe.Pointer(cerr))
if glib.GoBool(glib.GBoolean(C.ostree_repo_list_refs(repo.native(), nil, (**C.GHashTable)(refs.Ptr()), (*C.GCancellable)(cancellable.Ptr()), &cerr))) {
return generateError(cerr)
}
C.g_hash_table_iter_init((*C.GHashTableIter)(hashIter.Ptr()), (*C.GHashTable)(refs.Ptr()))
for C.g_hash_table_iter_next((*C.GHashTableIter)(hashIter.Ptr()), &hashkey, &hashvalue) != 0 {
var ref string = C.GoString((*C.char)(hashkey))
var commit string = C.GoString((*C.char)(hashvalue))
if strings.Compare(commitToDelete, commit) == 0 {
var buffer bytes.Buffer
buffer.WriteString("Commit ")
buffer.WriteString(commitToDelete)
buffer.WriteString(" is referenced by ")
buffer.WriteString(ref)
return errors.New(buffer.String())
}
}
if err := enableTombstoneCommits(repo); err != nil {
return err
}
if !glib.GoBool(glib.GBoolean(C.ostree_repo_delete_object(repo.native(), C.OSTREE_OBJECT_TYPE_COMMIT, C.CString(commitToDelete), (*C.GCancellable)(cancellable.Ptr()), &cerr))) {
return generateError(cerr)
}
return nil
}
// Prune commits but keep any younger than the given date regardless of whether they
// are reachable
func pruneCommitsKeepYoungerThanDate(repo *Repo, date time.Time, cancellable *glib.GCancellable) error {
var objects *glib.GHashTable
defer C.free(unsafe.Pointer(objects))
var hashIter glib.GHashTableIter
var key, value C.gpointer
defer C.free(unsafe.Pointer(key))
defer C.free(unsafe.Pointer(value))
var gerr = glib.NewGError()
var cerr = (*C.GError)(gerr.Ptr())
defer C.free(unsafe.Pointer(cerr))
if err := enableTombstoneCommits(repo); err != nil {
return err
}
if !glib.GoBool(glib.GBoolean(C.ostree_repo_list_objects(repo.native(), C.OSTREE_REPO_LIST_OBJECTS_ALL, (**C.GHashTable)(objects.Ptr()), (*C.GCancellable)(cancellable.Ptr()), &cerr))) {
return generateError(cerr)
}
C.g_hash_table_iter_init((*C.GHashTableIter)(hashIter.Ptr()), (*C.GHashTable)(objects.Ptr()))
for C.g_hash_table_iter_next((*C.GHashTableIter)(hashIter.Ptr()), &key, &value) != 0 {
var serializedKey *glib.GVariant
defer C.free(unsafe.Pointer(serializedKey))
var checksum *C.char
defer C.free(unsafe.Pointer(checksum))
var objType C.OstreeObjectType
var commitTimestamp uint64
var commit *glib.GVariant = nil
C.ostree_object_name_deserialize((*C.GVariant)(serializedKey.Ptr()), &checksum, &objType)
if objType != C.OSTREE_OBJECT_TYPE_COMMIT {
continue
}
cerr = nil
if !glib.GoBool(glib.GBoolean(C.ostree_repo_load_variant(repo.native(), C.OSTREE_OBJECT_TYPE_COMMIT, checksum, (**C.GVariant)(commit.Ptr()), &cerr))) {
return generateError(cerr)
}
commitTimestamp = (uint64)(C.ostree_commit_get_timestamp((*C.GVariant)(commit.Ptr())))
if commitTimestamp < (uint64)(date.Unix()) {
cerr = nil
if pruneOpts.StaticDeltasOnly != 0 {
if !glib.GoBool(glib.GBoolean(C.ostree_repo_prune_static_deltas(repo.native(), checksum, (*C.GCancellable)(cancellable.Ptr()), &cerr))) {
return generateError(cerr)
}
} else {
if !glib.GoBool(glib.GBoolean(C.ostree_repo_delete_object(repo.native(), C.OSTREE_OBJECT_TYPE_COMMIT, checksum, (*C.GCancellable)(cancellable.Ptr()), &cerr))) {
return generateError(cerr)
}
}
}
}
return nil
}

View File

@ -0,0 +1 @@
package otbuiltin

View File

@ -0,0 +1 @@
package otbuiltin

View File

@ -0,0 +1 @@
package otbuiltin

View File

@ -0,0 +1 @@
package otbuiltin

View File

@ -0,0 +1 @@
package otbuiltin

View File

@ -0,0 +1 @@
package otbuiltin

View File

@ -0,0 +1 @@
package otbuiltin

View File

@ -0,0 +1 @@
package otbuiltin

View File

@ -0,0 +1 @@
package otbuiltin

View File

@ -0,0 +1 @@
package otbuiltin

View File

View File

View File

View File

View File

View File

View File

View File