From bb9aee409180d06bb8c4c59a92a1c47106771da6 Mon Sep 17 00:00:00 2001 From: Tiago Katcipis Date: Thu, 29 Jun 2017 20:35:01 -0300 Subject: [PATCH 01/30] Kickoff the stdlib --- docs/reference.md | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/docs/reference.md b/docs/reference.md index 4e1b2b3a..72d6a523 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -171,10 +171,19 @@ echo $a+$b #Output:"12" ``` +# Packages + +TODO + # Iterating +TODO + # Built-in functions +Built-in functions are functions that are embedded on the +language. You do not have to import any package to use them. + ## print The function **print** is used to print simple @@ -237,4 +246,20 @@ example_list <= append($example_list, "2") echo $example_list ``` -# Packages +## exit + +TODO + +## glob + +TODO + +# Standard Library + +The standard library is a set of packages that comes with the +nash install (although not obligatory). + +They must be imported explicitly (as any other package) to +be used. + +* [fmt](docs/stdlib/fmt.md) From bcc89e9cfeb760b7bdf0c3bafd8b8c4d968ff727 Mon Sep 17 00:00:00 2001 From: Tiago Katcipis Date: Thu, 29 Jun 2017 20:53:07 -0300 Subject: [PATCH 02/30] Add println skeleton --- stdlib/fmt.sh | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 stdlib/fmt.sh diff --git a/stdlib/fmt.sh b/stdlib/fmt.sh new file mode 100644 index 00000000..9432663a --- /dev/null +++ b/stdlib/fmt.sh @@ -0,0 +1,3 @@ + +fn println() { +} From 79ec23e41f3e95decd6682a2bfb12710cb5bb7b7 Mon Sep 17 00:00:00 2001 From: Tiago Katcipis Date: Thu, 29 Jun 2017 21:00:14 -0300 Subject: [PATCH 03/30] Add docs for fmt_println --- docs/stdlib/fmt.md | 12 ++++++++++++ stdlib/fmt.sh | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 docs/stdlib/fmt.md diff --git a/docs/stdlib/fmt.md b/docs/stdlib/fmt.md new file mode 100644 index 00000000..10f70520 --- /dev/null +++ b/docs/stdlib/fmt.md @@ -0,0 +1,12 @@ +# fmt + +## fmt_println + +Same behavior as print but adds a newline on the end. + +```nash +import fmt + +fmt_println("hi") +#Output:"hi\n" +``` diff --git a/stdlib/fmt.sh b/stdlib/fmt.sh index 9432663a..e1ef8979 100644 --- a/stdlib/fmt.sh +++ b/stdlib/fmt.sh @@ -1,3 +1,3 @@ -fn println() { +fn fmt_println() { } From b210479d1c00c16f5e7b2d9f4222175470320e35 Mon Sep 17 00:00:00 2001 From: Tiago Katcipis Date: Thu, 29 Jun 2017 21:14:05 -0300 Subject: [PATCH 04/30] Start to unify the build and install process --- Makefile | 18 +++++++++++------- README.md | 20 +++++++++++++++----- cmd/nash/Makefile | 14 -------------- cmd/nashfmt/Makefile | 7 ------- 4 files changed, 26 insertions(+), 33 deletions(-) delete mode 100644 cmd/nash/Makefile delete mode 100644 cmd/nashfmt/Makefile diff --git a/Makefile b/Makefile index 375c89ba..5061f5a7 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,17 @@ +ifndef version +version=$(shell git rev-list -1 HEAD) +endif + +buildargs = -ldflags "-X main.VersionString=$(version)" -v + all: build test install build: - cd cmd/nash && make -e build - cd cmd/nashfmt && make -e build + GO15VENDOREXPERIMENT=1 go build $(buildargs) -o ./cmd/nash/nash ./cmd/nash + GO15VENDOREXPERIMENT=1 go build $(buildargs) -o ./cmd/nashfmt/nashfmt ./cmd/nashfmt + +install: + @echo "TODO" deps: go get -v -t golang.org/x/exp/ebnf @@ -18,11 +27,6 @@ docs: docsdeps test: deps build GO15VENDOREXPERIMENT=1 ./hack/check.sh -install: - cd cmd/nash && make -e install - cd cmd/nashfmt && make -e install - @echo "Nash installed on $(GOPATH)/bin/nash" - update-vendor: cd cmd/nash && nash ./vendor.sh diff --git a/README.md b/README.md index 22f28cf8..1d2b9f5c 100644 --- a/README.md +++ b/README.md @@ -50,13 +50,23 @@ Nash is a system shell, inspired by plan9 `rc`, that makes it easy to create rel ## Installation -If you have Go, go-get it: +Before proceeding to any of the install procedures it is important that you +set in your environment the **NASHPATH** variable, it will be used to find +your libraries and the standard library shipped with the language. -```sh -# Make sure GOPATH/bin is in your PATH -go get github.com/NeowayLabs/nash/cmd/nash +### Release + +TODO + +### Master + +Run: + +``` +make install ``` -If not, [download the latest binary release](https://github.com/NeowayLabs/nash/releases) and copy to somewhere in your PATH. + +And add the directory **$NASHPATH/bin** to your **PATH**. ## Getting started diff --git a/cmd/nash/Makefile b/cmd/nash/Makefile deleted file mode 100644 index bc0e9d9c..00000000 --- a/cmd/nash/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -all: build install - -ifndef version -version=$(shell git rev-list -1 HEAD) -endif - -buildargs = -ldflags "-X main.VersionString=$(version)" -v - -build: - @echo "building nash version: "$(version) - GO15VENDOREXPERIMENT=1 go build $(buildargs) - -install: - GO15VENDOREXPERIMENT=1 go install $(buildargs) diff --git a/cmd/nashfmt/Makefile b/cmd/nashfmt/Makefile deleted file mode 100644 index 61608bba..00000000 --- a/cmd/nashfmt/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -all: build install - -build: - GO15VENDOREXPERIMENT=1 go build -v - -install: - GO15VENDOREXPERIMENT=1 go install From 007a81281cdb89738b2dae3b691cb61120173fff Mon Sep 17 00:00:00 2001 From: Tiago Katcipis Date: Thu, 29 Jun 2017 21:25:58 -0300 Subject: [PATCH 05/30] Add install with check --- Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Makefile b/Makefile index 5061f5a7..53a26423 100644 --- a/Makefile +++ b/Makefile @@ -11,6 +11,9 @@ build: GO15VENDOREXPERIMENT=1 go build $(buildargs) -o ./cmd/nashfmt/nashfmt ./cmd/nashfmt install: +ifndef NASHPATH +$(error NASHPATH must be set in order to install and use nash) +endif @echo "TODO" deps: @@ -23,6 +26,7 @@ docs: docsdeps mdtoc -w ./README.md mdtoc -w ./docs/interactive.md mdtoc -w ./docs/reference.md + mdtoc -w ./docs/stdlib/fmt.md test: deps build GO15VENDOREXPERIMENT=1 ./hack/check.sh From c227d1add3692a7b69c9c035b6768d293ab2d9ff Mon Sep 17 00:00:00 2001 From: Tiago Katcipis Date: Thu, 29 Jun 2017 21:35:41 -0300 Subject: [PATCH 06/30] Add master install --- Makefile | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 53a26423..ccf86d6d 100644 --- a/Makefile +++ b/Makefile @@ -10,11 +10,20 @@ build: GO15VENDOREXPERIMENT=1 go build $(buildargs) -o ./cmd/nash/nash ./cmd/nash GO15VENDOREXPERIMENT=1 go build $(buildargs) -o ./cmd/nashfmt/nashfmt ./cmd/nashfmt -install: +install: build ifndef NASHPATH $(error NASHPATH must be set in order to install and use nash) endif - @echo "TODO" + @echo + @echo "Installing nash at: "$(NASHPATH) + mkdir -p $(NASHPATH)/bin + mkdir -p $(NASHPATH)/lib + rm -f $(NASHPATH)/bin/nash + rm -f $(NASHPATH)/bin/nashfmt + cp -p ./cmd/nash/nash $(NASHPATH)/bin + cp -p ./cmd/nashfmt/nashfmt $(NASHPATH)/bin + rm -rf $(NASHPATH)/stdlib + cp -pr ./stdlib $(NASHPATH)/stdlib deps: go get -v -t golang.org/x/exp/ebnf From e9f30df4bb84941fd4629491d409f4b5af4be986 Mon Sep 17 00:00:00 2001 From: Tiago Katcipis Date: Thu, 29 Jun 2017 21:38:56 -0300 Subject: [PATCH 07/30] Add version to nashfmt --- cmd/nash/main.go | 2 +- cmd/nashfmt/main.go | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/cmd/nash/main.go b/cmd/nash/main.go index 5983fce5..362fb36c 100644 --- a/cmd/nash/main.go +++ b/cmd/nash/main.go @@ -49,7 +49,7 @@ func main() { if version { fmt.Printf("build tag: %s\n", VersionString) - os.Exit(0) + return } if len(flag.Args()) > 0 { diff --git a/cmd/nashfmt/main.go b/cmd/nashfmt/main.go index b5aa887e..46a6f4c2 100644 --- a/cmd/nashfmt/main.go +++ b/cmd/nashfmt/main.go @@ -12,10 +12,14 @@ import ( var ( overwrite bool + version bool + // version is set at build time + VersionString = "No version provided" ) func init() { flag.BoolVar(&overwrite, "w", false, "overwrite file") + flag.BoolVar(&version, "version", false, "Show version") } func main() { @@ -26,6 +30,11 @@ func main() { flag.Parse() + if version { + fmt.Printf("build tag: %s\n", VersionString) + return + } + if len(flag.Args()) <= 0 { flag.PrintDefaults() return From 0cf470fefbc68302757442aa6659c9835631fc66 Mon Sep 17 00:00:00 2001 From: Tiago Katcipis Date: Thu, 29 Jun 2017 21:42:48 -0300 Subject: [PATCH 08/30] remove vendor flag --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index ccf86d6d..7ba9d0d1 100644 --- a/Makefile +++ b/Makefile @@ -7,8 +7,8 @@ buildargs = -ldflags "-X main.VersionString=$(version)" -v all: build test install build: - GO15VENDOREXPERIMENT=1 go build $(buildargs) -o ./cmd/nash/nash ./cmd/nash - GO15VENDOREXPERIMENT=1 go build $(buildargs) -o ./cmd/nashfmt/nashfmt ./cmd/nashfmt + go build $(buildargs) -o ./cmd/nash/nash ./cmd/nash + go build $(buildargs) -o ./cmd/nashfmt/nashfmt ./cmd/nashfmt install: build ifndef NASHPATH From ea4d50da91e789d066d94fc33c718215afea4ec3 Mon Sep 17 00:00:00 2001 From: Tiago Katcipis Date: Thu, 29 Jun 2017 21:56:39 -0300 Subject: [PATCH 09/30] execute NASHPATH validation only on install --- Makefile | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 7ba9d0d1..de2b29bc 100644 --- a/Makefile +++ b/Makefile @@ -10,10 +10,14 @@ build: go build $(buildargs) -o ./cmd/nash/nash ./cmd/nash go build $(buildargs) -o ./cmd/nashfmt/nashfmt ./cmd/nashfmt -install: build -ifndef NASHPATH -$(error NASHPATH must be set in order to install and use nash) -endif + +guard-%: + @ if [ "${${*}}" = "" ]; then \ + echo "'$*' must be set in order to install and use nash"; \ + exit 1; \ + fi + +install: build guard-NASHPATH @echo @echo "Installing nash at: "$(NASHPATH) mkdir -p $(NASHPATH)/bin @@ -38,7 +42,7 @@ docs: docsdeps mdtoc -w ./docs/stdlib/fmt.md test: deps build - GO15VENDOREXPERIMENT=1 ./hack/check.sh + ./hack/check.sh update-vendor: cd cmd/nash && nash ./vendor.sh From 7b9653e43fcc026e9631889364c07778f3134f4f Mon Sep 17 00:00:00 2001 From: Tiago Katcipis Date: Sun, 2 Jul 2017 14:33:02 -0300 Subject: [PATCH 10/30] Fix release to contain bin and stdlib dirs on root --- hack/releaser.sh | 50 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/hack/releaser.sh b/hack/releaser.sh index 916c7e54..5275b90d 100755 --- a/hack/releaser.sh +++ b/hack/releaser.sh @@ -19,18 +19,21 @@ mkdir -p dist fn prepare_execs(distfiles, os) { if $os == "windows" { newfiles = () - + for distfile in $distfiles { - file = $distfile+".exe" - - newfiles <= append($newfiles, $file) + src = $distfile[0] + dst = $distfile[1] + newsrc = $src + ".exe" + newdst = $dst + ".exe" + newfiles <= append($newfiles, ($newsrc $newdst)) } - + return $newfiles } + if $os == "linux" { for distfile in $distfiles { - strip $distfile + strip $distfile[0] } } @@ -45,13 +48,36 @@ for os in $supported_os { echo "building OS: "+$GOOS+" ARCH : "+$GOARCH make build "version="+$version - nash = "cmd/nash/nash" - nashfmt = "cmd/nashfmt/nashfmt" - execfiles = ($nash $nashfmt) + pkgdir <= mktemp -d + bindir = $pkgdir + "/bin" + stdlibdir = $pkgdir + "/stdlib" + mkdir -p $bindir + mkdir -p $stdlibdir + + nash_src = "./cmd/nash/nash" + nash_dst = $bindir + "/nash" + nashfmt_src = "./cmd/nashfmt/nashfmt" + nashfmt_dst = $bindir + "/nashfmt" + + execfiles = ( ($nash_src $nash_dst) ($nashfmt_src $nashfmt_dst) ) + execfiles <= prepare_execs($execfiles, $os) + + # TODO: Improve with glob, right now have only one package =) + distfiles <= append($execfiles, ("./stdlib/fmt.sh" $stdlibdir)) + + for distfile in $distfiles { + src = $distfile[0] + dst = $distfile[1] + cp -pr $src $dst + } - distfiles <= prepare_execs($execfiles, $os) - distar <= format("dist/nash-%s-%s-%s.tar.gz", $version, $os, $arch) + projectdir <= pwd + distar <= format("%s/dist/nash-%s-%s-%s.tar.gz", $projectdir, $version, $os, $arch) - tar cvfz $distar $distfiles + chdir($pkgdir) + pkgraw <= ls + pkgfiles <= split($pkgraw, "\n") + tar cvfz $distar $pkgfiles + chdir($projectdir) } } From 2d9602adde74692880ec7936e50074ee9dbf96bb Mon Sep 17 00:00:00 2001 From: Tiago Katcipis Date: Sun, 2 Jul 2017 14:46:54 -0300 Subject: [PATCH 11/30] Add docs and automation for release install --- README.md | 17 ++++++++++++++--- hack/install/linux.sh | 13 +++++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) create mode 100755 hack/install/linux.sh diff --git a/README.md b/README.md index 1d2b9f5c..5ae699cb 100644 --- a/README.md +++ b/README.md @@ -54,9 +54,22 @@ Before proceeding to any of the install procedures it is important that you set in your environment the **NASHPATH** variable, it will be used to find your libraries and the standard library shipped with the language. +Also add the directory **$NASHPATH/bin** to your **PATH** so you can run +nash in a more practical way (although not necessary). + ### Release -TODO +Installing is so stupid that we provide small scripts to install it. +If your platform is not supported take a look at the existent ones +and send a MR with the script for your platform. + +#### Linux + +Run: + +``` +./hack/install/linux.sh +``` ### Master @@ -66,8 +79,6 @@ Run: make install ``` -And add the directory **$NASHPATH/bin** to your **PATH**. - ## Getting started Nash syntax resembles a common shell: diff --git a/hack/install/linux.sh b/hack/install/linux.sh new file mode 100755 index 00000000..3fe0c134 --- /dev/null +++ b/hack/install/linux.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +set -o errexit +set -o nounset + +VERSION="v0.5" +echo "installing nash: "$VERSION" at NASHPATH: "$NASHPATH + +cd $NASHPATH +tarfile="nash-$VERSION-linux-amd64.tar.gz" +wget https://github.com/NeowayLabs/nash/releases/download/$VERSION/$tarfile +tar xvfz $tarfile +rm -f $tarfile From d5851e286b28e1366caa4f349e8d295c2144335f Mon Sep 17 00:00:00 2001 From: Tiago Katcipis Date: Sun, 2 Jul 2017 14:49:52 -0300 Subject: [PATCH 12/30] Update TOCs --- README.md | 6 ++++++ docs/interactive.md | 2 ++ docs/reference.md | 15 +++++++++++++-- docs/stdlib/fmt.md | 9 +++++++++ 4 files changed, 30 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5ae699cb..866e5708 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ + # Table of Contents - [nash](#nash) @@ -6,6 +7,9 @@ - [Useful stuff](#useful-stuff) - [Why nash scripts are reliable?](#why-nash-scripts-are-reliable) - [Installation](#installation) + - [Release](#release) + - [Linux](#linux) + - [Master](#master) - [Getting started](#getting-started) - [Accessing command line args](#accessing-command-line-args) - [Namespace features](#namespace-features) @@ -16,7 +20,9 @@ - [Security](#security) - [Concept](#concept) - [Motivation](#motivation) +- [Releasing](#releasing) - [Want to contribute?](#want-to-contribute) + # nash diff --git a/docs/interactive.md b/docs/interactive.md index a1015a2e..a15f192f 100644 --- a/docs/interactive.md +++ b/docs/interactive.md @@ -1,10 +1,12 @@ + # Table of Contents - [Line mode](#line-mode) - [Autocomplete](#autocomplete) - [Hooks](#hooks) - [bindfn](#bindfn) + When used as an interactive shell, nash supports a few features to diff --git a/docs/reference.md b/docs/reference.md index 72d6a523..3a6a7ab8 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -1,17 +1,28 @@ + # Table of Contents - [Command line arguments](#command-line-arguments) - [Flow control](#flow-control) + - [Branching](#branching) + - [Looping](#looping) + - [Lists](#lists) + - [Forever](#forever) - [Functions](#functions) - [Operators](#operators) - - [+ (Concatenation)](#-concatenation) + - [+](#) - [string](#string) +- [Packages](#packages) - [Iterating](#iterating) - [Built-in functions](#builtin-functions) + - [print](#print) + - [format](#format) - [len](#len) - [append](#append) -- [Packages](#packages) + - [exit](#exit) + - [glob](#glob) +- [Standard Library](#standard-library) + Here lies a comprehensive reference documentation of nash diff --git a/docs/stdlib/fmt.md b/docs/stdlib/fmt.md index 10f70520..d932c790 100644 --- a/docs/stdlib/fmt.md +++ b/docs/stdlib/fmt.md @@ -1,3 +1,12 @@ + + +# Table of Contents + +- [fmt](#fmt) + - [fmt_println](#fmtprintln) + + + # fmt ## fmt_println From 227a4b8633d8c39ca323e3b24888618363facb83 Mon Sep 17 00:00:00 2001 From: Tiago Katcipis Date: Sun, 2 Jul 2017 18:22:44 -0300 Subject: [PATCH 13/30] Add fmt_println implementation --- Makefile | 1 - hack/check.sh | 4 ++++ stdlib/fmt.sh | 4 +++- stdlib/fmt_example.sh | 3 +++ stdlib/fmt_test.sh | 14 ++++++++++++++ 5 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 stdlib/fmt_example.sh create mode 100644 stdlib/fmt_test.sh diff --git a/Makefile b/Makefile index de2b29bc..ca9e6826 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,6 @@ build: go build $(buildargs) -o ./cmd/nash/nash ./cmd/nash go build $(buildargs) -o ./cmd/nashfmt/nashfmt ./cmd/nashfmt - guard-%: @ if [ "${${*}}" = "" ]; then \ echo "'$*' must be set in order to install and use nash"; \ diff --git a/hack/check.sh b/hack/check.sh index 67be14e2..c89b6883 100755 --- a/hack/check.sh +++ b/hack/check.sh @@ -33,6 +33,10 @@ done $GO tool cover -func coverage.txt +echo "running stdlib tests" +export NASHPATH=`pwd` +./cmd/nash/nash ./stdlib/fmt_test.sh + # To submit the test coverage result to coveralls.io, # use goveralls (https://github.com/mattn/goveralls) # goveralls -coverprofile=profile.cov -service=travis-ci diff --git a/stdlib/fmt.sh b/stdlib/fmt.sh index e1ef8979..5fd629c4 100644 --- a/stdlib/fmt.sh +++ b/stdlib/fmt.sh @@ -1,3 +1,5 @@ -fn fmt_println() { +fn fmt_println(msg, args...) { + s <= format($msg, $args) + print($s + "\n") } diff --git a/stdlib/fmt_example.sh b/stdlib/fmt_example.sh new file mode 100644 index 00000000..fa4fd1ba --- /dev/null +++ b/stdlib/fmt_example.sh @@ -0,0 +1,3 @@ +import fmt + +fmt_println($ARGS[1], $ARGS[2]) diff --git a/stdlib/fmt_test.sh b/stdlib/fmt_test.sh new file mode 100644 index 00000000..11ea3ce3 --- /dev/null +++ b/stdlib/fmt_test.sh @@ -0,0 +1,14 @@ +fn test_println() { + got, status <= ./cmd/nash/nash ./stdlib/fmt_example.sh "hello %s" "world" + if $status != "0" { + exit("1") + } + + expected = "hello world" + if $got != $expected { + print("expected [%s] got [%s]\n", $expected, $got) + exit("1") + } +} + +test_println() From b8c3653d1f2e80c2a895beff5ec0299aa67c4671 Mon Sep 17 00:00:00 2001 From: Tiago Katcipis Date: Sun, 2 Jul 2017 18:29:04 -0300 Subject: [PATCH 14/30] Add stdlib on tries list --- internal/sh/shell.go | 3 ++- stdlib/fmt_test.sh | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/internal/sh/shell.go b/internal/sh/shell.go index ec03672a..bb7af199 100644 --- a/internal/sh/shell.go +++ b/internal/sh/shell.go @@ -803,12 +803,13 @@ func (shell *Shell) executeImport(node *ast.ImportNode) error { if !ok { return errors.NewError("NASHPATH environment variable not set on shell %s", shell.name) } else if nashPath.Type() != sh.StringType { - return errors.NewError("NASHPATH must be n string") + return errors.NewError("NASHPATH must be a string") } dotDir := nashPath.String() tries = append(tries, dotDir+"/lib/"+fname) + tries = append(tries, dotDir+"/stdlib/"+fname+".sh") if !hasExt { tries = append(tries, dotDir+"/lib/"+fname+".sh") diff --git a/stdlib/fmt_test.sh b/stdlib/fmt_test.sh index 11ea3ce3..8f60c1a9 100644 --- a/stdlib/fmt_test.sh +++ b/stdlib/fmt_test.sh @@ -1,3 +1,4 @@ + fn test_println() { got, status <= ./cmd/nash/nash ./stdlib/fmt_example.sh "hello %s" "world" if $status != "0" { From 679da5d2fb5e80be35cc0ad66c9aff855440f59e Mon Sep 17 00:00:00 2001 From: Tiago Katcipis Date: Sun, 2 Jul 2017 18:29:35 -0300 Subject: [PATCH 15/30] stdlib is the last try --- internal/sh/shell.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/sh/shell.go b/internal/sh/shell.go index bb7af199..efc053f0 100644 --- a/internal/sh/shell.go +++ b/internal/sh/shell.go @@ -809,12 +809,13 @@ func (shell *Shell) executeImport(node *ast.ImportNode) error { dotDir := nashPath.String() tries = append(tries, dotDir+"/lib/"+fname) - tries = append(tries, dotDir+"/stdlib/"+fname+".sh") if !hasExt { tries = append(tries, dotDir+"/lib/"+fname+".sh") } + tries = append(tries, dotDir+"/stdlib/"+fname+".sh") + shell.logf("Trying %q\n", tries) for _, path := range tries { From cdd33ff4882deeb78598c9d8fe71f1e024beb527 Mon Sep 17 00:00:00 2001 From: Tiago Katcipis Date: Sun, 2 Jul 2017 19:08:34 -0300 Subject: [PATCH 16/30] Fix stupid bug --- stdlib/fmt.sh | 3 +-- stdlib/fmt_example.sh | 5 +++++ stdlib/fmt_test.sh | 24 ++++++++++++++++++++---- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/stdlib/fmt.sh b/stdlib/fmt.sh index 5fd629c4..3ead6f97 100644 --- a/stdlib/fmt.sh +++ b/stdlib/fmt.sh @@ -1,5 +1,4 @@ fn fmt_println(msg, args...) { - s <= format($msg, $args) - print($s + "\n") + print($msg + "\n", $args...) } diff --git a/stdlib/fmt_example.sh b/stdlib/fmt_example.sh index fa4fd1ba..29e8b8b9 100644 --- a/stdlib/fmt_example.sh +++ b/stdlib/fmt_example.sh @@ -1,3 +1,8 @@ import fmt +if len($ARGS) == "2" { + fmt_println($ARGS[1]) + exit("0") +} + fmt_println($ARGS[1], $ARGS[2]) diff --git a/stdlib/fmt_test.sh b/stdlib/fmt_test.sh index 8f60c1a9..3f96548f 100644 --- a/stdlib/fmt_test.sh +++ b/stdlib/fmt_test.sh @@ -1,15 +1,31 @@ -fn test_println() { - got, status <= ./cmd/nash/nash ./stdlib/fmt_example.sh "hello %s" "world" +fn run_example(args...) { + got, status <= ./cmd/nash/nash ./stdlib/fmt_example.sh $args + return $got, $status +} + +fn assert_success(expected, got, status) { if $status != "0" { exit("1") } - - expected = "hello world" if $got != $expected { print("expected [%s] got [%s]\n", $expected, $got) exit("1") } } +fn test_println_format() { + got, status <= run_example("hello %s", "world") + + assert_success("hello world", $got, $status) +} + +fn test_println() { + expected = "pazu" + got, status <= run_example($expected) + + assert_success($expected, $got, $status) +} + +test_println_format() test_println() From e0c3a442720f1ae927e078767b7f437d7555ed80 Mon Sep 17 00:00:00 2001 From: Tiago Katcipis Date: Sun, 23 Jul 2017 12:15:41 -0300 Subject: [PATCH 17/30] Isolate setenv and unsetenv for each test Guarantee isolation between tests manipulating environment variables. --- internal/sh/shell_linux_test.go | 13 ++- internal/sh/shell_test.go | 174 +++++++++++++++++++++++++------- 2 files changed, 147 insertions(+), 40 deletions(-) diff --git a/internal/sh/shell_linux_test.go b/internal/sh/shell_linux_test.go index f216e8d6..5f18da1d 100644 --- a/internal/sh/shell_linux_test.go +++ b/internal/sh/shell_linux_test.go @@ -49,6 +49,8 @@ func TestExecuteRforkUserNS(t *testing.T) { } var out bytes.Buffer + f, teardown := setup() + defer teardown() sh, err := NewShell() @@ -57,7 +59,7 @@ func TestExecuteRforkUserNS(t *testing.T) { return } - sh.SetNashdPath(nashdPath) + sh.SetNashdPath(f.nashdPath) sh.SetStdout(&out) err = sh.Exec("rfork test", ` @@ -83,6 +85,9 @@ func TestExecuteRforkEnvVars(t *testing.T) { return } + f, teardown := setup() + defer teardown() + sh, err := NewShell() if err != nil { @@ -90,7 +95,7 @@ func TestExecuteRforkEnvVars(t *testing.T) { return } - sh.SetNashdPath(nashdPath) + sh.SetNashdPath(f.nashdPath) err = sh.Exec("test env", `abra = "cadabra" setenv abra @@ -111,6 +116,8 @@ func TestExecuteRforkUserNSNested(t *testing.T) { } var out bytes.Buffer + f, teardown := setup() + defer teardown() sh, err := NewShell() @@ -119,7 +126,7 @@ func TestExecuteRforkUserNSNested(t *testing.T) { return } - sh.SetNashdPath(nashdPath) + sh.SetNashdPath(f.nashdPath) sh.SetStdout(&out) err = sh.Exec("rfork userns nested", ` diff --git a/internal/sh/shell_test.go b/internal/sh/shell_test.go index e0e8fb77..29cdcb08 100644 --- a/internal/sh/shell_test.go +++ b/internal/sh/shell_test.go @@ -23,29 +23,39 @@ type execTestCase struct { expectedErr string } -var ( - testDir, gopath, nashdPath string -) +type fixture struct { + dir string + nashdPath string +} -func init() { - gopath = os.Getenv("GOPATH") +func setup() (fixture, func()) { + gopath := os.Getenv("GOPATH") if gopath == "" { panic("Please, run tests from inside GOPATH") } - testDir = gopath + "/src/github.com/NeowayLabs/nash/" + "testfiles" - nashdPath = gopath + "/src/github.com/NeowayLabs/nash/cmd/nash/nash" + testDir := gopath + "/src/github.com/NeowayLabs/nash/" + "testfiles" + nashdPath := gopath + "/src/github.com/NeowayLabs/nash/cmd/nash/nash" if _, err := os.Stat(nashdPath); err != nil { panic("Please, run make build before running tests") } os.Setenv("NASHPATH", "/tmp/.nash") + + return fixture{ + dir: testDir, + nashdPath: nashdPath, + }, func() { + os.Unsetenv("NASHPATH") + } } func testExecuteFile(t *testing.T, path, expected string) { var out bytes.Buffer + f, teardown := setup() + defer teardown() shell, err := NewShell() @@ -54,7 +64,7 @@ func testExecuteFile(t *testing.T, path, expected string) { return } - shell.SetNashdPath(nashdPath) + shell.SetNashdPath(f.nashdPath) shell.SetStdout(&out) err = shell.ExecFile(path) @@ -107,18 +117,25 @@ func testShellExec(t *testing.T, shell *Shell, testcase execTestCase) { } func testExec(t *testing.T, testcase execTestCase) { + + f, teardown := setup() + defer teardown() + shell, err := NewShell() if err != nil { t.Error(err) return } - shell.SetNashdPath(nashdPath) + shell.SetNashdPath(f.nashdPath) testShellExec(t, shell, testcase) } func testInteractiveExec(t *testing.T, testcase execTestCase) { + f, teardown := setup() + defer teardown() + shell, err := NewShell() if err != nil { @@ -126,7 +143,7 @@ func testInteractiveExec(t *testing.T, testcase execTestCase) { return } - shell.SetNashdPath(nashdPath) + shell.SetNashdPath(f.nashdPath) shell.SetInteractive(true) testShellExec(t, shell, testcase) @@ -156,11 +173,13 @@ func TestExecuteFile(t *testing.T) { path string expected string } + f, teardown := setup() + defer teardown() for _, ftest := range []fileTests{ {path: "/ex1.sh", expected: "hello world\n"}, } { - testExecuteFile(t, testDir+ftest.path, ftest.expected) + testExecuteFile(t, f.dir+ftest.path, ftest.expected) } } @@ -553,6 +572,9 @@ for i in $range { } func TestExecuteRedirection(t *testing.T) { + f, teardown := setup() + defer teardown() + shell, err := NewShell() if err != nil { @@ -560,7 +582,7 @@ func TestExecuteRedirection(t *testing.T) { return } - shell.SetNashdPath(nashdPath) + shell.SetNashdPath(f.nashdPath) path := "/tmp/nashell.test.txt" defer os.Remove(path) @@ -639,6 +661,9 @@ a = ".2" } func TestExecuteRedirectionMap(t *testing.T) { + f, teardown := setup() + defer teardown() + shell, err := NewShell() if err != nil { @@ -646,7 +671,7 @@ func TestExecuteRedirectionMap(t *testing.T) { return } - shell.SetNashdPath(nashdPath) + shell.SetNashdPath(f.nashdPath) err = shell.Exec("redirect map", ` echo -n "hello world" > /tmp/test1.txt @@ -671,24 +696,28 @@ func TestExecuteRedirectionMap(t *testing.T) { } func TestExecuteSetenv(t *testing.T) { + + f, teardown := setup() + defer teardown() + for _, test := range []execTestCase{ { "test setenv basic", `test = "hello" setenv test - ` + nashdPath + ` -c "echo $test"`, + ` + f.nashdPath + ` -c "echo $test"`, "hello\n", "", "", }, { "test setenv assignment", `setenv test = "hello" - ` + nashdPath + ` -c "echo $test"`, + ` + f.nashdPath + ` -c "echo $test"`, "hello\n", "", "", }, { "test setenv exec cmd", `setenv test <= echo -n "hello" - ` + nashdPath + ` -c "echo $test"`, + ` + f.nashdPath + ` -c "echo $test"`, "hello\n", "", "", }, { @@ -745,6 +774,9 @@ func TestExecuteCd(t *testing.T) { func TestExecuteImport(t *testing.T) { var out bytes.Buffer + f, teardown := setup() + defer teardown() + shell, err := NewShell() if err != nil { @@ -752,7 +784,7 @@ func TestExecuteImport(t *testing.T) { return } - shell.SetNashdPath(nashdPath) + shell.SetNashdPath(f.nashdPath) shell.SetStdout(&out) err = ioutil.WriteFile("/tmp/test.sh", []byte(`TESTE="teste"`), 0644) @@ -780,6 +812,9 @@ func TestExecuteImport(t *testing.T) { func TestExecuteIfEqual(t *testing.T) { var out bytes.Buffer + f, teardown := setup() + defer teardown() + shell, err := NewShell() if err != nil { @@ -787,7 +822,7 @@ func TestExecuteIfEqual(t *testing.T) { return } - shell.SetNashdPath(nashdPath) + shell.SetNashdPath(f.nashdPath) shell.SetStdout(&out) err = shell.Exec("test if equal", ` @@ -826,6 +861,9 @@ func TestExecuteIfEqual(t *testing.T) { func TestExecuteIfElse(t *testing.T) { var out bytes.Buffer + f, teardown := setup() + defer teardown() + shell, err := NewShell() if err != nil { @@ -833,7 +871,7 @@ func TestExecuteIfElse(t *testing.T) { return } - shell.SetNashdPath(nashdPath) + shell.SetNashdPath(f.nashdPath) shell.SetStdout(&out) err = shell.Exec("test if else", ` @@ -876,6 +914,9 @@ func TestExecuteIfElse(t *testing.T) { func TestExecuteIfElseIf(t *testing.T) { var out bytes.Buffer + f, teardown := setup() + defer teardown() + shell, err := NewShell() if err != nil { @@ -883,7 +924,7 @@ func TestExecuteIfElseIf(t *testing.T) { return } - shell.SetNashdPath(nashdPath) + shell.SetNashdPath(f.nashdPath) shell.SetStdout(&out) err = shell.Exec("test if else", ` @@ -924,6 +965,10 @@ func TestExecuteIfElseIf(t *testing.T) { } func TestExecuteFnDecl(t *testing.T) { + + f, teardown := setup() + defer teardown() + shell, err := NewShell() if err != nil { @@ -931,7 +976,7 @@ func TestExecuteFnDecl(t *testing.T) { return } - shell.SetNashdPath(nashdPath) + shell.SetNashdPath(f.nashdPath) err = shell.Exec("test fnDecl", ` fn build(image, debug) { @@ -945,6 +990,10 @@ func TestExecuteFnDecl(t *testing.T) { } func TestExecuteFnInv(t *testing.T) { + + f, teardown := setup() + defer teardown() + shell, err := NewShell() if err != nil { @@ -952,7 +1001,7 @@ func TestExecuteFnInv(t *testing.T) { return } - shell.SetNashdPath(nashdPath) + shell.SetNashdPath(f.nashdPath) var out bytes.Buffer @@ -1093,6 +1142,10 @@ func TestFnComposition(t *testing.T) { } func TestExecuteFnInvOthers(t *testing.T) { + + f, teardown := setup() + defer teardown() + shell, err := NewShell() if err != nil { @@ -1100,7 +1153,7 @@ func TestExecuteFnInvOthers(t *testing.T) { return } - shell.SetNashdPath(nashdPath) + shell.SetNashdPath(f.nashdPath) var out bytes.Buffer @@ -1133,6 +1186,10 @@ echo -n $integers } func TestNonInteractive(t *testing.T) { + + f, teardown := setup() + defer teardown() + shell, err := NewShell() if err != nil { @@ -1140,7 +1197,7 @@ func TestNonInteractive(t *testing.T) { return } - shell.SetNashdPath(nashdPath) + shell.SetNashdPath(f.nashdPath) shell.SetInteractive(true) testShellExec(t, shell, execTestCase{ @@ -1217,8 +1274,11 @@ func TestExecutePipe(t *testing.T) { var stderr bytes.Buffer var stdout bytes.Buffer + f, teardown := setup() + defer teardown() + // Case 1 - cmd := exec.Command(nashdPath, "-c", `echo hello | tr -d "[:space:]"`) + cmd := exec.Command(f.nashdPath, "-c", `echo hello | tr -d "[:space:]"`) cmd.Stderr = &stderr cmd.Stdout = &stdout @@ -1240,7 +1300,7 @@ func TestExecutePipe(t *testing.T) { stderr.Reset() // Case 2 - cmd = exec.Command(nashdPath, "-c", `echo hello | wc -l | tr -d "[:space:]"`) + cmd = exec.Command(f.nashdPath, "-c", `echo hello | wc -l | tr -d "[:space:]"`) cmd.Stderr = &stderr cmd.Stdout = &stdout @@ -1263,7 +1323,10 @@ func TestExecutePipe(t *testing.T) { func TestExecuteRedirectionPipe(t *testing.T) { var stderr bytes.Buffer - cmd := exec.Command(nashdPath, "-c", `cat stuff >[2=] | grep file`) + f, teardown := setup() + defer teardown() + + cmd := exec.Command(f.nashdPath, "-c", `cat stuff >[2=] | grep file`) cmd.Stderr = &stderr @@ -1302,6 +1365,9 @@ func testTCPRedirection(t *testing.T, port, command string) { t.Fatal(err) } + f, teardown := setup() + defer teardown() + go func() { shell, err := NewShell() @@ -1310,7 +1376,7 @@ func testTCPRedirection(t *testing.T, port, command string) { return } - shell.SetNashdPath(nashdPath) + shell.SetNashdPath(f.nashdPath) <-done @@ -1374,6 +1440,9 @@ func TestExecuteUnixRedirection(t *testing.T) { done := make(chan bool) writeDone := make(chan bool) + f, teardown := setup() + defer teardown() + go func() { defer func() { writeDone <- true @@ -1386,7 +1455,7 @@ func TestExecuteUnixRedirection(t *testing.T) { return } - shell.SetNashdPath(nashdPath) + shell.SetNashdPath(f.nashdPath) <-done @@ -1437,6 +1506,9 @@ func TestExecuteUnixRedirection(t *testing.T) { func TestExecuteUDPRedirection(t *testing.T) { message := "hello world" + f, teardown := setup() + defer teardown() + done := make(chan bool) writeDone := make(chan bool) @@ -1452,7 +1524,7 @@ func TestExecuteUDPRedirection(t *testing.T) { return } - shell.SetNashdPath(nashdPath) + shell.SetNashdPath(f.nashdPath) <-done @@ -1577,6 +1649,10 @@ echo -n $a`, } func TestExecuteFnAsFirstClass(t *testing.T) { + + f, teardown := setup() + defer teardown() + shell, err := NewShell() if err != nil { @@ -1584,7 +1660,7 @@ func TestExecuteFnAsFirstClass(t *testing.T) { return } - shell.SetNashdPath(nashdPath) + shell.SetNashdPath(f.nashdPath) var out bytes.Buffer @@ -1616,6 +1692,10 @@ func TestExecuteFnAsFirstClass(t *testing.T) { } func TestExecuteDump(t *testing.T) { + + f, teardown := setup() + defer teardown() + shell, err := NewShell() if err != nil { @@ -1623,7 +1703,7 @@ func TestExecuteDump(t *testing.T) { return } - shell.SetNashdPath(nashdPath) + shell.SetNashdPath(f.nashdPath) shell.Reset() var out bytes.Buffer @@ -1709,6 +1789,10 @@ func TestExecuteDump(t *testing.T) { } func TestExecuteDumpVariable(t *testing.T) { + + f, teardown := setup() + defer teardown() + shell, err := NewShell() if err != nil { @@ -1716,7 +1800,7 @@ func TestExecuteDumpVariable(t *testing.T) { return } - shell.SetNashdPath(nashdPath) + shell.SetNashdPath(f.nashdPath) shell.Reset() var out bytes.Buffer @@ -1776,6 +1860,10 @@ func TestExecuteDumpVariable(t *testing.T) { } func TestExecuteConcat(t *testing.T) { + + f, teardown := setup() + defer teardown() + shell, err := NewShell() if err != nil { @@ -1783,7 +1871,7 @@ func TestExecuteConcat(t *testing.T) { return } - shell.SetNashdPath(nashdPath) + shell.SetNashdPath(f.nashdPath) shell.Reset() var out bytes.Buffer @@ -1824,6 +1912,10 @@ echo -n $c`) } func TestExecuteFor(t *testing.T) { + + f, teardown := setup() + defer teardown() + shell, err := NewShell() if err != nil { @@ -1831,7 +1923,7 @@ func TestExecuteFor(t *testing.T) { return } - shell.SetNashdPath(nashdPath) + shell.SetNashdPath(f.nashdPath) var out bytes.Buffer @@ -1862,6 +1954,10 @@ loop` } func TestExecuteInfiniteLoop(t *testing.T) { + + f, teardown := setup() + defer teardown() + shell, err := NewShell() if err != nil { @@ -1869,7 +1965,7 @@ func TestExecuteInfiniteLoop(t *testing.T) { return } - shell.SetNashdPath(nashdPath) + shell.SetNashdPath(f.nashdPath) doneCtrlc := make(chan bool) doneLoop := make(chan bool) @@ -1917,6 +2013,10 @@ func TestExecuteInfiniteLoop(t *testing.T) { } func TestExecuteVariableIndexing(t *testing.T) { + + f, teardown := setup() + defer teardown() + shell, err := NewShell() if err != nil { @@ -1926,7 +2026,7 @@ func TestExecuteVariableIndexing(t *testing.T) { var out bytes.Buffer - shell.SetNashdPath(nashdPath) + shell.SetNashdPath(f.nashdPath) shell.SetStdout(&out) err = shell.Exec("indexing", `list = ("1" "2" "3") From d3e418d4d79f2add158a0047258864b2aef4a047 Mon Sep 17 00:00:00 2001 From: Tiago Katcipis Date: Sun, 23 Jul 2017 12:59:10 -0300 Subject: [PATCH 18/30] Add initial env tests --- internal/sh/shell_env_test.go | 42 ++++++++++++++++++++ internal/sh/shell_linux_test.go | 6 +-- internal/sh/shell_test.go | 70 ++++++++++++++++++--------------- 3 files changed, 83 insertions(+), 35 deletions(-) create mode 100644 internal/sh/shell_env_test.go diff --git a/internal/sh/shell_env_test.go b/internal/sh/shell_env_test.go new file mode 100644 index 00000000..249da48c --- /dev/null +++ b/internal/sh/shell_env_test.go @@ -0,0 +1,42 @@ +package sh + +import ( + "io/ioutil" + "os" + "testing" +) + +func TestDefaultNashPath(t *testing.T) { +} + +func TestLoadsStdlibFromNASHROOT(t *testing.T) { +} + +func TestLoadsStdlibFromDefaultNASHROOT(t *testing.T) { +} + +func TestLoadsStdlibFromGOPATHOnDefaultFailure(t *testing.T) { +} + +func setupHome(t *testing.T) (string, func()) { + + home, err := ioutil.TempDir("", "shellenvtests") + if err != nil { + t.Fatal(err) + } + err = os.Setenv("HOME", home) + if err != nil { + t.Fatal(err) + } + + return home, func() { + err := os.Unsetenv("HOME") + if err != nil { + t.Fatal(err) + } + err = os.RemoveAll(home) + if err != nil { + t.Fatal(err) + } + } +} diff --git a/internal/sh/shell_linux_test.go b/internal/sh/shell_linux_test.go index 5f18da1d..3b451719 100644 --- a/internal/sh/shell_linux_test.go +++ b/internal/sh/shell_linux_test.go @@ -49,7 +49,7 @@ func TestExecuteRforkUserNS(t *testing.T) { } var out bytes.Buffer - f, teardown := setup() + f, teardown := setup(t) defer teardown() sh, err := NewShell() @@ -85,7 +85,7 @@ func TestExecuteRforkEnvVars(t *testing.T) { return } - f, teardown := setup() + f, teardown := setup(t) defer teardown() sh, err := NewShell() @@ -116,7 +116,7 @@ func TestExecuteRforkUserNSNested(t *testing.T) { } var out bytes.Buffer - f, teardown := setup() + f, teardown := setup(t) defer teardown() sh, err := NewShell() diff --git a/internal/sh/shell_test.go b/internal/sh/shell_test.go index 29cdcb08..2e240be6 100644 --- a/internal/sh/shell_test.go +++ b/internal/sh/shell_test.go @@ -28,33 +28,39 @@ type fixture struct { nashdPath string } -func setup() (fixture, func()) { +func setup(t *testing.T) (fixture, func()) { gopath := os.Getenv("GOPATH") if gopath == "" { - panic("Please, run tests from inside GOPATH") + t.Fatal("Please, run tests from inside GOPATH") } testDir := gopath + "/src/github.com/NeowayLabs/nash/" + "testfiles" nashdPath := gopath + "/src/github.com/NeowayLabs/nash/cmd/nash/nash" if _, err := os.Stat(nashdPath); err != nil { - panic("Please, run make build before running tests") + t.Fatal("Please, run make build before running tests") } - os.Setenv("NASHPATH", "/tmp/.nash") + err := os.Setenv("NASHPATH", "/tmp/.nash") + if err != nil { + t.Fatal(err) + } return fixture{ dir: testDir, nashdPath: nashdPath, }, func() { - os.Unsetenv("NASHPATH") + err := os.Unsetenv("NASHPATH") + if err != nil { + t.Fatal(err) + } } } func testExecuteFile(t *testing.T, path, expected string) { var out bytes.Buffer - f, teardown := setup() + f, teardown := setup(t) defer teardown() shell, err := NewShell() @@ -118,7 +124,7 @@ func testShellExec(t *testing.T, shell *Shell, testcase execTestCase) { func testExec(t *testing.T, testcase execTestCase) { - f, teardown := setup() + f, teardown := setup(t) defer teardown() shell, err := NewShell() @@ -133,7 +139,7 @@ func testExec(t *testing.T, testcase execTestCase) { } func testInteractiveExec(t *testing.T, testcase execTestCase) { - f, teardown := setup() + f, teardown := setup(t) defer teardown() shell, err := NewShell() @@ -173,7 +179,7 @@ func TestExecuteFile(t *testing.T) { path string expected string } - f, teardown := setup() + f, teardown := setup(t) defer teardown() for _, ftest := range []fileTests{ @@ -572,7 +578,7 @@ for i in $range { } func TestExecuteRedirection(t *testing.T) { - f, teardown := setup() + f, teardown := setup(t) defer teardown() shell, err := NewShell() @@ -661,7 +667,7 @@ a = ".2" } func TestExecuteRedirectionMap(t *testing.T) { - f, teardown := setup() + f, teardown := setup(t) defer teardown() shell, err := NewShell() @@ -697,7 +703,7 @@ func TestExecuteRedirectionMap(t *testing.T) { func TestExecuteSetenv(t *testing.T) { - f, teardown := setup() + f, teardown := setup(t) defer teardown() for _, test := range []execTestCase{ @@ -774,7 +780,7 @@ func TestExecuteCd(t *testing.T) { func TestExecuteImport(t *testing.T) { var out bytes.Buffer - f, teardown := setup() + f, teardown := setup(t) defer teardown() shell, err := NewShell() @@ -812,7 +818,7 @@ func TestExecuteImport(t *testing.T) { func TestExecuteIfEqual(t *testing.T) { var out bytes.Buffer - f, teardown := setup() + f, teardown := setup(t) defer teardown() shell, err := NewShell() @@ -861,7 +867,7 @@ func TestExecuteIfEqual(t *testing.T) { func TestExecuteIfElse(t *testing.T) { var out bytes.Buffer - f, teardown := setup() + f, teardown := setup(t) defer teardown() shell, err := NewShell() @@ -914,7 +920,7 @@ func TestExecuteIfElse(t *testing.T) { func TestExecuteIfElseIf(t *testing.T) { var out bytes.Buffer - f, teardown := setup() + f, teardown := setup(t) defer teardown() shell, err := NewShell() @@ -966,7 +972,7 @@ func TestExecuteIfElseIf(t *testing.T) { func TestExecuteFnDecl(t *testing.T) { - f, teardown := setup() + f, teardown := setup(t) defer teardown() shell, err := NewShell() @@ -991,7 +997,7 @@ func TestExecuteFnDecl(t *testing.T) { func TestExecuteFnInv(t *testing.T) { - f, teardown := setup() + f, teardown := setup(t) defer teardown() shell, err := NewShell() @@ -1143,7 +1149,7 @@ func TestFnComposition(t *testing.T) { func TestExecuteFnInvOthers(t *testing.T) { - f, teardown := setup() + f, teardown := setup(t) defer teardown() shell, err := NewShell() @@ -1187,7 +1193,7 @@ echo -n $integers func TestNonInteractive(t *testing.T) { - f, teardown := setup() + f, teardown := setup(t) defer teardown() shell, err := NewShell() @@ -1274,7 +1280,7 @@ func TestExecutePipe(t *testing.T) { var stderr bytes.Buffer var stdout bytes.Buffer - f, teardown := setup() + f, teardown := setup(t) defer teardown() // Case 1 @@ -1323,7 +1329,7 @@ func TestExecutePipe(t *testing.T) { func TestExecuteRedirectionPipe(t *testing.T) { var stderr bytes.Buffer - f, teardown := setup() + f, teardown := setup(t) defer teardown() cmd := exec.Command(f.nashdPath, "-c", `cat stuff >[2=] | grep file`) @@ -1365,7 +1371,7 @@ func testTCPRedirection(t *testing.T, port, command string) { t.Fatal(err) } - f, teardown := setup() + f, teardown := setup(t) defer teardown() go func() { @@ -1440,7 +1446,7 @@ func TestExecuteUnixRedirection(t *testing.T) { done := make(chan bool) writeDone := make(chan bool) - f, teardown := setup() + f, teardown := setup(t) defer teardown() go func() { @@ -1506,7 +1512,7 @@ func TestExecuteUnixRedirection(t *testing.T) { func TestExecuteUDPRedirection(t *testing.T) { message := "hello world" - f, teardown := setup() + f, teardown := setup(t) defer teardown() done := make(chan bool) @@ -1650,7 +1656,7 @@ echo -n $a`, func TestExecuteFnAsFirstClass(t *testing.T) { - f, teardown := setup() + f, teardown := setup(t) defer teardown() shell, err := NewShell() @@ -1693,7 +1699,7 @@ func TestExecuteFnAsFirstClass(t *testing.T) { func TestExecuteDump(t *testing.T) { - f, teardown := setup() + f, teardown := setup(t) defer teardown() shell, err := NewShell() @@ -1790,7 +1796,7 @@ func TestExecuteDump(t *testing.T) { func TestExecuteDumpVariable(t *testing.T) { - f, teardown := setup() + f, teardown := setup(t) defer teardown() shell, err := NewShell() @@ -1861,7 +1867,7 @@ func TestExecuteDumpVariable(t *testing.T) { func TestExecuteConcat(t *testing.T) { - f, teardown := setup() + f, teardown := setup(t) defer teardown() shell, err := NewShell() @@ -1913,7 +1919,7 @@ echo -n $c`) func TestExecuteFor(t *testing.T) { - f, teardown := setup() + f, teardown := setup(t) defer teardown() shell, err := NewShell() @@ -1955,7 +1961,7 @@ loop` func TestExecuteInfiniteLoop(t *testing.T) { - f, teardown := setup() + f, teardown := setup(t) defer teardown() shell, err := NewShell() @@ -2014,7 +2020,7 @@ func TestExecuteInfiniteLoop(t *testing.T) { func TestExecuteVariableIndexing(t *testing.T) { - f, teardown := setup() + f, teardown := setup(t) defer teardown() shell, err := NewShell() From 87ba285f8ff30f0af3d39ab1d7b5d37de89dc67c Mon Sep 17 00:00:00 2001 From: Tiago Katcipis Date: Sun, 23 Jul 2017 14:59:25 -0300 Subject: [PATCH 19/30] Add first failing test for default NASHPATH --- internal/sh/shell_env_test.go | 104 +++++++++++++++++++++++++++++----- 1 file changed, 91 insertions(+), 13 deletions(-) diff --git a/internal/sh/shell_env_test.go b/internal/sh/shell_env_test.go index 249da48c..16c923ed 100644 --- a/internal/sh/shell_env_test.go +++ b/internal/sh/shell_env_test.go @@ -1,42 +1,120 @@ package sh import ( + "bytes" "io/ioutil" "os" "testing" ) -func TestDefaultNashPath(t *testing.T) { +func TestLoadsLibFromNASHPATH(t *testing.T) { + f, teardown := setupHome(t) + defer teardown() + + writeFile(t, f.home+"/lib.sh", ` + fn test() { + echo "hi" + } + `) + + f.Exec(t, ` + import lib + + test() + `, "hi\n") +} + +func TestLoadsLibFromHOMEIfNASHPATHIsUnset(t *testing.T) { +} + +func TestFailsToLoadLibIfHomeIsUnset(t *testing.T) { } func TestLoadsStdlibFromNASHROOT(t *testing.T) { } -func TestLoadsStdlibFromDefaultNASHROOT(t *testing.T) { +func TestLoadsStdlibFromHOMEIfNASHROOTIsUnset(t *testing.T) { +} + +func TestLoadsStdlibFromGOPATHOnIfStdlibNotOnHOME(t *testing.T) { +} + +func TestLoadsStdlibFromGOPATHOnIfHOMEIsUnset(t *testing.T) { +} + +func TestStdlibFailsIfStdlibNotOnGOPATH(t *testing.T) { +} + +func TestStdlibFailsIfGOPATHIsUnset(t *testing.T) { +} + +type envfixture struct { + home string + shell *Shell + stdout *bytes.Buffer } -func TestLoadsStdlibFromGOPATHOnDefaultFailure(t *testing.T) { +func (e *envfixture) Exec(t *testing.T, code string, expectedOutupt string) { + err := e.shell.Exec("shellenvtest", code) + if err != nil { + t.Fatal(err) + } + + output := e.stdout.String() + e.stdout.Reset() + + if output != expectedOutupt { + t.Fatalf( + "expected output: [%s] got: [%s]", + expectedOutupt, + output, + ) + } } -func setupHome(t *testing.T) (string, func()) { +func setupHome(t *testing.T) (envfixture, func()) { - home, err := ioutil.TempDir("", "shellenvtests") + home, err := ioutil.TempDir("", "nashenvtests") if err != nil { t.Fatal(err) } + + curhome := os.Getenv("HOME") + err = os.Setenv("HOME", home) if err != nil { t.Fatal(err) } - return home, func() { - err := os.Unsetenv("HOME") - if err != nil { - t.Fatal(err) - } - err = os.RemoveAll(home) - if err != nil { - t.Fatal(err) + shell, err := NewShell() + if err != nil { + t.Fatal(err) + } + var out bytes.Buffer + shell.SetStdout(&out) + + return envfixture{ + home: home, + shell: shell, + stdout: &out, + }, func() { + errs := []error{} + errs = append(errs, os.Setenv("HOME", curhome)) + errs = append(errs, os.Unsetenv("NASHPATH")) + errs = append(errs, os.Unsetenv("NASHROOT")) + errs = append(errs, os.RemoveAll(home)) + + for _, err := range errs { + if err != nil { + t.Errorf("error tearing down: %s", err) + } + } } +} + +func writeFile(t *testing.T, filename string, data string) { + err := ioutil.WriteFile(filename, []byte(data), os.ModePerm) + if err != nil { + t.Fatal(err) } } From d5097e156f1ff8444932147f0d25a171e07ef2d6 Mon Sep 17 00:00:00 2001 From: Tiago Katcipis Date: Sun, 23 Jul 2017 15:54:34 -0300 Subject: [PATCH 20/30] Write first test with some refactoring --- internal/sh/shell.go | 33 +++++++++++---- internal/sh/shell_env_test.go | 75 ++++++++++++++++++++--------------- 2 files changed, 69 insertions(+), 39 deletions(-) diff --git a/internal/sh/shell.go b/internal/sh/shell.go index efc053f0..d50ca15a 100644 --- a/internal/sh/shell.go +++ b/internal/sh/shell.go @@ -752,6 +752,28 @@ func (shell *Shell) executeReturn(n *ast.ReturnNode) ([]sh.Obj, error) { return returns, newErrStopWalking() } +func (shell *Shell) getNashPath() (string, error) { + // TODO: + // Test behavior without HOME + // Test HOME not a string + + //h, _ := shell.Getenv("HOME") + //home := h.String() + + nashPath, ok := shell.Getenv("NASHPATH") + + if !ok { + return "", errors.NewError("NASHPATH must be set") + } + + if nashPath.Type() != sh.StringType { + return "", errors.NewError("NASHPATH must be a string") + } + + return nashPath.String(), nil + +} + func (shell *Shell) executeImport(node *ast.ImportNode) error { obj, err := shell.evalExpr(node.Path) if err != nil { @@ -798,16 +820,11 @@ func (shell *Shell) executeImport(node *ast.ImportNode) error { } } - nashPath, ok := shell.Getenv("NASHPATH") - - if !ok { - return errors.NewError("NASHPATH environment variable not set on shell %s", shell.name) - } else if nashPath.Type() != sh.StringType { - return errors.NewError("NASHPATH must be a string") + dotDir, err := shell.getNashPath() + if err != nil { + return err } - dotDir := nashPath.String() - tries = append(tries, dotDir+"/lib/"+fname) if !hasExt { diff --git a/internal/sh/shell_env_test.go b/internal/sh/shell_env_test.go index 16c923ed..c9b03f1e 100644 --- a/internal/sh/shell_env_test.go +++ b/internal/sh/shell_env_test.go @@ -8,16 +8,22 @@ import ( ) func TestLoadsLibFromNASHPATH(t *testing.T) { - f, teardown := setupHome(t) + home, teardown := setupEnvTests(t) defer teardown() - writeFile(t, f.home+"/lib.sh", ` + nashpath := home + "/testnashpath" + os.Setenv("NASHPATH", nashpath) + + nashlib := nashpath + "/lib" + mkdirAll(t, nashlib) + + writeFile(t, nashlib+"/lib.sh", ` fn test() { echo "hi" } `) - f.Exec(t, ` + newTestShell(t).Exec(t, ` import lib test() @@ -48,20 +54,19 @@ func TestStdlibFailsIfStdlibNotOnGOPATH(t *testing.T) { func TestStdlibFailsIfGOPATHIsUnset(t *testing.T) { } -type envfixture struct { - home string +type testshell struct { shell *Shell stdout *bytes.Buffer } -func (e *envfixture) Exec(t *testing.T, code string, expectedOutupt string) { - err := e.shell.Exec("shellenvtest", code) +func (s *testshell) Exec(t *testing.T, code string, expectedOutupt string) { + err := s.shell.Exec("shellenvtest", code) if err != nil { t.Fatal(err) } - output := e.stdout.String() - e.stdout.Reset() + output := s.stdout.String() + s.stdout.Reset() if output != expectedOutupt { t.Fatalf( @@ -72,44 +77,52 @@ func (e *envfixture) Exec(t *testing.T, code string, expectedOutupt string) { } } -func setupHome(t *testing.T) (envfixture, func()) { +func newTestShell(t *testing.T) *testshell { - home, err := ioutil.TempDir("", "nashenvtests") + shell, err := NewShell() if err != nil { t.Fatal(err) } + var out bytes.Buffer + shell.SetStdout(&out) - curhome := os.Getenv("HOME") + return &testshell{shell: shell, stdout: &out} +} - err = os.Setenv("HOME", home) +func setupEnvTests(t *testing.T) (string, func()) { + + home, err := ioutil.TempDir("", "nashenvtests") if err != nil { t.Fatal(err) } - shell, err := NewShell() + curhome := os.Getenv("HOME") + + err = os.Setenv("HOME", home) if err != nil { t.Fatal(err) } - var out bytes.Buffer - shell.SetStdout(&out) - return envfixture{ - home: home, - shell: shell, - stdout: &out, - }, func() { - errs := []error{} - errs = append(errs, os.Setenv("HOME", curhome)) - errs = append(errs, os.Unsetenv("NASHPATH")) - errs = append(errs, os.Unsetenv("NASHROOT")) - errs = append(errs, os.RemoveAll(home)) - - for _, err := range errs { - if err != nil { - t.Errorf("error tearing down: %s", err) - } + return home, func() { + errs := []error{} + errs = append(errs, os.Setenv("HOME", curhome)) + errs = append(errs, os.Unsetenv("NASHPATH")) + errs = append(errs, os.Unsetenv("NASHROOT")) + errs = append(errs, os.RemoveAll(home)) + + for _, err := range errs { + if err != nil { + t.Errorf("error tearing down: %s", err) } } + } +} + +func mkdirAll(t *testing.T, nashlib string) { + err := os.MkdirAll(nashlib, os.ModePerm) + if err != nil { + t.Fatal(err) + } } func writeFile(t *testing.T, filename string, data string) { From a23eee538f35210b8ead9f25a572521d30e8046b Mon Sep 17 00:00:00 2001 From: Tiago Katcipis Date: Sun, 23 Jul 2017 15:59:02 -0300 Subject: [PATCH 21/30] Add default nashpath test --- internal/sh/shell.go | 7 ++++--- internal/sh/shell_env_test.go | 21 +++++++++++++++++++-- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/internal/sh/shell.go b/internal/sh/shell.go index d50ca15a..37b58f42 100644 --- a/internal/sh/shell.go +++ b/internal/sh/shell.go @@ -756,14 +756,15 @@ func (shell *Shell) getNashPath() (string, error) { // TODO: // Test behavior without HOME // Test HOME not a string + // It is very annoying to load env vars, perhaps a shell.GetStringEnv ? - //h, _ := shell.Getenv("HOME") - //home := h.String() + h, _ := shell.Getenv("HOME") + home := h.String() nashPath, ok := shell.Getenv("NASHPATH") if !ok { - return "", errors.NewError("NASHPATH must be set") + return home + "/nash", nil } if nashPath.Type() != sh.StringType { diff --git a/internal/sh/shell_env_test.go b/internal/sh/shell_env_test.go index c9b03f1e..b184960c 100644 --- a/internal/sh/shell_env_test.go +++ b/internal/sh/shell_env_test.go @@ -19,7 +19,7 @@ func TestLoadsLibFromNASHPATH(t *testing.T) { writeFile(t, nashlib+"/lib.sh", ` fn test() { - echo "hi" + echo "hasnashpath" } `) @@ -27,10 +27,27 @@ func TestLoadsLibFromNASHPATH(t *testing.T) { import lib test() - `, "hi\n") + `, "hasnashpath\n") } func TestLoadsLibFromHOMEIfNASHPATHIsUnset(t *testing.T) { + home, teardown := setupEnvTests(t) + defer teardown() + + nashlib := home + "/nash/lib" + mkdirAll(t, nashlib) + + writeFile(t, nashlib+"/lib.sh", ` + fn test() { + echo "defaultnashpath" + } + `) + + newTestShell(t).Exec(t, ` + import lib + + test() + `, "defaultnashpath\n") } func TestFailsToLoadLibIfHomeIsUnset(t *testing.T) { From 6ca1cd2717900db76a0b8a90471c75aefb7e7230 Mon Sep 17 00:00:00 2001 From: Tiago Katcipis Date: Sun, 23 Jul 2017 16:26:47 -0300 Subject: [PATCH 22/30] Add NASHROOT initial code --- internal/sh/shell.go | 31 ++++++++++++++++++++++++++++++- internal/sh/shell_env_test.go | 28 ++++++++++++++++++++++------ 2 files changed, 52 insertions(+), 7 deletions(-) diff --git a/internal/sh/shell.go b/internal/sh/shell.go index 37b58f42..fc4e0f9d 100644 --- a/internal/sh/shell.go +++ b/internal/sh/shell.go @@ -752,6 +752,29 @@ func (shell *Shell) executeReturn(n *ast.ReturnNode) ([]sh.Obj, error) { return returns, newErrStopWalking() } +func (shell *Shell) getNashRoot() (string, error) { + // TODO: + // Test behavior without HOME + // Test HOME not a string + // It is very annoying to load env vars, perhaps a shell.GetStringEnv ? + + //h, _ := shell.Getenv("HOME") + //home := h.String() + + nashroot, ok := shell.Getenv("NASHROOT") + + if !ok { + return "", errors.NewError("NASHROOT must be set") + } + + if nashroot.Type() != sh.StringType { + return "", errors.NewError("NASHROOT must be a string") + } + + return nashroot.String(), nil + +} + func (shell *Shell) getNashPath() (string, error) { // TODO: // Test behavior without HOME @@ -832,7 +855,13 @@ func (shell *Shell) executeImport(node *ast.ImportNode) error { tries = append(tries, dotDir+"/lib/"+fname+".sh") } - tries = append(tries, dotDir+"/stdlib/"+fname+".sh") + nashroot, err := shell.getNashRoot() + if err == nil { + tries = append(tries, nashroot+"/stdlib/"+fname+".sh") + } else { + // TODO: Fail if there is no nashroot present ? + shell.logf("unable to define a NASHROOT, there will be no stdlib available: error[%s]\n", err) + } shell.logf("Trying %q\n", tries) diff --git a/internal/sh/shell_env_test.go b/internal/sh/shell_env_test.go index b184960c..ef5bdc82 100644 --- a/internal/sh/shell_env_test.go +++ b/internal/sh/shell_env_test.go @@ -25,7 +25,6 @@ func TestLoadsLibFromNASHPATH(t *testing.T) { newTestShell(t).Exec(t, ` import lib - test() `, "hasnashpath\n") } @@ -45,15 +44,34 @@ func TestLoadsLibFromHOMEIfNASHPATHIsUnset(t *testing.T) { newTestShell(t).Exec(t, ` import lib - test() `, "defaultnashpath\n") } func TestFailsToLoadLibIfHomeIsUnset(t *testing.T) { + // TODO: Explode or just fails for not founding the lib ? } func TestLoadsStdlibFromNASHROOT(t *testing.T) { + home, teardown := setupEnvTests(t) + defer teardown() + + nashroot := home + "/testnashroot" + os.Setenv("NASHROOT", nashroot) + + nashstdlib := nashroot + "/stdlib" + mkdirAll(t, nashstdlib) + + writeFile(t, nashstdlib+"/lib.sh", ` + fn test() { + echo "hasnashroot" + } + `) + + newTestShell(t).Exec(t, ` + import lib + test() + `, "hasnashroot\n") } func TestLoadsStdlibFromHOMEIfNASHROOTIsUnset(t *testing.T) { @@ -65,10 +83,8 @@ func TestLoadsStdlibFromGOPATHOnIfStdlibNotOnHOME(t *testing.T) { func TestLoadsStdlibFromGOPATHOnIfHOMEIsUnset(t *testing.T) { } -func TestStdlibFailsIfStdlibNotOnGOPATH(t *testing.T) { -} - -func TestStdlibFailsIfGOPATHIsUnset(t *testing.T) { +func TestFailsToLoadStdlibIfGOPATHIsUnset(t *testing.T) { + // TODO: Explode or just fails for not founding the lib ? } type testshell struct { From c34a15a626bd6db0019def2f67027776863e2620 Mon Sep 17 00:00:00 2001 From: Tiago Katcipis Date: Sun, 23 Jul 2017 16:52:01 -0300 Subject: [PATCH 23/30] Add tests for default NASHROOT --- internal/sh/shell.go | 13 ++++++------- internal/sh/shell_env_test.go | 21 +++++++++++++++++++-- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/internal/sh/shell.go b/internal/sh/shell.go index fc4e0f9d..deb58673 100644 --- a/internal/sh/shell.go +++ b/internal/sh/shell.go @@ -758,13 +758,13 @@ func (shell *Shell) getNashRoot() (string, error) { // Test HOME not a string // It is very annoying to load env vars, perhaps a shell.GetStringEnv ? - //h, _ := shell.Getenv("HOME") - //home := h.String() - nashroot, ok := shell.Getenv("NASHROOT") if !ok { - return "", errors.NewError("NASHROOT must be set") + h, _ := shell.Getenv("HOME") + home := h.String() + + return home + "/nashroot", nil } if nashroot.Type() != sh.StringType { @@ -781,12 +781,11 @@ func (shell *Shell) getNashPath() (string, error) { // Test HOME not a string // It is very annoying to load env vars, perhaps a shell.GetStringEnv ? - h, _ := shell.Getenv("HOME") - home := h.String() - nashPath, ok := shell.Getenv("NASHPATH") if !ok { + h, _ := shell.Getenv("HOME") + home := h.String() return home + "/nash", nil } diff --git a/internal/sh/shell_env_test.go b/internal/sh/shell_env_test.go index ef5bdc82..4c00f082 100644 --- a/internal/sh/shell_env_test.go +++ b/internal/sh/shell_env_test.go @@ -75,14 +75,31 @@ func TestLoadsStdlibFromNASHROOT(t *testing.T) { } func TestLoadsStdlibFromHOMEIfNASHROOTIsUnset(t *testing.T) { -} + home, teardown := setupEnvTests(t) + defer teardown() -func TestLoadsStdlibFromGOPATHOnIfStdlibNotOnHOME(t *testing.T) { + nashroot := home + "/nashroot" + nashstdlib := nashroot + "/stdlib" + mkdirAll(t, nashstdlib) + + writeFile(t, nashstdlib+"/lib.sh", ` + fn test() { + echo "defaultnashroot" + } + `) + + newTestShell(t).Exec(t, ` + import lib + test() + `, "defaultnashroot\n") } func TestLoadsStdlibFromGOPATHOnIfHOMEIsUnset(t *testing.T) { } +func TestLoadsStdlibFromGOPATHOnIfStdlibNotOnHOME(t *testing.T) { +} + func TestFailsToLoadStdlibIfGOPATHIsUnset(t *testing.T) { // TODO: Explode or just fails for not founding the lib ? } From ed3ecbed7890d868371bf3018d778debf781ba36 Mon Sep 17 00:00:00 2001 From: Tiago Katcipis Date: Sun, 23 Jul 2017 17:13:55 -0300 Subject: [PATCH 24/30] Search stdlib on GOPATH if NASHROOT/HOME is unset --- internal/sh/shell.go | 7 ++++++- internal/sh/shell_env_test.go | 24 ++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/internal/sh/shell.go b/internal/sh/shell.go index deb58673..f5f5794e 100644 --- a/internal/sh/shell.go +++ b/internal/sh/shell.go @@ -761,7 +761,12 @@ func (shell *Shell) getNashRoot() (string, error) { nashroot, ok := shell.Getenv("NASHROOT") if !ok { - h, _ := shell.Getenv("HOME") + h, hashome := shell.Getenv("HOME") + if !hashome { + g, _ := shell.Getenv("GOPATH") + gopath := g.String() + return gopath + "/src/github.com/NeowayLabs/nash", nil + } home := h.String() return home + "/nashroot", nil diff --git a/internal/sh/shell_env_test.go b/internal/sh/shell_env_test.go index 4c00f082..5e99f205 100644 --- a/internal/sh/shell_env_test.go +++ b/internal/sh/shell_env_test.go @@ -95,6 +95,28 @@ func TestLoadsStdlibFromHOMEIfNASHROOTIsUnset(t *testing.T) { } func TestLoadsStdlibFromGOPATHOnIfHOMEIsUnset(t *testing.T) { + home, teardown := setupEnvTests(t) + defer teardown() + + os.Unsetenv("HOME") + os.Setenv("GOPATH", home) + // Avoid failure of no NASHPATH/HOME + os.Setenv("NASHPATH", "/whatever") + + nashroot := home + "/src/github.com/NeowayLabs/nash" + nashstdlib := nashroot + "/stdlib" + mkdirAll(t, nashstdlib) + + writeFile(t, nashstdlib+"/lib.sh", ` + fn test() { + echo "gopathnashroot" + } + `) + + newTestShell(t).Exec(t, ` + import lib + test() + `, "gopathnashroot\n") } func TestLoadsStdlibFromGOPATHOnIfStdlibNotOnHOME(t *testing.T) { @@ -147,6 +169,7 @@ func setupEnvTests(t *testing.T) (string, func()) { } curhome := os.Getenv("HOME") + curgopath := os.Getenv("GOPATH") err = os.Setenv("HOME", home) if err != nil { @@ -156,6 +179,7 @@ func setupEnvTests(t *testing.T) (string, func()) { return home, func() { errs := []error{} errs = append(errs, os.Setenv("HOME", curhome)) + errs = append(errs, os.Setenv("GOPATH", curgopath)) errs = append(errs, os.Unsetenv("NASHPATH")) errs = append(errs, os.Unsetenv("NASHROOT")) errs = append(errs, os.RemoveAll(home)) From a676f0cbd7ad7117ec797271ea0fb85ebabd45d6 Mon Sep 17 00:00:00 2001 From: Tiago Katcipis Date: Sun, 23 Jul 2017 17:52:06 -0300 Subject: [PATCH 25/30] Add handling for invalid default HOME nashroot --- internal/sh/shell.go | 23 +++++++++++++++++++---- internal/sh/shell_env_test.go | 27 ++++++++++++++++++++++++--- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/internal/sh/shell.go b/internal/sh/shell.go index f5f5794e..2aeef812 100644 --- a/internal/sh/shell.go +++ b/internal/sh/shell.go @@ -752,6 +752,18 @@ func (shell *Shell) executeReturn(n *ast.ReturnNode) ([]sh.Obj, error) { return returns, newErrStopWalking() } +func (shell *Shell) getNashRootFromGOPATH() (string, error) { + // TODO: NO GOPATH SET + g, _ := shell.Getenv("GOPATH") + gopath := g.String() + return gopath + "/src/github.com/NeowayLabs/nash", nil +} + +func isValidNashRoot(nashroot string) bool { + _, err := os.Stat(nashroot + "/stdlib") + return err == nil +} + func (shell *Shell) getNashRoot() (string, error) { // TODO: // Test behavior without HOME @@ -763,13 +775,16 @@ func (shell *Shell) getNashRoot() (string, error) { if !ok { h, hashome := shell.Getenv("HOME") if !hashome { - g, _ := shell.Getenv("GOPATH") - gopath := g.String() - return gopath + "/src/github.com/NeowayLabs/nash", nil + return shell.getNashRootFromGOPATH() } home := h.String() + nashroot := home + "/nashroot" + + if !isValidNashRoot(nashroot) { + return shell.getNashRootFromGOPATH() + } - return home + "/nashroot", nil + return nashroot, nil } if nashroot.Type() != sh.StringType { diff --git a/internal/sh/shell_env_test.go b/internal/sh/shell_env_test.go index 5e99f205..432a3f91 100644 --- a/internal/sh/shell_env_test.go +++ b/internal/sh/shell_env_test.go @@ -103,8 +103,7 @@ func TestLoadsStdlibFromGOPATHOnIfHOMEIsUnset(t *testing.T) { // Avoid failure of no NASHPATH/HOME os.Setenv("NASHPATH", "/whatever") - nashroot := home + "/src/github.com/NeowayLabs/nash" - nashstdlib := nashroot + "/stdlib" + nashstdlib := nashStdlibGoPath(home) mkdirAll(t, nashstdlib) writeFile(t, nashstdlib+"/lib.sh", ` @@ -119,7 +118,25 @@ func TestLoadsStdlibFromGOPATHOnIfHOMEIsUnset(t *testing.T) { `, "gopathnashroot\n") } -func TestLoadsStdlibFromGOPATHOnIfStdlibNotOnHOME(t *testing.T) { +func TestLoadsStdlibFromGOPATHIfStdlibNotOnHOME(t *testing.T) { + home, teardown := setupEnvTests(t) + defer teardown() + + os.Setenv("GOPATH", home) + + nashstdlib := nashStdlibGoPath(home) + mkdirAll(t, nashstdlib) + + writeFile(t, nashstdlib+"/lib.sh", ` + fn test() { + echo "nostdlibonhome" + } + `) + + newTestShell(t).Exec(t, ` + import lib + test() + `, "nostdlibonhome\n") } func TestFailsToLoadStdlibIfGOPATHIsUnset(t *testing.T) { @@ -205,3 +222,7 @@ func writeFile(t *testing.T, filename string, data string) { t.Fatal(err) } } + +func nashStdlibGoPath(gopath string) string { + return gopath + "/src/github.com/NeowayLabs/nash/stdlib" +} From 18633923421a5bfffc44722ab5ae0419258ff2a1 Mon Sep 17 00:00:00 2001 From: Tiago Katcipis Date: Sun, 30 Jul 2017 11:48:10 -0300 Subject: [PATCH 26/30] Add tests validating when no env vars are set --- internal/sh/shell.go | 10 ++----- internal/sh/shell_env_test.go | 49 +++++++++++++++++++++++++++++++++-- 2 files changed, 49 insertions(+), 10 deletions(-) diff --git a/internal/sh/shell.go b/internal/sh/shell.go index 2aeef812..def93850 100644 --- a/internal/sh/shell.go +++ b/internal/sh/shell.go @@ -765,10 +765,7 @@ func isValidNashRoot(nashroot string) bool { } func (shell *Shell) getNashRoot() (string, error) { - // TODO: - // Test behavior without HOME - // Test HOME not a string - // It is very annoying to load env vars, perhaps a shell.GetStringEnv ? + // TODO(katcipis): It is very annoying to load env vars, perhaps a shell.GetStringEnv ? nashroot, ok := shell.Getenv("NASHROOT") @@ -796,10 +793,7 @@ func (shell *Shell) getNashRoot() (string, error) { } func (shell *Shell) getNashPath() (string, error) { - // TODO: - // Test behavior without HOME - // Test HOME not a string - // It is very annoying to load env vars, perhaps a shell.GetStringEnv ? + // TODO(katcipis): It is very annoying to load env vars, perhaps a shell.GetStringEnv ? nashPath, ok := shell.Getenv("NASHPATH") diff --git a/internal/sh/shell_env_test.go b/internal/sh/shell_env_test.go index 432a3f91..25c66d58 100644 --- a/internal/sh/shell_env_test.go +++ b/internal/sh/shell_env_test.go @@ -48,8 +48,30 @@ func TestLoadsLibFromHOMEIfNASHPATHIsUnset(t *testing.T) { `, "defaultnashpath\n") } -func TestFailsToLoadLibIfHomeIsUnset(t *testing.T) { - // TODO: Explode or just fails for not founding the lib ? +func TestLoadsLibIfNoEnvVarIsSet(t *testing.T) { + home, teardown := setupEnvTests(t) + defer teardown() + + unsetAllEnvVars(t) + + writeFile(t, home+"/lib.sh", ` + fn test() { + echo "noenv" + } + `) + + oldcwd, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + + chdir(t, home) + defer chdir(t, oldcwd) + + newTestShell(t).Exec(t, ` + import lib + test() + `, "noenv\n") } func TestLoadsStdlibFromNASHROOT(t *testing.T) { @@ -193,6 +215,8 @@ func setupEnvTests(t *testing.T) (string, func()) { t.Fatal(err) } + mkdirAll(t, home) + return home, func() { errs := []error{} errs = append(errs, os.Setenv("HOME", curhome)) @@ -209,6 +233,20 @@ func setupEnvTests(t *testing.T) (string, func()) { } } +func unsetEnv(t *testing.T, name string) { + err := os.Unsetenv(name) + if err != nil { + t.Fatalf("error[%s] unsetting [%s]", err, name) + } +} + +func unsetAllEnvVars(t *testing.T) { + unsetEnv(t, "HOME") + unsetEnv(t, "GOPATH") + unsetEnv(t, "NASHPATH") + unsetEnv(t, "NASHROOT") +} + func mkdirAll(t *testing.T, nashlib string) { err := os.MkdirAll(nashlib, os.ModePerm) if err != nil { @@ -223,6 +261,13 @@ func writeFile(t *testing.T, filename string, data string) { } } +func chdir(t *testing.T, dir string) { + err := os.Chdir(dir) + if err != nil { + t.Fatalf("error[%s] changing dir to[%s]", err, dir) + } +} + func nashStdlibGoPath(gopath string) string { return gopath + "/src/github.com/NeowayLabs/nash/stdlib" } From f24c71d618b87ce140934060127b2259b2cac77f Mon Sep 17 00:00:00 2001 From: Tiago Katcipis Date: Sun, 30 Jul 2017 12:34:38 -0300 Subject: [PATCH 27/30] Dont fail if no env vars is set --- internal/sh/shell.go | 59 +++++++++++++++++++---------------- internal/sh/shell_env_test.go | 4 --- 2 files changed, 32 insertions(+), 31 deletions(-) diff --git a/internal/sh/shell.go b/internal/sh/shell.go index def93850..4592895d 100644 --- a/internal/sh/shell.go +++ b/internal/sh/shell.go @@ -752,9 +752,11 @@ func (shell *Shell) executeReturn(n *ast.ReturnNode) ([]sh.Obj, error) { return returns, newErrStopWalking() } -func (shell *Shell) getNashRootFromGOPATH() (string, error) { - // TODO: NO GOPATH SET - g, _ := shell.Getenv("GOPATH") +func (shell *Shell) getNashRootFromGOPATH(preverr error) (string, error) { + g, hasgopath := shell.Getenv("GOPATH") + if !hasgopath { + return "", errors.NewError("%s\nno GOPATH env var setted", preverr) + } gopath := g.String() return gopath + "/src/github.com/NeowayLabs/nash", nil } @@ -772,24 +774,19 @@ func (shell *Shell) getNashRoot() (string, error) { if !ok { h, hashome := shell.Getenv("HOME") if !hashome { - return shell.getNashRootFromGOPATH() + return shell.getNashRootFromGOPATH(errors.NewError("no HOME env var setted")) } home := h.String() nashroot := home + "/nashroot" if !isValidNashRoot(nashroot) { - return shell.getNashRootFromGOPATH() + return shell.getNashRootFromGOPATH(errors.NewError("$HOME/nashroot is not valid NASHROOT\n%s")) } return nashroot, nil } - if nashroot.Type() != sh.StringType { - return "", errors.NewError("NASHROOT must be a string") - } - return nashroot.String(), nil - } func (shell *Shell) getNashPath() (string, error) { @@ -798,7 +795,10 @@ func (shell *Shell) getNashPath() (string, error) { nashPath, ok := shell.Getenv("NASHPATH") if !ok { - h, _ := shell.Getenv("HOME") + h, hashome := shell.Getenv("HOME") + if !hashome { + return "", errors.NewError("No NASHPATH and no HOME env vars set") + } home := h.String() return home + "/nash", nil } @@ -857,23 +857,17 @@ func (shell *Shell) executeImport(node *ast.ImportNode) error { } } - dotDir, err := shell.getNashPath() - if err != nil { - return err - } - - tries = append(tries, dotDir+"/lib/"+fname) - - if !hasExt { - tries = append(tries, dotDir+"/lib/"+fname+".sh") + dotDir, nashpatherr := shell.getNashPath() + if nashpatherr == nil { + tries = append(tries, dotDir+"/lib/"+fname) + if !hasExt { + tries = append(tries, dotDir+"/lib/"+fname+".sh") + } } - nashroot, err := shell.getNashRoot() - if err == nil { + nashroot, nashrooterr := shell.getNashRoot() + if nashrooterr == nil { tries = append(tries, nashroot+"/stdlib/"+fname+".sh") - } else { - // TODO: Fail if there is no nashroot present ? - shell.logf("unable to define a NASHROOT, there will be no stdlib available: error[%s]\n", err) } shell.logf("Trying %q\n", tries) @@ -890,10 +884,21 @@ func (shell *Shell) executeImport(node *ast.ImportNode) error { } } - return errors.NewEvalError(shell.filename, node, + errmsg := fmt.Sprintf( "Failed to import path '%s'. The locations below have been tried:\n \"%s\"", fname, - strings.Join(tries, `", "`)) + strings.Join(tries, `", "`), + ) + + if nashpatherr != nil { + errmsg += "\nnashpath error: " + nashpatherr.Error() + } + + if nashrooterr != nil { + errmsg += "\nnashroot error: " + nashrooterr.Error() + } + + return errors.NewEvalError(shell.filename, node, errmsg) } // executePipe executes a pipe of ast.Command's. Each command can be diff --git a/internal/sh/shell_env_test.go b/internal/sh/shell_env_test.go index 25c66d58..3444b58c 100644 --- a/internal/sh/shell_env_test.go +++ b/internal/sh/shell_env_test.go @@ -161,10 +161,6 @@ func TestLoadsStdlibFromGOPATHIfStdlibNotOnHOME(t *testing.T) { `, "nostdlibonhome\n") } -func TestFailsToLoadStdlibIfGOPATHIsUnset(t *testing.T) { - // TODO: Explode or just fails for not founding the lib ? -} - type testshell struct { shell *Shell stdout *bytes.Buffer From b283b641a17391df4d4ee194bb25efeb59ba13db Mon Sep 17 00:00:00 2001 From: Tiago Katcipis Date: Mon, 31 Jul 2017 00:37:06 -0300 Subject: [PATCH 28/30] Update env vars docs --- README.md | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 879b33b8..a3c266df 100644 --- a/README.md +++ b/README.md @@ -57,15 +57,25 @@ Nash is a system shell, inspired by plan9 `rc`, that makes it easy to create rel ## Installation Before proceeding to any of the install procedures it is important that you -set in your environment the **NASHPATH** variable, it will be used to find -your libraries and the standard library shipped with the language. +set in your environment the **NASHPATH** and **NASHROOT** variables. -Also add the directory **$NASHPATH/bin** to your **PATH** so you can run -nash in a more practical way (although not necessary). +The **NASHROOT** variable is used to find the stdlib, while **NASHPATH** +is used to find libraries in general. It is important to have two different +paths since this will allow you to delete all libraries +(cleaning up your installation) by removing your $NASHPATH directory +without affecting your base nash installation and standard library. + +If no **NASHPATH** set a default of $HOME/nash will be assumed. +If no **NASHROOT** set a default of $HOME/nashroot will be assumed. + +The libraries lookup dir will be $NASHPATH/lib. +The standard library lookup dir will be $NASHROOT/stdlib. + +After installing the nash binary will be located at $NASHROOT/bin. ### Release -Installing is so stupid that we provide small scripts to install it. +Installing is so stupid that we provide small scripts to do it. If your platform is not supported take a look at the existent ones and send a MR with the script for your platform. From 025680b23f2c51dd39826f3117b89268682b71f1 Mon Sep 17 00:00:00 2001 From: Tiago Katcipis Date: Mon, 7 Aug 2017 14:40:24 -0300 Subject: [PATCH 29/30] Fix make install --- Makefile | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index ca9e6826..f1e598c5 100644 --- a/Makefile +++ b/Makefile @@ -16,17 +16,19 @@ guard-%: exit 1; \ fi -install: build guard-NASHPATH +NASHPATH=$(HOME)/nash +NASHROOT=$(HOME)/nashroot + +install: build @echo - @echo "Installing nash at: "$(NASHPATH) - mkdir -p $(NASHPATH)/bin - mkdir -p $(NASHPATH)/lib - rm -f $(NASHPATH)/bin/nash - rm -f $(NASHPATH)/bin/nashfmt - cp -p ./cmd/nash/nash $(NASHPATH)/bin - cp -p ./cmd/nashfmt/nashfmt $(NASHPATH)/bin - rm -rf $(NASHPATH)/stdlib - cp -pr ./stdlib $(NASHPATH)/stdlib + @echo "Installing nash at: "$(NASHROOT) + mkdir -p $(NASHROOT)/bin + rm -f $(NASHROOT)/bin/nash + rm -f $(NASHROOT)/bin/nashfmt + cp -p ./cmd/nash/nash $(NASHROOT)/bin + cp -p ./cmd/nashfmt/nashfmt $(NASHROOT)/bin + rm -rf $(NASHROOT)/stdlib + cp -pr ./stdlib $(NASHROOT)/stdlib deps: go get -v -t golang.org/x/exp/ebnf From 7db531b3b60a59722b7b516f58b0d13e44beef3a Mon Sep 17 00:00:00 2001 From: Tiago Katcipis Date: Mon, 7 Aug 2017 14:41:54 -0300 Subject: [PATCH 30/30] Remove unused guard clause --- Makefile | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Makefile b/Makefile index f1e598c5..07218c5a 100644 --- a/Makefile +++ b/Makefile @@ -10,12 +10,6 @@ build: go build $(buildargs) -o ./cmd/nash/nash ./cmd/nash go build $(buildargs) -o ./cmd/nashfmt/nashfmt ./cmd/nashfmt -guard-%: - @ if [ "${${*}}" = "" ]; then \ - echo "'$*' must be set in order to install and use nash"; \ - exit 1; \ - fi - NASHPATH=$(HOME)/nash NASHROOT=$(HOME)/nashroot