From 2dbbefd08ac414292c59bf9045ba808e355495ff Mon Sep 17 00:00:00 2001 From: cary-rowen Date: Wed, 15 Mar 2023 18:58:49 +0800 Subject: [PATCH] Updated add-on template,make add-ons compatible with NVDA2023.1. --- .github/workflows/build_addon.yml | 64 +++++++++++++++++++++ .pre-commit-config.yaml | 7 +++ .vscode/extensions.json | 12 ++++ .vscode/settings.json | 25 ++++++++ AudioControl-1.8.1.json | 29 ++++++++++ addon/doc/zh_CN/readme.md | 3 + buildVars.py | 16 +++--- sconstruct | 95 ++++++++++++++++++++++++++++++- 8 files changed, 242 insertions(+), 9 deletions(-) create mode 100644 .github/workflows/build_addon.yml create mode 100644 .pre-commit-config.yaml create mode 100644 .vscode/extensions.json create mode 100644 .vscode/settings.json create mode 100644 AudioControl-1.8.1.json diff --git a/.github/workflows/build_addon.yml b/.github/workflows/build_addon.yml new file mode 100644 index 0000000..9b97cd9 --- /dev/null +++ b/.github/workflows/build_addon.yml @@ -0,0 +1,64 @@ +name: build addon + +on: + push: + tags: ["*"] + # To build on main/master branch, uncomment the following line: + # branches: [ main , master ] + + pull_request: + branches: [ main, master ] + + workflow_dispatch: + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - run: echo -e "pre-commit\nscons\nmarkdown">requirements.txt + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: 3.9 + cache: 'pip' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip wheel + pip install -r requirements.txt + sudo apt-get update -y + sudo apt-get install -y gettext + + - name: Code checks + run: export SKIP=no-commit-to-branch; pre-commit run --all + + - name: building addon + run: scons + + - uses: actions/upload-artifact@v3 + with: + name: packaged_addon + path: ./*.nvda-addon + + upload_release: + runs-on: ubuntu-latest + if: ${{ startsWith(github.ref, 'refs/tags/') }} + needs: ["build"] + steps: + - uses: actions/checkout@v3 + - name: download releases files + uses: actions/download-artifact@v3 + - name: Display structure of downloaded files + run: ls -R + + - name: Release + uses: softprops/action-gh-release@v1 + with: + files: packaged_addon/*.nvda-addon + fail_on_unmatched_files: true + prerelease: ${{ contains(github.ref, '-') }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..dd7a9d6 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,7 @@ +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.3.0 + hooks: + - id: check-ast + - id: check-case-conflict + - id: check-yaml diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..75fa7aa --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,12 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. + // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp + // List of extensions which should be recommended for users of this workspace. + "recommendations": [ + "ms-python.python", + "ms-python.vscode-pylance", + "redhat.vscode-yaml" + ], + // List of extensions recommended by VS Code that should not be recommended for users of this workspace. + "unwantedRecommendations": [] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..7c58677 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,25 @@ +{ + "editor.accessibilitySupport": "on", + "python.linting.enabled": true, + "python.linting.maxNumberOfProblems": 10000, + "python.linting.flake8Args": [ + "--config=flake8.ini" + ], + "python.linting.flake8Enabled": true, + "python.linting.pylintEnabled": false, + "python.autoComplete.extraPaths": [ + "../nvda/source", + "../nvda/miscDeps/python" + ], + "files.insertFinalNewline": true, + "files.trimFinalNewlines": true, + "editor.insertSpaces": false, + "python.analysis.diagnosticSeverityOverrides": { + "reportUndefinedVariable": "none" + }, + "python.analysis.extraPaths": [ + "../nvda/source", + "../nvda/miscDeps/python" + ], + "python.defaultInterpreterPath": "../nvda/.venv/scripts/python.exe" +} diff --git a/AudioControl-1.8.1.json b/AudioControl-1.8.1.json new file mode 100644 index 0000000..42a33b5 --- /dev/null +++ b/AudioControl-1.8.1.json @@ -0,0 +1,29 @@ +{ + "addonId": "AudioControl", + "displayName": "Audio Control", + "URL": "", + "description": "A add-on for controlling audio processes and sound output devices.", + "sha256": "33899d5b27d9be04a99c2881260abe154a567b7410db2bde1d439cd1122beee5", + "homepage": "https://www.nvdacn.com/", + "addonVersionName": "1.8.1", + "addonVersionNumber": { + "major": 1, + "minor": 8, + "patch": 1 + }, + "minNVDAVersion": { + "major": 0, + "minor": 0, + "patch": 0 + }, + "lastTestedVersion": { + "major": 0, + "minor": 0, + "patch": 0 + }, + "channel": "stable", + "publisher": "", + "sourceURL": "https://github.com/cary-rowen/AudioControl", + "license": "GPL v2", + "licenseURL": "https://www.gnu.org/licenses/gpl-2.0.html" +} \ No newline at end of file diff --git a/addon/doc/zh_CN/readme.md b/addon/doc/zh_CN/readme.md index ee926de..9c76ebb 100644 --- a/addon/doc/zh_CN/readme.md +++ b/addon/doc/zh_CN/readme.md @@ -27,6 +27,9 @@ ## 兼容性 **NVDA2019.3及最新** +## 1.8.1 版更新日志 +* 兼容 NVDA2023.1 + ## 1.8 版更新日志 1. 锁定 / 解锁麦克风音量的状态支持记忆,重启 NVDA 不再恢复默认。 2. NVDA 2022.1 的兼容性更新; diff --git a/buildVars.py b/buildVars.py index 88c09ae..8cc193c 100644 --- a/buildVars.py +++ b/buildVars.py @@ -25,21 +25,27 @@ def _(arg): # Translators: Long description to be shown for this add-on on add-on information from add-ons manager "addon_description": _("""A add-on for controlling audio processes and sound output devices."""), # version - "addon_version": "1.8", + "addon_version": "1.8.1", # Author(s) "addon_author": "Cary-Rowen, Youlan, Cyrille Bougot, Chenfu", # URL for the add-on documentation support - "addon_url": "https://github.com/cary-rowen/AudioControl", + "addon_url": "https://www.nvdacn.com/", + # URL for the add-on repository where the source code can be found + "addon_sourceURL": "https://github.com/cary-rowen/AudioControl", # Documentation file name "addon_docFileName": "readme.html", # Minimum NVDA version supported (e.g. "2018.3.0", minor version is optional) "addon_minimumNVDAVersion": 2019.3, # Last NVDA version supported/tested (e.g. "2018.4.0", ideally more recent than minimum version) - "addon_lastTestedNVDAVersion": 2022.1, + "addon_lastTestedNVDAVersion": 2023.1, # Add-on update channel (default is None, denoting stable releases, # and for development releases, use "dev".) # Do not change unless you know what you are doing! "addon_updateChannel": None, + # Add-on license such as GPL 2 + "addon_license": "GPL v2", + # URL for the license document the ad-on is licensed under + "addon_licenseURL": "https://www.gnu.org/licenses/gpl-2.0.html", } # Define the python files that are the sources of your add-on. @@ -58,9 +64,6 @@ def _(arg): # Files that will be ignored when building the nvda-addon file # Paths are relative to the addon directory, not to the root directory of your addon sources. excludedFiles = [] -#excludedFiles: List[str] = [] - - # Base language for the NVDA add-on # If your add-on is written in a language other than english, modify this variable. @@ -73,4 +76,3 @@ def _(arg): # Extensions string must be of the form "markdown.extensions.extensionName" # e.g. "markdown.extensions.tables" to add tables. markdownExtensions = ['markdown.extensions.tables', 'markdown.extensions.extra', 'markdown.extensions.smarty', 'markdown.extensions.toc'] - diff --git a/sconstruct b/sconstruct index ab61654..d22756e 100644 --- a/sconstruct +++ b/sconstruct @@ -1,5 +1,5 @@ # NVDA add-on template SCONSTRUCT file -# Copyright (C) 2012-2021 Rui Batista, Noelia Martinez, Joseph Lee +# Copyright (C) 2012-2023 Rui Batista, Noelia Martinez, Joseph Lee # This file is covered by the GNU General Public License. # See the file COPYING.txt for more details. @@ -75,8 +75,21 @@ def mdTool(env): env['BUILDERS']['markdown'] = mdBuilder +def validateVersionNumber(key, val, env): + # Used to make sure version major.minor.patch are integers to comply with NV Access add-on store. + # Ignore all this if version number is not specified, in which case json generator will validate this info. + if val == "0.0.0": + return + versionNumber = val.split(".") + if len(versionNumber) < 3: + raise ValueError("versionNumber must have three parts (major.minor.patch)") + if not all([part.isnumeric() for part in versionNumber]): + raise ValueError("versionNumber (major.minor.patch) must be integers") + + vars = Variables() vars.Add("version", "The version of this build", buildVars.addon_info["addon_version"]) +vars.Add("versionNumber", "Version number of the form major.minor.patch", "0.0.0", validateVersionNumber) vars.Add(BoolVariable("dev", "Whether this is a daily development version", False)) vars.Add("channel", "Update channel for this build", buildVars.addon_info["addon_updateChannel"]) @@ -87,7 +100,9 @@ if env["dev"]: import datetime buildDate = datetime.datetime.now() year, month, day = str(buildDate.year), str(buildDate.month), str(buildDate.day) - env["addon_version"] = "".join([year, month.zfill(2), day.zfill(2), "-dev"]) + versionTimestamp = "".join([year, month.zfill(2), day.zfill(2)]) + env["addon_version"] = f"{versionTimestamp}-dev" + env["versionNumber"] = f"{versionTimestamp}.0.0" env["channel"] = "dev" elif env["version"] is not None: env["addon_version"] = env["version"] @@ -155,9 +170,85 @@ def createAddonBundleFromPath(path, dest): absPath = os.path.join(dir, filename) if pathInBundle not in buildVars.excludedFiles: z.write(absPath, pathInBundle) + createAddonStoreJson(dest) return dest +def createAddonStoreJson(bundle): + """Creates add-on store JSON file from an add-on package and manifest data.""" + import json + import hashlib + # Set different json file names and version number properties based on version number parsing results. + if env["versionNumber"] == "0.0.0": + env["versionNumber"] = buildVars.addon_info["addon_version"] + versionNumberParsed = env["versionNumber"].split(".") + if all([part.isnumeric() for part in versionNumberParsed]): + if len(versionNumberParsed) == 1: + versionNumberParsed += ["0", "0"] + elif len(versionNumberParsed) == 2: + versionNumberParsed.append("0") + else: + versionNumberParsed = [] + if len(versionNumberParsed): + major, minor, patch = [int(part) for part in versionNumberParsed] + jsonFilename = f'{buildVars.addon_info["addon_name"]}-{major}.{minor}.{patch}.json' + else: + jsonFilename = f'{buildVars.addon_info["addon_name"]}-{buildVars.addon_info["addon_version"]}.json' + major, minor, patch = 0, 0, 0 + print('Generating % s' % jsonFilename) + sha256 = hashlib.sha256() + with open(bundle, "rb") as f: + for byte_block in iter(lambda: f.read(65536), b""): + sha256.update(byte_block) + hashValue = sha256.hexdigest() + try: + minimumNVDAVersion = buildVars.addon_info["addon_minimumNVDAVersion"].split(".") + except AttributeError: + minimumNVDAVersion = [0, 0, 0] + minMajor, minMinor = minimumNVDAVersion[:2] + minPatch = minimumNVDAVersion[-1] if len(minimumNVDAVersion) == 3 else "0" + try: + lastTestedNVDAVersion = buildVars.addon_info["addon_lastTestedNVDAVersion"].split(".") + except AttributeError: + lastTestedNVDAVersion = [0, 0, 0] + lastTestedMajor, lastTestedMinor = lastTestedNVDAVersion[:2] + lastTestedPatch = lastTestedNVDAVersion[-1] if len(lastTestedNVDAVersion) == 3 else "0" + channel = buildVars.addon_info["addon_updateChannel"] + if channel is None: + channel = "stable" + addonStoreEntry = { + "addonId": buildVars.addon_info["addon_name"], + "displayName": buildVars.addon_info["addon_summary"], + "URL": "", + "description": buildVars.addon_info["addon_description"], + "sha256": hashValue, + "homepage": buildVars.addon_info["addon_url"], + "addonVersionName": buildVars.addon_info["addon_version"], + "addonVersionNumber": { + "major": major, + "minor": minor, + "patch": patch + }, + "minNVDAVersion": { + "major": int(minMajor), + "minor": int(minMinor), + "patch": int(minPatch) + }, + "lastTestedVersion": { + "major": int(lastTestedMajor), + "minor": int(lastTestedMinor), + "patch": int(lastTestedPatch) + }, + "channel": channel, + "publisher": "", + "sourceURL": buildVars.addon_info["addon_sourceURL"], + "license": buildVars.addon_info["addon_license"], + "licenseURL": buildVars.addon_info["addon_licenseURL"], + } + with open(jsonFilename, "w") as addonStoreJson: + json.dump(addonStoreEntry, addonStoreJson, indent="\t") + + def generateManifest(source, dest): addon_info = buildVars.addon_info with codecs.open(source, "r", "utf-8") as f: