Skip to content

Commit

Permalink
Create absolute symlinks if relative symlinks are not supported (see #…
Browse files Browse the repository at this point in the history
  • Loading branch information
leofeyer committed Apr 17, 2015
1 parent e3b81ca commit 77c1c10
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 22 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Expand Up @@ -4,6 +4,9 @@ Contao change log
Version 4.0.0-RC1 (2014-05-XX)
------------------------------

### Fixed
Create absolute symlinks if relative symlinks are not supported (see #208).

### Removed
The "postFlushData" hook has been removed (see #196).

Expand Down
12 changes: 12 additions & 0 deletions src/Analyzer/HtaccessAnalyzer.php
Expand Up @@ -38,6 +38,18 @@ public function __construct(\SplFileInfo $file)
$this->file = $file;
}

/**
* Creates a new object instance.
*
* @param \SplFileInfo $file The file object
*
* @return static The object instance
*/
public static function create(\SplFileInfo $file)
{
return new static($file);
}

/**
* Checks whether the .htaccess file grants access via HTTP.
*
Expand Down
62 changes: 40 additions & 22 deletions src/Command/SymlinksCommand.php
Expand Up @@ -15,6 +15,7 @@
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Filesystem\Exception\IOException;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Finder\SplFileInfo;
Expand Down Expand Up @@ -81,9 +82,9 @@ public function generateSymlinks($rootDir, OutputInterface $output)
$this->symlinkThemes($rootDir, $output);

// Symlink the assets and themes directory
$this->symlink('../assets', 'web/assets', $rootDir, $output);
$this->symlink('../../system/themes', 'web/system/themes', $rootDir, $output);
$this->symlink('../app/logs', 'system/logs', $rootDir, $output);
$this->symlink('assets', 'web/assets', $rootDir, $output);
$this->symlink('system/themes', 'web/system/themes', $rootDir, $output);
$this->symlink('app/logs', 'system/logs', $rootDir, $output);
}

/**
Expand All @@ -95,7 +96,7 @@ public function generateSymlinks($rootDir, OutputInterface $output)
*/
private function symlinkFiles($uploadPath, $rootDir, OutputInterface $output)
{
$this->relativeSymlink(
$this->createSymlinksFromFinder(
$this->findIn("$rootDir/$uploadPath")->files()->name('.public'),
$uploadPath,
$rootDir,
Expand All @@ -112,12 +113,10 @@ private function symlinkFiles($uploadPath, $rootDir, OutputInterface $output)
private function symlinkModules($rootDir, OutputInterface $output)
{
$filter = function (SplFileInfo $file) {
$htaccess = new HtaccessAnalyzer($file);

return $htaccess->grantsAccess();
return HtaccessAnalyzer::create($file)->grantsAccess();
};

$this->relativeSymlink(
$this->createSymlinksFromFinder(
$this->findIn("$rootDir/system/modules")->files()->filter($filter)->name('.htaccess'),
'system/modules',
$rootDir,
Expand All @@ -143,30 +142,33 @@ private function symlinkThemes($rootDir, OutputInterface $output)
continue;
}

$this->symlink("../../$path", 'system/themes/' . basename($path), $rootDir, $output);
$this->symlink($path, 'system/themes/' . basename($path), $rootDir, $output);
}
}

/**
* Generates a symlink relative to the given path.
* Generates symlinks from a Finder object.
*
* @param Finder $finder The finder object
* @param string $prepend The path to prepend
* @param string $rootDir The root directory
* @param OutputInterface $output The output object
*/
private function relativeSymlink(Finder $finder, $prepend, $rootDir, OutputInterface $output)
private function createSymlinksFromFinder(Finder $finder, $prepend, $rootDir, OutputInterface $output)
{
/** @var SplFileInfo $file */
foreach ($finder as $file) {
$path = rtrim($prepend . '/' . $file->getRelativePath(), '/');
$this->symlink(str_repeat('../', substr_count($path, '/') + 1) . $path, "web/$path", $rootDir, $output);
$this->symlink($path, "web/$path", $rootDir, $output);
}
}

/**
* Generates a symlink.
*
* The method will try to generate relative symlinks and fall back to generating
* absolute symlinks if relative symlinks are not supported (see #208).
*
* @param string $source The symlink name
* @param string $target The symlink target
* @param string $rootDir The root directory
Expand All @@ -177,19 +179,14 @@ private function symlink($source, $target, $rootDir, OutputInterface $output)
$this->validateSymlink($source, $target, $rootDir);

$fs = new Filesystem();
$fs->symlink($source, "$rootDir/$target");

$stat = lstat("$rootDir/$target");

// Try to fix the UID
if (function_exists('lchown') && $stat['uid'] !== getmyuid()) {
lchown("$rootDir/$target", getmyuid());
try {
$fs->symlink(rtrim($fs->makePathRelative($source, dirname($target)), '/'), "$rootDir/$target");
} catch (IOException $e) {
$fs->symlink("$rootDir/$source", "$rootDir/$target");
}

// Try to fix the GID
if (function_exists('lchgrp') && $stat['gid'] !== getmygid()) {
lchgrp("$rootDir/$target", getmygid());
}
$this->fixSymlinkPermissions($target, $rootDir);

$output->writeln("Added <comment>$target</comment> as symlink to <comment>$source</comment>.");
}
Expand Down Expand Up @@ -225,6 +222,27 @@ private function validateSymlink($source, $target, $rootDir)
}
}

/**
* Fixes the symlink permissions.
*
* @param string $target The symlink target
* @param string $rootDir The root directory
*/
private function fixSymlinkPermissions($target, $rootDir)
{
$stat = lstat("$rootDir/$target");

// Try to fix the UID
if (function_exists('lchown') && $stat['uid'] !== getmyuid()) {
lchown("$rootDir/$target", getmyuid());
}

// Try to fix the GID
if (function_exists('lchgrp') && $stat['gid'] !== getmygid()) {
lchgrp("$rootDir/$target", getmygid());
}
}

/**
* Returns a finder instance to find files in the given path.
*
Expand Down

0 comments on commit 77c1c10

Please sign in to comment.