AbdulElahGwaith's picture
Upload folder using huggingface_hub
985c397 verified
# 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