-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #37 from j-bryan/package_build
Create easily installable packages of FORCE tools
- Loading branch information
Showing
34 changed files
with
1,914 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
# FORCE One-Step Installer Creation | ||
FORCE one-step installers are created using the `cx_Freeze` python package after creating a python environment using either `venv` or `conda`. | ||
A computer with the same operating system and architecture as the target operating system must be used to generate an installer, i.e. use a Windows machine to generate a Windows installer, a Mac (Intel) to generate a Mac installer, etc. | ||
Note that installers generated with Apple computers with M-series chips will not be backwards compatible with Intel-based Apple computers. | ||
|
||
Windows and macOS are the only operating systems currently supported. | ||
Linux users are encouraged to use pip-installed or source built versions of the RAVEN, HERON, and TEAL software packages. | ||
|
||
## 1. Build FORCE executables | ||
Create a conda environment `force_build_310`, install the RAVEN, HERON, and TEAL pip packages, and build the FORCE executables using the script `build_force.sh`. | ||
The path to the conda executable must be provided using the `--conda-defs` argument. | ||
```console | ||
./build_force.sh --conda-defs <path to conda directory>/etc/profile.d/conda.sh | ||
``` | ||
|
||
## 2. Add IPOPT to build directory (Windows only) | ||
Download the IPOPT Windows binary: | ||
https://github.com/coin-or/Ipopt/releases | ||
|
||
Extract the downloaded zip directory and copy its contents to the raven_install directory, ensuring to replace the version numbers of IPOPT as needed. | ||
```console | ||
cd force_install | ||
unzip ~/Downloads/Ipopt-3.14.12-win64-msvs2019-md.zip | ||
mv Ipopt-3.14.12-win64-msvs2019-md local | ||
cd .. | ||
``` | ||
|
||
## 3. Copy examples and build/copy the RAVEN, HERON, and TEAL documentation | ||
Adding examples and documentation to the one-step installer requires having the source installation present on the build machine, with the `raven_libraries` conda environment already created. | ||
```console | ||
conda activate raven_libraries | ||
./copy_examples.sh --raven-dir /path/to/raven --heron-dir /path/to/HERON | ||
cp -R examples force_install/examples | ||
./make_docs.sh --raven-dir /path/to/raven --heron-dir /path/to/HERON --teal-dir /path/to/TEAL | ||
cp -R docs force_install/docs | ||
``` | ||
When running the `make_docs.sh` script, the optional `--no-build` flag may be added if the desired documentation PDFs have already been built, and you do not wish to rebuild the documents. | ||
If using the `--no-build` option, there is no need to have the `raven_libraries` active. | ||
```console | ||
./make_docs.sh --no-build --raven-dir /path/to/raven --heron-dir /path/to/HERON --teal-dir /path/to/TEAL | ||
cp -R docs force_install/docs | ||
``` | ||
|
||
## 4. Get NEAMS Workbench installer | ||
The installers for the NEAMS Workbench software can be found here: | ||
https://code.ornl.gov/neams-workbench/downloads/-/tree/5.4.1?ref_type=heads | ||
|
||
Download `Workbench-5.4.1.exe` for Windows and `Workbench-5.4.1.dmg` for macOS. | ||
Place this file in the `force_install` directory on Windows or the current directory on macOS. | ||
|
||
Windows: | ||
```console | ||
cp ~/Downloads/Workbench-5.4.1.exe force_install | ||
``` | ||
|
||
macOS: | ||
```console | ||
cp ~/Downloads/Workbench-5.4.1.dmg . | ||
``` | ||
|
||
## 5. Create the installer | ||
### Windows | ||
The Windows installer is created using Inno Setup. | ||
Run the `inno_package.iss` script from the Inno Setup application. | ||
The resulting .exe installer file can be found in the `inno_output` directory. | ||
|
||
### macOS | ||
Run the macOS build script | ||
```console | ||
./build_mac_app.sh | ||
``` | ||
The disk image `FORCE.dmg` contains applications for both FORCE and Workbench. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
#!/bin/bash | ||
|
||
# Have users point to the location of their conda installation so we can properly activate the | ||
# conda environment that is being made. Use the "--conda-defs" option to specify this path. | ||
while [[ $# -gt 0 ]]; do | ||
key="$1" | ||
case $key in | ||
--conda-defs) | ||
CONDA_DEFS="$2" | ||
shift | ||
shift | ||
source $CONDA_DEFS | ||
;; | ||
*) | ||
echo "Unknown option: $1" | ||
exit 1 | ||
;; | ||
esac | ||
done | ||
|
||
# Establish conda environment | ||
conda create -n force_build_310 python=3.10 -y | ||
conda activate force_build_310 | ||
|
||
# Check that the conda environment is active. If not, exit. | ||
if [[ $CONDA_DEFAULT_ENV != "force_build_310" ]]; then | ||
echo "Conda environment not activated. Maybe the path to the conda installation is incorrect?" | ||
echo "Provided conda path: $CONDA_DEFS" | ||
exit 1 | ||
fi | ||
|
||
pip install cx_Freeze | ||
pip install raven-framework heron-ravenframework teal-ravenframework | ||
# If on macOS, use conda to install ipopt | ||
if [[ "$OSTYPE" == "darwin"* ]]; then | ||
# Note: The PyPI version of ipopt is not maintained and is severl major version | ||
# behind the conda-forge distribution. | ||
conda install -c conda-forge ipopt -y | ||
fi | ||
|
||
# Build the FORCE executables | ||
python setup.py install_exe --install-dir force_install |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
#!/bin/bash | ||
|
||
# Set up the FORCE application bundle | ||
# We'll set up the app so that some FORCE launcher script is the main executable, and the RAVEN, | ||
# HERON, and TEAL executables are in the Resources directory. | ||
# Build the initial app from the force_launcher.scpt AppleScript | ||
osacompile -o FORCE.app force_launcher.scpt | ||
# Now copy over the force_install directory contents to the application's Resources directory | ||
cp -Rp force_install/* FORCE.app/Contents/Resources/ | ||
# Overwrite the app's icon with the FORCE icon | ||
cp icons/FORCE.icns FORCE.app/Contents/Resources/applet.icns | ||
|
||
# Create a new disk image | ||
hdiutil create -size 5g -fs HFS+ -volname "FORCE" -o force_build.dmg | ||
|
||
# Mount the new disk image | ||
hdiutil attach force_build.dmg -mountpoint /Volumes/FORCE | ||
|
||
# Mount the existing .dmg file file Workbench | ||
hdiutil attach Workbench-5.4.1.dmg -mountpoint /Volumes/Workbench | ||
|
||
# Add the workshop tests and data directories to FORCE so that Workbench's autocomplete works for workshop examples | ||
mkdir FORCE.app/Contents/Resources/tests | ||
mkdir FORCE.app/Contents/Resources/examples | ||
cp -Rp examples/workshop FORCE.app/Contents/Resources/tests/ | ||
cp -Rp examples/data FORCE.app/Contents/Resources/examples/ | ||
|
||
# Move the FORCE app to the disk image | ||
cp -Rp FORCE.app /Volumes/FORCE/ | ||
cp -Rp /Volumes/Workbench/Workbench-5.4.1.app /Volumes/FORCE/ | ||
|
||
# Move the "examples" and "docs" directories from the FORCE app bundle to the top level of the disk | ||
# image to make them more accessible. | ||
cp -Rp examples /Volumes/FORCE/ | ||
cp -Rp docs /Volumes/FORCE/ | ||
|
||
# Move the "examples" and "docs" directories from the FORCE app bundle to the top level of the disk | ||
# image to make them more accessible. | ||
if [ -d FORCE.app/Contents/Resources/examples ]; then | ||
mv /Volumes/FORCE/FORCE.app/Contents/Resources/examples /Volumes/FORCE/ | ||
else | ||
echo "WARNING: No examples directory found in FORCE.app bundle" | ||
fi | ||
if [ -d FORCE.app/Contents/Resources/docs ]; then | ||
mv FORCE.app/Contents/Resources/docs /Volumes/FORCE/ | ||
else | ||
echo "WARNING: No docs directory found in FORCE.app bundle" | ||
fi | ||
|
||
# Add .son file to Workbench app to provide a default HERON configuration | ||
cp default.apps.son /Volumes/FORCE/Workbench-5.4.1.app/Contents/ | ||
|
||
# Create a symlink to the Applications directory in the app's build directory | ||
ln -s /Applications /Volumes/FORCE/Applications | ||
|
||
# Unmount all the disk images | ||
hdiutil detach /Volumes/Workbench | ||
hdiutil detach /Volumes/FORCE | ||
|
||
# Convert to read-only compressed image | ||
if [ -f FORCE.dmg ]; then | ||
rm FORCE.dmg | ||
fi | ||
hdiutil convert force_build.dmg -format UDZO -o FORCE.dmg | ||
|
||
# Remove the temporary disk image | ||
rm force_build.dmg |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
#!/bin/bash | ||
# Copies examples from the test directories of RAVEN and HERON to provide examples for users using | ||
# the standalone install version of FORCE. | ||
|
||
# Get the RAVEN and HERON locations as arguments "--raven-dir" and "--heron-dir" | ||
# The destination directory is "examples" in the current directory but may be changed with the | ||
# "--dest" argument. | ||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) | ||
EXAMPLES_DIR="$SCRIPT_DIR/examples" | ||
|
||
while [[ $# -gt 0 ]] | ||
do | ||
key="$1" | ||
case $key in | ||
--raven-dir) | ||
RAVEN_DIR="$2" | ||
shift | ||
shift | ||
;; | ||
--heron-dir) | ||
HERON_DIR="$2" | ||
shift | ||
shift | ||
;; | ||
--dest) | ||
EXAMPLES_DIR="$2" | ||
shift | ||
shift | ||
;; | ||
*) | ||
echo "Unknown option: $1" | ||
exit 1 | ||
;; | ||
esac | ||
done | ||
|
||
# The examples we want to copy are the RAVEN user_guide tests, the HERON workshop tests, and the | ||
# HERON data directory which contains time series models for those workshop tests. | ||
EXAMPLES=($RAVEN_DIR/tests/framework/user_guide $HERON_DIR/data $HERON_DIR/tests/workshop) | ||
mkdir -p $EXAMPLES_DIR | ||
|
||
for ex in ${EXAMPLES[@]}; do | ||
cp -R "$ex" "$EXAMPLES_DIR" | ||
done | ||
|
||
# Clean up the copied examples, removing files and directories created when running the tests. | ||
DIRS_TO_REMOVE=("__pycache__" "gold" "*_o") | ||
for dirname in ${DIRS_TO_REMOVE[@]}; do | ||
find $EXAMPLES_DIR -type d -name $dirname -exec rm -r {} \; 2>/dev/null | ||
done | ||
FILES_TO_REMOVE=("tests" "moped_input.xml" "outer.xml" "inner.xml" "cash.xml" "*.lib" "write_inner.py" "*.heron" "*.heron.xml") | ||
for filename in ${FILES_TO_REMOVE[@]}; do | ||
find $EXAMPLES_DIR -name $filename -exec rm {} \; 2>/dev/null | ||
done | ||
|
||
# If building on Mac, replace the %HERON_DATA% magic string with a relative path to the data | ||
# directory. This is a little hacky but the %HERON_DATA% magic string doesn't look everywhere for | ||
# the data directory. This is only an issue for the Mac standalone install. HERON will find the | ||
# data directory correctly on Windows. | ||
# DATA_DIR=$EXAMPLES_DIR/data | ||
# if [[ "$OSTYPE" == "darwin"* ]]; then | ||
# # Find all XML files recursively from the current directory | ||
# find $EXAMPLES_DIR/workshop -type f -name "*.xml" | while read -r file; do | ||
# # Check if the file contains the %HERON_DATA% magic string. If not, skip this file. | ||
# grep -q "%HERON_DATA%" "$file" || continue | ||
|
||
# # Get the directory of the current XML file | ||
# FILE_DIR=$(dirname "$file") | ||
|
||
# # Calculate the relative path from the XML file directory to the data directory | ||
# echo "FILE_DIR: $FILE_DIR DATA_DIR: $DATA_DIR" | ||
# RELATIVE_PATH=$(python -c "import os.path; print(os.path.relpath('$DATA_DIR', '$FILE_DIR'))") | ||
# # RELATIVE_PATH=$(realpath -s --relative-to="$FILE_DIR" "$DATA_DIR") | ||
# echo $RELATIVE_PATH | ||
|
||
# # Use sed to replace %HERON_DATA% with the relative path to the data directory | ||
# sed -i '' "s|%HERON_DATA%|$RELATIVE_PATH|g" "$file" | ||
# done | ||
# fi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
applications { | ||
HERON { | ||
configurations { | ||
default { | ||
options { | ||
shared { | ||
Executable="/Applications/FORCE.app/Contents/Resources/heron" | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
set options to {"HERON", "RAVEN", "TEAL", "Quit"} | ||
|
||
set selectedOption to choose from list options with title "FORCE Launcher" with prompt "Which FORCE application would you like to use?" default items {"HERON"} | ||
|
||
if selectedOption is false then | ||
display dialog "No option selected. Exiting..." buttons {"OK"} default button "OK" | ||
else | ||
set selectedOption to item 1 of selectedOption | ||
if selectedOption is "HERON" then | ||
set filePathName to quoted form of "/Applications/FORCE.app/Contents/Resources/heron" | ||
else if selectedOption is "RAVEN" then | ||
set filePathName to quoted form of "/Applications/FORCE.app/Contents/Resources/raven_framework" | ||
else if selectedOption is "TEAL" then | ||
set filePathName to quoted form of "/Applications/FORCE.app/Contents/Resources/teal" | ||
else if selectedOption is "Quit" then | ||
display dialog "Exiting..." buttons {"OK"} default button "OK" | ||
return | ||
end if | ||
-- do shell script filePathName | ||
try | ||
do shell script "test -e " & filePathName | ||
-- If the test passes, the file exists and we proceed with the script | ||
do shell script filePathName | ||
on error | ||
-- If the file doesn't exist, display an error message | ||
display dialog "The file at " & filePathName & " does not exist." buttons {"OK"} default button "OK" | ||
end try | ||
end if |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
#!/usr/bin/env python | ||
# Copyright 2017 Battelle Energy Alliance, LLC | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
import re | ||
import sys | ||
from HERON.src.main import main | ||
from ui import run_from_gui | ||
from utils import add_local_bin_to_path | ||
|
||
|
||
if __name__ == '__main__': | ||
# Adds the "local/bin" directory to the system path in order to find ipopt and other executables | ||
add_local_bin_to_path() | ||
|
||
# Parse the command line arguments | ||
import argparse | ||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) | ||
parser = argparse.ArgumentParser(description='HERON') | ||
parser.add_argument('-w', action='store_true', default=False, required=False, help='Run in the GUI') | ||
parser.add_argument('--definition', action="store_true", dest="definition", help='HERON input file definition compatible with the NEAMS Workbench') | ||
parser.add_argument('input', nargs='?', help='HERON input file') | ||
args, unknown = parser.parse_known_args() | ||
|
||
# if the input file is not an xml file, assume it's an unknown argument | ||
if args.input and not args.input.endswith('.xml'): | ||
unknown.insert(0, args.input) | ||
args.input = None | ||
# remove the -w argument from sys.argv so it doesn't interfere with HERON's argument parsing | ||
if args.w: | ||
sys.argv.remove('-w') | ||
|
||
if (args.w or not args.input) and not args.definition: # if asked to or if no file is passed, run the GUI | ||
run_from_gui(main) | ||
else: | ||
main() |
Oops, something went wrong.