From e971176a275b7eaf5e1a873ef3ef2b95defd7d82 Mon Sep 17 00:00:00 2001 From: Naren Date: Mon, 25 May 2020 00:11:46 +0400 Subject: [PATCH 1/6] fixing issues --- src/Commands/Build.php | 23 ++++++++- src/Commands/Watch.php | 68 +++++++++++++++++++++---- src/Contents/Blade.php | 17 ++++++- src/Extractors/AssetExtractor.php | 6 ++- src/FileContentResolver.php | 5 ++ src/Responses/AbstractResponse.php | 1 + src/Responses/Factory.php | 15 +++--- src/SiteGenerator.php | 79 +++++++++++------------------ tests/Contents/BladeTest.php | 6 ++- tests/Mocks/blades/index.blade.php | 14 +++++ tests/Mocks/includes/part.blade.php | 1 + tests/Mocks/layouts/naren.blade.php | 2 + tests/path-cache-file.php | 2 +- 13 files changed, 166 insertions(+), 73 deletions(-) create mode 100644 tests/Mocks/blades/index.blade.php create mode 100644 tests/Mocks/includes/part.blade.php diff --git a/src/Commands/Build.php b/src/Commands/Build.php index cbc2e70..becb3c5 100644 --- a/src/Commands/Build.php +++ b/src/Commands/Build.php @@ -2,9 +2,11 @@ namespace Paphper\Commands; +use Paphper\Config; use Paphper\SiteGenerator; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; class Build extends Command @@ -16,9 +18,8 @@ class Build extends Command private $filesystem; private $loop; private $manager; - private $io; - public function __construct($config, $pageResolvers, $fileContentResolver, $filesystem, $loop, $manager) + public function __construct(Config $config, $pageResolvers, $fileContentResolver, $filesystem, $loop, $manager) { parent::__construct(); $this->config = $config; @@ -32,9 +33,27 @@ public function __construct($config, $pageResolvers, $fileContentResolver, $file public function execute(InputInterface $input, OutputInterface $output) { $io = new PaphperStyle($input, $output); + + $silent = $input->getOption('quiet'); + $force = $input->getOption('force'); + $baseFolder = $this->config->getBuildBaseFolder(); + + if (false === $force && true !== $silent) { + $answer = $io->ask(sprintf('This will delete the folder %s. Are you sure? Type yes to continue.', $baseFolder)); + if (!in_array($answer, ['y', 'ye', 'yes'])) { + $io->section('Skipping. Bye!'); + + return 0; + } + } $generator = new SiteGenerator($this->pageResolvers, $this->fileContentResolver, $this->config, $this->filesystem, $this->loop, $this->manager, $io); $generator->build(); return 0; } + + protected function configure() + { + $this->addOption('force', '-f', InputOption::VALUE_OPTIONAL, 'Force Build?', false); + } } diff --git a/src/Commands/Watch.php b/src/Commands/Watch.php index f6fa41d..b488c38 100644 --- a/src/Commands/Watch.php +++ b/src/Commands/Watch.php @@ -3,15 +3,17 @@ namespace Paphper\Commands; use Paphper\BuildFileResolver; +use Paphper\FileContentResolver; use Paphper\Responses\Factory as ResponseFactory; use Paphper\SiteGenerator; use Paphper\Utils\FileCreator; +use Paphper\Utils\Str; use Psr\Http\Message\ServerRequestInterface; use React\Http\Server; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\Finder\Finder; use Yosymfony\ResourceWatcher\Crc32ContentHash; use Yosymfony\ResourceWatcher\ResourceCachePhpFile; @@ -20,18 +22,18 @@ class Watch extends Command { public static $contentHashMap = []; + public static $filesToBuild = []; protected static $defaultName = 'dev'; private $config; private $filesystem; private $io; private $loop; private $watcher; - private $changedFiles = []; private $fileContentResolver; private $pageResolver; private $manager; - public function __construct($config, $pageResolver, $fileContentResolver, $filesystem, $loop, $manager) + public function __construct($config, $pageResolver, FileContentResolver $fileContentResolver, $filesystem, $loop, $manager) { parent::__construct(); $this->config = $config; @@ -45,15 +47,33 @@ public function __construct($config, $pageResolver, $fileContentResolver, $files public function execute(InputInterface $input, OutputInterface $output) { $port = $this->config->getPort(); - $this->io = $io = new SymfonyStyle($input, $output); + $this->io = $io = new PaphperStyle($input, $output); - $folderWatching = [$this->config->getPageBaseFolder()]; + $baseFolder = $this->config->getBuildBaseFolder(); + + $silent = $input->getOption('quiet'); + $force = $input->getOption('force'); + + if (false === $force && true !== $silent) { + $answer = $this->io->ask(sprintf('This will delete the folder %s. Are you sure? Type yes to continue.', $baseFolder)); + if (!in_array($answer, ['y', 'ye', 'yes'])) { + $this->io->section('Skipping. Bye!'); + + return 0; + } + } + + $folderWatching = [(new Str($this->config->getPageBaseFolder()))->getBeforeLast('/')]; $this->io->title('Watching for file changes'); $this->io->table(['watching folder'], [[implode(' and ', $folderWatching)]]); + $extensionToWatch = array_map(function ($extension) { + return '*'.$extension; + }, $this->fileContentResolver->getExtensions()); + $finder = new Finder(); $finder->files() - ->name(['*.html', '*.md', '*.blade.php']) + ->name($extensionToWatch) ->in($folderWatching); $hashContent = new Crc32ContentHash(); @@ -66,8 +86,26 @@ public function execute(InputInterface $input, OutputInterface $output) $this->loop->addPeriodicTimer(1, function () { $result = $this->watcher->findChanges(); - $this->changedFiles = $changedFiles = $result->getUpdatedFiles(); - foreach ($changedFiles as $filename) { + $changedFiles = $result->getUpdatedFiles(); + $pageFiles = array_filter($changedFiles, function ($filename) { + return (new Str($filename))->startsWith($this->config->getPageBaseFolder()); + }); + + if (empty($changedFiles)) { + return; + } + + if (0 === count($pageFiles)) { + $pagesToBuild = self::$filesToBuild; + } else { + $pagesToBuild = $pageFiles; + } + + foreach ($pagesToBuild as $filename) { + if (!in_array($filename, self::$filesToBuild)) { + self::$filesToBuild[] = $filename; + } + $htmlGenerator = $this->fileContentResolver->resolve($filename); $htmlGenerator->getPageContent() ->then(function ($content) use ($filename) { @@ -86,7 +124,14 @@ public function execute(InputInterface $input, OutputInterface $output) return $response->toResponse(); }); - $this->openBrowser($port); + $this->io->text('trying to open browser. Serving static server at 0.0.0.0:'.$port); + + try { + $this->openBrowser($port); + } catch (\Exception $exception){ + $this->io->text(sprintf('failed opening browser. open at 0.0.0.0:%s in a browser', $port)); + } + $socket = new \React\Socket\Server('0.0.0.0:'.$port, $this->loop); $server->listen($socket); @@ -109,4 +154,9 @@ public function openBrowser($port) exec('open http://localhost:'.$port); } } + + protected function configure() + { + $this->addOption('force', '-f', InputOption::VALUE_OPTIONAL, 'Force Build?', false); + } } diff --git a/src/Contents/Blade.php b/src/Contents/Blade.php index d38ef96..5b0bee8 100644 --- a/src/Contents/Blade.php +++ b/src/Contents/Blade.php @@ -30,7 +30,22 @@ public function getPageContent(): PromiseInterface $filename = (new Str($this->filename))->getBeforeLast('.blade.php'); $filename = (new Str($filename))->replaceAllWith($this->config->getPageBaseFolder(), ''); - $content = $this->blade->render('pages'.$filename); + /* + * because we are making the root of the folder base view file + * we need to build the page from the root + * For eg. for the folder path + * - pages + * - layouts + * we load all the folders for blade so that she can use @include etc. + * but for this to work the blade needs to be loaded as `pages.` pagename for pagename.blade.php + * so we get the name of the base folder and append to whatever the filename is, hence getting that folder to append + */ + $relativePageFolder = (new Str($this->config->getPageBaseFolder()))->getAfterLast('/'); + + /* + * added the folder name here explained above. + */ + $content = $this->blade->render($relativePageFolder.$filename); $meta = new PaperTagContentParser($this->config, $this->filesystem, $content); diff --git a/src/Extractors/AssetExtractor.php b/src/Extractors/AssetExtractor.php index 04198e8..9266729 100644 --- a/src/Extractors/AssetExtractor.php +++ b/src/Extractors/AssetExtractor.php @@ -21,6 +21,9 @@ class AssetExtractor '//link' => [ 'attribute' => 'href', ], + '//script' => [ + 'attribute' => 'src', + ], ]; public function __construct(string $content = null) @@ -54,7 +57,8 @@ private function addFromPattern($content, $pattern) private function addAsset(string $asset) { - if ((new Str($asset))->startsWith('http')) { + $filename = new Str($asset); + if ($filename->startsWith('http') || $filename->startsWith('//')) { return; } diff --git a/src/FileContentResolver.php b/src/FileContentResolver.php index ab546fd..f3877d6 100644 --- a/src/FileContentResolver.php +++ b/src/FileContentResolver.php @@ -28,4 +28,9 @@ public function resolve(string $filename): ContentInterface throw new ContentResolverException((new Str($filename))->getAfterLast('/').' file does not have a content resolver.'); } + + public function getExtensions(): array + { + return $this->extensions; + } } diff --git a/src/Responses/AbstractResponse.php b/src/Responses/AbstractResponse.php index 0d205d8..bde27ff 100644 --- a/src/Responses/AbstractResponse.php +++ b/src/Responses/AbstractResponse.php @@ -54,6 +54,7 @@ final protected function getMimeTypeHeader(string $imageType): array 'jpg' => ['Content-Type' => 'image/jpg'], 'ico' => ['Content-Type' => 'image/x-icon'], 'css' => ['Content-Type' => 'text/css'], + 'js' => ['Content-Type' => 'text/javascript'], ]; return $imageMimeTypes[$imageType]; diff --git a/src/Responses/Factory.php b/src/Responses/Factory.php index 937aec6..9b4c3f6 100644 --- a/src/Responses/Factory.php +++ b/src/Responses/Factory.php @@ -10,30 +10,27 @@ class Factory { - private static $imageFileExtensions = [ + private static $assetFileExtensions = [ 'jpg', 'jpeg', 'png', 'ico', 'svg', + 'css', + 'js', ]; public static function create(ServerRequestInterface $request, Config $config, FilesystemInterface $filesystem, ImageManager $manager) { - if (self::isImage($request->getUri()->getPath()) || self::isCss($request->getUri()->getPath())) { + if (self::isAsset($request->getUri()->getPath())) { return new Asset($request, $config, $filesystem, $manager); } return new Html($request, $config, $filesystem); } - public static function isCss(string $path) + public static function isAsset(string $path) { - return (new Str($path))->endsWith('css'); - } - - private static function isImage(string $path) - { - return (new Str(strtolower($path)))->endsWithAny(self::$imageFileExtensions); + return (new Str(strtolower($path)))->endsWithAny(self::$assetFileExtensions); } } diff --git a/src/SiteGenerator.php b/src/SiteGenerator.php index c2674d6..066ad3b 100644 --- a/src/SiteGenerator.php +++ b/src/SiteGenerator.php @@ -12,7 +12,6 @@ use React\EventLoop\LoopInterface; use React\Filesystem\FilesystemInterface; use React\Filesystem\Node\File; -use Symfony\Component\Console\Style\SymfonyStyle; class SiteGenerator { @@ -23,25 +22,26 @@ class SiteGenerator private $pageResolver; private $contentResolver; private $imageManager; + private $input; + private $output; - public function __construct(PageResolverInterface $pageResolver, FileContentResolver $contentResolver, Config $config, FilesystemInterface $filesystem, LoopInterface $loop, ImageManager $imageManager, SymfonyStyle $io = null) + public function __construct(PageResolverInterface $pageResolver, FileContentResolver $contentResolver, Config $config, FilesystemInterface $filesystem, LoopInterface $loop, ImageManager $imageManager, $io = null) { $this->pageResolver = $pageResolver; $this->config = $config; $this->filesystem = $filesystem; $this->loop = $loop; $this->io = $io; - $this->contentResolver = $contentResolver; - $this->imageManager = $imageManager; if (null === $io) { $this->io = $this->getMockIo(); } + + $this->contentResolver = $contentResolver; + $this->imageManager = $imageManager; } public function build() { - $this->io->title('The site creating has begun'); - $this->io->section('Removing build folder for fresh start'); await($this->removeBuildFolder(), $this->loop); $this->io->success('Folder Removed!'); @@ -60,19 +60,16 @@ public function build() return; } - $this->io->section('Scanning pages for used assets'); $images = []; await($this->lookForImages($images), $this->loop); if (empty($images)) { return; } - - $images = array_unique($images); $this->io->listing($images); $imageDirectories = []; - $this->io->section('Processing assets'); + $this->io->section('Scanning pages for used assets'); $imageSizeParser = new ImageSizeDetector($images); @@ -138,27 +135,7 @@ public function lookForImages(array &$images) public function getMockIo() { return new class() { - public function text(...$arg) - { - } - - public function title(...$arg) - { - } - - public function section(...$arg) - { - } - - public function success(...$arg) - { - } - - public function listing(...$arg) - { - } - - public function warning(...$arg) + public function __call($name, $args) { } }; @@ -225,24 +202,30 @@ private function processImages(ImageSizeDetector $images): void $sourceImage = $this->config->getAssetsBaseFolder().$image; $targetImage = $this->config->getBuildBaseFolder().$image; $source = $this->filesystem->file($sourceImage); - $target = $this->filesystem->file($targetImage); - $copy = $source->copy($target); - await($copy, $this->loop); - - if (!empty($sizes[$image])) { - $this->io->section('Resizing '.$image); - $this->io->listing($sizes[$image]); - foreach ($sizes[$image] as $size) { - $promise = $this->filesystem->file($sourceImage)->getContents()->then(function ($content) use ($image, $size) { - $resizeFile = $this->config->getBuildBaseFolder().(new ImageNameResolver($image, $size))->getFilename(); - [$width, $height] = explode('x', $size); - $data = $this->imageManager->make($content)->resize($width, $height)->encode(); - - return $this->filesystem->file($resizeFile)->putContents($data); - }); - await($promise, $this->loop); + + $promise = $source->exists()->then(function () use ($targetImage, $source, $image, $sourceImage, $sizes) { + $target = $this->filesystem->file($targetImage); + $copy = $source->copy($target); + await($copy, $this->loop); + if (!empty($sizes[$image])) { + $this->io->section('Resizing '.$image); + $this->io->listing($sizes[$image]); + foreach ($sizes[$image] as $size) { + $promise = $this->filesystem->file($sourceImage)->getContents()->then(function ($content) use ($image, $size) { + $resizeFile = $this->config->getBuildBaseFolder().(new ImageNameResolver($image, $size))->getFilename(); + [$width, $height] = explode('x', $size); + $data = $this->imageManager->make($content)->resize($width, $height)->encode(); + + return $this->filesystem->file($resizeFile)->putContents($data); + }); + await($promise, $this->loop); + } } - } + }, function () use ($image) { + $this->io->warning(sprintf('Asset %s missing but referenced in the html. Skipping', $image)); + }); + + await($promise, $this->loop); } } } diff --git a/tests/Contents/BladeTest.php b/tests/Contents/BladeTest.php index f5b5f15..72b1232 100644 --- a/tests/Contents/BladeTest.php +++ b/tests/Contents/BladeTest.php @@ -9,7 +9,7 @@ class BladeTest extends AbstractTestCase { - public function testThisWorks() + public function testBladeContentIsSuccessfullyGenerated() { $baseFolder = $this->config->getPageBaseFolder(); $lBlade = new \Jenssegers\Blade\Blade((new Str($baseFolder))->getBeforeLast('/'), $this->config->getCacheDir()); @@ -17,7 +17,7 @@ public function testThisWorks() $content = await($blade->getPageContent(), $this->loop); -// var_dump($content); + $this->assertSame($this->getBladeContent(), $content); } @@ -28,6 +28,8 @@ private function getBladeContent() This is a test + + diff --git a/tests/Mocks/blades/index.blade.php b/tests/Mocks/blades/index.blade.php new file mode 100644 index 0000000..159973e --- /dev/null +++ b/tests/Mocks/blades/index.blade.php @@ -0,0 +1,14 @@ + + title: This is a blade example + + +@extends('layouts.naren') + +@section('content') + + Hello biren + + Narn + + @include('includes.part') +@endsection diff --git a/tests/Mocks/includes/part.blade.php b/tests/Mocks/includes/part.blade.php new file mode 100644 index 0000000..80e5bd5 --- /dev/null +++ b/tests/Mocks/includes/part.blade.php @@ -0,0 +1 @@ +this is the and reading and swimming diff --git a/tests/Mocks/layouts/naren.blade.php b/tests/Mocks/layouts/naren.blade.php index 664146f..fefb374 100644 --- a/tests/Mocks/layouts/naren.blade.php +++ b/tests/Mocks/layouts/naren.blade.php @@ -2,6 +2,8 @@ {title} + + diff --git a/tests/path-cache-file.php b/tests/path-cache-file.php index fc8f789..bb0e502 100644 --- a/tests/path-cache-file.php +++ b/tests/path-cache-file.php @@ -1,2 +1,2 @@ '8bec7277', '/Users/naren/Extras/paphper/core/tests/Mocks/pages/blogs/index.html' => '87523236', '/Users/naren/Extras/paphper/core/tests/Mocks/pages/blogs/2020/index.html' => '87523236', '/Users/naren/Extras/paphper/core/tests/Mocks/pages/index.html' => '4c83085d', '/Users/naren/Extras/paphper/core/tests/Mocks/pages/bios/salam.html' => 'fe6305d9', '/Users/naren/Extras/paphper/core/tests/Mocks/pages/bios/naren.html' => 'e6a5674b', '/Users/naren/Extras/paphper/core/tests/Mocks/pages/blade.blade.php' => 'b23df256']; +return ['/Users/naren/Extras/paphper/core/tests/Mocks/html-with-images.html'=>'56530103','/Users/naren/Extras/paphper/core/tests/Mocks/includes/part.blade.php'=>'913ec99f','/Users/naren/Extras/paphper/core/tests/Mocks/blades/index.blade.php'=>'67f8aab7','/Users/naren/Extras/paphper/core/tests/Mocks/results/index.html'=>'e651c698','/Users/naren/Extras/paphper/core/tests/Mocks/layouts/blog.html'=>'81bdc2f8','/Users/naren/Extras/paphper/core/tests/Mocks/layouts/index.html'=>'7c1daf99','/Users/naren/Extras/paphper/core/tests/Mocks/layouts/naren.blade.php'=>'ccec0196','/Users/naren/Extras/paphper/core/tests/Mocks/build/index.html'=>'452ff236','/Users/naren/Extras/paphper/core/tests/Mocks/pages/non-html.md'=>'8bec7277','/Users/naren/Extras/paphper/core/tests/Mocks/pages/blogs/index.html'=>'87523236','/Users/naren/Extras/paphper/core/tests/Mocks/pages/blogs/2020/index.html'=>'87523236','/Users/naren/Extras/paphper/core/tests/Mocks/pages/blade.blade.php'=>'b23df256','/Users/naren/Extras/paphper/core/tests/Mocks/pages/index.html'=>'4c83085d','/Users/naren/Extras/paphper/core/tests/Mocks/pages/bios/salam.html'=>'fe6305d9','/Users/naren/Extras/paphper/core/tests/Mocks/pages/bios/naren.html'=>'e6a5674b','/Users/naren/Extras/paphper/core/tests/Mocks/build/blogs/index.html'=>'2e46da92','/Users/naren/Extras/paphper/core/tests/Mocks/build/blogs/2020/index.html'=>'2e46da92','/Users/naren/Extras/paphper/core/tests/Mocks/build/non-html/index.html'=>'7fc507c8','/Users/naren/Extras/paphper/core/tests/Mocks/build/blade/index.html'=>'76ce268f','/Users/naren/Extras/paphper/core/tests/Mocks/build/bios/naren/index.html'=>'158c1674','/Users/naren/Extras/paphper/core/tests/Mocks/build/bios/salam/index.html'=>'ce66579a',]; \ No newline at end of file From 1dce1a4b307d196bea48517e0e7ff97dd31f897a Mon Sep 17 00:00:00 2001 From: Naren Date: Mon, 25 May 2020 13:26:40 +0400 Subject: [PATCH 2/6] added working docker --- .circleci/config.yml | 2 +- src/Commands/Watch.php | 1 - src/SiteGenerator.php | 2 -- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index c28dfb6..a60dc70 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -2,7 +2,7 @@ version: 2 jobs: build: docker: - - image: circleci/php:7.4.4-cli + - image: developernaren/reactphp-gd steps: - checkout diff --git a/src/Commands/Watch.php b/src/Commands/Watch.php index b488c38..541ea1f 100644 --- a/src/Commands/Watch.php +++ b/src/Commands/Watch.php @@ -132,7 +132,6 @@ public function execute(InputInterface $input, OutputInterface $output) $this->io->text(sprintf('failed opening browser. open at 0.0.0.0:%s in a browser', $port)); } - $socket = new \React\Socket\Server('0.0.0.0:'.$port, $this->loop); $server->listen($socket); diff --git a/src/SiteGenerator.php b/src/SiteGenerator.php index 066ad3b..9aaf98c 100644 --- a/src/SiteGenerator.php +++ b/src/SiteGenerator.php @@ -22,8 +22,6 @@ class SiteGenerator private $pageResolver; private $contentResolver; private $imageManager; - private $input; - private $output; public function __construct(PageResolverInterface $pageResolver, FileContentResolver $contentResolver, Config $config, FilesystemInterface $filesystem, LoopInterface $loop, ImageManager $imageManager, $io = null) { From f8c9c5f36edcdea656c7cd29e6c88b187b9ef9c6 Mon Sep 17 00:00:00 2001 From: Naren Date: Mon, 25 May 2020 13:29:24 +0400 Subject: [PATCH 3/6] added working docker --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index a60dc70..806697a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -6,7 +6,7 @@ jobs: steps: - checkout - - run: sudo apt update + - run: apt update - restore_cache: keys: From f82f13987fa70d2f54474beedd05d465d1a3c910 Mon Sep 17 00:00:00 2001 From: Naren Date: Thu, 28 May 2020 23:45:11 +0400 Subject: [PATCH 4/6] fixes#6 --- src/Extractors/AssetExtractor.php | 2 +- tests/Extractors/AssetExtractorTest.php | 1 + tests/Mocks/html-with-images.html | 3 ++- tests/path-cache-file.php | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Extractors/AssetExtractor.php b/src/Extractors/AssetExtractor.php index 9266729..05654d7 100644 --- a/src/Extractors/AssetExtractor.php +++ b/src/Extractors/AssetExtractor.php @@ -16,7 +16,7 @@ class AssetExtractor ], "//*[contains(@style,'background-image')]" => [ 'attribute' => 'style', - 'pattern' => "[url\((\s)?[?=(',\")]([-\/.\w.]+)[?=(',\")]]", + 'pattern' => "[url\((\s)?[?=(',\")]{0,1}([-\/.\w.]+)[?=(',\")]{0,1}]", ], '//link' => [ 'attribute' => 'href', diff --git a/tests/Extractors/AssetExtractorTest.php b/tests/Extractors/AssetExtractorTest.php index 94bf83d..70608d3 100644 --- a/tests/Extractors/AssetExtractorTest.php +++ b/tests/Extractors/AssetExtractorTest.php @@ -43,6 +43,7 @@ public function testBackgroundAssetsAreFetched() $this->assertContains('narendra.bmp', $assetExtractor->getAssets()); $this->assertContains('saru.png', $assetExtractor->getAssets()); $this->assertContains('images/hel-lo/saru.png', $assetExtractor->getAssets()); + $this->assertContains('/narendra.jpg', $assetExtractor->getAssets()); }); await($test, $this->loop); diff --git a/tests/Mocks/html-with-images.html b/tests/Mocks/html-with-images.html index 6d8b1cf..8e31823 100644 --- a/tests/Mocks/html-with-images.html +++ b/tests/Mocks/html-with-images.html @@ -5,7 +5,8 @@ -
+
+
diff --git a/tests/path-cache-file.php b/tests/path-cache-file.php index bb0e502..65e090f 100644 --- a/tests/path-cache-file.php +++ b/tests/path-cache-file.php @@ -1,2 +1,2 @@ '56530103','/Users/naren/Extras/paphper/core/tests/Mocks/includes/part.blade.php'=>'913ec99f','/Users/naren/Extras/paphper/core/tests/Mocks/blades/index.blade.php'=>'67f8aab7','/Users/naren/Extras/paphper/core/tests/Mocks/results/index.html'=>'e651c698','/Users/naren/Extras/paphper/core/tests/Mocks/layouts/blog.html'=>'81bdc2f8','/Users/naren/Extras/paphper/core/tests/Mocks/layouts/index.html'=>'7c1daf99','/Users/naren/Extras/paphper/core/tests/Mocks/layouts/naren.blade.php'=>'ccec0196','/Users/naren/Extras/paphper/core/tests/Mocks/build/index.html'=>'452ff236','/Users/naren/Extras/paphper/core/tests/Mocks/pages/non-html.md'=>'8bec7277','/Users/naren/Extras/paphper/core/tests/Mocks/pages/blogs/index.html'=>'87523236','/Users/naren/Extras/paphper/core/tests/Mocks/pages/blogs/2020/index.html'=>'87523236','/Users/naren/Extras/paphper/core/tests/Mocks/pages/blade.blade.php'=>'b23df256','/Users/naren/Extras/paphper/core/tests/Mocks/pages/index.html'=>'4c83085d','/Users/naren/Extras/paphper/core/tests/Mocks/pages/bios/salam.html'=>'fe6305d9','/Users/naren/Extras/paphper/core/tests/Mocks/pages/bios/naren.html'=>'e6a5674b','/Users/naren/Extras/paphper/core/tests/Mocks/build/blogs/index.html'=>'2e46da92','/Users/naren/Extras/paphper/core/tests/Mocks/build/blogs/2020/index.html'=>'2e46da92','/Users/naren/Extras/paphper/core/tests/Mocks/build/non-html/index.html'=>'7fc507c8','/Users/naren/Extras/paphper/core/tests/Mocks/build/blade/index.html'=>'76ce268f','/Users/naren/Extras/paphper/core/tests/Mocks/build/bios/naren/index.html'=>'158c1674','/Users/naren/Extras/paphper/core/tests/Mocks/build/bios/salam/index.html'=>'ce66579a',]; \ No newline at end of file +return ['/Users/naren/Extras/paphper/core/tests/Mocks/html-with-images.html'=>'aac4ff09','/Users/naren/Extras/paphper/core/tests/Mocks/includes/part.blade.php'=>'913ec99f','/Users/naren/Extras/paphper/core/tests/Mocks/blades/index.blade.php'=>'67f8aab7','/Users/naren/Extras/paphper/core/tests/Mocks/results/index.html'=>'e651c698','/Users/naren/Extras/paphper/core/tests/Mocks/layouts/blog.html'=>'81bdc2f8','/Users/naren/Extras/paphper/core/tests/Mocks/layouts/index.html'=>'7c1daf99','/Users/naren/Extras/paphper/core/tests/Mocks/layouts/naren.blade.php'=>'ccec0196','/Users/naren/Extras/paphper/core/tests/Mocks/build/index.html'=>'452ff236','/Users/naren/Extras/paphper/core/tests/Mocks/pages/non-html.md'=>'8bec7277','/Users/naren/Extras/paphper/core/tests/Mocks/pages/blogs/index.html'=>'87523236','/Users/naren/Extras/paphper/core/tests/Mocks/pages/blogs/2020/index.html'=>'87523236','/Users/naren/Extras/paphper/core/tests/Mocks/pages/blade.blade.php'=>'b23df256','/Users/naren/Extras/paphper/core/tests/Mocks/pages/index.html'=>'4c83085d','/Users/naren/Extras/paphper/core/tests/Mocks/pages/bios/salam.html'=>'fe6305d9','/Users/naren/Extras/paphper/core/tests/Mocks/pages/bios/naren.html'=>'e6a5674b','/Users/naren/Extras/paphper/core/tests/Mocks/build/blogs/index.html'=>'2e46da92','/Users/naren/Extras/paphper/core/tests/Mocks/build/blogs/2020/index.html'=>'2e46da92','/Users/naren/Extras/paphper/core/tests/Mocks/build/non-html/index.html'=>'7fc507c8','/Users/naren/Extras/paphper/core/tests/Mocks/build/blade/index.html'=>'76ce268f','/Users/naren/Extras/paphper/core/tests/Mocks/build/bios/naren/index.html'=>'158c1674','/Users/naren/Extras/paphper/core/tests/Mocks/build/bios/salam/index.html'=>'ce66579a',]; \ No newline at end of file From 43f54909a2a196496ef098baf38595534ae76fcc Mon Sep 17 00:00:00 2001 From: Naren Date: Fri, 29 May 2020 10:39:42 +0400 Subject: [PATCH 5/6] used filesystem master --- composer.json | 5 +-- composer.lock | 76 ++++++++++++++++++++++++++++++++++++------ src/Commands/Watch.php | 2 +- src/SiteGenerator.php | 18 ++++++++++ 4 files changed, 87 insertions(+), 14 deletions(-) diff --git a/composer.json b/composer.json index eda2ee7..1216887 100644 --- a/composer.json +++ b/composer.json @@ -16,11 +16,12 @@ "react/http": "^0.8.6", "react/stream": "^1.1", "symfony/console": "^5.0", - "react/filesystem": "^0.1.2", + "react/filesystem": "dev-master", "yosymfony/resource-watcher": "^2.0", "symfony/dom-crawler": "^5.0", "jenssegers/blade": "^1.3", - "intervention/image": "^2.5" + "intervention/image": "^2.5", + "icamys/php-sitemap-generator": "^2.0" }, "replace": { "paphper/contracts": "self.version" diff --git a/composer.lock b/composer.lock index 8b5a366..7293107 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "b9314cf45d46f235534a03c425d7bdd5", + "content-hash": "c4d048cd9937d5a8306dca3c0f3e0aab", "packages": [ { "name": "cakephp/core", @@ -410,6 +410,62 @@ ], "time": "2019-07-01T23:21:34+00:00" }, + { + "name": "icamys/php-sitemap-generator", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/icamys/php-sitemap-generator.git", + "reference": "022fe40af04df825c192f75568106ef8ca5dd6c3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/icamys/php-sitemap-generator/zipball/022fe40af04df825c192f75568106ef8ca5dd6c3", + "reference": "022fe40af04df825c192f75568106ef8ca5dd6c3", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "ext-dom": "*", + "ext-mbstring": "*", + "ext-simplexml": "*", + "ext-spl": "*", + "ext-zlib": "*", + "php": "^7.2" + }, + "require-dev": { + "php-mock/php-mock-phpunit": "^2.5", + "phpunit/phpunit": "^8.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Icamys\\SitemapGenerator\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Prisacari Dmitrii", + "email": "prisacari.dmitrii@gmail.com", + "homepage": "http://github.com/icamys/" + } + ], + "description": "Simple PHP sitemap generator.", + "homepage": "https://github.com/icamys/php-sitemap-generator", + "keywords": [ + "PSR-1", + "PSR-2", + "PSR-4", + "Sitemap", + "generator", + "php" + ], + "time": "2020-02-11T19:00:23+00:00" + }, { "name": "illuminate/container", "version": "v7.11.0", @@ -1425,16 +1481,16 @@ }, { "name": "react/filesystem", - "version": "v0.1.2", + "version": "dev-master", "source": { "type": "git", "url": "https://github.com/reactphp/filesystem.git", - "reference": "766cdef9ba806367114f0c5ba36ea2a6eec8ccd2" + "reference": "fc89dc26ff7bda9e864798f8fd5b705c437a5cd9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/filesystem/zipball/766cdef9ba806367114f0c5ba36ea2a6eec8ccd2", - "reference": "766cdef9ba806367114f0c5ba36ea2a6eec8ccd2", + "url": "https://api.github.com/repos/reactphp/filesystem/zipball/fc89dc26ff7bda9e864798f8fd5b705c437a5cd9", + "reference": "fc89dc26ff7bda9e864798f8fd5b705c437a5cd9", "shasum": "" }, "require": { @@ -1450,9 +1506,6 @@ "clue/block-react": "^1.1", "phpunit/phpunit": "^6.0 || ^5.0 || ^4.8" }, - "suggest": { - "ext-eio": "^1.2" - }, "type": "library", "autoload": { "psr-4": { @@ -1475,10 +1528,9 @@ "description": "Asynchronous filesystem abstraction.", "keywords": [ "asynchronous", - "eio", "filesystem" ], - "time": "2018-10-22T12:10:29+00:00" + "time": "2020-05-08T09:44:27+00:00" }, { "name": "react/http", @@ -5358,7 +5410,9 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": { + "react/filesystem": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { diff --git a/src/Commands/Watch.php b/src/Commands/Watch.php index 541ea1f..255fc68 100644 --- a/src/Commands/Watch.php +++ b/src/Commands/Watch.php @@ -112,7 +112,7 @@ public function execute(InputInterface $input, OutputInterface $output) $buildFile = new BuildFileResolver($this->config, $filename); (new FileCreator($this->filesystem, $buildFile->getName(), $content))->writeFile() ->then(function () use ($buildFile) { - $this->io->text(sprintf('%s build', $buildFile->getName())); + $this->io->text(sprintf('%s built', $buildFile->getName())); }); }); } diff --git a/src/SiteGenerator.php b/src/SiteGenerator.php index 9aaf98c..d6d7170 100644 --- a/src/SiteGenerator.php +++ b/src/SiteGenerator.php @@ -2,6 +2,7 @@ namespace Paphper; +use Icamys\SitemapGenerator\SitemapGenerator; use function Clue\React\Block\await; use Intervention\Image\ImageManager; use Paphper\Contracts\PageResolverInterface; @@ -106,6 +107,23 @@ public function build() $this->io->section('Copying assets to right folders'); $this->io->listing($imageSizeParser->getOriginals()); $this->processImages($imageSizeParser); + + $this->io->section('Generating sitemap!'); + + $siteMapCreation = $this->pageResolver->getPages() + ->then(function ($pages){ + $generator = new SitemapGenerator('example.com', $this->config->getBuildBaseFolder()); + foreach ($pages as $page){ + $generator->addURL($page, new \DateTime(), 'always', 0.5); + } + $generator->createSitemap(); + $generator->setSitemapFileName("sitemap.xml"); + $generator->writeSitemap(); + $generator->updateRobots(); + }); + + await($siteMapCreation, $this->loop); + $this->io->success('Done! Site successfully generated!'); } From 4a6603af6385cf9a428689314c14c07cf6a5a2c1 Mon Sep 17 00:00:00 2001 From: Naren Date: Fri, 29 May 2020 15:11:08 +0400 Subject: [PATCH 6/6] added support for sitemap xml and robots.txt --- src/BuildFileResolver.php | 13 ++++++++++++ src/Responses/AbstractResponse.php | 2 ++ src/Responses/Factory.php | 2 ++ src/SiteGenerator.php | 32 ++++++++++++++++++++---------- src/Utils/Str.php | 5 +++++ tests/BuildFileResolverTest.php | 4 ++++ 6 files changed, 47 insertions(+), 11 deletions(-) diff --git a/src/BuildFileResolver.php b/src/BuildFileResolver.php index 1a215cb..32f445c 100644 --- a/src/BuildFileResolver.php +++ b/src/BuildFileResolver.php @@ -29,4 +29,17 @@ public function getFolder() { return (new Str($this->name))->getBeforeLast('/'); } + + public function getUrlPath() + { + $folder = $this->getFolder(); + $path = (new Str($folder))->removeAll($this->config->getBuildBaseFolder()); + + if(!(new Str($path))->startsWith('/')){ + return '/' . $path; + } + + return $path; + } + } diff --git a/src/Responses/AbstractResponse.php b/src/Responses/AbstractResponse.php index bde27ff..5458afb 100644 --- a/src/Responses/AbstractResponse.php +++ b/src/Responses/AbstractResponse.php @@ -55,6 +55,8 @@ final protected function getMimeTypeHeader(string $imageType): array 'ico' => ['Content-Type' => 'image/x-icon'], 'css' => ['Content-Type' => 'text/css'], 'js' => ['Content-Type' => 'text/javascript'], + 'txt' => ['Content-Type' => 'text/plain'], + 'xml' => ['Content-Type' => 'text/xml'], ]; return $imageMimeTypes[$imageType]; diff --git a/src/Responses/Factory.php b/src/Responses/Factory.php index 9b4c3f6..22c58d7 100644 --- a/src/Responses/Factory.php +++ b/src/Responses/Factory.php @@ -18,6 +18,8 @@ class Factory 'svg', 'css', 'js', + 'txt', + 'xml', ]; public static function create(ServerRequestInterface $request, Config $config, FilesystemInterface $filesystem, ImageManager $manager) diff --git a/src/SiteGenerator.php b/src/SiteGenerator.php index d6d7170..0606179 100644 --- a/src/SiteGenerator.php +++ b/src/SiteGenerator.php @@ -110,17 +110,7 @@ public function build() $this->io->section('Generating sitemap!'); - $siteMapCreation = $this->pageResolver->getPages() - ->then(function ($pages){ - $generator = new SitemapGenerator('example.com', $this->config->getBuildBaseFolder()); - foreach ($pages as $page){ - $generator->addURL($page, new \DateTime(), 'always', 0.5); - } - $generator->createSitemap(); - $generator->setSitemapFileName("sitemap.xml"); - $generator->writeSitemap(); - $generator->updateRobots(); - }); + $siteMapCreation = $this->createSitemap(); await($siteMapCreation, $this->loop); @@ -244,4 +234,24 @@ private function processImages(ImageSizeDetector $images): void await($promise, $this->loop); } } + + private function createSitemap(): \React\Promise\PromiseInterface + { + return $this->pageResolver->getPages() + ->then(function ($pages) { + $generator = new SitemapGenerator('example.com', $this->config->getBuildBaseFolder()); + foreach ($pages as $page) { + $generator->addURL($this->getUrl($page), new \DateTime(), 'always', 0.5); + } + $generator->createSitemap(); + $generator->setSitemapFileName("sitemap.xml"); + $generator->writeSitemap(); + $generator->updateRobots(); + }); + } + + private function getUrl($path) + { + return (new BuildFileResolver($this->config, $path))->getUrlPath(); + } } diff --git a/src/Utils/Str.php b/src/Utils/Str.php index ca59078..4432292 100644 --- a/src/Utils/Str.php +++ b/src/Utils/Str.php @@ -41,6 +41,11 @@ public function replaceAllWith(string $search, string $replace) return str_replace($search, $replace, $this); } + public function removeAll(string $search) + { + return str_replace($search, '', $this); + } + public function replaceLastWith(string $search, string $replace) { $length = strlen($search); diff --git a/tests/BuildFileResolverTest.php b/tests/BuildFileResolverTest.php index 36d6184..313b3cb 100644 --- a/tests/BuildFileResolverTest.php +++ b/tests/BuildFileResolverTest.php @@ -10,18 +10,21 @@ public function testBuildFileAreResolvedCorrectly() { $resolver = new BuildFileResolver($this->config, $this->config->getPageBaseFolder().'/blog.html'); $this->assertSame($this->config->getBuildBaseFolder().'/blog', $resolver->getFolder()); + $this->assertSame('/blog', $resolver->getUrlPath()); } public function testForDeepFolder() { $resolver = new BuildFileResolver($this->config, $this->config->getPageBaseFolder().'/blogs/testing/naren.md'); $this->assertSame($this->config->getBuildBaseFolder().'/blogs/testing/naren', $resolver->getFolder()); + $this->assertSame('/blogs/testing/naren', $resolver->getUrlPath()); } public function testForMdFolder() { $resolver = new BuildFileResolver($this->config, $this->config->getPageBaseFolder().'/index.md'); $this->assertSame($this->config->getBuildBaseFolder(), $resolver->getFolder()); + $this->assertSame('/', $resolver->getUrlPath()); } public function testForBladeFolder() @@ -29,5 +32,6 @@ public function testForBladeFolder() $resolver = new BuildFileResolver($this->config, $this->config->getPageBaseFolder().'/index.blade.php'); $this->assertSame($this->config->getBuildBaseFolder(), $resolver->getFolder()); + $this->assertSame('/', $resolver->getUrlPath()); } }