1
1
mirror of https://github.com/kanaka/mal.git synced 2024-09-11 13:55:55 +03:00

Tests: add testing Dockerfile. Impl fixes.

- tests/docker/Dockerfile: specifies full docker image containing all
  tools/languages (except matlab).
- tests/docker-build.sh: build above image.
- tests/docker-run.sh: launch above image.
    Example: ./tests/docker-run.sh make test^js^step2
- Various fixes across multiple languages:
    - Unicode fixes for bash and R on Ubuntu Utopic
    - readline history fixes for when ~/.mal-history is not available
      or readable/writable. No fatal errors.
    - fixes to work with perl 5.20 (and still perl 5.18)
This commit is contained in:
Joel Martin 2015-03-11 22:22:35 -05:00
parent 8569b2af48
commit c9de2e82ed
31 changed files with 259 additions and 56 deletions

5
.gitignore vendored
View File

@ -48,3 +48,8 @@ haskell/*.hi
haskell/*.o
lua/lib
lua/linenoise.so
nim/nimcache
.lein
.m2
.ivy2
.sbt

View File

@ -38,6 +38,8 @@ _raw_string_pr_str () {
local print_readably="${2}"
if [[ "${s:0:1}" = "${__keyw}" ]]; then
r=":${s:1}"
elif [[ "${s:0:2}" = "${__keyw}" ]]; then
r=":${s:2}"
elif [ "${print_readably}" == "yes" ]; then
s="${s//\\/\\\\}"
r="\"${s//\"/\\\"}\""

View File

@ -149,10 +149,10 @@ READ_STR () {
READLINE_EOF=
READLINE_HISTORY_FILE=${HOME}/.mal-history
READLINE () {
history -r "${READLINE_HISTORY_FILE}"
history -r "${READLINE_HISTORY_FILE}" 2>/dev/null || true
read -r -e -p "${1}" r || return "$?"
history -s -- "${r}"
history -a "${READLINE_HISTORY_FILE}"
history -a "${READLINE_HISTORY_FILE}" 2>/dev/null || true
}
fi

View File

@ -8,7 +8,7 @@ __mal_types_included=true
declare -A ANON
__obj_magic=__5bal7
__keyw=$(echo -en "\u029e")
__keyw=$(echo -en "\xCA\x9E") # \u029E
__obj_hash_code=${__obj_hash_code:-0}
__new_obj_hash_code () {

View File

@ -45,8 +45,10 @@ int append_to_history() {
#else
HIST_ENTRY *he = history_get(history_length-1);
FILE *fp = fopen(hf, "a");
fprintf(fp, "%s\n", he->line);
fclose(fp);
if (fp) {
fprintf(fp, "%s\n", he->line);
fclose(fp);
}
#endif
free(hf);
}

View File

@ -1,5 +1,6 @@
(ns readline
(:require [clojure.string :refer [split]]
[clojure.java.io :refer [file]]
[net.n01se.clojure-jna :as jna]))
(defonce history-loaded (atom nil))
@ -29,9 +30,11 @@
(defn readline [prompt & [lib]]
(when (not @history-loaded)
(reset! history-loaded true)
(load-history HISTORY-FILE))
(when (.canRead (file HISTORY-FILE))
(load-history HISTORY-FILE)))
(let [line (readline-call prompt)]
(when line
(add-history line)
(spit HISTORY-FILE (str line "\n") :append true))
(when (.canWrite (file HISTORY-FILE))
(spit HISTORY-FILE (str line "\n") :append true)))
line))

View File

@ -29,7 +29,10 @@ exports.readline = rlwrap.readline = (prompt = 'user> ') ->
line = rllib.readline prompt
if line
rllib.add_history line
fs.appendFileSync HISTORY_FILE, line + "\n"
try
fs.appendFileSync HISTORY_FILE, line + "\n"
catch exc
true
line

View File

@ -8,9 +8,11 @@ import qualified System.Console.Readline as RL
-- BSD license
--import qualified System.Console.Editline.Readline as RL
import System.Directory (getHomeDirectory)
import Control.Monad (when)
import System.Directory (getHomeDirectory, doesFileExist)
import System.IO (hGetLine, hFlush, hIsEOF, stdin, stdout)
import System.IO.Error (tryIOError)
history_file = do
home <- getHomeDirectory
@ -18,15 +20,19 @@ history_file = do
load_history = do
hfile <- history_file
content <- readFile hfile
mapM RL.addHistory (lines content)
fileExists <- doesFileExist hfile
when fileExists $ do
content <- readFile hfile
mapM RL.addHistory (lines content)
return ()
return ()
readline prompt = do
hfile <- history_file
maybeLine <- RL.readline prompt
case maybeLine of
Just line -> do
appendFile hfile (line ++ "\n")
RL.addHistory line
res <- tryIOError (appendFile hfile (line ++ "\n"))
return maybeLine
_ -> return maybeLine

View File

@ -34,7 +34,11 @@ exports.readline = rlwrap.readline = function(prompt) {
var line = rllib.readline(prompt);
if (line) {
rllib.add_history(line);
fs.appendFileSync(HISTORY_FILE, line + "\n");
try {
fs.appendFileSync(HISTORY_FILE, line + "\n");
} catch (exc) {
// ignored
}
}
return line;

View File

@ -10,9 +10,13 @@ M.raw = false
function M.readline(prompt)
if not history_loaded then
history_loaded = true
for line in io.lines(history_file) do
LN.historyadd(line)
end
xpcall(function()
for line in io.lines(history_file) do
LN.historyadd(line)
end
end, function(exc)
return true -- ignore the error
end)
end
if M.raw then
@ -23,9 +27,13 @@ function M.readline(prompt)
end
if line then
LN.historyadd(line)
local f = io.open(history_file, "a")
f:write(line.."\n")
f:close()
xpcall(function()
local f = io.open(history_file, "a")
f:write(line.."\n")
f:close()
end, function(exc)
return true -- ignore the error
end)
end
return line
end

View File

@ -10,6 +10,6 @@ __mal_readline_included := true
# have readline history.
READLINE_EOF :=
READLINE_HISTORY_FILE := $${HOME}/.mal-history
READLINE = $(eval __readline_temp := $(shell history -r $(READLINE_HISTORY_FILE); read -u 0 -r -e -p $(if $(1),$(1),"user> ") line && history -s -- "$${line}" && history -a $(READLINE_HISTORY_FILE) && echo "$${line}" || echo "__||EOF||__"))$(if $(filter __||EOF||__,$(__readline_temp)),$(eval READLINE_EOF := yes),$(__readline_temp))
READLINE = $(eval __readline_temp := $(shell history -r $(READLINE_HISTORY_FILE); read -u 0 -r -e -p $(if $(1),$(1),"user> ") line && history -s -- "$${line}" && echo "$${line}" || echo "__||EOF||__"; history -a $(READLINE_HISTORY_FILE) 2>/dev/null || true))$(if $(filter __||EOF||__,$(__readline_temp)),$(eval READLINE_EOF := yes),$(__readline_temp))
endif

View File

@ -22,7 +22,8 @@ sub _pr_str {
}
when(/^HashMap/) {
my @elems = ();
foreach my $key (keys $obj->{val}) {
foreach my $key (keys %{ $obj->{val} }) {
push(@elems, _pr_str(String->new($key), $_r));
push(@elems, _pr_str($obj->{val}->{$key}, $_r));
}

View File

@ -38,7 +38,7 @@ sub eval_ast {
}
when (/^HashMap/) {
my $new_hm = {};
foreach my $k (keys($ast->{val})) {
foreach my $k (keys( %{ $ast->{val} })) {
$new_hm->{$k} = EVAL($ast->get($k), $env);
}
return HashMap->new($new_hm);

View File

@ -35,7 +35,7 @@ sub eval_ast {
}
when (/^HashMap/) {
my $new_hm = {};
foreach my $k (keys($ast->{val})) {
foreach my $k (keys( %{ $ast->{val} })) {
$new_hm->{$k} = EVAL($ast->get($k), $env);
}
return HashMap->new($new_hm);

View File

@ -36,7 +36,7 @@ sub eval_ast {
}
when (/^HashMap/) {
my $new_hm = {};
foreach my $k (keys($ast->{val})) {
foreach my $k (keys( %{ $ast->{val} })) {
$new_hm->{$k} = EVAL($ast->get($k), $env);
}
return HashMap->new($new_hm);

View File

@ -36,7 +36,7 @@ sub eval_ast {
}
when (/^HashMap/) {
my $new_hm = {};
foreach my $k (keys($ast->{val})) {
foreach my $k (keys( %{ $ast->{val} })) {
$new_hm->{$k} = EVAL($ast->get($k), $env);
}
return HashMap->new($new_hm);

View File

@ -36,7 +36,7 @@ sub eval_ast {
}
when (/^HashMap/) {
my $new_hm = {};
foreach my $k (keys($ast->{val})) {
foreach my $k (keys( %{ $ast->{val} })) {
$new_hm->{$k} = EVAL($ast->get($k), $env);
}
return HashMap->new($new_hm);

View File

@ -59,7 +59,7 @@ sub eval_ast {
}
when (/^HashMap/) {
my $new_hm = {};
foreach my $k (keys($ast->{val})) {
foreach my $k (keys( %{ $ast->{val} })) {
$new_hm->{$k} = EVAL($ast->get($k), $env);
}
return HashMap->new($new_hm);

View File

@ -82,7 +82,7 @@ sub eval_ast {
}
when (/^HashMap/) {
my $new_hm = {};
foreach my $k (keys($ast->{val})) {
foreach my $k (keys( %{ $ast->{val} })) {
$new_hm->{$k} = EVAL($ast->get($k), $env);
}
return HashMap->new($new_hm);

View File

@ -83,7 +83,7 @@ sub eval_ast {
}
when (/^HashMap/) {
my $new_hm = {};
foreach my $k (keys($ast->{val})) {
foreach my $k (keys( %{ $ast->{val} })) {
$new_hm->{$k} = EVAL($ast->get($k), $env);
}
return HashMap->new($new_hm);

View File

@ -83,7 +83,7 @@ sub eval_ast {
}
when (/^HashMap/) {
my $new_hm = {};
foreach my $k (keys($ast->{val})) {
foreach my $k (keys( %{ $ast->{val} })) {
$new_hm->{$k} = EVAL($ast->get($k), $env);
}
return HashMap->new($new_hm);

View File

@ -102,13 +102,13 @@ sub _false_Q { return $_[0] eq $false }
{
package Integer;
sub new { my $class = shift; bless \$_[0] => $class }
sub new { my $class = shift; bless \do { my $x=$_[0] }, $class }
}
{
package Symbol;
sub new { my $class = shift; bless \$_[0] => $class }
sub new { my $class = shift; bless \do { my $x=$_[0] }, $class }
}
sub _symbol_Q { (ref $_[0]) =~ /^Symbol/ }

View File

@ -9,12 +9,14 @@ function mal_readline($prompt) {
// Load the history file
if (! $history_loaded) {
$history_loaded = true;
if ($file = fopen($HISTORY_FILE, "r")) {
while (!feof($file)) {
$line = fgets($file);
if ($line) { readline_add_history($line); }
if (is_readable($HISTORY_FILE)) {
if ($file = fopen($HISTORY_FILE, "r")) {
while (!feof($file)) {
$line = fgets($file);
if ($line) { readline_add_history($line); }
}
fclose($file);
}
fclose($file);
}
}
@ -23,9 +25,11 @@ function mal_readline($prompt) {
readline_add_history($line);
// Append to the history file
if ($file = fopen($HISTORY_FILE, "a")) {
fputs($file, $line . "\n");
fclose($file);
if (is_writable($HISTORY_FILE)) {
if ($file = fopen($HISTORY_FILE, "a")) {
fputs($file, $line . "\n");
fclose($file);
}
}
return $line;

View File

@ -25,6 +25,8 @@ def readline(prompt="user> "):
pyreadline.add_history(line)
with open(histfile, "a") as hf:
hf.write(line + "\n")
return line
except IOError:
pass
except EOFError:
return None
return line

View File

@ -29,6 +29,9 @@ if(!exists("..types..")) source("types.r")
"character"={
if (substring(exp,1,1) == "\u029e") {
concat(":", substring(exp,2))
} else if (substring(exp,1,8) == "<U+029E>") {
# terrible hack, appears in 3.1.1 on Utopic
concat(":", substring(exp,9))
} else if (print_readably) {
paste("\"",
gsub("\\n", "\\\\n",

View File

@ -25,16 +25,20 @@ readline <- function(prompt) {
if (!.state$rl_history_loaded) {
.state$rl_history_loaded <- TRUE
lines <- scan(HISTORY_FILE, what="", sep="\n", quiet=TRUE)
for(add_line in lines) {
.dyncall(.call_add_history, "Z)v", add_line)
if (file.access(HISTORY_FILE, 4) == 0) {
lines <- scan(HISTORY_FILE, what="", sep="\n", quiet=TRUE)
for(add_line in lines) {
.dyncall(.call_add_history, "Z)v", add_line)
}
}
}
line <- .readline(prompt)
if (is.null(line)) return(NULL)
.dyncall(.call_add_history, "Z)v", line)
write(line, file=HISTORY_FILE, append=TRUE)
if (file.access(HISTORY_FILE, 2) == 0) {
write(line, file=HISTORY_FILE, append=TRUE)
}
line
}

View File

@ -10,11 +10,13 @@
(define HISTORY-FILE (format "~a/.mal-history" (find-system-path 'home-dir)))
(define (load-history path)
(map
(lambda (line) (readline:add-history line))
(string-split
(port->string (open-input-file path))
#px"\n")))
(with-handlers
([exn:fail? (lambda (e) #t)])
(map
(lambda (line) (readline:add-history line))
(string-split
(port->string (open-input-file path))
#px"\n"))))
(define (readline prompt)
(when (not history-loaded)
@ -25,8 +27,10 @@
nil
(begin
(readline:add-history line)
(with-output-to-file
HISTORY-FILE
(lambda () (printf "~a~n" line))
#:exists 'append)
(with-handlers
([exn:fail? (lambda (e) #t)])
(with-output-to-file
HISTORY-FILE
(lambda () (printf "~a~n" line))
#:exists 'append))
line))))

View File

@ -6,11 +6,15 @@ $histfile = "#{ENV['HOME']}/.mal-history"
def _readline(prompt)
if !$history_loaded && File.exist?($histfile)
$history_loaded = true
File.readlines($histfile).each {|l| Readline::HISTORY.push(l.chomp)}
if File.readable?($histfile)
File.readlines($histfile).each {|l| Readline::HISTORY.push(l.chomp)}
end
end
if line = Readline.readline(prompt, true)
File.open($histfile, 'a+') {|f| f.write(line+"\n")}
if File.writable?($histfile)
File.open($histfile, 'a+') {|f| f.write(line+"\n")}
end
return line
else
return nil

6
tests/docker-build.sh Normal file
View File

@ -0,0 +1,6 @@
#!/bin/bash
IMAGE_NAME=${IMAGE_NAME:-mal-test-ubuntu-utopic}
GIT_TOP=$(git rev-parse --show-toplevel)
docker build -t "${IMAGE_NAME}" "${GIT_TOP}/tests/"

9
tests/docker-run.sh Executable file
View File

@ -0,0 +1,9 @@
#!/bin/bash
IMAGE_NAME=${IMAGE_NAME:-mal-test-ubuntu-utopic}
GIT_TOP=$(git rev-parse --show-toplevel)
docker run -it --rm -u ${EUID} \
--volume=${GIT_TOP}:/mal \
${IMAGE_NAME} \
"${@}"

133
tests/docker/Dockerfile Normal file
View File

@ -0,0 +1,133 @@
FROM ubuntu:utopic
MAINTAINER Joel Martin <github@martintribe.org>
ENV DEBIAN_FRONTEND noninteractive
RUN echo "deb http://dl.bintray.com/sbt/debian /" > /etc/apt/sources.list.d/sbt.list
RUN apt-get -y update
#
# General dependencies
#
VOLUME /mal
RUN apt-get -y install make wget curl git
# Deps for compiled languages (C, Go, Rust, Nim, etc)
RUN apt-get -y install gcc pkg-config
# Deps for Java-based languages (Clojure, Scala, Java)
RUN apt-get -y install openjdk-7-jre-headless
ENV MAVEN_OPTS -Duser.home=/mal
# Deps for Mono-based languages (C#, VB.Net)
RUN apt-get -y install mono-runtime mono-mcs mono-vbnc
# Deps for node.js languages (JavaScript, CoffeeScript, miniMAL, etc)
RUN apt-get -y install nodejs npm
RUN ln -sf nodejs /usr/bin/node
#
# Implementation specific installs
#
# Bash
RUN apt-get -y install bash
# C
RUN apt-get -y install libglib2.0 libglib2.0-dev
RUN apt-get -y install libffi-dev libreadline-dev libedit2 libedit-dev
# Clojure
ADD https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein \
/usr/local/bin/lein
RUN sudo chmod 0755 /usr/local/bin/lein
ENV LEIN_HOME /mal/.lein
# CoffeeScript
RUN npm install -g coffee-script
RUN touch /.coffee_history && chmod go+w /.coffee_history
# C#
RUN apt-get -y install mono-mcs
# Forth
RUN apt-get -y install gforth
# Go
RUN apt-get -y install golang
# Haskell
RUN apt-get -y install ghc haskell-platform libghc-readline-dev libghc-editline-dev
# Java
RUN apt-get -y install maven2
# JavaScript
# Already satisfied above
# Lua
RUN apt-get -y install lua5.1 lua-rex-pcre luarocks
RUN luarocks install linenoise
# Mal
# N/A: self-hosted on other language implementations
# GNU Make
# Already satisfied as a based dependency for testing
# miniMAL
RUN npm install -g minimal-lisp
# Nim
RUN git clone -b devel git://github.com/Araq/Nim.git /tmp/Nim
RUN cd /tmp/Nim && git clone -b devel --depth 1 git://github.com/nim-lang/csources
RUN cd /tmp/Nim/csources && sh build.sh
RUN cd /tmp/Nim && bin/nim c koch
RUN cd /tmp/Nim && ./koch boot -d:release
RUN cd /tmp/Nim && ./koch install /usr/local/bin
RUN rm -r /tmp/Nim
# OCaml
RUN apt-get -y install ocaml-batteries-included
# perl
RUN apt-get -y install perl
# PHP
RUN apt-get -y install php5-cli
# PostScript/ghostscript
RUN apt-get -y install ghostscript
# python
RUN apt-get -y install python
# R
RUN apt-get -y install r-base-core
# Racket
RUN apt-get -y install racket
# Ruby
RUN apt-get -y install ruby
# Rust
RUN curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sh
# Scala
RUN apt-get -y --force-yes install sbt
RUN apt-get -y install scala
ENV SBT_OPTS -Duser.home=/mal
# VB.Net
RUN apt-get -y install mono-vbnc
# TODO: move this up with Clojure
ENV LEIN_JVM_OPTS -Duser.home=/mal
ENV DEBIAN_FRONTEND newt
ENV HOME /
WORKDIR /mal