From 4b95a8b5d3da7faaf77d389a217e6adfb3d4cfe8 Mon Sep 17 00:00:00 2001 From: Frank Halasz Date: Sat, 18 Feb 2023 06:19:57 -0800 Subject: [PATCH] Windows installer and medley script for running Medley in Docker on Windows (#1077) * Update docker file build to use new deb linux installers; move Dockefile to .github/workflows since its really only useable from the buildDocker.yml workflow * Fix typo in dockerfile location * remove extraneous " in >>GITHUB_ENV statements * Fix handling of TARGETPLATFORM in Dockerfile * Trying with just one platform * Fix issues with missing man-db in docker build workflow; added man-db to depends in deb builds for linux * Sicthed docker from tightvnc to tigervnc to match oio. This getting the apt package name right. * Going back to single platform to debug this thing * Trying with just arm64 * Removing arm/v7 from docker images. Takes too long to build and just wastes our github actions minutes. This is assuming its a never used feature since docker is not big on raspberry pis and their ilk. * Fix typo in control-linux; update build_deb so that files in /usr/local installed by deb are owned by root; add ubuntu user and nano in docker file for dbebugging; when in draft only create for x86_64 platform * Fix typo in buildDocker.yml * Add sudo to docker image; in docker image ensure that all /usr/local/interlisp files are owned by root * Add securityTypes none to docker entrypoint * Updated docker base to Ubuntu 22.10 to get fixed xrdp; add xrdp to the docker image; updated user permission in docker image; * In Dockerfile make xrdp install noninteractive * Update medley.sh scripts to handle docker case * Fix a couple of typos * BuildDcoker: added pulling latest draft release (if any) when this is a draft docker build; removed checkout of medley code cause its not used * BuildDocker: added medley checkout backin - turns pout its needed by a bunch of actions even though I dont really think they use it * BuildDocker: moved download assets to use gh instaed of a marketplace action becauase that action could not handle draft releases. * Tweaking medley.sh and associated tweaks to work Windows via wsl medley and docker * adding first pass at powershell script for windows docker and wsl * Tuning how Xvnc, medley, and vncviewer handle the various ways of exiting - eg logout vs closing viewer window. * Tuning vncviewer launch to make sure that tty works as expected when medley.sh runs in background * Minor typo fixes and added extra check to use of /run/shm in medley_vnc.sh * Added SSH_KEY secret to buildReleaseIncDocker workflow * Gertting the add SSH_KEY secret into orkflows right this time, hopefully * Adding TERM env variable and setting USER to medley in docker image * Debugging medley.ps1 and adding a couple of arguments * Typo in Dockerfile medley * Synchronizing flag processing and usage for medley.ps1 and medley.sh; refactored medley_args.sh and medley_usage.sh code. * Adding first pass at windows installer * Adding first pass an inno setup script for Windows installation * Update buildLoadup workflow and downloads page for windows installer * Fix typo in buildLoadup * BuildLoadup make sure windows runner uses powershell * Another typo in buildLoadup * Another typo in buildLoadup; damn those double quotes * Updating handling of windows installer in buildLoadup, added vncviewer to medley.iss install * Unknown syntax error in buildLoadup * Another damn typo from double quotes * buildLoadup: fixed loadup job outputs * buidLoadup: fixed bug with COMBINED_RELEASE_TAG; fixed Upload script in windows job to be compatible with actions.script v6. * buidLoadup: upload win installer adapted to find draft releases as well as full releases * BuildLoadup: fixing up javascript in actions in windows job to use / instead of \ in pathname * BuildLoadup: changing win installer update to same action used for other release assets * Fix windows installer file name; in BuildLoadup move update downl;oad page to the Windows runner because uploading the window-installer changes the release download url, so updating the downloads page must be done after the windows installer upload.; General buildLoadup cleanup * Run md2html to update downloads page * Fix typo in build_deb.sh * Removing some leftover crud in medley_usage.sh * Fixing up windows installer a bit, mostly cosmetic * Adding support for WSL1; mostly forcing --vnc and changing how to find open ports and displays since WSL1 networking is different tha WSL2 * Update manual page for new Windows Medley script * First pass done for man page that incorporates new Windows medley script. Add Xvnc wait before calling run-medley in case of docker to prevent occasonal missing X windows server error. * Change buildLoadup to update man page to a draft if this is a draft run. --- .github/workflows/Dockerfile_medley | 78 ++++ .github/workflows/buildDocker.yml | 109 +++-- .github/workflows/buildLoadup.yml | 186 ++++++-- .github/workflows/buildReleaseInclDocker.yml | 5 +- .github/workflows/testLogin.yml | 23 - Dockerfile | 55 --- docs/man-page/man_medley.html | 37 +- docs/man-page/medley.1 | 48 +- docs/man-page/medley.1.gz | Bin 2674 -> 3144 bytes docs/man-page/medley.1.md | 50 ++- installers/deb/build_deb.sh | 21 +- installers/deb/control-linux | 4 +- .../downloads_page/medley_downloads.html | 51 ++- installers/downloads_page/medley_downloads.md | 40 +- installers/win/.gitignore | 3 + installers/win/Medley.ico | Bin 0 -> 159126 bytes installers/win/editpath/EditPath.iss | 165 +++++++ installers/win/editpath/EditPath.md | 118 +++++ installers/win/editpath/README.TXT | 3 + installers/win/editpath/i386/EditPath.exe | Bin 0 -> 116224 bytes installers/win/editpath/x86_64/EditPath.exe | Bin 0 -> 134144 bytes installers/win/makeflix.iss | 128 ++++++ installers/win/medley.iss | 65 +++ installers/win/medley_logo.bmp | Bin 0 -> 54054 bytes installers/win/medley_logo.png | Bin 0 -> 10272 bytes installers/win/medley_logo_small.bmp | Bin 0 -> 13254 bytes scripts/medley/medley.cmd | 3 + scripts/medley/medley.ps1 | 410 ++++++++++++++++++ scripts/medley/medley.sh | 44 +- scripts/medley/medley_args.sh | 172 ++++---- scripts/medley/medley_usage.sh | 70 ++- scripts/medley/medley_vnc.sh | 258 +++++++---- 32 files changed, 1721 insertions(+), 425 deletions(-) create mode 100644 .github/workflows/Dockerfile_medley delete mode 100644 .github/workflows/testLogin.yml delete mode 100644 Dockerfile create mode 100644 installers/win/.gitignore create mode 100644 installers/win/Medley.ico create mode 100644 installers/win/editpath/EditPath.iss create mode 100644 installers/win/editpath/EditPath.md create mode 100644 installers/win/editpath/README.TXT create mode 100644 installers/win/editpath/i386/EditPath.exe create mode 100644 installers/win/editpath/x86_64/EditPath.exe create mode 100644 installers/win/makeflix.iss create mode 100644 installers/win/medley.iss create mode 100644 installers/win/medley_logo.bmp create mode 100644 installers/win/medley_logo.png create mode 100644 installers/win/medley_logo_small.bmp create mode 100644 scripts/medley/medley.cmd create mode 100755 scripts/medley/medley.ps1 mode change 100644 => 100755 scripts/medley/medley_args.sh diff --git a/.github/workflows/Dockerfile_medley b/.github/workflows/Dockerfile_medley new file mode 100644 index 00000000..6a26d93a --- /dev/null +++ b/.github/workflows/Dockerfile_medley @@ -0,0 +1,78 @@ +#******************************************************************************* +# +# Dockerfile to build Medley image from latest Maiko image +# plus latest release tars from github +# +# Copyright 2022-2023 by Interlisp.org +# +# ****************************************************************************** + +FROM ubuntu:22.10 +ARG TARGETPLATFORM + +# Handle ARGs, ENV variables, and LABELs +ARG BUILD_DATE=unknown +ARG MEDLEY_RELEASE=unknown +ARG MAIKO_RELEASE=unknown +ARG REPO_OWNER=Interlisp +LABEL name="Medley" +LABEL description="The Medley Interlisp environment" +LABEL url="https://github.com/${REPO_OWNER}/medley" +LABEL build-date=$BUILD_DATE +LABEL medley_release=$MEDLEY_RELEASE +LABEL maiko_release=$MAIKO_RELEASE + +ENV MEDLEY_DOCKER_BUILD_DATE=$BUILD_DATE +ENV MEDLEY_RELEASE=$MEDLEY_RELEASE +ENV MAIKO_RELEASE=$MAIKO_RELEASE + +ENV LANG=C.UTF-8 + +# Copy over the release deb files +ADD ./*.deb /tmp + +# Install Medley/Maiko and add tightvnc server and xclip to the image +RUN apt-get update \ + && apt-get install -y apt-utils \ + && apt-get install -y tigervnc-standalone-server \ + && apt-get install -y xclip \ + && apt-get install -y man-db \ + && apt-get install -y nano \ + && apt-get install -y sudo \ + && p=$(echo "${TARGETPLATFORM}" | sed -e "s#linux/##") \ + && p=$( \ + if [ "$p" = "amd64" ]; \ + then echo "x86_64"; \ + elif [ "$p" = "arm64" ]; \ + then echo "aarch64"; \ + elif [ "$p" = "arm/v7" ]; \ + then echo "armv7l"; \ + else \ + echo "x86_64"; \ + fi \ + ) \ + && deb="medley-full-${MEDLEY_RELEASE#medley-}" \ + && deb=${deb}_${MAIKO_RELEASE#maiko-}-linux-${p}.deb \ + && apt-get install -y /tmp/${deb} \ + && chown --recursive root:root /usr/local/interlisp \ + && (if [ -n "$(which unminimize)" ]; then (yes | unminimize); fi) + +# "Finalize" image +EXPOSE 5900 +RUN adduser --gecos "" medley \ + && adduser --gecos "" ubuntu \ + && adduser medley sudo \ + && adduser ubuntu sudo \ + && (echo 'medley:yeldem' | chpasswd ) \ + && (echo 'ubuntu:utnubu' | chpasswd ) \ + && echo "medley ALL=(ALL) NOPASSWD:ALL" >>/etc/sudoers \ + && echo "ubuntu ALL=(ALL) NOPASSWD:ALL" >>/etc/sudoers \ + && mkdir -p /home/medley/il \ + && chown medley:medley /home/medley/il + +ENV TERM=xterm +USER medley +WORKDIR /home/medley +#ENTRYPOINT USER=medley Xvnc -SecurityTypes none -geometry 1280x720 :0 & DISPLAY=:0 medley --full -g 1280x720 +ENTRYPOINT /bin/bash + diff --git a/.github/workflows/buildDocker.yml b/.github/workflows/buildDocker.yml index 7046ef75..c9171daa 100644 --- a/.github/workflows/buildDocker.yml +++ b/.github/workflows/buildDocker.yml @@ -136,60 +136,60 @@ jobs: # Checkout latest commit - name: Checkout Medley uses: actions/checkout@v3 + + # Find latest release (draft or normal) + # and download its assets + - name: Download linux debs from latest (draft) release + run: | + tag="" + if [ "${{ needs.inputs.outputs.draft }}" = "true" ]; + then + tag=$(gh release list | grep Draft | head -n 1 | awk '{ print $3 }') + fi + if [ -z "${tag}" ]; + then + tag=$(gh release list | grep Latest | head -n 1 | awk '{ print $3 }') + fi + mkdir -p release_debs + gh release download ${tag} -D release_debs -p '*-linux-*.deb' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + # Get Maiko and Medley release information from name of deb files + # just downloaded from the Medley latest release + - name: Get info about Miako and Medley releases + id: release_info + run: | + regex="^[^0-9]*\([^_]*\)_\([^-]*-[^-]*\)-\([^-]*\)-\([^.]*\).*\$" + ls -1 release_debs | head -n 1 > debname.tmp + medley_release="medley-$(sed -e "s/${regex}/\1/" debname.tmp)" + maiko_release="maiko-$(sed -e "s/${regex}/\2/" debname.tmp)" + rm -f debname.tmp + echo "MEDLEY_RELEASE=${medley_release}" >> ${GITHUB_ENV} + echo "MAIKO_RELEASE=${maiko_release}" >> ${GITHUB_ENV} # Set repo env variables - name: Set repo/docker env variables id: repo_env run: | - REPO_NAME=${GITHUB_REPOSITORY#*/} - echo "REPO_NAME=${REPO_NAME}" >> ${GITHUB_ENV} - echo "repo_name=${REPO_NAME}" >> ${GITHUB_OUTPUT} - DOCKER_NAMESPACE=$(echo "${{ github.repository_owner }}" | tr '[:upper:]' '[:lower:]') - echo "DOCKER_NAMESPACE=${DOCKER_NAMESPACE}" >> ${GITHUB_ENV} - echo "docker_namespace=${DOCKER_NAMESPACE}" >> ${GITHUB_OUTPUT} - - # Get tag of latest Medley release. - - name: Get Medley Release Information - id: release_info - uses: abatilo/release-info-action@v1.3.2 - with: - owner: ${{ github.repository_owner }} - repo: medley - - # Get asset tars from latest Medley release - - name: Download Release Assets - uses: robinraju/release-downloader@v1.7 - with: - repository: ${{ github.repository_owner }}/medley - token: ${{ secrets.GITHUB_TOKEN }} - latest: true - fileName: "*" - out-file-path: "release_tars" - - # Get Maiko release information about latest Maiko Docker Image - - name: Get info from latest Maiko image - id: maiko_setup - run: | - docker pull ${DOCKER_NAMESPACE}/maiko:latest - MAIKO_RELEASE=$(docker run --entrypoint /bin/bash ${DOCKER_NAMESPACE}/maiko:latest -c "echo \${MAIKO_RELEASE}") - echo "MAIKO_RELEASE=${MAIKO_RELEASE}" >> ${GITHUB_ENV} - echo "maiko_release=${MAIKO_RELEASE}" >> ${GITHUB_OUTPUT} - - # Setup environment variables - - name: Setup Environment Variables - id: setup_env - run: | - RELEASE_TAG=${{ steps.release_info.outputs.latest_tag }} - DOCKER_IMAGE=${DOCKER_NAMESPACE}/${REPO_NAME} + repo_name="${GITHUB_REPOSITORY#*/}" + docker_namespace="$(echo "${{ github.repository_owner }}" | tr '[:upper:]' '[:lower:]')" + docker_image="${docker_namespace}/${repo_name}" if [ "${{ needs.inputs.outputs.draft }}" = "false" ]; - then DOCKER_TAGS="${DOCKER_IMAGE}:latest,${DOCKER_IMAGE}:${RELEASE_TAG#*-}_${MAIKO_RELEASE#*-}" - else DOCKER_TAGS="${DOCKER_IMAGE}:draft" + then + docker_tags="${docker_image}:latest,${docker_image}:${MEDLEY_RELEASE#*-}_${MAIKO_RELEASE#*-}" + platforms="linux/amd64,linux/arm64" + else + docker_tags="${docker_image}:draft" + platforms="linux/amd64" fi - echo "docker_tags=${DOCKER_TAGS}" >> ${GITHUB_OUTPUT} - echo "docker_image=${DOCKER_IMAGE}" >> ${GITHUB_OUTPUT} - echo "build_time=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> ${GITHUB_OUTPUT} - echo "release_tag=${RELEASE_TAG}" >> ${GITHUB_OUTPUT} - echo "release_tag=${RELEASE_TAG}" >> ${GITHUB_ENV} + echo "REPO_NAME=${repo_name}" >> ${GITHUB_ENV} + echo "DOCKER_NAMESPACE=${docker_namespace}" >> ${GITHUB_ENV} + echo "DOCKER_IMAGE=${docker_image}" >> ${GITHUB_ENV} + echo "DOCKER_TAGS=${docker_tags}" >> ${GITHUB_ENV} + echo "BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> ${GITHUB_ENV} + echo "PLATFORMS=${platforms}" >> ${GITHUB_ENV} + #linux/amd64,linux/arm64,linux/arm/v7 # Setup the Docker Machine Emulation environment. - name: Set up QEMU @@ -217,17 +217,16 @@ jobs: with: builder: ${{ steps.buildx.outputs.name }} build-args: | - BUILD_DATE=${{ steps.setup_env.outputs.build_time }} - RELEASE_TAG=${{ steps.setup_env.outputs.release_tag }} - MAIKO_RELEASE=${{ steps.setup_env.outputs.maiko_release }} - DOCKER_NAMESPACE=${{ steps.repo_env.outputs.docker_namespace }} + BUILD_DATE=${{ env.BUILD_DATE }} + MEDLEY_RELEASE=${{ env.MEDLEY_RELEASE }} + MAIKO_RELEASE=${{ env.MAIKO_RELEASE }} REPO_OWNER=${{ github.repository_owner }} - context: ./release_tars - file: ./Dockerfile - platforms: linux/amd64,linux/arm64,linux/arm/v7 + context: ./release_debs + file: ./.github/workflows/Dockerfile_medley + platforms: ${{ env.PLATFORMS }} # Push the result to DockerHub push: true - tags: ${{ steps.setup_env.outputs.docker_tags }} + tags: ${{ env.DOCKER_TAGS }} ###################################################################################### diff --git a/.github/workflows/buildLoadup.yml b/.github/workflows/buildLoadup.yml index 28810135..efae66d6 100644 --- a/.github/workflows/buildLoadup.yml +++ b/.github/workflows/buildLoadup.yml @@ -49,6 +49,9 @@ on: required: false type: string default: 'false' + secrets: + OIO_SSH_KEY: + required: true defaults: run: @@ -113,6 +116,8 @@ jobs: ###################################################################################### + + # # Do the loadup # @@ -120,6 +125,12 @@ jobs: runs-on: ubuntu-latest + outputs: + combined_release_tag: ${{ steps.job_outputs.outputs.COMBINED_RELEASE_TAG }} + medley_release_tag: ${{ steps.job_outputs.outputs.MEDLEY_RELEASE_TAG }} + medley_short_release_tag: ${{ steps.job_outputs.outputs.MEDLEY_SHORT_RELEASE_TAG }} + debs_filename_base: ${{ steps.debs.outputs.DEBS_FILENAME_BASE }} + needs: [inputs, sentry] if: | needs.sentry.outputs.release_not_built == 'true' @@ -143,20 +154,6 @@ jobs: id: tag uses: ./../actions/release-tag-action - # Setup environment variables - - name: Setup Environment Variables - id: setup_env - run: | - echo "build_time=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> ${GITHUB_OUTPUT} - echo "TARBALL_DIR=installers/deb/tmp/tarballs" >>${GITHUB_ENV} - echo "DEBS_DIR=installers/deb/debs" >>${GITHUB_ENV} - echo "TARS_DIR=installers/deb/tars" >>${GITHUB_ENV} - echo "MEDLEY_RELEASE_TAG=${RELEASE_TAG}" >>${GITHUB_ENV} - - # Setup some needed dirs in workspace - - name: Create work dirs - run: mkdir -p ${TARBALL_DIR} - # Get Maiko release information, retrieves the name of the latest # release. Used to download the correct Maiko release - name: Get Maiko Release Information @@ -166,6 +163,33 @@ jobs: owner: ${{ github.repository_owner }} repo: maiko + # Setup environment variables & establish job outputs + - name: Setup Environment Variables + run: | + echo "build_time=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> ${GITHUB_OUTPUT} + echo "TARBALL_DIR=installers/deb/tmp/tarballs" >>${GITHUB_ENV} + echo "DEBS_DIR=installers/deb/debs" >>${GITHUB_ENV} + echo "TARS_DIR=installers/deb/tars" >>${GITHUB_ENV} + echo "MEDLEY_RELEASE_TAG=${RELEASE_TAG}" >>${GITHUB_ENV} + echo "MAIKO_RELEASE_TAG=${{ steps.maiko.outputs.latest_tag }}" >>${GITHUB_ENV} + - name: More Environment Variables + run: | + echo "MEDLEY_SHORT_RELEASE_TAG=${MEDLEY_RELEASE_TAG#medley-}" >>${GITHUB_ENV} + echo "MAIKO_SHORT_RELEASE_TAG=${MAIKO_RELEASE_TAG#maiko-}" >>${GITHUB_ENV} + - name: Even More Environment Variables + run: | + echo "COMBINED_RELEASE_TAG=${MEDLEY_SHORT_RELEASE_TAG}_${MAIKO_SHORT_RELEASE_TAG}" >>${GITHUB_ENV} + - name: Establish job outputs + id: job_outputs + run: | + echo "COMBINED_RELEASE_TAG=${COMBINED_RELEASE_TAG}" >> $GITHUB_OUTPUT; + echo "MEDLEY_RELEASE_TAG=${MEDLEY_RELEASE_TAG}" >> $GITHUB_OUTPUT; + echo "MEDLEY_SHORT_RELEASE_TAG=${MEDLEY_SHORT_RELEASE_TAG}" >> $GITHUB_OUTPUT; + + # Setup some needed dirs in workspace + - name: Create work dirs + run: mkdir -p ${TARBALL_DIR} + # Download Maiko Release Assets - name: Download Release Assets uses: robinraju/release-downloader@v1.6 @@ -174,11 +198,11 @@ jobs: token: ${{ secrets.GITHUB_TOKEN }} latest: true out-file-path: ${{ env.TARBALL_DIR }} - fileName: "${{ steps.maiko.outputs.latest_tag }}-linux.*.tgz" + fileName: "${{ env.MAIKO_RELEASE_TAG }}-linux.*.tgz" - name: Untar Maiko Release for use in loadup run: | - tar -xzf "${TARBALL_DIR}/${{ steps.maiko.outputs.latest_tag }}-linux.x86_64.tgz" + tar -xzf "${TARBALL_DIR}/${{ env.MAIKO_RELEASE_TAG }}-linux.x86_64.tgz" # Checkout Notecards and tar it in the tarballsdir - name: Checkout Notecards @@ -192,7 +216,7 @@ jobs: cd .. tar cfz medley/${TARBALL_DIR}/notecards.tgz notecards - # + # Install vnc - name: Install vnc run: sudo apt-get update && sudo apt-get install -y tightvncserver @@ -202,7 +226,7 @@ jobs: export DISPLAY=":0" PATH="$PWD/maiko:$PATH" scripts/loadup-all.sh -apps - + - name: Build loadups release tar run: | cd .. @@ -240,11 +264,16 @@ jobs: medley/internal + # Build the deb files as well as the tgz files - name: Build .deb files for 3 architectures + id: debs run: | cd installers/deb - ./build_deb.sh + debs_filename_base=$(./build_deb.sh) + echo "DEBS_FILENAME_BASE=${debs_filename_base}" >> $GITHUB_ENV; + echo "DEBS_FILENAME_BASE=${debs_filename_base}" >> $GITHUB_OUTPUT; + # Push the release up to github releases - name: Delete existing release with same tag (if any) uses: cb80/delrel@latest with: @@ -267,41 +296,114 @@ jobs: generateReleaseNotes: true token: ${{ secrets.GITHUB_TOKEN }} - - name: Update the downloads page and the man page to the OIO satic page host + + # + # Create the Windows installer, push it up to the release on github and + # update the downloads page on OIO + # + windows_installer: + + runs-on: windows-latest + + needs: [inputs, sentry, loadup] + if: | + needs.sentry.outputs.release_not_built == 'true' + || needs.inputs.outputs.force == 'true' + + steps: + # Checkout latest commit + - name: Checkout Medley + uses: actions/checkout@v3 + + # Store the values output from loadup job as environment variables + - name: Environment Variables + shell: powershell run: | - maiko_release_tag="${{ steps.maiko.outputs.latest_tag }}" - medley_short_release_tag="${MEDLEY_RELEASE_TAG#medley-}" - full_release_filename="${MEDLEY_RELEASE_TAG/medley/medley-full}_${maiko_release_tag#maiko-}" - # Need info about where github stores assets because draft releases are not tagged - release_url="${{ steps.push_release.outputs.html_url }}" - github_subdir="$( echo "${release_url}" | sed -e "s#^.*/\([^/]\+\)\$#\1#g" )" - # + $crt="${{ needs.loadup.outputs.combined_release_tag }}" + echo "COMBINED_RELEASE_TAG=$crt" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append + $mrt="${{ needs.loadup.outputs.medley_release_tag }}" + echo "MEDLEY_RELEASE_TAG=$mrt" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append + $msrt="${{ needs.loadup.outputs.medley_short_release_tag }}" + echo "MEDLEY_SHORT_RELEASE_TAG=$msrt" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append + $debs="${{ needs.loadup.outputs.debs_filename_base }}" + echo "DEBS_FILENAME_BASE=$debs" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append + + # Download vnc viewer + - name: Download vncviewer + shell: powershell + run: | + $url = "https://sourceforge.net/projects/tigervnc/files/stable/1.12.0/vncviewer64-1.12.0.exe" + $output = "installers\win\vncviewer64-1.12.0.exe" + (New-Object System.Net.WebClient).DownloadFile($url, $output) + + # Run iscc.exe to compile the installer + - name: Compile medley.iss + shell: powershell + run: | + iscc installers\win\medley.iss + $filename="medley-install_${env:COMBINED_RELEASE_TAG}_x64.exe" + echo "INSTALLER_FILENAME=$filename" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append + + # Upload windows installer to release + - name: Upload windows installer to release + id: push + uses: ncipollo/release-action@v1 + with: + allowUpdates: true + artifacts: installers/win/${{ env.INSTALLER_FILENAME }} + tag: ${{ env.MEDLEY_RELEASE_TAG }} + token: ${{ secrets.GITHUB_TOKEN }} + omitBodyDuringUpdate: true + omitDraftDuringUpdate: true + omitNameDuringUpdate: true + omitPrereleaseDuringUpdate: true + + # Install the OpenSSH Client + - name: Install the OpenSSH Client + shell: powershell + run: | + Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0 + + # Update the downloads page and the man page on OIO + - name: Update the downloads page and the man page to the OIO static page host + shell: bash + run: | + # Figure out filenames + download_url="${{ steps.push.outputs.html_url }}" + download_url="${download_url/\/tag\//\/download\/}" local_template="installers/downloads_page/medley_downloads.html" local_filename="medley_downloads.html" + local_manpath="docs/man-page/man_medley.html" if [ "${{ needs.inputs.outputs.draft }}" = "true" ]; then remote_filename="draft_downloads" + remote_manname="man_draft.html" else remote_filename="${local_filename%.html}" + remote_manname="man_medley.html" fi remote_filepath="/srv/oio/static/${remote_filename}" + remote_manpath="/srv/oio/static/${remote_manname}" + # Fill in downloads page template sed \ - -e "s/@@@FULL.RELEASE.FILENAME@@@/${full_release_filename}/g" \ - -e "s/@@@GITHUB.SUBDIR@@@/${github_subdir}/g" \ - -e "s/@@@MEDLEY.SHORT.RELEASE.TAG@@@/${medley_short_release_tag}/g" \ + -e "s/@@@MEDLEY.SHORT.RELEASE.TAG@@@/${MEDLEY_SHORT_RELEASE_TAG}/g" \ + -e "s~@@@DOWNLOAD_URL@@@~${download_url}~g" \ + -e "s/@@@DEBS.FILENAME.BASE@@@/${DEBS_FILENAME_BASE}/g" \ + -e "s/@@@WINDOWS.INSTALLER.FILENAME@@@/${INSTALLER_FILENAME}/g" \ < "${local_template}" > "${local_filename}" - local_manpath="docs/man-page/man_medley.html" - remote_manpath="/srv/oio/static/man_medley.html" + # Create sftp instruction file echo "-rm ${remote_filepath}.oldold" > batch echo "-rename ${remote_filepath}.old ${remote_filepath}.oldold" >> batch echo "-rename ${remote_filepath}.html ${remote_filepath}.old" >> batch echo "-put ${local_filename} ${remote_filepath}.html" >> batch echo "-put ${local_manpath} ${remote_manpath}" >> batch + # Do the sftp eval $(ssh-agent) ssh-add - <<< "${SSH_KEY}" sftp -o StrictHostKeyChecking=no -b batch ubuntu@online.interlisp.org env: SSH_KEY: ${{ secrets.OIO_SSH_KEY }} + ###################################################################################### @@ -316,7 +418,7 @@ jobs: outputs: build_successful: ${{ steps.output.outputs.build_successful }} - needs: [inputs, sentry, loadup] + needs: [inputs, sentry, loadup, windows_installer] steps: # Checkout the actions for this repo owner @@ -340,3 +442,21 @@ jobs: echo "build_successful='true'" >> $GITHUB_OUTPUT ###################################################################################### + + + +# - name: Download the Windows installer created in windows job +# uses: actions/download-artifact@v3 +# with: +# name: windows_installer +# path: installers/win + +# - name: Rename the Windows installer w/ version tag +# run: | +# maiko_release_tag="${{ steps.maiko.outputs.latest_tag }}" +# combined_release_tag="${MEDLEY_RELEASE_TAG#medley-}_${maiko_release_tag#maiko-}" +# windows_installer_filename="medley_install_${combined_release_tag}_x64.exe" +# cd installers/win +# mv medley_install_vXXXVERSIONXXX_x64.exe "${windows_installer_filename}" +# echo "WINDOWS_INSTALLER_FILENAME=${windows_installer_filename}" >>${GITHUB_ENV} + diff --git a/.github/workflows/buildReleaseInclDocker.yml b/.github/workflows/buildReleaseInclDocker.yml index aac9b2f9..c45fc532 100644 --- a/.github/workflows/buildReleaseInclDocker.yml +++ b/.github/workflows/buildReleaseInclDocker.yml @@ -94,7 +94,9 @@ jobs: with: draft: ${{ needs.inputs.outputs.draft }} force: ${{ needs.inputs.outputs.force }} - + secrets: + OIO_SSH_KEY: ${{ secrets.OIO_SSH_KEY }} + ###################################################################################### @@ -109,6 +111,5 @@ jobs: DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} - ###################################################################################### diff --git a/.github/workflows/testLogin.yml b/.github/workflows/testLogin.yml deleted file mode 100644 index ac943ac7..00000000 --- a/.github/workflows/testLogin.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: 'Test Docker Login' - -# Run this workflow on ... -on: - workflow_dispatch: - -defaults: - run: - shell: bash - - -jobs: - - login_test: - runs-on: ubuntu-latest - steps: - - id: only_step - uses: docker/login-action@v1 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - - diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 405675f5..00000000 --- a/Dockerfile +++ /dev/null @@ -1,55 +0,0 @@ -#******************************************************************************* -# -# Dockerfile to build Medley image from latest Maiko image -# plus latest release tars from github -# -# Copyright 2022-2023 by Interlisp.org -# -# ****************************************************************************** - -ARG DOCKER_NAMESPACE=interlisp - -FROM ${DOCKER_NAMESPACE}/maiko:latest - -# Add tightvnc server and xclip to the image -RUN apt-get update && apt-get install -y tightvncserver && apt-get install -y xclip - -# Handle ARGs, ENV variables, and LABELs -ARG BUILD_DATE=unknown -ARG RELEASE_TAG=unknown -ARG MAIKO_RELEASE=unknown -ARG REPO_OWNER=Interlisp -LABEL name="Medley" -LABEL description="The Medley Interlisp environment" -LABEL url="https://github.com/${REPO_OWNER}/medley" -LABEL build-time=$BUILD_DATE -LABEL release_tag=$RELEASE_TAG -LABEL maiko_release=$MAIKO_RELEASE - -ENV MEDLEY_BUILD_DATE=$BUILD_DATE -ENV MEDLEY_RELEASE=$RELEASE_TAG - -ARG IL_INSTALLDIR=/usr/local/interlisp -ENV IL_INSTALLDIR=${IL_INSTALLDIR} -ENV MAIKO_INSTALLDIR=${IL_INSTALLDIR}/maiko -ENV MEDLEY_INSTALLDIR=${IL_INSTALLDIR}/medley - -ARG DOCKER_NAMESPACE=interlisp -ENV DOCKER_NAMESPACE=${DOCKER_NAMESPACE} - -ENV LANG=C.UTF-8 - -# Copy over the release tars -RUN mkdir -p ${IL_INSTALLDIR} -ADD ./*.tgz ${IL_INSTALLDIR} - -# Link run_medley script into /usr/local/bin -RUN mkdir -p /usr/local/bin && \ - ln -s ${MEDLEY_INSTALLDIR}/run-medley /usr/local/bin/run-medley - -# "Finalize" image -EXPOSE 5900 -RUN adduser --disabled-password --gecos "" medley -USER medley -WORKDIR /home/medley -ENTRYPOINT USER=medley Xvnc -geometry 1280x720 :0 & DISPLAY=:0 ${MEDELY_INSTALLDIR}/run-medley -full -g 1280x720 -sc 1280x720 diff --git a/docs/man-page/man_medley.html b/docs/man-page/man_medley.html index b1b97048..44149e06 100644 --- a/docs/man-page/man_medley.html +++ b/docs/man-page/man_medley.html @@ -37,35 +37,50 @@

Sets the size of the virtual display as seen from Medley’s point of view. The Medley window is an unscaled viewport onto this virtual display. If --screensize is not specified but --geometry is, then the virtual display size will be set so that the entire virtual display fits into the given window geometry. If neither --screensize nor --geometry is provided, then the screen size is set to 1440x900.

-t STRING, --title STRING
-

Use STRING as title of Medley window. Not relevent when the --vnc flag is set.

+

Use STRING as title of Medley window. Ignored when when the --vnc flag is set or when running on Windows (Docker) installations.

-
-d :N, --display :N
-

Use X display :N. Defaults to the value of $DISPLAY. Not relevant when the --vnc flag is set.

+
-d :N, --display :N ** Not applicable to Windows (Docker) installations **
+

Use X display :N. Defaults to the value of $DISPLAY. This flag is ignored when the --vnc flag is set as well as on Windows (Docker) installations.

-
-v, --vnc (Applicable only to Windows System for Linux installations)
-

Use a VNC window running on the Windows side instead of an X window. The VNC window will folllow the Windows desktop scaling setting allowing for much more usable Medley on high resolution displays. On WSL, X windows do not scale well.

+
-v, --vnc ** Applicable only to WSL installations **
+

Use a VNC window running on the Windows side instead of an X window. The VNC window will folllow the Windows desktop scaling setting allowing for much more usable Medley on high resolution displays. On WSL, X windows do not scale well. This flag is always set for WSL1 installations.

-i [ID_STRING | - | --], --id [ID_STRING | - | --]

Use ID_STRING as the id for this run of Medley, iunless ID_STRING is “-” or “--”. If ID_STRING is “-”, then use the basename of $MEDLEYDIR as the id. If ID_STRING is “--”, then use the basename of the parent directory of $MEDLEYDIR as the id. Only one instance of Medley with a given id can run at a time. The id is used to distinguish the virtual memory stores so that multiple instances of Medley can run simultaneously. Default id is “default”.

-m N, --mem N
-

Set Medley to run in N MB of virtual memory. Defaults to 256MB.

+

Set Medley to run in N MB of virtual memory. Defaults to 256MB.

-p FILE, --vmem FILE
-

Use FILE as the Medley virtual memory (vmem) store. FILE must be writeable by the current user. Care must be taken not to use the same vmem FILE for two instances of Medley running simultaneously. The --id flag will not protect against vmem collisions when the --vmem flag is used. Default is to store the vmem in LOGINDIR/vmem/lisp_XXX.virtualmem, where XXX is the id of this Medley run (see --id flag above). See --logindir below for setting of LOGINDIR.

+

Use FILE as the Medley virtual memory (vmem) store. FILE must be writeable by the current user. Care must be taken not to use the same vmem FILE for two instances of Medley running simultaneously. The --id flag will not protect against vmem collisions when the --vmem flag is used. Default is to store the vmem in LOGINDIR/vmem/lisp_XXX.virtualmem, where XXX is the id of this Medley run (see --id flag above). See --logindir below for setting of LOGINDIR. On Windows (Docker) installations, FILE is specified in the Medley file system, not the host Windows file system.

-r [FILE | -], --greet [FILE | -]
-

Use FILE as the Medley greetfile, unless FILE is “-” in which case Medley will start up without using a greetfile. The default Medley greetfile is $MEDLEYDIR/greetfiles/MEDLEYDIR-INIT, except when the --apps flag is used in which case it is $MEDLEYDIR/greetfiles/APPS-INIT.

+

Use FILE as the Medley greetfile, unless FILE is “-” in which case Medley will start up without using a greetfile. The default Medley greetfile is $MEDLEYDIR/greetfiles/MEDLEYDIR-INIT, except when the --apps flag is used in which case it is $MEDLEYDIR/greetfiles/APPS-INIT. On Windows (Docker) installations, FILE is specified in the Medley file system, not the host Windows file system.

-
-x [DIR | -], --logindir [DIR | -]
-

use DIR as LOGINDIR in Medley, unless DIR is “-”, in which case use $MEDLEYDIR/logindir. DIR (or $MEDLEYDIR/logindir) must be writeable by the current user. LOGINDIR defaults to $HOME/il. LOGINDIR is used by Medley as the working directory on start-up and where it loads any “personal” initialization file from.

+
-x [DIR | -], --logindir [DIR | -] ** On Linux and WSL installations **
+

Use DIR as LOGINDIR in Medley, unless DIR is “-”, in which case use $MEDLEYDIR/logindir. DIR (or $MEDLEYDIR/logindir) must be writeable by the current user. LOGINDIR defaults to $HOME/il. LOGINDIR is used by Medley as the working directory on start-up and where it loads any “personal” initialization file from.

+
+
-x [DIR | -], --logindir [DIR | -] ** On Windows (Docker) installations **
+

Map DIR in the Windows host file system to /home/medley/il in the Medley file system (in the Docker container). LOGINDIR is always /home/medley/il from Medley’s standpoint. The “-” value is not valid in this case.

+
+
-u, --update ** Windows (Docker) installations only **
+

Before running Medley, do a pull to retrieve the latest interlisp/medley docker image from Docker Hub.

+
+
-b, --background ** Windows (Docker) installations only **
+

Run Medley in background rather than foreground.

+
+
-p PORT, --port PORT ** Windows (Docker) installations only **
+

Use PORT as the port that VNC viewer uses to contact the VNC server within the Docker container. Default is 5900.

+
+
-w [DISTRO | -], --wsl [DISTRO | -] ** Windows (Docker) installations only **
+

Run Medley in the context of the named WSL DISTRO instead of within Docker. If DISTRO is “-”, used the default WSL distro. Equivalent to typing “wsl -d DISTRO medley ...” into a Command or Powershell window.

Other Options

SYSOUT_FILE
-

The pathname of the file to use as a sysout for Medley to start from. If SYSOUT_FILE is not provided and none of the flags (--apps, --full, --lisp) is used, then Medley will start from the saved virtual memory file from the previous session with the same ID_STRING as this run. If no such virtual memory file exists, then Medley will start from the standard full.sysout (equivalent to specifying the --full flag).

+

The pathname of the file to use as a sysout for Medley to start from. If SYSOUT_FILE is not provided and none of the flags (--apps, --full, --lisp) is used, then Medley will start from the saved virtual memory file from the previous session with the same ID_STRING as this run. If no such virtual memory file exists, then Medley will start from the standard full.sysout (equivalent to specifying the --full flag). On Windows (Docker) installations, SYSOUT_FILE is specified in the Medley file system, not the host Windows file system.

PASS_ON_ARGS

All arguments after the “--” flag, are passed unaltered to lde via run-medley.

diff --git a/docs/man-page/medley.1 b/docs/man-page/medley.1 index 6dbe6a6a..a5a0a746 100644 --- a/docs/man-page/medley.1 +++ b/docs/man-page/medley.1 @@ -95,18 +95,21 @@ size is set to 1440x900. .TP .B \-t \f[I]STRING\f[R], \-\-title \f[I]STRING\f[R] Use STRING as title of Medley window. -Not relevent when the \-\-vnc flag is set. +Ignored when when the \-\-vnc flag is set or when running on Windows +(Docker) installations. .TP -.B \-d \f[I]:N\f[R], \-\-display \f[I]:N\f[R] +.B \-d \f[I]:N\f[R], \-\-display \f[I]:N\f[R]\ \ \ \ ** \f[B]Not applicable to Windows (Docker) installations\f[R] ** Use X display :N. Defaults to the value of $DISPLAY. -Not relevant when the \-\-vnc flag is set. +This flag is ignored when the \-\-vnc flag is set as well as on Windows +(Docker) installations. .TP -.B \-v, \-\-vnc (Applicable only to Windows System for Linux installations) +.B \-v, \-\-vnc\ \ \ \ ** \f[B]Applicable only to WSL installations\f[R] ** Use a VNC window running on the Windows side instead of an X window. The VNC window will folllow the Windows desktop scaling setting allowing for much more usable Medley on high resolution displays. On WSL, X windows do not scale well. +This flag is always set for WSL1 installations. .TP .B \-i [\f[I]ID_STRING\f[R] | \- | \-\-], \-\-id [\f[I]ID_STRING\f[R] | \- | \-\-] Use ID_STRING as the id for this run of Medley, iunless ID_STRING is @@ -121,7 +124,7 @@ instances of Medley can run simultaneously. Default id is \[lq]default\[rq]. .TP .B \-m \f[I]N\f[R], \-\-mem \f[I]N\f[R] -Set Medley to run in N MB of virtual memory. +Set Medley to run in \f[I]N\f[R] MB of virtual memory. Defaults to 256MB. .TP .B \-p \f[I]FILE\f[R], \-\-vmem \f[I]FILE\f[R] @@ -134,6 +137,8 @@ The \-\-id flag will not protect against vmem collisions when the Default is to store the vmem in LOGINDIR/vmem/lisp_XXX.virtualmem, where XXX is the id of this Medley run (see \-\-id flag above). See \-\-logindir below for setting of LOGINDIR. +On Windows (Docker) installations, \f[I]FILE\f[R] is specified in the +Medley file system, not the host Windows file system. .TP .B \-r [\f[I]FILE\f[R] | \-], \-\-greet [\f[I]FILE\f[R] | \-] Use FILE as the Medley greetfile, unless FILE is \[lq]\-\[rq] in which @@ -141,14 +146,41 @@ case Medley will start up without using a greetfile. The default Medley greetfile is $MEDLEYDIR/greetfiles/MEDLEYDIR\-INIT, except when the \-\-apps flag is used in which case it is $MEDLEYDIR/greetfiles/APPS\-INIT. +On Windows (Docker) installations, \f[I]FILE\f[R] is specified in the +Medley file system, not the host Windows file system. .TP -.B \-x [\f[I]DIR\f[R] | \-], \-\-logindir [\f[I]DIR\f[R] | \-] -use DIR as LOGINDIR in Medley, unless DIR is \[lq]\-\[rq], in which case +.B \-x [\f[I]DIR\f[R] | \-], \-\-logindir [\f[I]DIR\f[R] | \-]\ \ \ \ ** \f[B]On Linux and WSL installations\f[R] ** +Use DIR as LOGINDIR in Medley, unless DIR is \[lq]\-\[rq], in which case use $MEDLEYDIR/logindir. DIR (or $MEDLEYDIR/logindir) must be writeable by the current user. LOGINDIR defaults to $HOME/il. LOGINDIR is used by Medley as the working directory on start\-up and where it loads any \[lq]personal\[rq] initialization file from. +.TP +.B \-x [\f[I]DIR\f[R] | \-], \-\-logindir [\f[I]DIR\f[R] | \-]\ \ \ \ ** \f[B]On Windows (Docker) installations\f[R] ** +Map DIR in the Windows host file system to /home/medley/il in the Medley +file system (in the Docker container). +LOGINDIR is always /home/medley/il from Medley\[cq]s standpoint. +The \[lq]\-\[rq] value is not valid in this case. +.TP +.B \-u, \-\-update\ \ \ \ ** \f[B]Windows (Docker) installations only\f[R] ** +Before running Medley, do a pull to retrieve the latest interlisp/medley +docker image from Docker Hub. +.TP +.B \-b, \-\-background\ \ \ \ ** \f[B]Windows (Docker) installations only\f[R] ** +Run Medley in background rather than foreground. +.TP +.B \-p \f[I]PORT\f[R], \-\-port \f[I]PORT\f[R]\ \ \ \ ** \f[B]Windows (Docker) installations only\f[R] ** +Use \f[I]PORT\f[R] as the port that VNC viewer uses to contact the VNC +server within the Docker container. +Default is 5900. +.TP +.B \-w [\f[I]DISTRO\f[R] | \-], \-\-wsl [\f[I]DISTRO\f[R] | \-]\ \ \ \ ** \f[B]Windows (Docker) installations only\f[R] ** +Run Medley in the context of the named WSL \f[I]DISTRO\f[R] instead of +within Docker. +If \f[I]DISTRO\f[R] is \[lq]\-\[rq], used the default WSL distro. +Equivalent to typing \[lq]wsl \-d \f[I]DISTRO\f[R] medley \&...\[rq] +into a Command or Powershell window. .SS Other Options .PP \ @@ -161,6 +193,8 @@ virtual memory file from the previous session with the same ID_STRING as this run. If no such virtual memory file exists, then Medley will start from the standard full.sysout (equivalent to specifying the \-\-full flag). +On Windows (Docker) installations, \f[I]SYSOUT_FILE\f[R] is specified in +the Medley file system, not the host Windows file system. .TP .B \f[I]PASS_ON_ARGS\f[R] All arguments after the \[lq]\-\-\[rq] flag, are passed unaltered to lde diff --git a/docs/man-page/medley.1.gz b/docs/man-page/medley.1.gz index 11dd5f379efb59d4a1469108e45049e1aaac4d74..a73df928a1f2be91c3feffc53428e32c33991601 100644 GIT binary patch literal 3144 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 literal 2674 zcmV-&3XSz2iwFpb6xL$^18rqwY-M>aF#xq$ZExE+68_F#K@^Kaf=%Q$+g)Ib!vT3~ zV<54OD7_|#gMyZ5n+PSUqGZR#{rH<1k}~}gG+!2IibxvH3}>EsX2>Mtcl@+%Od%ST z39VOrCQDh1M&^97;v-S!CgUf`pDY=_V~NPQX35!n-6SkYulV5f=8`3&5gSh* z&z=g>1;5@t@$sW9p14IDmbcZ89a^3~42Gk$pYB)j$fsJ&EFb?XNfM6F@V@_)KBU91 zci%tvuP>b(eK{TvyGLY56*h+2t>mfXq)L*{Kja(HVgQ>+l>3Zl!K zx#Xt8*jk9J&1yA40jbe?X9#VeWMe9>+PbF=Ah)MNzgq^h=8Z!v!L8wUSeA+oBNbTsYWbxL4e$+pnP;mTM|A0bVS#UUE_$F}= z5QI#(06N$P21v_BMsoXq7rC~(H0QW@Z5lf z(sbr{gnUs|fGy$RKWUY2pg>eP^V>?;K`P}dRZlhIqGW2s3jA95l$MToKofI&waMW+ zirPhySm-TLM8VA{;+qgfQ|i?^l(>2#EL7NQkz`RM|Dg>Ew?T-mebWX}aC3wBW(Ova z-g*V~4Ece2jFD97wqw#br_8Oz6$8`A3@q9serrtO%H#Zcm=Z{Ywq|Xps^$22UHp!E zpn#rb$EDEbsIbV+KNLpk!q_ntKd2?LZ|Rf11g7Z%jWpxgRpy86Mm$T3v?^7jfD|uZ zWairn$NGT?`mIc`BqF$=WWp|7nk`4gY{~errhYwvN_i3ry5<5CN3a$5> z%7L_B_?1+%ITFujsNYVJ~Xy6Pd6 z@N{zzUU(h*39tl8xR}#kl%)VWfVd4X`ViusLqn1Ao^U8jJ3%tGZdf5kh5l*9(dKYaZ7{^jrY@44E8IuJpRK79P^;^=?rC@Xi z6OqRO6)~9iV8X3<4HHpP8{e4jZu^5TQC=I>Xu0!^eYKLiXUv@wg4}L#EzlkBx=}~7 zsCH3i1bgpPfJWh}2hN^YDZb^jJtCt(9;v2IsMv zM%_!sDhP8^s8sC-^PmI<`oFr(}XyK4S^G0iFOFn(z&>Z;J zouOJ{*wC31HZ1wK^!ljt32YfxJXnByDPiDR$4>D_N?QNodjuc;KlnudjgNhbRsL&9 z3Ssx1fQPe7PBEuahmfvec*Ip(YH4k>Mp;I~B-BEBu%dz>oMPc9~!gyhn2|Qw;dc89K7*{3cJF{Q1|-S!AnnYP-qY z*M4WO`#@mCr;vxONz_N`0GA%RfF+FNi`F*SD3-N?8ppbutVn~OT4=^i*g0Nf1la~A z^^(dAd=7ZAh!t{;^imZp4Udz+)?*fN&2|#*Jo{l0A^8!Zpc&{Ta1;WF%Ru*i4fX786e9LkWdtIb3Odh9{`Gb_@akLitqRL_lb`lygNb@wPf%% zTr8>FRfe+B^vDma+}wkhn1zIKFZJ)WnE_L&Iyz(pIs|pWkq85|r=s=o3<)Sqz|c^e z{Q|E+f|g8`hNGG%Bof-<7L3YruCh7HfCtvqi}zb}uxcx+WjxBd`v@w-=XU8s@ zS`$aFdvAN|Tf*c1pnrG75yM3Lw@1BBCR*7aFw<%KUX-VKcoxg9vLR)jP!?3drT`|%ertdJm z(vhUZZnkk#c@Us@#KQIB`ikr@#L~Ca-RfE2Dv5>6*%nQAfpLwumJ0<82|QtKcfjl@ zHy%M)m^<9C4*SHRYM*xb0zK9K(m&SSdc}8F2l7X&V4iiimj0kZR}Y~`QJNxkm~5nQ z=PwQH6a?2-zU~&Cv~0{Kr0a<8(ko#Rr7fTeWZi(EbG$ncxO42r;cEJds4Wd11k88s z!0$U$z_#4F8$_L;Tf8T#I|`6#4wCEh;mu*UE|dgS!{)NLkm9zwZFZ$?pMCw}{`i7j z=Zk8t+6nJl3updM{NMAYsqCj-Zw4@GCrM_CUVrN^3q3``{~=}P!_mWS|I5`KX*@U8 gs>b_}gY1x>yg&H^`J!8&n0m(k4@P1@7jhc_09>muiU0rr diff --git a/docs/man-page/medley.1.md b/docs/man-page/medley.1.md index 8b4d7e7e..0f0ed85d 100644 --- a/docs/man-page/medley.1.md +++ b/docs/man-page/medley.1.md @@ -41,7 +41,7 @@ Flags -z, \-\-man : Show the man page for medley --f, \-\-full +-f, \-\-full : Start Medley from the standard "full" sysout. full.sysout includes a complete Interlisp and CommonLisp environment with a standard set of development tools. It does not include any of the applications built using Medley. (See *SYSOUT_FILE* below for more information on starting sysouts.) @@ -80,17 +80,18 @@ The Medley window is an unscaled viewport onto this virtual display. If \-\-scre window geometry. If neither \-\-screensize nor \-\-geometry is provided, then the screen size is set to 1440x900. -t *STRING*, \-\-title *STRING* -: Use STRING as title of Medley window. Not relevent when the \-\-vnc flag is set. +: Use STRING as title of Medley window. Ignored when when the \-\-vnc flag is set or when running on Windows (Docker) +installations. --d *:N*, \-\-display *:N* -: Use X display :N. Defaults to the value of $DISPLAY. Not relevant when -the \-\-vnc flag is set. +-d *:N*, \-\-display *:N*    \*\* **Not applicable to Windows (Docker) installations** \*\* +~ Use X display :N. Defaults to the value of $DISPLAY. This flag is ignored when the \-\-vnc flag is set as +well as on Windows (Docker) installations. --v, \-\-vnc (Applicable only to Windows System for Linux installations) +-v, \-\-vnc    \*\* **Applicable only to WSL installations** \*\* : Use a VNC window running on the Windows side instead of an X window. The VNC window will folllow the Windows desktop scaling setting allowing for much more usable Medley on high resolution displays. On WSL, X windows -do not scale well. +do not scale well. This flag is always set for WSL1 installations. -i [*ID_STRING* | - | \-\-], \-\-id [*ID_STRING* | - | \-\-] : Use ID_STRING as the id for this run of Medley, iunless ID_STRING is "-" or "\-\-". @@ -101,27 +102,45 @@ The id is used to distinguish the virtual memory stores so that multiple instances of Medley can run simultaneously. Default id is "default". -m *N*, \-\-mem *N* -: Set Medley to run in N MB of virtual memory. Defaults to 256MB. +: Set Medley to run in *N* MB of virtual memory. Defaults to 256MB. -p *FILE*, \-\-vmem *FILE* : Use FILE as the Medley virtual memory (vmem) store. FILE must be writeable by the current user. Care must be taken not to use the same vmem FILE for two instances of Medley running simultaneously. The \-\-id flag will not protect against vmem collisions when the \-\-vmem flag is used. -Default is to store the vmem in LOGINDIR/vmem/lisp_XXX.virtualmem, where XXX is the id of this -Medley run (see \-\-id flag above). See \-\-logindir below for setting of LOGINDIR. +Default is to store the vmem in LOGINDIR/vmem/lisp_XXX.virtualmem, where XXX is the id of this +Medley run (see \-\-id flag above). See \-\-logindir below for setting of LOGINDIR. On Windows (Docker) installations, *FILE* is specified in the Medley file system, not the host Windows file system. -r \[*FILE* | -], \-\-greet \[*FILE* | -] : Use FILE as the Medley greetfile, unless FILE is "-" in which case Medley will start up without using a greetfile. The default Medley greetfile is $MEDLEYDIR/greetfiles/MEDLEYDIR-INIT, except when the \-\-apps flag is used -in which case it is $MEDLEYDIR/greetfiles/APPS-INIT. +in which case it is $MEDLEYDIR/greetfiles/APPS-INIT. On Windows (Docker) installations, *FILE* is +specified in the Medley file system, not the host Windows file system. --x \[*DIR* | -], \-\-logindir \[*DIR* | -] -: use DIR as LOGINDIR in Medley, unless DIR is "-", in which case use +-x \[*DIR* | -], \-\-logindir \[*DIR* | -]    \*\* **On Linux and WSL installations** \*\* +: Use DIR as LOGINDIR in Medley, unless DIR is "-", in which case use \$MEDLEYDIR/logindir. DIR (or \$MEDLEYDIR/logindir) must be writeable by the current user. LOGINDIR defaults to \$HOME/il. LOGINDIR is used by Medley as the working directory on start-up and where it loads any "personal" initialization file from. +-x \[*DIR* | -], \-\-logindir \[*DIR* | -]    \*\* **On Windows (Docker) installations** \*\* +: Map DIR in the Windows host file system to /home/medley/il in the Medley +file system (in the Docker container). LOGINDIR is always /home/medley/il from Medley's standpoint. The "-" value is not valid in this case. + +-u, \-\-update    \*\* **Windows (Docker) installations only** \*\* +: Before running Medley, do a pull to retrieve the latest interlisp/medley docker image from Docker Hub. + +-b, \-\-background    \*\* **Windows (Docker) installations only** \*\* +: Run Medley in background rather than foreground. + +-p *PORT*, \-\-port *PORT*    \*\* **Windows (Docker) installations only** \*\* +: Use *PORT* as the port that VNC viewer uses to contact the VNC server within the Docker container. Default is 5900. + +-w \[*DISTRO* | -], \-\-wsl \[*DISTRO* | -]    \*\* **Windows (Docker) installations only** \*\* +: Run Medley in the context of the named WSL *DISTRO* instead of within Docker. If *DISTRO* is "-", used the default WSL distro. Equivalent to typing "wsl -d *DISTRO* medley ..." into a Command or Powershell window. + + Other Options -------------   @@ -130,8 +149,9 @@ Other Options : The pathname of the file to use as a sysout for Medley to start from. If SYSOUT_FILE is not provided and none of the flags (\-\-apps, \-\-full, \-\-lisp) is used, then Medley will start from the saved virtual memory file from the previous session with the same ID_STRING as this run. -If no such virtual memory file exists, then Medley will start from the standard full.sysout -(equivalent to specifying the \-\-full flag). +If no such virtual memory file exists, then Medley will start from the standard full.sysout +(equivalent to specifying the \-\-full flag). On Windows (Docker) installations, *SYSOUT_FILE* is +specified in the Medley file system, not the host Windows file system. *PASS_ON_ARGS* : All arguments after the "\-\-" flag, are passed unaltered to lde via run-medley. diff --git a/installers/deb/build_deb.sh b/installers/deb/build_deb.sh index 27096f10..5beb7314 100755 --- a/installers/deb/build_deb.sh +++ b/installers/deb/build_deb.sh @@ -11,6 +11,15 @@ ############################################################################### # set -x +# mess with file desscriptors so we get only one line on stdout +# so we can communicate only what we want back to any githib runner +# stash fd 1 in fd 3 +exec 3>&1 +# make fd 1 (stdout) be the same as stdout +# so none of the std output from this file will be captured by +# $() but it will still be written out to the tty (via stderr) +exec 1>&2 + tarball_dir=tmp/tarballs # Make sure we are in the right directory @@ -60,6 +69,7 @@ fi pushd ${tarball_dir} >/dev/null 2>/dev/null medley_release=$(echo medley-*-loadups.tgz | sed "s/medley-\(.*\)-loadups.tgz/\1/") maiko_release=$(echo maiko-*-linux.x86_64.tgz | sed "s/maiko-\(.*\)-linux.x86_64.tgz/\1/") +debs_filename_base="medley-full-${medley_release}_${maiko_release}" popd >/dev/null 2>/dev/null @@ -120,9 +130,13 @@ do cp -p tmp/vncviewer64-1.12.0.exe ${il_dir}/wsl/vncviewer64-1.12.0.exe fi # + # Make sure all files are owned by root + # + sudo su <<< "chown --recursive root:root ${il_dir}" + # # Create tar file for this arch # - filename="medley-full-${medley_release}_${maiko_release}-${wslp}-${arch}" + filename="${debs_filename_base}-${wslp}-${arch}" mkdir -p tars echo "Creating tar file tars/${filename}.tgz" tar -C ${il_dir} -czf tars/${filename}.tgz . @@ -137,3 +151,8 @@ do done done +# send just one line back to github $() construct +# do this by restoring fd 1 to what it was orginally +exec 1>&3 +echo "${debs_filename_base}" + diff --git a/installers/deb/control-linux b/installers/deb/control-linux index 885c36ef..8fee0cd4 100644 --- a/installers/deb/control-linux +++ b/installers/deb/control-linux @@ -1,9 +1,9 @@ Package: medley-interlisp -Version: 1.0.0 +Version: 1.0.1 Release: --RELEASE-- Maintainer: info@interlisp.org Description: Medley Interlisp for Linux Homepage: https://github.com/interlisp/medley Architecture: --ARCH-- -Depends: xdg-utils +Depends: man-db, xdg-utils diff --git a/installers/downloads_page/medley_downloads.html b/installers/downloads_page/medley_downloads.html index 2dd89cb7..e41529a9 100644 --- a/installers/downloads_page/medley_downloads.html +++ b/installers/downloads_page/medley_downloads.html @@ -2,37 +2,44 @@
  • MEDLEY DOWNLOADS

  • +
  • WINDOWS 10/11 (Medley runs in a Docker container)

    + +

    Release @@@MEDLEY.SHORT.RELEASE.TAG@@@ for Windows x64 machines

  • diff --git a/installers/downloads_page/medley_downloads.md b/installers/downloads_page/medley_downloads.md index fe1420f7..7d251244 100644 --- a/installers/downloads_page/medley_downloads.md +++ b/installers/downloads_page/medley_downloads.md @@ -1,38 +1,42 @@ * # MEDLEY DOWNLOADS - * ## Standard Installations (for Debian-based distros) + * ## LINUX (including Windows System for Linux) - * ### Standard Linux + * ### Standard Installations (for Debian-based distros) - [Release @@@MEDLEY.SHORT.RELEASE.TAG@@@ for x86\_64 machines](https://github.com/Interlisp/medley/releases/download/@@@GITHUB.SUBDIR@@@/@@@FULL.RELEASE.FILENAME@@@-linux-x86\_64.deb) + * #### Standard Linux - [Release @@@MEDLEY.SHORT.RELEASE.TAG@@@ for ARM64 machines](https://github.com/Interlisp/medley/releases/download/@@@GITHUB.SUBDIR@@@/@@@FULL.RELEASE.FILENAME@@@-linux-aarch64.deb) + [Release @@@MEDLEY.SHORT.RELEASE.TAG@@@ for x86\_64 machines](@@@DOWNLOAD_URL@@@/@@@DEBS.FILENAME.BASE@@@-linux-x86\_64.deb) - [Release @@@MEDLEY.SHORT.RELEASE.TAG@@@ for ARMv7 machines](https://github.com/Interlisp/medley/releases/download/@@@GITHUB.SUBDIR@@@/@@@FULL.RELEASE.FILENAME@@@-linux-armv7l.deb) + [Release @@@MEDLEY.SHORT.RELEASE.TAG@@@ for ARM64 machines](@@@DOWNLOAD_URL@@@/@@@DEBS.FILENAME.BASE@@@-linux-aarch64.deb) - * ### Windows System for Linux + [Release @@@MEDLEY.SHORT.RELEASE.TAG@@@ for ARMv7 machines](@@@DOWNLOAD_URL@@@/@@@DEBS.FILENAME.BASE@@@-linux-armv7l.deb) - [Release @@@MEDLEY.SHORT.RELEASE.TAG@@@ for x86\.64 machines](https://github.com/Interlisp/medley/releases/download/@@@GITHUB.SUBDIR@@@/@@@FULL.RELEASE.FILENAME@@@-wsl-x86\_64.deb) + * #### Windows System for Linux - [Release @@@MEDLEY.SHORT.RELEASE.TAG@@@ for ARM64 machines](https://github.com/Interlisp/medley/releases/download/@@@GITHUB.SUBDIR@@@/@@@FULL.RELEASE.FILENAME@@@-wsl-aarch64.deb) + [Release @@@MEDLEY.SHORT.RELEASE.TAG@@@ for x86\.64 machines](@@@DOWNLOAD_URL@@@/@@@DEBS.FILENAME.BASE@@@-wsl-x86\_64.deb) - * ## Local Installations (for any Linux distro) + [Release @@@MEDLEY.SHORT.RELEASE.TAG@@@ for ARM64 machines](@@@DOWNLOAD_URL@@@/@@@DEBS.FILENAME.BASE@@@-wsl-aarch64.deb) - * ### Standard Linux + * ### Local Installations (for any Linux distro) - [Release @@@MEDLEY.SHORT.RELEASE.TAG@@@ for x86\_64 machines](https://github.com/Interlisp/medley/releases/download/@@@GITHUB.SUBDIR@@@/@@@FULL.RELEASE.FILENAME@@@-linux-x86\_64.tgz) + * #### Standard Linux - [Release @@@MEDLEY.SHORT.RELEASE.TAG@@@ for ARM64 machines](https://github.com/Interlisp/medley/releases/download/@@@GITHUB.SUBDIR@@@/@@@FULL.RELEASE.FILENAME@@@-linux-aarch64.tgz) + [Release @@@MEDLEY.SHORT.RELEASE.TAG@@@ for x86\_64 machines](@@@DOWNLOAD_URL@@@/@@@DEBS.FILENAME.BASE@@@-linux-x86\_64.tgz) - [Release @@@MEDLEY.SHORT.RELEASE.TAG@@@ for ARMv7 machines](https://github.com/Interlisp/medley/releases/download/@@@GITHUB.SUBDIR@@@/@@@FULL.RELEASE.FILENAME@@@-linux-armv7l.tgz) + [Release @@@MEDLEY.SHORT.RELEASE.TAG@@@ for ARM64 machines](@@@DOWNLOAD_URL@@@/@@@DEBS.FILENAME.BASE@@@-linux-aarch64.tgz) - * ### Windows System for Linux - - [Release @@@MEDLEY.SHORT.RELEASE.TAG@@@ for x86\_64 machines](https://github.com/Interlisp/medley/releases/download/@@@GITHUB.SUBDIR@@@/@@@FULL.RELEASE.FILENAME@@@-wsl-x86\_64.tgz) - - [Release @@@MEDLEY.SHORT.RELEASE.TAG@@@ for ARM64 machines](https://github.com/Interlisp/medley/releases/download/@@@GITHUB.SUBDIR@@@/@@@FULL.RELEASE.FILENAME@@@-wsl-aarch64.tgz) + [Release @@@MEDLEY.SHORT.RELEASE.TAG@@@ for ARMv7 machines](@@@DOWNLOAD_URL@@@/@@@DEBS.FILENAME.BASE@@@-linux-armv7l.tgz) + * #### Windows System for Linux + [Release @@@MEDLEY.SHORT.RELEASE.TAG@@@ for x86\_64 machines](@@@DOWNLOAD_URL@@@/@@@DEBS.FILENAME.BASE@@@-wsl-x86\_64.tgz) + + [Release @@@MEDLEY.SHORT.RELEASE.TAG@@@ for ARM64 machines](@@@DOWNLOAD_URL@@@/@@@DEBS.FILENAME.BASE@@@-wsl-aarch64.tgz) + + * ## WINDOWS 10/11 (Medley runs in a Docker container) + + [Release @@@MEDLEY.SHORT.RELEASE.TAG@@@ for Windows x64 machines](@@@DOWNLOAD_URL@@@/@@@WINDOWS.INSTALLER.FILENAME@@@) diff --git a/installers/win/.gitignore b/installers/win/.gitignore new file mode 100644 index 00000000..7c4c3101 --- /dev/null +++ b/installers/win/.gitignore @@ -0,0 +1,3 @@ +medley-install_*.exe +vncviewer*.exe + diff --git a/installers/win/Medley.ico b/installers/win/Medley.ico new file mode 100644 index 0000000000000000000000000000000000000000..6f0f1972278efbd025b93b24eb8ce1ed85eaf847 GIT binary patch literal 159126 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 literal 0 HcmV?d00001 diff --git a/installers/win/editpath/EditPath.iss b/installers/win/editpath/EditPath.iss new file mode 100644 index 00000000..0312dcaa --- /dev/null +++ b/installers/win/editpath/EditPath.iss @@ -0,0 +1,165 @@ +; Copyright (C) 2021-2023 by Bill Stewart (bstewart at iname.com) +; +; This program is free software; you can redistribute it and/or modify it under +; the terms of the GNU Lesser General Public License as published by the Free +; Software Foundation; either version 3 of the License, or (at your option) any +; later version. +; +; This program is distributed in the hope that it will be useful, but WITHOUT +; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +; FOR A PARTICULAR PURPOSE. See the GNU General Lesser Public License for more +; details. +; +; You should have received a copy of the GNU Lesser General Public License +; along with this program. If not, see https://www.gnu.org/licenses/. + +; Sample Inno Setup (https://www.jrsoftware.org/isinfo.php) script +; demonstrating use of PathMgr.dll. +; +; This script uses PathMgr.dll in the following ways: +; * Copies PathMgr.dll to the target machine (required for uninstall) +; * Defines a task in [Tasks] that should modify the Path +; * Imports the AddDirToPath() DLL function at setup time +; * Imports the RemoveDirFromPath() DLL function at uninstall time +; * Stores task state as custom setting using RegisterPreviousData() +; * Retrieves task state custom setting during setup and uninstall initialize +; * At post install, adds app dir to Path if task selected +; * At uninstall, removes dir from Path if custom setting present +; * Unloads and deletes DLL and removes app dir at uninstall deinitialize + +#if Ver < EncodeVer(6,0,0,0) + #error This script requires Inno Setup 6 or later +#endif + +[Setup] +AppId={{A17D2D05-C729-4F2A-9CC7-E04906C5A842} +AppName=EditPath +AppVersion=4.0.4.0 +UsePreviousAppDir=false +DefaultDirName={autopf}\EditPath +Uninstallable=true +OutputDir=. +OutputBaseFilename=EditPath_Setup +ArchitecturesInstallIn64BitMode=x64 +PrivilegesRequired=none +PrivilegesRequiredOverridesAllowed=dialog + +[Files] +; Install PathMgr.dll for use with both setup and uninstall; use +; uninsneveruninstall flag because DeinitializeSetup() will delete after +; unloading the DLL; install the 32-bit version of PathMgr.dll because both +; setup and uninstall executables are 32-bit +Source: "i386\PathMgr.dll"; DestDir: "{app}"; Flags: uninsneveruninstall + +; Other files to install on target system +Source: "i386\EditPath.exe"; DestDir: "{app}"; Check: not Is64BitInstallMode() +Source: "x86_64\EditPath.exe"; DestDir: "{app}"; Check: Is64BitInstallMode() +Source: "EditPath.md"; DestDir: "{app}" + +[Tasks] +Name: modifypath; Description: "&Add to Path" + +[Code] +const + MODIFY_PATH_TASK_NAME = 'modifypath'; // Specify name of task + +var + PathIsModified: Boolean; // Cache task selection from previous installs + ApplicationUninstalled: Boolean; // Has application been uninstalled? + +// Import AddDirToPath() at setup time ('files:' prefix) +function DLLAddDirToPath(DirName: string; PathType, AddType: DWORD): DWORD; + external 'AddDirToPath@files:PathMgr.dll stdcall setuponly'; + +// Import RemoveDirFromPath() at uninstall time ('{app}\' prefix) +function DLLRemoveDirFromPath(DirName: string; PathType: DWORD): DWORD; + external 'RemoveDirFromPath@{app}\PathMgr.dll stdcall uninstallonly'; + +// Wrapper for AddDirToPath() DLL function +function AddDirToPath(const DirName: string): DWORD; +var + PathType, AddType: DWORD; +begin + // PathType = 0 - use system Path + // PathType = 1 - use user Path + // AddType = 0 - add to end of Path + // AddType = 1 - add to beginning of Path + if IsAdminInstallMode() then + PathType := 0 + else + PathType := 1; + AddType := 0; + result := DLLAddDirToPath(DirName, PathType, AddType); +end; + +// Wrapper for RemoveDirFromPath() DLL function +function RemoveDirFromPath(const DirName: string): DWORD; +var + PathType: DWORD; +begin + // PathType = 0 - use system Path + // PathType = 1 - use user Path + if IsAdminInstallMode() then + PathType := 0 + else + PathType := 1; + result := DLLRemoveDirFromPath(DirName, PathType); +end; + +procedure RegisterPreviousData(PreviousDataKey: Integer); +begin + // Store previous or current task selection as custom user setting + if PathIsModified or WizardIsTaskSelected(MODIFY_PATH_TASK_NAME) then + SetPreviousData(PreviousDataKey, MODIFY_PATH_TASK_NAME, 'true'); +end; + +function InitializeSetup(): Boolean; +begin + result := true; + // Was task selected during a previous install? + PathIsModified := GetPreviousData(MODIFY_PATH_TASK_NAME, '') = 'true'; +end; + +function InitializeUninstall(): Boolean; +begin + result := true; + // Was task selected during a previous install? + PathIsModified := GetPreviousData(MODIFY_PATH_TASK_NAME, '') = 'true'; + ApplicationUninstalled := false; +end; + +procedure CurStepChanged(CurStep: TSetupStep); +begin + if CurStep = ssPostInstall then + begin + // Add app directory to Path at post-install step if task selected + if PathIsModified or WizardIsTaskSelected(MODIFY_PATH_TASK_NAME) then + AddDirToPath(ExpandConstant('{app}')); + end; +end; + +procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep); +begin + if CurUninstallStep = usUninstall then + begin + // Remove app directory from path during uninstall if task was selected; + // use variable because we can't use WizardIsTaskSelected() at uninstall + if PathIsModified then + RemoveDirFromPath(ExpandConstant('{app}')); + end + else if CurUninstallStep = usPostUninstall then + begin + ApplicationUninstalled := true; + end; +end; + +procedure DeinitializeUninstall(); +begin + if ApplicationUninstalled then + begin + // Unload and delete PathMgr.dll and remove app dir when uninstalling + UnloadDLL(ExpandConstant('{app}\PathMgr.dll')); + DeleteFile(ExpandConstant('{app}\PathMgr.dll')); + RemoveDir(ExpandConstant('{app}')); + end; +end; diff --git a/installers/win/editpath/EditPath.md b/installers/win/editpath/EditPath.md new file mode 100644 index 00000000..bce1768a --- /dev/null +++ b/installers/win/editpath/EditPath.md @@ -0,0 +1,118 @@ +# EditPath + +EditPath is a Windows console (text-based, command-line) program for managing the system Path and user Path. + +# Author + +Bill Stewart - bstewart at iname dot com + +# License + +EditPath.exe is covered by the GNU Lesser Public License (LPGL). See the file `LICENSE` for details. + +# Download + +https://github.com/Bill-Stewart/PathMgr/releases/ + +# Background + +The system Path is found in the following location in the Windows registry: + +Root: `HKEY_LOCAL_MACHINE` +Subkey: `SYSTEM\CurrentControlSet\Control\Session Manager\Environment` +Value name: `Path` + +The current user Path is found in the following location in the registry: + +Root: `HKEY_CURRENT_USER` +Subkey: `Environment` +Value name: `Path` + +In both cases, the `Path` value is (or should be) the registry type `REG_EXPAND_SZ`, which means that it is a string that can contain values surrounded by `%` characters that Windows will automatically expand to environment variable values. (For example, `%SystemRoot%` will be expanded to `C:\Windows` on most systems.) + +The `Path` value contains a `;`-delimited list of directory names that the system should search for executables, library files, scripts, etc. Windows appends the content of the current user Path to the system Path and expands the environment variable references. The resulting string is set as the `Path` environment variable for processes. + +EditPath provides a command-line interface for managing the `Path` value in the system location (in `HKEY_LOCAL_MACHINE`) and the current user location (in `HKEY_CURRENT_USER`). + +# Usage + +The following describes the command-line usage for the program. Parameters are case-sensitive. + +**EditPath** [_options_] _type_ _action_ + +You must specify only one of the following _type_ parameters: + +| _type_ | Abbreviation | Description +| ------- | ------------ | ----------- +| **--system** | **-s** | Specifies the system Path +| **--user** | **-u** | Specifies the user Path + +You must specify only one of the following _action_ parameters: + +| _action_ | Abbreviation | Description +| -------- | ------------ | ----------- +| **--list** | **-l** | Lists directories in Path +| **--test "**_dirname_**"** | **-t "**_dirname_**"** | Tests if directory exists in Path +| **--add "**_dirname_**"** | **-a "**_dirname_**"** | Adds directory to Path +| **--remove "**_dirname_**"** | **-r "**_dirname_**"** | Removes directory from Path + +The following parameters are optional: + +| _options_ | Abbreviation | Description +| --------- | ------------ | ----------- +| **--quiet** | **-q** | Suppresses result messages +| **--expand** | **-x** | Expands environment variables (**--list** only) +| **--beginning** | **-b** | Adds to beginning of Path (**--add** only) + +# Exit Codes + +The following table lists typical exit codes when not using **--test** (**-t**). + +| Exit Code | Description +| --------- | ----------- +| 0 | No errors +| 2 | The Path value is not present in the registry +| 3 | The specified directory does not exist in the Path +| 5 | Access is denied +| 87 | Incorrect parameter(s) +| 183 | The specified directory already exists in the Path + +The following table lists typical exit codes when using **--test** (**-t**). + +| Exit Code | Description +| --------- | ----------- +| 1 | The specified directory exists in the unexpanded Path +| 2 | The specified directory exists in the expanded Path +| 3 | The specified directory does not exist in the Path + +# Remarks + +* Anything on the command line after **--test**, **--add**, or **--remove** is considered to be the argument for the parameter. To avoid ambiguity, specify the _action_ parameter last on the command line. + +* Uexpanded vs. expanded refers to whether the environment variable references (i.e., names between `%` characters) are expanded after retrieving the Path value from the registry. For example, `%SystemRoot%` is unexpanded but `C:\Windows` is expanded. + +* The **--add** (**-a**) parameter checks whether the specified directory exists in both the unexpanded and expanded copies of the Path before adding the directory. For example, if the environment variable `TESTAPP` is set to `C:\TestApp` and `%TESTAPP%` is in the Path, specifying `--add C:\TestApp` will return exit code 183 (i.e., the directory already exists in the Path) because `%TESTAPP%` expands to `C:\TestApp`. + +* The **--remove** (**-r**) parameter does not expand environment variable references. For example, if the environment variable `TESTAPP` is set to `C:\TestApp` and `%TESTAPP%` is in the Path, specifying `--remove "C:\TestApp"` will return exit code 3 (i.e., the directory does not exist in the Path) because **--remove** does not expand `%TESTAPP%` to `C:\TestApp`. For the command to succeed, you would have to specify `--remove "%TESTAPP%"` instead. + +* The program will exit with error code 87 if a parameter (or an argument to a parameter) is missing or not valid, if mutually exclusive parameters are specified, etc. + +* The program will exit with error code 5 if the current user does not have permission to update the Path value in the registry (for example, if you try to update the system Path using a standard user account or an unelevated administrator account). + +# Examples + +1. `EditPath --expand --system --list` + + This command outputs the directories in the system Path, with environment variables expanded. You can also write this command as `EditPath -x -s -l`. + +2. `EditPath --user --add "%LOCALAPPDATA%\Programs\MyApp"` + + Adds the specified directory name to the user Path. + +3. `EditPath -s -r "C:\Program Files\MyApp\bin"` + + Removes the specified directory from the system Path. + +4. `EditPath -s --test "C:\Program Files (x86)\MyApp\bin"` + + Returns an exit code of 3 if the specified directory is not in the system Path, 1 if the specified directory is in the unexpanded copy of the system Path, or 2 if the specified directory is in the expanded copy of the system Path. diff --git a/installers/win/editpath/README.TXT b/installers/win/editpath/README.TXT new file mode 100644 index 00000000..c922ee30 --- /dev/null +++ b/installers/win/editpath/README.TXT @@ -0,0 +1,3 @@ +Editpath installed here is extracted from Release 1.04 from https://github.com/Bill-Stewart/PathMgr. + + diff --git a/installers/win/editpath/i386/EditPath.exe b/installers/win/editpath/i386/EditPath.exe new file mode 100644 index 0000000000000000000000000000000000000000..7e9f2837504767033a8d79a3426170aceffabc60 GIT binary patch literal 116224 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
    N0ib%Ha58wh6#XA9>EHx+I)u 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 literal 0 HcmV?d00001 diff --git a/installers/win/editpath/x86_64/EditPath.exe b/installers/win/editpath/x86_64/EditPath.exe new file mode 100644 index 0000000000000000000000000000000000000000..6e79f1619a498340d624beee62d1c77a3e78b83e GIT binary patch literal 134144 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 literal 0 HcmV?d00001 diff --git a/installers/win/makeflix.iss b/installers/win/makeflix.iss new file mode 100644 index 00000000..d74615b3 --- /dev/null +++ b/installers/win/makeflix.iss @@ -0,0 +1,128 @@ +; -- makeflix.iss -- +; fgh 2016-08-19 + +#define x86_or_x64 "x86" +#define version "1.0.1" + +#if x86_or_x64 == "x86" +#define exe_dir "Win32" +#else +#define exe_dir "x64" +#endif + +[Setup] +ArchitecturesAllowed={#x86_or_x64} +AppName=Makeflix +AppVersion={#version} +AppPublisher=Lellan, Inc. +AppPublisherURL=http://www.lellan.com/ +AppCopyright=Copyright (C) 2012-2017 Lellan, Inc. +DefaultDirName={pf}\Lellan\Makeflix +DefaultGroupName=Lellan +UninstallDisplayIcon={app}\makeflix.exe +Compression=lzma2 +SolidCompression=yes +; "ArchitecturesInstallIn64BitMode=x64" requests that the install be +; done in "64-bit mode" on x64, meaning it should use the native +; 64-bit Program Files directory and the 64-bit view of the registry. +ArchitecturesInstallIn64BitMode=x64 +; Source Dir is lellan/toolchain/makeflix/windows +SourceDir="..\" +OutputDir="deploy" +OutputBaseFilename="makeflix_v{#version}_{#x86_or_x64}" +SetupIconFile="..\images\Lellan_Logo_20130221.ico" +LicenseFile="..\deploy\EULA.rtf" +DisableWelcomePage=no + +[Files] +Source: "makeflix\{#exe_dir}\Release\makeflix.exe"; DestDir: "{app}"; DestName: "makeflix.exe"; Flags: ignoreversion +Source: "deploy\DLLs\{#x86_or_x64}\Qt5Core.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "deploy\DLLs\{#x86_or_x64}\Qt5Gui.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "deploy\DLLs\{#x86_or_x64}\Qt5Widgets.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "deploy\DLLs\{#x86_or_x64}\Qt5Network.dll"; DestDir: "{app}"; Flags: ignoreversion +Source: "deploy\DLLs\{#x86_or_x64}\platforms\qwindows.dll"; DestDir: "{app}\platforms"; Flags: ignoreversion +Source: "deploy\gstreamer\{#x86_or_x64}\*"; DestDir: "{app}\gstreamer"; Flags: recursesubdirs ignoreversion +Source: "deploy\vc_redist\vc_redist.{#x86_or_x64}.exe"; DestDir: "{tmp}"; Flags: deleteafterinstall +Source: "deploy\bonjour\Bonjour.{#x86_or_x64}.msi"; DestDir: "{tmp}" ; Flags: deleteafterinstall + +Source: "..\deploy\Makeflix_Open_Source_Libraries.pdf"; DestDir: "{app}" + +[Icons] +Name: "{group}\Makeflix"; Filename: "{app}\makeflix.exe" +Name: "{group}\Uninstall Makeflix"; Filename: "{uninstallexe}" + + +[Run] +#define VCmsg "Installing Microsoft Visual C++ Redistributable ..." +Filename: "{tmp}\vc_redist{#x86_or_x64}.exe"; StatusMsg: "{#VCmsg}"; Check: not VCinstalled +#define BonjourMsg "Installing Apple Bonjour support ..." +Filename: "msiexec"; Parameters: "/i {tmp}\Bonjour.{#x86_or_x64}.msi"; StatusMsg: "{#BonjourMsg}"; Check: not BonjourInstalled + +[Registry] +Root: HKLM; Subkey: "SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\makeflix.exe"; ValueType: string; ValueName: "(Default)"; ValueData: "{app}\makeflix.exe"; Flags: uninsdeletekey +Root: HKLM; Subkey: "SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\makeflix.exe"; ValueType: string; ValueName: "Path"; ValueData: "{app}\gstreamer\bin"; Flags: uninsdeletekey + +[Code] +function VCinstalled: Boolean; + // By Michael Weiner + // Function for Inno Setup Compiler + // 13 November 2015 + // Modified by Frank G Halasz to handle WOW case + // 23 August 2016 + // Returns True if Microsoft Visual C++ Redistributable is installed, otherwise False. + // The programmer may set the year of redistributable to find; see below. + var + names: TArrayOfString; + i: Integer; + dName, key, year, platfm: String; + begin + // Year of redistributable to find; leave null to find installation for any year. + year := '2015'; + Result := False; + if Is64BitInstallMode then + begin + platfm := 'x64'; + key := 'Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall'; + end + else if not IsWin64 then + begin + platfm := 'x86'; + key := 'Software\Microsoft\Windows\CurrentVersion\Uninstall'; + end + else + begin + platfm := 'x86'; + key := 'Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall'; + end; + // Get an array of all of the uninstall subkey names. + if RegGetSubkeyNames(HKEY_LOCAL_MACHINE, key, names) then + // Uninstall subkey names were found. + begin + i := 0 + while ((i < GetArrayLength(names)) and (Result = False)) do + // The loop will end as soon as one instance of a Visual C++ redistributable is found. + begin + // For each uninstall subkey, look for a DisplayName value. + // If not found, then the subkey name will be used instead. + if not RegQueryStringValue(HKEY_LOCAL_MACHINE, key + '\' + names[i], 'DisplayName', dName) then + dName := names[i]; + // See if the value contains both of the strings below. + Result := (Pos(Trim('Visual C++ ' + year),dName) * Pos('Redistributable',dName) * Pos(platfm, dName) <> 0) + i := i + 1; + end; + end; + end; + + function BonjourInstalled: Boolean; + // Returns True if Apple Bonjour is installed, otherwise False. + // Ignores date/version of Bonjour. + begin + Result := False; + // If this key exists, then + // bonjour services must already be installed + if RegKeyExists(HKEY_LOCAL_MACHINE, 'SYSTEM\CurrentControlSet\Services\Bonjour Service') then + // Uninstall subkey names were found. + begin + Result := True; + end; + end; diff --git a/installers/win/medley.iss b/installers/win/medley.iss new file mode 100644 index 00000000..8e6ade8f --- /dev/null +++ b/installers/win/medley.iss @@ -0,0 +1,65 @@ +;############################################################################### +;# +;# medley.iss - Inno Setup compiler script for creating a Windows +;# installer for the medley.ps1 powrshell script for +;# running Medley within a docker container on Windows +;# +;# 2023-02-12 Frank Halasz +;# +;# Copyright 2023 Interlisp.org +;# +;############################################################################### + +#define x86_or_x64 "x64" +#if GetEnv('COMBINED_RELEASE_TAG') != "" +#define VERSION=GetEnv('COMBINED_RELEASE_TAG') +#else +#define VERSION="local" +#endif + +[Setup] +PrivilegesRequired=lowest +ArchitecturesAllowed={#x86_or_x64} +AppName=Medley +AppVersion={#version} +AppPublisher=Interlisp.org +AppPublisherURL=https://interlisp.org/ +AppCopyright=Copyright (C) 2023 Interlisp.org +DefaultDirName={localappdata}\Medley\Scripts +DefaultGroupName=Medley +Compression=lzma2 +SolidCompression=yes +; "ArchitecturesInstallIn64BitMode=x64" requests that the install be +; done in "64-bit mode" on x64, meaning it should use the native +; 64-bit Program Files directory and the 64-bit view of the registry. +ArchitecturesInstallIn64BitMode=x64 +OutputDir="." +OutputBaseFilename="medley-install_{#version}_{#x86_or_x64}" +SetupIconFile="Medley.ico" +DisableWelcomePage=no +MissingRunOnceIdsWarning=no +DisableProgramGroupPage=yes +WizardImageFile=medley_logo.bmp +WizardSmallImageFile=medley_logo_small.bmp +WizardImageStretch=no +UninstallDisplayIcon="{app}\Medley.ico" + + + +[Files] +Source: "..\..\scripts\medley\medley.ps1"; DestDir: "{app}"; DestName: "medley.ps1"; Flags: ignoreversion +Source: "..\..\scripts\medley\medley.cmd"; DestDir: "{app}"; DestName: "medley.cmd"; Flags: ignoreversion +Source: "editpath\x86_64\EditPath.exe"; DestDir: "{app}"; DestName: "EditPath.exe"; Flags: ignoreversion +Source: "Medley.ico"; DestDir: "{app}"; DestName: "Medley.ico"; Flags: ignoreversion +Source: "vncviewer64-1.12.0.exe"; DestDir: "{app}"; DestName: "vncviewer64-1.12.0.exe"; Flags: ignoreversion +[Icons] +Name: "{group}\Medley\Uninstall_Medley"; Filename: "{uninstallexe}" +Name: "{group}\Medley\Medley"; Filename: "powershell"; Parameters: "-NoExit -File {app}\medley.ps1 --help"; IconFilename: "{app}\Medley.ico" + + +[Run] +Filename: "{app}\EditPath.exe"; Parameters: "--user --add {app}"; Flags: runhidden + +[UninstallRun] +Filename: "{app}\EditPath.exe"; Parameters: "--user --remove {app}"; Flags: runhidden + diff --git a/installers/win/medley_logo.bmp b/installers/win/medley_logo.bmp new file mode 100644 index 0000000000000000000000000000000000000000..9efbe3af85d96a9cf986caa18c870c352c517bff GIT binary patch literal 54054 zcmeI*1+Xkddj??K-QC?K5Znpw?(Xgo++A~V3GVI=A-KD{yE}wGPyViSb?AfGee}^KmRMrpg%|#}7Rus_FTUuai{5F?*Cf9}q^@4g%BggYO9{INUUefHUBUwiE}&4vnp{PBl7O1xvtFTVKV zbI(2Z^UptrI=}q#%bRb$dHe0RUw!q}CgtgO-+dQf4`cY|n{UD$f4yj&FTecqufP5p zZ^jEZpLyn)|E?%@lTJO=_|s26{mwh@gw->tS6_Yg&O7ha`*qh{_s~NRefHUBh8-G& z4aCyj0}niK?X}n5efQml8s`!_ZOg@7cipAC-FM&pKU*jV9B{zgbI*O@g%?`Ys-rSB z9c{VgmUGQD*HlwYHTmR|>vX{d7uLE+<_tk+jP@S1Ds6ZqKhtCV~sWb<)6j8mR)w)6HYh*gH_*Kr=511 z9+5h{?(e6ce!9#u%j~)5o?sbo#tZn@nz@+!zb0kA`R3bdtF6%83aD`M$tN2dU;x9) zE3Z7`j5E$T=bU<9Y_Y|({N$5QhV5YWW}bOw1EzHtpbDF9wizJRTKPDPCN7Z7nC+1! z-i@!|21_ovWG!r%l=iL4xZ{qy-g@hub=Fx3cj~F9uD<%}(@ZlBhGPq8O0|3Mz1ND( zJMX;k;1#T6AckDPSUNiV+m;;=*gMaPLJo>=`j7{eHS^wG~e z^GtUPY}Q$4g#@f7R6r?r7FuYbufP5}+`*>&1SbdtIpCaWrkSky8E2ef43}Pd>GI1j zKkc;B9((Mu>O;tW`|UT`WRrOmUiTL#aR=mLFY%F!H{N(dgX51sK7#&xQXtk)ZHIgA zxo4JHX3;EYz5e>^E3LGWjibBUZo3W6_uY42ukW$P9s%A{OfkiXBaR3#meIaA>7Jmio= z!d~!{JijSai|rI%icZKf9~HtZvM2qC2cCg$RtbIzG)qKQBYHh_Ulu|%nUMPnpfR7l%w z%XQhM2x>4*%!n*MKpsA z+BkW1&_M^83v5g>$s`z25IWu^vg_&_>#x6l?47~C8e|Hz^@t7Y7KZI<5q+Z|-#|5N1fv*cm|^G@7G%Q>H)O3uL&=?0R#_z~OM1s@ zXu_5#OsDQ&yvRhTH+2gQS$E}OgSaF$NJ&J=A2u2htbjzvh&8Q0j)5*TL)Wko6q2xs zV8b-sIrPv&ZMX0iTV}M;Mx(0v8FW$F9pHthgvAUq%s|zQQ?t!Bn;C7t{q_`5 zGVaG8e>7PIY_x`N7;2o3JH}5Pq9di9=3KLb2%zbwpML43mj^;ez&3#dtAR!cXClF7gblli?g~gqX8SOoM;d7)<`34YKD1!J>Rfi& zWqJwNU=L!^mRFlR12hNBhuue_dFB55@5f0j5i7$OR$OsK^)J8t@<4jlx5cE0Dt27J zh8~#@=;(FB&=iS7bY{3sm}W!Rpq~S$2^y`}sT{nLc84yoO?T`v$iyv!vT6$U!h{n} zxb@ashwkeBH67?;$C--(=M?^>Qe_H+GjAz)mMDMN=1xnu1!$z;ao>ISF(+|U6KCMt zK3)&lV75?DZ7XgK*hXuHFb?U?C6`>{jy;ZFsUNVR1!Bc|+5*-Pa!lDB+P+uZF+8+J z4$xvCPdD9k{DB$=8)}mMg)LAyG#Ic!?vP5y9CHlGg5fi5sM9J$-j&X@A#A|B?revv zuDXg{gF1vPv)#NRHXsvsH62v;*K)xvy)o@H=Q?16Tn;{>oSJ3pqV^h9lY&QWux&FV zv6xnXrj7KTQd}(pGaR>Wh3iHhpp|#5HpzL0I?G<+Y zQ%^l*88_HqgPnHTi4y=ruq(BXpzsC&?%*MyWy2bbG2kAw3j_+ib2RaOz$8={JSFhB zrQJkejC!QH}gCg_lk9F!|BLsc8HzT_%b(&p;4KuYPgeiH* znP4n&Hs;79kIY@O)>>-?L0{@>^ljsHu|Z1GTjF7FTx_Ut4CS{4K^b*)5fVf^rc$rN?Nlm*9~EVK}YjpY&KmO zgBqbg2J4_LQ|PNkAeLGi?Sj4_o1W@~G2+ zma#sJsA^$kF@B5qHzW=*`319h_9_d-pw^?bvO1hUTodfC4otkfF7S5F6aEU`nDTll zyJg&)(~lFcYT-%d)hU7vhCdZi!mr2;d~l6wX6#-Xhq5F%Br=wX(3S`0IH5M4&34X6}dv*7Cqeb>my+1IOqP zRChQwe-w@v>C0M?K^l!Xv*Yy=N8{=VZ*iFtlwt=wX?#9(`&gMv(CZjryrWqyaDqwo zr0yCRe~}7E?~yw)@i?VVIpvfSPdt&bO z&#W`WjKHP{Hge`@0asXI1zBt@asxg_P7LuQL{UUD1tWN#qbt%FB#vTG0%5KReNVA0 zG;$v{I7`Kw_=kD0RpT2sJ5hUpR9}=$HRkXOFT4<^gQ<$QYRBL?EoEkkIK#6F0K?6q zeIYgjvyXUMxEb{luwh%tk?=@IiVJ@GGF9J6B7^~vBxSf(S&35sPMzJBm2BpYKvJ9O3Wgv?^@uHwCFhC3N+tCnZ zvp0kd5)DXrV?vNZYg{h$PiO(TfDNF+h+KQBM>*cu6jQFhSm<@JfmPZd@^b&9*>c!n zhlz%_E>jxC1{XRbOAIcg-w;XcAh|Axh}DF`l|+=dgJCv=4X<-Qil&inXpNId)j)cI zdvZBo1Je*bi@QcmnP4&jFtK>En=k5O!?qe~sG(#Un03>I4O<>IQiC^@DH&`~sLX;& zz^g1ApO$cRr6FvfDPAN^f;YyY033-iE+wIQeTW-PKdZ|db4Y<^RXdr zEA&ZolK_xkoc`dps#=HcM_VIy@zqw=p(@{yOOvu_nj{5-)X-4|8}yUG2Ok{yj0e?1 zF<>;MtWpvJHb@H0KaR7OzM%pwg3Ll|IX~Kw%SWGK*N`9)8)Q~&%7uhy17Jy|H@o&a z9~+ph#bKt^EtZrdrKMM`iM3MxG1XSqp%NPu%OE3Svouvv+F++-uz{09FNM(kXgGre z+~SSYhJXz}O*sy=7BX?rupvPRSBXs#TV4Sqc6S_bH(%sq zqxi@r-Em^XbtwK~@tT#`u+EMRQka8SVQOJ<><$)+W;58Ji{gRQCteYhRROUi>HrLq zMSa6hB8FAV-GL+3!UiPBo6?t%Uzjz$g~(tN@xugc&_$_g?&Bo7TN5{)dtMr6zq6Sz8>QacHEXh9&FfQ6zAa4!%mlnrtOD%8i05ZY6U zC9RS+>o3SLDELk@*pN+1uVBEc&)oqDjAHQ91(pR-A=?u+C_;wEailwHi3Go!4q$jn?&A^|I5QTCpu$RG{;1|Hchr|cDPbl6 z!&8C=Wwqv}reH?nDK>B(VI%A%Xus;yTW};65Yq$mA&G*%O~w&nIx-AcrF^PD`V`O9 zEt~E|+V7{>$V`nni6|LuC!=q~S0G1ykjT_eD|o7oJ1I8YM17v~pss}a8gXBVuV*fF zXKXnYGWGlXrvZlo8$KCP%P(4doE_6e9WD!0t2;K?gG2x&q?H^w*dUd7=Fyi{N!*B` zxTxEE|E<8E911@_yRTnhL)b$2L)5s|e$S8t_^AX;*PJ}M%qx{Y89}6yNG?E9NZ1{e z3X-C-=76~)7ni%ntm#pd`F?>7`adp*E{NVSLIkHe-?$#J4tfhuNT~usFVvNS_%CA} zB<%~$v-@byv}pDh2I3%3(}ka*Z2v|X>(Etg!UKJVaV^gZA-HP_O3(Jr!bu-7Wo_Dt zj{LCGnSnskbYb!Ju+buom_OVgys0=jauSaZ%n23M~qYDEyRD4s5w}%T+K+}sfmh>|tjgF^R-wH5| zxkLmCtt6$FY7>tb`pVL zgT!YU<+RrJNBtBVSgtRb$Op!?(lz1ShEhp8a<0<*{OZ!b-LFii!RUC!tv|77hf=~_ z+oas!ppu~-U$>3y;~TO`g+;_|#n;%gLTm;T4=8!j_Z)ObrA&w68m-;rh?7&QJ7%5l zJ4q?Qb*oy$5GX__@Fy{b37KiF)Svwn8&dj>oK1wRaeXW!VAx{*lLvlF3^_i6B_E-6 zUpy|}biwb(WvVGDZS-&lrU-XoQ?!te;jPpw&bc8!T&KRP#z(4-7iBevvm0KdZiU8q zVCZ1F(@5+N=^@$nA8xqebSGA;DR0rvqyh3=>v3=o+oTGqY;S?wH{V89bb7!K`wyp}x4hfngeCO33<%G}Qt{!r>+wh=hSSW)&b76bT*r ziP5?sq*Cz2M#{JtFxVg<#0q_{7!f7i(cEPIOMwoHmca&MNzCANv|Dix#(QRMNf57i zot{aJVS=G7066y-GCd*oqw7K- z*1;R5yR`T6t_KD-EF&91j+SMVu7lQ2qhQ6PdDw;-Y}l%d1#$ z$OxsQI>8M#8FFxF^K9o}LwEQO93n0?qgG$;r#T^JLA8cws+Mrf1j(2Z6j5erYPkf8 zuy&=M=3oQ5j0f9cZaC&pwWDy8bsP_98?($(uTY2F#JdO-VnrTo%3jJqMQF2K*r4!J z+No0I4K-~!W5e3Hj0=lT-=pTK>709@I5y&E1{>&$OXC|<2s9;J$e^@9f^AO2bdZ*M zpnZ`qcaSO72f~m%m9?IO4clDe2duI+n8|5J;o5oL&>d|gSR!7L%81WUP+gEp`r@=P zM^YxW+`|~k_zN2}Vb)*MMG#pwCT-s=EL|CctZXyIMv%*B$E+aM!!p`gzUe_^P*5@F z3^uGh^$#Q{0MdZji45MfpaN9D294C7Rq%6s$0gK zTpJ8OnC@gm2jvIC^+i>d#iaeP0w%?t#qQ)McfboxbGE8_Y`QQQt#HWkX8Kjqv5Y$@ zHrNqP8Q7J4jPbt|!Nxf&I1TUJhFO?)%og#lf16KKf|H4L1>sK;dS$<#YIk!BBggPq9|c zAn>{~Oakq+gBx(NSwll*gBSp@g_#2qT}W!WULv7ovlE46Q22iw;{7r%I05Vh;=uN& z+tYIzEnJaa6s@3-bsihc6AlLo9xIZY(WZ;5go4)GO2PmSRmNwoCU=%7AwKUBM#N&} z1r-@*1>3V|4e&Aj7;oVTK`-ZDn7tSaI7^2uT{eqxvFH$TfyioRJHUutz|mB$s`Vfd+1C=#JPGQMC)2E{+Iw9vhrRmehjl z9c9yH@Ru@L?FEbl zOo!=vdtuxw~jGHAD zjayPY8LO>!`0qCZev*)?^sVPLvrVo)KlYc1%GR>SkjXcC`| z-KoR+CWC0LaXR4wRIn_OVxLW;LZ{*;Q?vD-{TdtWLAoNMFcYNR#f>KA%WUB%O)2}Kv z(zl8)by~9_Y&6$h`c}uT`!zN=f+&ZS4Lr80VrF))2cU z8XJM!v`zB5){0@^#0rHZRLhg*sH~yKGP-MJs13c_UTp9QaFSFOhCr#-Rzp+nRW7&! zZN!GeB%U0Gd8TkZNtWn9Y^dOrd({fAKpU~a_r)j77nByBQc+s@`Bm+Rf`hDEjZ6_q zujE&a-XW@Dq@!-91HM9gvB6m<+LadGAx>8ws`9Ww+vG|TU*N73hG?Y-w#G9i1D^DC zCm687vF~GO9L2tn)?5*OVhdENNpy1jnk&NJQcO+1?xOuo zDg|rBPFk(aSQS2{M z1h_>QGdHXL6tm!a>?^(j8@wEX^{rS#oFsyq{@U?MYMXknt}7YP`WDjBej8@R4jxi0W}`bK8)bAGlF8>|>9 za1yj?6;3nu5mPiX9*zr`$uH7wS+DZ6Wrw=1T3Hr{RGCcUnV&suWELdnXB)90&O%Lf zK%iC;2xB8uVgsRt;NglxKBvg^mRyHBRjnf%Q1VZuo}8I`4;z^U$@$qvY}ECAN!mm~ z2Ykdd)8cC+@+uu7a84~#xFckG*DdnFXgkt-qZLM$<)j*ZFb$zlV)(qi-wYfen5Mr!reC61<%S>sxG4U-`#4 z@N^vMk(~UTz_Miu2Ix$;FRJAfERI>! z!$uKoIEcqN;5!vL#eq#cf$PaPi>Ma0YR1#(wfZd^8{`@QJ0qD>LPA0h8?|WE=zRw^ zc@G>kb`YR$z#^ydva#XVW6+(rPiqz5WpX0E!{3F@S(E<$sJ~!C#-J~5)per!!Vj-( zeXaGbJ&d)OEls0gzN*kA?JwGeZRM~@si=UZq98$N}^rl?!E zyyX0_vg^iS2NGSnVJ@)2uVu?~ARunt;=>5xP(!As*V&l9b5&$gA=V~#@3d5rqNal< zJ!}+N+cwsrT}bkDgu&NQ>K4gePMk^7aMH~e{4(_=@bJVI8C$@H&-E1f8fy6bsZM*? zD6+Qgt-~rTsDDyc<$rRm(@&hW_c`da_@9f32_J2%Tf+ZwAeGA@&4Pura!R+o6YsUw z#ubnO?ti0@Hq1L+`MvkzcVv({L+4A3BwE3u>o!iL*HqhAAYg;7>MOoJ?$=5Y+dbfb N1KK{qUW4fh{4ahnDiHtx literal 0 HcmV?d00001 diff --git a/installers/win/medley_logo.png b/installers/win/medley_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..24c466b676ca8b5674232599cded655a7c15d39f GIT binary patch literal 10272 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 mRS=lq88 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 literal 0 HcmV?d00001 diff --git a/scripts/medley/medley.cmd b/scripts/medley/medley.cmd new file mode 100644 index 00000000..9fdbeef5 --- /dev/null +++ b/scripts/medley/medley.cmd @@ -0,0 +1,3 @@ +@echo off +powershell medley.ps1 %* + diff --git a/scripts/medley/medley.ps1 b/scripts/medley/medley.ps1 new file mode 100755 index 00000000..87021c74 --- /dev/null +++ b/scripts/medley/medley.ps1 @@ -0,0 +1,410 @@ +############################################################################### +# +# medley.ps1 - PowerShell script for running Medley Interlisp in a Docker +# container on Windows. This script will pull the +# interlisp/medley docker container, run the container +# using the Linux medley script as the entrypoint +# passing on the flags as given to this script, and +# then start a vncviewer onto medley running in the +# container. +# +# This script can also be used to start medley in a WSL +# distro, although the same can easily be accomplished +# using the wsl command. +# +# 2023-02-10 Frank Halasz +# +# Copyright 2023 Interlisp.org +# +############################################################################### + + +# +# Various useful functions +# + +# Function to check if docker is installed on this system +function Test-DockerInstalled { + $ErrorActionPreference = "SilentlyContinue" + if (Get-Command "docker" -Syntax) + { return $true } + else + { return $false } +} + +# Function to check if docker is running on this system +function Test-DockerRunning { + $ErrorActionPreference = "SilentlyContinue" + docker info 2>&1 >$null + if ( $LastExitCode -eq 0 ) + { return $true } + else + { return $false } +} + +# Function to test if WSL is installed on this machine +function Test-WSLInstalled { + #$ErrorActionPreference = "SilentlyContinue" + if ((Get-Command "wsl" -Syntax) -and + (((wsl --list --verbose) -replace "`0" | Measure-Object -Line | Select -ExpandProperty Lines) -gt 1)) + { return $true } + else + { return $false } + +} + +# Function to test if a named WSL distro is actually present +function Test-WSLDistro { + param($distro="unknown") + $paddedDistro= " " + $distro + " " + if ( (wsl --list --verbose) -replace "`0" | Select-String -Pattern $paddedDistro ) + { return $true } + else + { return $false } +} + +# Function to test if medley is installed (using standard installation) +# in the wsl distro whose name is the first and only arg. Defaults +# to the default wsl distro +function Test-MedleyInstalled { + param($distro) + if($distro -and (-not (Test-WSLDistro $distro))) + { + return $false + } + if ($distro) + { + $is_installed = wsl -d $distro bash -c "test -e /usr/local/interlisp; echo \`$?" + } + else + { + $is_installed = wsl bash -c "test -e /usr/local/interlisp; echo \`$?" + } + if ($is_installed -eq 0) + { + return $true + } + else + { + return $false + } +} + +# Function to find an unused port between 5900 and 5999 +function Find-OpenPort { + $min_port=5900 + $max_port=5999 + $udp_openPorts = Get-NetUDPEndpoint | Where-Object { ($_.LocalPort -ge $min_port) -and ($_.LocalPort -le $max_port) } + $tcp_openPorts = Get-NetTCPConnection | Where-Object { ($_.LocalPort -ge $min_port) -and ($_.LocalPort -le $max_port) } + $openPorts = ($udp_openPorts + $tcp_openPorts) | Select-Object -Property LocalPort | Sort-Object -Property LocalPort -Unique + $expected=$min_port; + foreach ($port in $openPorts) + { + if ( $port.LocalPort -ne $expected ) + { + break; + } + else + { + ${expected}++ + } + } + if ($expected -gt $max_port) + { + Write-Output "Error: No available ports between 5900 and 5999." + Write-Output "Exiting." + exit 34 + } + else + { + return $expected + } +} + + +# +# Function that processes all the arguments to this script +# +function Process-Args { + + # Default values for script-scoped varaibles + $script:bg = $false + $script:draft = "latest" + $script:logindir = "${env:USERPROFILE}\AppData\Local\Medley\il" + $script:medleyArgs = @() + $script:noviewer = $false + $script:port = $false + $script:update = $false + $script:wsl = $false + $displayFlag = $false + $display = "" + + # Variables local this function + $passRest = $false + $vncRequested = $false + + # Loop thru args + for ( $idx = 0; $idx -lt $args.count; $idx++ ) { + $arg = $args[$idx] + if ($passRest) + { + $script:medleyArgs += $args + continue + } + switch($arg) { + { @("-b", "--background") -contains $_ } + { + $script:bg= $true + } + { @("-d", "--display") -contains $_ } + { + $displayFlag = $true + $display = $args[$idx+1] + if ( ($idx + 1 -gt $args.count) -or ($display -match "^-") ) + { + Write-Output "Error: the `"--display`" flag is missing its value" "Exiting" + exit 33 + } + if ( $display -notmatch ":[0-9]+" ) + { + Write-Output "Error: the `"--display`" value is not of the form `":N`, where N is number between 0 and 63: $display" "Exiting" + exit 33 + } + } + { @("-h", "--help", "-z", "--man") -contains $_ } + { + $script:noviewer = $true + $script:medleyArgs += $_ + } + { @("-p", "--port") -contains $_ } + { + if ( ($idx + 1 -gt $args.count) -or ($args[$idx+1] -match "^-") ) + { + Write-Output "Error: the `"-p / --port`" flag is missing its value" "Exiting" + exit 33 + } + $script:port = $args[$idx+1] + if (( $script:port -notmatch "^[0-9]*`$" ) -or ( $script:port -le 1024) -or ( $script:port -gt 65535 )) + { + Write-Output "Error: the value of `"-p / --port`" flag is not an integer between 1025 and 65535: $script:port " "Exiting" + exit 33 + } + $idx++ + } + { @("-u", "--update") -contains $_ } + { + $script:update = $true + } + { @("-v", "--vnc") -contains $_ } + { + $vncRequested = $true + } + { @("-w", "--wsl") -contains $_ } + { + if (-not (Test-WSLInstalled)) + { + Write-Output "Error: The `"-w / --wsl`" flag was used, But WSL is not installed." "Exiting" + exit 33 + } + if ( ($idx + 1 -gt $args.count) -or ($args[$idx+1] -match "^-") ) + { + Write-Output "Error: the `"--wsl`" flag is missing its value" "Exiting" + exit 33 + } + $script:wsl = $true + $script:wslDistro = $args[$idx + 1] + if (($script:wslDistro -ne "-") -and (-not (Test-WSLDistro $script:wslDistro))) + { + Write-Output "Error: value of `"--wsl`" flag is not an installed WsL distro: $script:wslDistro." "Exiting" + exit 33 + } + if (-not (Test-MedleyInstalled $script:wslDistro)) + { + Write-Output "Error: value of `"--wsl`" flag is an installed WsL distro, but Medley is not installed in standard location: $script:wslDistro." "Exiting" + exit 33 + } + $idx++ + } + { @("-x", "--logindir") -contains $_ } + { + $script:logindir=$args[$idx+1] + $idx++ + } + { @("-y", "--draft") -contains $_ } + { + $script:draft="draft" + } + { $_ -eq "--" } + { + $passRest=$true + $script:medleyArgs += $_ + } + default + { + $script:medleyArgs += $_ + } + } + } + if ($script:logindir) + { + if ($script:wsl) + { + $script:medleyArgs = @( "--logindir", $script:logindir) + $script:medleyArgs + } + } + if ($script:update -and $script:wsl) + { + Write-Output "Warning: Both the -u or --update flag and the -w or --wsl flags were given. " + Write-Output "The -u or --update flag is not relevant for wsl." + Write-Output "Ignoring the -u or --update flag." + } + if ($vncRequested) + { + if (-not $script:wsl) + { + Write-Output "Warning: The -v or --vnc flag is not relevant when running under docker" + Write-Output "Ignoring the -v or --vnc flag." + } + else + { + $script:medleyArgs = @( "--vnc") + $script:medleyArg + } + } + if ($script:wsl -and $displayFlag) + { + $script:medleyArgs = @( "--display", "$display") + $script:medleyArg + } +} + + + +############################################################################### + +# +# Main script +# + +# +# Process the arguments +# +Process-Args @args + +# +# If we're not calling wsl, check if docker is installed and running, +# check if logindir is a legitamte directory, do the pull if required. +# +if (-not $wsl) + { + # Make sure docker is installed + if (-not (Test-DockerInstalled) ) + { + Write-Output "Error: Docker is not installed on this system." + Write-Output "This medley app requires Docker unless the --wsl flag is used" + Write-Output "Exiting." + exit 34 + } + # Make sure docker is running + if (-not (Test-DockerRunning) ) + { + Write-Output "Error: The Docker engine is installed but not currently running on this system." + Write-Output "This medley app requires the Docker Engine running unless the --wsl flag is used" + Write-Output "Exiting." + exit 33 + } + # Check/create logindir + if (-not (Test-Path -Path $logindir -PathType Container)) + { + try + { + $null = New-Item -ItemType Directory -Path ${logindir} -Force -ErrorAction Stop + } + catch + { + Write-Output "Error: The specified logindir does not exist and cannot be created: ${logindir}" + Write-Output "Exiting." + exit 35 + } + } + # Do a pull if required + if ($update -or (-not (docker image ls interlisp/medley:${draft} | Select-String medley))) + { + docker pull interlisp/medley:${draft} + } + } + +# +# Call wsl or run docker +# +if ($wsl) + { + # + # Call wsl + # + if ( $wslDistro -eq "-" ) + { + $distro = @() + } + else + + { + $distro = @( "-d", $wslDistro ) + } + wsl @distro medley @medleyArgs + } +else + + { + # + # Run docker and vncviewer + # + + # Find an open port to use for vnc + if (-not $port) { $port=Find-OpenPort } + Write-Output "Using VNC_PORT=$port" + + + # Unless $noviewer is set (i.e., if --help and --man flag are set), + # start the vncviwer in the background. + # But wait for the docker container to actually come up + # before starting it + if (-not $noviewer) + { + Start-Job -InputObject "$port" -ScriptBlock { + $port = $input.Clone() + $stopTime = (Get-Date).AddSeconds(10) + $hit=$false + while ((-not $hit) -and ((Get-Date) -lt $stopTime)) + { + docker container ls | Select-String 'medley' | Select-String "${port}->5900" | Set-Variable "hit" + if (-not $hit) { Start-Sleep -Milliseconds 250 } + } + if ($hit) + { + Write-Host $hit + vncviewer64-1.12.0.exe -geometry '+50+50' -ReconnectOnError=off −AlertOnFatalError=off localhost:${port} + } + } >$null + } + + # + # Run the docker container using medley as the entrypoint and passing on the args + # Run in the foreground unless requested to run in the background by the -b flag. + # + + if (-not $bg) + { + docker run -it --rm -p ${port}:5900 -v ${logindir}:/home/medley/il --entrypoint medley --env TERM=xterm interlisp/medley:${draft} --windows @medleyArgs + } + else + { + $dockerArgs=@("run", "--rm", "-p", "${port}:5900", "-v", "${logindir}:/home/medley/il", "--entrypoint", "medley", "interlisp/medley:${draft}", "--windows") + $medleyArgs + Start-Process -NoNewWindow -FilePath "docker" -ArgumentList $dockerArgs + } + } + +############################################################################### +# +# Done +# +############################################################################### + diff --git a/scripts/medley/medley.sh b/scripts/medley/medley.sh index 0fb942e9..e8f54761 100755 --- a/scripts/medley/medley.sh +++ b/scripts/medley/medley.sh @@ -56,13 +56,39 @@ export MEDLEYDIR=$(cd ${SCRIPTDIR}; cd ../..; pwd) IL_DIR=$(cd ${MEDLEYDIR}; cd ..; pwd) export LOGINDIR=${HOME}/il -# Are we running under WSL? -grep --ignore-case --quiet wsl /proc/sys/kernel/osrelease -if [ $? -eq 0 ]; +# Are we running under Docker or if not under WSL? +if [ -n "${MEDLEY_DOCKER_BUILD_DATE}" ]; then - wsl='true' -else + docker='true' wsl='false' +else + docker='false' + wsl_ver=0 + # WSL2 + grep --ignore-case --quiet wsl /proc/sys/kernel/osrelease + if [ $? -eq 0 ]; + then + wsl='true' + wsl_ver=2 + else + # WSL1 + grep --ignore-case --quiet microsoft /proc/sys/kernel/osrelease + if [ $? -eq 0 ]; + then + if [ $(uname -m) = x86_64 ]; + then + wsl='true' + wsl_ver=1 + else + echo "ERROR: Running Medley on WSL1 requires an x86_64-based PC." + echo "This is not an x86_64-based PC." + echo "Exiting" + exit 23 + fi + else + wsl='false' + fi + fi fi # process args @@ -79,7 +105,7 @@ then exit 3 fi -# Set the LDEDESTSYSOUT env variable based on id +# Set LDEDESTSYSOUT env variable based on id if [ -z ${LDEDESTSYSOUT} ]; then if [ "${run_id}" = "default" ]; @@ -104,12 +130,12 @@ fi mkdir -p ${LOGINDIR}/vmem # Call run-medley with or without vnc -if [[ ${wsl} = false || ${use_vnc} = false ]]; +if [[ ( ${wsl} = false || ${use_vnc} = false ) && ${docker} = false ]]; then # If not using vnc, just call run-medley - ${MEDLEYDIR}/run-medley -id "${run_id}" ${geometry} ${screensize} "${run_args[@]}" + ${MEDLEYDIR}/run-medley -id "${run_id}" ${geometry} ${screensize} ${run_args[@]} else - # do the vnc thing on wsl + # do the vnc thing on wsl or docker source ${SCRIPTDIR}/medley_vnc.sh fi diff --git a/scripts/medley/medley_args.sh b/scripts/medley/medley_args.sh old mode 100644 new mode 100755 index 10a05d5c..7275d0db --- a/scripts/medley/medley_args.sh +++ b/scripts/medley/medley_args.sh @@ -14,27 +14,53 @@ # load usage function source ${SCRIPTDIR}/medley_usage.sh -# Process args +# Defaults +apps_flag=false +err_msg="" +full_flag=false +geometry="" +greet_specified=false +lisp_flag=false +noscroll=false +pass_args=false run_args=() run_id="default" -use_vnc='false' -geometry="" screensize="" -noscroll='false' -pass_args=false -lisp_flag=false -full_flag=false -apps_flag=false sysout_flag=false sysout_arg="" -err_msg="" -greet_specified='false' +use_vnc=false +windows=false +# Loop thru args and process while [ "$#" -ne 0 ]; do if [ ${pass_args} = false ]; then case "$1" in + -a | --apps) + sysout_arg="apps" + apps_flag=true + ;; + -d | --display) + check_for_dash_or_end "$1" "$2" + run_args+=(-d $2) + shift + ;; + -e | --interlisp) + export MEDLEY_EXEC="inter" + ;; + -f | --full) + sysout_arg="-full" + full_flag=true + ;; + -g | --geometry) + check_for_dash_or_end "$1" "$2" + geometry="$2" + shift + ;; + -h | --help) + usage + ;; -i | --id) if [ "$2" = "-" ]; then @@ -48,6 +74,47 @@ do fi shift ;; + -k | --vmem) + check_for_dash_or_end "$1" "$2" + check_file_writeable_or_creatable "$1" "$2" + export LDEDESTSYSOUT="$2" + shift + ;; + -l | --lisp) + sysout_arg="-lisp" + lisp_flag=true + ;; + -m | --mem) + check_for_dash_or_end "$1" "$2" + run_args+=(-m $2) + shift + ;; + -n | --noscroll) + noscroll=true + run_args+=("-noscroll") + ;; + -r | --greet) + if [[ "$2" = "-" || "$2" = "--" ]]; + then + run_args+=("--nogreet") + else + check_for_dash_or_end "$1" "$2" + check_file_readable "$1" "$2" + run_args+=("-greet" "$2") + fi + greet_specified='true' + shift + ;; + -s | --screensize) + check_for_dash_or_end "$1" "$2" + screensize="$2" + shift + ;; + -t | --title) + check_for_dash_or_end "$1" "$2" + run_args+=(-title $2) + shift + ;; -v | --vnc) if [[ ${wsl} = true && $(uname -m) = x86_64 ]]; then @@ -60,68 +127,6 @@ do use_vnc=false fi ;; - -g | --geometry) - check_for_dash_or_end "$1" "$2" - geometry="$2" - shift - ;; - -s | --screensize) - check_for_dash_or_end "$1" "$2" - screensize="$2" - shift - ;; - -n | --noscroll) - noscroll=true - run_args+=("-noscroll") - ;; - -e | --interlisp) - export MEDLEY_EXEC="inter" - ;; - -a | --apps) - sysout_arg="apps" - apps_flag=true - ;; - -f | --full) - sysout_arg="-full" - full_flag=true - ;; - -l | --lisp) - sysout_arg="-lisp" - lisp_flag=true - ;; - -m | --mem) - check_for_dash_or_end "$1" "$2" - run_args+=(-m $2) - shift - ;; - -t | --title) - check_for_dash_or_end "$1" "$2" - run_args+=(-title $2) - shift - ;; - -d | --display) - check_for_dash_or_end "$1" "$2" - run_args+=(-d $2) - shift - ;; - -r | --greet) - if [[ "$2" = "-" || "$2" = "--" ]]; - then - run_args+=("--nogreet") - else - check_for_dash_or_end "$1" "$2" - check_file_readable "$1" "$2" - run_args+=("-greet" "$2") - fi - greet_specified='true' - shift - ;; - -p | --vmem) - check_for_dash_or_end "$1" "$2" - check_file_writeable_or_creatable "$1" "$2" - export LDEDESTSYSOUT="$2" - shift - ;; -x | --logindir) if [[ "$2" = "-" || "$2" = "--" ]]; then @@ -134,13 +139,14 @@ do fi shift ;; - -h | --help) - usage - ;; -z | --man) /usr/bin/man -l "${MEDLEYDIR}/docs/man-page/medley.1.gz" exit 0 ;; + --windows) + # internal: called from Windows medley.ps1 (via docker) + windows=true + ;; --) pass_args=true ;; @@ -190,15 +196,23 @@ then fi if [ "${sysout_arg}" = "apps" ]; then - export LDESRCESYSOUT="$MEDLEYDIR/loadups/apps.sysout" + export LDESRCESYSOUT="${MEDLEYDIR}/loadups/apps.sysout" if [ "${greet_specified}" = "false" ]; then - export LDEINIT="$MEDLEYDIR/greetfiles/APPS-INIT.LCOM" + export LDEINIT="${MEDLEYDIR}/greetfiles/APPS-INIT.LCOM" fi else # pass on to run-medley - export LDESRCESYSOUT="" - run_args+=("${sysout_arg}") + unset LDESRCESYSOUT + if [ -n "${sysout_arg}" ]; + then + run_args+=("${sysout_arg}") + fi fi +# if running on WSL1, force use_vnc +if [[ ${wsl} = true && ${wsl_ver} -eq 1 ]]; +then + use_vnc=true +fi diff --git a/scripts/medley/medley_usage.sh b/scripts/medley/medley_usage.sh index 00ccb0b8..a0397b84 100644 --- a/scripts/medley/medley_usage.sh +++ b/scripts/medley/medley_usage.sh @@ -17,6 +17,34 @@ usage() { local err_msg local msg_path=/tmp/msg-$$ local lines=("$@") + + if [ ${wsl} = true ]; + then + wsl_incl="+w" + wsl_excl="-w" + else + wsl_incl="-w" + wsl_excl="+w" + fi + + if [ ${docker} = true ]; + then + docker_incl="+d" + docker_excl="-d" + else + docker_incl="-d" + docker_excl="+d" + fi + + if [ ${windows} = true ]; + then + windows_incl="+W" + windows_excl="-W" + else + windows_incl="-W" + windows_excl="+W" + fi + if [ $# -ne 0 ]; then echo > ${msg_path} @@ -26,7 +54,12 @@ usage() { else touch ${msg_path} fi - cat ${msg_path} - </dev/null + if [ $? -eq 1 ]; + then + result=${ctr} + break + else + (( ctr++ )) + fi fi done echo ${result} @@ -40,8 +48,13 @@ local result=-1 while [ ${ctr} -lt 6000 ]; do - ss -a | grep -q "LISTEN.*:${ctr}[^0-9]" - if [ $? -ne 0 ]; + if [[ ${wsl} = true && ${wsl_ver} -eq 1 ]]; + then + netstat.exe -a -n | awk '{ print $2 }' | grep -q ":${ctr}\$" + else + ss -a | grep -q "LISTEN.*:${ctr}[^0-9]" + fi + if [ $? -eq 1 ]; then result=${ctr} break @@ -53,102 +66,185 @@ } # - # Make sure prequisites for vnc support are in place + # Make sure prequisites for vnc support in wsl are in place # - win_userprofile="$(cmd.exe /c "/dev/null)" - vnc_dir="$(wslpath ${win_userprofile})/AppData/Local/Interlisp" - vnc_exe="vncviewer64-1.12.0.exe" - if [[ $(which Xvnc) = "" || $(Xvnc -version |& grep -iq tigervnc; echo $?) -eq 1 ]]; + if [ "${use_vnc}" = "true" ]; then - echo "Error: The -v or --vnc flag was set." - echo "But it appears that that TigerVNC \(Xvnc\) has not been installed." - echo "Please install TigerVNC using \"sudo apt install tigervnc-standalone-server tigervnc-xorg-extension\"" - echo "Exiting." - exit 4 - elif [ ! -e "${vnc_dir}/${vnc_exe}" ]; - then - if [ -e "${IL_DIR}/wsl/${vnc_exe}" ]; + win_userprofile="$(cmd.exe /c "/dev/null)" + vnc_dir="$(wslpath ${win_userprofile})/AppData/Local/Interlisp" + vnc_exe="vncviewer64-1.12.0.exe" + if [[ $(which Xvnc) = "" || $(Xvnc -version |& grep -iq tigervnc; echo $?) -eq 1 ]]; then - # make sure TigerVNC viewer is in a Windows (not Linux) directory. If its in a Linux directory - # there will be a long delay when it starts up - mkdir -p ${vnc_dir} - cp -p "${IL_DIR}/wsl/${vnc_exe}" "${vnc_dir}/${vnc_exe}" - else - echo "TigerVnc viewer is required by the -vnc option but is not installed." - echo -n "Ok to download from SourceForge? [y, Y, n or N, default n] " - read resp - if [ -z ${resp} ]; then resp=n; else resp=${resp:0:1}; fi - if [[ ${resp} = 'n' || ${resp} = 'N' ]]; + echo "Error: The -v or --vnc flag was set." + echo "But it appears that that TigerVNC \(Xvnc\) has not been installed." + echo "Please install TigerVNC using \"sudo apt install tigervnc-standalone-server tigervnc-xorg-extension\"" + echo "Exiting." + exit 4 + elif [ ! -e "${vnc_dir}/${vnc_exe}" ]; + then + if [ -e "${IL_DIR}/wsl/${vnc_exe}" ]; then - echo "Ok. You can download the Tiger VNC viewer \(v1.12.0\) .exe yourself and " - echo "place it in ${vnc_dir}/${vnc_exe}. Then retry." - echo "Exiting." - exit 5 + # make sure TigerVNC viewer is in a Windows (not Linux) directory. If its in a Linux directory + # there will be a long delay when it starts up + mkdir -p ${vnc_dir} + cp -p "${IL_DIR}/wsl/${vnc_exe}" "${vnc_dir}/${vnc_exe}" else - pushd "${vnc_dir}" >/dev/null - wget https://sourceforge.net/projects/tigervnc/files/stable/1.12.0/vncviewer64-1.12.0.exe - popd >/dev/null + echo "TigerVnc viewer is required by the -vnc option but is not installed." + echo -n "Ok to download from SourceForge? [y, Y, n or N, default n] " + read resp + if [ -z ${resp} ]; then resp=n; else resp=${resp:0:1}; fi + if [[ ${resp} = 'n' || ${resp} = 'N' ]]; + then + echo "Ok. You can download the Tiger VNC viewer \(v1.12.0\) .exe yourself and " + echo "place it in ${vnc_dir}/${vnc_exe}. Then retry." + echo "Exiting." + exit 5 + else + pushd "${vnc_dir}" >/dev/null + wget https://sourceforge.net/projects/tigervnc/files/stable/1.12.0/vncviewer64-1.12.0.exe + popd >/dev/null + fi fi fi fi - # - # Find an unused display, start Xvnc, run-medley, then start the vnc viewer on the windows side + # Start the log file so we can trace any issues with vnc, etc # - #set -x LOG=${LOGINDIR}/logs/medley_${run_id}.log mkdir -p $(dirname -- ${LOG}) echo "START" >${LOG} - OPEN_DISPLAY=`find_open_display` - if [ ${OPEN_DISPLAY} -eq -1 ]; + # + # If we're running under docker: + # set the VNC_PORT to the value of the --port flag (or its default value) + # set DISPLAY to :0 + # + #set -x + if [ "${docker}" = "true" ]; then - echo "Error: cannot find an unused DISPLAY between 1 and 63" - echo "Exiting" - exit 33 + export VNC_PORT=5900 + export DISPLAY=:0 else - echo "Using DISPLAY=${OPEN_DISPLAY}" + # are we running in background - used for pretty-fying the echos + case $(ps -o stat= -p $$) in + *+*) bg=false ;; + *) bg=true ;; + esac + # For not docker (i.e., for wsl/vnc) + # find an unused display and an available port + # + #set -x + OPEN_DISPLAY=`find_open_display` + if [ ${OPEN_DISPLAY} -eq -1 ]; + then + echo "Error: cannot find an unused DISPLAY between 1 and 63" + echo "Exiting" + exit 33 + else + if [ ${bg} = true ]; then echo; fi + echo "Using DISPLAY=:${OPEN_DISPLAY}" + fi + export DISPLAY=":${OPEN_DISPLAY}" + export VNC_PORT=`find_open_port` + if [ ${VNC_PORT} -eq -1 ]; + then + echo "Error: cannot find an unused port between 5900 and 5999" + echo "Exiting" + exit 33 + else + echo "Using VNC_PORT=${VNC_PORT}" + fi fi - VNC_PORT=`find_open_port` - if [ ${VNC_PORT} -eq -1 ]; - then - echo "Error: cannot find an unused port between 5900 and 5999" - echo "Exiting" - exit 33 - else - echo "Using VNC_PORT=${VNC_PORT}" - fi - export DISPLAY=":${OPEN_DISPLAY}" - # start vnc + # + # Start the Xvnc server + # mkdir -p ${LOGINDIR}/logs - /usr/bin/Xvnc ":${OPEN_DISPLAY}" \ + /usr/bin/Xvnc "${DISPLAY}" \ -rfbport ${VNC_PORT} \ -geometry "${geometry#-g }" \ -SecurityTypes None \ -NeverShared \ -DisconnectClients=0 \ + --MaxDisconnectionTime=10 \ >> ${LOG} 2>&1 & - xvnc_pid="" - while [ -z ${xvnc_pid} ]; - do - sleep .25 - xvnc_pid=$(ps h -C Xvnc -o pid,command | grep "Xvnc :${OPEN_DISPLAY}" | awk '{print $1}') - done - echo "XVNC_PID is ${xvnc_pid}" - # run Medley - ( ${MEDLEYDIR}/run-medley -id "${run_id}" ${geometry} ${screensize} "${run_args[@]}" 2>>${LOG} \ - ; \ - kill -9 ${xvnc_pid} ${xvnc_pid} >>${LOG} 2>&1 - ) & - # Give medley time to startup - sleep 2 - # Start vnc viewer on Windows side - pushd ${vnc_dir} >/dev/null - ( ./${vnc_exe} -geometry "+50+50" \ - -ReconnectOnError=off \ - −AlertOnFatalError=off \ - $(ip_addr):${VNC_PORT} \ - >>${LOG} 2>&1 \ - ; \ - kill -9 ${xvnc_pid} >>${LOG} 2>&1 \ - ) & - popd >/dev/null + + # Leaving pid wait for all but docker, + # which seems to need it. For all others + # it seems like its not needed but we'll have + # to see how it runs on slower/faster machines + # FGH 2023-02-16 + if [ ${docker} = true ]; + then + xvnc_pid="" + end_time=$(expr $(date +%s) + 10) + while [ -z "${xvnc_pid}" ]; + do + if [ $(date +%s) -gt $end_time ]; + then + echo "Xvnc server failed to start." + echo "See log file at ${LOG}" + echo "Exiting" + exit 3 + fi + sleep .125 + xvnc_pid=$(pgrep -f "Xvnc ${DISPLAY}") + done + # echo "XVNC_PID is ${xvnc_pid}" + fi + # + # Run Medley in foreground if docker, else in background + # + tmp_dir=$(if [[ -d /run/shm && ! -h /run/shm ]]; then echo "/run/shm"; else echo "/tmp"; fi) + medley_run=$(mktemp --tmpdir=${tmp_dir} medley-XXXXX) + cat > ${medley_run} <<..EOF + #!/bin/bash + ${MEDLEYDIR}/run-medley -id '${run_id}' ${geometry} ${screensize} ${run_args[@]} \ + 2>&1 | tee -a ${LOG} | grep -v "broken (explicit kill" + if [ -n "\$(pgrep -f "${vnc_exe}.*:${VNC_PORT}")" ]; then vncconfig -disconnect; fi +..EOF + #cat ${medley_run} + chmod +x ${medley_run} + if [ "${docker}" = "true" ]; + then + ${medley_run}; rm ${medley_run} + else + (${medley_run}; rm ${medley_run}) & + # + # If not docker (i.e., if wsl/vnc), start the vncviewer on the windows side + # + + # First give medley time to startup + # sleep .25 + # SLeep appears not to be needed, but faster/slower machines ???? + # FGH 2023-02-08 + + # Then start vnc viewer on Windows side + start_time=$(date +%s) + ${vnc_dir}/${vnc_exe} \ + -geometry "+50+50" \ + -ReconnectOnError=off \ + −AlertOnFatalError=off \ + $(ip_addr):${VNC_PORT} \ + >>${LOG} 2>&1 & + wait $! + if [ $( expr $(date +%s) - ${start_time} ) -lt 5 ]; + then + if [ -z "$(pgrep -f "Xvnc ${DISPLAY}")" ]; + then + echo "Xvnc server failed to start." + echo "See log file at ${LOG}" + echo "Exiting" + exit 3 + else + echo "VNC viewer failed to start."; + echo "See log file at ${LOG}"; + echo "Exiting" ; + exit 4; + fi + fi + fi + # + # Done, "Go back" to medley.sh + # + true + +#######################################