249 lines
11 KiB
Python
249 lines
11 KiB
Python
# SPDX-License-Identifier: LGPL-2.1-or-later
|
|
# ***************************************************************************
|
|
# * *
|
|
# * Copyright (c) 2025 sliptonic <shopinthewoods@gmail.com> *
|
|
# * *
|
|
# * This file is part of FreeCAD. *
|
|
# * *
|
|
# * FreeCAD is free software: you can redistribute it and/or modify it *
|
|
# * under the terms of the GNU Lesser General Public License as *
|
|
# * published by the Free Software Foundation, either version 2.1 of the *
|
|
# * License, or (at your option) any later version. *
|
|
# * *
|
|
# * FreeCAD is distributed in the hope that it will be useful, but *
|
|
# * WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
|
# * Lesser General Public License for more details. *
|
|
# * *
|
|
# * You should have received a copy of the GNU Lesser General Public *
|
|
# * License along with FreeCAD. If not, see *
|
|
# * <https://www.gnu.org/licenses/>. *
|
|
# * *
|
|
# ***************************************************************************
|
|
"""
|
|
CAM Asset Migration Module
|
|
|
|
Handles migration of CAM assets during FreeCAD version upgrades.
|
|
"""
|
|
|
|
import FreeCAD
|
|
import Path
|
|
import Path.Preferences
|
|
import pathlib
|
|
import os
|
|
import glob
|
|
from ..assets.ui import AssetOpenDialog
|
|
from ..camassets import cam_assets
|
|
from ..library.serializers import all_serializers as library_serializers
|
|
from ..library.models import Library
|
|
|
|
# Logging setup - same pattern as Job.py
|
|
if False:
|
|
Path.Log.setLevel(Path.Log.Level.DEBUG, Path.Log.thisModule())
|
|
Path.Log.trackModule(Path.Log.thisModule())
|
|
else:
|
|
Path.Log.setLevel(Path.Log.Level.INFO, Path.Log.thisModule())
|
|
|
|
if FreeCAD.GuiUp:
|
|
import FreeCADGui
|
|
from PySide.QtWidgets import QApplication, QMessageBox
|
|
from PySide.QtCore import Qt
|
|
|
|
|
|
class CAMAssetMigrator:
|
|
"""
|
|
Handles migration of CAM assets during FreeCAD version upgrades.
|
|
|
|
This class provides functionality to:
|
|
- Check if migration is needed for custom CAM asset locations
|
|
- Offer migration to users through a dialog
|
|
- Perform the actual asset migration with versioned directories
|
|
"""
|
|
|
|
def __init__(self):
|
|
self.pref_group_path = "User parameter:BaseApp/Preferences/Mod/CAM/Migration"
|
|
|
|
def check_migration_needed(self):
|
|
self.check_asset_location()
|
|
self.check_tool_library_workdir()
|
|
|
|
def check_asset_location(self):
|
|
"""
|
|
Check if CAM asset migration is needed for version upgrade.
|
|
|
|
This method determines if the current CAM assets are stored in a custom
|
|
location outside the default user data directory and if migration has
|
|
not been offered for the current FreeCAD version.
|
|
"""
|
|
Path.Log.debug("Starting CAM asset migration check")
|
|
|
|
try:
|
|
# Get current directories
|
|
user_app_data_dir = FreeCAD.getUserAppDataDir()
|
|
user_app_data_path = pathlib.Path(user_app_data_dir)
|
|
Path.Log.debug(f"User app data directory: {user_app_data_dir}")
|
|
|
|
# Get the current CAM asset path (may be naked or versioned)
|
|
current_asset_path = Path.Preferences.getAssetPath()
|
|
current_asset_pathlib = pathlib.Path(current_asset_path)
|
|
Path.Log.debug(f"Current CAM asset path: {current_asset_path}")
|
|
|
|
# Only migrate if CamAssets is outside the standard user data directory
|
|
if current_asset_pathlib.is_relative_to(user_app_data_path):
|
|
Path.Log.debug("CamAssets is in default location, no custom migration needed")
|
|
return
|
|
|
|
# Check if migration has already been offered for this version
|
|
if self.has_migration_been_offered():
|
|
Path.Log.debug("Migration has already been offered for this version, skipping")
|
|
return
|
|
|
|
# Determine the base path (naked path without version)
|
|
if FreeCAD.ApplicationDirectories.isVersionedPath(str(current_asset_path)):
|
|
# Check if we're already using the current version
|
|
if FreeCAD.ApplicationDirectories.usingCurrentVersionConfig(
|
|
str(current_asset_path)
|
|
):
|
|
Path.Log.debug("Already using current version, no migration needed")
|
|
return
|
|
|
|
Path.Log.info("Asset relocation is needed and should be offered")
|
|
if self._offer_asset_relocation():
|
|
self._migrate_assets(str(current_asset_path))
|
|
return
|
|
|
|
except Exception as e:
|
|
Path.Log.error(f"Error checking CAM asset migration: {e}")
|
|
import traceback
|
|
|
|
Path.Log.info(f"Full traceback: {traceback.format_exc()}")
|
|
return
|
|
|
|
def check_tool_library_workdir(self):
|
|
workdir_str = "LastPathToolLibrary"
|
|
migrated_str = "Migrated" + workdir_str
|
|
workdir = Path.Preferences.preferences().GetString(workdir_str)
|
|
migrated_dir = Path.Preferences.preferences().GetString(migrated_str)
|
|
Path.Log.debug(f"workdir: {workdir}, migrated: {migrated_dir}")
|
|
if workdir and not migrated_dir:
|
|
# Look for tool libraries to import
|
|
if os.path.isdir(workdir):
|
|
libraries = [f for f in glob.glob(workdir + os.path.sep + "*.fctl")]
|
|
libraries.sort()
|
|
if len(libraries):
|
|
# Migrate libraries, automatically and silently
|
|
Path.Log.info("Migrating tool libraries into CAM assets")
|
|
for library in libraries:
|
|
Path.Log.info("Migrating " + library)
|
|
import_dialog = AssetOpenDialog(
|
|
cam_assets,
|
|
asset_class=Library,
|
|
serializers=library_serializers,
|
|
parent=None,
|
|
)
|
|
asset = import_dialog.deserialize_file(pathlib.Path(library), quiet=True)
|
|
if asset:
|
|
cam_assets.add(asset)
|
|
|
|
# Mark directory as migrated
|
|
Path.Preferences.preferences().SetString(migrated_str, workdir)
|
|
|
|
def _offer_asset_relocation(self):
|
|
"""
|
|
Present asset relocation dialog to user.
|
|
|
|
Returns:
|
|
bool: True if user accepted relocation, False otherwise
|
|
"""
|
|
# Get current version info
|
|
major = int(FreeCAD.ConfigGet("BuildVersionMajor"))
|
|
minor = int(FreeCAD.ConfigGet("BuildVersionMinor"))
|
|
current_version = FreeCAD.ApplicationDirectories.versionStringForPath(major, minor)
|
|
|
|
# Get current asset path for display
|
|
current_asset_path = Path.Preferences.getAssetPath()
|
|
|
|
Path.Log.debug(f"Offering asset relocation to user for version {current_version}")
|
|
|
|
if not FreeCAD.GuiUp:
|
|
Path.Log.debug("GUI not available, skipping migration offer")
|
|
return False
|
|
|
|
msg = (
|
|
f"FreeCAD has been upgraded to version {current_version}.\n\n"
|
|
f"Your CAM assets are stored in a custom location:\n{current_asset_path}\n\n"
|
|
"Would you like to migrate your CAM assets to a versioned directory "
|
|
"to preserve them during future upgrades?\n\n"
|
|
"This will copy your assets to a new directory."
|
|
)
|
|
|
|
Path.Log.debug("Showing asset relocation dialog to user")
|
|
|
|
reply = QMessageBox.question(
|
|
None, "CAM Asset Migration", msg, QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes
|
|
)
|
|
|
|
# Record that we offered migration for this version
|
|
pref_group = FreeCAD.ParamGet(self.pref_group_path)
|
|
offered_versions = pref_group.GetString("OfferedToMigrateCAMAssets", "")
|
|
known_versions = set(offered_versions.split(",")) if offered_versions else set()
|
|
known_versions.add(current_version)
|
|
pref_group.SetString("OfferedToMigrateCAMAssets", ",".join(known_versions))
|
|
Path.Log.debug(f"Updated offered versions: {known_versions}")
|
|
|
|
if reply == QMessageBox.Yes:
|
|
Path.Log.info("User accepted migration, starting asset migration")
|
|
return True
|
|
else:
|
|
Path.Log.info("User declined migration")
|
|
return False
|
|
|
|
def _migrate_assets(self, source_path):
|
|
"""
|
|
Perform actual directory copying and preference updates.
|
|
|
|
Args:
|
|
source_path: Current CAM asset directory path
|
|
"""
|
|
Path.Log.info(f"Starting asset migration from {source_path}")
|
|
|
|
try:
|
|
FreeCAD.ApplicationDirectories.migrateAllPaths([source_path])
|
|
Path.Log.info(
|
|
"Migration complete - preferences will be handled automatically by the system"
|
|
)
|
|
|
|
if FreeCAD.GuiUp:
|
|
QMessageBox.information(
|
|
None,
|
|
"Migration Complete",
|
|
f"CAM assets have been migrated from:\n{source_path}\n\n"
|
|
"The system will automatically handle preference updates.",
|
|
)
|
|
|
|
except Exception as e:
|
|
error_msg = f"Failed to migrate CAM assets: {e}"
|
|
Path.Log.error(error_msg)
|
|
import traceback
|
|
|
|
Path.Log.debug(f"Migration error traceback: {traceback.format_exc()}")
|
|
if FreeCAD.GuiUp:
|
|
QMessageBox.critical(None, "Migration Failed", error_msg)
|
|
|
|
def has_migration_been_offered(self):
|
|
"""
|
|
Check if migration has been offered for current version.
|
|
|
|
Returns:
|
|
bool: True if migration was offered for this version
|
|
"""
|
|
|
|
pref_group = FreeCAD.ParamGet(self.pref_group_path)
|
|
major = int(FreeCAD.ConfigGet("BuildVersionMajor"))
|
|
minor = int(FreeCAD.ConfigGet("BuildVersionMinor"))
|
|
|
|
current_version_string = FreeCAD.ApplicationDirectories.versionStringForPath(major, minor)
|
|
offered_versions = pref_group.GetString("OfferedToMigrateCAMAssets", "")
|
|
known_versions = set(offered_versions.split(",")) if offered_versions else set()
|
|
return current_version_string in known_versions
|