Skip to content

Commit

Permalink
Merge pull request #35 from fly-apps/integ_frankenphp_single_file_binary
Browse files Browse the repository at this point in the history
Support FrankenPHP to embed Laravel app into a standalone binary
  • Loading branch information
KTanAug21 authored Apr 25, 2024
2 parents 8e9f8d0 + d4e3ade commit e7e7285
Show file tree
Hide file tree
Showing 9 changed files with 109 additions and 9 deletions.
7 changes: 4 additions & 3 deletions app/Commands/GenerateCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ class GenerateCommand extends Command
{--force : Overwrite existing files}
{--skip : Keep existing files}
{--dev : Include dev dependencies like the local .env file}
{--laravel-version= : Set the laravel version}
{--path=. : Set the directory to check files in.}';
{--path=. : Set the directory to check files in}
{--frankenphp-binary : Generate a single file binary of the app via frankenphp}';

/**
* The description of the command.
Expand Down Expand Up @@ -54,7 +54,8 @@ public function handle()
'laravel_version' => $scan->laravelVersion( $this->options() ),
'fly' => $scan->isForFly(),
'octane' => $scan->octaneFlavor( $this->options() ),
'filament' => $scan->filamentVersion( $this->options() )
'filament' => $scan->filamentVersion( $this->options() ),
'frankenphp_binary' => $this->option('frankenphp-binary')
];

// Define the list of templates to render.
Expand Down
4 changes: 2 additions & 2 deletions app/Services/File.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ class File
*/
public function createFile( $output, $result )
{

// Create the directory the file is supposed to be located in
if( strpos($output, '/') ){
// Get path to file
Expand Down Expand Up @@ -46,7 +45,8 @@ public function deleteDir( $dir )
if( is_file($filePath) )
unlink( $filePath);
}
rmdir( $dir );
}
rmdir( $dir );

}
}
Binary file modified builds/dockerfile-laravel
Binary file not shown.
6 changes: 5 additions & 1 deletion resources/views/dockerfile.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,8 @@
&& chown -R www-data:www-data /var/www/html/public
@endif

EXPOSE 8080
@if($frankenphp_binary)
@include('frankenphp.builder')
@else
EXPOSE 8080
@endif
25 changes: 25 additions & 0 deletions resources/views/frankenphp/builder.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Builder stage to create frankenphp binary containing our embedded app
FROM dunglas/frankenphp:static-builder as builder

# Copy our app found in the previous "base" stage
WORKDIR /go/src/app/dist/app
COPY --from=base /var/www/html .

# Build the static binary, be sure to select only the PHP extensions you want
WORKDIR /go/src/app/
RUN EMBED=dist/app/ \
FRANKENPHP_VERSION=1.1.2 \
PHP_EXTENSIONS=bcmath,cli,common,curl,gd,intl,mbstring,mysql,pgsql,redis,soap,sqlite3,xml,zip,swoole,fpm \
./build-static.sh

# Last runner stage, to only contain and run our generated binary from builder stage
FROM dunglas/frankenphp AS runner

# Replace the official binary by the one contained your custom modules
COPY --from=builder /go/src/app/dist/frankenphp-linux-x86_64 /usr/local/bin/frankenphp

# EXPOSE ports
EXPOSE 8080

# Start app
ENTRYPOINT ["/usr/local/bin/frankenphp", "php-server", "--listen",":8080"]
40 changes: 38 additions & 2 deletions tests/Feature/GenerateCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,29 @@ function setUpDirectoryForBaseSnippetCombo( $baseDirectory, $newComposerArr, $te
}
}

function setFlags( $extCompArr, $pathToFiles ): string
{
$flags = "";

// Where to scan files in
if( $pathToFiles )
$flags .= '--path="'.$pathToFiles.'" ';

// Additional flags from mock composer.json
if( isset($extCompArr['flags']) ){
foreach( $extCompArr['flags'] as $flagKey=>$flagVal ){

if( is_bool($flagVal) )
$flags .= "--".$flagKey." ";
else{
$flags .= "--$flagKey='$flagVal' ";
}
}
}

return $flags;
}

// Test that expected files are generated properly for specific "base specifications"
it('generates proper templates for each supported base', function ( )
{
Expand Down Expand Up @@ -108,9 +131,12 @@ function setUpDirectoryForBaseSnippetCombo( $baseDirectory, $newComposerArr, $te
$testDir = 'tests/Feature/Combination';
setUpDirectoryForBaseSnippetCombo( $base, $newComposer, $testDir );

// Get flags from mock composer.json file
$flags = setFlags( $extComposer['extra'], $testDir );

// Generate templates, by scanning contents of files in the combination folder
// FIRST assert: command successfully runs and exits
$this->artisan('generate --path="'.$testDir.'"')->assertExitCode(0);
$this->artisan('generate '.$flags)->assertExitCode(0);

// Verify that specific templates still matches the expected content from each base reference
// BUT! contain the snippet expected from the snippet/extension folder
Expand All @@ -123,12 +149,17 @@ function setUpDirectoryForBaseSnippetCombo( $baseDirectory, $newComposerArr, $te

// Get base reference file content
$referenceFileName = $base.'/'.$templateName;
$referenceContent = explode("\n", file_get_contents($referenceFileName) );
if( file_exists($referenceFileName) ){
$referenceContent = explode("\n", file_get_contents($referenceFileName) );
}else
$referenceContent = [""];

// Get Difference between generated and base reference
$diff = new \Diff($referenceContent, $generatedContent);
$renderer = new \Diff_Renderer_Text_Unified();
$differenceFound = '';


foreach (explode("\n", $diff->render($renderer)) as $line) {
if (
str_starts_with($line, '+') ||
Expand All @@ -137,10 +168,15 @@ function setUpDirectoryForBaseSnippetCombo( $baseDirectory, $newComposerArr, $te
$differenceFound .= trim( $line,'+|-' )."\n";
}
}

// Override the reference file with generated file content if needed; PLEASE double check diff and re-test this new ref manually!
if( env('OVERRIDE_TEST_REFERENCES')===true )
file_put_contents( $ext.'/'.$templateName, $differenceFound );

// There difference between the two should be the snippet added thanks to combining the base composer with snippet composer
$differenceFound = trim( $differenceFound, "\n");
$referenceContent = trim( file_get_contents( $ext.'/'.$templateName ),"\n");

$this->assertEquals( $referenceContent, $differenceFound, $failedFor );

// Delete unnecessary files
Expand Down
2 changes: 1 addition & 1 deletion tests/Feature/Snippets/filament_v3/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# If we're using Filament v3 and above, run caching commands...
RUN php artisan icons:cache && php artisan filament:cache-components
RUN php artisan icons:cache && php artisan filament:cache-components
24 changes: 24 additions & 0 deletions tests/Feature/Snippets/frankenphp_binary/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Builder stage to create frankenphp binary containing our embedded app
FROM dunglas/frankenphp:static-builder as builder

# Copy our app found in the previous "base" stage
WORKDIR /go/src/app/dist/app
COPY --from=base /var/www/html .

# Build the static binary, be sure to select only the PHP extensions you want
WORKDIR /go/src/app/
RUN EMBED=dist/app/ \
FRANKENPHP_VERSION=1.1.2 \
PHP_EXTENSIONS=bcmath,cli,common,curl,gd,intl,mbstring,mysql,pgsql,redis,soap,sqlite3,xml,zip,swoole,fpm \
./build-static.sh

# Last runner stage, to only contain and run our generated binary from builder stage
FROM dunglas/frankenphp AS runner

# Replace the official binary by the one contained your custom modules
COPY --from=builder /go/src/app/dist/frankenphp-linux-x86_64 /usr/local/bin/frankenphp

# EXPOSE ports
# Start app
ENTRYPOINT ["/usr/local/bin/frankenphp", "php-server", "--listen",":8080"]

10 changes: 10 additions & 0 deletions tests/Feature/Snippets/frankenphp_binary/composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"require": {
},
"extra":{
"flags":{
"frankenphp-binary":true
},
"templates":["Dockerfile"]
}
}

0 comments on commit e7e7285

Please sign in to comment.