FreeCAD / src /App /ApplicationDirectories.h
AbdulElahGwaith's picture
Upload folder using huggingface_hub
985c397 verified
// SPDX-License-Identifier: LGPL-2.1-or-later
/***************************************************************************************************
* *
* Copyright (c) 2002 Jürgen Riegel <juergen.riegel@web.de> *
* Copyright (c) 2025 The FreeCAD project association AISBL *
* *
* 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/>. *
* *
**************************************************************************************************/
#ifndef SRC_APP_APPLICATIONDIRECTORIES_H_
#define SRC_APP_APPLICATIONDIRECTORIES_H_
#include "FCConfig.h"
#include "FCGlobal.h"
#include <filesystem>
#include <map>
#include <string>
#include <vector>
#ifdef FC_OS_WIN32
#include <QString>
#endif
namespace App {
/// A helper class to handle application-wide directory management on behalf of the main
/// App::Application class. Most of this class's methods were originally in Application, and
/// were extracted here to be more easily testable (and to better follow the single-
/// responsibility principle, though further work is required in that area).
class AppExport ApplicationDirectories {
public:
/// Constructor
/// \param config The base configuration dictionary. Used to create the appropriate
/// directories, and updated to reflect their locations. New code should not directly access
/// elements of this dictionary to determine directory locations, but should instead use
/// the public methods of this class to determine the locations needed.
explicit ApplicationDirectories(std::map<std::string,std::string> &config);
/// Given argv[0], figure out the home path. Used to initialize the AppHomePath element of
/// the configuration map prior to instantiating this class.
static std::filesystem::path findHomePath(const char* sCall);
/// "Home" here is the parent directory of the actual executable file being run. It is
/// exposed here primarily for historical compatibility reasons, and new code should almost
/// certainly NOT use this path for anything. See alternatives in the
/// `App::ApplicationDirectories` class.
const std::filesystem::path& getHomePath() const;
/// Get the user's home directory. This should not be used for many things, use caution when
/// deciding to use it for anything, there are usually better places.
const std::filesystem::path& getUserHomePath() const;
/// Temp path is the location of all temporary files: it is not guaranteed to preserve
/// information between runs of the program, but *is* guaranteed to exist for the duration
/// of a single program execution (that is, files are not deleted from it *during* the run).
const std::filesystem::path& getTempPath() const;
/// Get a file in the temp directory. WARNING: NOT THREAD-SAFE! Currently just forwards to
/// the FileInfo class. TODO: Rewrite to be thread safe
std::filesystem::path getTempFileName(const std::string & filename = "") const;
/// The user cache path can be used to store files that the program *prefers* not be deleted
/// between runs, but that will be recreated or otherwise handled if they do not exist due
/// to the cache being cleared. There is no guarantee that the files will exist from
/// run-to-run, but an effort is made to preserve them (unlike the temp directory, which
/// should never be used to save data between runs).
const std::filesystem::path& getUserCachePath() const;
/// The primary directory used to store per-user application data. This is the parent
/// directory of all installed addons, per-user configuration files, etc. Developers looking
/// for a place to put per-user data should begin here. Common subdirectories include "Mod",
/// "Macros", "Materials" and many others that don't begin with the letter "M". This is
/// typically a versioned directory, though users may choose to use a single path for
/// multiple versions of the software.
const std::filesystem::path& getUserAppDataDir() const;
/// Historically, a single directory was used to store user-created (or user-installed)
/// macro files. This is the path to that directory. Note that going forward it should *not*
/// be assumed that all installed macros are located in this directory. This is typically a
/// versioned directory, though users may choose to use a single path for multiple versions
/// of the software.
const std::filesystem::path& getUserMacroDir() const;
/// The "resource" directory should be used to store non-ephemeral resources such as icons,
/// templates, hardware setup, etc. -- items that should be preserved from run-to-run of the
/// program, and between versions. This is *not* a versioned directory, and multiple
/// versions of the software may access the same data.
const std::filesystem::path& getResourceDir() const;
/// Nominally, this is the directory where "help" files are stored, though for historical
/// reasons several other informational files are stored here as well. It should only be
/// used for user-facing informational files.
const std::filesystem::path& getHelpDir() const;
/// The root path of user config files `user.cfg` and `system.cfg`.
const std::filesystem::path& getUserConfigPath() const;
/// The directory of all extension modules. Added to `sys.path` during Python
/// initialization.
const std::filesystem::path& getLibraryDir() const;
/// Get the user's home directory
static std::filesystem::path getUserHome();
/// Returns true if the current active directory set is custom, and false if it's the
/// standard system default.
bool usingCustomDirectories() const;
// Versioned-Path Management Methods:
/// Determine if a given config path is for the current version of the program
/// \param config The path to check
bool usingCurrentVersionConfig(std::filesystem::path config) const;
/// Migrate a set of versionable configuration directories from the given path to a new
/// version. The new version's directories cannot exist yet, and the old ones *must* exist.
/// If the old paths are themselves versioned, then the new paths will be placed at the same
/// level in the directory structure (e.g., they will be siblings of each entry in paths).
/// If paths are NOT versioned, the new (versioned) copies will be placed *inside* the
/// original paths.
void migrateAllPaths(const std::vector<std::filesystem::path> &paths) const;
/// A utility method to generate the versioned directory name for a given version. This only
/// returns the version string, not an entire path. As of FreeCAD 1.1, the string is of the
/// form "vX-Y" where X is the major version and Y is the minor, but external code should
/// not assume that is always the form, and should instead use this method, which is
/// guaranteed stable (that is, given "1" and "1" as the major and minor, it will always
/// return the string "v1-1", even if in later versions the format changes.
static std::string versionStringForPath(int major, int minor);
/// Given an arbitrary path, determine if it has the correct form to be a versioned path
/// (e.g. is the last component a recognized version of the code). DOES NOT recognize
/// versions *newer* than the current version, even if the directory name matches the path
/// naming convention used by the previous version.
bool isVersionedPath(const std::filesystem::path &startingPath) const;
/// Given a base path that is expected to contained versioned subdirectories, locate the
/// directory name (*not* the path, only the final component, the version string itself)
/// corresponding to the most recent version of the software, up to and including the
/// current version, but NOT exceeding it.
std::string mostRecentAvailableConfigVersion(const std::filesystem::path &startingPath) const;
/// Given a base path that is expected to contained versioned subdirectories, locate the
/// directory corresponding to the most recent version of the software, up to and including
/// the current version, but NOT exceeding it.
std::filesystem::path mostRecentConfigFromBase(const std::filesystem::path &startingPath) const;
/// A utility method to copy all files and directories from oldPath to newPath, handling the
/// case where newPath might itself be a subdirectory of oldPath (and *not* attempting that
/// otherwise-recursive copy).
static void migrateConfig(const std::filesystem::path &oldPath, const std::filesystem::path &newPath);
#ifdef FC_OS_WIN32
/// On Windows, gets the location of the user's "AppData" directory. Invalid on other OSes.
QString getOldGenericDataLocation();
#endif
/// Adds subdirectory information to the appData vector for use in constructing full paths to config files, etc.
static void getSubDirectories(const std::map<std::string,std::string>& mConfig,
std::vector<std::string>& appData);
/// To a given path it adds the subdirectories where to store application-specific files.
/// On Linux or BSD a hidden directory (i.e. starting with a dot) is added.
static void getOldDataLocation(const std::map<std::string,std::string>& mConfig,
std::vector<std::string>& appData);
/// If the passed path name is not empty, it will be returned, otherwise the user home path of the system will
/// be returned.
static std::filesystem::path findUserHomePath(const std::filesystem::path& userHome);
protected:
/// Override all application directories with temp directories. Returns true on success and
/// false if the temp directory creation failed.
bool startSafeMode(std::map<std::string,std::string>& mConfig);
/// Take a path and add a version to it, if it's possible to do so. A version can be
/// appended only if a) the versioned subdirectory already exists, or b) pathToCheck/subdirs
/// does NOT yet exist. This does not actually create any directories, just determines
/// if we can append the versioned directory name to subdirs.
void appendVersionIfPossible(const std::filesystem::path& basePath,
std::vector<std::string> &subdirs) const;
static std::filesystem::path findPath(
const std::filesystem::path& stdHome,
const std::filesystem::path& customHome,
const std::vector<std::string>& paths,
bool create);
void configurePaths(std::map<std::string,std::string> &config);
void configureResourceDirectory(const std::map<std::string,std::string>& mConfig);
void configureLibraryDirectory(const std::map<std::string,std::string>& mConfig);
void configureHelpDirectory(const std::map<std::string,std::string>& mConfig);
/*!
* Returns a tuple of path names where to store config, data, and temp. files.
* The method therefore reads the environment variables:
* \list
* \li FREECAD_USER_HOME
* \li FREECAD_USER_DATA
* \li FREECAD_USER_TEMP
* \endlist
*/
static std::tuple<std::filesystem::path, std::filesystem::path, std::filesystem::path> getCustomPaths();
/*!
* Returns a tuple of XDG-compliant standard paths names where to store config, data and cached files.
* The method therefore reads the environment variables:
* \list
* \li XDG_CONFIG_HOME
* \li XDG_DATA_HOME
* \li XDG_CACHE_HOME
* \endlist
*/
std::tuple<std::filesystem::path, std::filesystem::path, std::filesystem::path, std::filesystem::path> getStandardPaths();
/// Find the BuildVersionMajor, BuildVersionMinor pair in the config map, convert them to an int tuple, and
/// return it. If the pair is not found, or cannot be converted to integers, a RuntimeError is raised.
/// \param config The config map to search.
/// \return The version tuple.
static std::tuple<int, int> extractVersionFromConfigMap(const std::map<std::string,std::string> &config);
/// A utility method to remove any stray null characters from a path (Conda sometimes
/// injects these for unknown reasons -- see #6892 in the bug tracker).
/// \param pathAsString The std::string path to sanitize
/// \returns A path with any stray nulls removed
static std::filesystem::path sanitizePath(const std::string& pathAsString);
private:
std::tuple<int, int> _currentVersion;
std::filesystem::path _home;
std::filesystem::path _temp;
std::filesystem::path _userCache;
std::filesystem::path _userConfig;
std::filesystem::path _userAppData;
std::filesystem::path _userMacro;
std::filesystem::path _userHome;
std::filesystem::path _resource;
std::filesystem::path _library;
std::filesystem::path _help;
bool _usingCustomDirectories {false};
};
} // App
#endif //SRC_APP_APPLICATIONDIRECTORIES_H_