mirror of
https://github.com/NixOS/nixpkgs.git
synced 2024-11-25 08:23:09 +00:00
freecad: make customizable (#347776)
This commit is contained in:
commit
d6a0449d10
@ -898,6 +898,8 @@
|
||||
|
||||
- `virtualisation.incus` module gained new `incus-user.service` and `incus-user.socket` systemd units. It is now possible to add a user to `incus` group instead of `incus-admin` for increased security.
|
||||
|
||||
- `freecad` now supports addons and custom configuration in nix-way, which can be used by calling `freecad.customize`.
|
||||
|
||||
## Detailed Migration Information {#sec-release-24.11-migration}
|
||||
|
||||
### `sound` options removal {#sec-release-24.11-migration-sound}
|
||||
|
@ -0,0 +1,149 @@
|
||||
From 23ddb6ff148ec5c27da050ba0eb7a2e449b8450b Mon Sep 17 00:00:00 2001
|
||||
From: Yury Shvedov <yury.shvedov@kaspersky.com>
|
||||
Date: Mon, 4 Nov 2024 14:22:22 +0300
|
||||
Subject: [PATCH] Gui: take in account module-path argument
|
||||
|
||||
Use paths passed with `--module-path` argument to search for preference
|
||||
packs
|
||||
|
||||
Change-Id: If168dbd99a826757290ee6b918f5b712305fe2bb
|
||||
---
|
||||
src/Gui/DlgPreferencePackManagementImp.cpp | 16 +++++----
|
||||
src/Gui/PreferencePackManager.cpp | 39 +++++++++++++++++-----
|
||||
src/Gui/PreferencePackManager.h | 5 +++
|
||||
3 files changed, 44 insertions(+), 16 deletions(-)
|
||||
|
||||
diff --git a/src/Gui/DlgPreferencePackManagementImp.cpp b/src/Gui/DlgPreferencePackManagementImp.cpp
|
||||
index a1a0dad41a..50f3982f21 100644
|
||||
--- a/src/Gui/DlgPreferencePackManagementImp.cpp
|
||||
+++ b/src/Gui/DlgPreferencePackManagementImp.cpp
|
||||
@@ -54,7 +54,7 @@ void DlgPreferencePackManagementImp::showEvent(QShowEvent* event)
|
||||
// but can only disable individual installed packs (though we can completely uninstall the pack's
|
||||
// containing Addon by redirecting to the Addon Manager).
|
||||
auto savedPreferencePacksDirectory = fs::path(App::Application::getUserAppDataDir()) / "SavedPreferencePacks";
|
||||
- auto modDirectory = fs::path(App::Application::getUserAppDataDir()) / "Mod";
|
||||
+ auto modDirectories = Application::Instance->prefPackManager()->modPaths();
|
||||
auto resourcePath = fs::path(App::Application::getResourceDir()) / "Gui" / "PreferencePacks";
|
||||
|
||||
// The displayed tree has two levels: at the toplevel is either "User-Saved Packs" or the name
|
||||
@@ -66,12 +66,14 @@ void DlgPreferencePackManagementImp::showEvent(QShowEvent* event)
|
||||
auto builtinPacks = getPacksFromDirectory(resourcePath);
|
||||
|
||||
std::map<std::string, std::vector<std::string>> installedPacks;
|
||||
- if (fs::exists(modDirectory) && fs::is_directory(modDirectory)) {
|
||||
- for (const auto& mod : fs::directory_iterator(modDirectory)) {
|
||||
- auto packs = getPacksFromDirectory(mod);
|
||||
- if (!packs.empty()) {
|
||||
- auto modName = mod.path().filename().string();
|
||||
- installedPacks.emplace(modName, packs);
|
||||
+ for (const auto& modDirectory : modDirectories) {
|
||||
+ if (fs::exists(modDirectory) && fs::is_directory(modDirectory)) {
|
||||
+ for (const auto& mod : fs::directory_iterator(modDirectory)) {
|
||||
+ auto packs = getPacksFromDirectory(mod);
|
||||
+ if (!packs.empty()) {
|
||||
+ auto modName = mod.path().filename().string();
|
||||
+ installedPacks.emplace(modName, packs);
|
||||
+ }
|
||||
}
|
||||
}
|
||||
}
|
||||
diff --git a/src/Gui/PreferencePackManager.cpp b/src/Gui/PreferencePackManager.cpp
|
||||
index dfc54240c0..83e32fa05e 100644
|
||||
--- a/src/Gui/PreferencePackManager.cpp
|
||||
+++ b/src/Gui/PreferencePackManager.cpp
|
||||
@@ -30,6 +30,7 @@
|
||||
#endif
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
+#include <boost/algorithm/string.hpp>
|
||||
#include <QDir>
|
||||
|
||||
#include "PreferencePackManager.h"
|
||||
@@ -134,12 +135,11 @@ void PreferencePack::applyConfigChanges() const
|
||||
}
|
||||
|
||||
PreferencePackManager::PreferencePackManager()
|
||||
+ : _preferencePackPaths(modPaths())
|
||||
{
|
||||
- auto modPath = fs::path(App::Application::getUserAppDataDir()) / "Mod";
|
||||
auto savedPath = fs::path(App::Application::getUserAppDataDir()) / "SavedPreferencePacks";
|
||||
auto resourcePath = fs::path(App::Application::getResourceDir()) / "Gui" / "PreferencePacks";
|
||||
- _preferencePackPaths.push_back(resourcePath);
|
||||
- _preferencePackPaths.push_back(modPath);
|
||||
+ _preferencePackPaths.insert(_preferencePackPaths.begin(), resourcePath);
|
||||
_preferencePackPaths.push_back(savedPath);
|
||||
rescan();
|
||||
|
||||
@@ -232,6 +232,26 @@ void Gui::PreferencePackManager::importConfig(const std::string& packName,
|
||||
rescan();
|
||||
}
|
||||
|
||||
+// TODO(Shvedov): Is this suitable place for this method? It is more generic,
|
||||
+// and maybe more suitable place at Application?
|
||||
+std::vector<boost::filesystem::path> Gui::PreferencePackManager::modPaths() const
|
||||
+{
|
||||
+ auto userModPath = fs::path(App::Application::getUserAppDataDir()) / "Mod";
|
||||
+
|
||||
+ auto& config = App::Application::Config();
|
||||
+ auto additionalModules = config.find("AdditionalModulePaths");
|
||||
+ std::vector<boost::filesystem::path> result;
|
||||
+
|
||||
+ if (additionalModules != config.end()) {
|
||||
+ boost::split(result,
|
||||
+ additionalModules->second,
|
||||
+ boost::is_any_of(";"),
|
||||
+ boost::token_compress_on);
|
||||
+ }
|
||||
+ result.emplace_back(userModPath);
|
||||
+ return result;
|
||||
+}
|
||||
+
|
||||
void Gui::PreferencePackManager::FindPreferencePacksInPackage(const fs::path &mod)
|
||||
{
|
||||
try {
|
||||
@@ -528,7 +548,6 @@ std::vector<PreferencePackManager::TemplateFile> PreferencePackManager::template
|
||||
// (alternate spellings are provided for packages using CamelCase and snake_case, and both major English dialects)
|
||||
|
||||
auto resourcePath = fs::path(App::Application::getResourceDir()) / "Gui";
|
||||
- auto modPath = fs::path(App::Application::getUserAppDataDir()) / "Mod";
|
||||
|
||||
std::string group = "Built-In";
|
||||
if (fs::exists(resourcePath) && fs::is_directory(resourcePath)) {
|
||||
@@ -536,11 +555,13 @@ std::vector<PreferencePackManager::TemplateFile> PreferencePackManager::template
|
||||
std::copy(localFiles.begin(), localFiles.end(), std::back_inserter(_templateFiles));
|
||||
}
|
||||
|
||||
- if (fs::exists(modPath) && fs::is_directory(modPath)) {
|
||||
- for (const auto& mod : fs::directory_iterator(modPath)) {
|
||||
- group = mod.path().filename().string();
|
||||
- const auto localFiles = scanForTemplateFiles(group, mod);
|
||||
- std::copy(localFiles.begin(), localFiles.end(), std::back_inserter(_templateFiles));
|
||||
+ for (const auto& modPath : modPaths()) {
|
||||
+ if (fs::exists(modPath) && fs::is_directory(modPath)) {
|
||||
+ for (const auto& mod : fs::directory_iterator(modPath)) {
|
||||
+ group = mod.path().filename().string();
|
||||
+ const auto localFiles = scanForTemplateFiles(group, mod);
|
||||
+ std::copy(localFiles.begin(), localFiles.end(), std::back_inserter(_templateFiles));
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/src/Gui/PreferencePackManager.h b/src/Gui/PreferencePackManager.h
|
||||
index 301e160df2..e5776e47a0 100644
|
||||
--- a/src/Gui/PreferencePackManager.h
|
||||
+++ b/src/Gui/PreferencePackManager.h
|
||||
@@ -191,6 +191,11 @@ namespace Gui {
|
||||
*/
|
||||
void importConfig(const std::string &packName, const boost::filesystem::path &path);
|
||||
|
||||
+ /**
|
||||
+ * Get a list of all mod directories.
|
||||
+ */
|
||||
+ std::vector<boost::filesystem::path> modPaths() const;
|
||||
+
|
||||
private:
|
||||
|
||||
void FindPreferencePacksInPackage(const boost::filesystem::path& mod);
|
||||
--
|
||||
2.44.1
|
||||
|
98
pkgs/by-name/fr/freecad/freecad-utils.nix
Normal file
98
pkgs/by-name/fr/freecad/freecad-utils.nix
Normal file
@ -0,0 +1,98 @@
|
||||
{
|
||||
runCommand,
|
||||
buildEnv,
|
||||
makeWrapper,
|
||||
lib,
|
||||
python311,
|
||||
writeShellScript,
|
||||
}:
|
||||
let
|
||||
wrapPathsStr =
|
||||
flag: values:
|
||||
builtins.concatStringsSep " " (
|
||||
builtins.concatMap (p: [
|
||||
"--add-flags"
|
||||
flag
|
||||
"--add-flags"
|
||||
p
|
||||
]) values
|
||||
);
|
||||
|
||||
wrapCfgStr =
|
||||
typ: val:
|
||||
let
|
||||
installer = writeShellScript "insteller-${typ}" ''
|
||||
dst="$HOME/.config/FreeCAD/${typ}.cfg"
|
||||
if [ ! -f "$dst" ]; then
|
||||
mkdir -p "$(dirname "$dst")"
|
||||
cp --no-preserve=mode,ownership '${val}' "$dst"
|
||||
fi
|
||||
'';
|
||||
in
|
||||
lib.optionalString (val != null) "--run ${installer}";
|
||||
|
||||
pythonsProcessed = builtins.map (
|
||||
pyt:
|
||||
if builtins.isString pyt then
|
||||
pyt
|
||||
else if builtins.isFunction pyt then
|
||||
"${(python311.withPackages pyt)}/lib/python3.11/site-packages"
|
||||
else
|
||||
throw "Expected string or function as python paths for freecad"
|
||||
);
|
||||
|
||||
makeCustomizable =
|
||||
freecad:
|
||||
freecad
|
||||
// {
|
||||
customize =
|
||||
{
|
||||
name ? freecad.name,
|
||||
modules ? [ ],
|
||||
pythons ? [ ],
|
||||
makeWrapperFlags ? [ ],
|
||||
userCfg ? null,
|
||||
systemCfg ? null,
|
||||
}:
|
||||
let
|
||||
modulesStr = wrapPathsStr "--module-path" modules;
|
||||
pythonsStr = wrapPathsStr "--python-path" (pythonsProcessed pythons);
|
||||
makeWrapperFlagsStr = builtins.concatStringsSep " " (builtins.map (f: "'${f}'") makeWrapperFlags);
|
||||
|
||||
userCfgStr = wrapCfgStr "user" userCfg;
|
||||
systemCfgStr = wrapCfgStr "system" systemCfg;
|
||||
|
||||
bin = runCommand "${name}-bin" { nativeBuildInputs = [ makeWrapper ]; } ''
|
||||
mkdir -p "$out/bin"
|
||||
for exe in FreeCAD{,Cmd}; do
|
||||
if [[ ! -e ${freecad}/bin/$exe ]]; then
|
||||
echo "No binary $exe in freecad package"
|
||||
false
|
||||
fi
|
||||
dest="$out/bin/$exe";
|
||||
makeWrapper "${freecad}/bin/$exe" "$dest" \
|
||||
--inherit-argv0 \
|
||||
${modulesStr} \
|
||||
${pythonsStr} \
|
||||
${userCfgStr} \
|
||||
${systemCfgStr} \
|
||||
${makeWrapperFlagsStr}
|
||||
done
|
||||
ln -s FreeCAD $out/bin/freecad
|
||||
ln -s FreeCADCmd $out/bin/freecadcmd
|
||||
'';
|
||||
in
|
||||
makeCustomizable (buildEnv {
|
||||
inherit name;
|
||||
paths = [
|
||||
(lib.lowPrio freecad)
|
||||
bin
|
||||
];
|
||||
});
|
||||
override = f: makeCustomizable (freecad.override f);
|
||||
overrideAttrs = f: makeCustomizable (freecad.overrideAttrs f);
|
||||
};
|
||||
in
|
||||
{
|
||||
inherit makeCustomizable;
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
{ lib
|
||||
, callPackage
|
||||
, cmake
|
||||
, coin3d
|
||||
, doxygen
|
||||
, eigen
|
||||
, fetchFromGitHub
|
||||
, fmt
|
||||
, freecad
|
||||
, gfortran
|
||||
, gts
|
||||
, hdf5
|
||||
@ -22,7 +22,6 @@
|
||||
, opencascade-occt_7_6
|
||||
, pkg-config
|
||||
, python311Packages
|
||||
, runCommand # for passthru.tests
|
||||
, spaceNavSupport ? stdenv.hostPlatform.isLinux
|
||||
, stdenv
|
||||
, swig
|
||||
@ -60,8 +59,9 @@ let
|
||||
scipy
|
||||
shiboken2
|
||||
;
|
||||
freecad-utils = callPackage ./freecad-utils.nix { };
|
||||
in
|
||||
stdenv.mkDerivation (finalAttrs: {
|
||||
freecad-utils.makeCustomizable (stdenv.mkDerivation (finalAttrs: {
|
||||
pname = "freecad";
|
||||
version = "1.0rc4";
|
||||
|
||||
@ -131,6 +131,7 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
patches = [
|
||||
./0001-NIXOS-don-t-ignore-PYTHONPATH.patch
|
||||
./0002-FreeCad-OndselSolver-pkgconfig.patch
|
||||
./0003-Gui-take-in-account-module-path-argument.patch
|
||||
];
|
||||
|
||||
cmakeFlags = [
|
||||
@ -174,22 +175,7 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
ln -s $out/bin/FreeCADCmd $out/bin/freecadcmd
|
||||
'';
|
||||
|
||||
passthru.tests = {
|
||||
# Check that things such as argument parsing still work correctly with
|
||||
# the above PYTHONPATH patch. Previously the patch used above changed
|
||||
# the `PyConfig_InitIsolatedConfig` to `PyConfig_InitPythonConfig`,
|
||||
# which caused the built-in interpreter to attempt (and fail) to doubly
|
||||
# parse argv. This should catch if that ever regresses and also ensures
|
||||
# that PYTHONPATH is still respected enough for the FreeCAD console to
|
||||
# successfully run and check that it was included in `sys.path`.
|
||||
python-path =
|
||||
runCommand "freecad-test-console"
|
||||
{
|
||||
nativeBuildInputs = [ freecad ];
|
||||
} ''
|
||||
HOME="$(mktemp -d)" PYTHONPATH="$(pwd)/test" FreeCADCmd --log-file $out -c "if not '$(pwd)/test' in sys.path: sys.exit(1)" </dev/null
|
||||
'';
|
||||
};
|
||||
passthru.tests = callPackage ./tests {};
|
||||
|
||||
meta = {
|
||||
homepage = "https://www.freecad.org";
|
||||
@ -214,4 +200,4 @@ stdenv.mkDerivation (finalAttrs: {
|
||||
maintainers = with lib.maintainers; [ gebner srounce ];
|
||||
platforms = lib.platforms.linux;
|
||||
};
|
||||
})
|
||||
}))
|
||||
|
7
pkgs/by-name/fr/freecad/tests/default.nix
Normal file
7
pkgs/by-name/fr/freecad/tests/default.nix
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
callPackage,
|
||||
}:
|
||||
{
|
||||
python-path = callPackage ./python-path.nix { };
|
||||
modules = callPackage ./modules.nix { };
|
||||
}
|
42
pkgs/by-name/fr/freecad/tests/modules.nix
Normal file
42
pkgs/by-name/fr/freecad/tests/modules.nix
Normal file
@ -0,0 +1,42 @@
|
||||
{
|
||||
freecad,
|
||||
runCommand,
|
||||
writeTextFile,
|
||||
}:
|
||||
let
|
||||
mkModule =
|
||||
n:
|
||||
writeTextFile {
|
||||
name = "module-${n}";
|
||||
destination = "/Init.py";
|
||||
text = ''
|
||||
import sys
|
||||
import os
|
||||
|
||||
out = os.environ['out']
|
||||
f = open(out + "/module-${n}.touch", "w")
|
||||
f.write("module-${n}");
|
||||
f.close()
|
||||
'';
|
||||
};
|
||||
module-1 = mkModule "1";
|
||||
module-2 = mkModule "2";
|
||||
freecad-customized = freecad.customize {
|
||||
modules = [
|
||||
module-1
|
||||
module-2
|
||||
];
|
||||
};
|
||||
in
|
||||
runCommand "freecad-test-modules"
|
||||
{
|
||||
nativeBuildInputs = [ freecad-customized ];
|
||||
}
|
||||
''
|
||||
mkdir $out
|
||||
HOME="$(mktemp -d)" FreeCADCmd --log-file $out/freecad.log -c "sys.exit(0)" </dev/null
|
||||
test -f $out/module-1.touch
|
||||
test -f $out/module-2.touch
|
||||
grep -q 'Initializing ${module-1}... done' $out/freecad.log
|
||||
grep -q 'Initializing ${module-2}... done' $out/freecad.log
|
||||
''
|
18
pkgs/by-name/fr/freecad/tests/python-path.nix
Normal file
18
pkgs/by-name/fr/freecad/tests/python-path.nix
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
freecad,
|
||||
runCommand,
|
||||
}:
|
||||
# Check that things such as argument parsing still work correctly with
|
||||
# the above PYTHONPATH patch. Previously the patch used above changed
|
||||
# the `PyConfig_InitIsolatedConfig` to `PyConfig_InitPythonConfig`,
|
||||
# which caused the built-in interpreter to attempt (and fail) to doubly
|
||||
# parse argv. This should catch if that ever regresses and also ensures
|
||||
# that PYTHONPATH is still respected enough for the FreeCAD console to
|
||||
# successfully run and check that it was included in `sys.path`.
|
||||
runCommand "freecad-test-console"
|
||||
{
|
||||
nativeBuildInputs = [ freecad ];
|
||||
}
|
||||
''
|
||||
HOME="$(mktemp -d)" PYTHONPATH="$(pwd)/test" FreeCADCmd --log-file $out -c "if not '$(pwd)/test' in sys.path: sys.exit(1)" </dev/null
|
||||
''
|
Loading…
Reference in New Issue
Block a user