Skip to content

Commit 1261686

Browse files
committed
[FEATURE] ✨ Build binary
Add build scripts to generate a self-contained binary with Phpacker.
1 parent f102e4a commit 1261686

File tree

9 files changed

+217
-4
lines changed

9 files changed

+217
-4
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
.env
22
.idea
3+
/build/
34
/composer.phar
45
/composer.lock
56
/vendor/
67
/repositories.json*
8+
/*.phar

README.md

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,38 @@ cd my-patches
7070

7171
## Requirements
7272

73-
- PHP
7473
- Git
74+
- PHP, when installed via Composer
75+
76+
Patchbot is written in PHP, but standalone Linux binaries are available.
77+
Combined with multi-language patch support (Shell, Python, Git diff),
78+
_you can use Patchbot without writing or running PHP_ yourself.
7579

7680
## Installation
7781

82+
### Standalone binary
83+
84+
Download the latest binary from the
85+
[GitHub Releases](https://github.com/pixelbrackets/patchbot-dist/releases):
86+
87+
```bash
88+
# Download and make executable
89+
curl -L -o patchbot https://github.com/pixelbrackets/patchbot-dist/releases/latest/download/patchbot-linux-x64
90+
chmod +x patchbot
91+
92+
# Run
93+
./patchbot list
94+
```
95+
96+
A PHAR archive is also available for systems with PHP installed:
97+
98+
```bash
99+
curl -L -o patchbot.phar https://github.com/pixelbrackets/patchbot-dist/releases/latest/download/patchbot.phar
100+
php patchbot.phar list
101+
```
102+
103+
### Composer (Recommended)
104+
78105
Use the
79106
[skeleton package](https://packagist.org/packages/pixelbrackets/patchbot-skeleton/)
80107
to create a patch project right away:

bin/patchbot

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,18 @@ if (!$loaded) {
1818
);
1919
}
2020

21-
$version = \Jean85\PrettyVersions::getVersion('pixelbrackets/patchbot')->getPrettyVersion();
21+
// Determine version: prefer .version file (PHAR/binary builds), fallback to PrettyVersions (Composer installs)
22+
if (file_exists(__DIR__ . '/../.version')) {
23+
$version = trim(file_get_contents(__DIR__ . '/../.version'));
24+
} else {
25+
$version = \Jean85\PrettyVersions::getVersion('pixelbrackets/patchbot')->getPrettyVersion();
26+
}
2227

23-
$runner = new \Robo\Runner(\Pixelbrackets\Patchbot\RoboFile::class);
24-
$statusCode = $runner->execute($argv, 'Patchbot', $version);
28+
try {
29+
$runner = new \Robo\Runner(\Pixelbrackets\Patchbot\RoboFile::class);
30+
$statusCode = $runner->execute($argv, 'Patchbot', $version);
31+
} catch (\Exception $e) {
32+
echo 'Fatal Error: ' . $e->getMessage() . PHP_EOL;
33+
$statusCode = 1;
34+
}
2535
exit($statusCode);

build-binary.sh

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#!/bin/bash
2+
set -e
3+
4+
# Check requirements
5+
if [ ! -f "patchbot.phar" ]; then
6+
echo "Error: patchbot.phar not found. Run build-phar.php first"
7+
exit 1
8+
fi
9+
10+
if [ ! -f "$HOME/.config/composer/vendor/bin/phpacker" ]; then
11+
echo "Error: PHPacker not found. Install with: composer global require phpacker/phpacker"
12+
exit 1
13+
fi
14+
15+
# Read PHP version from .php-version file
16+
PHP_VERSION=$(tr -d '[:space:]' < .php-version)
17+
18+
# Build Linux binary with PHPacker
19+
~/.config/composer/vendor/bin/phpacker build linux x64 --src=./patchbot.phar --dest=./build --php="$PHP_VERSION" --no-interaction
20+
21+
# Clean up
22+
if [ -d "build/linux" ]; then
23+
[ -f "build/linux/linux-x64" ] && mv build/linux/linux-x64 build/patchbot-linux-x64 && chmod +x build/patchbot-linux-x64
24+
[ -f "build/linux/linux-arm64" ] && mv build/linux/linux-arm64 build/patchbot-linux-arm64 && chmod +x build/patchbot-linux-arm64
25+
rmdir build/linux 2>/dev/null || true
26+
fi
27+
28+
echo "Done"

build-executables.sh

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#!/bin/bash
2+
set -e
3+
4+
# Build all executables (PHAR and binary)
5+
6+
# Install dependencies without dev dependencies
7+
composer install --no-dev --optimize-autoloader
8+
9+
# Build PHAR
10+
php --define phar.readonly=0 build-phar.php
11+
if [ ! -f "patchbot.phar" ]; then
12+
echo "Error: patchbot.phar was not created"
13+
exit 1
14+
fi
15+
16+
# Test PHAR
17+
php patchbot.phar list > /dev/null
18+
19+
# Build binary
20+
./build-binary.sh
21+
22+
# Move PHAR to build directory
23+
mv patchbot.phar build/patchbot.phar
24+
25+
# Generate checksums
26+
cd build
27+
sha256sum patchbot-linux-* patchbot.phar > checksums.txt 2>/dev/null || sha256sum patchbot.phar > checksums.txt
28+
cd ..
29+
30+
# Re-Install with dev dependencies for further development
31+
composer install
32+
33+
echo "Done"

build-phar.php

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<?php
2+
3+
// Catch missing write rights
4+
if (ini_get('phar.readonly') == 1) {
5+
echo 'Run »php --define phar.readonly=0 build-phar.php« to build the phar' . PHP_EOL;
6+
exit(1);
7+
}
8+
9+
$exclude = [
10+
'.claude',
11+
'.editorconfig',
12+
'.env',
13+
'.env.example',
14+
'.git',
15+
'.gitattributes',
16+
'.gitignore',
17+
'.gitlab-ci.example.yml',
18+
'.gitlab-ci.yml',
19+
'.idea',
20+
'.notes',
21+
'.php-version',
22+
'.php_cs.cache',
23+
'CLAUDE.md',
24+
'CONTRIBUTING.md',
25+
'build',
26+
'build-phar.php',
27+
'composer.phar',
28+
'docs',
29+
'patches',
30+
'phpacker.json',
31+
'repositories.json',
32+
'tests',
33+
];
34+
35+
$baseDir = realpath(__DIR__);
36+
$filter = function ($file, $key, $iterator) use ($exclude, $baseDir) {
37+
// Only check exclude list for root-level entries
38+
if (realpath($file->getPath()) === $baseDir && in_array($file->getFilename(), $exclude)) {
39+
return false;
40+
}
41+
return $iterator->hasChildren() || $file->isFile() || $file->isLink();
42+
};
43+
44+
$iterator = new RecursiveIteratorIterator(
45+
new RecursiveCallbackFilterIterator(
46+
new RecursiveDirectoryIterator(__DIR__, RecursiveDirectoryIterator::SKIP_DOTS | RecursiveDirectoryIterator::FOLLOW_SYMLINKS),
47+
$filter
48+
)
49+
);
50+
51+
// Inject version from Git tag
52+
exec('git describe --tags --dirty --always', $gitVersion);
53+
$version = trim($gitVersion[0] ?? 'dev');
54+
file_put_contents(__DIR__ . '/.version', $version);
55+
echo 'Building version: ' . $version . PHP_EOL;
56+
57+
// Create entry script to avoid shebang duplicates
58+
$file = file(__DIR__ . '/bin/patchbot');
59+
unset($file[0]);
60+
file_put_contents(__DIR__ . '/bin/patchbot.php', $file);
61+
62+
// Create phar
63+
$phar = new \Phar('patchbot.phar');
64+
$phar->setSignatureAlgorithm(\Phar::SHA1);
65+
$phar->startBuffering();
66+
$phar->buildFromIterator($iterator, __DIR__);
67+
//default executable
68+
$phar->setStub(
69+
'#!/usr/bin/env php ' . PHP_EOL . $phar->createDefaultStub('bin/patchbot.php')
70+
);
71+
$phar->stopBuffering();
72+
73+
// Make phar executable
74+
chmod(__DIR__ . '/patchbot.phar', 0770);
75+
76+
// Remove generated entry script and version file
77+
unlink(__DIR__ . '/bin/patchbot.php');
78+
unlink(__DIR__ . '/.version');
79+
80+
echo 'Done';

composer.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@
4040
}
4141
},
4242
"scripts": {
43+
"build:binary": "./build-binary.sh",
44+
"build:executables": "./build-executables.sh",
45+
"build:phar": "php --define phar.readonly=0 build-phar.php",
4346
"test": [
4447
"phpunit tests/unit/"
4548
]

docs/walkthrough.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,30 @@ you have two options:
3838

3939
## 2. Create a Patch Project
4040

41+
### Using the standalone binary
42+
43+
If you don't use PHP, download the standalone binary from
44+
[GitHub Releases](https://github.com/pixelbrackets/patchbot-dist/releases)
45+
and create a project directory manually:
46+
47+
```bash
48+
# Download binary
49+
curl -L -o patchbot https://github.com/pixelbrackets/patchbot-dist/releases/latest/download/patchbot-linux-x64
50+
chmod +x patchbot
51+
52+
# Create project structure
53+
mkdir -p my-patches/patches
54+
cd my-patches
55+
56+
# Create your first patch
57+
../patchbot create "My first patch" --type=sh
58+
```
59+
60+
The binary bundles the PHP runtime, so no PHP installation is needed on
61+
your system. Write patches in Shell, Python, or as Git diffs.
62+
63+
### Using Composer
64+
4165
The easiest way to get started is the
4266
[skeleton package](https://packagist.org/packages/pixelbrackets/patchbot-skeleton/):
4367

phpacker.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"src": "./patchbot.phar",
3+
"dest": "./build",
4+
"platform": "linux",
5+
"php": "8.4"
6+
}

0 commit comments

Comments
 (0)