public function swapPublish($filename, $hash)
    {
        if ($this->getVisibility($filename, $hash) === AssetStore::VISIBILITY_PUBLIC) {
            // The file is already publish
            return;
        }

        $parsedFileID = new ParsedFileID($filename, $hash);
        $from = $this->getProtectedFilesystem();
        $to = $this->getPublicFilesystem();
        $fromStrategy = $this->getProtectedResolutionStrategy();
        $toStrategy = $this->getPublicResolutionStrategy();
        // Contain a list of temporary file that needs to be move to the $from store once we are done.


        // Look for files that might be overriden by publishing to destination store, those need to be stashed away
        /** @var ParsedFileID $variantParsedFileID */
        $swapFileIDStr = $toStrategy->buildFileID($parsedFileID);
        $swapFiles = [];
        if ($to->has($swapFileIDStr)) {
            $swapParsedFileID = $toStrategy->resolveFileID($swapFileIDStr, $to);
            foreach ($toStrategy->findVariants($swapParsedFileID, $to) as $variantParsedFileID) {
                $toFileID = $variantParsedFileID->getFileID();
                $fromFileID = $fromStrategy->buildFileID($variantParsedFileID);

                // Cache destination file into the origin store under a `.swap` directory
                $stream = $to->readStream($toFileID);
                $from->putStream('.swap/' . $fromFileID, $stream);
                if (is_resource($stream)) {
                    fclose($stream);
                }
                $swapFiles[] = $variantParsedFileID->setFileID($fromFileID);

                // Blast existing variants from the destination
                $to->delete($toFileID);
                $this->truncateDirectory(dirname($toFileID), $to);
            }
        }


        // Let's find all the variants on the origin store ... those need to be moved to the destination
        /** @var ParsedFileID $variantParsedFileID */
        foreach ($fromStrategy->findVariants($parsedFileID, $from) as $variantParsedFileID) {
            // Copy via stream
            $fromFileID = $variantParsedFileID->getFileID();
            $toFileID = $toStrategy->buildFileID($variantParsedFileID);

            $stream = $from->readStream($fromFileID);
            $to->putStream($toFileID, $stream);
            if (is_resource($stream)) {
                fclose($stream);
            }

            // Remove the origin file and keep the file ID
            $from->delete($fromFileID);
            $this->truncateDirectory(dirname($fromFileID), $from);
        }

        foreach ($swapFiles as $variantParsedFileID) {
            $fileID = $variantParsedFileID->getFileID();
            $from->rename('.swap/' . $fileID, $fileID);
        }
        $from->deleteDir('.swap');
    }