diff options
Diffstat (limited to 'xbmc/addons/kodi-dev-kit/tools')
7 files changed, 889 insertions, 0 deletions
diff --git a/xbmc/addons/kodi-dev-kit/tools/code-generator/code_generator.py b/xbmc/addons/kodi-dev-kit/tools/code-generator/code_generator.py new file mode 100755 index 0000000..06cf810 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/tools/code-generator/code_generator.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# Copyright (C) 2021 Team Kodi +# This file is part of Kodi - https://kodi.tv +# +# SPDX-License-Identifier: GPL-2.0-or-later +# See LICENSES/README.md for more information. + +KODI_DIR = "../../../../../" +DEVKIT_DIR = "xbmc/addons/kodi-dev-kit" + +# Global includes +from optparse import OptionParser + +# Own includes +from src.commitChanges import * +from src.generateCMake__CMAKE_TREEDATA_COMMON_addon_dev_kit_txt import * +from src.generateCMake__XBMC_ADDONS_KODIDEVKIT_INCLUDE_KODI_allfiles import * +from src.helper_Log import * + +# =============================================================================== +def GenerateCMakeParts(options): + Log.PrintGroupStart("Generate cmake parts") + + # Generate Kodi's cmake system related include files to find related parts + GenerateCMake__XBMC_ADDONS_KODIDEVKIT_INCLUDE_KODI_all_files(options) + GenerateCMake__CMAKE_TREEDATA_COMMON_addon_dev_kit_txt(options) + + +# =============================================================================== +if __name__ == "__main__": + # parse command-line options + disc = """\ +This utility autogenerate the interface between Kodi and addon. +It is currently still in the initial phase and will be expanded in the future. +""" + parser = OptionParser(description=disc) + parser.add_option( + "-f", + "--force", + action="store_true", + dest="force", + default=False, + help="Force the generation of auto code", + ) + parser.add_option( + "-d", + "--debug", + action="store_true", + dest="debug", + default=False, + help="Add debug identifiers to generated files", + ) + parser.add_option( + "-c", + "--commit", + action="store_true", + dest="commit", + default=False, + help="Create automatic a git commit about API changes (WARNING: No hand edits should be present before!)", + ) + (options, args) = parser.parse_args() + + Log.Init(options) + Log.PrintMainStart(options) + + ##---------------------------------------------------------------------------- + # CMake generation + GenerateCMakeParts(options) + + ##---------------------------------------------------------------------------- + # Commit GIT changes generation (only makes work if '-c' option is used) + if options.commit: + Log.PrintGroupStart("Git update") + CommitChanges(options) diff --git a/xbmc/addons/kodi-dev-kit/tools/code-generator/src/commitChanges.py b/xbmc/addons/kodi-dev-kit/tools/code-generator/src/commitChanges.py new file mode 100644 index 0000000..896cca5 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/tools/code-generator/src/commitChanges.py @@ -0,0 +1,91 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2021 Team Kodi +# This file is part of Kodi - https://kodi.tv +# +# SPDX-License-Identifier: GPL-2.0-or-later +# See LICENSES/README.md for more information. + +# Own includes +from code_generator import DEVKIT_DIR, KODI_DIR +from .generateCMake__CMAKE_TREEDATA_COMMON_addon_dev_kit_txt import * +from .generateCMake__XBMC_ADDONS_KODIDEVKIT_INCLUDE_KODI_allfiles import * +from .helper_Log import * + +# Global includes +import importlib, os, subprocess + +git_found = importlib.find_loader("git") is not None +if git_found: + from git import Repo + + +def CommitChanges(options): + """ + Do a git commit of the automatically changed locations of the dev-kit. + """ + if not options.commit: + return + if not git_found: + Log.PrintFatal( + 'Needed "GitPython" module not present! To make commits need them be installed.' + ) + quit(1) + + Log.PrintBegin("Perform GIT update check") + Log.PrintResult(Result.SEE_BELOW) + + contains_devkit_change = False + contains_external_change = False + changes_list = [] + + # Hack place one to get also new added files + subprocess.run(["git", "add", "-A"], check=True, stdout=subprocess.PIPE).stdout + + r = Repo(KODI_DIR) + for x in r.index.diff("HEAD"): + if GenerateCMake__XBMC_ADDONS_KODIDEVKIT_INCLUDE_KODI_all_files_RelatedCheck( + x.b_path + ): + Log.PrintBegin(" - Changed file {}".format(x.b_path)) + contains_devkit_change = True + changes_list.append(x.b_path) + Log.PrintResult(Result.NEW if x.new_file else Result.UPDATE) + elif GenerateCMake__CMAKE_TREEDATA_COMMON_addon_dev_kit_txt_RelatedCheck( + x.b_path + ): + Log.PrintBegin(" - Changed file {}".format(x.b_path)) + contains_devkit_change = True + changes_list.append(x.b_path) + Log.PrintResult(Result.NEW if x.new_file else Result.UPDATE) + else: + Log.PrintBegin(" - Changed file {}".format(x.b_path)) + Log.PrintFollow(" (Not auto update related)") + Log.PrintResult(Result.IGNORED) + contains_external_change = True + + # Hack place two to reset about before + subprocess.run(["git", "reset", "HEAD"], check=True, stdout=subprocess.PIPE).stdout + + Log.PrintBegin("Perform GIT commit") + if contains_devkit_change: + # Add changed or added files to git + for x in changes_list: + r.index.add(x) + + commit_msg = ( + "[auto][addons] devkit script update ({})\n" + "\n" + "This commit automatic generated by script '{}/tools/code-generator.py'.\n" + "\n" + "{}".format( + datetime.utcnow().strftime("%d/%m/%Y %H:%M:%S"), + DEVKIT_DIR, + open(Log.log_file).read(), + ) + ) + r.index.commit(commit_msg) + Log.PrintFollow(" ( Commit SHA256: {})".format(str(r.head.reference.commit))) + Log.PrintResult(Result.OK) + else: + Log.PrintResult(Result.ALREADY_DONE) diff --git a/xbmc/addons/kodi-dev-kit/tools/code-generator/src/generateCMake__CMAKE_TREEDATA_COMMON_addon_dev_kit_txt.py b/xbmc/addons/kodi-dev-kit/tools/code-generator/src/generateCMake__CMAKE_TREEDATA_COMMON_addon_dev_kit_txt.py new file mode 100644 index 0000000..20ed447 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/tools/code-generator/src/generateCMake__CMAKE_TREEDATA_COMMON_addon_dev_kit_txt.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2021 Team Kodi +# This file is part of Kodi - https://kodi.tv +# +# SPDX-License-Identifier: GPL-2.0-or-later +# See LICENSES/README.md for more information. + +# Own includes +from code_generator import DEVKIT_DIR, KODI_DIR +from .helper_Log import * + +# Global includes +import glob, os, re + + +def GenerateCMake__CMAKE_TREEDATA_COMMON_addon_dev_kit_txt_RelatedCheck(filename): + """ + This function is called by git update to be able to assign changed files to the dev kit. + """ + return True if filename == "cmake/treedata/common/addon_dev_kit.txt" else False + + +def GenerateCMake__CMAKE_TREEDATA_COMMON_addon_dev_kit_txt(options): + """ + This function generate the "cmake/treedata/common/addon_dev_kit.txt" + by scan of related directories to use for addon interface build. + """ + gen_file = "cmake/treedata/common/addon_dev_kit.txt" + + Log.PrintBegin("Check for {}".format(gen_file)) + + scan_dir = "{}{}/include/kodi/**/CMakeLists.txt".format(KODI_DIR, DEVKIT_DIR) + parts = "# Auto generated {}.\n" "# See {}/tools/code-generator.py.\n\n".format( + gen_file, DEVKIT_DIR + ) + + for entry in glob.glob(scan_dir, recursive=True): + cmake_dir = entry.replace(KODI_DIR, "").replace("/CMakeLists.txt", "") + with open(entry) as search: + for line in search: + line = line.rstrip() # remove '\n' at end of line + m = re.search("^ *core_add_devkit_header\((.*)\)", line) + if m: + parts += "{} addons_kodi-dev-kit_include_{}\n".format( + cmake_dir, m.group(1) + ) + break + file = "{}{}".format(KODI_DIR, gen_file) + present = os.path.isfile(file) + if not present or parts != open(file).read() or options.force: + with open(file, "w") as f: + f.write(parts) + Log.PrintResult(Result.NEW if not present else Result.UPDATE) + else: + Log.PrintResult(Result.ALREADY_DONE) diff --git a/xbmc/addons/kodi-dev-kit/tools/code-generator/src/generateCMake__XBMC_ADDONS_KODIDEVKIT_INCLUDE_KODI_allfiles.py b/xbmc/addons/kodi-dev-kit/tools/code-generator/src/generateCMake__XBMC_ADDONS_KODIDEVKIT_INCLUDE_KODI_allfiles.py new file mode 100644 index 0000000..c1000be --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/tools/code-generator/src/generateCMake__XBMC_ADDONS_KODIDEVKIT_INCLUDE_KODI_allfiles.py @@ -0,0 +1,134 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2021 Team Kodi +# This file is part of Kodi - https://kodi.tv +# +# SPDX-License-Identifier: GPL-2.0-or-later +# See LICENSES/README.md for more information. + +# Own includes +from code_generator import DEVKIT_DIR, KODI_DIR +from .helper_Log import * + +# Global includes +import glob, os, re + + +def GenerateCMake__XBMC_ADDONS_KODIDEVKIT_INCLUDE_KODI_all_files_RelatedCheck(filename): + """ + This function is called by git update to be able to assign changed files to the dev kit. + """ + scan_dir = "{}{}/include/kodi/**/".format(KODI_DIR, DEVKIT_DIR) + dirs = sorted(glob.glob(scan_dir, recursive=True)) + for dir in dirs: + source_dir = "{}CMakeLists.txt".format(dir.replace(KODI_DIR, "")) + if source_dir == filename: + return True + + return False + + +def GenerateCMake__XBMC_ADDONS_KODIDEVKIT_INCLUDE_KODI_all_files(options): + """ + This function generate the "CMakeLists.txt" in xbmc/addons/kodi-dev-kit/include/kodi + and sub dirs by scan of available files + """ + Log.PrintBegin( + "Generate CMakeLists.txt files in {}/include/kodi dirs".format(DEVKIT_DIR) + ) + Log.PrintResult(Result.SEE_BELOW) + + scan_dir = "{}{}/include/kodi/**/".format(KODI_DIR, DEVKIT_DIR) + + found = False + dirs = sorted(glob.glob(scan_dir, recursive=True)) + for dir in dirs: + source_dir = dir.replace(KODI_DIR, "") + Log.PrintBegin(" - Check {}CMakeLists.txt".format(source_dir)) + + # Scan for *.h + os_limits = [] + header_configure = [] + header_entry = [] + src_parts = sorted(glob.glob("{}*.h*".format(dir), recursive=False)) + for src_part in src_parts: + with open(src_part) as search: + for line in search: + line = line.rstrip() # remove '\n' at end of line + m = re.search("^\/\*---AUTO_GEN_PARSE<\$\$(.*):(.*)>---\*\/", line) + if m: + if m.group(1) == "CORE_SYSTEM_NAME": + if src_part.endswith(".in"): + Log.PrintResult(Result.FAILURE) + Log.PrintFatal( + 'File extensions with ".h.in" are currently not supported and require revision of Kodi\'s cmake system!' + ) + exit(1) + """ + NOTE: This code currently unused. About ".in" support need Kodi's cmake build system revised. + code = '' + for entry in m.group(2).split(","): + label = 'CORE_SYSTEM_NAME STREQUAL {}'.format(entry) + code += 'if({}'.format(label) if code == '' else ' OR\n {}'.format(label) + code += ')\n' + code += ' configure_file(${{CMAKE_SOURCE_DIR}}/{}\n'.format(src_part.replace(KODI_DIR, '')) + code += ' ${{CORE_BUILD_DIR}}/{} @ONLY)\n'.format(src_part.replace(KODI_DIR, '').replace('.in', '')) + code += 'endif()' + header_configure.append(code) + """ + for entry in m.group(2).split(","): + entry = entry.strip() + if not entry in os_limits: + os_limits.append(entry) + header_entry.append( + "$<$<STREQUAL:${{CORE_SYSTEM_NAME}},{}>:{}>".format( + entry, + src_part.replace(dir, "").replace(".in", ""), + ) + ) + found = True + break + if not found: + header_entry.append(src_part.replace(dir, "")) + found = False + + if len(os_limits) > 0: + Log.PrintFollow( + " (Contains limited OS header: {})".format( + ", ".join(map(str, os_limits)) + ) + ) + + cmake_cfg_text = ( + "\n{}".format("".join("{}\n".format(entry) for entry in header_configure)) + if len(header_configure) > 0 + else "" + ) + cmake_hdr_text = "set(HEADERS\n{})\n".format( + "".join(" {}\n".format(entry) for entry in header_entry) + ) + cmake_part = ( + source_dir[len(DEVKIT_DIR + "/include_") :].replace("/", "_").rstrip("_") + ) # Generate cmake sub part name + + # Make final CMakeLists.txt + cmake_file = ( + "# Auto generated CMakeLists.txt.\n" + "# See {}/tools/code-generator.py.\n" + "{}" + "\n" + "{}" + "\n" + "if(HEADERS)\n" + " core_add_devkit_header({})\n" + "endif()\n".format(DEVKIT_DIR, cmake_cfg_text, cmake_hdr_text, cmake_part) + ) + + file = "{}CMakeLists.txt".format(dir) + present = os.path.isfile(file) + if not present or cmake_file != open(file).read() or options.force: + with open(file, "w") as f: + f.write(cmake_file) + Log.PrintResult(Result.NEW if not present else Result.UPDATE) + else: + Log.PrintResult(Result.ALREADY_DONE) diff --git a/xbmc/addons/kodi-dev-kit/tools/code-generator/src/helper_Log.py b/xbmc/addons/kodi-dev-kit/tools/code-generator/src/helper_Log.py new file mode 100644 index 0000000..6279afa --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/tools/code-generator/src/helper_Log.py @@ -0,0 +1,201 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2021 Team Kodi +# This file is part of Kodi - https://kodi.tv +# +# SPDX-License-Identifier: GPL-2.0-or-later +# See LICENSES/README.md for more information. + +from datetime import datetime +import os + + +class Result: + OK = 1 + FAILURE = 2 + UPDATE = 3 + ALREADY_DONE = 4 + NEW = 5 + SEE_BELOW = 6 + IGNORED = 7 + + +class Log: + log_file = "creation_log.txt" + current_cursor_pos = 0 + terminal_columns = 120 + + # Class of different styles + class style: + BOLD = "\033[01m" + BLACK = "\033[30m" + RED = "\033[31m" + GREEN = "\033[32m" + YELLOW = "\033[33m" + BLUE = "\033[34m" + MAGENTA = "\033[35m" + CYAN = "\033[36m" + WHITE = "\033[37m" + UNDERLINE = "\033[4m" + RESET = "\033[0m" + + def Init(options): + # Try to get terminal with, is optional and no matter if something fails + try: + columns, rows = os.get_terminal_size(0) + Log.terminal_columns = columns + except: + pass + + if os.path.isfile(Log.log_file): + os.rename(Log.log_file, Log.log_file + ".old") + + if options.debug: + print("DEBUG: Used command line options: {}".format(str(options))) + + with open(Log.log_file, "w") as f: + f.write("Used call options: {}\n".format(str(options))) + + def PrintMainStart(options): + print("┌{}┐".format("─" * (Log.terminal_columns - 2))) + text = "Auto generation of addon interface code" + print( + "│ {}{}{}{}{}│".format( + Log.style.BOLD, + Log.style.CYAN, + text, + Log.style.RESET, + " " * (Log.terminal_columns - len(text) - 3), + ) + ) + text = "Used options:" + print( + "│ {}{}{}{}{}{}│".format( + Log.style.BOLD, + Log.style.WHITE, + Log.style.UNDERLINE, + text, + Log.style.RESET, + " " * (Log.terminal_columns - len(text) - 3), + ) + ) + Log.__printUsedBooleanValueLine("force", options.force) + Log.__printUsedBooleanValueLine("debug", options.debug) + Log.__printUsedBooleanValueLine("commit", options.commit) + print("└{}┘".format("─" * (Log.terminal_columns - 2))) + + def PrintGroupStart(text): + print("─" * Log.terminal_columns) + print( + "{}{} ...{}{}".format( + Log.style.CYAN, + text, + " " * (Log.terminal_columns - len(text) - 4), + Log.style.RESET, + ) + ) + with open(Log.log_file, "a") as f: + f.write("{}...\n".format(text)) + + def PrintBegin(text): + # datetime object containing current date and time + dt_string = datetime.utcnow().strftime("%d/%m/%Y %H:%M:%S") + Log.current_cursor_pos = len(text) + len(dt_string) + 3 + + print( + "[{}{}{}] {}{}{}{}".format( + Log.style.MAGENTA, + dt_string, + Log.style.RESET, + Log.style.WHITE, + Log.style.BOLD, + text, + Log.style.RESET, + ), + end="", + ) + with open(Log.log_file, "a") as f: + f.write("[{}] {}: ".format(dt_string, text)) + + def PrintFollow(text): + Log.current_cursor_pos += len(text) + + print(Log.style.CYAN + text + Log.style.RESET, end="") + with open(Log.log_file, "a") as f: + f.write("{} ".format(text)) + + def PrintResult(result_type, result_text=None): + text = "" + color = Log.style.WHITE + + if result_type == Result.OK: + text = "OK" + color = Log.style.GREEN + elif result_type == Result.NEW: + text = "Created new" + color = Log.style.CYAN + elif result_type == Result.FAILURE: + text = "Failed" + color = Log.style.RED + elif result_type == Result.UPDATE: + text = "Updated" + color = Log.style.YELLOW + elif result_type == Result.ALREADY_DONE: + text = "Present and up to date" + color = Log.style.GREEN + elif result_type == Result.SEE_BELOW: + text = "See below" + color = Log.style.BLUE + elif result_type == Result.IGNORED: + text = "Ignored" + color = Log.style.YELLOW + + print( + "{}{}{}{}".format( + color, + Log.style.BOLD, + text.rjust(Log.terminal_columns - Log.current_cursor_pos), + Log.style.RESET, + ) + ) + f = open(Log.log_file, "a") + f.write("{}\n".format(text)) + if result_text: + print("Results of call before:{}\n".format(result_text)) + f.write("Results of call before:{}\n".format(result_text)) + f.close() + + def PrintFatal(error_text): + # datetime object containing current date and time + dt_string = datetime.utcnow().strftime("%d/%m/%Y %H:%M:%S") + Log.current_cursor_pos = len(error_text) + len(dt_string) + 3 + + print( + "[{}{}{}] {}{}FATAL: {}{}".format( + Log.style.YELLOW, + dt_string, + Log.style.RESET, + Log.style.RED, + Log.style.BOLD, + Log.style.RESET, + error_text, + ) + ) + with open(Log.log_file, "a") as f: + f.write("[{}] {}\n".format(dt_string, error_text)) + + def __printUsedBooleanValueLine(name, value): + text = "--{} = {}{}".format( + name, + Log.style.RED + "yes" if value else Log.style.GREEN + "no", + Log.style.RESET, + ) + print( + "│ {}{}{}{}{}│".format( + Log.style.BOLD, + Log.style.WHITE, + text, + Log.style.RESET, + " " * (Log.terminal_columns - len(text) + 6), + ) + ) diff --git a/xbmc/addons/kodi-dev-kit/tools/debian-addon-package-test.sh b/xbmc/addons/kodi-dev-kit/tools/debian-addon-package-test.sh new file mode 100755 index 0000000..d778954 --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/tools/debian-addon-package-test.sh @@ -0,0 +1,141 @@ +#!/bin/bash + +# This script is for purely testing purposes! +# +# It is meant to be able to test at binary addons the creation of a debian +# package. +# +# The created files are below the source code folder. +# +# Example: +# ./build-debian-addon-package.sh $HOME/your_path/screensaver.stars +# +# To remove generated code: +# ./build-debian-addon-package.sh $HOME/your_path/screensaver.stars --clean +# + +BASE_DIR="" +REPO_DIR="" +PACKAGEVERSION="" +VERSION_MAIN="" +VERSION_MINOR="" +VERSION_REVISON="" +GIT_REV="" +DIST="" +TAGREV=${TAGREV:-"0"} + +function usage { + echo "\ +-------------------------------------------------------------------------------- + +This script builds a Kodi addon debian package from the given addon source. + +As value, the path to the addon must be given. +In addition --clean can be used to remove the created debian files. + +WARNING: This script is for testing purposes only! + +--------------------------------------------------------------------------------" +} + +function checkEnv { + echo "#------ build environment ------#" + echo "BASE_DIR: $BASE_DIR" + echo "REPO_DIR: $REPO_DIR" + getVersion + echo "VERSION_MAIN: $VERSION_MAIN" + echo "VERSION_MINOR: $VERSION_MINOR" + echo "VERSION_REVISON: $VERSION_REVISON" + if [ $GIT_REV ]; then + echo "GIT_REV: $GIT_REV" + fi + echo "TAGREV: $TAGREV" + echo "DIST: $DIST" + echo "ARCHS: $ARCHS" + + echo "#-------------------------------#" +} + +function getVersion { + if [ -d ${BASE_DIR}/.git ]; then + getGitRev + fi + PACKAGEVERSION=$(cat ${BASE_DIR}/$REPO_DIR/addon.xml.in | sed -n '/version/ s/.*version=\"\([0-9]\+\.[0-9]\+\.[0-9]\+\)\".*/\1/p' | awk 'NR == 1') + VERSION_MAIN=$(echo $PACKAGEVERSION | awk -F. '{print $1}') + VERSION_MINOR=$(echo $PACKAGEVERSION | awk -F. '{print $2}') + VERSION_REVISON=$(echo $PACKAGEVERSION | awk -F. '{print $3}') +} + +function getGitRev { + cd $BASE_DIR || exit 1 + GIT_REV=$(git log -1 --pretty=format:"%h") +} + +function cleanup() { + echo "Starting to remove debian generated files" + cd ${BASE_DIR} + rm -rf obj-$ARCHS-linux-gnu + rm -rf debian/.debhelper + rm -rf debian/"kodi-"$(echo $REPO_DIR | tr . -) + rm -rf debian/"kodi-"$(echo $REPO_DIR | tr . -)-dbg + rm -rf debian/tmp + rm -f debian/changelog + rm -f debian/debhelper-build-stamp + rm -f debian/files + rm -f debian/*.log + rm -f debian/*.substvars +} + +if [[ $1 = "-h" ]] || [[ $1 = "--help" ]]; then + echo "$0:" + usage + exit +fi + +if [ ! $1 ] || [ ${1} = "--clean" ]; then + printf "$0:\nERROR: Addon source code must be given as the first parameter!\n" + usage + exit 1 +elif [ ! -d $1 ]; then + printf "$0:\nERROR: Given folder is not present or not a valid addon source!\n" + usage + exit 1 +fi + +ARCHS=$(uname -m) +BASE_DIR=$(realpath ${1}) +REPO_DIR=$(basename ${1}) +DIST=$(lsb_release -cs) + +if [ ! -f ${BASE_DIR}/$REPO_DIR/addon.xml.in ]; then + echo "$0: +ERROR: \"required $REPO_DIR/addon.xml.in\" not found! + +The base source dir and addon.xml.in containing directory names must be equal" + usage + exit 1 +fi + +checkEnv + +ORIGTARBALL="kodi-"$(echo $REPO_DIR | tr . -)"_${PACKAGEVERSION}.orig.tar.gz" + +if [[ ${2} = "--clean" ]]; then + cleanup + exit +fi + +echo "Detected addon package version: ${PACKAGEVERSION}" + +sed -e "s/#PACKAGEVERSION#/${PACKAGEVERSION}/g" \ + -e "s/#TAGREV#/${TAGREV}/g" \ + -e "s/#DIST#/${DIST}/g" ${BASE_DIR}/debian/changelog.in > ${BASE_DIR}/debian/changelog + +echo "Create needed compressed source code file: ${BASE_DIR}/../${ORIGTARBALL}.tar.gz" + +# git archive --format=tar.gz -o ${BASE_DIR}/../${ORIGTARBALL} HEAD # Unused git, leaved as optional way +EXCLUDE=$(cat .gitignore | sed -e '/#/d' -e '/^\s*$/d' -e 's/^/--exclude=/' -e 's/\/$//' | tr '\n' ' ') +tar -zcvf ${BASE_DIR}/../${ORIGTARBALL} --exclude=.git $EXCLUDE * # Used to prevent on code changed for test a git commit + +echo "Building debian-source package for ${DIST}" +dpkg-buildpackage -us -uc --diff-ignore="()$" diff --git a/xbmc/addons/kodi-dev-kit/tools/doxygen-header-class-list-creator.py b/xbmc/addons/kodi-dev-kit/tools/doxygen-header-class-list-creator.py new file mode 100755 index 0000000..0b0590e --- /dev/null +++ b/xbmc/addons/kodi-dev-kit/tools/doxygen-header-class-list-creator.py @@ -0,0 +1,190 @@ +#!/usr/bin/env python3 + +from optparse import OptionParser +import glob +import io +import os +import re +import sys + +def read_file(name, normalize=True): + """ Read a file. """ + try: + with open(name, 'r', encoding='utf-8') as f: + # read the data + data = f.read() + if normalize: + # normalize line endings + data = data.replace("\r\n", "\n") + return data + except IOError as e: + (errno, strerror) = e.args + sys.stderr.write('Failed to read file ' + name + ': ' + strerror) + raise + +def write_file(name, data): + """ Write a file. """ + try: + with open(name, 'w', encoding='utf-8') as f: + # write the data + if sys.version_info.major == 2: + f.write(data.decode('utf-8')) + else: + f.write(data) + except IOError as e: + (errno, strerror) = e.args + sys.stderr.write('Failed to write file ' + name + ': ' + strerror) + raise + +def auto_check_header(file): + groups_to_check = [] + + data = read_file(file) + if not 'addon_auto_check' in data: + return '' + + for line in io.StringIO(data): + line = re.search(r"^.*\/\/\/.*@copydetails *(.*)(_header|_source)_addon_auto_check.*", line, flags=re.UNICODE) + if line and line.group(1): + group = line.group(1) + if group in groups_to_check: + continue + + print(' - Found use with %s' % group) + groups_to_check.append(line.group(1)) + + return groups_to_check + +def parse_header(file, group, new_path=''): + header_sources = '' + header_addon = '' + source_addon = '' + + data = read_file(file) + group_found = False + group_start = False + virtual_function_start = False + for line in io.StringIO(data): + if not group_found and 'defgroup ' + group in line: + group_found = True + continue + elif group_found and not group_start and '///@{' in line: + group_start = True + continue + elif group_start and '///@}' in line: + break + elif re.match(r'^.*//.*', line) or re.match(r'^.*//.*', line) or line == '\n' or not group_start: + continue + + if re.match(r'^.*virtual.*', line): + virtual_function_start = True + + if virtual_function_start: + header_sources += re.sub(r"^\s+", "", line, flags=re.UNICODE) + + if virtual_function_start and re.match(r'^.*}.*', line): + virtual_function_start = False + + if not group_found: + return "" + + header_sources = header_sources.replace("\n", "") + header_sources = " ".join(re.split("\s+", header_sources, flags=re.UNICODE)) + header_sources = header_sources.replace("}", "}\n") + header_sources = header_sources.replace("= 0;", "= 0;\n") + header_sources = header_sources.replace(",", ", ") + + # Generate class header part of list + header_addon += '/// @defgroup ' + group + '_header_addon_auto_check Group header include\n' + header_addon += '/// @ingroup ' + group + '\n' + header_addon += '///@{\n' + header_addon += '/// *Header parts:*\n' + header_addon += '/// ~~~~~~~~~~~~~{.cpp}\n' + header_addon += '///\n' + for line in io.StringIO(header_sources): + line = re.search(r"^.*virtual.([A-Za-z1-9].*\(.*\))", line, flags=re.UNICODE) + if line: + header_addon += '/// ' + re.sub(' +', ' ', line.group(1)) + ' override;\n' + header_addon += '///\n' + header_addon += '/// ~~~~~~~~~~~~~\n' + header_addon += '///@}\n\n' + + # Generate class source part of list + source_addon += '/// @defgroup ' + group + '_source_addon_auto_check Group source include\n' + source_addon += '/// @ingroup ' + group + '\n' + source_addon += '///@{\n' + source_addon += '/// *Source parts:*\n' + source_addon += '/// ~~~~~~~~~~~~~{.cpp}\n' + source_addon += '///\n' + for line in io.StringIO(header_sources): + line = line.replace("{", "\n{\n ") + line = line.replace("}", "\n}") + for line in io.StringIO(line + '\n'): + func = re.search(r"^.*(virtual *) *(.*) ([a-z|A-Z|0-9].*)(\(.*\))", line, flags=re.UNICODE) + if func: + source_addon += '/// ' + re.sub(' +', ' ', func.group(2) + ' CMyInstance::' + func.group(3) + func.group(4) + '\n') + else: + source_addon += '/// ' + line + if '= 0' in line: + source_addon += '/// {\n' + source_addon += '/// // Required in interface to have!\n' + source_addon += '/// // ...\n' + source_addon += '/// }\n' + + source_addon += '/// ~~~~~~~~~~~~~\n' + source_addon += '///@}\n\n' + + return header_addon + source_addon + +def print_error(msg): + print('Error: %s\nSee --help for usage.' % msg) + +# cannot be loaded as a module +if __name__ != "__main__": + sys.stderr.write('This file cannot be loaded as a module!') + sys.exit() + +# parse command-line options +disc = """ +This utility generate group list about addon header sources to add inside doxygen. +""" + +parser = OptionParser(description=disc) +parser.add_option( + '--header-file', + dest='headerfile', + metavar='DIR', + help='the to checked header [required]') +parser.add_option( + '--doxygen-group', + dest='doxygengroup', + help='the to checked doxygen group inside header [required]') +(options, args) = parser.parse_args() + +docs = '' +groups_to_check = [] + +# Check about use of helper docs +if options.doxygengroup is None: + print('Scaning about used places...') + headers = glob.glob("../include/kodi/**/*.h", recursive=True) + for header in headers: + group = auto_check_header(header) + if group: + groups_to_check += group +else: + groups_to_check.append(options.doxygengroup) + +# Generate the helper docs +if options.headerfile is None: + headers = glob.glob("../include/kodi/**/*.h", recursive=True) + print('Parsing about docs:') + for header in headers: + print(' - %s' % header) + for group in groups_to_check: + docs += parse_header(header, group) +else: + for group in groups_to_check: + docs += parse_header(options.headerfile, group) + +write_file("../include/groups.dox", docs) |