VOOZH about

URL: https://deepwiki.com/MahoCommerce/maho-composer-plugin/3.1-core-file-copying-process

⇱ Core File Copying Process | MahoCommerce/maho-composer-plugin | DeepWiki


Loading...
Menu

Core File Copying Process

This document details the recursive directory copying algorithm implemented by the FileCopyPlugin class. It explains how the plugin executes its primary responsibility: deploying static assets from the core Maho package and all installed modules to the project's file system. This includes special handling for the mahocommerce/maho package, the maho CLI executable, and module assets from public/, skin/, and js/ directories.

For information about the file preservation mechanism that prevents overwriting customized files, see File Preservation System. For details on how the plugin identifies and filters packages, see Package Type Handling and Asset Discovery.

Event Handler Entry Point

The FileCopyPlugin subscribes to three Composer script events and uses a singleton pattern to ensure execution occurs only once per Composer command, even when multiple events trigger.


Event Subscription and Singleton Pattern

The plugin subscribes to three high-level command events through the getSubscribedEvents method:

EventPurpose
ScriptEvents::POST_INSTALL_CMDTriggered after composer install
ScriptEvents::POST_UPDATE_CMDTriggered after composer update
ScriptEvents::POST_CREATE_PROJECT_CMDTriggered after composer create-project

The onPostCmd method checks self::$hasRun immediately and returns if true, preventing duplicate file operations when Composer fires multiple events during a single command execution.

Sources: src/FileCopyPlugin.php36-51

Execution Flow Overview

The onPostCmd method orchestrates the entire file copying process in three distinct phases: initialization, core package processing, and module asset processing.


Phase Breakdown

  1. Initialization Phase (src/FileCopyPlugin.php53-62): Retrieves the IOInterface for logging, accesses the Composer instance, determines the vendor directory location, and establishes the project root directory using getcwd().

  2. Configuration Phase (src/FileCopyPlugin.php64-73): Loads the preserve-files array from the root package's extra.maho configuration, validating that all entries are strings before storing them in $this->preserveFiles.

  3. Core Package Phase (src/FileCopyPlugin.php76-80): Checks for the presence of vendor/mahocommerce/maho and performs special processing for the core Maho package.

  4. Module Processing Phase (src/FileCopyPlugin.php82-107): Retrieves all installed packages, filters for maho-module and magento-module types, and processes their asset directories.

Sources: src/FileCopyPlugin.php45-108

Core Package Special Treatment

The mahocommerce/maho package receives unique handling that differs from module processing. This special treatment occurs only when the plugin runs in a child project that has mahocommerce/maho as a dependency.


Special Handling Actions

When vendor/mahocommerce/maho exists:

  1. Public Directory Deployment: Recursively copies all contents from vendor/mahocommerce/maho/public/ to the project's public/ directory using copyDirectory().

  2. Executable Installation: Directly copies the maho CLI executable from vendor/mahocommerce/maho/maho to ./maho in the project root using PHP's copy() function (not the recursive copyDirectory() method).

  3. Executable Permissions: Sets executable permissions 0744 (owner: read/write/execute, group/others: read) on the deployed maho script using chmod().

Rationale: This special treatment exists because the core Maho package contains the primary web assets and CLI tool. The plugin performs this step only in child projects (where Maho is a dependency) and not when running within the mahocommerce/maho repository itself.

Sources: src/FileCopyPlugin.php76-80

Module Asset Processing

After handling the core package, the plugin processes all installed modules to deploy their static assets. This phase involves package discovery, type filtering, and multi-directory copying.


Module Discovery and Filtering

The plugin retrieves all installed packages from Composer's LocalRepository and filters them using array_filter() with a callback that checks if the package type is either 'magento-module' or 'maho-module'.

Package Path Resolution

For each module, the plugin determines the correct source path by checking if a modman symlink exists:

Priority 1: vendor/mahocommerce/maho-modman-symlinks/{packageName}
Priority 2: vendor/{packageName}

This dual-path resolution allows the plugin to work with both packages that use modman-style symlink deployment (see ModmanPlugin Module Deployment) and packages that use standard Composer directory structure.

Asset Directory Processing

The plugin conditionally copies three types of asset directories:

DirectoryDestinationPurpose
public/public/General web-accessible files (images, CSS, etc.)
skin/public/skin/Theme-related assets (Magento 1.x convention)
js/public/js/JavaScript libraries and modules

Each directory is only processed if it exists in the source package. The copyDirectory() method merges assets from all modules into the shared destination directories.

Sources: src/FileCopyPlugin.php82-107

Recursive Copy Algorithm

The copyDirectory method implements a depth-first recursive algorithm that handles both files and directories, respecting the file preservation configuration.


Algorithm Characteristics

The recursive copying algorithm exhibits the following behavior:

  1. Pre-order Directory Creation: Creates the destination directory with @mkdir($dst, 0777, true) before processing contents. The @ suppressor prevents warnings if the directory already exists. The true parameter enables recursive parent directory creation.

  2. Depth-First Traversal: Processes directories recursively before continuing with sibling entries, ensuring complete subtree copying.

  3. Entry Filtering: Skips . and .. pseudo-entries to prevent infinite recursion and invalid paths.

  4. Relative Path Calculation: Converts absolute destination paths to project-relative paths by removing the $this->projectDir prefix, enabling comparison against the preserve-files configuration.

  5. Conditional File Preservation: Checks each file against $this->preserveFiles array before copying. Files are preserved (skipped) only if both conditions are true:

    • The relative path exists in the preserveFiles array
    • The destination file already exists on disk
  6. Verbose Logging: Outputs skipped file messages only when IOInterface::VERBOSE mode is enabled, reducing noise during normal operations.

Error Handling

The method includes two error paths:

  • Missing Source: Logs a message and returns early if the source directory doesn't exist
  • Unopenable Directory: Logs a message and returns early if opendir() fails

Both errors are non-fatal; execution continues with subsequent directories.

Sources: src/FileCopyPlugin.php110-143

Integration with Composer's File System

The file copying process integrates with Composer's configuration system and file layout conventions.


Composer API Integration Points

API MethodPurposeUsage in Plugin
Config::get('vendor-dir')Retrieves vendor directory pathDetermines base path for package locations
RepositoryManager::getLocalRepository()Accesses installed packagesQueries for module packages to process
RootPackage::getExtra()Retrieves custom configurationLoads preserve-files settings
IOInterface::write()Outputs messagesLogs directory processing and preservation

The plugin respects Composer's vendor directory configuration, allowing projects to customize the location of installed dependencies through the vendor-dir setting in composer.json.

Sources: src/FileCopyPlugin.php53-107