diff --git a/Makefile b/Makefile index 41a306ab67..293736b652 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD 2>/dev/null) GIT_BRANCH_CLEAN := $(shell echo $(GIT_BRANCH) | sed -e "s/[^[:alnum:]]/-/g") EPOCH_TEST_COMMIT := 0418ebf59f9e1f564831c0ba9378b7f8e40a1c73 NATIVETAGS := exclude_graphdriver_devicemapper exclude_graphdriver_btrfs exclude_graphdriver_overlay -AUTOTAGS := $(shell ./hack/btrfs_tag.sh) $(shell ./hack/libdm_tag.sh) +AUTOTAGS := $(shell ./hack/btrfs_tag.sh) $(shell ./hack/libdm_tag.sh) $(shell ./hack/ostree_tag.sh) BUILDFLAGS := -tags "$(AUTOTAGS) $(TAGS)" $(FLAGS) GO := go diff --git a/Vagrantfile b/Vagrantfile index 3c4d867d4a..c82c1f81bd 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -1,13 +1,13 @@ # -*- mode: ruby -*- # vi: set ft=ruby : # -# The fedora/25-cloud-base and debian/jessie64 boxes are also available for +# The fedora/28-cloud-base and debian/jessie64 boxes are also available for # the "virtualbox" provider. Set the VAGRANT_PROVIDER environment variable to # "virtualbox" to use them instead. # Vagrant.configure("2") do |config| config.vm.define "fedora" do |c| - c.vm.box = "fedora/25-cloud-base" + c.vm.box = "fedora/28-cloud-base" c.vm.synced_folder ".", "/vagrant", type: "rsync", rsync__exclude: "bundles", rsync__args: ["-vadz", "--delete"] c.vm.provision "shell", inline: <<-SHELL diff --git a/docs/containers-storage.conf.5.md b/docs/containers-storage.conf.5.md index 243228c13a..3b898e731d 100644 --- a/docs/containers-storage.conf.5.md +++ b/docs/containers-storage.conf.5.md @@ -129,6 +129,12 @@ Marks thinpool device for deferred deletion. If the thinpool is in use when the Specifies the maximum number of retries XFS should attempt to complete IO when ENOSPC (no space) error is returned by underlying storage device. (default: 0, which means to try continuously.) +**ostree_repo=""** + Tell storage drivers to use the specified OSTree repository. Some storage drivers, such as overlay, might use + +**skip_mount_home=""** + Tell storage drivers to not create a PRIVATE bind mount on their home directory. + # HISTORY May 2017, Originally compiled by Dan Walsh Format copied from crio.conf man page created by Aleksa Sarai diff --git a/drivers/overlay/overlay.go b/drivers/overlay/overlay.go index 468c4393d7..5d5d61d9c8 100644 --- a/drivers/overlay/overlay.go +++ b/drivers/overlay/overlay.go @@ -24,6 +24,7 @@ import ( "github.com/containers/storage/pkg/idtools" "github.com/containers/storage/pkg/locker" "github.com/containers/storage/pkg/mount" + "github.com/containers/storage/pkg/ostree" "github.com/containers/storage/pkg/parsers" "github.com/containers/storage/pkg/system" units "github.com/docker/go-units" @@ -85,6 +86,8 @@ type overlayOptions struct { imageStores []string quota quota.Quota fuseProgram string + ostreeRepo string + skipMountHome bool } // Driver contains information about the home directory and the list of active mounts that are created using this driver. @@ -99,6 +102,7 @@ type Driver struct { naiveDiff graphdriver.DiffDriver supportsDType bool locker *locker.Locker + convert map[string]bool } var ( @@ -160,8 +164,16 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap } } - if err := mount.MakePrivate(home); err != nil { - return nil, err + if !opts.skipMountHome { + if err := mount.MakePrivate(home); err != nil { + return nil, err + } + } + + if opts.ostreeRepo != "" { + if err := ostree.CreateOSTreeRepository(opts.ostreeRepo, rootUID, rootGID); err != nil { + return nil, err + } } d := &Driver{ @@ -173,6 +185,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap supportsDType: supportsDType, locker: locker.New(), options: *opts, + convert: make(map[string]bool), } d.naiveDiff = graphdriver.NewNaiveDiffDriver(d, d) @@ -240,6 +253,18 @@ func parseOptions(options []string) (*overlayOptions, error) { return nil, fmt.Errorf("overlay: can't stat FUSE program %s: %v", val, err) } o.fuseProgram = val + case "overlay2.ostree_repo", "overlay.ostree_repo", ".ostree_repo": + logrus.Debugf("overlay: ostree_repo=%s", val) + if !ostree.OstreeSupport() { + return nil, fmt.Errorf("overlay: ostree_repo specified but support for ostree is missing") + } + o.ostreeRepo = val + case "overlay2.skip_mount_home", "overlay.skip_mount_home", ".skip_mount_home": + logrus.Debugf("overlay: skip_mount_home=%s", val) + o.skipMountHome, err = strconv.ParseBool(val) + if err != nil { + return nil, err + } default: return nil, fmt.Errorf("overlay: Unknown option %s", key) } @@ -394,6 +419,11 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) (retErr return fmt.Errorf("--storage-opt size is only supported for ReadWrite Layers") } } + + if d.options.ostreeRepo != "" { + d.convert[id] = true + } + return d.create(id, parent, opts) } @@ -561,6 +591,12 @@ func (d *Driver) getLowerDirs(id string) ([]string, error) { func (d *Driver) Remove(id string) error { d.locker.Lock(id) defer d.locker.Unlock(id) + + // Ignore errors, we don't want to fail if the ostree branch doesn't exist, + if d.options.ostreeRepo != "" { + ostree.DeleteOSTree(d.options.ostreeRepo, id) + } + dir := d.dir(id) lid, err := ioutil.ReadFile(path.Join(dir, "link")) if err == nil { @@ -786,6 +822,13 @@ func (d *Driver) ApplyDiff(id string, idMappings *idtools.IDMappings, parent str return 0, err } + _, convert := d.convert[id] + if convert { + if err := ostree.ConvertToOSTree(d.options.ostreeRepo, applyDir, id); err != nil { + return 0, err + } + } + return directory.Size(applyDir) } diff --git a/drivers/vfs/driver.go b/drivers/vfs/driver.go index cee55f8d16..9314cb8760 100644 --- a/drivers/vfs/driver.go +++ b/drivers/vfs/driver.go @@ -9,6 +9,7 @@ import ( "github.com/containers/storage/drivers" "github.com/containers/storage/pkg/chrootarchive" "github.com/containers/storage/pkg/idtools" + "github.com/containers/storage/pkg/ostree" "github.com/containers/storage/pkg/system" "github.com/opencontainers/selinux/go-selinux/label" ) @@ -42,6 +43,27 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap d.homes = append(d.homes, strings.Split(option[12:], ",")...) continue } + if strings.HasPrefix(option, "vfs.ostree_repo=") { + if !ostree.OstreeSupport() { + return nil, fmt.Errorf("vfs: ostree_repo specified but support for ostree is missing") + } + d.ostreeRepo = option[16:] + } + if strings.HasPrefix(option, ".ostree_repo=") { + if !ostree.OstreeSupport() { + return nil, fmt.Errorf("vfs: ostree_repo specified but support for ostree is missing") + } + d.ostreeRepo = option[13:] + } + } + if d.ostreeRepo != "" { + rootUID, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps) + if err != nil { + return nil, err + } + if err := ostree.CreateOSTreeRepository(d.ostreeRepo, rootUID, rootGID); err != nil { + return nil, err + } } return graphdriver.NewNaiveDiffDriver(d, graphdriver.NewNaiveLayerIDMapUpdater(d)), nil } @@ -53,6 +75,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap type Driver struct { homes []string idMappings *idtools.IDMappings + ostreeRepo string } func (d *Driver) String() string { @@ -77,11 +100,15 @@ func (d *Driver) Cleanup() error { // CreateReadWrite creates a layer that is writable for use as a container // file system. func (d *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts) error { - return d.Create(id, parent, opts) + return d.create(id, parent, opts, false) } // Create prepares the filesystem for the VFS driver and copies the directory for the given id under the parent. func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error { + return d.create(id, parent, opts, true) +} + +func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts, ro bool) error { if opts != nil && len(opts.StorageOpt) != 0 { return fmt.Errorf("--storage-opt is not supported for vfs") } @@ -106,14 +133,23 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error { if _, mountLabel, err := label.InitLabels(labelOpts); err == nil { label.SetFileLabel(dir, mountLabel) } - if parent == "" { - return nil + if parent != "" { + parentDir, err := d.Get(parent, "") + if err != nil { + return fmt.Errorf("%s: %s", parent, err) + } + if err := CopyWithTar(parentDir, dir); err != nil { + return err + } } - parentDir, err := d.Get(parent, "") - if err != nil { - return fmt.Errorf("%s: %s", parent, err) + + if ro && d.ostreeRepo != "" { + if err := ostree.ConvertToOSTree(d.ostreeRepo, dir, id); err != nil { + return err + } } - return CopyWithTar(parentDir, dir) + return nil + } func (d *Driver) dir(id string) string { @@ -132,6 +168,10 @@ func (d *Driver) dir(id string) string { // Remove deletes the content from the directory for a given id. func (d *Driver) Remove(id string) error { + if d.ostreeRepo != "" { + // Ignore errors, we don't want to fail if the ostree branch doesn't exist, + ostree.DeleteOSTree(d.ostreeRepo, id) + } return system.EnsureRemoveAll(d.dir(id)) } diff --git a/hack/ostree_tag.sh b/hack/ostree_tag.sh new file mode 100755 index 0000000000..b6de58f5dc --- /dev/null +++ b/hack/ostree_tag.sh @@ -0,0 +1,7 @@ +#!/bin/bash +cc -E - $(pkg-config --cflags ostree-1) > /dev/null 2> /dev/null << EOF +#include +EOF +if test $? -eq 0 ; then + echo ostree +fi diff --git a/hack/spc_ci_test.sh b/hack/spc_ci_test.sh index 28a7845cca..4e12fca349 100755 --- a/hack/spc_ci_test.sh +++ b/hack/spc_ci_test.sh @@ -13,15 +13,15 @@ fi # Additional packages needed ontop of the base (generic) image case "$DISTRO" in *ubuntu*) - export INSTALL_CMD="apt-get -qq install bats btrfs-tools libdevmapper-dev" + export INSTALL_CMD="apt-get -qq install bats btrfs-tools libdevmapper-dev ostree libostree-dev" ;; *fedora*) export INSTALL_CMD="dnf -y install bats btrfs-progs btrfs-progs-devel - e2fsprogs xfsprogs device-mapper-devel" + e2fsprogs xfsprogs device-mapper-devel ostree ostree-devel" ;; *centos*) export INSTALL_CMD="yum install -y bats btrfs-progs btrfs-progs-devel - e2fsprogs xfsprogs device-mapper-devel" + e2fsprogs xfsprogs device-mapper-devel ostree ostree-devel" ;; *) echo "Unknown/unsupported \$DISTRO=$DISTRO" diff --git a/pkg/ostree/no_ostree.go b/pkg/ostree/no_ostree.go new file mode 100644 index 0000000000..0a8e7d6796 --- /dev/null +++ b/pkg/ostree/no_ostree.go @@ -0,0 +1,19 @@ +// +build !ostree + +package ostree + +func OstreeSupport() bool { + return false +} + +func DeleteOSTree(repoLocation, id string) error { + return nil +} + +func CreateOSTreeRepository(repoLocation string, rootUID int, rootGID int) error { + return nil +} + +func ConvertToOSTree(repoLocation, root, id string) error { + return nil +} diff --git a/pkg/ostree/ostree.go b/pkg/ostree/ostree.go new file mode 100644 index 0000000000..e9b57a0fb4 --- /dev/null +++ b/pkg/ostree/ostree.go @@ -0,0 +1,198 @@ +// +build ostree + +package ostree + +import ( + "fmt" + "golang.org/x/sys/unix" + "os" + "path/filepath" + "runtime" + "syscall" + "time" + "unsafe" + + "github.com/containers/storage/pkg/idtools" + "github.com/containers/storage/pkg/system" + glib "github.com/ostreedev/ostree-go/pkg/glibobject" + "github.com/ostreedev/ostree-go/pkg/otbuiltin" + "github.com/pkg/errors" +) + +// #cgo pkg-config: glib-2.0 gobject-2.0 ostree-1 +// #include +// #include +// #include +// #include +// #include +// #include +import "C" + +func OstreeSupport() bool { + return true +} + +func fixFiles(dir string, usermode bool) (bool, []string, error) { + var SkipOstree = errors.New("skip ostree deduplication") + + var whiteouts []string + + err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { + if info.Mode()&(os.ModeNamedPipe|os.ModeSocket|os.ModeDevice) != 0 { + if !usermode { + stat, ok := info.Sys().(*syscall.Stat_t) + if !ok { + return errors.New("not syscall.Stat_t") + } + + if stat.Rdev == 0 && (stat.Mode&unix.S_IFCHR) != 0 { + whiteouts = append(whiteouts, path) + return nil + } + } + // Skip the ostree deduplication if we encounter a file type that + // ostree does not manage. + return SkipOstree + } + if info.IsDir() { + if usermode { + if err := os.Chmod(path, info.Mode()|0700); err != nil { + return err + } + } + } else if usermode && (info.Mode().IsRegular()) { + if err := os.Chmod(path, info.Mode()|0600); err != nil { + return err + } + } + return nil + }) + if err == SkipOstree { + return true, nil, nil + } + if err != nil { + return false, nil, err + } + return false, whiteouts, nil +} + +// Create prepares the filesystem for the OSTREE driver and copies the directory for the given id under the parent. +func ConvertToOSTree(repoLocation, root, id string) error { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + repo, err := otbuiltin.OpenRepo(repoLocation) + if err != nil { + return errors.Wrap(err, "could not open the OSTree repository") + } + + skip, whiteouts, err := fixFiles(root, os.Getuid() != 0) + if err != nil { + return errors.Wrap(err, "could not prepare the OSTree directory") + } + if skip { + return nil + } + + if _, err := repo.PrepareTransaction(); err != nil { + return errors.Wrap(err, "could not prepare the OSTree transaction") + } + + if skip { + return nil + } + + commitOpts := otbuiltin.NewCommitOptions() + commitOpts.Timestamp = time.Now() + commitOpts.LinkCheckoutSpeedup = true + commitOpts.Parent = "0000000000000000000000000000000000000000000000000000000000000000" + branch := fmt.Sprintf("containers-storage/%s", id) + + for _, w := range whiteouts { + if err := os.Remove(w); err != nil { + return errors.Wrap(err, "could not delete whiteout file") + } + } + + if _, err := repo.Commit(root, branch, commitOpts); err != nil { + return errors.Wrap(err, "could not commit the layer") + } + + if _, err := repo.CommitTransaction(); err != nil { + return errors.Wrap(err, "could not complete the OSTree transaction") + } + + if err := system.EnsureRemoveAll(root); err != nil { + return errors.Wrap(err, "could not delete layer") + } + + checkoutOpts := otbuiltin.NewCheckoutOptions() + checkoutOpts.RequireHardlinks = true + checkoutOpts.Whiteouts = false + if err := otbuiltin.Checkout(repoLocation, root, branch, checkoutOpts); err != nil { + return errors.Wrap(err, "could not checkout from OSTree") + } + + for _, w := range whiteouts { + if err := unix.Mknod(w, unix.S_IFCHR, 0); err != nil { + return errors.Wrap(err, "could not recreate whiteout file") + } + } + return nil +} + +func CreateOSTreeRepository(repoLocation string, rootUID int, rootGID int) error { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + _, err := os.Stat(repoLocation) + if err != nil && !os.IsNotExist(err) { + return err + } else if err != nil { + if err := idtools.MkdirAllAs(repoLocation, 0700, rootUID, rootGID); err != nil { + return errors.Wrap(err, "could not create OSTree repository directory: %v") + } + + if _, err := otbuiltin.Init(repoLocation, otbuiltin.NewInitOptions()); err != nil { + return errors.Wrap(err, "could not create OSTree repository") + } + } + return nil +} + +func openRepo(path string) (*C.struct_OstreeRepo, error) { + var cerr *C.GError + 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)) + repo := C.ostree_repo_new(pathc) + r := glib.GoBool(glib.GBoolean(C.ostree_repo_open(repo, nil, &cerr))) + if !r { + C.g_object_unref(C.gpointer(repo)) + return nil, glib.ConvertGError(glib.ToGError(unsafe.Pointer(cerr))) + } + return repo, nil +} + +func DeleteOSTree(repoLocation, id string) error { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + repo, err := openRepo(repoLocation) + if err != nil { + return err + } + defer C.g_object_unref(C.gpointer(repo)) + + branch := fmt.Sprintf("containers-storage/%s", id) + + cbranch := C.CString(branch) + defer C.free(unsafe.Pointer(cbranch)) + + var cerr *C.GError + r := glib.GoBool(glib.GBoolean(C.ostree_repo_set_ref_immediate(repo, nil, cbranch, nil, nil, &cerr))) + if !r { + return glib.ConvertGError(glib.ToGError(unsafe.Pointer(cerr))) + } + return nil +} diff --git a/storage.conf b/storage.conf index 2eedc619d6..e1c0d2c449 100644 --- a/storage.conf +++ b/storage.conf @@ -120,3 +120,10 @@ override_kernel_check = "false" # attempt to complete IO when ENOSPC (no space) error is returned by # underlying storage device. # xfs_nospace_max_retries = "0" + +# If specified, use OSTree to deduplicate files with the overlay backend +ostree_repo = "" + +# Set to skip a PRIVATE bind mount on the storage home directory. Only supported by +# certain container storage drivers +skip_mount_home = "false" diff --git a/store.go b/store.go index 29972b6905..870ccf7b0a 100644 --- a/store.go +++ b/store.go @@ -2987,6 +2987,11 @@ type OptionsConfig struct { RemapGroup string `toml:"remap-group"` // Thinpool container options to be handed to thinpool drivers Thinpool struct{ ThinpoolOptionsConfig } `toml:"thinpool"` + // OSTree repository + OstreeRepo string `toml:"ostree_repo"` + + // Do not create a bind mount on the storage home + SkipMountHome string `toml:"skip_mount_home"` } // TOML-friendly explicit tables used for conversions. @@ -3077,6 +3082,12 @@ func init() { if config.Storage.Options.Size != "" { DefaultStoreOptions.GraphDriverOptions = append(DefaultStoreOptions.GraphDriverOptions, fmt.Sprintf("%s.size=%s", config.Storage.Driver, config.Storage.Options.Size)) } + if config.Storage.Options.OstreeRepo != "" { + DefaultStoreOptions.GraphDriverOptions = append(DefaultStoreOptions.GraphDriverOptions, fmt.Sprintf("%s.ostree_repo=%s", config.Storage.Driver, config.Storage.Options.OstreeRepo)) + } + if config.Storage.Options.SkipMountHome != "" { + DefaultStoreOptions.GraphDriverOptions = append(DefaultStoreOptions.GraphDriverOptions, fmt.Sprintf("%s.skip_mount_home=%s", config.Storage.Driver, config.Storage.Options.SkipMountHome)) + } if config.Storage.Options.OverrideKernelCheck != "" { DefaultStoreOptions.GraphDriverOptions = append(DefaultStoreOptions.GraphDriverOptions, fmt.Sprintf("%s.override_kernel_check=%s", config.Storage.Driver, config.Storage.Options.OverrideKernelCheck)) } diff --git a/tests/helpers.bash b/tests/helpers.bash index 528ad64dce..09fd9a5745 100755 --- a/tests/helpers.bash +++ b/tests/helpers.bash @@ -24,6 +24,8 @@ function teardown() { # Create a file "$1" with random contents of length $2, or 256. function createrandom() { dd if=/dev/urandom bs=1 count=${2:-256} of=${1:-${BATS_TMPDIR}/randomfile} status=none + # Set the mtime to the epoch so it won't be different once it is deduplicated with OSTree + touch -t 7001010000.00 ${1:-${BATS_TMPDIR}/randomfile} } # Run the CLI with the specified options. diff --git a/tests/import-layer-ostree.bats b/tests/import-layer-ostree.bats new file mode 100644 index 0000000000..048bac5a3d --- /dev/null +++ b/tests/import-layer-ostree.bats @@ -0,0 +1,59 @@ +#!/usr/bin/env bats + +load helpers + +@test "import-layer-ostree" { + case "$STORAGE_DRIVER" in + overlay*|vfs) + ;; + *) + skip "not supported by driver $STORAGE_DRIVER" + ;; + esac + + # The checkdiffs function needs "tar". + if test -z "$(which tar 2> /dev/null)" ; then + skip "need tar" + fi + if test -z "$(which ostree 2> /dev/null)" ; then + skip "need ostree" + fi + + OSTREE_REPO=${TESTDIR}/ostree + mkdir -p $OSTREE_REPO + + # Create and populate three interesting layers. + populate + + OPTS="--storage-opt=.ostree_repo=$OSTREE_REPO,.skip_mount_home=true" + + # Extract the layers. + storage diff $OPTS -u -f $TESTDIR/lower.tar $lowerlayer + storage diff $OPTS -c -f $TESTDIR/middle.tar $midlayer + storage diff $OPTS -u -f $TESTDIR/upper.tar $upperlayer + + # Delete the layers. + storage delete-layer $OPTS $upperlayer + storage delete-layer $OPTS $midlayer + storage delete-layer $OPTS $lowerlayer + + # Import new layers using the layer diffs and mark them read-only. Only read-only layers are deduplicated with OSTree. + run storage --debug=false import-layer $OPTS -r -f $TESTDIR/lower.tar + [ "$status" -eq 0 ] + [ "$output" != "" ] + lowerlayer="$output" + + run storage --debug=false import-layer $OPTS -r -f $TESTDIR/middle.tar "$lowerlayer" + [ "$status" -eq 0 ] + [ "$output" != "" ] + midlayer="$output" + + run storage --debug=false import-layer $OPTS -r -f $TESTDIR/upper.tar "$midlayer" + [ "$status" -eq 0 ] + [ "$output" != "" ] + upperlayer="$output" + + # The contents of these new layers should match what the old ones had. + checkchanges + checkdiffs +} diff --git a/vagrant/provision.sh b/vagrant/provision.sh index cd7befaa0d..76463bc14b 100755 --- a/vagrant/provision.sh +++ b/vagrant/provision.sh @@ -16,12 +16,14 @@ case "${ID_LIKE:-${ID:-unknown}}" in apt-get -q -y install zfs-dkms zfsutils-linux apt-get -q -y install golang gccgo apt-get -q -y install bats + apt-get -q -y install libostree-dev ostree ;; fedora) dnf -y clean all dnf -y install make git gcc btrfs-progs-devel device-mapper-devel dnf -y install golang gcc-go dnf -y install bats + dnf -y install ostree-devel ostree alternatives --set go /usr/lib/golang/bin/go ;; unknown) diff --git a/vendor.conf b/vendor.conf index 54c78ab1ca..c0498a02d1 100644 --- a/vendor.conf +++ b/vendor.conf @@ -20,3 +20,4 @@ github.com/tchap/go-patricia v2.2.6 github.com/vbatts/tar-split v0.10.2 golang.org/x/net 7dcfb8076726a3fdd9353b6b8a1f1b6be6811bd6 golang.org/x/sys 07c182904dbd53199946ba614a412c61d3c548f5 +github.com/ostreedev/ostree-go aeb02c6b6aa2889db3ef62f7855650755befd460 diff --git a/vendor/github.com/ostreedev/ostree-go/LICENSE b/vendor/github.com/ostreedev/ostree-go/LICENSE new file mode 100644 index 0000000000..aa93b4dab9 --- /dev/null +++ b/vendor/github.com/ostreedev/ostree-go/LICENSE @@ -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/vendor/github.com/ostreedev/ostree-go/README.md b/vendor/github.com/ostreedev/ostree-go/README.md new file mode 100644 index 0000000000..c79010a0fc --- /dev/null +++ b/vendor/github.com/ostreedev/ostree-go/README.md @@ -0,0 +1,4 @@ +OSTree-Go +========= + +Go bindings for OSTree. Find out more about OSTree [here](https://github.com/ostreedev/ostree) diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/glibobject/gboolean.go b/vendor/github.com/ostreedev/ostree-go/pkg/glibobject/gboolean.go new file mode 100644 index 0000000000..a4ad0f0005 --- /dev/null +++ b/vendor/github.com/ostreedev/ostree-go/pkg/glibobject/gboolean.go @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2013 Conformal Systems + * + * 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 +// #include +// #include +// #include "glibobject.go.h" +// #include +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 +} diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/glibobject/gcancellable.go b/vendor/github.com/ostreedev/ostree-go/pkg/glibobject/gcancellable.go new file mode 100644 index 0000000000..537db4720d --- /dev/null +++ b/vendor/github.com/ostreedev/ostree-go/pkg/glibobject/gcancellable.go @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2013 Conformal Systems + * + * 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 +// #include +// #include +// #include "glibobject.go.h" +// #include +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 diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/glibobject/gerror.go b/vendor/github.com/ostreedev/ostree-go/pkg/glibobject/gerror.go new file mode 100644 index 0000000000..714b15d0bf --- /dev/null +++ b/vendor/github.com/ostreedev/ostree-go/pkg/glibobject/gerror.go @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2013 Conformal Systems + * + * 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 +// #include +// #include +// #include "glibobject.go.h" +// #include +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())))) +} diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/glibobject/gfile.go b/vendor/github.com/ostreedev/ostree-go/pkg/glibobject/gfile.go new file mode 100644 index 0000000000..babe705096 --- /dev/null +++ b/vendor/github.com/ostreedev/ostree-go/pkg/glibobject/gfile.go @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2013 Conformal Systems + * + * 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 +// #include +// #include +// #include "glibobject.go.h" +// #include +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 +} diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/glibobject/gfileinfo.go b/vendor/github.com/ostreedev/ostree-go/pkg/glibobject/gfileinfo.go new file mode 100644 index 0000000000..9c155834a8 --- /dev/null +++ b/vendor/github.com/ostreedev/ostree-go/pkg/glibobject/gfileinfo.go @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2013 Conformal Systems + * + * 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 +// #include +// #include +// #include "glibobject.go.h" +// #include +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 +} diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/glibobject/ghashtable.go b/vendor/github.com/ostreedev/ostree-go/pkg/glibobject/ghashtable.go new file mode 100644 index 0000000000..20cc321cbb --- /dev/null +++ b/vendor/github.com/ostreedev/ostree-go/pkg/glibobject/ghashtable.go @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2013 Conformal Systems + * + * 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 +// #include +// #include +// #include "glibobject.go.h" +// #include +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} +} diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/glibobject/ghashtableiter.go b/vendor/github.com/ostreedev/ostree-go/pkg/glibobject/ghashtableiter.go new file mode 100644 index 0000000000..1657edf5fc --- /dev/null +++ b/vendor/github.com/ostreedev/ostree-go/pkg/glibobject/ghashtableiter.go @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2013 Conformal Systems + * + * 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 +// #include +// #include +// #include "glibobject.go.h" +// #include +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} +} diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/glibobject/glibobject.go b/vendor/github.com/ostreedev/ostree-go/pkg/glibobject/glibobject.go new file mode 100644 index 0000000000..f3d3aa5266 --- /dev/null +++ b/vendor/github.com/ostreedev/ostree-go/pkg/glibobject/glibobject.go @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2013 Conformal Systems + * + * 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 +// #include +// #include +// #include "glibobject.go.h" +// #include +import "C" diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/glibobject/glibobject.go.h b/vendor/github.com/ostreedev/ostree-go/pkg/glibobject/glibobject.go.h new file mode 100644 index 0000000000..a55bd242f9 --- /dev/null +++ b/vendor/github.com/ostreedev/ostree-go/pkg/glibobject/glibobject.go.h @@ -0,0 +1,17 @@ +#include + +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/vendor/github.com/ostreedev/ostree-go/pkg/glibobject/gobject.go b/vendor/github.com/ostreedev/ostree-go/pkg/glibobject/gobject.go new file mode 100644 index 0000000000..dedbe749a4 --- /dev/null +++ b/vendor/github.com/ostreedev/ostree-go/pkg/glibobject/gobject.go @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2013 Conformal Systems + * + * 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 +// #include +// #include +// #include "glibobject.go.h" +// #include +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(C.gpointer(v.native())) +} + +func (v *GObject) IsFloating() bool { + c := C.g_object_is_floating(C.gpointer(v.native())) + return GoBool(GBoolean(c)) +} + +func (v *GObject) ForceFloating() { + C.g_object_force_floating(v.native()) +} diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/glibobject/goptioncontext.go b/vendor/github.com/ostreedev/ostree-go/pkg/glibobject/goptioncontext.go new file mode 100644 index 0000000000..05fd54a1a4 --- /dev/null +++ b/vendor/github.com/ostreedev/ostree-go/pkg/glibobject/goptioncontext.go @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2013 Conformal Systems + * + * 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 +// #include +// #include +// #include "glibobject.go.h" +// #include +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} +} diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/glibobject/gvariant.go b/vendor/github.com/ostreedev/ostree-go/pkg/glibobject/gvariant.go new file mode 100644 index 0000000000..30572ea87f --- /dev/null +++ b/vendor/github.com/ostreedev/ostree-go/pkg/glibobject/gvariant.go @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2013 Conformal Systems + * + * 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 +// #include +// #include +// #include "glibobject.go.h" +// #include +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} +} diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otadmin/admin.go.h b/vendor/github.com/ostreedev/ostree-go/pkg/otadmin/admin.go.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otadmin/admincleanup.go b/vendor/github.com/ostreedev/ostree-go/pkg/otadmin/admincleanup.go new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otadmin/admindeploy.go b/vendor/github.com/ostreedev/ostree-go/pkg/otadmin/admindeploy.go new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otadmin/admindiff.go b/vendor/github.com/ostreedev/ostree-go/pkg/otadmin/admindiff.go new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otadmin/admininit.go b/vendor/github.com/ostreedev/ostree-go/pkg/otadmin/admininit.go new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otadmin/admininstutil.go b/vendor/github.com/ostreedev/ostree-go/pkg/otadmin/admininstutil.go new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otadmin/adminosinit.go b/vendor/github.com/ostreedev/ostree-go/pkg/otadmin/adminosinit.go new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otadmin/adminsetorigin.go b/vendor/github.com/ostreedev/ostree-go/pkg/otadmin/adminsetorigin.go new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otadmin/adminstatus.go b/vendor/github.com/ostreedev/ostree-go/pkg/otadmin/adminstatus.go new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otadmin/adminswitch.go b/vendor/github.com/ostreedev/ostree-go/pkg/otadmin/adminswitch.go new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otadmin/adminundeploy.go b/vendor/github.com/ostreedev/ostree-go/pkg/otadmin/adminundeploy.go new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otadmin/adminunlock.go b/vendor/github.com/ostreedev/ostree-go/pkg/otadmin/adminunlock.go new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otadmin/adminupgrade.go b/vendor/github.com/ostreedev/ostree-go/pkg/otadmin/adminupgrade.go new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/builtin.go b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/builtin.go new file mode 100644 index 0000000000..d3a8ae5fde --- /dev/null +++ b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/builtin.go @@ -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 +// #include +// #include +// #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 + } +} diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/builtin.go.h b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/builtin.go.h new file mode 100644 index 0000000000..734de98219 --- /dev/null +++ b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/builtin.go.h @@ -0,0 +1,191 @@ +#ifndef BUILTIN_GO_H +#define BUILTIN_GO_H + +#include +#include +#include +#include + +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 diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/cat.go b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/cat.go new file mode 100644 index 0000000000..d43ea07c74 --- /dev/null +++ b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/cat.go @@ -0,0 +1 @@ +package otbuiltin diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/checkout.go b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/checkout.go new file mode 100644 index 0000000000..55b51bfbd0 --- /dev/null +++ b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/checkout.go @@ -0,0 +1,102 @@ +package otbuiltin + +import ( + "strings" + "unsafe" + + glib "github.com/ostreedev/ostree-go/pkg/glibobject" +) + +// #cgo pkg-config: ostree-1 +// #include +// #include +// #include +// #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 +} diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/checksum.go b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/checksum.go new file mode 100644 index 0000000000..d43ea07c74 --- /dev/null +++ b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/checksum.go @@ -0,0 +1 @@ +package otbuiltin diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/commit.go b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/commit.go new file mode 100644 index 0000000000..9550f802c8 --- /dev/null +++ b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/commit.go @@ -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 +// #include +// #include +// #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, C.gpointer(&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(C.gpointer(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.gpointer(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.gpointer( C.g_strdup((*C.gchar)(C.CString(line))))) + + return nil +} diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/config.go b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/config.go new file mode 100644 index 0000000000..d43ea07c74 --- /dev/null +++ b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/config.go @@ -0,0 +1 @@ +package otbuiltin diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/diff.go b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/diff.go new file mode 100644 index 0000000000..d43ea07c74 --- /dev/null +++ b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/diff.go @@ -0,0 +1 @@ +package otbuiltin diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/export.go b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/export.go new file mode 100644 index 0000000000..d43ea07c74 --- /dev/null +++ b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/export.go @@ -0,0 +1 @@ +package otbuiltin diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/fsck.go b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/fsck.go new file mode 100644 index 0000000000..d43ea07c74 --- /dev/null +++ b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/fsck.go @@ -0,0 +1 @@ +package otbuiltin diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/gpgsign.go b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/gpgsign.go new file mode 100644 index 0000000000..d43ea07c74 --- /dev/null +++ b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/gpgsign.go @@ -0,0 +1 @@ +package otbuiltin diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/init.go b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/init.go new file mode 100644 index 0000000000..c1ca2dc7e8 --- /dev/null +++ b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/init.go @@ -0,0 +1,90 @@ +package otbuiltin + +import ( + "errors" + "strings" + "unsafe" + + glib "github.com/ostreedev/ostree-go/pkg/glibobject" +) + +// #cgo pkg-config: ostree-1 +// #include +// #include +// #include +// #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 +} diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/log.go b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/log.go new file mode 100644 index 0000000000..2ceea09257 --- /dev/null +++ b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/log.go @@ -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 +// #include +// #include +// #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, ×tamp) + + // 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) + } +} diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/ls.go b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/ls.go new file mode 100644 index 0000000000..d43ea07c74 --- /dev/null +++ b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/ls.go @@ -0,0 +1 @@ +package otbuiltin diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/prune.go b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/prune.go new file mode 100644 index 0000000000..8dfa40a55b --- /dev/null +++ b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/prune.go @@ -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 +// #include +// #include +// #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 +} diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/pull.go b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/pull.go new file mode 100644 index 0000000000..d43ea07c74 --- /dev/null +++ b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/pull.go @@ -0,0 +1 @@ +package otbuiltin diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/pulllocal.go b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/pulllocal.go new file mode 100644 index 0000000000..d43ea07c74 --- /dev/null +++ b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/pulllocal.go @@ -0,0 +1 @@ +package otbuiltin diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/refs.go b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/refs.go new file mode 100644 index 0000000000..d43ea07c74 --- /dev/null +++ b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/refs.go @@ -0,0 +1 @@ +package otbuiltin diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/remote.go b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/remote.go new file mode 100644 index 0000000000..d43ea07c74 --- /dev/null +++ b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/remote.go @@ -0,0 +1 @@ +package otbuiltin diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/reset.go b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/reset.go new file mode 100644 index 0000000000..d43ea07c74 --- /dev/null +++ b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/reset.go @@ -0,0 +1 @@ +package otbuiltin diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/revparse.go b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/revparse.go new file mode 100644 index 0000000000..d43ea07c74 --- /dev/null +++ b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/revparse.go @@ -0,0 +1 @@ +package otbuiltin diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/show.go b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/show.go new file mode 100644 index 0000000000..d43ea07c74 --- /dev/null +++ b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/show.go @@ -0,0 +1 @@ +package otbuiltin diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/staticdelta.go b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/staticdelta.go new file mode 100644 index 0000000000..d43ea07c74 --- /dev/null +++ b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/staticdelta.go @@ -0,0 +1 @@ +package otbuiltin diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/summary.go b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/summary.go new file mode 100644 index 0000000000..d43ea07c74 --- /dev/null +++ b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/summary.go @@ -0,0 +1 @@ +package otbuiltin diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/trivialhttpd.go b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/trivialhttpd.go new file mode 100644 index 0000000000..d43ea07c74 --- /dev/null +++ b/vendor/github.com/ostreedev/ostree-go/pkg/otbuiltin/trivialhttpd.go @@ -0,0 +1 @@ +package otbuiltin diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otremote/remote.go.h b/vendor/github.com/ostreedev/ostree-go/pkg/otremote/remote.go.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otremote/remotedelete.go b/vendor/github.com/ostreedev/ostree-go/pkg/otremote/remotedelete.go new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otremote/remotegpgimport.go b/vendor/github.com/ostreedev/ostree-go/pkg/otremote/remotegpgimport.go new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otremote/remotelist.go b/vendor/github.com/ostreedev/ostree-go/pkg/otremote/remotelist.go new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otremote/remoterefs.go b/vendor/github.com/ostreedev/ostree-go/pkg/otremote/remoterefs.go new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otremote/remoteshowurl.go b/vendor/github.com/ostreedev/ostree-go/pkg/otremote/remoteshowurl.go new file mode 100644 index 0000000000..e69de29bb2 diff --git a/vendor/github.com/ostreedev/ostree-go/pkg/otremote/remotesummary.go b/vendor/github.com/ostreedev/ostree-go/pkg/otremote/remotesummary.go new file mode 100644 index 0000000000..e69de29bb2