├── Dockerfile ├── LICENSE ├── README.md ├── entrypoint └── rmfiles.sh /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:bookworm-slim as installer 2 | 3 | ARG DYALOG_RELEASE=19.0 4 | ARG BUILDTYPE=minimal 5 | 6 | RUN apt-get update && apt-get install -y curl && \ 7 | apt-get clean && rm -Rf /var/lib/apt/lists/* 8 | 9 | RUN DEBFILE=`curl -o - -s https://www.dyalog.com/uploads/php/download.dyalog.com/download.php?file=docker.metafile | awk -v v="$DYALOG_RELEASE" '$0~v && /deb/ {print $3}'` && \ 10 | curl -o /tmp/dyalog.deb ${DEBFILE} 11 | 12 | ADD rmfiles.sh / 13 | 14 | RUN dpkg -i --ignore-depends=libtinfo5 /tmp/dyalog.deb && /rmfiles.sh 15 | 16 | FROM debian:bookworm-slim 17 | 18 | ARG DYALOG_RELEASE=19.0 19 | 20 | RUN apt-get update && apt-get install -y --no-install-recommends locales && \ 21 | apt-get clean && rm -Rf /var/lib/apt/lists/* && \ 22 | sed -i -e 's/# en_GB.UTF-8 UTF-8/en_GB.UTF-8 UTF-8/' /etc/locale.gen && \ 23 | locale-gen 24 | 25 | ENV LANG en_GB.UTF-8 26 | ENV LANGUAGE en_GB:UTF-8 27 | ENV LC_ALL en_GB.UTF-8 28 | 29 | RUN apt-get update && apt-get install -y --no-install-recommends libncurses5 && \ 30 | apt-get clean && rm -Rf /var/lib/apt/lists/* 31 | 32 | COPY --from=0 /opt /opt 33 | 34 | RUN P=$(echo ${DYALOG_RELEASE} | sed 's/\.//g') && update-alternatives --install /usr/bin/dyalog dyalog /opt/mdyalog/${DYALOG_RELEASE}/64/unicode/dyalog ${P} 35 | RUN P=$(echo ${DYALOG_RELEASE} | sed 's/\.//g') && update-alternatives --install /usr/bin/dyalogscript dyalogscript /opt/mdyalog/${DYALOG_RELEASE}/64/unicode/scriptbin/dyalogscript ${P} 36 | RUN cp /opt/mdyalog/${DYALOG_RELEASE}/64/unicode/LICENSE /LICENSE 37 | 38 | ADD entrypoint / 39 | RUN sed -i "s/{{DYALOG_RELEASE}}/${DYALOG_RELEASE}/" /entrypoint 40 | 41 | RUN useradd -s /bin/bash -d /home/dyalog -m dyalog 42 | RUN mkdir /app /storage && \ 43 | chmod 777 /app /storage 44 | 45 | LABEL org.label-schema.licence="proprietary / non-commercial" \ 46 | org.label-schema.licenceURL="https://www.dyalog.com/uploads/documents/Private_Personal_Educational_Licence.pdf" 47 | 48 | EXPOSE 4502 49 | 50 | USER dyalog 51 | WORKDIR /home/dyalog 52 | VOLUME [ "/storage", "/app" ] 53 | ENTRYPOINT ["/entrypoint"] 54 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Dyalog Ltd. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # dyalog/dyalog Container 3 | 4 | This container provides access to a Dyalog APL interpreter, with support for interactive debugging via RIDE or a web browser. The container is built using a Dockerfile and startup script which can be found in the [Dyalog/DyalogDocker](https://github.com/Dyalog/DyalogDocker) GitHub repository. 5 | 6 | ## Interactive APL Sessions 7 | 8 | Dyalog's Remote IDE (RIDE) is recommended for interactive use and debugging of the container. You can either download RIDE from [GitHub](https://github.com/Dyalog/ride) and install it locally, or you can configure the interpreter to serve RIDE up as a web application and connect to it using a web browser. Either option requires opening a port and set the [RIDE_INIT]([http://help.dyalog.com/latest/Content/UserGuide/Installation%20and%20Configuration/Configuration%20Parameters/RIDE_Init.htm) environment variable: 9 | 10 | To connect from a local RIDE, use the `serve` keyword in `RIDE_INIT`, after which you can connect RIDE and establish an interactive session. In this example, we use port 4502: 11 | 12 | `docker run -e RIDE_INIT=serve:*:4502 -p 4502:4502 dyalog/dyalog` 13 | 14 | To use a web browser, use the `http` keyword, after which you can connect a browser, in this example to [http://localhost:8888](http://localhost:8888/). 15 | 16 | `docker run -e RIDE_INIT=http:*:8888 -p 8888:8888 dyalog/dyalog` 17 | 18 | It is also possible to start an interactive session without RIDE simply by starting the container with the `--interactive` and `--tty` switches (or `-it` for short). 19 | 20 | `docker run -it dyalog/dyalog` 21 | 22 | If you do not set `RIDE_INIT` or enable `-it`, the container will terminate as soon as the interpreter requires session input. 23 | 24 | If you map directories into the container using the `-v` switch, your APL session will be able to load source code and data from these directories. The next sections describes how you can configure the container to run code that is mapped into it. 25 | 26 | ## Starting Your Application 27 | 28 | If you set one of the environment variables `LOAD`, `CONFIGFILE` or `DYAPP` in the container at startup, the settings will be used by the interpreter when it is launched. For example, if the directory `/home/mkrom/myapp` contains your application, you can mount this directory into the running image as `/myapp` and start your application from the workspace `boot.dws`within the directory as follows: 29 | 30 | `docker run -v /home/mkrom/myapp:/myapp -e LOAD=/myapp/boot.dws` 31 | 32 | As the application runs, any changes that it makes to the `/myapp` directory will immediately be visible from outside the container. You will need to add the settings for RIDE if you want to be able to interact with the application while it is running (other than by inspecting the contents of mapped directories). 33 | 34 | ## Automatic Application Startup 35 | 36 | When the container starts, it runs the [entrypoint](https://github.com/Dyalog/DyalogDocker/blob/master/entrypoint) script. If none of the environment variables mentioned in the previous section are set, the script looks for a directory called `/app`, and if the directory contains APL code or a configuration file which the script is able to identify, it will be used to automatically launch your application. The script searches for: 37 | 38 | 1. A single configuration file `.dcfg`. Note that the file must have a setting for the `LX` parameter if it is to start an application. 39 | 2. A single source for a function `.aplf`, namespace `.apln` or class `.aplc`. 40 | 3. A single Dyalog application file `.dyapp` (note that these are considered deprecated). 41 | 4. A single Dyalog workspace `.dws`. 42 | 43 | If the mapped folder does not match any of the above constraints, APL is started with a clear workspace. 44 | 45 | For example, if you have a directory which contains a single APL function: 46 | 47 | ``` 48 | $ cat /home/mkrom/helloworld/helloworld.aplf 49 | helloworld 50 | ⎕←'Hello World!' 51 | ``` 52 | 53 | Then you can start a container which runs the function my mapping the folder into the container as `/app`: 54 | 55 | ``` 56 | $ docker run -v /home/mkrom/helloworld:/app dyalog/dyalog 57 | _______ __ _ ____ _____ 58 | | __ \ \ / //\ | | / __ \ / ____| 59 | |_| | \ \_/ // \ | | | | | | | 60 | | |\ // /\ \ | | | | | | | _ 61 | ____| | | |/ / \ \| |___| |__| | |__| | 62 | |_____/ |_/_/ \_\______\____/ \_____| 63 | 64 | https://www.dyalog.com 65 | 66 | found aplf file Launching with LOAD=/app/helloworld.aplf 67 | Dyalog APL/S-64 Version 18.2.45333 68 | Serial number: UNREGISTERED - not for commercial use 69 | +-----------------------------------------------------------------+ 70 | | Dyalog is free for non-commercial use but is not free software. | 71 | | A basic licence can be used for experiments and proof of | 72 | | concept until the point in time that it is of value. | 73 | | For further information visit | 74 | | https://www.dyalog.com/prices-and-licences.htm | 75 | +-----------------------------------------------------------------+ 76 | Mon Mar 7 11:03:02 2022 77 | Loaded: #.helloworld from "/app/helloworld.aplf" 78 | Hello World! 79 | ``` 80 | 81 | If you follow the instructions for enabling RIDE that you can find at the start of this document , the container will not terminate after running the loaded code (unless the code itself closes the APL session), but pause and allow debugging. If changes are made to the files in the `/app` directory, they will be reflected in the mapped directory (in this case `/home/mkrom/helloworld`). 82 | 83 | ## Extending the dyalog/dyalog Container 84 | 85 | You can build your own container images based on `dyalog/dyalog` using the statement `FROM dyalog/dyalog` in a dockerfile. This will give you a container which contains the Dyalog APL interpreter as `/opt/mdyalog/19.0/64/unicode/dyalog`. 86 | 87 | Review the [entrypoint](https://github.com/Dyalog/DyalogDocker/blob/master/entrypoint) script for an example of how to launch the interpreter. 88 | 89 | 90 | ## Licence 91 | Dyalog is free for non-commercial use and for limited commercial use, but is not free software. You may create public docker images which include Dyalog APL in addition to your own work, if you observe the following conditions: 92 | 93 | - You must include Dyalog's LICENSE file in a prominent location and include instructions which require it's inclusion in any derived works. 94 | - If you do not have a commercial licence with a corresponding [Run Time Licence](https://www.dyalog.com/prices-and-licences.htm#runtimelic), and you make images available for download, the default Run Time Licence will automatically apply. This allows non-commercial use, and limited commercial distribution up to the revenue limit set out in the [Licenses, Terms and Conditions](https://www.dyalog.com/prices-and-licences.htm). -------------------------------------------------------------------------------- /entrypoint: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ## This file replaces the Dyalog mapl script 4 | echo " _______ __ _ ____ _____ " 5 | echo "| __ \ \ / //\ | | / __ \ / ____|" 6 | echo "|_| | \ \_/ // \ | | | | | | | " 7 | echo " | |\ // /\ \ | | | | | | | _ " 8 | echo " ____| | | |/ / \ \| |___| |__| | |__| |" 9 | echo "|_____/ |_/_/ \_\______\____/ \_____|" 10 | echo "" 11 | echo "https://www.dyalog.com" 12 | echo "" 13 | 14 | export DYALOG=/opt/mdyalog/{{DYALOG_RELEASE}}/64/unicode/ 15 | export LD_LIBRARY_PATH="${DYALOG}:${LD_LIBRARY_PATH}" 16 | export WSPATH=$WSPATH:${DYALOG}/ws 17 | export TERM=dumb 18 | export APL_TEXTINAPLCORE=${APL_TEXTINAPLCORE-1} 19 | export TRACE_ON_ERROR=0 20 | export SESSION_FILE="${SESSION_FILE-$DYALOG/default.dse}" 21 | 22 | if [ "x${LOAD}" = "x" ] \ 23 | && [ "x${CONFIGFILE}" = "x" ] \ 24 | && [ "x${DYAPP}" = "x" ]; then 25 | 26 | if [ $(ls /app/*.dcfg 2>/dev/null | wc -l) = 1 ]; then 27 | export CONFIGFILE=$(ls /app/*.dcfg) 28 | echo "found config file Launching with CONFIGFILE=$CONFIGFILE" 29 | elif [ $(ls /app/*.aplf 2>/dev/null | wc -l) = 1 ]; then 30 | export LOAD=$(ls /app/*.aplf) 31 | echo "found aplf file Launching with LOAD=$LOAD" 32 | elif [ $(ls /app/*.apln 2>/dev/null | wc -l) = 1 ]; then 33 | export LOAD=$(ls /app/*.apln) 34 | echo "found apln file Launching with LOAD=$LOAD" 35 | elif [ $(ls /app/*.aplc 2>/dev/null | wc -l) = 1 ]; then 36 | export LOAD=$(ls /app/*.aplc) 37 | echo "found aplc file Launching with LOAD=$LOAD" 38 | elif [ $(ls /app/*.dyapp 2>/dev/null | wc -l) = 1 ]; then 39 | export DYAPP=$(ls /app/*.dyapp) 40 | echo "found dyapp file Launching with DYAPP=$DYAPP" 41 | elif [ $(ls /app/*.dws 2>/dev/null | wc -l) = 1 ]; then 42 | WS=$(ls /app/*.dws) 43 | echo "found dws file Launching with $WS" 44 | elif [ $(ls /app/*.dyapp 2>/dev/null | wc -l) -gt 1 ]; then 45 | echo "found too many dyapp files Starting Dyalog with CLEAR WS" 46 | elif [ $(ls /app/*.dws 2>/dev/null | wc -l) -gt 1 ]; then 47 | echo "found too many dws files Starting Dyalog with CLEAR WS" 48 | else 49 | echo "nothing to load in /app Starting with CLEAR WS" 50 | fi 51 | else 52 | echo "LOAD, CONFIGFILE or DYAPP was set, not loading any defaults" 53 | fi 54 | 55 | if [ -n "${RIDE_INIT}" ]; then 56 | $DYALOG/dyalog +s -q ${WS} $@ 57 | else 58 | $DYALOG/dyalog -s ${WS} $@ 59 | fi 60 | -------------------------------------------------------------------------------- /rmfiles.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$BUILDTYPE" = "minimal" ]; then 4 | cd /opt/mdyalog/19.0/64/unicode/ 5 | 6 | rm -Rf aplfmt \ 7 | aplkeys/file_siso \ 8 | aplkeys/utf8 \ 9 | aplkeys/xterm \ 10 | aplkeys/screen \ 11 | aplkeys.sh \ 12 | apltrans/utf8 \ 13 | apltrans/xterm \ 14 | apltrans/screen \ 15 | BuildID \ 16 | dyalog.BuildID \ 17 | dyalog.config.example \ 18 | dyalog.desktop \ 19 | dyalog.rt \ 20 | dyalog.svg \ 21 | fonts \ 22 | help \ 23 | libcef.so \ 24 | lib/ademo64.so \ 25 | lib/testcallback.so \ 26 | lib/htmlrenderer.so \ 27 | make_scripts \ 28 | mapl \ 29 | outprods \ 30 | samples \ 31 | DWASamples \ 32 | Samples \ 33 | TestCertificates \ 34 | ws/apl2in.dws \ 35 | ws/apl2pcin.dws \ 36 | ws/ddb.dws \ 37 | ws/display.dws \ 38 | ws/eval.dws \ 39 | ws/fonts.dws \ 40 | ws/ftp.dws \ 41 | ws/groups.dws \ 42 | ws/max.dws \ 43 | ws/min.dws \ 44 | ws/ops.dws \ 45 | ws/quadna.dws \ 46 | ws/smdemo.dws \ 47 | ws/smdesign.dws \ 48 | ws/smtutor.dws \ 49 | ws/tube.dws \ 50 | ws/tutor.dws \ 51 | ws/xfrcode.dws \ 52 | ws/xlate.dws \ 53 | xflib \ 54 | xfsrc \ 55 | cef.pak \ 56 | cef_100_percent.pak \ 57 | cef_200_percent.pak \ 58 | chrome_100_percent.pak \ 59 | chrome_200_percent.pak \ 60 | cef_extensions.pak \ 61 | chrome-sandbox \ 62 | devtools_resources.pak \ 63 | icudtl.dat \ 64 | locales \ 65 | snapshot_blob.bin \ 66 | natives_blob.bin \ 67 | lib/libcef.so \ 68 | lib/libAplWrapper.so \ 69 | lib/libHttpInterceptor.so \ 70 | 71 | fi 72 | --------------------------------------------------------------------------------