mirror of
https://github.com/fleetbase/fleetbase.git
synced 2026-01-08 15:26:19 +00:00
Compare commits
67 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
723deff398 | ||
|
|
fd9adc3961 | ||
|
|
4244a04052 | ||
|
|
e3c60a2232 | ||
|
|
1eaeb2c46e | ||
|
|
1d64d18b8b | ||
|
|
1124ecb56c | ||
|
|
672f3d51ca | ||
|
|
cd5af8dfc8 | ||
|
|
1a0073eae0 | ||
|
|
d24b1d6fbe | ||
|
|
ebbc4b2bf8 | ||
|
|
b531c18d65 | ||
|
|
fded8b24df | ||
|
|
98d082c780 | ||
|
|
d905943511 | ||
|
|
5c73b6e76d | ||
|
|
cedf96fc97 | ||
|
|
854fa2e680 | ||
|
|
91b01c8a17 | ||
|
|
a4033db36c | ||
|
|
c54ef7fb30 | ||
|
|
b5ec15f0bb | ||
|
|
1f609dd882 | ||
|
|
01883da5a2 | ||
|
|
d2ab5b8a94 | ||
|
|
dca23f7e3f | ||
|
|
d94dff7fbb | ||
|
|
e1ab6a3b11 | ||
|
|
c79fe67e44 | ||
|
|
d8adf42b24 | ||
|
|
80da5fe013 | ||
|
|
06fd5e20e8 | ||
|
|
f04807de1e | ||
|
|
b7666eeb3e | ||
|
|
dd895a0fd8 | ||
|
|
8c74c0fb99 | ||
|
|
92170c965e | ||
|
|
fcb3694874 | ||
|
|
aa46059bff | ||
|
|
a5175bb11b | ||
|
|
01816a1fe0 | ||
|
|
15d500cd58 | ||
|
|
95d77a6ddd | ||
|
|
eefc93e130 | ||
|
|
0f18ae85f1 | ||
|
|
a4812192da | ||
|
|
15d3c957b8 | ||
|
|
c2bd098d14 | ||
|
|
98511fd418 | ||
|
|
225110c8dc | ||
|
|
1aa2a99763 | ||
|
|
6e888af772 | ||
|
|
d61205d898 | ||
|
|
72078553cc | ||
|
|
bfae04a645 | ||
|
|
c59f028755 | ||
|
|
2b959db773 | ||
|
|
a9354ccbfd | ||
|
|
23e6d1e6b9 | ||
|
|
86da1bd095 | ||
|
|
ae89600ae6 | ||
|
|
6697b79185 | ||
|
|
4dc9764853 | ||
|
|
e372bc6396 | ||
|
|
2f432d148a | ||
|
|
8f66bc12e4 |
64
.github/workflows/build-binaries.yml
vendored
Normal file
64
.github/workflows/build-binaries.yml
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
name: Build Fleetbase Binaries
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
workflow_run:
|
||||
workflows: ["Create Release"]
|
||||
types: [completed]
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
env:
|
||||
DIST_DIR: builds/dist
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
jobs:
|
||||
build-linux:
|
||||
name: Linux Build
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Build Linux binary
|
||||
run: |
|
||||
chmod +x ./builds/linux/build-linux.sh
|
||||
./builds/linux/build-linux.sh
|
||||
- name: Upload Linux binary
|
||||
if: github.event_name == 'workflow_run'
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: ${{ github.event.workflow_run.head_branch }}
|
||||
files: |
|
||||
${{ env.DIST_DIR }}/fleetbase-linux-x86_64
|
||||
draft: false
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
build-macos:
|
||||
name: macOS (ARM64) Build
|
||||
needs: build-linux
|
||||
runs-on: macos-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install build dependencies
|
||||
run: |
|
||||
brew update
|
||||
brew install autoconf automake coreutils asdf php@8.4
|
||||
source "$(brew --prefix asdf)/libexec/asdf.sh"
|
||||
asdf plugin add php https://github.com/asdf-community/asdf-php.git
|
||||
- name: Build macOS binary
|
||||
run: |
|
||||
chmod +x ./builds/osx/build-osx.sh
|
||||
./builds/osx/build-osx.sh
|
||||
- name: Upload Linux binary
|
||||
if: github.event_name == 'workflow_run'
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: ${{ github.event.workflow_run.head_branch }}
|
||||
files: |
|
||||
${{ env.DIST_DIR }}/fleetbase-darwin-arm64
|
||||
draft: false
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
21
.github/workflows/create-release.yml
vendored
Normal file
21
.github/workflows/create-release.yml
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
name: Create Release
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
jobs:
|
||||
create:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Publish GitHub Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: ${{ github.ref_name }}
|
||||
name: ${{ github.ref_name }}
|
||||
body_path: RELEASE.md
|
||||
draft: false
|
||||
prerelease: false
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
61
.github/workflows/discord-announcement.yml
vendored
Normal file
61
.github/workflows/discord-announcement.yml
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
name: Discord Announcement
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ["Create Release"]
|
||||
types: [completed]
|
||||
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag:
|
||||
description: "Release tag to announce (e.g. v0.7.1)"
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
discord_announcement:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
# 1️⃣ Figure out which tag we’re talking about
|
||||
- id: vars
|
||||
shell: bash
|
||||
run: |
|
||||
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
|
||||
TAG="${{ github.event.inputs.tag }}"
|
||||
else
|
||||
TAG="${{ github.event.workflow_run.head_branch }}"
|
||||
fi
|
||||
echo "TAG=$TAG" >> "$GITHUB_ENV"
|
||||
|
||||
# 2️⃣ Check out the exact commit for that tag
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ env.TAG }}
|
||||
fetch-depth: 1
|
||||
|
||||
# 3️⃣ Stash RELEASE.md in an env var (one atomic write → no EOF error)
|
||||
- id: prep-body
|
||||
shell: bash
|
||||
run: |
|
||||
body=$(<RELEASE.md)
|
||||
max=4000
|
||||
[[ ${#body} -gt $max ]] && body="${body:0:$max}…" # add ellipsis if trimmed
|
||||
{
|
||||
echo "body<<EOF"
|
||||
echo "$body"
|
||||
echo "EOF"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
|
||||
# 4️⃣ Fire the webhook
|
||||
- uses: tsickert/discord-webhook@v5.3.0
|
||||
with:
|
||||
webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
||||
username: Fleetbase
|
||||
content: |
|
||||
@everyone
|
||||
📦 **Fleetbase ${{ env.TAG }} released!**
|
||||
<https://github.com/${{ github.repository }}/releases/tag/${{ env.TAG }}>
|
||||
embed-title: "Fleetbase ${{ env.TAG }} — release notes"
|
||||
embed-url: "https://github.com/fleetbase/fleetbase/releases/tag/${{ env.TAG }}"
|
||||
embed-description: ${{ steps.prep-body.outputs.body }}
|
||||
embed-color: 4362730 # 0x4291EA (Fleetbase Blue)
|
||||
48
.github/workflows/discord_announcement.yml
vendored
48
.github/workflows/discord_announcement.yml
vendored
@@ -1,48 +0,0 @@
|
||||
name: Discord Announcement
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
|
||||
jobs:
|
||||
discord_announcement:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Get tag message
|
||||
id: tag
|
||||
run: |
|
||||
echo "::set-output name=version::$(git describe --tags --abbrev=0)"
|
||||
if [[ "${ACT}" == "true" ]]; then
|
||||
# If running with act, use an environment variable for the tag message
|
||||
echo "::set-output name=message::$(echo -e "${TAG_MESSAGE}" | base64)"
|
||||
else
|
||||
# If running on GitHub, use git to get the tag message
|
||||
echo "::set-output name=message::$(git tag -l --format='%(contents)' $(git describe --tags --abbrev=0) | base64)"
|
||||
fi
|
||||
|
||||
- name: Print tag message
|
||||
run: echo "${{ steps.tag.outputs.message }}"
|
||||
|
||||
- name: Get tag name
|
||||
id: get_tag
|
||||
run: echo "::set-output name=tag::${GITHUB_REF/refs\/tags\//}"
|
||||
|
||||
- name: Decode message
|
||||
id: decode
|
||||
run: |
|
||||
echo "Decoding message..."
|
||||
echo "::set-output name=message::$(echo '${{ steps.tag.outputs.message }}' | base64 --decode)"
|
||||
|
||||
- name: Send message to Discord
|
||||
uses: tsickert/discord-webhook@v5.3.0
|
||||
with:
|
||||
webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
||||
content: "@everyone \n📦 New Fleetbase Version ${{ steps.get_tag.outputs.tag }} Released!\n${{ steps.decode.outputs.message }} \nVersion: ${{ steps.get_tag.outputs.tag }} \n[Release Notes for ${{ steps.get_tag.outputs.tag }}](https://github.com/fleetbase/fleetbase/releases/tag/${{ steps.get_tag.outputs.tag }})"
|
||||
username: Fleetbase
|
||||
2
.github/workflows/gcp-cd.yml
vendored
2
.github/workflows/gcp-cd.yml
vendored
@@ -1,4 +1,4 @@
|
||||
name: Fleetbase CI/CD
|
||||
name: Fleetbase GCP CI/CD
|
||||
|
||||
on:
|
||||
push:
|
||||
|
||||
50
.github/workflows/publish-docker-images.yml
vendored
Normal file
50
.github/workflows/publish-docker-images.yml
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
name: Fleetbase Docker Images
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
branch:
|
||||
description: 'Branch to build from'
|
||||
required: false
|
||||
default: 'main'
|
||||
version:
|
||||
description: 'Image version tag (e.g., v0.7.1-beta)'
|
||||
required: false
|
||||
|
||||
jobs:
|
||||
docker-release:
|
||||
name: Build and Push Docker Images
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
env:
|
||||
REGISTRY: fleetbase
|
||||
VERSION: ${{ github.event.inputs.version || (github.ref_type == 'tag' && startsWith(github.ref_name, 'v') && github.ref_name) || 'manual' }}
|
||||
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ github.event.inputs.branch || github.ref_name }}
|
||||
submodules: recursive
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
||||
|
||||
- name: Build and Push Console & API Images
|
||||
uses: docker/bake-action@v2
|
||||
with:
|
||||
push: true
|
||||
targets: |
|
||||
fleetbase-console
|
||||
fleetbase-api
|
||||
files: |
|
||||
./docker-bake.hcl
|
||||
13
.gitignore
vendored
13
.gitignore
vendored
@@ -34,4 +34,15 @@ packages/customer-portal
|
||||
# wip
|
||||
packages/solid
|
||||
solid
|
||||
verdaccio
|
||||
verdaccio
|
||||
# asdf
|
||||
.tools-versions
|
||||
# binary build resources
|
||||
builds/osx/frankenphp
|
||||
# build artifacts
|
||||
/builds/dist/
|
||||
/builds/linux/spc/downloads/*
|
||||
*.exe
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
29
README.md
29
README.md
@@ -32,10 +32,7 @@ Fleetbase is a modular logistics and supply chain operating system designed to s
|
||||
|
||||
```bash
|
||||
git clone git@github.com:fleetbase/fleetbase.git
|
||||
cd fleetbase
|
||||
docker-compose up -d
|
||||
docker exec -ti fleetbase-application-1 bash
|
||||
sh deploy.sh
|
||||
cd fleetbase && ./scripts/docker-install.sh
|
||||
```
|
||||
|
||||
## 📖 Table of contents
|
||||
@@ -75,10 +72,7 @@ Make sure you have both the latest versions of docker and docker-compose install
|
||||
|
||||
```bash
|
||||
git clone git@github.com:fleetbase/fleetbase.git
|
||||
cd fleetbase
|
||||
docker-compose up -d
|
||||
docker exec -ti fleetbase-application-1 bash
|
||||
sh deploy.sh
|
||||
cd fleetbase && ./scripts/docker-install.sh
|
||||
```
|
||||
|
||||
### Accessing Fleetbase
|
||||
@@ -89,7 +83,17 @@ Fleetbase API: http://localhost:8000
|
||||
|
||||
### Additional Configurations
|
||||
|
||||
**CORS:** If you’re installing directly on a server you may need to add your IP address or domain to the `api/config/cors.php` file in the `allowed_hosts` array.
|
||||
**CORS:** If you’re installing directly on a server you will need to configure the environment variables to the application container:
|
||||
```
|
||||
CONSOLE_HOST=http://{yourhost}:4200
|
||||
```
|
||||
If you have additional applications or frontends you can use the environment variable `FRONTEND_HOSTS` to add a comma delimited list of additioal frontend hosts.
|
||||
|
||||
**Application Key** If you get an issue about a missing application key just run:
|
||||
```bash
|
||||
docker compose exec application bash -c "php artisan key:generate --show"
|
||||
```
|
||||
Next copy this value to the `APP_KEY` environment variable in the application container and restart.
|
||||
|
||||
**Routing:** Fleetbase ships with a default OSRM server hosted by `[router.project-osrm.org](https://router.project-osrm.org)` but you’re able to use your own or any other OSRM compatible server. You can modify this in the `console/environments` directory by modifying the .env file of the environment you’re deploying and setting the `OSRM_HOST` to the OSRM server for Fleetbase to use.
|
||||
|
||||
@@ -100,6 +104,7 @@ version: “3.8”
|
||||
services:
|
||||
application:
|
||||
environment:
|
||||
CONSOLE_HOST: http://localhost:4200
|
||||
MAIL_MAILER: (ses, smtp, mailgun, postmark, sendgrid)
|
||||
OSRM_HOST: https://router.project-osrm.org
|
||||
IPINFO_API_KEY:
|
||||
@@ -108,7 +113,6 @@ services:
|
||||
TWILIO_SID:
|
||||
TWILIO_TOKEN:
|
||||
TWILIO_FROM:
|
||||
CONSOLE_HOST: http://localhost:4200
|
||||
```
|
||||
|
||||
You can learn more about full installation, and configuration in the [official documentation](https://docs.fleetbase.io/getting-started/install).
|
||||
@@ -145,9 +149,8 @@ Fleetbase offers a few open sourced apps which are built on Fleetbase which can
|
||||
## 🛣️ Roadmap
|
||||
1. **Inventory and Warehouse Management** ~ Pallet will be Fleetbase’s first official extension for WMS & Inventory.
|
||||
2. **Accounting and Invoicing** ~ Ledger will be Fleetbase’s first official extension accounting and invoicing.
|
||||
3. **Binary Builds** ~ Run Fleetbase from a single binary.
|
||||
4. **Fleetbase for Desktop** ~ Desktop builds for OSX and Windows.
|
||||
5. **Custom Maps and Routing Engines** ~ Feature to enable easy integrations with custom maps and routing engines like Google Maps or Mapbox etc…
|
||||
3. **Fleetbase for Desktop** ~ Desktop builds for OSX and Windows.
|
||||
4. **Custom Maps and Routing Engines** ~ Feature to enable easy integrations with custom maps and routing engines like Google Maps or Mapbox etc…
|
||||
|
||||
## 🪲 Bugs and 💡 Feature Requests
|
||||
|
||||
|
||||
34
RELEASE.md
Normal file
34
RELEASE.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# 🚀 Fleetbase v0.7.5 — 2025-05-30
|
||||
|
||||
> “Route optimization and routing control advancements”
|
||||
|
||||
---
|
||||
|
||||
## ✨ Highlights
|
||||
- Added route optimization and routing control services for registering additional routing engines and route optimization services.
|
||||
- Added settings for Routing (Next release will be able to set unit "Miles" or "Kilometers")
|
||||
- Improved and optimized environment and settings mapper.
|
||||
- Added entity activity events
|
||||
- Patched multiple waypoint order creation via API
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Breaking Changes
|
||||
- None 🙂
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Upgrade Steps
|
||||
```bash
|
||||
# Pull latest version
|
||||
git pull origin main --no-rebase
|
||||
|
||||
# Update docker
|
||||
docker compose down && docker compose up -d
|
||||
|
||||
# Run deploy script
|
||||
docker compose exec application bash -c "./deploy.sh"
|
||||
```
|
||||
|
||||
## Need help?
|
||||
Join the discussion on [GitHub Discussions](https://github.com/fleetbase/fleetbase/discussions) or drop by [#fleetbase on Discord](https://discord.com/invite/HnTqQ6zAVn)
|
||||
@@ -10,10 +10,10 @@
|
||||
"require": {
|
||||
"php": "^8.0",
|
||||
"appstract/laravel-opcache": "^4.0",
|
||||
"fleetbase/core-api": "^1.6.5",
|
||||
"fleetbase/fleetops-api": "^0.6.8",
|
||||
"fleetbase/core-api": "^1.6.11",
|
||||
"fleetbase/fleetops-api": "^0.6.14",
|
||||
"fleetbase/registry-bridge": "^0.0.19",
|
||||
"fleetbase/storefront-api": "^0.3.31",
|
||||
"fleetbase/storefront-api": "^0.4.0",
|
||||
"guzzlehttp/guzzle": "^7.0.1",
|
||||
"laravel/framework": "^10.0",
|
||||
"laravel/octane": "^2.3",
|
||||
|
||||
443
api/composer.lock
generated
443
api/composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -26,7 +26,7 @@ return [
|
||||
|
|
||||
*/
|
||||
|
||||
'env' => env('APP_ENV', 'production'),
|
||||
'env' => env('APP_ENV', env('ENVIRONMENT', 'production')),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?php
|
||||
|
||||
use Fleetbase\Support\Utils;
|
||||
use Laravel\Octane\Contracts\OperationTerminated;
|
||||
use Laravel\Octane\Events\RequestHandled;
|
||||
use Laravel\Octane\Events\RequestReceived;
|
||||
@@ -192,6 +193,7 @@ return [
|
||||
'routes',
|
||||
'composer.lock',
|
||||
'.env',
|
||||
...Utils::arrayFrom(env('OCTANE_WATCH_DIRS'))
|
||||
],
|
||||
|
||||
/*
|
||||
|
||||
47
builds/linux/build-linux.sh
Normal file
47
builds/linux/build-linux.sh
Normal file
@@ -0,0 +1,47 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
# Resolve the directory the script is located in
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
ROOT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
|
||||
APP_NAME="Fleetbase"
|
||||
IMAGE_NAME="fleetbase-linux-static"
|
||||
CONTAINER_NAME="fleetbase-linux-build"
|
||||
DIST_DIR="$ROOT_DIR/builds/dist"
|
||||
BINARY_NAME="fleetbase-linux-x86_64"
|
||||
DOCKERFILE="$ROOT_DIR/builds/linux/static-build.Dockerfile"
|
||||
|
||||
# Ensure pkg-config archive is available
|
||||
SPC_DOWNLOADS_DIR="$SCRIPT_DIR/spc/downloads"
|
||||
PKG_TAR="pkg-config-0.29.2.tar.gz"
|
||||
PKG_URL="https://static-php-cli.fra1.digitaloceanspaces.com/static-php-cli/deps/pkg-config/${PKG_TAR}"
|
||||
|
||||
if [[ ! -f "${SPC_DOWNLOADS_DIR}/${PKG_TAR}" ]]; then
|
||||
echo "📥 pkg-config archive missing – downloading..."
|
||||
mkdir -p "${SPC_DOWNLOADS_DIR}"
|
||||
curl -L --retry 3 -o "${SPC_DOWNLOADS_DIR}/${PKG_TAR}" "${PKG_URL}"
|
||||
else
|
||||
echo "✅ pkg-config archive already present."
|
||||
fi
|
||||
|
||||
# Build the image
|
||||
echo "📦 Building static Linux binary for ${APP_NAME}..."
|
||||
docker build -f "$DOCKERFILE" -t "$IMAGE_NAME" .
|
||||
|
||||
# Create a container from the built image
|
||||
echo "📦 Creating container to extract binary..."
|
||||
docker create --name "$CONTAINER_NAME" "$IMAGE_NAME"
|
||||
|
||||
# Make sure dist folder exist
|
||||
mkdir -p "$DIST_DIR"
|
||||
|
||||
# Copy binary from container to local dist folder
|
||||
echo "📂 Extracting binary..."
|
||||
docker cp "$CONTAINER_NAME:/go/src/app/dist/frankenphp-linux-x86_64" "$DIST_DIR/$BINARY_NAME"
|
||||
|
||||
# Cleanup the temp container
|
||||
docker rm "$CONTAINER_NAME"
|
||||
|
||||
echo "✅ Build complete! Binary is located at: $DIST_DIR/$BINARY_NAME"
|
||||
12
builds/linux/spc/libgeos-linux.php
Normal file
12
builds/linux/spc/libgeos-linux.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\builder\linux\library;
|
||||
|
||||
class libgeos extends LinuxLibraryBase
|
||||
{
|
||||
use \SPC\builder\unix\library\libgeos;
|
||||
|
||||
public const NAME = 'libgeos';
|
||||
}
|
||||
33
builds/linux/spc/libgeos-unix.php
Normal file
33
builds/linux/spc/libgeos-unix.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\builder\unix\library;
|
||||
|
||||
use SPC\exception\FileSystemException;
|
||||
use SPC\exception\RuntimeException;
|
||||
use SPC\store\FileSystem;
|
||||
|
||||
trait libgeos
|
||||
{
|
||||
/**
|
||||
* @throws FileSystemException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
protected function build(): void
|
||||
{
|
||||
FileSystem::resetDir($this->source_dir . '/build');
|
||||
|
||||
shell()->cd($this->source_dir . '/build')
|
||||
->setEnv([
|
||||
'CFLAGS' => $this->getLibExtraCFlags(),
|
||||
'LDFLAGS' => $this->getLibExtraLdFlags(),
|
||||
'LIBS' => $this->getLibExtraLibs(),
|
||||
])
|
||||
->execWithEnv("cmake {$this->builder->makeCmakeArgs()} -DBUILD_SHARED_LIBS=OFF ..")
|
||||
->execWithEnv("make -j{$this->builder->concurrency}")
|
||||
->execWithEnv('make install');
|
||||
|
||||
$this->patchPkgconfPrefix(['geos.pc']);
|
||||
}
|
||||
}
|
||||
92
builds/linux/static-build.Dockerfile
Normal file
92
builds/linux/static-build.Dockerfile
Normal file
@@ -0,0 +1,92 @@
|
||||
FROM --platform=linux/amd64 dunglas/frankenphp:static-builder
|
||||
|
||||
WORKDIR /go/src/app
|
||||
|
||||
# Copy Fleetbase app
|
||||
COPY ../../api ./dist/app
|
||||
|
||||
# Set working directory to the embedded Fleetbase app
|
||||
WORKDIR /go/src/app/dist/app
|
||||
|
||||
# Setup for production environment
|
||||
ENV APP_ENV=production
|
||||
ENV APP_DEBUG=false
|
||||
ENV BROADCAST_DRIVER=socketcluster
|
||||
ENV OSRM_HOST="https://router.project-osrm.org"
|
||||
ENV REGISTRY_PREINSTALLED_EXTENSIONS=true
|
||||
|
||||
# Optional: Ensure writable storage
|
||||
RUN chmod -R 775 bootstrap/cache storage
|
||||
|
||||
# Set permissions for deploy script
|
||||
RUN chmod +x ./deploy.sh
|
||||
|
||||
# Move back to main app directory before running build-static.sh
|
||||
WORKDIR /go/src/app
|
||||
|
||||
# Install geos lib
|
||||
RUN apk add --no-cache geos geos-dev
|
||||
|
||||
# Inject the libgeos library handlers
|
||||
COPY ./builds/linux/spc/libgeos-linux.php ./dist/static-php-cli/src/SPC/builder/linux/library/libgeos.php
|
||||
COPY ./builds/linux/spc/libgeos-unix.php ./dist/static-php-cli/src/SPC/builder/unix/library/libgeos.php
|
||||
|
||||
# Patch source.json to add geos extension source
|
||||
RUN jq '. + {"php-geos": {"type": "url", "url": "https://github.com/libgeos/php-geos/archive/dfe1ab17b0f155cc315bc13c75689371676e02e1.zip", "license": [{"type": "file", "path": "php-geos-dfe1ab17b0f155cc315bc13c75689371676e02e1/MIT-LICENSE"}, {"type": "file", "path": "php-geos-dfe1ab17b0f155cc315bc13c75689371676e02e1/LGPL-2"}]}}' \
|
||||
./dist/static-php-cli/config/source.json > ./dist/static-php-cli/config/source.tmp.json && \
|
||||
mv ./dist/static-php-cli/config/source.tmp.json ./dist/static-php-cli/config/source.json
|
||||
|
||||
# Pathc source.json to add libgeos library
|
||||
RUN jq '. + {"libgeos": {"type": "url", "url": "https://download.osgeo.org/geos/geos-3.12.1.tar.bz2", "filename": "geos-3.12.1.tar.bz2", "extract": "geos-3.12.1", "build-dir": "build", "license": [{"type": "file", "path": "COPYING"}]}}' \
|
||||
./dist/static-php-cli/config/source.json > ./dist/static-php-cli/config/source.tmp.json && \
|
||||
mv ./dist/static-php-cli/config/source.tmp.json ./dist/static-php-cli/config/source.json
|
||||
|
||||
# Patch ext.json to add geos extension dynamically
|
||||
RUN jq '. + {"geos": {"type": "external", "arg-type": "enable", "source": "php-geos", "lib-depends": ["libgeos"]}}' \
|
||||
./dist/static-php-cli/config/ext.json > ./dist/static-php-cli/config/ext.tmp.json && \
|
||||
mv ./dist/static-php-cli/config/ext.tmp.json ./dist/static-php-cli/config/ext.json
|
||||
|
||||
# Patch lib.json to add libgeos
|
||||
RUN jq '. + {"libgeos": {"source": "libgeos", "static-libs-unix": ["libgeos.a", "libgeos_c.a"]}}' \
|
||||
./dist/static-php-cli/config/lib.json > ./dist/static-php-cli/config/lib.tmp.json && \
|
||||
mv ./dist/static-php-cli/config/lib.tmp.json ./dist/static-php-cli/config/lib.json
|
||||
|
||||
# Install dependencies for SPC CLI
|
||||
WORKDIR /go/src/app/dist/static-php-cli
|
||||
RUN composer install --no-dev -a
|
||||
|
||||
# Set PHP extensions to be built (including geos!)
|
||||
ENV PHP_EXTENSIONS="pdo_mysql,gd,bcmath,redis,intl,zip,gmp,apcu,opcache,imagick,sockets,pcntl,geos,iconv,mbstring,fileinfo,ctype,tokenizer,simplexml,dom,filter,session"
|
||||
ENV PHP_EXTENSION_LIBS="libgeos,libzip,bzip2,libxml2,openssl,zlib"
|
||||
|
||||
# Force SPC to use the local source version (not download binary)
|
||||
ENV SPC_REL_TYPE=source
|
||||
|
||||
# Debug build
|
||||
ENV SPC_LOG_LEVEL=debug
|
||||
|
||||
# Skip compression
|
||||
ENV NO_COMPRESS=1
|
||||
|
||||
# set PHP version
|
||||
ENV PHP_VERSION=8.2
|
||||
|
||||
# Move to the app directory
|
||||
WORKDIR /go/src/app
|
||||
|
||||
# Make sure pkg-config is available within the static build container
|
||||
COPY ./builds/linux/spc/downloads/pkg-config-0.29.2.tar.gz ./dist/static-php-cli/downloads/pkg-config-0.29.2.tar.gz
|
||||
|
||||
# Pre-build pkg-config using the existing tarball
|
||||
RUN apk add --no-cache build-base && \
|
||||
tar -xzf ./dist/static-php-cli/downloads/pkg-config-0.29.2.tar.gz -C /tmp && \
|
||||
cd /tmp/pkg-config-0.29.2 && \
|
||||
./configure --with-internal-glib --prefix=/go/src/app/dist/static-php-cli/build/bin && \
|
||||
make && make install && \
|
||||
rm -rf /tmp/pkg-config-0.29.2
|
||||
|
||||
# Do not run git pull
|
||||
RUN sed -i 's/^[ \t]*git pull/# git pull/' ./build-static.sh
|
||||
|
||||
# Build the FrankenPHP static binary
|
||||
RUN EMBED=dist/app ./build-static.sh
|
||||
188
builds/osx/build-osx.sh
Executable file
188
builds/osx/build-osx.sh
Executable file
@@ -0,0 +1,188 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
log() {
|
||||
echo -e "\033[1;34m[🔧 $1]\033[0m"
|
||||
}
|
||||
|
||||
log_success() {
|
||||
echo -e "\033[1;32m[✅ $1]\033[0m"
|
||||
}
|
||||
|
||||
log_warn() {
|
||||
echo -e "\033[1;33m[⚠️ $1]\033[0m"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "\033[1;31m[❌ $1]\033[0m"
|
||||
}
|
||||
|
||||
# Define base paths
|
||||
log "Resolving directories..."
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
ROOT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||
OSX_DIR="$ROOT_DIR/builds/osx"
|
||||
DIST_DIR="$ROOT_DIR/builds/dist"
|
||||
APP_DIR="$ROOT_DIR/api"
|
||||
BREW_PREFIX="/opt/homebrew"
|
||||
|
||||
OS="$(uname -s | tr '[:upper:]' '[:lower:]')"
|
||||
ARCH="$(uname -m)"
|
||||
BINARY_NAME="fleetbase-$OS-$ARCH"
|
||||
|
||||
log "Binary will be: $BINARY_NAME"
|
||||
|
||||
# Setup PHP 8.4
|
||||
log "Detecting current PHP version..."
|
||||
ORIGINAL_PHP_PATH="$(which php)"
|
||||
ORIGINAL_PHP_VERSION="$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION.".".PHP_RELEASE_VERSION;' 2>/dev/null)"
|
||||
IS_ASDF_MANAGED=false
|
||||
|
||||
if [[ "$ORIGINAL_PHP_PATH" == *".asdf"* ]]; then
|
||||
IS_ASDF_MANAGED=true
|
||||
fi
|
||||
|
||||
# 🔁 Trap to restore PHP when script exits
|
||||
trap 'if [ "$IS_ASDF_MANAGED" = true ]; then
|
||||
log "Restoring asdf-managed PHP version: $ORIGINAL_PHP_VERSION"
|
||||
asdf set php "$ORIGINAL_PHP_VERSION" || true
|
||||
log "Reverted to PHP $(php -v | head -n 1)"
|
||||
else
|
||||
log "Unsetting asdf set to restore system PHP"
|
||||
asdf set php system || true
|
||||
log "Reverted to PHP $(php -v | head -n 1)"
|
||||
fi' EXIT
|
||||
|
||||
log "Detected PHP version: $ORIGINAL_PHP_VERSION"
|
||||
log "Detected PHP binary: $ORIGINAL_PHP_PATH"
|
||||
|
||||
# ───────────────────────────────────────────────────────────────────────────────
|
||||
# If the *current* php is already 8.4.x, we skip the entire asdf install step
|
||||
# ───────────────────────────────────────────────────────────────────────────────
|
||||
if [[ "$ORIGINAL_PHP_PATH" == "$BREW_PREFIX/bin/php" && "$ORIGINAL_PHP_VERSION" =~ ^8\.4\. ]]; then
|
||||
log "Homebrew PHP $ORIGINAL_PHP_VERSION detected at $ORIGINAL_PHP_PATH — skipping asdf build/install."
|
||||
else
|
||||
# Only install under asdf if we don’t already have 8.4.0 installed
|
||||
log "No Homebrew PHP 8.4 detected (found $ORIGINAL_PHP_PATH $ORIGINAL_PHP_VERSION), using asdf to build/install."
|
||||
if ! asdf list php | grep -q "8.4.0"; then
|
||||
# Use brew to install required dependencies for asdf php management
|
||||
log "Checking and installing Homebrew packages required for PHP 8.4 build..."
|
||||
|
||||
for pkg in autoconf automake bison freetype gd gettext icu4c krb5 libedit libiconv libjpeg libpng libxml2 libzip pkg-config re2c zlib sqlite3 libsodium oniguruma openssl@3 nasm; do
|
||||
if ! brew list "$pkg" &>/dev/null; then
|
||||
log_warn "$pkg not found. Installing..."
|
||||
arch -arm64 brew install "$pkg"
|
||||
else
|
||||
log "$pkg already installed. Skipping."
|
||||
fi
|
||||
done
|
||||
|
||||
# Set necessary env flags/paths for PHP build on OSX ARM64
|
||||
export CPPFLAGS="-I$BREW_PREFIX/opt/oniguruma/include -I$BREW_PREFIX/opt/libsodium/include -I$BREW_PREFIX/opt/bzip2/include -I$BREW_PREFIX/opt/zlib/include -I$BREW_PREFIX/opt/openssl@3/include -I$BREW_PREFIX/opt/libxml2/include -I$BREW_PREFIX/opt/libedit/include -I$BREW_PREFIX/opt/curl/include -I$BREW_PREFIX/opt/sqlite3/include -I$BREW_PREFIX/opt/freetype/include -I$BREW_PREFIX/opt/jpeg/include -I$BREW_PREFIX/opt/libpng/include -I$BREW_PREFIX/opt/libzip/include"
|
||||
export LDFLAGS="-L$BREW_PREFIX/opt/openssl@3/lib -lssl -lcrypto -lz -L$BREW_PREFIX/opt/oniguruma/lib -lonig -L$BREW_PREFIX/opt/libsodium/lib -lsodium -L$BREW_PREFIX/opt/bzip2/lib -Wl,-rpath,$BREW_PREFIX/opt/bzip2/lib -lbz2 -L$BREW_PREFIX/opt/zlib/lib -L$BREW_PREFIX/opt/openssl@3/lib -L$BREW_PREFIX/opt/libxml2/lib -L$BREW_PREFIX/opt/libedit/lib -L$BREW_PREFIX/opt/sqlite3/lib -lsqlite3 -L$BREW_PREFIX/opt/curl/lib -lcurl -L$BREW_PREFIX/opt/freetype/lib -L$BREW_PREFIX/opt/jpeg/lib -L$BREW_PREFIX/opt/libpng/lib -L$BREW_PREFIX/opt/libzip/lib -lzip -lz"
|
||||
export PKG_CONFIG_PATH="$BREW_PREFIX/opt/openssl/lib/pkgconfig:$BREW_PREFIX/opt/oniguruma/lib/pkgconfig:$BREW_PREFIX/opt/libsodium/lib/pkgconfig:$BREW_PREFIX/opt/libzip/lib/pkgconfig:$BREW_PREFIX/opt/gd/lib/pkgconfig:$BREW_PREFIX/opt/zlib/lib/pkgconfig:$BREW_PREFIX/opt/openssl@3/lib/pkgconfig:$BREW_PREFIX/opt/libxml2/lib/pkgconfig:$BREW_PREFIX/opt/curl/lib/pkgconfig:$BREW_PREFIX/opt/sqlite3/lib/pkgconfig:$BREW_PREFIX/opt/freetype/lib/pkgconfig:$BREW_PREFIX/opt/jpeg/lib/pkgconfig:$BREW_PREFIX/opt/libpng/lib/pkgconfig"
|
||||
export PHP_CONFIGURE_OPTIONS="--with-openssl=$(brew --prefix openssl) --with-iconv=$(brew --prefix libiconv)"
|
||||
|
||||
log "Installing PHP 8.4.0 with asdf..."
|
||||
asdf install php 8.4.0 --verbose
|
||||
else
|
||||
log "asdf already has PHP 8.4.0 installed, skipping"
|
||||
fi
|
||||
|
||||
log "Switching to PHP 8.4.0 with asdf set..."
|
||||
asdf set php 8.4.0 --home
|
||||
fi
|
||||
|
||||
# Clone FrankenPHP
|
||||
if [ ! -d "$OSX_DIR/frankenphp" ]; then
|
||||
log "Cloning FrankenPHP..."
|
||||
git clone https://github.com/dunglas/frankenphp "$OSX_DIR/frankenphp"
|
||||
else
|
||||
log_warn "FrankenPHP already cloned. Skipping."
|
||||
fi
|
||||
|
||||
cd "$OSX_DIR/frankenphp"
|
||||
|
||||
# Patch build script
|
||||
log "Patching build-static.sh to skip git pull..."
|
||||
sed -i '' 's/^[ \t]*git pull/# git pull/' ./build-static.sh
|
||||
|
||||
# Set environment variables
|
||||
log "Exporting build environment variables..."
|
||||
export PHP_VERSION=8.2
|
||||
export PHP_EXTENSIONS="pdo_mysql,gd,bcmath,redis,intl,zip,gmp,apcu,opcache,imagick,sockets,pcntl,geos,iconv,mbstring,fileinfo,ctype,tokenizer,simplexml,dom,filter,session"
|
||||
export PHP_EXTENSION_LIBS="libgeos,libzip,bzip2,libxml2,openssl,zlib"
|
||||
export SPC_REL_TYPE=source
|
||||
export NO_COMPRESS=1
|
||||
export SPC_OPT_BUILD_ARGS="--debug"
|
||||
export CMAKE_OSX_ARCHITECTURES=arm64
|
||||
|
||||
# Clone and prepare static-php-cli in dist/
|
||||
STATIC_PHP_CLI_DIR="$OSX_DIR/frankenphp/dist/static-php-cli"
|
||||
if [ ! -d "$STATIC_PHP_CLI_DIR" ]; then
|
||||
log "Cloning static-php-cli into dist/..."
|
||||
git clone https://github.com/crazywhalecc/static-php-cli.git "$STATIC_PHP_CLI_DIR"
|
||||
else
|
||||
log_warn "static-php-cli already exists in dist/. Skipping clone."
|
||||
fi
|
||||
|
||||
# Inject libgeos support
|
||||
log "Injecting libgeos patch files..."
|
||||
cp "$ROOT_DIR/builds/osx/spc/libgeos-unix.php" "$STATIC_PHP_CLI_DIR/src/SPC/builder/unix/library/libgeos.php"
|
||||
cp "$ROOT_DIR/builds/osx/spc/libgeos-macos.php" "$STATIC_PHP_CLI_DIR/src/SPC/builder/macos/library/libgeos.php"
|
||||
cp "$ROOT_DIR/builds/osx/spc/UnixBuilderBase-macos.php" "$STATIC_PHP_CLI_DIR/src/SPC/builder/unix/UnixBuilderBase.php"
|
||||
|
||||
# Patch SPC config
|
||||
log "Patching SPC config files (source.json, ext.json, lib.json)..."
|
||||
jq '. + {"php-geos": {"type": "url", "url": "https://github.com/libgeos/php-geos/archive/dfe1ab17b0f155cc315bc13c75689371676e02e1.zip", "license": [{"type": "file", "path": "php-geos-dfe1ab17b0f155cc315bc13c75689371676e02e1/MIT-LICENSE"}, {"type": "file", "path": "php-geos-dfe1ab17b0f155cc315bc13c75689371676e02e1/LGPL-2"}]}}' \
|
||||
"$STATIC_PHP_CLI_DIR/config/source.json" > "$STATIC_PHP_CLI_DIR/config/source.tmp.json" && \
|
||||
mv "$STATIC_PHP_CLI_DIR/config/source.tmp.json" "$STATIC_PHP_CLI_DIR/config/source.json"
|
||||
|
||||
jq '. + {"libgeos": {"type": "url", "url": "https://download.osgeo.org/geos/geos-3.12.1.tar.bz2", "filename": "geos-3.12.1.tar.bz2", "extract": "geos-3.12.1", "build-dir": "build", "license": [{"type": "file", "path": "COPYING"}]}}' \
|
||||
"$STATIC_PHP_CLI_DIR/config/source.json" > "$STATIC_PHP_CLI_DIR/config/source.tmp.json" && \
|
||||
mv "$STATIC_PHP_CLI_DIR/config/source.tmp.json" "$STATIC_PHP_CLI_DIR/config/source.json"
|
||||
|
||||
jq '. + {"libgeos": {"source": "libgeos", "static-libs-unix": ["libgeos.a", "libgeos_c.a"]}}' \
|
||||
"$STATIC_PHP_CLI_DIR/config/lib.json" > "$STATIC_PHP_CLI_DIR/config/lib.tmp.json" && \
|
||||
mv "$STATIC_PHP_CLI_DIR/config/lib.tmp.json" "$STATIC_PHP_CLI_DIR/config/lib.json"
|
||||
|
||||
jq '. + {"geos": {"type": "external", "arg-type": "enable", "source": "php-geos", "lib-depends": ["libgeos"]}}' \
|
||||
"$STATIC_PHP_CLI_DIR/config/ext.json" > "$STATIC_PHP_CLI_DIR/config/ext.tmp.json" && \
|
||||
mv "$STATIC_PHP_CLI_DIR/config/ext.tmp.json" "$STATIC_PHP_CLI_DIR/config/ext.json"
|
||||
|
||||
# Prepare app embed folder
|
||||
log "📦 Preparing embedded app directory..."
|
||||
rm -rf ./dist/app
|
||||
mkdir -p ./dist/app
|
||||
cp -R "$APP_DIR"/* ./dist/app/
|
||||
|
||||
log "Patching build-static.sh to skip git pull and composer install..."
|
||||
|
||||
# Skip `git pull`
|
||||
sed -i '' 's/^[[:space:]]*git pull/# git pull/' "$OSX_DIR/frankenphp/build-static.sh"
|
||||
|
||||
# Patch add CoreServices framework for Caddy build on OSX
|
||||
sed -i '' 's/-framework CoreFoundation -framework SystemConfiguration/& -framework CoreServices/' "$OSX_DIR/frankenphp/build-static.sh"
|
||||
|
||||
# ── work around 403 on GH macOS runners ────────────────────────────────────────
|
||||
log "Patching curl to use a browser-like User-Agent (to avoid 403s)…"
|
||||
curl() {
|
||||
command curl -sSL -A "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.6 Safari/605.1.15" "$@"
|
||||
}
|
||||
export -f curl
|
||||
|
||||
# Build the binary
|
||||
log "⚙️ Running FrankenPHP build-static.sh..."
|
||||
EMBED=dist/app ./build-static.sh
|
||||
|
||||
# Move built binary to dist
|
||||
log "Moving built binary to output folder..."
|
||||
mkdir -p "$DIST_DIR"
|
||||
mv dist/frankenphp-mac-$ARCH "$DIST_DIR/$BINARY_NAME"
|
||||
|
||||
log_success "✅ macOS binary built at: $DIST_DIR/$BINARY_NAME"
|
||||
|
||||
# Clean up frankenphp build and app embed folder
|
||||
log "🧹 Cleaning temporary app directory..."
|
||||
rm -rf "$OSX_DIR/frankenphp"
|
||||
271
builds/osx/spc/UnixBuilderBase-macos.php
Normal file
271
builds/osx/spc/UnixBuilderBase-macos.php
Normal file
@@ -0,0 +1,271 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\builder\unix;
|
||||
|
||||
use SPC\builder\BuilderBase;
|
||||
use SPC\builder\linux\LinuxBuilder;
|
||||
use SPC\exception\FileSystemException;
|
||||
use SPC\exception\RuntimeException;
|
||||
use SPC\exception\WrongUsageException;
|
||||
use SPC\store\Config;
|
||||
use SPC\store\FileSystem;
|
||||
use SPC\util\DependencyUtil;
|
||||
use SPC\util\SPCConfigUtil;
|
||||
|
||||
abstract class UnixBuilderBase extends BuilderBase
|
||||
{
|
||||
/** @var string cflags */
|
||||
public string $arch_c_flags;
|
||||
|
||||
/** @var string C++ flags */
|
||||
public string $arch_cxx_flags;
|
||||
|
||||
/** @var string cmake toolchain file */
|
||||
public string $cmake_toolchain_file;
|
||||
|
||||
/**
|
||||
* @throws WrongUsageException
|
||||
* @throws FileSystemException
|
||||
*/
|
||||
public function getAllStaticLibFiles(): array
|
||||
{
|
||||
$libs = [];
|
||||
|
||||
// reorder libs
|
||||
foreach ($this->libs as $lib) {
|
||||
foreach ($lib->getDependencies() as $dep) {
|
||||
$libs[] = $dep;
|
||||
}
|
||||
$libs[] = $lib;
|
||||
}
|
||||
|
||||
$libFiles = [];
|
||||
$libNames = [];
|
||||
// merge libs
|
||||
foreach ($libs as $lib) {
|
||||
if (!in_array($lib::NAME, $libNames, true)) {
|
||||
$libNames[] = $lib::NAME;
|
||||
array_unshift($libFiles, ...$lib->getStaticLibs());
|
||||
}
|
||||
}
|
||||
return array_map(fn ($x) => realpath(BUILD_LIB_PATH . "/{$x}"), $libFiles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return generic cmake options when configuring cmake projects
|
||||
*/
|
||||
public function makeCmakeArgs(): string
|
||||
{
|
||||
$extra = $this instanceof LinuxBuilder ? '-DCMAKE_C_COMPILER=' . getenv('CC') . ' ' : '';
|
||||
|
||||
// NEW: allow env-variable override
|
||||
$arch = getenv('CMAKE_OSX_ARCHITECTURES') ?: 'arm64';
|
||||
|
||||
return $extra .
|
||||
'-DCMAKE_BUILD_TYPE=Release ' .
|
||||
'-DCMAKE_INSTALL_PREFIX=' . BUILD_ROOT_PATH . ' ' .
|
||||
'-DCMAKE_INSTALL_BINDIR=bin ' .
|
||||
'-DCMAKE_INSTALL_LIBDIR=lib ' .
|
||||
'-DCMAKE_INSTALL_INCLUDEDIR=include ' .
|
||||
"-DCMAKE_OSX_ARCHITECTURES={$arch} " .
|
||||
"-DCMAKE_TOOLCHAIN_FILE={$this->cmake_toolchain_file}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate configure flags
|
||||
*/
|
||||
public function makeAutoconfFlags(int $flag = AUTOCONF_ALL): string
|
||||
{
|
||||
$extra = '';
|
||||
// TODO: add auto pkg-config support
|
||||
if (($flag & AUTOCONF_LIBS) === AUTOCONF_LIBS) {
|
||||
$extra .= 'LIBS="' . BUILD_LIB_PATH . '" ';
|
||||
}
|
||||
if (($flag & AUTOCONF_CFLAGS) === AUTOCONF_CFLAGS) {
|
||||
$extra .= 'CFLAGS="-I' . BUILD_INCLUDE_PATH . '" ';
|
||||
}
|
||||
if (($flag & AUTOCONF_CPPFLAGS) === AUTOCONF_CPPFLAGS) {
|
||||
$extra .= 'CPPFLAGS="-I' . BUILD_INCLUDE_PATH . '" ';
|
||||
}
|
||||
if (($flag & AUTOCONF_LDFLAGS) === AUTOCONF_LDFLAGS) {
|
||||
$extra .= 'LDFLAGS="-L' . BUILD_LIB_PATH . '" ';
|
||||
}
|
||||
return $extra;
|
||||
}
|
||||
|
||||
public function proveLibs(array $sorted_libraries): void
|
||||
{
|
||||
// search all supported libs
|
||||
$support_lib_list = [];
|
||||
$classes = FileSystem::getClassesPsr4(
|
||||
ROOT_DIR . '/src/SPC/builder/' . osfamily2dir() . '/library',
|
||||
'SPC\builder\\' . osfamily2dir() . '\library'
|
||||
);
|
||||
foreach ($classes as $class) {
|
||||
if (defined($class . '::NAME') && $class::NAME !== 'unknown' && Config::getLib($class::NAME) !== null) {
|
||||
$support_lib_list[$class::NAME] = $class;
|
||||
}
|
||||
}
|
||||
|
||||
// if no libs specified, compile all supported libs
|
||||
if ($sorted_libraries === [] && $this->isLibsOnly()) {
|
||||
$libraries = array_keys($support_lib_list);
|
||||
$sorted_libraries = DependencyUtil::getLibs($libraries);
|
||||
}
|
||||
|
||||
// add lib object for builder
|
||||
foreach ($sorted_libraries as $library) {
|
||||
if (!in_array(Config::getLib($library, 'type', 'lib'), ['lib', 'package'])) {
|
||||
continue;
|
||||
}
|
||||
// if some libs are not supported (but in config "lib.json", throw exception)
|
||||
if (!isset($support_lib_list[$library])) {
|
||||
throw new WrongUsageException('library [' . $library . '] is in the lib.json list but not supported to compile, but in the future I will support it!');
|
||||
}
|
||||
$lib = new ($support_lib_list[$library])($this);
|
||||
$this->addLib($lib);
|
||||
}
|
||||
|
||||
// calculate and check dependencies
|
||||
foreach ($this->libs as $lib) {
|
||||
$lib->calcDependency();
|
||||
}
|
||||
$this->lib_list = $sorted_libraries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanity check after build complete
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
protected function sanityCheck(int $build_target): void
|
||||
{
|
||||
// sanity check for php-cli
|
||||
if (($build_target & BUILD_TARGET_CLI) === BUILD_TARGET_CLI) {
|
||||
logger()->info('running cli sanity check');
|
||||
[$ret, $output] = shell()->execWithResult(BUILD_ROOT_PATH . '/bin/php -n -r "echo \"hello\";"');
|
||||
$raw_output = implode('', $output);
|
||||
if ($ret !== 0 || trim($raw_output) !== 'hello') {
|
||||
throw new RuntimeException("cli failed sanity check: ret[{$ret}]. out[{$raw_output}]");
|
||||
}
|
||||
|
||||
foreach ($this->getExts(false) as $ext) {
|
||||
logger()->debug('testing ext: ' . $ext->getName());
|
||||
$ext->runCliCheckUnix();
|
||||
}
|
||||
}
|
||||
|
||||
// sanity check for phpmicro
|
||||
if (($build_target & BUILD_TARGET_MICRO) === BUILD_TARGET_MICRO) {
|
||||
$test_task = $this->getMicroTestTasks();
|
||||
foreach ($test_task as $task_name => $task) {
|
||||
$test_file = SOURCE_PATH . '/' . $task_name . '.exe';
|
||||
if (file_exists($test_file)) {
|
||||
@unlink($test_file);
|
||||
}
|
||||
file_put_contents($test_file, file_get_contents(SOURCE_PATH . '/php-src/sapi/micro/micro.sfx') . $task['content']);
|
||||
chmod($test_file, 0755);
|
||||
[$ret, $out] = shell()->execWithResult($test_file);
|
||||
foreach ($task['conditions'] as $condition => $closure) {
|
||||
if (!$closure($ret, $out)) {
|
||||
$raw_out = trim(implode('', $out));
|
||||
throw new RuntimeException("micro failed sanity check: {$task_name}, condition [{$condition}], ret[{$ret}], out[{$raw_out}]");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sanity check for embed
|
||||
if (($build_target & BUILD_TARGET_EMBED) === BUILD_TARGET_EMBED) {
|
||||
logger()->info('running embed sanity check');
|
||||
$sample_file_path = SOURCE_PATH . '/embed-test';
|
||||
if (!is_dir($sample_file_path)) {
|
||||
@mkdir($sample_file_path);
|
||||
}
|
||||
// copy embed test files
|
||||
copy(ROOT_DIR . '/src/globals/common-tests/embed.c', $sample_file_path . '/embed.c');
|
||||
copy(ROOT_DIR . '/src/globals/common-tests/embed.php', $sample_file_path . '/embed.php');
|
||||
$util = new SPCConfigUtil($this);
|
||||
$config = $util->config($this->ext_list, $this->lib_list, $this->getOption('with-suggested-exts'), $this->getOption('with-suggested-libs'));
|
||||
$lens = "{$config['cflags']} {$config['ldflags']} {$config['libs']}";
|
||||
if (PHP_OS_FAMILY === 'Linux' && getenv('SPC_LIBC') === 'musl') {
|
||||
$lens .= ' -static';
|
||||
}
|
||||
[$ret, $out] = shell()->cd($sample_file_path)->execWithResult(getenv('CC') . ' -o embed embed.c ' . $lens);
|
||||
if ($ret !== 0) {
|
||||
throw new RuntimeException('embed failed sanity check: build failed. Error message: ' . implode("\n", $out));
|
||||
}
|
||||
// if someone changed to --enable-embed=shared, we need to add LD_LIBRARY_PATH
|
||||
if (getenv('SPC_CMD_VAR_PHP_EMBED_TYPE') === 'shared') {
|
||||
$ext_path = 'LD_LIBRARY_PATH=' . BUILD_ROOT_PATH . '/lib:$LD_LIBRARY_PATH ';
|
||||
FileSystem::removeFileIfExists(BUILD_ROOT_PATH . '/lib/libphp.a');
|
||||
} else {
|
||||
$ext_path = '';
|
||||
FileSystem::removeFileIfExists(BUILD_ROOT_PATH . '/lib/libphp.so');
|
||||
}
|
||||
[$ret, $output] = shell()->cd($sample_file_path)->execWithResult($ext_path . './embed');
|
||||
if ($ret !== 0 || trim(implode('', $output)) !== 'hello') {
|
||||
throw new RuntimeException('embed failed sanity check: run failed. Error message: ' . implode("\n", $output));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将编译好的二进制文件发布到 buildroot
|
||||
*
|
||||
* @param int $type 发布类型
|
||||
* @throws RuntimeException
|
||||
* @throws FileSystemException
|
||||
*/
|
||||
protected function deployBinary(int $type): bool
|
||||
{
|
||||
$src = match ($type) {
|
||||
BUILD_TARGET_CLI => SOURCE_PATH . '/php-src/sapi/cli/php',
|
||||
BUILD_TARGET_MICRO => SOURCE_PATH . '/php-src/sapi/micro/micro.sfx',
|
||||
BUILD_TARGET_FPM => SOURCE_PATH . '/php-src/sapi/fpm/php-fpm',
|
||||
default => throw new RuntimeException('Deployment does not accept type ' . $type),
|
||||
};
|
||||
logger()->info('Deploying ' . $this->getBuildTypeName($type) . ' file');
|
||||
FileSystem::createDir(BUILD_ROOT_PATH . '/bin');
|
||||
shell()->exec('cp ' . escapeshellarg($src) . ' ' . escapeshellarg(BUILD_ROOT_PATH . '/bin/'));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run php clean
|
||||
*
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
protected function cleanMake(): void
|
||||
{
|
||||
logger()->info('cleaning up');
|
||||
shell()->cd(SOURCE_PATH . '/php-src')->exec('make clean');
|
||||
}
|
||||
|
||||
/**
|
||||
* Patch phpize and php-config if needed
|
||||
* @throws FileSystemException
|
||||
*/
|
||||
protected function patchPhpScripts(): void
|
||||
{
|
||||
// patch phpize
|
||||
if (file_exists(BUILD_BIN_PATH . '/phpize')) {
|
||||
logger()->debug('Patching phpize prefix');
|
||||
FileSystem::replaceFileStr(BUILD_BIN_PATH . '/phpize', "prefix=''", "prefix='" . BUILD_ROOT_PATH . "'");
|
||||
FileSystem::replaceFileStr(BUILD_BIN_PATH . '/phpize', 's##', 's#/usr/local#');
|
||||
}
|
||||
// patch php-config
|
||||
if (file_exists(BUILD_BIN_PATH . '/php-config')) {
|
||||
logger()->debug('Patching php-config prefix and libs order');
|
||||
$php_config_str = FileSystem::readFile(BUILD_BIN_PATH . '/php-config');
|
||||
$php_config_str = str_replace('prefix=""', 'prefix="' . BUILD_ROOT_PATH . '"', $php_config_str);
|
||||
// move mimalloc to the beginning of libs
|
||||
$php_config_str = preg_replace('/(libs=")(.*?)\s*(' . preg_quote(BUILD_LIB_PATH, '/') . '\/mimalloc\.o)\s*(.*?)"/', '$1$3 $2 $4"', $php_config_str);
|
||||
// move lstdc++ to the end of libs
|
||||
$php_config_str = preg_replace('/(libs=")(.*?)\s*(-lstdc\+\+)\s*(.*?)"/', '$1$2 $4 $3"', $php_config_str);
|
||||
FileSystem::writeFile(BUILD_BIN_PATH . '/php-config', $php_config_str);
|
||||
}
|
||||
}
|
||||
}
|
||||
12
builds/osx/spc/libgeos-macos.php
Normal file
12
builds/osx/spc/libgeos-macos.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\builder\macos\library;
|
||||
|
||||
class libgeos extends MacOSLibraryBase
|
||||
{
|
||||
use \SPC\builder\unix\library\libgeos;
|
||||
|
||||
public const NAME = 'libgeos';
|
||||
}
|
||||
33
builds/osx/spc/libgeos-unix.php
Normal file
33
builds/osx/spc/libgeos-unix.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace SPC\builder\unix\library;
|
||||
|
||||
use SPC\exception\FileSystemException;
|
||||
use SPC\exception\RuntimeException;
|
||||
use SPC\store\FileSystem;
|
||||
|
||||
trait libgeos
|
||||
{
|
||||
/**
|
||||
* @throws FileSystemException
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
protected function build(): void
|
||||
{
|
||||
FileSystem::resetDir($this->source_dir . '/build');
|
||||
|
||||
shell()->cd($this->source_dir . '/build')
|
||||
->setEnv([
|
||||
'CFLAGS' => $this->getLibExtraCFlags(),
|
||||
'LDFLAGS' => $this->getLibExtraLdFlags(),
|
||||
'LIBS' => $this->getLibExtraLibs(),
|
||||
])
|
||||
->execWithEnv("cmake {$this->builder->makeCmakeArgs()} -DBUILD_SHARED_LIBS=OFF ..")
|
||||
->execWithEnv("make -j{$this->builder->concurrency}")
|
||||
->execWithEnv('make install');
|
||||
|
||||
$this->patchPkgconfPrefix(['geos.pc']);
|
||||
}
|
||||
}
|
||||
@@ -6,19 +6,19 @@ WORKDIR /console
|
||||
|
||||
# Create the pnpm directory and set the PNPM_HOME environment variable
|
||||
RUN mkdir -p ~/.pnpm
|
||||
ENV PNPM_HOME /root/.pnpm
|
||||
ENV PNPM_HOME=/root/.pnpm
|
||||
|
||||
# Set environment
|
||||
ARG ENVIRONMENT=production
|
||||
|
||||
# Add the pnpm global bin to the PATH
|
||||
ENV PATH /root/.pnpm/bin:$PATH
|
||||
ENV PATH=/root/.pnpm/bin:$PATH
|
||||
|
||||
# Copy pnpm-lock.yaml (or package.json) into the directory /console in the container
|
||||
COPY console/package.json console/pnpm-lock.yaml ./
|
||||
COPY package.json pnpm-lock.yaml ./
|
||||
|
||||
# Copy over .npmrc if applicable
|
||||
COPY console/.npmr[c] ./
|
||||
COPY .npmr[c] ./
|
||||
|
||||
# Install global dependencies
|
||||
RUN npm install -g ember-cli pnpm
|
||||
@@ -33,7 +33,7 @@ RUN mkdir -p -m 0600 ~/.ssh && ssh-keyscan github.com >> ~/.ssh/known_hosts
|
||||
RUN pnpm install
|
||||
|
||||
# Copy the console directory contents into the container at /console
|
||||
COPY console .
|
||||
COPY . .
|
||||
|
||||
# Build the application
|
||||
RUN pnpm build --environment $ENVIRONMENT
|
||||
@@ -48,7 +48,7 @@ COPY --from=builder /console/dist /usr/share/nginx/html
|
||||
EXPOSE 4200
|
||||
|
||||
# Use custom nginx.conf
|
||||
COPY console/nginx.conf /etc/nginx/conf.d/default.conf
|
||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
# Start Nginx server
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
@@ -1,57 +0,0 @@
|
||||
# ---- Build Stage ----
|
||||
FROM node:18.15.0-alpine
|
||||
|
||||
# Set the working directory in the container to /console
|
||||
WORKDIR /console
|
||||
|
||||
# Create the pnpm directory and set the PNPM_HOME environment variable
|
||||
RUN mkdir -p ~/.pnpm
|
||||
ENV PNPM_HOME /root/.pnpm
|
||||
|
||||
# Set environment
|
||||
ARG ENVIRONMENT=production
|
||||
|
||||
# Add the pnpm global bin to the PATH
|
||||
ENV PATH /root/.pnpm/bin:$PATH
|
||||
|
||||
# Copy pnpm-lock.yaml (or package.json) into the directory /console in the container
|
||||
COPY console/package.json console/pnpm-lock.yaml ./
|
||||
|
||||
# Copy over .npmrc if applicable
|
||||
COPY console/.npmr[c] ./
|
||||
|
||||
# Install global dependencies
|
||||
RUN npm install -g ember-cli pnpm
|
||||
|
||||
# Install git
|
||||
RUN apk update && apk add git openssh-client
|
||||
|
||||
# Trust GitHub's RSA host key
|
||||
RUN mkdir -p -m 0600 ~/.ssh && ssh-keyscan github.com >> ~/.ssh/known_hosts
|
||||
|
||||
# Install app dependencies
|
||||
RUN pnpm install
|
||||
|
||||
# Copy the console directory contents into the container at /console
|
||||
COPY console .
|
||||
|
||||
# Build the application
|
||||
RUN pnpm build --environment $ENVIRONMENT
|
||||
|
||||
# # Make sure the build output is available in /console/dist
|
||||
# RUN ls -la /console/dist
|
||||
|
||||
# # ---- Serve Stage ----
|
||||
# FROM nginx:alpine
|
||||
|
||||
# # Copy the built app to our served directory
|
||||
# COPY --from=builder /console/dist /usr/share/nginx/html
|
||||
|
||||
# # Expose the port nginx is bound to
|
||||
# EXPOSE 4201
|
||||
|
||||
# # Use custom nginx.conf
|
||||
# COPY console/nginx.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
# # Start Nginx server
|
||||
# CMD ["nginx", "-g", "daemon off;"]
|
||||
@@ -4,6 +4,7 @@ import loadInitializers from 'ember-load-initializers';
|
||||
import config from '@fleetbase/console/config/environment';
|
||||
import loadExtensions from '@fleetbase/ember-core/utils/load-extensions';
|
||||
import mapEngines from '@fleetbase/ember-core/utils/map-engines';
|
||||
import loadRuntimeConfig from '@fleetbase/console/utils/runtime-config';
|
||||
|
||||
export default class App extends Application {
|
||||
modulePrefix = config.modulePrefix;
|
||||
@@ -20,4 +21,11 @@ export default class App extends Application {
|
||||
}
|
||||
}
|
||||
|
||||
loadInitializers(App, config.modulePrefix);
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
await loadRuntimeConfig();
|
||||
loadInitializers(App, config.modulePrefix);
|
||||
|
||||
let fleetbase = App.create();
|
||||
fleetbase.deferReadiness();
|
||||
fleetbase.boot();
|
||||
});
|
||||
|
||||
@@ -3,7 +3,7 @@ import { tracked } from '@glimmer/tracking';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { action } from '@ember/object';
|
||||
import { isArray } from '@ember/array';
|
||||
import { task } from 'ember-concurrency-decorators';
|
||||
import { task } from 'ember-concurrency';
|
||||
|
||||
export default class MetricComponent extends Component {
|
||||
@service fetch;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Component from '@glimmer/component';
|
||||
import { action } from '@ember/object';
|
||||
import { task } from 'ember-concurrency-decorators';
|
||||
import { task } from 'ember-concurrency';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import Controller from '@ember/controller';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
import { action } from '@ember/object';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { task } from 'ember-concurrency-decorators';
|
||||
import { task } from 'ember-concurrency';
|
||||
import getTwoFaMethods from '@fleetbase/console/utils/get-two-fa-methods';
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import Controller from '@ember/controller';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { action } from '@ember/object';
|
||||
import { alias } from '@ember/object/computed';
|
||||
import { debug } from '@ember/debug';
|
||||
import { task } from 'ember-concurrency';
|
||||
|
||||
export default class ConsoleAccountIndexController extends Controller {
|
||||
@@ -40,6 +42,18 @@ export default class ConsoleAccountIndexController extends Controller {
|
||||
*/
|
||||
@alias('currentUser.user') user;
|
||||
|
||||
/**
|
||||
* Available timezones for selection.
|
||||
*
|
||||
* @memberof ConsoleAccountIndexController
|
||||
*/
|
||||
@tracked timezones = [];
|
||||
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.loadTimezones.perform();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle upload of new photo
|
||||
*
|
||||
@@ -116,6 +130,19 @@ export default class ConsoleAccountIndexController extends Controller {
|
||||
return isPasswordValid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load all available timezones from lookup.
|
||||
*
|
||||
* @memberof ConsoleAccountIndexController
|
||||
*/
|
||||
@task *loadTimezones() {
|
||||
try {
|
||||
this.timezones = yield this.fetch.get('lookup/timezones');
|
||||
} catch (error) {
|
||||
debug(`Unable to load timezones : ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if any user attribute has been changed
|
||||
*
|
||||
|
||||
@@ -2,7 +2,7 @@ import Controller from '@ember/controller';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { action } from '@ember/object';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
import { task } from 'ember-concurrency-decorators';
|
||||
import { task } from 'ember-concurrency';
|
||||
import getTwoFaMethods from '@fleetbase/console/utils/get-two-fa-methods';
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,6 +2,8 @@ import Controller from '@ember/controller';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { action } from '@ember/object';
|
||||
import { debug } from '@ember/debug';
|
||||
import { task } from 'ember-concurrency';
|
||||
|
||||
export default class ConsoleSettingsIndexController extends Controller {
|
||||
/**
|
||||
@@ -25,13 +27,6 @@ export default class ConsoleSettingsIndexController extends Controller {
|
||||
*/
|
||||
@service fetch;
|
||||
|
||||
/**
|
||||
* The request loading state.
|
||||
*
|
||||
* @memberof ConsoleSettingsIndexController
|
||||
*/
|
||||
@tracked isLoading = false;
|
||||
|
||||
/**
|
||||
* the upload queue.
|
||||
*
|
||||
@@ -46,23 +41,32 @@ export default class ConsoleSettingsIndexController extends Controller {
|
||||
*/
|
||||
@tracked uploadedFiles = [];
|
||||
|
||||
/**
|
||||
* Available timezones for selection.
|
||||
*
|
||||
* @memberof ConsoleAccountIndexController
|
||||
*/
|
||||
@tracked timezones = [];
|
||||
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.loadTimezones.perform();
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the organization settings.
|
||||
*
|
||||
* @memberof ConsoleSettingsIndexController
|
||||
*/
|
||||
@action saveSettings(event) {
|
||||
event.preventDefault();
|
||||
this.isLoading = true;
|
||||
@task *saveSettings(event) {
|
||||
event?.preventDefault();
|
||||
|
||||
this.model
|
||||
.save()
|
||||
.then(() => {
|
||||
this.notifications.success('Organization changes successfully saved.');
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false;
|
||||
});
|
||||
try {
|
||||
yield this.model.save();
|
||||
this.notifications.success('Organization changes successfully saved.');
|
||||
} catch (error) {
|
||||
debug(`Unable to save organization settings : ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -91,4 +95,17 @@ export default class ConsoleSettingsIndexController extends Controller {
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load all available timezones from lookup.
|
||||
*
|
||||
* @memberof ConsoleAccountIndexController
|
||||
*/
|
||||
@task *loadTimezones() {
|
||||
try {
|
||||
this.timezones = yield this.fetch.get('lookup/timezones');
|
||||
} catch (error) {
|
||||
debug(`Unable to load timezones : ${error.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import Controller from '@ember/controller';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
import { action } from '@ember/object';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { task } from 'ember-concurrency-decorators';
|
||||
import { task } from 'ember-concurrency';
|
||||
import getTwoFaMethods from '@fleetbase/console/utils/get-two-fa-methods';
|
||||
|
||||
export default class ConsoleSettingsTwoFaController extends Controller {
|
||||
|
||||
@@ -2,7 +2,7 @@ import Controller from '@ember/controller';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { action } from '@ember/object';
|
||||
import { task } from 'ember-concurrency-decorators';
|
||||
import { task } from 'ember-concurrency';
|
||||
|
||||
export default class InstallController extends Controller {
|
||||
@service fetch;
|
||||
|
||||
@@ -14,5 +14,6 @@ export function initialize(application) {
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'load-leaflet',
|
||||
initialize,
|
||||
};
|
||||
|
||||
@@ -39,9 +39,6 @@ export default class ConsoleRoute extends Route {
|
||||
async afterModel(model, transition) {
|
||||
this.universe.callHooks('console:after-model', this.session, this.router, model, transition);
|
||||
removeBootLoader();
|
||||
|
||||
// Reboot extensions
|
||||
this.universe.bootEngines();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -67,3 +67,11 @@ body.console-admin-organizations-index-index .next-table-wrapper > table {
|
||||
body[data-theme='dark'] #boot-loader > .loader-container > .loading-message {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/** hotfix: ember-power-select-trigger broken padding after upgrade - @todo move to ember-ui */
|
||||
body.fleetbase-console .ember-power-select-trigger {
|
||||
padding-top: 0.5rem;
|
||||
padding-right: 2.5rem;
|
||||
padding-bottom: 0.5rem;
|
||||
padding-left: 0.75rem;
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
{{page-title (t "app.name")}}
|
||||
<ModalsContainer />
|
||||
<NotificationContainer @position="top" @zindex="99999" />
|
||||
<BasicDropdownWormhole />
|
||||
<div id="application-root-wormhole"></div>
|
||||
{{outlet}}
|
||||
@@ -33,6 +33,9 @@
|
||||
<PhoneInput @value={{this.user.phone}} @onInput={{fn (mut this.user.phone)}} class="form-input input-lg w-full" />
|
||||
</InputGroup>
|
||||
<InputGroup @name={{t "common.date-of-birth"}} @type="date" @value={{this.user.date_of_birth}} />
|
||||
<InputGroup @name={{t "common.timezone"}} @helpText={{t "console.account.index.timezone"}}>
|
||||
<Select @value={{this.user.timezone}} @options={{this.timezones}} @onSelect={{fn (mut this.user.timezone)}} @placeholder={{t "console.account.index.timezone"}} />
|
||||
</InputGroup>
|
||||
</div>
|
||||
<div class="mt-3 flex items-center justify-end">
|
||||
<Button @buttonType="submit" @type="primary" @size="lg" @icon="save" @text={{t "common.save-button-text"}} @onClick={{perform this.saveProfile}} @isLoading={{not this.saveProfile.isIdle}} />
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<div class="container mx-auto h-screen">
|
||||
<div class="max-w-3xl my-10 mx-auto space-y-6">
|
||||
<ContentPanel @title={{t "console.settings.index.title"}} @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
|
||||
<form {{on "submit" this.saveSettings}}>
|
||||
<form {{on "submit" (perform this.saveSettings)}}>
|
||||
<InputGroup @name={{t "console.settings.index.organization-name"}} @value={{@model.name}} />
|
||||
<InputGroup @name={{t "console.settings.index.organization-description"}} @value={{@model.description}} />
|
||||
<InputGroup @name={{t "console.settings.index.organization-phone"}}>
|
||||
@@ -13,9 +13,12 @@
|
||||
<InputGroup @name={{t "console.settings.index.organization-currency"}}>
|
||||
<CurrencySelect @currency={{@model.currency}} @onCurrencyChange={{fn (mut @model.currency)}} @triggerClass="w-full form-select" />
|
||||
</InputGroup>
|
||||
<InputGroup @name={{t "common.timezone"}} @helpText={{t "console.settings.index.organization-timezone"}}>
|
||||
<Select @value={{@model.timezone}} @options={{this.timezones}} @onSelect={{fn (mut @model.timezone)}} @placeholder={{t "console.settings.index.select-timezone"}} class="w-full form-select" />
|
||||
</InputGroup>
|
||||
<InputGroup @name={{t "console.settings.index.organization-id"}} @value={{@model.public_id}} @disabled={{true}} />
|
||||
<div class="mt-3 flex items-center justify-end">
|
||||
<Button @buttonType="submit" @type="primary" @size="lg" @icon="save" @text="{{t "common.save-button-text"}}" @isLoading={{this.isLoading}} />
|
||||
<Button @buttonType="submit" @type="primary" @size="lg" @icon="save" @text="{{t "common.save-button-text"}}" @isLoading={{this.saveSettings.isRunning}} />
|
||||
</div>
|
||||
</form>
|
||||
</ContentPanel>
|
||||
|
||||
84
console/app/utils/runtime-config.js
Normal file
84
console/app/utils/runtime-config.js
Normal file
@@ -0,0 +1,84 @@
|
||||
import config from '@fleetbase/console/config/environment';
|
||||
import toBoolean from '@fleetbase/ember-core/utils/to-boolean';
|
||||
import { set } from '@ember/object';
|
||||
import { debug } from '@ember/debug';
|
||||
|
||||
/**
|
||||
* Maps allowed runtime keys to internal config paths.
|
||||
*/
|
||||
const RUNTIME_CONFIG_MAP = {
|
||||
API_HOST: 'API.host',
|
||||
API_NAMESPACE: 'API.namespace',
|
||||
SOCKETCLUSTER_PATH: 'socket.path',
|
||||
SOCKETCLUSTER_HOST: 'socket.hostname',
|
||||
SOCKETCLUSTER_SECURE: 'socket.secure',
|
||||
SOCKETCLUSTER_PORT: 'socket.port',
|
||||
OSRM_HOST: 'osrm.host',
|
||||
EXTENSIONS: 'APP.extensions',
|
||||
};
|
||||
|
||||
/**
|
||||
* Coerce and sanitize runtime config values based on key.
|
||||
*
|
||||
* @param {String} key
|
||||
* @param {*} value
|
||||
* @return {*}
|
||||
*/
|
||||
function coerceValue(key, value) {
|
||||
switch (key) {
|
||||
case 'SOCKETCLUSTER_PORT':
|
||||
return parseInt(value, 10);
|
||||
|
||||
case 'SOCKETCLUSTER_SECURE':
|
||||
return toBoolean(value);
|
||||
|
||||
case 'EXTENSIONS':
|
||||
return typeof value === 'string' ? value.split(',') : Array.from(value);
|
||||
|
||||
default:
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply runtime config overrides based on strict allowlist mapping.
|
||||
*
|
||||
* @param {Object} rawConfig
|
||||
*/
|
||||
export function applyRuntimeConfig(rawConfig = {}) {
|
||||
Object.entries(rawConfig).forEach(([key, value]) => {
|
||||
const configPath = RUNTIME_CONFIG_MAP[key];
|
||||
|
||||
if (configPath) {
|
||||
const coercedValue = coerceValue(key, value);
|
||||
set(config, configPath, coercedValue);
|
||||
} else {
|
||||
debug(`[runtime-config] Ignored unknown key: ${key}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Load and apply runtime config.
|
||||
*
|
||||
* @export
|
||||
* @return {void}
|
||||
*/
|
||||
export default async function loadRuntimeConfig() {
|
||||
if (config.APP.disableRuntimeConfig) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`/fleetbase.config.json?_t=${Date.now()}`, { cache: 'no-cache' });
|
||||
if (!response.ok) {
|
||||
debug('No fleetbase.config.json found, using built-in config defaults');
|
||||
return;
|
||||
}
|
||||
|
||||
const runtimeConfig = await response.json();
|
||||
applyRuntimeConfig(runtimeConfig);
|
||||
} catch (e) {
|
||||
debug(`Failed to load runtime config : ${e.message}`);
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,9 @@ module.exports = function (environment) {
|
||||
},
|
||||
|
||||
APP: {
|
||||
autoboot: false,
|
||||
extensions: asArray(getenv('EXTENSIONS')),
|
||||
disableRuntimeConfig: toBoolean(getenv('DISABLE_RUNTIME_CONFIG'))
|
||||
},
|
||||
|
||||
API: {
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
/** eslint-disable node/no-unpublished-require */
|
||||
const EmberApp = require('ember-cli/lib/broccoli/ember-app');
|
||||
const FleetbaseExtensionsIndexer = require('fleetbase-extensions-indexer');
|
||||
const Funnel = require('broccoli-funnel');
|
||||
const writeFile = require('broccoli-file-creator');
|
||||
const postcssImport = require('postcss-import');
|
||||
const postcssPresetEnv = require('postcss-preset-env');
|
||||
const postcssEach = require('postcss-each');
|
||||
@@ -11,6 +13,8 @@ const postcssConditionals = require('postcss-conditionals-renewed');
|
||||
const postcssAtRulesVariables = require('postcss-at-rules-variables');
|
||||
const autoprefixer = require('autoprefixer');
|
||||
const tailwind = require('tailwindcss');
|
||||
const toBoolean = require('./config/utils/to-boolean');
|
||||
const environment = process.env.EMBER_ENV;
|
||||
|
||||
module.exports = function (defaults) {
|
||||
const app = new EmberApp(defaults, {
|
||||
@@ -59,19 +63,15 @@ module.exports = function (defaults) {
|
||||
});
|
||||
|
||||
let extensions = new FleetbaseExtensionsIndexer();
|
||||
let runtimeConfigTree;
|
||||
if (toBoolean(process.env.DISABLE_RUNTIME_CONFIG)) {
|
||||
runtimeConfigTree = writeFile('fleetbase.config.json', '{}');
|
||||
} else {
|
||||
runtimeConfigTree = new Funnel('.', {
|
||||
files: ['fleetbase.config.json'],
|
||||
destDir: '/',
|
||||
});
|
||||
}
|
||||
|
||||
// Use `app.import` to add additional libraries to the generated
|
||||
// output files.
|
||||
//
|
||||
// If you need to use different assets in different
|
||||
// environments, specify an object as the first parameter. That
|
||||
// object's keys should be the environment name and the values
|
||||
// should be the asset to use in that environment.
|
||||
//
|
||||
// If the library that you are including contains AMD or ES6
|
||||
// modules that you would like to import into your application
|
||||
// please specify an object with the list of modules as keys
|
||||
// along with the exports of each module as its value.
|
||||
|
||||
return app.toTree([extensions]);
|
||||
return app.toTree([extensions, runtimeConfigTree].filter(Boolean));
|
||||
};
|
||||
|
||||
3
console/fleetbase.config.json
Normal file
3
console/fleetbase.config.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"API_HOST": "http://localhost:8000"
|
||||
}
|
||||
@@ -6,4 +6,18 @@ server {
|
||||
root /usr/share/nginx/html;
|
||||
try_files $uri $uri/ /index.html =404;
|
||||
}
|
||||
|
||||
# Serve runtime config with no cache
|
||||
location = /fleetbase.config.json {
|
||||
root /usr/share/nginx/html;
|
||||
default_type application/json;
|
||||
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
||||
add_header Pragma "no-cache";
|
||||
add_header Expires 0;
|
||||
try_files /fleetbase.config.json @config_fallback;
|
||||
}
|
||||
|
||||
location @config_fallback {
|
||||
return 200 '{}';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@fleetbase/console",
|
||||
"version": "0.7.0",
|
||||
"version": "0.7.5",
|
||||
"private": true,
|
||||
"description": "Modular logistics and supply chain operating system (LSOS)",
|
||||
"repository": "https://github.com/fleetbase/fleetbase",
|
||||
@@ -29,24 +29,23 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@ember/legacy-built-in-components": "^0.4.2",
|
||||
"@fleetbase/dev-engine": "^0.2.9",
|
||||
"@fleetbase/ember-core": "latest",
|
||||
"@fleetbase/ember-ui": "latest",
|
||||
"@fleetbase/fleetops-data": "latest",
|
||||
"@fleetbase/fleetops-engine": "^0.6.8",
|
||||
"@fleetbase/fleetops-engine": "^0.6.14",
|
||||
"@fleetbase/iam-engine": "^0.1.3",
|
||||
"@fleetbase/dev-engine": "^0.2.9",
|
||||
"@fleetbase/leaflet-routing-machine": "^3.2.17",
|
||||
"@fleetbase/registry-bridge-engine": "^0.0.19",
|
||||
"@fleetbase/storefront-engine": "^0.3.31",
|
||||
"@fleetbase/leaflet-routing-machine": "^3.2.16",
|
||||
"@fleetbase/storefront-engine": "^0.4.0",
|
||||
"@fortawesome/ember-fontawesome": "^2.0.0",
|
||||
"ember-changeset": "4.1.2",
|
||||
"ember-changeset-validations": "4.1.2",
|
||||
"ember-composable-helpers": "^5.0.0",
|
||||
"ember-concurrency": "^3.1.1",
|
||||
"ember-concurrency": "^4.0.4",
|
||||
"ember-concurrency-decorators": "^2.0.3",
|
||||
"ember-intl": "6.3.2",
|
||||
"ember-math-helpers": "^2.18.2",
|
||||
"ember-power-select": "^7.2.0",
|
||||
"ember-prism": "^0.13.0",
|
||||
"ember-radio-button": "3.0.0-beta.1",
|
||||
"ember-tag-input": "^3.1.0",
|
||||
@@ -56,13 +55,13 @@
|
||||
"postcss-nth-list": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@embroider/macros": "1.16.12",
|
||||
"@babel/core": "^7.25.2",
|
||||
"@babel/eslint-parser": "^7.25.1",
|
||||
"@babel/plugin-proposal-decorators": "^7.24.7",
|
||||
"@ember/optional-features": "^2.1.0",
|
||||
"@ember/string": "^3.1.1",
|
||||
"@ember/test-helpers": "^3.3.1",
|
||||
"@embroider/macros": "1.16.12",
|
||||
"@fleetbase/intl-lint": "^0.0.1",
|
||||
"@fortawesome/fontawesome-svg-core": "6.4.0",
|
||||
"@fortawesome/free-brands-svg-icons": "6.4.0",
|
||||
@@ -72,6 +71,7 @@
|
||||
"@tailwindcss/forms": "^0.5.7",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"broccoli-asset-rev": "^3.0.0",
|
||||
"broccoli-file-creator": "^2.1.1",
|
||||
"broccoli-funnel": "^3.0.8",
|
||||
"concurrently": "^8.2.2",
|
||||
"date-fns": "^2.30.0",
|
||||
|
||||
2847
console/pnpm-lock.yaml
generated
2847
console/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
10
console/tests/unit/utils/runtime-config-test.js
Normal file
10
console/tests/unit/utils/runtime-config-test.js
Normal file
@@ -0,0 +1,10 @@
|
||||
import runtimeConfig from '@fleetbase/console/utils/runtime-config';
|
||||
import { module, test } from 'qunit';
|
||||
|
||||
module('Unit | Utility | runtime-config', function () {
|
||||
// TODO: Replace this with your real tests.
|
||||
test('it works', function (assert) {
|
||||
let result = runtimeConfig();
|
||||
assert.ok(result);
|
||||
});
|
||||
});
|
||||
@@ -75,6 +75,7 @@ common:
|
||||
permissions-required-for-changes: You do not have the required permissions to make changes.
|
||||
push-notifications: Push Notifications
|
||||
role: Role
|
||||
timezone: Timezone
|
||||
component:
|
||||
file:
|
||||
dropdown-label: File actions
|
||||
@@ -229,6 +230,7 @@ console:
|
||||
upload-new: Upload new
|
||||
phone: Your phone number.
|
||||
photos: photos
|
||||
timezone: Select your timezone.
|
||||
admin:
|
||||
schedule-monitor:
|
||||
schedule-monitor: Schedule Monitor
|
||||
@@ -301,6 +303,8 @@ console:
|
||||
backdrop: Backdrop
|
||||
backdrop-help-text: Optional banner or background image for your organization.
|
||||
upload-new-backdrop: Upload new backdrop
|
||||
organization-timezone: Select the default timezone for your organization.
|
||||
select-timezone: Select timezone.
|
||||
extensions:
|
||||
title: Extensions are coming soon!
|
||||
message: Please check back in the upcoming versions as we prepare to launch the Extensions repository and marketplace.
|
||||
|
||||
@@ -9,6 +9,10 @@ group "default" {
|
||||
targets = ["app", "app-httpd"]
|
||||
}
|
||||
|
||||
group "release" {
|
||||
targets = ["fleetbase-console", "fleetbase-api"]
|
||||
}
|
||||
|
||||
target "app" {
|
||||
name = "app-${tgt}"
|
||||
|
||||
@@ -48,4 +52,27 @@ target "app-httpd" {
|
||||
GCP ? "${REGISTRY}/app-httpd:%s" : "${REGISTRY}:app-httpd-%s",
|
||||
compact(["latest", VERSION])
|
||||
) : []
|
||||
}
|
||||
|
||||
target "fleetbase-console" {
|
||||
context = "./console"
|
||||
dockerfile = "Dockerfile"
|
||||
platforms = ["linux/amd64"]
|
||||
|
||||
tags = notequal("", REGISTRY) ? formatlist(
|
||||
"${REGISTRY}/fleetbase-console:%s",
|
||||
compact(["latest", VERSION])
|
||||
) : []
|
||||
}
|
||||
|
||||
target "fleetbase-api" {
|
||||
context = "./"
|
||||
dockerfile = "docker/Dockerfile"
|
||||
target = "app-release"
|
||||
platforms = ["linux/amd64"]
|
||||
|
||||
tags = notequal("", REGISTRY) ? formatlist(
|
||||
"${REGISTRY}/fleetbase-api:%s",
|
||||
compact(["latest", VERSION])
|
||||
) : []
|
||||
}
|
||||
@@ -31,13 +31,20 @@ services:
|
||||
SOCKETCLUSTER_WORKERS: 10
|
||||
SOCKETCLUSTER_BROKERS: 10
|
||||
|
||||
scheduler:
|
||||
image: fleetbase/fleetbase-api:latest
|
||||
command: ["go-crond", "--verbose", "root:./crontab"]
|
||||
environment:
|
||||
DATABASE_URL: "mysql://root@database/fleetbase"
|
||||
QUEUE_CONNECTION: redis
|
||||
CACHE_DRIVER: redis
|
||||
CACHE_PATH: /fleetbase/api/storage/framework/cache
|
||||
CACHE_URL: tcp://cache
|
||||
REDIS_URL: tcp://cache
|
||||
|
||||
queue:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: docker/Dockerfile
|
||||
target: events-dev
|
||||
args:
|
||||
ENVIRONMENT: development
|
||||
image: fleetbase/fleetbase-api:latest
|
||||
command: ["php", "artisan", "queue:work"]
|
||||
healthcheck:
|
||||
test: ["CMD", "php", "artisan", "queue:status"]
|
||||
interval: 30s
|
||||
@@ -52,21 +59,16 @@ services:
|
||||
REDIS_URL: tcp://cache
|
||||
|
||||
console:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: console/Dockerfile.server-build
|
||||
args:
|
||||
ENVIRONMENT: development
|
||||
image: fleetbase/fleetbase-console:latest
|
||||
ports:
|
||||
- "4200:4200"
|
||||
volumes:
|
||||
- ./console/fleetbase.config.json:/usr/share/nginx/html/fleetbase.config.json
|
||||
|
||||
application:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: docker/Dockerfile
|
||||
target: app-dev
|
||||
args:
|
||||
ENVIRONMENT: development
|
||||
image: fleetbase/fleetbase-api:latest
|
||||
volumes:
|
||||
- ./api/.env:/fleetbase/api/.env
|
||||
environment:
|
||||
ENVIRONMENT: development
|
||||
DATABASE_URL: "mysql://root@database/fleetbase"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
FROM dunglas/frankenphp:1.5.0-php8.2-bookworm AS base
|
||||
|
||||
# Install packages
|
||||
RUN apt-get update && apt-get install -y git bind9-utils mycli nodejs npm nano \
|
||||
RUN apt-get update && apt-get install -y git bind9-utils mycli nodejs npm nano uuid-runtime \
|
||||
&& mkdir -p /root/.ssh \
|
||||
&& ssh-keyscan github.com >> /root/.ssh/known_hosts
|
||||
|
||||
@@ -75,20 +75,34 @@ ENV QUEUE_CONNECTION=redis
|
||||
ENV CADDYFILE_PATH=/fleetbase/Caddyfile
|
||||
ENV CONSOLE_PATH=/fleetbase/console
|
||||
ENV OCTANE_SERVER=frankenphp
|
||||
ENV FLEETBASE_VERSION=0.7.5
|
||||
|
||||
# Set environment
|
||||
ARG ENVIRONMENT=production
|
||||
ENV APP_ENV=$ENVIRONMENT
|
||||
|
||||
# Setup github auth
|
||||
ARG GITHUB_AUTH_KEY
|
||||
|
||||
# Copy Caddyfile
|
||||
COPY --chown=www-data:www-data ./Caddyfile $CADDYFILE_PATH
|
||||
|
||||
# Create /fleetbase directory and set correct permissions
|
||||
RUN mkdir -p /fleetbase/api && mkdir -p /fleetbase/console && chown -R www-data:www-data /fleetbase
|
||||
|
||||
# Generate and store a UUID in .fleetbase-id
|
||||
RUN uuidgen > /fleetbase/api/.fleetbase-id
|
||||
|
||||
# Export the same ID as an environment variable for use in the container
|
||||
RUN export FLEETBASE_INSTANCE_ID=$(cat /fleetbase/api/.fleetbase-id) && \
|
||||
echo "FLEETBASE_INSTANCE_ID=$FLEETBASE_INSTANCE_ID" >> /etc/environment
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /fleetbase/api
|
||||
|
||||
# If GITHUB_AUTH_KEY is provided, create auth.json with it
|
||||
RUN if [ -n "$GITHUB_AUTH_KEY" ]; then echo "{\"github-oauth\": {\"github.com\": \"$GITHUB_AUTH_KEY\"}}" > auth.json; fi
|
||||
|
||||
# Prepare composer cache directory
|
||||
RUN mkdir -p /var/www/.cache/composer && chown -R www-data:www-data /var/www/.cache/composer
|
||||
|
||||
@@ -116,21 +130,18 @@ RUN chmod -R 755 /fleetbase/api/storage
|
||||
# Set permissions for deploy script
|
||||
RUN chmod +x /fleetbase/api/deploy.sh
|
||||
|
||||
# Scheduler base stage
|
||||
FROM base AS scheduler-base
|
||||
|
||||
# Install go-crond
|
||||
RUN curl -L https://github.com/webdevops/go-crond/releases/download/23.12.0/go-crond.linux.amd64 > /usr/local/bin/go-crond && chmod +x /usr/local/bin/go-crond
|
||||
COPY docker/crontab ./crontab
|
||||
RUN chmod 0600 ./crontab
|
||||
|
||||
# Scheduler dev stage
|
||||
FROM scheduler-base AS scheduler-dev
|
||||
FROM base AS scheduler-dev
|
||||
ENTRYPOINT []
|
||||
CMD ["go-crond", "--verbose", "root:./crontab"]
|
||||
|
||||
# Scheduler stage
|
||||
FROM scheduler-base AS scheduler
|
||||
FROM base AS scheduler
|
||||
ENTRYPOINT ["/sbin/ssm-parent", "-c", ".ssm-parent.yaml", "run", "--"]
|
||||
CMD ["go-crond", "--verbose", "root:./crontab"]
|
||||
|
||||
@@ -147,7 +158,12 @@ CMD ["php", "artisan", "queue:work"]
|
||||
# Application dev stage
|
||||
FROM base AS app-dev
|
||||
ENTRYPOINT ["docker-php-entrypoint"]
|
||||
CMD ["sh", "-c", "php artisan octane:frankenphp --max-requests=250 --port=8000 --host=0.0.0.0 --watch"]
|
||||
CMD ["sh", "-c", "php artisan octane:frankenphp --max-requests=250 --port=8000 --host=0.0.0.0 --watch"]
|
||||
|
||||
# Application release stage
|
||||
FROM base AS app-release
|
||||
ENTRYPOINT ["docker-php-entrypoint"]
|
||||
CMD ["sh", "-c", "php artisan octane:frankenphp --max-requests=250 --port=8000 --host=0.0.0.0"]
|
||||
|
||||
# Application stage
|
||||
FROM base AS app
|
||||
|
||||
Submodule packages/core-api updated: 377f05b3f7...a816ed3527
Submodule packages/ember-core updated: 996a9358b1...e2206260e4
Submodule packages/ember-ui updated: b5215c9866...db72d9ee29
Submodule packages/fleetops updated: dfff83b3f1...bba85c0a94
Submodule packages/storefront updated: 4718080d88...52d37d3e3a
170
scripts/docker-install.sh
Executable file
170
scripts/docker-install.sh
Executable file
@@ -0,0 +1,170 @@
|
||||
#!/usr/bin/env bash
|
||||
# scripts/docker-install.sh
|
||||
# Fleetbase Docker installer (dev / prod aware)
|
||||
# --------------------------------------------
|
||||
set -euo pipefail
|
||||
|
||||
###############################################################################
|
||||
# 1. Ask for host (default: localhost)
|
||||
###############################################################################
|
||||
read -rp "Enter host or IP address to bind to [localhost]: " HOST_INPUT
|
||||
HOST=${HOST_INPUT:-localhost}
|
||||
echo "➜ Using host: $HOST"
|
||||
|
||||
###############################################################################
|
||||
# 2. Ask for environment (development | production)
|
||||
###############################################################################
|
||||
while true; do
|
||||
read -rp "Choose environment (development / production) [development]: " ENV_INPUT
|
||||
ENV_INPUT=$(echo "$ENV_INPUT" | tr '[:upper:]' '[:lower:]')
|
||||
case "$ENV_INPUT" in
|
||||
""|d|dev|development) ENVIRONMENT=development; break ;;
|
||||
p|prod|production) ENVIRONMENT=production; break ;;
|
||||
*) echo "Please type either 'development' or 'production'." ;;
|
||||
esac
|
||||
done
|
||||
echo "➜ Environment: $ENVIRONMENT"
|
||||
|
||||
USE_HTTPS=false
|
||||
APP_DEBUG=true
|
||||
SC_SECURE=false
|
||||
if [[ "$ENVIRONMENT" == "production" ]]; then
|
||||
USE_HTTPS=true
|
||||
APP_DEBUG=false
|
||||
SC_SECURE=true
|
||||
fi
|
||||
|
||||
###############################################################################
|
||||
# 3. Determine project root no matter where script is called from
|
||||
###############################################################################
|
||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
PROJECT_ROOT="$( cd "$SCRIPT_DIR/.." && pwd )"
|
||||
cd "$PROJECT_ROOT"
|
||||
|
||||
###############################################################################
|
||||
# 4. Generate a fresh Laravel APP_KEY
|
||||
###############################################################################
|
||||
if ! command -v openssl >/dev/null 2>&1; then
|
||||
echo "✖ openssl is required but not found. Install it and retry." >&2
|
||||
exit 1
|
||||
fi
|
||||
APP_KEY="base64:$(openssl rand -base64 32 | tr -d '\n')"
|
||||
echo "✔ Generated APP_KEY"
|
||||
|
||||
###############################################################################
|
||||
# 5. Ensure docker‑compose.override.yml is present & updated
|
||||
###############################################################################
|
||||
OVERRIDE_FILE="docker-compose.override.yml"
|
||||
|
||||
# url helpers
|
||||
SCHEME_API=$([[ "$USE_HTTPS" == true ]] && echo "https" || echo "http")
|
||||
SCHEME_CONSOLE=$([[ "$USE_HTTPS" == true ]] && echo "https" || echo "http")
|
||||
|
||||
update_override_with_yq() {
|
||||
yq -i "
|
||||
.services.application.environment.APP_KEY = \"$APP_KEY\" |
|
||||
.services.application.environment.CONSOLE_HOST = \"$SCHEME_CONSOLE://$HOST:4200\" |
|
||||
.services.application.environment.ENVIRONMENT = \"$ENVIRONMENT\" |
|
||||
.services.application.environment.APP_DEBUG = \"$APP_DEBUG\"
|
||||
" "$OVERRIDE_FILE"
|
||||
echo "✔ $OVERRIDE_FILE updated (yq)"
|
||||
}
|
||||
|
||||
create_override() {
|
||||
cat > "$OVERRIDE_FILE" <<YML
|
||||
services:
|
||||
application:
|
||||
environment:
|
||||
APP_KEY: "$APP_KEY"
|
||||
CONSOLE_HOST: "$SCHEME_CONSOLE://$HOST:4200"
|
||||
ENVIRONMENT: "$ENVIRONMENT"
|
||||
APP_DEBUG: "$APP_DEBUG"
|
||||
YML
|
||||
echo "✔ $OVERRIDE_FILE written"
|
||||
}
|
||||
|
||||
if [[ -f "$OVERRIDE_FILE" ]]; then
|
||||
if command -v yq >/dev/null 2>&1; then
|
||||
update_override_with_yq
|
||||
else
|
||||
cp "$OVERRIDE_FILE" "${OVERRIDE_FILE}.bak.$(date +%Y%m%d%H%M%S)"
|
||||
echo "ℹ︎ Existing $OVERRIDE_FILE backed up (no yq found — recreating)"
|
||||
create_override
|
||||
fi
|
||||
else
|
||||
create_override
|
||||
fi
|
||||
|
||||
###############################################################################
|
||||
# 6. Write console/fleetbase.config.json atomically
|
||||
###############################################################################
|
||||
CONFIG_DIR="console"
|
||||
CONFIG_PATH="$CONFIG_DIR/fleetbase.config.json"
|
||||
mkdir -p "$CONFIG_DIR"
|
||||
|
||||
cat > "${CONFIG_PATH}.tmp" <<JSON
|
||||
{
|
||||
"API_HOST": "$SCHEME_API://$HOST:8000",
|
||||
"SOCKETCLUSTER_HOST": "$HOST",
|
||||
"SOCKETCLUSTER_PORT": "38000",
|
||||
"SOCKETCLUSTER_SECURE": "$SC_SECURE"
|
||||
}
|
||||
JSON
|
||||
mv -f "${CONFIG_PATH}.tmp" "$CONFIG_PATH"
|
||||
echo "✔ $CONFIG_PATH updated"
|
||||
|
||||
###############################################################################
|
||||
# 7. Start stack, wait for DB, then run deploy
|
||||
###############################################################################
|
||||
echo "⏳ Starting Fleetbase containers..."
|
||||
docker compose up -d
|
||||
|
||||
###############################################################################
|
||||
# 7a. Wait for the database container to be ready
|
||||
###############################################################################
|
||||
DB_SERVICE="database" # ← change if your docker‑compose uses a different name
|
||||
DB_WAIT_TIMEOUT=60 # seconds
|
||||
|
||||
echo "⏳ Waiting for “$DB_SERVICE” to become ready (timeout: ${DB_WAIT_TIMEOUT}s)…"
|
||||
DB_CONTAINER=$(docker compose ps -q "$DB_SERVICE")
|
||||
|
||||
if [ -z "$DB_CONTAINER" ]; then
|
||||
echo "✖ Cannot find a running container for service \"$DB_SERVICE\". Check docker‑compose.yml."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# If the service defines a HEALTHCHECK we can rely on it…
|
||||
if docker inspect -f '{{.State.Health.Status}}' "$DB_CONTAINER" &>/dev/null; then
|
||||
SECONDS=0
|
||||
until [ "$(docker inspect -f '{{.State.Health.Status}}' "$DB_CONTAINER")" = "healthy" ]; do
|
||||
if [ "$SECONDS" -ge "$DB_WAIT_TIMEOUT" ]; then
|
||||
echo "✖ Timed out waiting for the database to become healthy."
|
||||
exit 1
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
sleep 12
|
||||
else
|
||||
# Fallback: use mysqladmin ping (works for MySQL / MariaDB)
|
||||
SECONDS=0
|
||||
until docker compose exec "$DB_SERVICE" sh -c "mysqladmin --silent --wait=1 -uroot -h127.0.0.1 ping" &>/dev/null; do
|
||||
if [ "$SECONDS" -ge "$DB_WAIT_TIMEOUT" ]; then
|
||||
echo "✖ Timed out waiting for the database to accept connections."
|
||||
exit 1
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
fi
|
||||
echo "✔ Database is ready."
|
||||
|
||||
###############################################################################
|
||||
# 7b. Run the deploy script inside the application container
|
||||
###############################################################################
|
||||
echo "⏳ Running deploy script inside the application container..."
|
||||
docker compose exec application bash -c "./deploy.sh"
|
||||
docker compose up -d
|
||||
|
||||
echo
|
||||
echo "🏁 Fleetbase is up!"
|
||||
printf " API → %s://%s:8000\n" "$SCHEME_API" "$HOST"
|
||||
printf " Console → %s://%s:4200\n\n" "$SCHEME_CONSOLE" "$HOST"
|
||||
@@ -1,55 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Find the root directory of your repository
|
||||
root_dir=$(git rev-parse --show-toplevel)
|
||||
|
||||
# Check if the packages directory exists
|
||||
packages_dir="$root_dir/packages"
|
||||
if [ ! -d "$packages_dir" ]; then
|
||||
echo "Packages directory not found."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Initialize flags
|
||||
remove_lock=false
|
||||
remove_modules=false
|
||||
|
||||
for arg in "$@"
|
||||
do
|
||||
case $arg in
|
||||
--remove-lock)
|
||||
remove_lock=true
|
||||
;;
|
||||
--remove-modules)
|
||||
remove_modules=true
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Navigate to the packages directory
|
||||
cd "$packages_dir"
|
||||
|
||||
# Find all child directories and run pnpm install if package.json exists
|
||||
for dir in */; do
|
||||
if [[ -f "${dir}package.json" ]]; then
|
||||
echo "Running pnpm install in $dir"
|
||||
|
||||
# Remove pnpm-lock.yaml if the option is set
|
||||
if [ "$remove_lock" = true ] && [ -f "${dir}pnpm-lock.yaml" ]; then
|
||||
echo "Removing pnpm-lock.yaml in $dir"
|
||||
rm "${dir}pnpm-lock.yaml"
|
||||
fi
|
||||
|
||||
# Remove ./node_modules if the option is set
|
||||
if [ "$remove_modules" = true ] && [ -d "${dir}node_modules" ]; then
|
||||
echo "Removing /node_modules in $dir"
|
||||
rm -rf "${dir}node_modules"
|
||||
fi
|
||||
|
||||
cd "$dir"
|
||||
pnpm install
|
||||
cd "$packages_dir" # Go back to the packages directory
|
||||
else
|
||||
echo "No package.json found in $dir, skipping..."
|
||||
fi
|
||||
done
|
||||
@@ -1,22 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Exit the script as soon as a command fails
|
||||
set -e
|
||||
|
||||
echo "Switching to the main branch..."
|
||||
# git checkout main
|
||||
|
||||
echo "Updating submodules..."
|
||||
git submodule update --init --recursive
|
||||
|
||||
echo "Updating console..."
|
||||
cd console
|
||||
git checkout main
|
||||
git pull
|
||||
cd ..
|
||||
|
||||
echo "Building Docker images..."
|
||||
docker-compose build console
|
||||
docker-compose build application
|
||||
|
||||
echo "Update completed. Run \`docker-compose up -d\` to launch!"
|
||||
Reference in New Issue
Block a user