From a0b0f432f788538d764fbe9c05e0f9165dad33f1 Mon Sep 17 00:00:00 2001 From: "Dr.-Ing. Amilcar do Carmo Lucas" Date: Thu, 25 Apr 2024 01:13:27 +0200 Subject: [PATCH] IMPROVEMENT: Use userappdata instead of commonappdata on windows This has the advantage of not requiring admin permissions --- MethodicConfigurator/backend_filesystem.py | 17 +++++++---------- credits/CREDITS.md | 1 + credits/platformdirs-LICENSE | 21 +++++++++++++++++++++ credits/update_credits_licenses.py | 1 + windows/ardupilot_methodic_configurator.iss | 21 ++++++++++----------- 5 files changed, 40 insertions(+), 21 deletions(-) create mode 100644 credits/platformdirs-LICENSE diff --git a/MethodicConfigurator/backend_filesystem.py b/MethodicConfigurator/backend_filesystem.py index 6e4e78b..ce3e786 100644 --- a/MethodicConfigurator/backend_filesystem.py +++ b/MethodicConfigurator/backend_filesystem.py @@ -38,6 +38,8 @@ from zipfile import ZipFile +from platformdirs import user_config_dir + from annotate_params import BASE_URL, PARAM_DEFINITION_XML_FILE, Par from annotate_params import get_xml_data from annotate_params import create_doc_dict @@ -479,26 +481,21 @@ def copy_fc_values_to_file(self, selected_file: str, params: Dict[str, float]): @staticmethod def __get_settings_directory(): - settings_directory_file = os_path.join(os_path.dirname(os_path.realpath(__file__)), "settings_directory") - with open(settings_directory_file, "r", encoding='utf-8') as settings_directory_file_contents: - settings_directory = settings_directory_file_contents.read().strip() + settings_directory = user_config_dir(".ardupilot_methodic_configurator", False, ensure_exists=True) if not os_path.exists(settings_directory): raise FileNotFoundError(f"The settings directory '{settings_directory}' does not exist.") - elif not os_path.isdir(settings_directory): + if not os_path.isdir(settings_directory): raise NotADirectoryError(f"The path '{settings_directory}' is not a directory.") return settings_directory @staticmethod def __get_settings_as_dict(): - # Define the path to the settings.json file settings_path = os_path.join(LocalFilesystem.__get_settings_directory(), "settings.json") - # Initialize settings as an empty dictionary settings = {} - # Try to read the existing settings try: with open(settings_path, "r", encoding='utf-8') as settings_file: settings = json_load(settings_file) @@ -506,17 +503,17 @@ def __get_settings_as_dict(): # If the file does not exist, it will be created later pass - # Ensure the directory_selection key exists in the settings + if "Format version" not in settings: + settings["Format version"] = 1 + if "directory_selection" not in settings: settings["directory_selection"] = {} return settings @staticmethod def __set_settings_from_dict(settings): - # Define the path to the settings.json file settings_path = os_path.join(LocalFilesystem.__get_settings_directory(), "settings.json") - # Write the updated settings back to the file with open(settings_path, "w", encoding='utf-8') as settings_file: json_dump(settings, settings_file, indent=4) diff --git a/credits/CREDITS.md b/credits/CREDITS.md index b0f3396..60b8171 100644 --- a/credits/CREDITS.md +++ b/credits/CREDITS.md @@ -17,6 +17,7 @@ It directly uses: | [webbrowser](https://docs.python.org/3/library/webbrowser.html) | [Python Software Foundation License](https://docs.python.org/3/license.html) | | [pymavlink](https://github.com/ArduPilot/pymavlink) | [GNU Lesser General Public License v3.0](https://github.com/ArduPilot/pymavlink/blob/master/COPYING) | | [ArduPilot tempcal_IMU.py](https://github.com/ArduPilot/ardupilot/blob/master/Tools/scripts/tempcal_IMU.py) | [](https://github.com/ArduPilot/ardupilot/blob/master/COPYING.txt) | +| [platformdirs](https://platformdirs.readthedocs.io/en/latest/index.html) | [MIT](https://github.com/platformdirs/platformdirs/blob/main/LICENSE) | | [pyserial](https://pyserial.readthedocs.io/en/latest/pyserial.html) | [BSD License](https://github.com/pyserial/pyserial/blob/master/LICENSE.txt) | | [Scrollable TK frame](https://gist.github.com/mp035/9f2027c3ef9172264532fcd6262f3b01) by Mark Pointing | [Mozilla Public License, v. 2.0](https://mozilla.org/MPL/2.0/) | | [Python Tkinter ComboBox](https://dev.to/geraldew/python-tkinter-an-exercise-in-wrapping-the-combobox-ndb) by geraldew | [Mozilla Public License, v. 2.0](https://mozilla.org/MPL/2.0/) | diff --git a/credits/platformdirs-LICENSE b/credits/platformdirs-LICENSE new file mode 100644 index 0000000..f35fed9 --- /dev/null +++ b/credits/platformdirs-LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2010-202x The platformdirs developers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/credits/update_credits_licenses.py b/credits/update_credits_licenses.py index 70447b3..4cebd90 100644 --- a/credits/update_credits_licenses.py +++ b/credits/update_credits_licenses.py @@ -26,6 +26,7 @@ {"name": "pymavlink", "license_url": "https://raw.githubusercontent.com/ArduPilot/pymavlink/master/COPYING"}, {"name": "ArduPilot tempcal_IMU.py", "license_url": "https://raw.githubusercontent.com/ArduPilot/ardupilot/master/COPYING.txt"}, + {"name": "platformdirs", "license_url": "https://raw.githubusercontent.com/platformdirs/platformdirs/main/LICENSE"}, {"name": "pyserial", "license_url": "https://raw.githubusercontent.com/pyserial/pyserial/master/LICENSE.txt"}, {"name": "Scrollable_TK_frame", "license_url": "https://mozilla.org/MPL/2.0/"}, {"name": "Python_Tkinter_ComboBox", "license_url": "https://mozilla.org/MPL/2.0/"}, diff --git a/windows/ardupilot_methodic_configurator.iss b/windows/ardupilot_methodic_configurator.iss index 3ab21c1..2c7c5d6 100644 --- a/windows/ardupilot_methodic_configurator.iss +++ b/windows/ardupilot_methodic_configurator.iss @@ -42,11 +42,11 @@ Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{ Source: "..\MethodicConfigurator\dist\ardupilot_methodic_configurator\ardupilot_methodic_configurator.exe"; DestDir: "{app}"; Flags: ignoreversion Source: "..\MethodicConfigurator\dist\ardupilot_methodic_configurator\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs ; NOTE: Don't use "Flags: ignoreversion" on any shared system files -Source: "..\vehicle_examples\diatone_taycan_mxc\4.3.8-params\*.*"; DestDir: "{commonappdata}\.ardupilot_methodic_configurator\vehicle_examples\diatone_taycan_mxc\4.3.8-params"; Flags: ignoreversion -Source: "..\vehicle_examples\diatone_taycan_mxc\4.4.4-params\*.*"; DestDir: "{commonappdata}\.ardupilot_methodic_configurator\vehicle_examples\diatone_taycan_mxc\4.4.4-params"; Flags: ignoreversion -Source: "..\vehicle_examples\diatone_taycan_mxc\4.5.1-params\*.*"; DestDir: "{commonappdata}\.ardupilot_methodic_configurator\vehicle_examples\diatone_taycan_mxc\4.5.1-params"; Flags: ignoreversion -Source: "..\vehicle_examples\diatone_taycan_mxc\4.6.0-DEV-params\*.*"; DestDir: "{commonappdata}\.ardupilot_methodic_configurator\vehicle_examples\diatone_taycan_mxc\4.6.0-DEV-params"; Flags: ignoreversion -Source: "..\windows\version.txt"; DestDir: "{commonappdata}\.ardupilot_methodic_configurator"; Flags: ignoreversion +Source: "..\vehicle_examples\diatone_taycan_mxc\4.3.8-params\*.*"; DestDir: "{userappdata}\.ardupilot_methodic_configurator\vehicle_examples\diatone_taycan_mxc\4.3.8-params"; Flags: ignoreversion +Source: "..\vehicle_examples\diatone_taycan_mxc\4.4.4-params\*.*"; DestDir: "{userappdata}\.ardupilot_methodic_configurator\vehicle_examples\diatone_taycan_mxc\4.4.4-params"; Flags: ignoreversion +Source: "..\vehicle_examples\diatone_taycan_mxc\4.5.1-params\*.*"; DestDir: "{userappdata}\.ardupilot_methodic_configurator\vehicle_examples\diatone_taycan_mxc\4.5.1-params"; Flags: ignoreversion +Source: "..\vehicle_examples\diatone_taycan_mxc\4.6.0-DEV-params\*.*"; DestDir: "{userappdata}\.ardupilot_methodic_configurator\vehicle_examples\diatone_taycan_mxc\4.6.0-DEV-params"; Flags: ignoreversion +Source: "..\windows\version.txt"; DestDir: "{userappdata}\.ardupilot_methodic_configurator"; Flags: ignoreversion Source: "..\windows\MethodicConfigurator.ico"; DestDir: "{app}"; Flags: ignoreversion Source: "..\windows\settings_template.json"; DestDir: "{app}\_internal"; Flags: ignoreversion Source: "..\MethodicConfigurator\ArduPilot_icon.png"; DestDir: "{app}\_internal"; Flags: ignoreversion @@ -55,11 +55,11 @@ Source: "..\MethodicConfigurator\file_documentation.json"; DestDir: "{app}\_inte Source: "..\credits\*.*"; DestDir: "{app}\credits"; Flags: ignoreversion [Icons] -Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; WorkingDir: "{commonappdata}\.ardupilot_methodic_configurator\vehicle_examples"; Tasks: desktopicon; IconFilename: "{app}\MethodicConfigurator.ico" +Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; WorkingDir: "{userappdata}\.ardupilot_methodic_configurator\vehicle_examples"; Tasks: desktopicon; IconFilename: "{app}\MethodicConfigurator.ico" Name: "{group}\Documentation"; Filename: "https://github.com/ArduPilot/MethodicConfigurator/blob/master/USERMANUAL.md" -Name: "{group}\Vehicle Examples"; Filename: "{commonappdata}\.ardupilot_methodic_configurator\vehicle_examples" +Name: "{group}\Vehicle Examples"; Filename: "{userappdata}\.ardupilot_methodic_configurator\vehicle_examples" Name: "{group}\ArduPilot MethodicConfigurator Forum"; Filename: "https://discuss.ardupilot.org/t/new-ardupilot-methodic-configurator-gui/115038/" -Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; WorkingDir: "{commonappdata}\.ardupilot_methodic_configurator\vehicle_examples"; IconFilename: "{app}\MethodicConfigurator.ico" +Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; WorkingDir: "{userappdata}\.ardupilot_methodic_configurator\vehicle_examples"; IconFilename: "{app}\MethodicConfigurator.ico" [Run] Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent @@ -178,7 +178,7 @@ begin if LoadStringFromFile(FileName, FileContent) then begin UnicodeFileContent := String(FileContent) - ProgData := ExpandConstant('{commonappdata}') + ProgData := ExpandConstant('{userappdata}') StringChangeEx(ProgData, '\', '\\', True) StringChangeEx(UnicodeFileContent, '{PROGRAM_DATA}', ProgData, True); Result := SaveStringToFile(FileName, AnsiString(UnicodeFileContent), False); @@ -192,7 +192,6 @@ begin if CurStep = ssPostInstall then begin ReplacePlaceholdersInFile(ExpandConstant('{app}\_internal\settings_template.json')); - // Optionally, rename the file to settings.json if you want to use the original file name - RenameFile(ExpandConstant('{app}\_internal\settings_template.json'), ExpandConstant('{app}\_internal\settings.json')); + RenameFile(ExpandConstant('{app}\_internal\settings_template.json'), ExpandConstant('{userappdata}\.ardupilot_methodic_configurator\settings.json')); end; end;