Skip to content

manager

appimage_updater.config.manager

Configuration management with object-oriented API.

AppConfigs(*app_names, config_path=None)

Application configurations manager with iterator support.

Usage

app_configs = AppConfigs("FreeCAD", "OrcaSlicer") for app_config in app_configs: print(app_config.download_dir)

Or access by name

freecad = app_configs["FreeCAD"] freecad.prerelease = True app_configs.save()

Parameters:

Name Type Description Default
*app_names str

Names of applications to load

()
config_path Path | None

Path to configuration file (optional)

None
Source code in src/appimage_updater/config/manager.py
def __init__(self, *app_names: str, config_path: Path | None = None) -> None:
    """Initialize application configurations.

    Args:
        *app_names: Names of applications to load
        config_path: Path to configuration file (optional)
    """
    self._config_path = config_path
    self._config = self._load_config()
    self._app_names = set(app_names) if app_names else set()
    self._filtered_apps = self._get_filtered_apps()

add(app_config)

Add a new application configuration.

Source code in src/appimage_updater/config/manager.py
def add(self, app_config: ApplicationConfig) -> None:
    """Add a new application configuration."""
    # Remove existing config with same name
    self._config.applications = [app for app in self._config.applications if app.name != app_config.name]
    # Add new config
    self._config.applications.append(app_config)
    # Update filtered list if we're filtering by names
    if not self._app_names or app_config.name in self._app_names:
        self._filtered_apps = self._get_filtered_apps()

remove(app_name)

Remove an application configuration.

Source code in src/appimage_updater/config/manager.py
def remove(self, app_name: str) -> None:
    """Remove an application configuration."""
    self._config.applications = [app for app in self._config.applications if app.name != app_name]
    self._filtered_apps = self._get_filtered_apps()

save()

Save configuration to file.

Source code in src/appimage_updater/config/manager.py
def save(self) -> None:
    """Save configuration to file."""
    if self._config_path and self._config_path.is_dir():
        # For directory-based configs, save individual application files
        self._save_directory_based_config()
    else:
        # For file-based configs, save to single file
        self.save_config(self._config, self._config_path)
    logger.info("Application configurations saved")

GlobalConfigManager(config_path=None)

Global configuration manager with property-based access.

Usage

globals = GlobalConfig() globals.concurrent_downloads = 4 globals.timeout_seconds = 60 globals.save()

Parameters:

Name Type Description Default
config_path Path | None

Path to configuration file (optional)

None
Source code in src/appimage_updater/config/manager.py
def __init__(self, config_path: Path | None = None) -> None:
    """Initialize global configuration.

    Args:
        config_path: Path to configuration file (optional)
    """
    self._config_path = config_path
    self._config = self._load_config()

concurrent_downloads property writable

Number of concurrent downloads.

default_auto_subdir property writable

Default auto subdirectory setting.

default_checksum_enabled property writable

Default checksum enabled setting.

default_download_dir property writable

Default download directory.

default_prerelease property writable

Default prerelease setting.

default_retain_count property writable

Default number of old files to retain.

default_rotation_enabled property writable

Default rotation enabled setting.

Default symlink directory.

Default symlink enabled setting.

Default symlink naming pattern.

defaults property

Access to default settings.

timeout_seconds property writable

HTTP timeout in seconds.

user_agent property writable

User agent string for HTTP requests.

get_default_config_dir() staticmethod

Get default configuration directory path.

Source code in src/appimage_updater/config/manager.py
@staticmethod
def get_default_config_dir() -> Path:
    """Get default configuration directory path."""
    # Check for test environment override
    test_config_dir = os.environ.get("APPIMAGE_UPDATER_TEST_CONFIG_DIR")
    if test_config_dir:
        return Path(test_config_dir) / "apps"

    return Path.home() / ".config" / "appimage-updater" / "apps"

get_default_config_path() staticmethod

Get default configuration file path.

Source code in src/appimage_updater/config/manager.py
@staticmethod
def get_default_config_path() -> Path:
    """Get default configuration file path."""
    # Check for test environment override
    test_config_dir = os.environ.get("APPIMAGE_UPDATER_TEST_CONFIG_DIR")
    if test_config_dir:
        return Path(test_config_dir) / "config.json"

    return Path.home() / ".config" / "appimage-updater" / "config.json"

save()

Save configuration to file.

Source code in src/appimage_updater/config/manager.py
def save(self) -> None:
    """Save configuration to file."""
    self.save_config(self._config, self._config_path)
    logger.info("Global configuration saved")

save_global_config_only(config_file=None, config_dir=None)

Save only global config, preserving existing applications.

Source code in src/appimage_updater/config/manager.py
def save_global_config_only(self, config_file: Path | None = None, config_dir: Path | None = None) -> None:
    """Save only global config, preserving existing applications."""
    target_file = self.get_target_config_path(config_file, config_dir)

    # Build global config dict
    global_config_dict = {
        "global_config": self._config.global_config.model_dump(),
    }

    # Preserve existing applications
    config_dict = self.preserve_applications_in_config_file(target_file, global_config_dict)

    # Ensure parent directory exists
    target_file.parent.mkdir(parents=True, exist_ok=True)

    # Write to file
    with target_file.open("w") as f:
        json.dump(config_dict, f, indent=2, default=str)

    logger.info(f"Saved global configuration to: {target_file}")

Manager

Base configuration manager class with common functionality.

delete_app_config_files(app_names, config_dir)

Delete specific app config files from directory.

Source code in src/appimage_updater/config/manager.py
def delete_app_config_files(self, app_names: list[str], config_dir: Path) -> None:
    """Delete specific app config files from directory."""
    for app_name in app_names:
        app_file = config_dir / f"{app_name.lower()}.json"
        if app_file.exists():
            app_file.unlink()
            logger.debug(f"Deleted app config file: {app_file}")

get_target_config_path(config_file, config_dir)

Determine target config path based on file/dir preferences.

Source code in src/appimage_updater/config/manager.py
def get_target_config_path(self, config_file: Path | None, config_dir: Path | None) -> Path:
    """Determine target config path based on file/dir preferences."""
    if config_file:
        return config_file
    elif config_dir:
        config_dir.mkdir(parents=True, exist_ok=True)
        return config_dir / "global.json"
    else:
        # Use defaults
        default_dir = GlobalConfigManager.get_default_config_dir()
        default_file = GlobalConfigManager.get_default_config_path()

        if default_dir.exists():
            return default_dir.parent / "config.json"
        elif default_file.exists():
            return default_file
        else:
            # Create new directory-based structure
            default_dir.mkdir(parents=True, exist_ok=True)
            return default_dir.parent / "config.json"

load_config(config_path=None)

Load configuration from file or directory.

Source code in src/appimage_updater/config/manager.py
def load_config(self, config_path: Path | None = None) -> Config:
    """Load configuration from file or directory."""
    if config_path is None:
        config_path = GlobalConfigManager.get_default_config_path()
        # Check if directory-based config exists
        config_dir = config_path.parent / "apps"
        if config_dir.exists() and config_dir.is_dir():
            return self._load_config_from_directory(config_dir)

    if config_path.is_dir():
        return self._load_config_from_directory(config_path)
    else:
        return self._load_config_from_file(config_path)

preserve_applications_in_config_file(target_file, global_config_dict)

Preserve existing applications when saving global config only.

Source code in src/appimage_updater/config/manager.py
def preserve_applications_in_config_file(
    self, target_file: Path, global_config_dict: dict[str, Any]
) -> dict[str, Any]:
    """Preserve existing applications when saving global config only."""
    config_dict = global_config_dict.copy()

    if target_file.exists():
        try:
            with target_file.open() as f:
                existing_config = json.load(f)
                if "applications" in existing_config:
                    config_dict["applications"] = existing_config["applications"]
        except (json.JSONDecodeError, KeyError, OSError) as e:
            logger.warning(f"Failed to preserve applications from {target_file}: {e}")

    return config_dict

save_config(config, config_path=None)

Save configuration to file.

Source code in src/appimage_updater/config/manager.py
def save_config(self, config: Config, config_path: Path | None = None) -> None:
    """Save configuration to file."""
    if config_path is None:
        config_path = GlobalConfigManager.get_default_config_path()

    # Ensure parent directory exists
    config_path.parent.mkdir(parents=True, exist_ok=True)

    # Convert to dict and save as JSON
    config_dict = {
        "global_config": config.global_config.model_dump(),
        "applications": [app.model_dump() for app in config.applications],
    }

    with config_path.open("w") as f:
        json.dump(config_dict, f, indent=2, default=str)

save_directory_config(config, config_dir)

Save config to directory-based structure with separate files per app.

Source code in src/appimage_updater/config/manager.py
def save_directory_config(self, config: Config, config_dir: Path) -> None:
    """Save config to directory-based structure with separate files per app."""
    # Ensure directory exists
    config_dir.mkdir(parents=True, exist_ok=True)

    # Save global config
    self.update_global_config_in_directory(config, config_dir)

    # Save each application as a separate file
    for app in config.applications:
        app_filename = f"{app.name.lower()}.json"
        app_file_path = config_dir / app_filename

        # Create application config structure
        app_config_dict = {"applications": [app.model_dump()]}

        with app_file_path.open("w") as f:
            json.dump(app_config_dict, f, indent=2, default=str)

    logger.info(f"Saved directory-based configuration to: {config_dir}")

save_single_file_config(config, config_path=None)

Save entire config to a single JSON file.

Source code in src/appimage_updater/config/manager.py
def save_single_file_config(self, config: Config, config_path: Path | None = None) -> None:
    """Save entire config to a single JSON file."""
    if config_path is None:
        config_path = GlobalConfigManager.get_default_config_path()

    # Ensure parent directory exists
    config_path.parent.mkdir(parents=True, exist_ok=True)

    # Convert to dict and save as JSON
    config_dict = {
        "global_config": config.global_config.model_dump(),
        "applications": [app.model_dump() for app in config.applications],
    }

    with config_path.open("w") as f:
        json.dump(config_dict, f, indent=2, default=str)

    logger.info(f"Saved configuration to: {config_path}")

update_application_in_config_directory(app_config, config_dir)

Update single application in config directory.

Source code in src/appimage_updater/config/manager.py
def update_application_in_config_directory(self, app_config: ApplicationConfig, config_dir: Path) -> None:
    """Update single application in config directory."""

    app_name_lower = app_config.name.lower()

    # Find the config file containing this app
    for config_file in config_dir.glob("*.json"):
        try:
            with config_file.open() as f:
                config_data = json.load(f)
        except (json.JSONDecodeError, OSError):
            continue

        applications = config_data.get("applications", [])
        for i, app in enumerate(applications):
            if app.get("name", "").lower() == app_name_lower:
                applications[i] = app_config.model_dump()
                config_data["applications"] = applications

                # Write back to file
                with config_file.open("w") as f:
                    json.dump(config_data, f, indent=2, default=str)

                logger.info(f"Updated application '{app_config.name}' in: {config_file}")
                return

    raise ValueError(f"Application '{app_config.name}' not found in configuration directory")

update_application_in_config_file(app_config, config_file)

Update single application in a JSON config file.

Source code in src/appimage_updater/config/manager.py
def update_application_in_config_file(self, app_config: ApplicationConfig, config_file: Path) -> None:
    """Update single application in a JSON config file."""

    # Load existing configuration
    with config_file.open() as f:
        config_data = json.load(f)

    applications = config_data.get("applications", [])
    app_name_lower = app_config.name.lower()

    # Find and update the application
    for i, app in enumerate(applications):
        if app.get("name", "").lower() == app_name_lower:
            applications[i] = app_config.model_dump()
            config_data["applications"] = applications
            break
    else:
        raise ValueError(f"Application '{app_config.name}' not found in configuration file")

    # Write back to file
    with config_file.open("w") as f:
        json.dump(config_data, f, indent=2, default=str)

    logger.info(f"Updated application '{app_config.name}' in: {config_file}")

update_global_config_in_directory(config, config_dir)

Update global config file in directory.

Source code in src/appimage_updater/config/manager.py
def update_global_config_in_directory(self, config: Config, config_dir: Path) -> None:
    """Update global config file in directory."""

    global_config_file = config_dir / "config.json"
    with global_config_file.open("w") as f:
        json.dump(config.global_config.model_dump(), f, indent=2, default=str)

    logger.debug(f"Updated global config in: {global_config_file}")