diff flatpak/build_manifest.py @ 139:d36a68e396d5

flatpak: set appdata release version for dev version: appdata file can now use a template (which has the same name with "_tpl_" prefix), which is used in dev version to automatically set the release with the right Mercurial revision/date. Comment from org.salutatoi.Cagou.appdata.xml has been moved as first child of <component>, so it is not lost while parsing the file.
author Goffi <goffi@goffi.org>
date Sun, 23 Jun 2019 17:34:10 +0200
parents 274af514a5cf
children e23e414987d7
line wrap: on
line diff
--- a/flatpak/build_manifest.py	Sat Jun 22 15:59:07 2019 +0200
+++ b/flatpak/build_manifest.py	Sun Jun 23 17:34:10 2019 +0200
@@ -8,6 +8,7 @@
 import hashlib
 from ftplib import FTP
 from urllib.parse import urlparse
+from textwrap import dedent
 import sys
 import os
 import json
@@ -16,6 +17,7 @@
 import shutil
 from packaging.version import parse as parse_version
 import requests
+from lxml import etree
 
 
 CACHE_LIMIT = 3600 * 24
@@ -85,6 +87,11 @@
 }
 SHOW_REQUIRES_HEADER = 'Requires: '
 SETTINGS_KEY = '_build_settings'
+APPDATA_RELEASE_DEV_TEXT = dedent("""\
+    This is a development version, used as a preview.
+    Please note that it is incomplete and it probably contains bugs.
+    """)
+OVERWRITE_WARNING = "{} already exists, do you want to overwrite it (y/N)? "
 
 
 @dataclass
@@ -116,7 +123,7 @@
 
     # build group
     build_group.add_argument('-f', '--force', action="store_true",
-                        help="force overwritting of existing manifest")
+                        help="force overwritting of existing manifest and appdata file")
     build_group.add_argument('--ignore-cache', action='append', default=[],
                         help='ignore the cache of this step ("all" to ignore all caches)')
     build_group.add_argument(
@@ -365,7 +372,7 @@
         step_name = f"{stem}__{url}"
 
     if step_message is None:
-        step_messate = f"generating module for {stem}"
+        step_message = f"generating module for {stem}"
 
     print_step(step_message)
     cache = get_cache(step_name)
@@ -447,6 +454,21 @@
     deps.append(package)
 
 
+def get_hg_id_date(path):
+    """Get short identifier and date of current commit from given Mercurial repository
+
+    version is retrieve with `hg id`, a "+" is appended after shortrev if it has
+    been modified.
+    @param path(str, Path): path to the repository
+    @return(tuple(str, date)): found revision + iso date
+    """
+    hg_cplted = subprocess.run(
+        ["hg",  "id", "--template", "{id|short}{dirty}\n{date|isodate}", path],
+        capture_output=True, text=True)
+    hg_cplted.check_returncode()
+    return hg_cplted.stdout.split('\n')
+
+
 def get_cache_dir():
     """Return path to directory to use for cache"""
     return Path(f"cache_{app_id}")
@@ -585,7 +607,6 @@
                           hash_=dep_hash,
                           url=version_json['url'],
                           requirements=requirements,
-                          # extra_requirements=extra_requirements,
                           )
 
             deps_map[name_canonical] = dep
@@ -792,10 +813,46 @@
         )
 
 
+def generate_appdata_from_template(template_file):
+    appdata_file = Path(f"{app_id}.appdata.xml")
+    if appdata_file.exists() and not args.force:
+        confirm = input(OVERWRITE_WARNING.format(appdata_file))
+        if confirm != 'y':
+            print("manifest building cancelled")
+            sys.exit(0)
+    parser = etree.XMLParser(remove_blank_text=True)
+    tree = etree.parse(template_file, parser)
+    root = tree.getroot()
+    if args.version == 'dev':
+        print("addind release data for dev version")
+        releases_elt = root.find('releases')
+        if releases_elt is None:
+            raise ValueError(
+                "<releases/> element is missing in appdata template, please add it")
+        release_elt = etree.SubElement(
+            releases_elt,
+            "release",
+            {'type': 'development',
+             'version': dev_version_rev,
+             'date': dev_version_date},
+        )
+        description_elt = etree.SubElement(release_elt, 'description')
+        text_lines = APPDATA_RELEASE_DEV_TEXT.strip().split('\n')
+        for text in text_lines:
+            etree.SubElement(description_elt, 'p').text = text
+        print(f"release data added for this version ({dev_version_rev})")
+
+    with open(appdata_file, "wb") as f:
+        f.write(etree.tostring(root, encoding="utf-8", xml_declaration=True,
+                               pretty_print=True))
+
+    return appdata_file.as_posix()
+
+
 def get_app_metadata():
     desktop_file = build_settings.get('desktop_file')
     appdata_file = build_settings.get('appdata_file')
-    if desktop_file is None and app_data_file is None:
+    if desktop_file is None and appdata_file is None:
         return
 
     print_step("retrieving application metadata")
@@ -811,6 +868,9 @@
             ))
 
     if appdata_file is not None:
+        if appdata_file.startswith('_tpl_'):
+            print("found appdata template, we now use it to generate the file")
+            appdata_file = generate_appdata_from_template(appdata_file)
         print("generating module for appdata metadata")
         data.extend(file_upload(
             filename = appdata_file,
@@ -833,8 +893,7 @@
     print(f"generating manifest for {app_id} ({args.version})")
 
     if package_file.exists() and not args.force:
-        confirm = input(
-            f"{package_file} already exists, do you want to overwritte it (y/N)? ")
+        confirm = input(OVERWRITE_WARNING.format(package_file))
         if confirm != 'y':
             print("manifest building cancelled")
             sys.exit(0)
@@ -852,9 +911,14 @@
     if "setup_requirements" in build_settings:
         PYTHON_SETUP_REQUIREMENTS.extend(build_settings["setup_requirements"])
     main_package = canonical(build_settings.get('package', args.name))
-    if args.version == 'dev' and 'dev_repos' in build_settings:
+    if args.version == 'dev':
+        if 'dev_repos' not in build_settings:
+            raise NotImplementedError(
+                "dev version can currently only be handled with a dev repostiory "
+                "(dev_repos)")
         dev_repos = build_settings['dev_repos']
         main_package_source = cache_from_repos()
+        dev_version_rev, dev_version_date = get_hg_id_date(main_package_source)
     else:
         main_package_source = main_package
 
@@ -903,7 +967,7 @@
     modules.extend(get_app_metadata())
 
     # now the app itself
-    if args.version == 'dev' and 'dev_repos' in build_settings:
+    if args.version == 'dev':
         # mercurial is needed for dev version to install but also to
         # retrieve revision used
         modules.extend(get_python_package("mercurial"))