[gnome-build-meta/valentindavid/gnome-os-ostree: 23/25] Add OSTree based VM image



commit 5c0afbe3048f95470ac340068e642cf32fa4fe66
Author: Valentin David <valentin david codethink co uk>
Date:   Sun Nov 17 11:48:52 2019 +0100

    Add OSTree based VM image

 .gitignore                                  |   4 +
 elements/vm/deps.bst                        |  28 +++++++
 elements/vm/filesystem.bst                  |  13 +++
 elements/vm/flathub-config.bst              |  17 ++++
 elements/vm/image.bst                       | 113 ++++++++++++++++++++++++++
 elements/vm/initial-scripts.bst             |   7 ++
 elements/vm/initramfs.bst                   |  67 ++++++++++++++++
 elements/vm/initramfs/deps.bst              |  15 ++++
 elements/vm/initramfs/initial-scripts.bst   |   7 ++
 elements/vm/ostree-config.bst               |  50 ++++++++++++
 elements/vm/repo-deps.bst                   |   5 ++
 elements/vm/repo.bst                        |  39 +++++++++
 files/vm/flathub-config/add-flathub.preset  |   1 +
 files/vm/flathub-config/add-flathub.service |  12 +++
 files/vm/gnome.gpg                          |  29 +++++++
 files/vm/ostree-config/gnome.conf.in        |   4 +
 files/vm/ostree-config/ostree.conf          |   4 +
 plugins/collect_initial_scripts.py          |  55 +++++++++++++
 plugins/ostree_mirror.py                    | 120 ++++++++++++++++++++++++++++
 project.conf                                |  20 +++++
 utils/build-image.sh                        |  14 ++++
 utils/run-local-repo.sh                     |   3 +
 utils/update-local-repo.sh                  |  37 +++++++++
 utils/update-repo.sh                        | 108 +++++++++++++++++++++++++
 24 files changed, 772 insertions(+)
---
diff --git a/.gitignore b/.gitignore
index add5986a..f78329c0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,3 +6,7 @@ plugins/__pycache__
 
 # Never commit project.refs
 project.refs
+
+image/disk.qcow2
+ostree-repo
+ostree-gpg
diff --git a/elements/vm/deps.bst b/elements/vm/deps.bst
new file mode 100644
index 00000000..427a11f1
--- /dev/null
+++ b/elements/vm/deps.bst
@@ -0,0 +1,28 @@
+kind: stack
+
+runtime-depends:
+- freedesktop-sdk.bst:components/util-linux.bst
+- freedesktop-sdk.bst:components/tzdata.bst
+- freedesktop-sdk.bst:components/systemd.bst
+- freedesktop-sdk.bst:components/xorg-server.bst
+- freedesktop-sdk.bst:components/shadow.bst
+- freedesktop-sdk.bst:vm/mesa-default.bst
+
+- core-deps/flatpak.bst
+- vm/initramfs.bst
+- vm/ostree-config.bst
+- core-deps/avahi.bst
+- core-deps/eos-updater.bst
+
+- vm/plymouth-gnome-theme.bst
+- vm/kbd.bst
+
+- freedesktop-sdk.bst:vm/config/pulseaudio.bst
+- freedesktop-sdk.bst:vm/config/sudo.bst
+- freedesktop-sdk.bst:vm/config/journald.bst
+- vm/flathub-config.bst
+
+# And add GNOME core on top !
+- sdk-platform.bst
+- core.bst
+- core/systemd-presets.bst
diff --git a/elements/vm/filesystem.bst b/elements/vm/filesystem.bst
new file mode 100644
index 00000000..da7e9f3f
--- /dev/null
+++ b/elements/vm/filesystem.bst
@@ -0,0 +1,13 @@
+kind: compose
+
+build-depends:
+- vm/deps.bst
+
+# Currently we just take everything and remove the
+# devel stuff (headers and static libraries), and debugging
+# symbols which take a huge amount of space, we could
+# refine this and make it much more selective, though.
+config:
+  exclude:
+  - devel
+  - debug
diff --git a/elements/vm/flathub-config.bst b/elements/vm/flathub-config.bst
new file mode 100644
index 00000000..25d2036b
--- /dev/null
+++ b/elements/vm/flathub-config.bst
@@ -0,0 +1,17 @@
+kind: manual
+
+depends:
+- freedesktop-sdk.bst:bootstrap-import.bst
+
+runtime-depends:
+- core-deps/flatpak.bst
+
+config:
+  install-commands:
+  - |
+    install -Dm644 -t "%{install-root}%{indep-libdir}/systemd/system" add-flathub.service
+    install -Dm644 -t "%{install-root}%{indep-libdir}/systemd/system-preset" add-flathub.preset
+
+sources:
+- kind: local
+  path: files/vm/flathub-config
diff --git a/elements/vm/image.bst b/elements/vm/image.bst
new file mode 100644
index 00000000..6a203d72
--- /dev/null
+++ b/elements/vm/image.bst
@@ -0,0 +1,113 @@
+kind: manual
+
+build-depends:
+- core-deps/ostree.bst
+- vm/qemu-tools.bst
+- freedesktop-sdk.bst:integration/mtab.bst
+- freedesktop-sdk.bst:components/genimage.bst
+
+variables:
+  (?):
+  - arch == "x86_64":
+      linux-root: 4F68BCE3-E8CD-4DB1-96E7-FBCAF984B709
+  - arch == "i686":
+      linux-root: 44479540-F297-41B2-9AF7-D131D5F0458A
+  - arch == "arm":
+      linux-root: 69DAD710-2CE4-4E3C-B16C-21A1D49ABED3
+  - arch == "aarch64":
+      linux-root: B921B045-1DF0-41C3-AF44-4C6F280D3FAE
+
+  sysroot: "%{build-root}/sysroot"
+
+environment:
+  OSTREE_REPO: "%{sysroot}/ostree/repo"
+
+config:
+  build-commands:
+  - mkdir -p "${OSTREE_REPO}"
+  - ostree init --repo="${OSTREE_REPO}" --mode=bare
+
+  - ostree config --group sysroot set bootloader none
+  - ostree pull-local "%{build-root}/source-repo" %{ostree-branch}
+
+  - mkdir -p "%{sysroot}/boot"
+
+  - ostree admin init-fs "%{sysroot}"
+  - ostree admin os-init --sysroot="%{sysroot}" gnome-os
+  - |
+    ostree admin deploy --os="gnome-os" \
+         --sysroot="%{sysroot}" %{ostree-branch} \
+         --karg="rw" --karg="quiet" --karg="splash"
+
+  - |
+    mkdir -p "%{sysroot}/etc/ostree"
+    cp -r "%{sysroot}"/ostree/boot.1/gnome-os/*/*/etc/ostree/remotes.d "%{sysroot}/etc/ostree/remotes.d"
+
+  - |
+    ostree admin set-origin --sysroot="%{sysroot}" \
+           --index=0 \
+           GnomeOS dummy \
+           %{ostree-branch}
+
+  - |
+    cp -r "%{sysroot}"/ostree/boot.1/gnome-os/*/*/boot/EFI/ "%{sysroot}/boot/"
+
+  - |
+    mkdir -p genimage
+
+  - |
+    cat >genimage/genimage.cfg <<EOF
+    image efi.img {
+        vfat {
+            extraargs = "-F32 -n EFI"
+        }
+        mountpoint = "/boot"
+        size = 100M
+    }
+    image root.img {
+        ext4  {
+            label = "root"
+        }
+        size = 16G
+    }
+    image disk.img {
+        hdimage {
+            align = 1M
+            gpt = true
+        }
+        partition efi {
+            image = "efi.img"
+            partition-type-uuid = "U"
+        }
+        partition root {
+            image = "root.img"
+            partition-type-uuid = "%{linux-root}"
+        }
+    }
+    image disk.qcow2 {
+        qemu {
+        }
+        partition image {
+            image = "disk.img"
+        }
+    }
+    EOF
+
+  - |
+    cd genimage
+    genimage --rootpath "%{sysroot}"
+
+  - |
+    install -Dm644 -t "%{install-root}" genimage/images/disk.qcow2
+
+sources:
+- kind: ostree_mirror
+  (?):
+  - repo_mode == 'local':
+      path: ostree-repo
+      gpg: local.gpg
+  - repo_mode == 'nightly':
+      url: https://nightly.gnome.org/
+      gpg: files/vm/gnome.gpg
+  match: 'gnome-os/*'
+  directory: source-repo
diff --git a/elements/vm/initial-scripts.bst b/elements/vm/initial-scripts.bst
new file mode 100644
index 00000000..a811a267
--- /dev/null
+++ b/elements/vm/initial-scripts.bst
@@ -0,0 +1,7 @@
+kind: collect_initial_scripts
+
+build-depends:
+- vm/deps.bst
+
+config:
+  path: /etc/fdsdk/initial_scripts
diff --git a/elements/vm/initramfs.bst b/elements/vm/initramfs.bst
new file mode 100644
index 00000000..8127a743
--- /dev/null
+++ b/elements/vm/initramfs.bst
@@ -0,0 +1,67 @@
+kind: script
+
+build-depends:
+- vm/initramfs/deps.bst
+- vm/initramfs/initial-scripts.bst
+- freedesktop-sdk.bst:vm/prepare-image.bst
+
+variables:
+  uuidnamespace: aea54278-2587-4075-ae67-8688ace4ce3d
+
+config:
+  layout:
+  - element: ''
+    destination: '/tmp'
+  - element: ''
+    destination: '/efi'
+  - element: ''
+    destination: '/var/tmp'
+  - element: vm/initramfs/deps.bst
+    destination: '/'
+  - element: vm/initramfs/initial-scripts.bst
+    destination: '/'
+  - element: vm/prepare-image.bst
+    destination: '/'
+
+  commands:
+  - |
+    prepare-image.sh \
+       --seed "%{uuidnamespace}" \
+       --rootsource /dev/gpt-auto-root \
+        --efisource LABEL=EFI \
+       --efipath /boot \
+       --rootpasswd "root" >/dev/null
+
+  - |
+    mkdir -p "%{install-root}/usr/lib/"
+    cp -r /usr/lib/modules "%{install-root}/usr/lib/"
+
+  - |
+    version="$(ls -1 /lib/modules | head -n1)"
+    mkdir -p "%{install-root}/usr/lib/modules/${version}"
+    dracut -v --fstab \
+           --no-machineid \
+           --kver "${version}" \
+           --add ostree \
+           --add plymouth \
+           --install 'fsck.ext4' \
+           "%{install-root}/usr/lib/modules/${version}/initramfs"
+
+  - |
+    version="$(ls -1 /lib/modules | head -n1)"
+    cp /boot/vmlinuz "%{install-root}/usr/lib/modules/${version}/vmlinuz"
+
+  - dbus-uuidgen >/etc/machine-id
+  - SYSTEMD_RELAX_ESP_CHECKS=1 bootctl --path='/efi' --no-variables install
+  - rm /etc/machine-id
+
+  - |
+    cp -r /efi "%{install-root}/boot"
+
+  - |
+    cat <<EOF >%{install-root}/boot/loader/loader.conf
+    timeout 3
+    editor yes
+    console-mode keep
+    default *
+    EOF
diff --git a/elements/vm/initramfs/deps.bst b/elements/vm/initramfs/deps.bst
new file mode 100644
index 00000000..29872db7
--- /dev/null
+++ b/elements/vm/initramfs/deps.bst
@@ -0,0 +1,15 @@
+kind: stack
+
+runtime-depends:
+- freedesktop-sdk.bst:bootstrap-import.bst
+- freedesktop-sdk.bst:components/util-linux.bst
+- freedesktop-sdk.bst:components/linux.bst
+- freedesktop-sdk.bst:components/systemd.bst
+- freedesktop-sdk.bst:components/dbus.bst
+- freedesktop-sdk.bst:components/dracut.bst
+- freedesktop-sdk.bst:components/os-release.bst
+- freedesktop-sdk.bst:components/shadow.bst
+- freedesktop-sdk.bst:components/tzdata.bst
+- freedesktop-sdk.bst:components/pkg-config.bst
+- core-deps/ostree.bst
+- vm/plymouth-gnome-theme.bst
diff --git a/elements/vm/initramfs/initial-scripts.bst b/elements/vm/initramfs/initial-scripts.bst
new file mode 100644
index 00000000..069d8f3f
--- /dev/null
+++ b/elements/vm/initramfs/initial-scripts.bst
@@ -0,0 +1,7 @@
+kind: collect_initial_scripts
+
+build-depends:
+- vm/initramfs/deps.bst
+
+config:
+  path: /etc/fdsdk/initial_scripts
diff --git a/elements/vm/ostree-config.bst b/elements/vm/ostree-config.bst
new file mode 100644
index 00000000..3cb885c1
--- /dev/null
+++ b/elements/vm/ostree-config.bst
@@ -0,0 +1,50 @@
+kind: manual
+
+build-depends:
+- freedesktop-sdk.bst:bootstrap-import.bst
+- freedesktop-sdk.bst:components/m4.bst
+
+runtime-depends:
+- freedesktop-sdk.bst:components/systemd.bst
+- core-deps/ostree.bst
+
+config:
+  build-commands:
+  - |
+    m4 -DOSTREE_REMOTE_URL="%{ostree-remote-url}" \
+      gnome.conf.in >gnome.conf
+
+  install-commands:
+  - |
+    mkdir %{install-root}/boot
+    mkdir %{install-root}/efi
+    mkdir %{install-root}/etc
+    mkdir %{install-root}/mnt
+    mkdir %{install-root}/run
+    mkdir %{install-root}/opt
+    mkdir %{install-root}/sys
+    mkdir %{install-root}/tmp
+    mkdir %{install-root}/dev
+    mkdir %{install-root}/proc
+
+  - |
+    mkdir -p "%{install-root}/sysroot"
+    ln -s sysroot/ostree "%{install-root}/ostree"
+    ln -s var/home "%{install-root}/home"
+    ln -s var/roothome "%{install-root}/root"
+    ln -s run/media "%{install-root}/media"
+
+  - |
+    install -Dm644 -t "%{install-root}/usr/lib/tmpfiles.d" ostree.conf
+    install -Dm644 *.gpg "%{install-root}/etc/pki/ostree/gnome.gpg"
+    install -Dm644 -t "%{install-root}/etc/ostree/remotes.d" gnome.conf
+
+sources:
+- kind: local
+  path: files/vm/ostree-config
+- kind: local
+  (?):
+  - repo_mode == 'local':
+      path: local.gpg
+  - repo_mode == 'nightly':
+      path: files/vm/gnome.gpg
diff --git a/elements/vm/repo-deps.bst b/elements/vm/repo-deps.bst
new file mode 100644
index 00000000..120ad68c
--- /dev/null
+++ b/elements/vm/repo-deps.bst
@@ -0,0 +1,5 @@
+kind: stack
+
+runtime-depends:
+- core-deps/ostree.bst
+- freedesktop-sdk.bst:vm/prepare-image.bst
diff --git a/elements/vm/repo.bst b/elements/vm/repo.bst
new file mode 100644
index 00000000..90e8bea2
--- /dev/null
+++ b/elements/vm/repo.bst
@@ -0,0 +1,39 @@
+kind: script
+
+build-depends:
+- vm/repo-deps.bst
+- vm/filesystem.bst
+- vm/initial-scripts.bst
+- freedesktop-sdk.bst:vm/prepare-image.bst
+
+variables:
+  uuidnamespace: aea54278-2587-4075-ae67-8688ace4ce3d
+
+environment:
+  OSTREE_REPO: "%{install-root}/ostree/repo"
+
+config:
+  layout:
+  - element: ''
+    destination: /tmp
+  - element: vm/repo-deps.bst
+    destination: /
+  - element: vm/filesystem.bst
+    destination: /sysroot
+  - element: vm/initial-scripts.bst
+    destination: /
+
+  commands:
+  - |
+    prepare-image.sh \
+       --sysroot /sysroot \
+       --seed "%{uuidnamespace}" \
+       --rootsource /dev/gpt-auto-root \
+        --efisource LABEL=EFI \
+       --efipath /boot \
+       --rootpasswd "root" >/dev/null
+
+  - mkdir -p "${OSTREE_REPO}"
+  - ostree init --repo="${OSTREE_REPO}" --mode=archive
+  - mv /sysroot/etc /sysroot/usr/etc
+  - ostree commit --branch=%{ostree-branch} /sysroot
diff --git a/files/vm/flathub-config/add-flathub.preset b/files/vm/flathub-config/add-flathub.preset
new file mode 100644
index 00000000..185c4062
--- /dev/null
+++ b/files/vm/flathub-config/add-flathub.preset
@@ -0,0 +1 @@
+enable add-flathub.service
diff --git a/files/vm/flathub-config/add-flathub.service b/files/vm/flathub-config/add-flathub.service
new file mode 100644
index 00000000..0fa35e0a
--- /dev/null
+++ b/files/vm/flathub-config/add-flathub.service
@@ -0,0 +1,12 @@
+[Unit]
+Description=Add flathub
+ConditionFirstBoot=yes
+Wants=network-online.target
+After=network-online.target systemd-resolved.service nss-lookup.target
+
+[Service]
+Type=oneshot
+ExecStart=flatpak remote-add flathub https://flathub.org/repo/flathub.flatpakrepo
+
+[Install]
+WantedBy=multi-user.target
diff --git a/files/vm/gnome.gpg b/files/vm/gnome.gpg
new file mode 100644
index 00000000..ecd64cde
--- /dev/null
+++ b/files/vm/gnome.gpg
@@ -0,0 +1,29 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mQINBFuhBAsBEADDIU1v3mx7yvJwwbVw11gBm3HYR1kV0EbTI311nDuZ3oSf3zf9
+Rm2gI73C8v5nq6WcTjwkL0tvArf4OxWNFufWKqa6UfODOzwBXeNhkyZEFvvgI0qi
+f6IIbxMSXgntNmH+sD1quXJ7tiGyf2cA1FzQJJVUMRwsb2yGx3XLIZW7JDZgVJvW
+NVDmPg7unuECRXsmEGFusfiejsIwDLyOzXIushFk7APLR5QWyYdI2Ujb077aaMqo
+Ytfv4Iv1Ulgg44dlKqEqdRCbCtlBfirqbi4zi5TNI3dQbyxiPuCBls18Aw9sRq96
+MmpKlyD02Ig8TxzmVcjAJ2nGN/3ptWOva1Osadkh3GGgxWhPV1WEF66Vfnx07wp3
+8081bnpCl0wDLjGumZ0sIAwQ7g5ZdC8Nulx93iOr5uTixYSvcn0djuEbwDC2Qs0U
+yLP2+uT6OcHyT3PjT5zA3nTrMPsgTNPcK/ajrMVe2XUxml/3vZipBdAeJFhtAfAI
+M2mbXw6h63zcjeNBG7ieqlKvbKf4t9uFhzUGC59T/lef5e4GU+OftEDHSirmBeM9
+kext3mSMuzDNdz5G0UgzBoBMfHnWQOgexCvJanYQ9OvJ57O51E6NaTHW0YePS2fl
+p2nRNyGzeZ5352kZxSxaCorKTDuzhrPHtvXGnzp/n9n10gsYZFH7ZSrKrwARAQAB
+tDVHTk9NRSBCdWlsZCBNZXRhIFNpZ25pbmcgS2V5IDxyZWxlYXNlLXRlYW1AZ25v
+bWUub3JnPokCTgQTAQgAOBYhBKE065L4wSlBNu1a1EZc+7lq3wZXBQJboQQLAhsD
+BQsJCAcCBhUICQoLAgQWAgMBAh4BAheAAAoJEEZc+7lq3wZX0iQP/i8bw8x7LrKm
++2SxSBh900v+gtM0Ev/I0a6arSnDy+RYrLTOmG3E5sjtUosuOALIWnBQuIY8fgJv
+dw/ezzx71Vg8Ztuhav5OmN3dnV/HYNXHVisGnGQd09duY/WAK1qyyxZlnX8z3C8s
++AZUX15BNPFjJTHGuoQzBxlCtJHZSyw7TlXaHWl7TunB85O30kgAAA52cDjYdEmm
+x9IjPBmdBlpR0WZf7BxW3pnFsRdH1+J7UTbzum5WLgu+QXVnTA2bBY2fTOqlgjLS
+lBQjp/iXRM33H45HJJKAxpNiC4JZTeO68/hmnBIdKF182b/2URfIY4lgBnglffdm
+IH9EoKmThXktwOfjUeivsTO+BTpsHKzQ9HNLFJ5FE8qgAdtN4GhHHGA8wapG774I
+OOPhbGHa88LiMLkCQJmj8JBmag77SHz0jMyRDnEfWj+d3tscfJcU3ePP/Aet+1IK
+cWdcyPrzhgYYbzhZzCsKrTpZRa0XDMfb6hzuRVZdt+fX2xiNWcx5UHvpGa7dHork
+WmRlBUVTO0G6yAUKNRZ5fBk4Jt5Uh/aAXBOf4D4uC5sy3OHLL0oG/oRhT7lPwMTX
+NnblEwZgPFDcqGUYSLUFOKyDHqu04hVrzwKgOE4fUBJv4AKtWiEnmPEvEAANe0kK
+hrMbt8BZCpPMnrfB0HohI+KXIfiQAjLv
+=MJcD
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/files/vm/ostree-config/gnome.conf.in b/files/vm/ostree-config/gnome.conf.in
new file mode 100644
index 00000000..2732f205
--- /dev/null
+++ b/files/vm/ostree-config/gnome.conf.in
@@ -0,0 +1,4 @@
+[remote "GnomeOS"]
+url=OSTREE_REMOTE_URL
+gpg-verify=true
+gpgkeypath=/etc/pki/ostree/gnome.gpg
diff --git a/files/vm/ostree-config/ostree.conf b/files/vm/ostree-config/ostree.conf
new file mode 100644
index 00000000..a8531636
--- /dev/null
+++ b/files/vm/ostree-config/ostree.conf
@@ -0,0 +1,4 @@
+d /var/log/journal 0755 root root -
+L /var/home - - - - ../sysroot/home
+d /var/roothome 0700 root root -
+d /run/media 0755 root root -
diff --git a/plugins/collect_initial_scripts.py b/plugins/collect_initial_scripts.py
new file mode 100644
index 00000000..fe3b346d
--- /dev/null
+++ b/plugins/collect_initial_scripts.py
@@ -0,0 +1,55 @@
+import os
+import re
+from buildstream import Element, ElementError, Scope
+
+class ExtractInitialScriptsElement(Element):
+    def configure(self, node):
+        self.node_validate(node, [
+            'path',
+        ])
+
+        self.path = self.node_subst_member(node, 'path')
+
+    def preflight(self):
+        runtime_deps = list(self.dependencies(Scope.RUN, recurse=False))
+        if runtime_deps:
+            raise ElementError("{}: Only build type dependencies supported by collect-integration elements"
+                               .format(self))
+
+        sources = list(self.sources())
+        if sources:
+            raise ElementError("{}: collect-integration elements may not have sources".format(self))
+
+    def get_unique_key(self):
+        key = {
+            'path': self.path,
+        }
+        return key
+
+    def configure_sandbox(self, sandbox):
+        pass
+
+    def stage(self, sandbox):
+        pass
+
+    def assemble(self, sandbox):
+        basedir = sandbox.get_directory()
+        path = os.path.join(basedir, self.path.lstrip(os.sep))
+        index = 0
+        for dependency in self.dependencies(Scope.BUILD):
+            public = dependency.get_public_data('initial-script')
+            if public and 'script' in public:
+                script = self.node_subst_member(public, 'script')
+                index += 1
+                depname = re.sub('[^A-Za-z0-9]', '_', dependency.name)
+                basename = '{:03}-{}'.format(index, depname)
+                filename = os.path.join(path, basename)
+                os.makedirs(path, exist_ok=True)
+                with open(filename, 'w') as f:
+                    f.write(script)
+                os.chmod(filename, 0o755)
+
+        return os.sep
+
+def setup():
+    return ExtractInitialScriptsElement
diff --git a/plugins/ostree_mirror.py b/plugins/ostree_mirror.py
new file mode 100644
index 00000000..bac84ab3
--- /dev/null
+++ b/plugins/ostree_mirror.py
@@ -0,0 +1,120 @@
+import os
+import shutil
+import gi
+gi.require_version('OSTree', '1.0')
+gi.require_version('Gio', '2.0')
+from gi.repository import OSTree, Gio, GLib
+from buildstream import Source, SourceError, Consistency
+from buildstream import utils
+import collections
+import fnmatch
+
+class OSTreeMirrorSource(Source):
+
+    def configure(self, node):
+        self.node_validate(node, ['match', 'path', 'url', 'ref', 'gpg'] + Source.COMMON_CONFIG_KEYS)
+
+        self.original_url = self.node_get_member(node, str, 'url', None)
+        if self.original_url:
+            self.url = self.translate_url(self.original_url)
+        else:
+            path = self.node_get_project_path(node, 'path')
+            fullpath = os.path.join(self.get_project_directory(), path)
+            self.url = self.original_url = 'file://{}'.format(fullpath)
+        self.ref = self.node_get_member(node, list, 'ref', None)
+        if self.ref is not None:
+            for r in self.ref:
+                self.node_validate(r, ['ref', 'checksum'])
+        self.mirror = os.path.join(self.get_mirror_directory(),
+                                   utils.url_directory_name(self.original_url))
+
+        gpg = self.node_get_project_path(node, 'gpg')
+        self.gpg = os.path.join(self.get_project_directory(), gpg)
+        self.match = self.node_get_member(node, str, 'match', None)
+
+        self.repo = OSTree.Repo.new(Gio.File.new_for_path(self.mirror))
+        if os.path.isdir(self.mirror):
+            self.repo.open()
+        else:
+            os.makedirs(self.mirror)
+            self.repo.create(OSTree.RepoMode.ARCHIVE)
+            self.repo.remote_add('origin', self.url, None, None)
+
+        gpgfile = Gio.File.new_for_path(self.gpg)
+        self.repo.remote_gpg_import('origin', gpgfile.read(None), None, None)
+
+    def preflight(self):
+        pass
+
+    def get_unique_key(self):
+        return [self.original_url, sorted(self.ref, key=lambda x: x['ref'])]
+
+    def load_ref(self, node):
+        self.ref = self.node_get_member(node, list, 'ref', None)
+        if self.ref is not None:
+            for r in self.ref:
+                self.node_validate(r, ['ref', 'checksum'])
+
+    def get_ref(self):
+        return self.ref
+
+    def set_ref(self, ref, node):
+        node['ref'] = self.ref = ref
+
+    def track(self):
+        self.repo.pull('origin', None,
+                       OSTree.RepoPullFlags.MIRROR,
+                       None, None)
+
+        found, refs = self.repo.remote_list_refs('origin')
+        kept_refs = []
+        for ref, checksum in sorted(refs.items(), key = lambda x: x[0]):
+            if not self.match or fnmatch.fnmatch(ref, self.match):
+                kept_refs.append({'ref': ref, 'checksum': checksum})
+
+        return kept_refs
+
+    def _refs(self):
+        for r in self.ref:
+            ref = r['ref']
+            checksum = r['checksum']
+            yield ref, checksum
+
+    def fetch(self):
+        to_fetch = []
+        for _, checksum in self._refs():
+            found, _ = self.repo.resolve_rev(checksum, False)
+            if not found:
+                to_fetch.append(checksum)
+
+        if to_fetch:
+            self.repo.pull('origin', [to_fetch],
+                           OSTree.RepoPullFlags.MIRROR,
+                           None, None)
+
+    def stage(self, directory):
+        local_repo = OSTree.Repo.new(Gio.File.new_for_path(directory))
+        local_repo.create(OSTree.RepoMode.ARCHIVE)
+
+        refs = GLib.Variant("as", [checksum for _, checksum in self._refs()])
+        options = GLib.Variant("a{sv}", {
+            'refs': refs,
+        })
+
+        local_repo.pull_with_options('file://{}'.format(self.mirror),
+                                     options, None)
+        for ref, checksum in self._refs():
+            local_repo.set_ref_immediate(None, ref, checksum, None)
+
+    def get_consistency(self):
+        if self.ref is None:
+            return Consistency.INCONSISTENT
+
+        for _, checksum in self._refs():
+            found, _ = self.repo.resolve_rev(checksum, False)
+            if not found:
+                return Consistency.RESOLVED
+        return Consistency.CACHED
+
+def setup():
+    return OSTreeMirrorSource
diff --git a/project.conf b/project.conf
index 54cca149..c20d1695 100644
--- a/project.conf
+++ b/project.conf
@@ -32,6 +32,13 @@ options:
     - i686
     - x86_64
 
+  repo_mode:
+    type: enum
+    description: Which remote repository should the bootable image use
+    default: nightly
+    values:
+    - nightly
+    - local
 
 # Source aliases.
 #
@@ -205,6 +212,7 @@ shell:
 
 variables:
   branch: master
+  ostree-branch: "gnome-os/%{arch}/%{branch}"
   gcc_arch: "%{arch}"
   abi: "gnu"
   gcc_triplet: "%{gcc_arch}-linux-%{abi}"
@@ -228,6 +236,12 @@ variables:
     - arch == "arm":
         abi: "gnueabihf"
 
+    - repo_mode == 'local':
+        # This is the default address to the host using QEMU user netdev
+        ostree-remote-url: "http://10.0.2.2:8000/";
+    - repo_mode == 'nightly':
+        ostree-remote-url: "https://nightly.gnome.org/gnomeos/repo";
+
   # This should eventually done with buildstream includes
   strip-binaries: |
     touch source-files
@@ -284,3 +298,9 @@ plugins:
   sources:
     cargo: 0
     git_tag: 1
+- origin: local
+  path: plugins
+  elements:
+    collect_initial_scripts: 0
+  sources:
+    ostree_mirror: 0
diff --git a/utils/build-image.sh b/utils/build-image.sh
new file mode 100755
index 00000000..e18f935e
--- /dev/null
+++ b/utils/build-image.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+set -eu
+
+: ${REPO_MODE:=local}
+export BST="${BST:-bst} -o repo_mode ${REPO_MODE}"
+
+if [ "${REPO_MODE}" = local ]; then
+    ./utils/update-local-repo.sh
+fi
+
+${BST} track vm/image.bst
+${BST} build vm/image.bst
+${BST} checkout vm/image.bst image
diff --git a/utils/run-local-repo.sh b/utils/run-local-repo.sh
new file mode 100755
index 00000000..7ac3bf85
--- /dev/null
+++ b/utils/run-local-repo.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+exec python3 -m http.server 8000 --directory ostree-repo
diff --git a/utils/update-local-repo.sh b/utils/update-local-repo.sh
new file mode 100755
index 00000000..ce534f08
--- /dev/null
+++ b/utils/update-local-repo.sh
@@ -0,0 +1,37 @@
+#!/bin/bash
+
+set -eu
+
+export BST="${BST:-bst} -o repo_mode local"
+
+ref="$(${BST} show --format "%{vars}" --deps none vm/repo.bst | sed '/ostree-branch: /{;s///;q;};d')"
+
+
+
+if ! [ -d ostree-gpg ]; then
+    rm -rf ostree-gpg.tmp
+    mkdir ostree-gpg.tmp
+    chmod 0700 ostree-gpg.tmp
+    cat >ostree-gpg.tmp/key-config <<EOF
+Key-Type: DSA
+Key-Length: 1024
+Subkey-Type: ELG-E
+Subkey-Length: 1024
+Name-Real: Gnome OS
+Expire-Date: 0
+%no-protection
+%commit
+%echo finished
+EOF
+    gpg --batch --homedir=ostree-gpg.tmp --generate-key ostree-gpg.tmp/key-config
+    gpg --homedir=ostree-gpg.tmp -k --with-colons | sed '/^fpr:/q;d' | cut -d: -f10 
ostree-gpg.tmp/default-id
+    gpg --homedir=ostree-gpg.tmp --export --armor >local.gpg
+    mv ostree-gpg.tmp ostree-gpg
+fi
+
+utils/update-repo.sh \
+    --gpg-homedir=ostree-gpg \
+    --gpg-sign="$(cat ostree-gpg/default-id)" \
+    --collection-id=org.gnome.GnomeOS \
+    ostree-repo vm/repo.bst \
+    "${ref}"
diff --git a/utils/update-repo.sh b/utils/update-repo.sh
new file mode 100755
index 00000000..2e5b2b1a
--- /dev/null
+++ b/utils/update-repo.sh
@@ -0,0 +1,108 @@
+#!/bin/bash
+
+set -eu
+
+gpg_opts=()
+main_opts=()
+
+help() {
+    cat <<EOF
+$0 [OPTIONS] REPO ELEMENT REF
+EOF
+}
+
+while [ $# -gt 0 ]; do
+    case "$1" in
+       --gpg-*=*)
+           gpg_opts+=("$1")
+           ;;
+       --gpg-*)
+           gpg_opts+=("$1", "$2")
+           shift
+           ;;
+       --collection-id=*)
+           collection_id="${1#--collection-id=}"
+           ;;
+       --collection-id)
+           collection_id="${2}"
+           shift
+           ;;
+       --help)
+           help
+           exit 0
+           ;;
+       --)
+           main_opts+=("$@")
+           shift $(($#-1))
+           ;;
+       --*)
+           echo "Unknown option '$1'" 1>&2
+           exit 1
+           ;;
+       -*)
+           for ((i=1;$i < ${#1};++i)); do
+               case "${1:i}" in
+                   h)
+                       help
+                       exit 0
+                       ;;
+                   *)
+                       echo "Unknown option '${1:i}'" 1>&2
+                       exit 1
+                       ;;
+               esac
+           done
+           ;;
+       *)
+           main_opts+=("$1")
+           ;;
+    esac
+    shift
+done
+
+if [ ${#main_opts[*]} -ne 3 ]; then
+    echo "Wrong number of parameters" 1>&2
+    exit 1
+fi
+
+OSTREE_REPO="${main_opts[0]}"
+export OSTREE_REPO
+element="${main_opts[1]}"
+ref="${main_opts[2]}"
+
+checkout="$(mktemp --suffix="-update-repo" -d -p "$(dirname ${OSTREE_REPO})")"
+
+on_exit() {
+    rm -rf "${checkout}"
+}
+trap on_exit EXIT
+
+${BST:-bst} build "${element}"
+${BST:-bst} checkout --hardlinks "${element}" "${checkout}"
+
+if ! [ -d ${OSTREE_REPO} ]; then
+    ostree init --repo=${OSTREE_REPO} --mode=archive
+fi
+
+commit="$(ostree --repo="${checkout}/ostree/repo" rev-parse "${ref}")"
+ostree pull-local "${checkout}/ostree/repo" "${commit}"
+
+prev_commit="$(ostree rev-parse "${ref}" 2>/dev/null || true)"
+
+ostree commit ${gpg_opts[*]} \
+       --branch="${ref}" --tree=ref="${commit}" --skip-if-unchanged
+
+new_commit="$(ostree rev-parse "${ref}")"
+
+if [ "${new_commit}" != "${prev_commit}" ]; then
+    ostree prune --refs-only --keep-younger-than="6 months ago"
+
+    if [ -n "${prev_commit}" ]; then
+        ostree static-delta generate "${ref}"
+    fi
+
+    ostree summary \
+           ${collection_id:+--add-metadata=ostree.deploy-collection-id='"'"${collection_id}"'"'} \
+           ${gpg_opts[*]} \
+           --update
+fi


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]