View source
<?php
namespace Drupal\ludwig;
use Drupal\Core\Archiver\ArchiverManager;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\FileTransfer\Local;
use Drupal\Core\Site\Settings;
use GuzzleHttp\ClientInterface;
use GuzzleHttp\Exception\RequestException;
class PackageDownloader implements PackageDownloaderInterface {
protected $archiverManager;
protected $fileSystem;
protected $httpClient;
protected $root;
protected $extractionDir;
protected $cacheDir;
public function __construct(ArchiverManager $archiver_manager, FileSystemInterface $file_system, ClientInterface $http_client, $root) {
$this->archiverManager = $archiver_manager;
$this->fileSystem = $file_system;
$this->httpClient = $http_client;
$this->root = $root;
$hash = substr(hash('sha256', Settings::getHashSalt()), 0, 8);
$this->extractionDir = 'temporary://luwdig-extraction-' . $hash;
if (!file_exists($this->extractionDir)) {
mkdir($this->extractionDir);
}
$this->cacheDir = 'temporary://ludwig-cache-' . $hash;
if (!file_exists($this->cacheDir)) {
mkdir($this->cacheDir);
}
}
public function download(array $package) {
$provider_path = $this->root . '/' . $package['provider_path'];
if (!is_writable($provider_path)) {
throw new \Exception(sprintf('The extension directory %s is not writable.', $provider_path));
}
$archive_path = $this
->downloadArchive($package);
if (!$archive_path) {
throw new \Exception(sprintf('Unable to retrieve %s from %s.', $package['name'], $package['download_url']));
}
$archiver = $this
->extractArchive($archive_path);
$files = $archiver
->listContents();
if (!$files) {
throw new \Exception(sprintf('The archive downloaded from %s contains no files.', $package['download_url']));
}
$source_location = $this->fileSystem
->realpath($this->extractionDir . '/' . $files[0]);
$package_destination = $this->root . '/' . $package['path'];
$file_transfer = new Local($this->root, $this->fileSystem);
$file_transfer
->copyDirectory($source_location, $package_destination);
$new_perms = substr(sprintf('%o', fileperms($package_destination)), -4, -1) . "5";
$file_transfer
->chmod($package_destination, intval($new_perms, 8), TRUE);
}
protected function downloadArchive($package) {
$parsed_url = parse_url($package['download_url']);
$cache_dir = $this->cacheDir . '/' . str_replace('/', '-', $package['name']);
if (!file_exists($cache_dir)) {
mkdir($cache_dir);
}
$local = $cache_dir . '/' . $this->fileSystem
->basename($parsed_url['path']);
if (!file_exists($local)) {
$destination = $local;
try {
$data = $this->httpClient
->request('get', $package['download_url'])
->getBody()
->getContents();
$local = $this->fileSystem
->saveData($data, $destination, FileSystemInterface::EXISTS_REPLACE);
} catch (RequestException $exception) {
throw new \Exception(sprintf('Failed to fetch file due to error "%s". Fix the related "url" record in "%s" module ludwig.json file.', $exception
->getMessage(), $package['provider']));
}
if (!$local) {
throw new \Exception(sprintf('%s could not be saved to %s', $package['download_url'], $destination));
}
return $local;
}
else {
return $local;
}
}
protected function extractArchive($file) {
$archiver = $this->archiverManager
->getInstance([
'filepath' => $this->fileSystem
->realpath($file),
]);
if (!$archiver) {
throw new \Exception(sprintf('Cannot extract %file, not a valid archive.', [
'%file' => $file,
]));
}
$files = $archiver
->listContents();
$package = strtok($files[0], '/\\');
$extract_location = $this->extractionDir . '/' . $package;
if (file_exists($extract_location)) {
$this->fileSystem
->deleteRecursive($extract_location);
}
return $archiver
->extract($this->extractionDir);
}
}