Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
*.pem
.env
.history
build/
build-bin/
node_modules
probot/
src/linters/phpcs/vendor
Expand Down
10 changes: 7 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
{
"private": true,
"engines": {
"node" : "20"
},
"dependencies": {
"@humanmade/probot-util": "^0.2.0",
"lodash.chunk": "^4.2.0",
Expand All @@ -19,10 +22,11 @@
"run.env": "^1.1.0"
},
"scripts": {
"build:php": "scripts/build-php.sh",
"build:babel-watch": "babel src --out-dir build --ignore src/linters/phpcs/vendor -D -w",
"build:bin": "aws s3 sync s3://hm-linter/bin ./bin && chmod +x ./bin/*",
"build:lib": "aws s3 sync s3://hm-linter/lib ./lib && chmod +x ./lib/*",
"build:npm": "docker run --rm -v \"${PWD}\":/var/task lambci/lambda:build-nodejs12.x npm install",
"build:npm": "scripts/build-npm.sh",
"build": "npm run build:bin && npm run build:lib && npm run build:npm",
"clean:package": "( test -f lambda-function.zip && rm lambda-function.zip ) || true",
"deploy:check": "test -f bin/php && test -f lib/libcrypt.so && test -f production.private-key.pem",
Expand All @@ -34,7 +38,7 @@
"deploy:push-dev": "NODE_ENV=development run.env scripts/deploy.sh",
"deploy": "npm run clean:package && npm run build && npm run deploy:check && npm run deploy:package-production && npm run deploy:push",
"deploy:dev": "npm run clean:package && npm run build && npm run deploy:check-dev && npm run deploy:package-dev && npm run deploy:push-dev",
"start": "docker run -it --rm --env-file .env.dev -e NO_UPDATE_NOTIFIER=1 -v \"$PWD\":/var/task:ro --entrypoint /var/task/node_modules/.bin/nodemon lambci/lambda:nodejs12.x /var/task/start-development.js",
"test": "docker run -i --rm --env-file .env -e DOCKER_LAMBDA_USE_STDIN=1 -v \"$PWD\":/var/task:ro lambci/lambda:nodejs12.x index.probotHandler"
"start": "docker run -it --rm --env-file .env.dev -e NO_UPDATE_NOTIFIER=1 -v \"$PWD\":/var/task:ro --entrypoint /var/task/node_modules/.bin/nodemon public.ecr.aws/lambda/nodejs:20 /var/task/start-development.js",
"test": "docker run -i --rm --env-file .env -e DOCKER_LAMBDA_USE_STDIN=1 -v \"$PWD\":/var/task:ro public.ecr.aws/lambda/nodejs:20 index.probotHandler"
}
}
12 changes: 12 additions & 0 deletions scripts/Dockerfile.build-npm
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Lambda base image Amazon linux
FROM public.ecr.aws/lambda/nodejs:20 AS builder

# Build Node Modules
COPY package.json package.json
COPY package-lock.json package-lock.json
RUN npm ci

# Export binary as output
FROM scratch AS export

COPY --from=builder /var/task/node_modules node_modules
48 changes: 48 additions & 0 deletions scripts/Dockerfile.build-php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Lambda base image Amazon linux
FROM public.ecr.aws/lambda/provided:al2 AS builder

# Set desired PHP Version
ARG php_version="8.2.24"
RUN echo ${php_version}
RUN yum clean all && \
yum install -y autoconf \
bison \
bzip2-devel \
gcc \
gcc-c++ \
git \
gzip \
libcurl-devel \
libicu-devel \
libtool \
libxml2-devel \
make \
oniguruma-devel \
openssl-devel \
re2c \
sqlite \
sqlite-devel \
tar \
unzip \
xz-devel \
zip

# Download the PHP source, compile, and install both PHP and Composer
RUN curl -sL https://github.com/php/php-src/archive/php-${php_version}.tar.gz | tar -xvz && \
cd php-src-php-${php_version} && \
./buildconf --force && \
./configure --prefix=/opt/php-bin/ --with-openssl --with-curl --with-zlib --without-pear --enable-bcmath --with-bz2 --enable-mbstring --with-mysqli && \
make -j 5 && \
make install && \
/opt/php-bin/bin/php -v

COPY copy-dependencies.php /copy-deps.php
COPY libs-x86.txt /libs-x86.txt
RUN mkdir /opt/php-bin/lib-export
RUN /opt/php-bin/bin/php /copy-deps.php /opt/php-bin/bin/php /opt/php-bin/lib-export
RUN ls /opt/php-bin/lib-export
# Export binary as output
FROM scratch AS export
ARG php_version
COPY --from=builder /opt/php-bin/bin/php /bin/php
COPY --from=builder /opt/php-bin/lib-export /lib
9 changes: 9 additions & 0 deletions scripts/build-npm.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/bash -e

SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )

cd $SCRIPT_DIR
cp ../package.json ./
cp ../package-lock.json ./
docker build --platform linux/amd64 --progress plain -f "Dockerfile.build-npm" -o ../ .
rm package*.json
12 changes: 12 additions & 0 deletions scripts/build-php.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/bash -e

if [[ -z $1 ]]; then
echo "You must provide a valid PHP version, if running via npm use `npm run build:php -- <version>`"
exit 1
fi

PHP_VERSION="$1"
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )

cd $SCRIPT_DIR
docker build --platform linux/amd64 --progress plain --build-arg "php_version=${PHP_VERSION}" -f "Dockerfile.build-php" -o ../ .
88 changes: 88 additions & 0 deletions scripts/copy-dependencies.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<?php declare(strict_types=1);

/********************************************************
*
* Copies the system dependencies used by a binary/extension.
*
* Usage:
* php copy-dependencies.php <file-to-analyze> <target-directory>
*
* For example:
* php copy-dependencies.php /opt/bin/php /opt/lib
*
* This is taken from Bref PHP.
*
********************************************************/

if (! ($argv[1] ?? false)) {
echo 'Missing the first argument, check the file to see how to use it' . PHP_EOL;
exit(1);
}
if (! ($argv[2] ?? false)) {
echo 'Missing the second argument, check the file to see how to use it' . PHP_EOL;
exit(1);
}
[$_, $pathToCheck, $targetDirectory] = $argv;

$arch = 'x86';
if (php_uname('m') !== 'x86_64') {
$arch = 'arm';
}

$librariesThatExistOnLambda = file(__DIR__ . "/libs-$arch.txt");
$librariesThatExistOnLambda = array_map('trim', $librariesThatExistOnLambda);
// For some reason some libraries are actually not in Lambda, despite being in the docker image 🤷
$librariesThatExistOnLambda = array_filter($librariesThatExistOnLambda, function ($library) {
return ! str_contains($library, 'libgcrypt.so') && ! str_contains($library, 'libgpg-error.so');
});

$requiredLibraries = listDependencies($pathToCheck);

print_r($requiredLibraries);
// Exclude existing system libraries
$requiredLibraries = array_filter($requiredLibraries, function (string $lib) use ($librariesThatExistOnLambda) {
// Libraries that we compiled are in /usr/lib or /usr/lib64, we compiled them because they are more
// recent than the ones in Lambda so we definitely want to use them
$isALibraryWeCompiled = str_starts_with($lib, '/usr/lib');
$doesNotExistInLambda = !in_array(basename($lib), $librariesThatExistOnLambda, true);
$keep = $isALibraryWeCompiled || $doesNotExistInLambda;
if (! $keep) {
echo "Skipping $lib because it's already in Lambda" . PHP_EOL;
}
return $keep;
});

// Copy all the libraries
foreach ($requiredLibraries as $libraryPath) {
$targetPath = $targetDirectory . '/' . basename($libraryPath);
echo "Copying $libraryPath to $targetPath" . PHP_EOL;
$success = copy($libraryPath, $targetPath);
if (! $success) {
throw new RuntimeException("Could not copy $libraryPath to $targetPath");
}
}


function listDependencies(string $path): array
{
// ldd lists the dependencies of a binary or library/extension (.so file)
exec("ldd $path 2>&1", $lines);
if (str_contains(end($lines), 'exited with unknown exit code (139)')) {
// We can't use `ldd` on binaries (like /opt/bin/php) because it fails on cross-platform builds
// so we fall back to `LD_TRACE_LOADED_OBJECTS` (which doesn't work for .so files, that's why we also try `ldd`)
// See https://stackoverflow.com/a/35905007/245552
$output = shell_exec("LD_TRACE_LOADED_OBJECTS=1 $path 2>&1");
if (!$output) {
throw new RuntimeException("Could not list dependencies for $path");
}
$lines = explode(PHP_EOL, $output);
}
$dependencies = [];
foreach ($lines as $line) {
$matches = [];
if (preg_match('/=> (.*) \(0x[0-9a-f]+\)/', $line, $matches)) {
$dependencies[] = $matches[1];
}
}
return $dependencies;
}
Loading