Skip to content

waiting for testing #91

waiting for testing

waiting for testing #91

Workflow file for this run

name: Build Flex Executables
on:
push:
branches: [ main ]
jobs:
build:
name: Build Flex Executable (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
include:
- os: ubuntu-latest
output_name: flex-linux
asset_name: flex-linux
- os: windows-latest
output_name: flex
asset_name: flex.exe
- os: macos-latest
output_name: flex-macos
asset_name: flex-macos
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.10'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install ply==3.11
pip install pyinstaller
pip install requests>=2.0.0
pip install ipaddress
- name: Build with PyInstaller for Linux/macOS
if: matrix.os != 'windows-latest'
run: |
cd src
# Ensure data directories exist to avoid warnings
mkdir -p flex_AI/data/Compiler_AI
mkdir -p flex_AI/data/ammar_data
mkdir -p hooks
# Create sample files if they don't exist to ensure the directories are included
if [ ! -f "flex_AI/data/Compiler_AI/data.txt" ]; then
echo "# Flex AI compiler examples will be included in future releases" > flex_AI/data/Compiler_AI/data.txt
fi
if [ ! -f "flex_AI/data/ammar_data/total.txt" ]; then
echo "# Flex AI usage examples will be included in future releases" > flex_AI/data/ammar_data/total.txt
fi
# Create PyInstaller hook files
cat > hooks/hook-encodings.py << 'EOF'
"""
PyInstaller hook for encodings module
This hook ensures that the idna encoding is properly included in the build,
which is required for proper handling of URLs and internationalized domain names.
"""
# Explicitly include idna encoding to prevent the "unknown encoding: idna" error
hiddenimports = ['encodings.idna', 'encodings.ascii', 'encodings.utf_8', 'encodings.latin_1', 'encodings.cp1252']
EOF
cat > hooks/hook-flex_AI.py << 'EOF'
"""
PyInstaller hook for flex_AI module
This hook ensures that the data directories for flex_AI are properly included in the build,
and that all necessary dependencies are imported.
"""
from PyInstaller.utils.hooks import collect_data_files
# Include all data files from the flex_AI module
datas = collect_data_files('flex_AI')
# Ensure these modules are included
hiddenimports = [
'encodings.idna',
'ipaddress',
'requests',
'json',
'urllib3',
'chardet',
'certifi'
]
EOF
pyinstaller --onefile --clean --name=${{ matrix.output_name }} \
--add-data "flex_compiler:flex_compiler" \
--add-data "flex_interpreter:flex_interpreter" \
--add-data "flex_parser:flex_parser" \
--add-data "flex_tokenizer:flex_tokenizer" \
--add-data "flex_AI:flex_AI" \
--additional-hooks-dir=hooks \
--hidden-import="encodings.idna" \
--hidden-import="ipaddress" \
main.py
- name: Build with PyInstaller for Windows
if: matrix.os == 'windows-latest'
shell: cmd
run: |
cd src
REM Ensure data directories exist to avoid warnings
mkdir flex_AI\data\Compiler_AI 2>nul
mkdir flex_AI\data\ammar_data 2>nul
mkdir hooks 2>nul
REM Create sample files if they don't exist to ensure the directories are included
if not exist "flex_AI\data\Compiler_AI\data.txt" (
echo # Flex AI compiler examples will be included in future releases > flex_AI\data\Compiler_AI\data.txt
)
if not exist "flex_AI\data\ammar_data\total.txt" (
echo # Flex AI usage examples will be included in future releases > flex_AI\data\ammar_data\total.txt
)
REM Create PyInstaller hook files - using single file redirects for Windows
echo from PyInstaller.utils.hooks import collect_data_files > hooks\hook-flex_AI.py
echo. >> hooks\hook-flex_AI.py
echo # Include all data files from the flex_AI module >> hooks\hook-flex_AI.py
echo datas = collect_data_files('flex_AI') >> hooks\hook-flex_AI.py
echo. >> hooks\hook-flex_AI.py
echo # Ensure these modules are included >> hooks\hook-flex_AI.py
echo hiddenimports = [ >> hooks\hook-flex_AI.py
echo 'encodings.idna', >> hooks\hook-flex_AI.py
echo 'ipaddress', >> hooks\hook-flex_AI.py
echo 'requests', >> hooks\hook-flex_AI.py
echo 'json', >> hooks\hook-flex_AI.py
echo 'urllib3', >> hooks\hook-flex_AI.py
echo 'chardet', >> hooks\hook-flex_AI.py
echo 'certifi' >> hooks\hook-flex_AI.py
echo ] >> hooks\hook-flex_AI.py
echo # PyInstaller hook for encodings > hooks\hook-encodings.py
echo # This hook ensures that the idna encoding is properly included in the build >> hooks\hook-encodings.py
echo. >> hooks\hook-encodings.py
echo # Explicitly include idna encoding to prevent the "unknown encoding: idna" error >> hooks\hook-encodings.py
echo hiddenimports = ['encodings.idna', 'encodings.ascii', 'encodings.utf_8', 'encodings.latin_1', 'encodings.cp1252'] >> hooks\hook-encodings.py
pyinstaller --onefile --clean --name=${{ matrix.output_name }} ^
--add-data "flex_compiler;flex_compiler" ^
--add-data "flex_interpreter;flex_interpreter" ^
--add-data "flex_parser;flex_parser" ^
--add-data "flex_tokenizer;flex_tokenizer" ^
--add-data "flex_AI;flex_AI" ^
--additional-hooks-dir=hooks ^
--hidden-import="encodings.idna" ^
--hidden-import="ipaddress" ^
main.py
# Create Windows Installer
- name: Create Windows Installer
if: matrix.os == 'windows-latest'
shell: powershell
run: |
# Install NSIS installer system
choco install nsis -y
# Create installer script with single $ for NSIS variables
# PowerShell won't interpolate these since they're in a here-string
$installerScript = @'
!include "MUI2.nsh"
Name "Flex Language Interpreter"
OutFile "flex-installer.exe"
Unicode True
!define MUI_ICON "src\flex_compiler\icon.ico"
!define MUI_UNICON "src\flex_compiler\icon.ico"
!define MUI_WELCOMEPAGE_TITLE "Flex Language Interpreter Setup"
!define MUI_WELCOMEPAGE_TEXT "This will install the Flex Language Interpreter on your computer."
!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_PAGE_FINISH
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
!insertmacro MUI_LANGUAGE "English"
InstallDir "$PROGRAMFILES\Flex"
Section "Install"
SetOutPath "$INSTDIR"
File "src\dist\flex.exe"
# Create batch file to invoke the executable
FileOpen $0 "$INSTDIR\flex.bat" w
FileWrite $0 "@echo off$\r$\n"
FileWrite $0 "$INSTDIR\flex.exe %*$\r$\n"
FileClose $0
# Add to PATH using standard documented syntax
System::Call 'Kernel32::SetEnvironmentVariable(t "PATH", t "$INSTDIR;${ENV PATH}")'
# Create uninstaller
WriteUninstaller "$INSTDIR\uninstall.exe"
# Create Start Menu shortcut
CreateDirectory "$SMPROGRAMS\Flex"
CreateShortcut "$SMPROGRAMS\Flex\Flex.lnk" "$INSTDIR\flex.exe"
CreateShortcut "$SMPROGRAMS\Flex\Uninstall.lnk" "$INSTDIR\uninstall.exe"
# Create registry entries with explicit backslashes where needed
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Flex" "DisplayName" "Flex Language Interpreter"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Flex" "UninstallString" "$INSTDIR\uninstall.exe"
SectionEnd
Section "Uninstall"
Delete "$INSTDIR\flex.exe"
Delete "$INSTDIR\flex.bat"
Delete "$INSTDIR\uninstall.exe"
# Remove Start Menu shortcuts
Delete "$SMPROGRAMS\Flex\Flex.lnk"
Delete "$SMPROGRAMS\Flex\Uninstall.lnk"
RMDir "$SMPROGRAMS\Flex"
# Remove registry entries
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Flex"
# Remove installation directory
RMDir "$INSTDIR"
SectionEnd
'@
# Create installer script file - no replacements needed since we're using single quotes
Set-Content -Path "installer.nsi" -Value $installerScript -Encoding UTF8
# Debug output for script issues
Write-Host "--- Generated NSIS script ---"
Get-Content "installer.nsi" | ForEach-Object { Write-Host $_ }
Write-Host "----------------------------"
# Create icon if it doesn't exist
New-Item -Path "src\flex_compiler" -ItemType Directory -Force
if (-not (Test-Path "src\flex_compiler\icon.ico")) {
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/microsoft/vscode/main/resources/win32/code.ico" -OutFile "src\flex_compiler\icon.ico"
}
# Check if NSIS is properly installed
if (Test-Path 'C:\Program Files (x86)\NSIS\makensis.exe') {
Write-Host "NSIS found at expected location"
} else {
Write-Host "NSIS not found at expected location - searching for it"
$nsisPath = Get-Command makensis.exe -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Source
if ($nsisPath) {
Write-Host "Found NSIS at: $nsisPath"
} else {
Write-Host "NSIS not found in PATH - this will likely fail"
}
}
# First try with less verbose output
Write-Host "Compiling NSIS script (normal verbosity)..."
$compileResult = & 'C:\Program Files (x86)\NSIS\makensis.exe' installer.nsi
$exitCode = $LASTEXITCODE
if ($exitCode -ne 0) {
Write-Host "Compilation failed with exit code $exitCode. Retrying with verbose output..."
# Retry with verbose output to get more detailed error information
& 'C:\Program Files (x86)\NSIS\makensis.exe' /V4 installer.nsi
} else {
Write-Host "Compilation successful!"
}
# Create macOS Package
- name: Create macOS Package
if: matrix.os == 'macos-latest'
run: |
# Create package structure
mkdir -p pkg_root/usr/local/bin
mkdir -p pkg_root/usr/local/share/flex
# Copy executable
cp src/dist/flex-macos pkg_root/usr/local/bin/flex
chmod +x pkg_root/usr/local/bin/flex
# Create scripts
mkdir -p scripts
# Preinstall script
cat > scripts/preinstall << EOF
#!/bin/bash
# Remove previous version if exists
if [ -f /usr/local/bin/flex ]; then
rm -f /usr/local/bin/flex
fi
exit 0
EOF
# Postinstall script
cat > scripts/postinstall << EOF
#!/bin/bash
# Set permissions
chmod 755 /usr/local/bin/flex
exit 0
EOF
# Make scripts executable
chmod +x scripts/preinstall scripts/postinstall
# Use direct pkgbuild without component plist
pkgbuild --root pkg_root \
--identifier com.flex.interpreter \
--version 1.0 \
--install-location / \
--scripts scripts \
flex-component.pkg
# Create distribution file
cat > distribution.xml << EOF
<?xml version="1.0" encoding="utf-8"?>
<installer-gui-script minSpecVersion="1">
<title>Flex Language Interpreter</title>
<welcome file="welcome.html"/>
<license file="license.html"/>
<conclusion file="conclusion.html"/>
<domains enable_localSystem="true"/>
<options customize="allow" allow-external-scripts="no"/>
<choices-outline>
<line choice="default">
<line choice="com.flex.interpreter"/>
</line>
</choices-outline>
<choice id="default"/>
<choice id="com.flex.interpreter" visible="false">
<pkg-ref id="com.flex.interpreter"/>
</choice>
<pkg-ref id="com.flex.interpreter" version="1.0" onConclusion="none">flex-component.pkg</pkg-ref>
</installer-gui-script>
EOF
# Create HTML files
mkdir -p resources
# Welcome file
cat > resources/welcome.html << EOF
<html>
<body>
<h1>Flex Language Interpreter</h1>
<p>This package will install the Flex Language Interpreter on your Mac.</p>
</body>
</html>
EOF
# License file
cat > resources/license.html << EOF
<html>
<body>
<h1>License Agreement</h1>
<p>Copyright (c) 2025 Flex Team</p>
<p>Permission is hereby granted, free of charge, to any person obtaining a copy of this software...</p>
</body>
</html>
EOF
# Conclusion file
cat > resources/conclusion.html << EOF
<html>
<body>
<h1>Installation Complete</h1>
<p>The Flex Language Interpreter has been installed in /usr/local/bin/flex</p>
<p>You can now run it from Terminal by typing "flex"</p>
</body>
</html>
EOF
# Build the final package
productbuild --distribution distribution.xml \
--resources resources \
--package-path . \
flex-installer.pkg
# Linux installation script
- name: Create Linux Installer
if: matrix.os == 'ubuntu-latest'
run: |
mkdir -p installer
cp src/dist/flex-linux installer/flex
# Create installation script
cat > installer/install.sh << 'EOF'
#!/bin/bash
# Flex Language Interpreter Installer
echo "Flex Language Interpreter Installer"
echo "==================================="
# Check if running as root
if [ "$EUID" -ne 0 ]; then
echo "Please run as root (use sudo)"
exit 1
fi
# Default installation directory
DEFAULT_INSTALL_DIR="/usr/local/bin"
# Ask for installation directory
read -p "Installation directory [$DEFAULT_INSTALL_DIR]: " INSTALL_DIR
INSTALL_DIR=${INSTALL_DIR:-$DEFAULT_INSTALL_DIR}
# Create directory if it doesn't exist
mkdir -p "$INSTALL_DIR"
# Copy executable
cp "$(dirname "$0")/flex" "$INSTALL_DIR/flex"
chmod +x "$INSTALL_DIR/flex"
echo "Flex has been installed to $INSTALL_DIR/flex"
echo "You can now run it by typing 'flex'"
EOF
chmod +x installer/install.sh
# Create tarball
tar -czvf flex-linux-installer.tar.gz -C installer .
- name: Set Executable Permissions (Linux/macOS)
if: matrix.os != 'windows-latest'
run: |
cd src/dist
chmod +x ${{ matrix.output_name }}
ls -la ${{ matrix.output_name }}
- name: Test Executable (Linux/macOS)
if: matrix.os != 'windows-latest'
run: |
cd src/dist
./${{ matrix.output_name }} --version
- name: Test Executable (Windows)
if: matrix.os == 'windows-latest'
run: |
cd src\dist
.\${{ matrix.output_name }}.exe --version
- name: Upload Artifacts
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.asset_name }}
path: src/dist/${{ matrix.output_name }}*
retention-days: 7
# Upload Windows installer as artifact
- name: Upload Windows Installer Artifact
if: matrix.os == 'windows-latest'
uses: actions/upload-artifact@v4
with:
name: flex-windows-installer
path: flex-installer.exe
retention-days: 7
# Upload macOS installer as artifact
- name: Upload macOS Installer Artifact
if: matrix.os == 'macos-latest'
uses: actions/upload-artifact@v4
with:
name: flex-macos-installer
path: flex-installer.pkg
retention-days: 7
# Upload Linux installer as artifact
- name: Upload Linux Installer Artifact
if: matrix.os == 'ubuntu-latest'
uses: actions/upload-artifact@v4
with:
name: flex-linux-installer
path: flex-linux-installer.tar.gz
retention-days: 7
release:
name: Create Release
needs: [build]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Download All Artifacts
uses: actions/download-artifact@v4
- name: Display structure of downloaded files
run: ls -R
- name: Set Permissions for Downloaded Artifacts
run: |
chmod +x ./flex-linux/flex-linux || true
chmod +x ./flex-macos/flex-macos || true
ls -la ./flex-linux/flex-linux ./flex-macos/flex-macos || true
- name: Prepare release artifacts
run: |
mkdir -p release
# Debug the file structure
echo "Directory structure after downloading:"
find . -type f -name "flex-*" | sort
# Copy with platform-specific names for clarity
cp ./flex-linux/flex-linux release/flex-linux || true
cp ./flex.exe/flex.exe release/flex.exe || true
cp ./flex-macos/flex-macos release/flex-macos || true
# Copy installers
cp ./flex-windows-installer/flex-installer.exe release/flex-windows-installer.exe || true
cp ./flex-macos-installer/flex-installer.pkg release/flex-macos-installer.pkg || true
cp ./flex-linux-installer/flex-linux-installer.tar.gz release/flex-linux-installer.tar.gz || true
# Make sure executables have correct permissions
chmod +x release/* || true
echo "Release directory contents:"
ls -la release/
- name: Checkout repository for tag information
uses: actions/checkout@v4
with:
fetch-depth: 0
path: repo
- name: Get next version number
id: calc_version
working-directory: repo
run: |
# Check if there are any existing tags that match vX format
if git tag -l "v[0-9]*" | grep -q .; then
# Get highest version number from existing tags
latest_version=$(git tag -l "v[0-9]*" | sort -V | tail -n1 | sed 's/v//')
next_version=$((latest_version + 1))
else
# No existing version tags, start at 1
next_version=1
fi
echo "Next version will be: v$next_version"
echo "next_version=$next_version" >> $GITHUB_OUTPUT
# First create a tag without creating a release
- name: Create Git Tag
working-directory: repo
run: |
git config --local user.email "hassansonson2002@gmail.com"
git config --local user.name "hassan220022"
git tag -a v${{ steps.calc_version.outputs.next_version }} -m "Release v${{ steps.calc_version.outputs.next_version }}"
git push origin v${{ steps.calc_version.outputs.next_version }}
# Use the official GitHub Release API instead of the JavaScript approach
- name: Create Release
uses: softprops/action-gh-release@v1
with:
tag_name: v${{ steps.calc_version.outputs.next_version }}
name: Release v${{ steps.calc_version.outputs.next_version }}
body: |
## Flex Language Interpreter v${{ steps.calc_version.outputs.next_version }}
This release contains both standalone executables and installers for all major platforms.
### Installers (Recommended)
These installers will guide you through the setup process and let you choose where to install Flex:
- **Windows**: Download `flex-windows-installer.exe`
- **macOS**: Download `flex-macos-installer.pkg`
- **Linux**: Download `flex-linux-installer.tar.gz` (extract and run `sudo ./install.sh`)
### Standalone Executables
For advanced users who prefer manual installation:
- **Linux**: Download `flex-linux`
- **Windows**: Download `flex.exe`
- **macOS**: Download `flex-macos`
#### Manual Installation (Standalone Executables)
##### Linux/macOS:
1. Download the appropriate executable for your platform
2. Make it executable: `chmod +x flex-*`
3. Move to a directory in your PATH: `sudo mv flex-* /usr/local/bin/flex`
4. Run it: `flex yourfile.flex`
##### Windows:
1. Download `flex.exe`
2. Option 1 - Add to PATH:
- Move `flex.exe` to a folder (e.g., `C:\Flex`)
- Add this folder to your PATH environment variable
- Create a batch file named `flex.bat` in the same folder with this content:
```
@echo off
flex.exe %*
```
- Now you can run `flex` from any command prompt
3. Option 2 - Direct use:
- Run by typing the full path: `C:\path\to\flex.exe yourfile.flex`
files: |
release/flex-linux
release/flex.exe
release/flex-macos
release/flex-windows-installer.exe
release/flex-macos-installer.pkg
release/flex-linux-installer.tar.gz
generate_release_notes: false