1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3# 4# Copyright © 2018 Thibault Saunier <tsaunier@igalia.com> 5# 6# This library is free software; you can redistribute it and/or modify it under 7# the terms of the GNU Lesser General Public License as published by the Free 8# Software Foundation; either version 2.1 of the License, or (at your option) 9# any later version. 10# 11# This library is distributed in the hope that it will be useful, but WITHOUT 12# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 13# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 14# details. 15# 16# You should have received a copy of the GNU Lesser General Public License 17# along with this library. If not, see <http://www.gnu.org/licenses/>. 18 19import argparse 20import json 21import os 22import sys 23import re 24import subprocess 25import tempfile 26 27from collections import OrderedDict 28try: 29 from collections.abc import Mapping 30except ImportError: # python <3.3 31 from collections import Mapping 32 33 34# Marks values in the json file as "unstable" so that they are 35# not updated automatically, this aims at making the cache file 36# stable and handle corner cases were we can't automatically 37# make it happen. For properties, the best way is to use th 38# GST_PARAM_DOC_SHOW_DEFAULT flag. 39UNSTABLE_VALUE = "unstable-values" 40 41 42 43def dict_recursive_update(d, u): 44 modified = False 45 unstable_values = d.get(UNSTABLE_VALUE, []) 46 if not isinstance(unstable_values, list): 47 unstable_values = [unstable_values] 48 for k, v in u.items(): 49 if isinstance(v, Mapping): 50 r = d.get(k, {}) 51 modified |= dict_recursive_update(r, v) 52 d[k] = r 53 elif k not in unstable_values: 54 modified = True 55 if k == "package": 56 d[k] = re.sub(" git$| source release$| prerelease$", "", v) 57 else: 58 d[k] = u[k] 59 return modified 60 61 62def test_unstable_values(): 63 current_cache = { "v1": "yes", "unstable-values": "v1"} 64 new_cache = { "v1": "no" } 65 66 assert(dict_recursive_update(current_cache, new_cache) == False) 67 68 new_cache = { "v1": "no", "unstable-values": "v2" } 69 assert(dict_recursive_update(current_cache, new_cache) == True) 70 71 current_cache = { "v1": "yes", "v2": "yay", "unstable-values": "v1",} 72 new_cache = { "v1": "no" } 73 assert(dict_recursive_update(current_cache, new_cache) == False) 74 75 current_cache = { "v1": "yes", "v2": "yay", "unstable-values": "v2"} 76 new_cache = { "v1": "no", "v2": "unstable" } 77 assert (dict_recursive_update(current_cache, new_cache) == True) 78 assert (current_cache == { "v1": "no", "v2": "yay", "unstable-values": "v2" }) 79 80if __name__ == "__main__": 81 cache_filename = sys.argv[1] 82 output_filename = sys.argv[2] 83 build_root = os.environ.get('MESON_BUILD_ROOT', '') 84 85 subenv = os.environ.copy() 86 cache = {} 87 try: 88 with open(cache_filename, newline='\n', encoding='utf8') as f: 89 cache = json.load(f) 90 except FileNotFoundError: 91 pass 92 93 out = output_filename + '.tmp' 94 cmd = [os.path.join(os.path.dirname(os.path.realpath(__file__)), 'gst-hotdoc-plugins-scanner'), out] 95 gst_plugins_paths = [] 96 for plugin_path in sys.argv[3:]: 97 cmd.append(plugin_path) 98 gst_plugins_paths.append(os.path.dirname(plugin_path)) 99 100 try: 101 with open(os.path.join(build_root, 'GstPluginsPath.json'), newline='\n', encoding='utf8') as f: 102 plugin_paths = os.pathsep.join(json.load(f)) 103 except FileNotFoundError: 104 plugin_paths = "" 105 106 if plugin_paths: 107 subenv['GST_PLUGIN_PATH'] = subenv.get('GST_PLUGIN_PATH', '') + ':' + plugin_paths 108 109 # Hide stderr unless an actual error happens as we have cases where we get g_warnings 110 # and other issues because plugins are being built while `gst_init` is called 111 stderrlogfile = output_filename + '.stderr' 112 with open(stderrlogfile, 'w', encoding='utf8') as log: 113 try: 114 data = subprocess.check_output(cmd, env=subenv, stderr=log, encoding='utf8', universal_newlines=True) 115 except subprocess.CalledProcessError as e: 116 log.flush() 117 with open(stderrlogfile, 'r', encoding='utf8') as f: 118 print(f.read(), file=sys.stderr) 119 raise 120 121 with open(out, 'r', newline='\n', encoding='utf8') as jfile: 122 try: 123 plugins = json.load(jfile, object_pairs_hook=OrderedDict) 124 except json.decoder.JSONDecodeError: 125 print("Could not decode:\n%s" % jfile.read(), file=sys.stderr) 126 raise 127 128 modified = dict_recursive_update(cache, plugins) 129 130 with open(output_filename, 'w', newline='\n', encoding='utf8') as f: 131 json.dump(cache, f, indent=4, sort_keys=True, ensure_ascii=False) 132 133 if modified: 134 with open(cache_filename, 'w', newline='\n', encoding='utf8') as f: 135 json.dump(cache, f, indent=4, sort_keys=True, ensure_ascii=False) 136