Skip to content

Instantly share code, notes, and snippets.

@asac
Created Jan 6, 2016
Embed
What would you like to do?
snapcraft kbuild discussion
diff --git a/examples/busybox/icon.png b/examples/busybox/icon.png
new file mode 100644
index 0000000..05b7f56
Binary files /dev/null and b/examples/busybox/icon.png differ
diff --git a/examples/busybox/snapcraft.yaml b/examples/busybox/snapcraft.yaml
new file mode 100644
index 0000000..93d8528
--- /dev/null
+++ b/examples/busybox/snapcraft.yaml
@@ -0,0 +1,17 @@
+name: busybox
+version: 1.0
+summary: busybox example to showcase the snapcraft kbuild plugin
+description: this is a snapcraft example package that contains the output of the snapcraft busybox example.
+icon: icon.png
+
+binaries:
+ ls:
+ exec: bin/ls
+
+parts:
+ busybox:
+ plugin: kbuild
+ source: git://github.com/asac/busybox
+ snap:
+ - bin/*
+
diff --git a/snapcraft/__init__.py b/snapcraft/__init__.py
index 2595ad2..1e61570 100644
--- a/snapcraft/__init__.py
+++ b/snapcraft/__init__.py
@@ -262,6 +262,14 @@ class BasePlugin:
os.makedirs(cwd, exist_ok=True)
return common.run(cmd, cwd=cwd, **kwargs)
+ def run_raw(self, cmd, cwd=None, **kwargs):
+ if cwd is None:
+ cwd = self.builddir
+ if True:
+ print(' '.join(cmd))
+ os.makedirs(cwd, exist_ok=True)
+ return common.run_raw(cmd, cwd=cwd, **kwargs)
+
def run_output(self, cmd, cwd=None, **kwargs):
if cwd is None:
cwd = self.builddir
diff --git a/snapcraft/common.py b/snapcraft/common.py
index aadad7e..632f838 100644
--- a/snapcraft/common.py
+++ b/snapcraft/common.py
@@ -49,6 +49,16 @@ def run(cmd, **kwargs):
f.flush()
subprocess.check_call(['/bin/sh', f.name] + cmd, **kwargs)
+def run_raw(cmd, **kwargs):
+ assert isinstance(cmd, list), 'run command must be a string'
+ # FIXME: This is gross to keep writing this, even when env is the same
+ with tempfile.NamedTemporaryFile(mode='w+') as f:
+ f.write(assemble_env())
+ f.write('\n')
+ f.write(' '.join(cmd)+'\n')
+ f.flush()
+ subprocess.check_call(['/bin/sh', f.name], **kwargs)
+
def run_output(cmd, **kwargs):
assert isinstance(cmd, list), 'run command must be a list'
diff --git a/snapcraft/plugins/kbuild.py b/snapcraft/plugins/kbuild.py
new file mode 100644
index 0000000..cee43af
--- /dev/null
+++ b/snapcraft/plugins/kbuild.py
@@ -0,0 +1,103 @@
+# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
+#
+# Copyright (C) 2015 Canonical Ltd
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 3 as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+"""The kbuild plugin is used for building kbuild based projects as snapcraft
+parts.
+
+The plugin applies your selected defconfig first by running
+
+ make defconfig
+
+and then uses the kconfigs flag to augment the resulting config by prepending
+the configured kconfigs values to the .config and running
+
+ "yes" "" | make oldconfig
+
+to create an updated .config file.
+
+If kconfigfile is provided this plugin will use the provided config file wholesale
+as the starting point instead of make $defconfig. In case user configures both a
+kdefconfig as well as kconfigfile, kconfigfile approach will be used.
+
+"""
+
+import os
+import snapcraft
+
+
+class KBuildPlugin(snapcraft.BasePlugin):
+
+ @classmethod
+ def schema(cls):
+ schema = super().schema()
+
+ schema['properties']['kdefconfig'] = {
+ 'type': 'string',
+ 'default': 'defconfig',
+ }
+
+ schema['properties']['kconfigfile'] = {
+ 'type': 'string',
+ 'default': '',
+ }
+
+ schema['properties']['kconfigs'] = {
+ 'type': 'array',
+ 'minitems': 1,
+ 'uniqueItems': True,
+ 'items': {
+ 'type': 'string',
+ },
+ 'default': [],
+ }
+
+ return schema
+
+ def __init__(self, name, options):
+ super().__init__(name, options)
+ self.build_packages.extend([
+ 'make',
+ ])
+
+ def build(self):
+ super().build()
+ config = ""
+ configpath = os.path.join(self.builddir, ".config")
+
+ # first run defconfig for setting baseline
+ if not os.path.exists(configpath):
+ self.run(['make', self.options.kdefconfig])
+
+ with open(os.path.join(self.builddir, ".config"), "r") as f:
+ config=f.read()
+ f.close()
+
+ for kconfig in self.options.kconfigs:
+ config=config+"\n"+kconfig
+
+ with open(os.path.join(self.builddir, ".config"), "w") as f:
+ f.write(config)
+ f.close()
+
+ # update config to include kconfig amendments
+ self.run_raw(['\"yes\"', '\"\"', '|' 'make', 'oldconfig'])
+
+ # build the software
+ self.run(['make'])
+
+ # install to installdir
+ self.run(['make', 'CONFIG_PREFIX='+self.installdir, 'install'])
+
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment