diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index aac0d59..d0cd7a7 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -2,6 +2,19 @@ name: 'Build and Test' on: [ push ] +env: + GODOT: Godot_v3.3.2-stable + GODOT_VERSION: 3.3.2 + GODOT_RELEASE: stable + + # Caches should be automatically invalidated when versions change, + # but invalidation can be forced by incrementing these numbers. + EMSCRIPTEN_CACHE_VERSION: 1 + EXPORT_TEMPLATE_CACHE_VERSION: 1 + GODOT_CACHE_VERSION: 1 + GODOT_CPP_CACHE_VERSION: 1 + LIBUV_CACHE_VERSION: 1 + jobs: build: name: 'Build' @@ -44,7 +57,7 @@ jobs: cache-name: cache-godot-cpp with: path: addons/godot_xterm/native/thirdparty/godot-cpp - key: godot-cpp-v1-${{ matrix.platform }}-${{ matrix.target }}-${{ matrix.bits }}-${{ env.GODOT_CPP_COMMIT_HASH }} + key: godot-cpp-${{ matrix.platform }}-${{ matrix.target }}-${{ matrix.bits }}-${{ env.GODOT_CPP_COMMIT_HASH }}-v${{ env.GODOT_CPP_CACHE_VERSION }} - name: Get libuv submodule commit hash shell: bash env: @@ -56,7 +69,7 @@ jobs: id: cache-libuv with: path: addons/godot_xterm/native/thirdparty/libuv - key: libuv-cache-v1-${{ matrix.platform }}-${{ matrix.target }}-${{ matrix.bits }}-${{ env.LIBUV_COMMIT_HASH }} + key: libuv-cache-${{ matrix.platform }}-${{ matrix.target }}-${{ matrix.bits }}-${{ env.LIBUV_COMMIT_HASH }}-v${{ env.LIBUV_CACHE_VERSION }} - name: Cache emscripten if: ${{ matrix.platform == 'javascript' }} uses: actions/cache@v2 @@ -64,7 +77,7 @@ jobs: cache-name: cache-emscripten with: path: addons/godot_xterm/native/.emcache - key: emsdk-cache-v1-${{ matrix.target }} + key: emsdk-cache-${{ matrix.target }}-v${{ env.EMSCRIPTEN_CACHE_VERSION }} # Ubuntu-specific steps. - name: Install ubuntu build dependencies @@ -146,98 +159,203 @@ jobs: addons/godot_xterm/native/bin/*.dylib addons/godot_xterm/native/bin/*.dll - test: - name: 'Test' - needs: build - env: - GODOT: Godot_v3.3.2-stable_${{ matrix.platform }} + + # GDNative HTML5 export templates aren't provided so we must build them + export_template: + name: 'Export Template' + runs-on: ubuntu-latest + strategy: + matrix: + target: [ release, debug ] + steps: + - uses: actions/checkout@v2 + with: + submodules: recursive + - name: Get godot submodule commit hash + shell: bash + env: + ACTIONS_ALLOW_UNSECURE_COMMANDS: true + run: | + echo ::set-env name=GODOT_COMMIT_HASH::$(git ls-tree HEAD misc/export_templates/godot -l | cut -d\ -f3) + - name: Cache export template + uses: actions/cache@v2 + id: cache-export-template + env: + cache-name: cache-export-template + with: + path: misc/export_templates/godot/bin + key: godot-${{ env.GODOT_COMMIT_HASH }}-${{ matrix.target }}-v${{ env.EXPORT_TEMPLATE_CACHE_VERSION }} + - name: Build template in docker container + if: steps.cache-export-template.outputs.cache-hit != 'true' + run: cd misc/export_templates && ./build.sh -t ${{ matrix.target }} + - name: Upload export template + uses: actions/upload-artifact@v2 + with: + name: html5-gdnative-export-templates + path: misc/export_templates/godot/bin/webassembly_gdnative_${{matrix.target}}.zip + + + install_godot: + name: 'Install Godot' runs-on: ${{ matrix.os }} strategy: - fail-fast: false matrix: - platform: [ x11.64 ] #, x11.32, win64.exe, win32.exe, osx.universal ] - target: [ release, debug ] + platform: [ x11.64, linux_headless.64, osx.universal ] #, x11.32, win64.exe, win32.exe ] include: - platform: x11.64 os: ubuntu-latest + - platform: linux_headless.64 + os: ubuntu-latest + - platform: osx.universal + os: macos-latest # For Windows platform we need to install mesa-dist-win. - # 32 bit X11 and MacOS also needs special attention. - # So disable all of them for now. + # 32 bit X11 also needs special attention. + # So disable both of them for now. #- platform: x11.32 # os: ubuntu-latest #- platform: win64.exe # os: windows-latest #- platform: win32.exe # os: windows-latest - #- platform: osx.universal - # os: macos-latest steps: - uses: actions/checkout@v2 with: submodules: recursive - - - name: Cache Godot + - name: Cache Godot executable uses: actions/cache@v2 id: cache-godot env: cache-name: cache-godot with: path: godot_executable/ - key: godot-cache-v1-${{ env.GODOT }} - - #- name: Install 32 bit dependencies on 64 bit Ubuntu - # if: ${{ matrix.platform == 'x11.32' }} - # run: sudo apt-get install -y libxcursor-dev:i386 - - name: Install Ubuntu dependencies - if: ${{ matrix.os == 'ubuntu-latest' }} - run: sudo apt-get install -y pulseaudio - + key: godot-cache-${{ env.GODOT }}_${{ matrix.platform }}-v${{ env.GODOT_CACHE_VERSION }} - name: Download Godot uses: suisei-cn/actions-download-file@v1 if: steps.cache-godot.outputs.cache-hit != 'true' with: - url: https://downloads.tuxfamily.org/godotengine/3.3.2/${{ env.GODOT }}.zip + url: https://downloads.tuxfamily.org/godotengine/${{ env.GODOT_VERSION }}/${{ env.GODOT }}_${{ matrix.platform }}.zip target: godot_executable/ - name: Extract Godot shell: bash if: steps.cache-godot.outputs.cache-hit != 'true' run: | cd godot_executable - unzip ${{ env.GODOT }}.zip + unzip ${{ env.GODOT }}_${{ matrix.platform }}.zip - name: Symlink Godot - if: ${{ matrix.platform == 'osx.universal' }} - run: ln -s godot_executable/Godot.app/Contents/MacOS/Godot godot_executable/${{ env.GODOT }} + if: steps.cache-godot.outputs.cache-hit != 'true' && matrix.platform == 'osx.universal' + run: ln -s Godot.app/Contents/MacOS/Godot godot_executable/${{ env.GODOT }}_${{ matrix.platform }} + + test: + name: 'Test' + needs: [ install_godot, build, export_template ] + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + platform: [ x11.64, osx.universal ] #, x11.32, win64.exe, win32.exe ] + target: [ release, debug ] + include: + - platform: x11.64 + os: ubuntu-latest + - platform: osx.universal + os: macos-latest + # For Windows platform we need to install mesa-dist-win. + # 32 bit X11 also needs special attention. + # So disable both of them for now. + #- platform: x11.32 + # os: ubuntu-latest + #- platform: win64.exe + # os: windows-latest + #- platform: win32.exe + # os: windows-latest + steps: + - uses: actions/checkout@v2 + with: + submodules: recursive + - name: Cache godot executable + uses: actions/cache@v2 + id: cache-godot + env: + cache-name: cache-godot + with: + path: godot_executable/ + key: godot-cache-${{ env.GODOT }}_${{ matrix.platform }}-v${{ env.GODOT_CACHE_VERSION }} + - name: Install Ubuntu dependencies + if: ${{ matrix.os == 'ubuntu-latest' }} + run: sudo apt-get install -y pulseaudio - name: Install binary build artifacts uses: actions/download-artifact@v2 with: name: libgodot-xterm-${{ matrix.target }} path: addons/godot_xterm/native/bin - - name: Install plugins uses: GabrielBB/xvfb-action@v1 with: - run: godot_executable/${{ env.GODOT }} --no-window -s plug.gd install + run: godot_executable/${{ env.GODOT }}_${{ matrix.platform }} --no-window -s plug.gd install - # Use export to force re-import of files, even though it will fail if we - # don't have any export templates installed it should still import the - # files first. + # HACK: Use export to force re-import of files. + # See the proposal to support command line import https://github.com/godotengine/godot-proposals/issues/1362 + - name: Install html5 export templates + uses: actions/download-artifact@v2 + with: + name: html5-gdnative-export-templates + path: misc/export_templates/godot/bin + - name: Create export directory + run: mkdir -p docs/demo - name: Import files uses: GabrielBB/xvfb-action@v1 with: - run: ./godot_executable/${{ env.GODOT }} --export HTML5 - continue-on-error: true + run: ./godot_executable/${{ env.GODOT }}_${{ matrix.platform }} --export HTML5 - name: Run tests uses: GabrielBB/xvfb-action@v1 with: - run: ./godot_executable/${{ env.GODOT }} --no-window -s addons/gut/gut_cmdln.gd -gconfig=test/.gutconfig.ci.json - + run: ./godot_executable/${{ env.GODOT }}_${{ matrix.platform }} --no-window -s addons/gut/gut_cmdln.gd -gconfig=test/.gutconfig.ci.json - name: Run unix tests if: ${{ matrix.platform != 'win64.exe' && matrix.platform != 'win32.exe' }} uses: GabrielBB/xvfb-action@v1 with: - run: ./godot_executable/${{ env.GODOT }} --no-window -s addons/gut/gut_cmdln.gd -gconfig=test/.gutconfig.unix.json + run: ./godot_executable/${{ env.GODOT }}_${{ matrix.platform }} --no-window -s addons/gut/gut_cmdln.gd -gconfig=test/.gutconfig.unix.json + + + html5_export: + name: 'HTML5 Export' + needs: [ install_godot, build, export_template ] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + submodules: recursive + - name: Cache godot executable + uses: actions/cache@v2 + id: cache-godot + env: + cache-name: cache-godot + with: + path: godot_executable/ + key: godot-cache-${{ env.GODOT }}_linux_headless.64-v${{ env.GODOT_CACHE_VERSION }} + - name: Install binary build artifacts + uses: actions/download-artifact@v2 + with: + name: libgodot-xterm-release + path: addons/godot_xterm/native/bin + - name: Install html5 export templates + uses: actions/download-artifact@v2 + with: + name: html5-gdnative-export-templates + path: misc/export_templates/godot/bin + - name: Create export directory + run: mkdir -p docs/demo + - name: Export html5 + run: ./godot_executable/${{ env.GODOT }}_linux_headless.64 --export HTML5 + # FIXME: HTML5 Exports not properly exporting .cast files. + # So skip upload for now. + #- name: Upload export + # uses: actions/upload-artifact@v2 + # with: + # name: html5-demo + # path: docs/demo # Git archive should only include addons/godot_xterm directory. @@ -274,3 +392,4 @@ jobs: echo "Expected directory (addons/godot_xterm) not found." exit 1 fi + diff --git a/export_presets.cfg b/export_presets.cfg index 18951d3..d05541e 100644 --- a/export_presets.cfg +++ b/export_presets.cfg @@ -5,7 +5,7 @@ platform="HTML5" runnable=true custom_features="" export_filter="all_resources" -include_filter="addons/godot_xterm/themes/fonts/hack/hack_regular-3.003.ttf" +include_filter="*.cast, addons/godot_xterm/themes/fonts/hack/hack_regular-3.003.ttf" exclude_filter="misc/*, **/thirdparty/*, **/unifont/*, **/nerd_fonts/*, **/noto_color_emoji/*, *bold*.ttf, *italic*.ttf" export_path="docs/demo/index.html" script_export_mode=1 diff --git a/misc/export_templates/build.sh b/misc/export_templates/build.sh index d96d724..2bf7f70 100755 --- a/misc/export_templates/build.sh +++ b/misc/export_templates/build.sh @@ -1,6 +1,25 @@ -#!/bin/sh set -e +# Parse args. +args=$@ +while [[ $# -gt 0 ]]; do + key="$1" + case $key in + -t|--target) + target="$2" + shift + shift + ;; + *) + echo "Usage: ./build.sh [-t|--target ]"; + exit 128 + shift + ;; + esac +done +# Set defaults. +target=${target:-debug} + # Get the absolute path to the directory this script is in. EXPORT_TEMPLATES_DIR="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" @@ -13,11 +32,10 @@ fi # Use Docker to build HTML5 GDNative export templates. UID_GID="0:0" docker-compose build javascript +UID_GID="$(id -u):$(id -g)" docker-compose run -e TARGET=$target javascript -# Debug -UID_GID="$(id -u):$(id -g)" docker-compose run -e TARGET=debug javascript -mv godot/bin/godot.javascript.debug.gdnative.zip godot/bin/webassembly_gdnative_debug.zip - -### Release -UID_GID="$(id -u):$(id -g)" docker-compose run -e TARGET=release javascript -mv godot/bin/godot.javascript.opt.gdnative.zip godot/bin/webassembly_gdnative_release.zip +if [ "$target" == "debug" ]; then + mv godot/bin/godot.javascript.debug.gdnative.zip godot/bin/webassembly_gdnative_debug.zip +else + mv godot/bin/godot.javascript.opt.gdnative.zip godot/bin/webassembly_gdnative_release.zip +fi diff --git a/project.godot b/project.godot index 764b145..a9ba2c3 100644 --- a/project.godot +++ b/project.godot @@ -13,37 +13,11 @@ _global_script_classes=[ { "class": "GDXterm", "language": "GDScript", "path": "res://addons/godot_xterm/namespace.gd" -}, { -"base": "Reference", -"class": "WAT", -"language": "GDScript", -"path": "res://addons/WAT/namespace.gd" -}, { -"base": "Node", -"class": "WATTest", -"language": "GDScript", -"path": "res://addons/WAT/test/test.gd" } ] _global_script_class_icons={ -"GDXterm": "", -"WAT": "", -"WATTest": "" +"GDXterm": "" } -[WAT] - -Test_Directory="res://test" -Results_Directory="res://test" -Test_Metadata_Directory="res://test" -Tags=PoolStringArray( "unit", "integration", "unix", "windows" ) -Window_Size=Vector2( 1280, 720 ) -Minimize_Window_When_Running_Tests=false -Port=6008 -Run_All_Tests=Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":0,"unicode":0,"echo":false,"script":null) - -Auto_Refresh_Tests=false -Display=8 - [application] config/name="Godot Xterm" diff --git a/test/platform/unix/unix.test.gd b/test/platform/unix/unix.test.gd index 18de93c..6bdf094 100644 --- a/test/platform/unix/unix.test.gd +++ b/test/platform/unix/unix.test.gd @@ -1,6 +1,14 @@ extends "res://addons/gut/test.gd" var pty: GDXterm.PTYUnix +var helper: Helper + + +func before_all(): + if OS.get_name() == "OSX": + helper = MacOSHelper.new() + else: + helper = LinuxHelper.new() func before_each(): @@ -19,16 +27,16 @@ func test_open_succeeds(): func test_open_creates_a_new_pty(): - var num_pts = Helper._get_pts().size() + var num_pts = helper._get_pts().size() pty.open() - var new_num_pts = Helper._get_pts().size() + var new_num_pts = helper._get_pts().size() assert_eq(new_num_pts, num_pts + 1) func test_open_pty_has_correct_name(): - var original_pts = Helper._get_pts() + var original_pts = helper._get_pts() var result = pty.open() - var new_pts = Helper._get_pts() + var new_pts = helper._get_pts() for pt in original_pts: new_pts.erase(pt) assert_eq(result[1].pty, new_pts[0]) @@ -38,30 +46,15 @@ func test_open_pty_has_correct_win_size(): var cols = 7684 var rows = 9314 var result = pty.open(cols, rows) - var winsize = Helper._get_winsize(result[1].master) + var winsize = helper._get_winsize(result[1].master) assert_eq(winsize.cols, cols) assert_eq(winsize.rows, rows) class Helper: static func _get_pts() -> Array: - var dir := Directory.new() - - var pty_dir = "/dev/pts" if OS.get_name() == "X11" else "/dev" - var pty_prefix = "tty" if OS.get_name() == "OSX" else "" - - if dir.open(pty_dir) != OK or dir.list_dir_begin(true, true) != OK: - assert(false, "Could not open /dev/pts.") - - var pts := [] - var file_name: String = dir.get_next() - - while file_name != "": - if file_name.trim_prefix(pty_prefix).is_valid_integer(): - pts.append("/dev/pts/%s" % file_name) - file_name = dir.get_next() - - return pts + assert(false, "Abstract method") + return [] static func _get_winsize(fd: int) -> Dictionary: var output = [] @@ -88,3 +81,32 @@ class Helper: var size = str2var("Vector2" + output[0].strip_edges()) return {rows = int(size.x), cols = int(size.y)} + + +class LinuxHelper: + extends Helper + static func _get_pts() -> Array: + var dir := Directory.new() + + if dir.open("/dev/pts") != OK or dir.list_dir_begin(true, true) != OK: + assert(false, "Could not open /dev/pts.") + + var pts := [] + var file_name: String = dir.get_next() + + while file_name != "": + if file_name.is_valid_integer(): + pts.append("/dev/pts/%s" % file_name) + file_name = dir.get_next() + + return pts + + +class MacOSHelper: + extends Helper + static func _get_pts() -> Array: + # TODO: Implement for macOS. + # On macOS there is no /dev/pts directory, rather new ptys are created + # under /dev/ttysXYZ. + assert(false, "Not implemented") + return []