Skip to content

Add Windows setup script #403

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Mar 31, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 41 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ This repository contains the source for LMMS's website, live at <https://lmms.io

## How to test the website locally

### Linux

1. Fork the repository [here](https://github.com/LMMS/lmms.io/fork)
2. Clone the forked repository.

Expand All @@ -14,41 +16,55 @@ git clone https://github.com/<your-username>/lmms.io.git
3. Get Composer

This project uses [Composer](http://getcomposer.org) for dependency management. You'll have to fetch those dependencies using Composer. For this, you must have Composer installed on your system. For quickly installing Composer locally on *nix, run:

Install PHP 8.2 and the required components.\
These commands are for Linux. It may be different from how it is installed on other OSes.

```bash
sudo add-apt-repository ppa:ondrej/php
sudo apt install curl php8.2 php8.2-xml php8.2-gd php8.2-intl php-symfony
```

```bash
cd lmms.io
curl -sS https://getcomposer.org/installer | php
```

For installing Composer locally on Windows (i.e. Wamp), run:

```bash
cd lmms.io
php -r "eval('?>'.file_get_contents('https://getcomposer.org/installer'));"
curl -sS https://getcomposer.org/installer | php
```

> **Note:**
> You need to add `php.exe` to the Windows PATH, usually located in `c:\wamp\bin\php\phpx.y.z`
> For instructions for other OSes or for installing globally, visit Composer's [Getting Started](https://getcomposer.org/doc/00-intro.md) document.

1. Fetch dependencies using Composer.

After downloading Composer locally using the instructions above, fetch the dependencies by running the command below.

```bash
php composer.phar install
```

You'll have to run this command every time the dependencies in `composer.json` change.


### Windows

A convenient setup script is provided in `dev/windows/setup.ps1`. You just need to provide the path of where you've installed PHP, and it will setup PHP, install Composer, and install the project's dependencies on its own.

If you skipped automatic `.ini` validation or modification, there are some changes you'll need to make to your configuration file manually:

1. Locate `php.ini-development` or `php.ini` in the folder where you've installed/extracted the PHP release. This folder should also be where `php.exe` resides
* If you have the `php.ini-development` file, remove the `-development` suffix from the file extension, the resulting file name should just be `php.ini`
* If you would like to just edit your existing `php.ini`, leave it be.
2. Edit the file, and uncomment these lines:
1. `;extension_dir = "ext"`
2. `;extension=gd`
3. `;extension=intl`
4. `;extension=openssl`
5. `;extension=pdo_mysql`
3. Save your edits, then re-run the setup script.

Not only does this allow the automatic script to execute, but also enable the local development server to function at all.

### macOS

> **Note**:
> For macOS, some dependencies must be [installed manually](https://superuser.com/a/1359317/443147).

Expand All @@ -57,25 +73,25 @@ You'll have to run this command every time the dependencies in `composer.json` c
```bash
php -S localhost:8000 -t ./public/
```

You can then open <http://localhost:8000/> in a browser.

1. Optionally, configure the local `apache` and `nginx` instances.

With Apache:

```xml
<Directory /home/user/lmms.io/public/>
# add fallback resource to Apache config
FallbackResource /index.php
</Directory>
<Directory /home/user/lmms.io/public/>
# add fallback resource to Apache config
FallbackResource /index.php
</Directory>
```

With Nginx:

```nginx
# go to our front controller if none of them exists
location / {
try_files $uri $uri/ /index.php?$args;
}
# go to our front controller if none of them exists
location / {
try_files $uri $uri/ /index.php?$args;
}
```
163 changes: 163 additions & 0 deletions dev/windows/setup.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
param (
[ValidateScript({ Test-Path $_ })]
[string] $phpDir
)

# check if php exists in Path, then set it as full PHP dir
if (-not [string]::IsNullOrEmpty((Get-Command php).Source)) {
$phpDir = Split-Path (Get-Command php).Source
$fullPhpDir = (Get-Command php).Source
}

# if not, then check if the phpDir arg exists
elseif ([string]::IsNullOrEmpty($phpDir)) {
$phpDir = Read-Host "Enter the path of your PHP installation (e.g. 'C:\Program Files\php', 'D:\php', 'C:\wamp\bin\php')"

# check if given path exists
if (-not (Test-Path $phpDir)) {
throw "The directory '$phpDir' does not exist. Did you point to the exact file instead of the containing folder?"
}

$fullPhpDir = Join-Path $phpDir "php.exe"

# check if php.exe is there
if (-not (Test-Path $fullPhpDir)) {
throw "'php.exe' was not found in '$phpDir'. Was it installed correctly?"
}
}

Write-Host -ForegroundColor Gray "[setup] Using $fullPhpDir as PHP runner"

$rootDir = Split-Path -Path (Split-Path -Path $PSScriptRoot)

function Validate-Ini {
Write-Host "[setup] Validating .ini file"

# ungodly regexes of setting lines that are commented
# bulletproof except for the most egregious
$iniSettingsRegex = @(
";\s*\s*extension_dir\s*=\s*(`"ext`")"
";\s*\s*extension\s*=\s*(gd)\b"
";\s*\s*extension\s*=\s*(intl)\b"
";\s*\s*extension\s*=\s*(openssl)\b"
";\s*\s*extension\s*=\s*(pdo_mysql)\b"
";\s*\s*extension\s*=\s*(zip)\b"
)

# will change to false if the validation fails
$iniValid = $true

# cover edge case if `include_path` is defined
$iniIncludePathExists = $false

$iniFilePath = Join-Path $phpDir "php.ini"
$iniFileDevPath = Join-Path $phpDir "php.ini-development"

# if the .ini doesn't exist, but the dev template does
if (-not (Test-Path $iniFilePath) -and (Test-Path $iniFileDevPath)) {
$confirm = Read-Host "You do not have a 'php.ini' file, but you have the 'php.ini-development' file. Would you like the script to enable the development .ini? Saying [n] will exit the script [y/n]"

if ($confirm -match "y") {
Write-Host "[setup] Renaming 'php.ini-development' to 'php.ini'"
Rename-Item -Path $iniFileDevPath -NewName "php.ini"
}
else {
throw "Exiting since the script must use 'php.ini'. You must rename/create the file yourself"
}
}
# if none was found, then we're inbetween a rock and a hard place
elseif (-not (Test-Path $iniFilePath) -and -not (Test-Path $iniFileDevPath)) {
throw "'php.ini' and 'php.ini-development' cannot be found. Was PHP installed correctly?"
}

$iniFile = Get-Content $iniFilePath

# actual file validation starts here
foreach ($line in $iniFile) {
if ($line -match [regex]::new("^(include_path)", "Multiline")) {
Write-Host -ForegroundColor Yellow "[setup] You have 'include_path' defined in your settings file. This will disrupt the development server. You can temporarily comment out the 'include_path' setting so that PHP can use the relative working directory path to infer locations. The script will not modify this setting as this may break other applications depending on this setting"
$iniIncludePathExists = $true
}
foreach ($settingRegex in $iniSettingsRegex) {
if ($line -match $settingRegex) {
$iniValid = $false
}
}
}

# .ini is invalid, prompt to fix
if ($iniValid -eq $false) {
$confirm = Read-Host "[setup] Your .ini file is not suitable for running the local test environment. Would you like the script to modify the file and enable the relevant settings? The script will only modify the settings needed for the project to run and leave others unchanged, you can view the list of settings that needs to be enabled in the root README [y/n]"

if ($confirm -match "y") {
Write-Host "[setup] Modifying and writing settings"

# read-write each line, and uncomment lines that match the regex
$iniFileNew = ""
foreach ($iniLine in $iniFile) {
$isSettingLine = $false
foreach ($settingRegex in $iniSettingsRegex) {
if ($iniLine -match $settingRegex) {
$isSettingLine = $true
$iniFileNew += $iniLine.Replace(";", "") + "`n"
break
}
}
if (-not $isSettingLine) {
$iniFileNew += $iniLine + "`n"
}
}

Write-Host -ForegroundColor Green "[setup] Settings file modified"

# the modified file hasn't been written yet, write it now, per-line
Clear-Content -Path $iniFilePath
foreach ($line in $iniFileNew) {
Add-Content -Path $iniFilePath -Value $line
}

Write-Host -ForegroundColor Green "[setup] Succesfully validated and written '.ini' settings, continuing setup"
}
# take a chance that the install process will continue to run fine, probably not
else {
Write-Host -ForegroundColor Yellow "[setup] Skipping .ini file modification. You must enable the relevant settings by yourself. Refer to the README for instructions on how to enable the settings manually."
Write-Host -ForegroundColor Red "[setup] There's a chance that the script will error after this"
}
}
else {
Write-Host -ForegroundColor Green "[setup] All settings are valid, continuing setup"
}
}

Validate-Ini


function Setup-Composer {
# shift to root dir
Set-Location $rootDir

# download composer
Write-Host "[setup] Dowloading composer's installer"
$composerInstallerUrl = "https://getcomposer.org/installer"
$composerInstallerPath = Join-Path $rootDir "composer-setup.php"
Invoke-WebRequest -Uri $composerInstallerUrl -OutFile $composerInstallerPath

# check if composer's installer exists
if (-Not (Test-Path $composerInstallerPath)) {
throw "Failed to download Composer installer"
}

Write-Host "[setup] Installing composer"
Start-Process -FilePath $fullPhpDir -ArgumentList $composerInstallerPath -Wait -NoNewWindow

Write-Host "[setup] Getting dependencies"
Start-Process -FilePath $fullPhpDir -ArgumentList "composer.phar install" -Wait -NoNewWindow

# cleanup composer's installer
Write-Host "[setup] Cleaning up composer's installer"
Remove-Item $composerInstallerPath
}

Setup-Composer

Write-Host -ForegroundColor Green "[setup] Setup complete! Run 'php -S localhost:8000 -t ./public/' to start the local dev server"