Skip to content

Commit 93b28d5

Browse files
authored
Merge pull request #147 from NeowayLabs/setenv
Setenv
2 parents db4c0b9 + e13fbdd commit 93b28d5

File tree

7 files changed

+163
-12
lines changed

7 files changed

+163
-12
lines changed

Diff for: ast/node.go

+18-2
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ type (
6868
token.FileInfo
6969

7070
varName string
71+
assign Node
7172
}
7273

7374
// AssignmentNode is a node for variable assignments
@@ -455,18 +456,27 @@ func (n *ImportNode) IsEqual(other Node) bool {
455456
}
456457

457458
// NewSetenvNode creates a new assignment node
458-
func NewSetenvNode(info token.FileInfo, name string) *SetenvNode {
459+
func NewSetenvNode(info token.FileInfo, name string, assign Node) (*SetenvNode, error) {
460+
if assign != nil && assign.Type() != NodeAssignment &&
461+
assign.Type() != NodeExecAssign {
462+
return nil, errors.New("Invalid assignment in setenv")
463+
}
464+
459465
return &SetenvNode{
460466
NodeType: NodeSetenv,
461467
FileInfo: info,
462468

463469
varName: name,
464-
}
470+
assign: assign,
471+
}, nil
465472
}
466473

467474
// Identifier returns the environment name.
468475
func (n *SetenvNode) Identifier() string { return n.varName }
469476

477+
// Assignment returns the setenv assignment (if any)
478+
func (n *SetenvNode) Assignment() Node { return n.assign }
479+
470480
// IsEqual returns if it is equal to the other node.
471481
func (n *SetenvNode) IsEqual(other Node) bool {
472482
if n == other {
@@ -484,6 +494,12 @@ func (n *SetenvNode) IsEqual(other Node) bool {
484494
return false
485495
}
486496

497+
if n.assign != o.assign {
498+
if !n.assign.IsEqual(o.assign) {
499+
return false
500+
}
501+
}
502+
487503
return n.varName == o.varName
488504
}
489505

Diff for: ast/node_fmt.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,11 @@ func (n *ImportNode) String() string {
151151

152152
// String returns the string representation of assignment
153153
func (n *SetenvNode) String() string {
154-
return "setenv " + n.varName
154+
if n.assign == nil {
155+
return "setenv " + n.varName
156+
}
157+
158+
return "setenv " + n.assign.String()
155159
}
156160

157161
func (n *AssignmentNode) string() (string, bool) {

Diff for: internal/sh/shell.go

+19
Original file line numberDiff line numberDiff line change
@@ -1474,8 +1474,27 @@ func (shell *Shell) executeSetenv(v *ast.SetenvNode) error {
14741474
var (
14751475
varValue sh.Obj
14761476
ok bool
1477+
assign = v.Assignment()
1478+
err error
14771479
)
14781480

1481+
if assign != nil {
1482+
switch assign.Type() {
1483+
case ast.NodeAssignment:
1484+
err = shell.executeAssignment(assign.(*ast.AssignmentNode))
1485+
case ast.NodeExecAssign:
1486+
err = shell.executeExecAssign(assign.(*ast.ExecAssignNode))
1487+
default:
1488+
err = errors.NewEvalError(shell.filename,
1489+
v, "Failed to eval setenv, invalid assignment type: %+v",
1490+
assign)
1491+
}
1492+
1493+
if err != nil {
1494+
return err
1495+
}
1496+
}
1497+
14791498
varName := v.Identifier()
14801499

14811500
if varValue, ok = shell.Getvar(varName); !ok {

Diff for: internal/sh/shell_test.go

+39-2
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,44 @@ func TestExecuteRedirectionMap(t *testing.T) {
419419
}
420420
}
421421

422+
func TestExecuteSetenv(t *testing.T) {
423+
for _, test := range []execTest{
424+
{
425+
"test setenv basic",
426+
`test = "hello"
427+
setenv test
428+
` + nashdPath + ` -c "echo $test"`,
429+
"hello\n", "", "",
430+
},
431+
{
432+
"test setenv assignment",
433+
`setenv test = "hello"
434+
` + nashdPath + ` -c "echo $test"`,
435+
"hello\n", "", "",
436+
},
437+
{
438+
"test setenv exec cmd",
439+
`setenv test <= echo -n "hello"
440+
` + nashdPath + ` -c "echo $test"`,
441+
"hello\n", "", "",
442+
},
443+
{
444+
"test setenv semicolon",
445+
`setenv a setenv b`,
446+
"", "",
447+
"test setenv semicolon:1:9: Unexpected token setenv, expected semicolon (;) or EOL",
448+
},
449+
} {
450+
testExec(t,
451+
test.desc,
452+
test.execStr,
453+
test.expectedStdout,
454+
test.expectedStderr,
455+
test.expectedErr,
456+
)
457+
}
458+
}
459+
422460
func TestExecuteCd(t *testing.T) {
423461
for _, test := range []execTest{
424462
{
@@ -1689,8 +1727,7 @@ func TestExecuteSubShellDoesNotOverwriteparentEnv(t *testing.T) {
16891727
return
16901728
}
16911729

1692-
err = shell.Exec("set env", `SHELL = "bleh"
1693-
setenv SHELL`)
1730+
err = shell.Exec("set env", `setenv SHELL = "bleh"`)
16941731

16951732
if err != nil {
16961733
t.Error(err)

Diff for: parser/parse.go

+31-4
Original file line numberDiff line numberDiff line change
@@ -454,19 +454,46 @@ func (p *Parser) parseImport(importToken scanner.Token) (ast.Node, error) {
454454
}
455455

456456
func (p *Parser) parseSetenv(it scanner.Token) (ast.Node, error) {
457-
fileInfo := it.FileInfo
457+
var (
458+
setenv *ast.SetenvNode
459+
assign ast.Node
460+
err error
461+
fileInfo = it.FileInfo
462+
)
458463

459464
it = p.next()
465+
next := p.peek()
460466

461467
if it.Type() != token.Ident {
462-
return nil, newParserError(it, p.name, "Unexpected token %v, expected VARIABLE", it)
468+
return nil, newParserError(it, p.name, "Unexpected token %v, expected identifier", it)
463469
}
464470

465-
if p.peek().Type() == token.Semicolon {
471+
if next.Type() == token.Assign || next.Type() == token.AssignCmd {
472+
assign, err = p.parseAssignment(it)
473+
474+
if err != nil {
475+
return nil, err
476+
}
477+
478+
setenv, err = ast.NewSetenvNode(fileInfo, it.Value(), assign)
479+
} else {
480+
setenv, err = ast.NewSetenvNode(fileInfo, it.Value(), nil)
481+
482+
if p.peek().Type() != token.Semicolon {
483+
return nil, newParserError(p.peek(),
484+
p.name,
485+
"Unexpected token %v, expected semicolon (;) or EOL",
486+
p.peek())
487+
}
488+
466489
p.ignore()
467490
}
468491

469-
return ast.NewSetenvNode(fileInfo, it.Value()), nil
492+
if err != nil {
493+
return nil, err
494+
}
495+
496+
return setenv, nil
470497
}
471498

472499
func (p *Parser) getArgument(allowArg, allowConcat bool) (ast.Expr, error) {

Diff for: parser/parse_test.go

+50-2
Original file line numberDiff line numberDiff line change
@@ -111,12 +111,55 @@ func TestParsePipe(t *testing.T) {
111111
func TestBasicSetAssignment(t *testing.T) {
112112
expected := ast.NewTree("simple set assignment")
113113
ln := ast.NewBlockNode(token.NewFileInfo(1, 0))
114-
set := ast.NewSetenvNode(token.NewFileInfo(1, 0), "test")
114+
set, err := ast.NewSetenvNode(token.NewFileInfo(1, 0), "test", nil)
115+
116+
if err != nil {
117+
t.Fatal(err)
118+
}
115119

116120
ln.Push(set)
117121
expected.Root = ln
118122

119123
parserTestTable("simple set assignment", `setenv test`, expected, t, true)
124+
125+
// setenv with assignment
126+
expected = ast.NewTree("setenv with simple assignment")
127+
ln = ast.NewBlockNode(token.NewFileInfo(1, 0))
128+
assign := ast.NewAssignmentNode(token.NewFileInfo(1, 7),
129+
"test",
130+
ast.NewStringExpr(token.NewFileInfo(1, 15), "hello", true))
131+
set, err = ast.NewSetenvNode(token.NewFileInfo(1, 0), "test", assign)
132+
133+
if err != nil {
134+
t.Fatal(err)
135+
}
136+
137+
ln.Push(set)
138+
expected.Root = ln
139+
140+
parserTestTable("setenv with simple assignment", `setenv test = "hello"`, expected, t, true)
141+
142+
expected = ast.NewTree("setenv with simple cmd assignment")
143+
ln = ast.NewBlockNode(token.NewFileInfo(1, 0))
144+
145+
cmd := ast.NewCommandNode(token.NewFileInfo(1, 15), "ls", false)
146+
147+
cmdAssign, err := ast.NewExecAssignNode(token.NewFileInfo(1, 7), "test", cmd)
148+
149+
if err != nil {
150+
t.Fatal(err)
151+
}
152+
153+
set, err = ast.NewSetenvNode(token.NewFileInfo(1, 0), "test", cmdAssign)
154+
155+
if err != nil {
156+
t.Fatal(err)
157+
}
158+
159+
ln.Push(set)
160+
expected.Root = ln
161+
162+
parserTestTable("simple assignment", `setenv test <= ls`, expected, t, true)
120163
}
121164

122165
func TestBasicAssignment(t *testing.T) {
@@ -436,7 +479,12 @@ func TestParseCd(t *testing.T) {
436479

437480
assign := ast.NewAssignmentNode(token.NewFileInfo(1, 0), "HOME", ast.NewStringExpr(token.NewFileInfo(1, 8), "/", true))
438481

439-
set := ast.NewSetenvNode(token.NewFileInfo(3, 0), "HOME")
482+
set, err := ast.NewSetenvNode(token.NewFileInfo(3, 0), "HOME", nil)
483+
484+
if err != nil {
485+
t.Fatal(err)
486+
}
487+
440488
cd = ast.NewCommandNode(token.NewFileInfo(5, 0), "cd", false)
441489
pwd := ast.NewCommandNode(token.NewFileInfo(6, 0), "pwd", false)
442490

Diff for: spec.ebnf

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ bindfn = "bindfn" identifier identifier .
6666
dump = "dump" [ filename ] .
6767

6868
/* Set environment variable */
69-
setenvDecl = "setenv" identifier .
69+
setenvDecl = "setenv" ( identifier | varDecl ) .
7070

7171
/* Comment */
7272
comment = "#" { unicode_char } .

0 commit comments

Comments
 (0)