From 8a3289bdac8dbb97324ceffb0b3198397d4c4143 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Louis-Francis=20Ratt=C3=A9-Boulianne?= <lfrb@collabora.com>
Date: Sat, 10 Dec 2016 22:15:02 -0500
Subject: [PATCH] Add export command to create application bundles
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Louis-Francis Ratté-Boulianne <lfrb@collabora.com>

Differential Revision: https://phabricator.apertis.org/D5230
---
 doc/man/ade-export.1 | 37 +++++++++++++++++++++
 doc/man/ade.1        |  8 +++++
 tools/ade            | 77 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 122 insertions(+)
 create mode 100644 doc/man/ade-export.1

diff --git a/doc/man/ade-export.1 b/doc/man/ade-export.1
new file mode 100644
index 0000000..7315f60
--- /dev/null
+++ b/doc/man/ade-export.1
@@ -0,0 +1,37 @@
+.TH ADE\-EXPORT 1 09/12/2016 0.1612.0 Apertis\ Development\ Tools\ Manual
+
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+
+.SH NAME
+
+ade-export \- Export project to application bundle
+
+.SH SYNOPSIS
+.sp
+.nf
+\fIade export\fR [--dest=<directory>]
+.fi
+.sp
+.SH DESCRIPTION
+.sp
+Create an application bundle from the project in the current directory\&. The
+bundle will be named \fB<bundle\-id>\-<version>\&.bundle\fR\&.
+.sp
+.SH OPTIONS
+.sp
+.PP
+\fI\-\-dest\fR
+.RS 4
+Directory where the bundle will be saved\&.
+.sp
+.RE
+.SH SEE ALSO
+
+ade(1)
+
+.SH COPYRIGHT
+
+Copyright (c) 2016 Collabora Ltd.
diff --git a/doc/man/ade.1 b/doc/man/ade.1
index c3abccf..ceeff6f 100644
--- a/doc/man/ade.1
+++ b/doc/man/ade.1
@@ -69,6 +69,14 @@ Build the project for simulator or target device\&.
 See \fBade-build(1)\fR
 .sp
 .RE
+.PP
+\fIexport\fR
+.RS 4
+Export application to application bundle\&.
+.sp
+See \fBade-export(1)\fR
+.sp
+.RE
 .SH SEE ALSO
 
 ade-sysroot(1)
diff --git a/tools/ade b/tools/ade
index fcd18a7..862f99f 100755
--- a/tools/ade
+++ b/tools/ade
@@ -58,6 +58,14 @@ class SysrootManagerError(Exception):
         return self.message
 
 
+class InvalidBundleError(Exception):
+    def __init__(self, message=''):
+        self.message = message
+
+    def __str__(self):
+        return self.message
+
+
 class InvalidDeviceError(Exception):
     def __init__(self, message):
         self.message = message
@@ -669,6 +677,12 @@ class Project:
         p = subprocess.Popen(args, cwd=self.root, env=env)
         p.wait()
 
+    def make(self, target='all', env=dict()):
+        if not self.is_configured():
+            raise NotConfiguredError
+        p = subprocess.Popen(['make', target], cwd=self.root, env=env)
+        p.wait()
+
     def build(self, verbose=False):
         if not self.is_configured():
             raise NotConfiguredError
@@ -678,6 +692,12 @@ class Project:
         p = subprocess.Popen(args, cwd=self.root)
         p.wait()
 
+    def install(self, path=None):
+        env = os.environ.copy()
+        if path:
+            env['DESTDIR'] = path
+        self.make('install', env)
+
     def set_pkg_config_vars(self, env, sysroot):
         def join_paths(paths):
             triplet = TargetTriplet(sysroot.version.arch).triplet
@@ -707,6 +727,48 @@ class Project:
         env['PKG_CONFIG_SYSROOT_DIR'] = join_paths(pkgconfig_sysroot)
 
 
+class Bundle:
+
+    def __init__(self, path, bundle_id=None, version=None):
+        self.path = path
+        self.id = bundle_id
+        self.version = version
+
+    def from_project(project, destdir=None):
+        if destdir:
+            destdir = os.path.expanduser(destdir)
+        else:
+            destdir = os.getcwd()
+        filename = "{0}-{1}.bundle".format(project.bundle_id, project.version)
+        path = os.path.join(destdir, filename)
+        bundle = Bundle(path, project.bundle_id, project.version)
+
+        with tempfile.TemporaryDirectory() as tmpdir:
+            bundledir = os.path.join(tmpdir, 'bundle')
+            repodir = os.path.join(tmpdir, 'repo')
+            os.makedirs(bundledir)
+
+            with open(os.path.join(bundledir, 'metadata'), 'w') as f:
+                f.write("[Application]\n")
+                f.write("name={0}\n".format(bundle.id))
+                f.write("X-Apertis-BundleVersion={0}".format(bundle.version))
+            os.makedirs(os.path.join(bundledir, 'export'))
+            os.makedirs(os.path.join(bundledir, 'files'))
+            project.install(os.path.join(bundledir, 'files'))
+
+            cmd = ['flatpak', 'build-export', repodir, bundledir]
+            ret = subprocess.run(cmd)
+            if ret.returncode:
+                sys.exit(ret.returncode)
+
+            cmd = ['flatpak', 'build-bundle', repodir, bundle.path, bundle.id]
+            ret = subprocess.run(cmd)
+            if ret.returncode:
+                sys.exit(ret.returncode)
+
+        return bundle
+
+
 class Ade:
 
     def __init__(self):
@@ -1065,6 +1127,17 @@ class Ade:
         except NotConfiguredError:
             self.die("Project is not configured; run 'configure' command first")
 
+    def do_export(self):
+        try:
+            project = Project()
+            bundle = Bundle.from_project(project, self.dest)
+        except NotConfiguredError:
+            self.die("Project is not configured; run 'configure' command first")
+        except InvalidProjectError as e:
+            self.die("Invalid project: {0}".format(e))
+        except Exception as e:
+            self.die("Couldn't create bundle: {0}".format(e))
+
     def info(self, message):
         if self.format == 'friendly':
             print(message)
@@ -1154,6 +1227,10 @@ if __name__ == '__main__':
     build_parser.add_argument('--verbose', help="Verbose output", action='store_true')
     build_parser.add_argument('args', help="Configure options", nargs=argparse.REMAINDER)
 
+    # Export parser
+    export_parser = subparsers.add_parser('export', help="Create an application bundle")
+    export_parser.add_argument('--dest',  help="Bundle destination directory")
+
     argcomplete.autocomplete(root_parser)
 
     obj = Ade()
-- 
GitLab