mirror of
https://github.com/go-sylixos/elvish.git
synced 2024-12-12 17:27:50 +08:00
Fix hang reading value channel from a redirection
Fixes #600 Fixes #1010
This commit is contained in:
parent
b11fe9d257
commit
b58b495d77
|
@ -497,21 +497,31 @@ type invalidFD struct{ fd int }
|
|||
|
||||
func (err invalidFD) Error() string { return fmt.Sprintf("invalid fd: %d", err.fd) }
|
||||
|
||||
func (op *redirOp) fileChan() chan interface{} {
|
||||
if op.mode == parse.Read {
|
||||
// ClosedChan is used when redirecting from a named file because we
|
||||
// don't support reading "values" (as opposed to bytes) from a file.
|
||||
return ClosedChan
|
||||
}
|
||||
// TODO: Replace BlackholeChan for output with a value sink that will
|
||||
// throw an exception if it sees any values since we don't support writing
|
||||
// values to a file without first converting them to bytes.
|
||||
return BlackholeChan
|
||||
}
|
||||
|
||||
func (op *redirOp) exec(fm *Frame) error {
|
||||
var dst int
|
||||
if op.dstOp == nil {
|
||||
// use default dst fd
|
||||
if op.dstOp == nil { // the common case: use default destination file-descriptor
|
||||
switch op.mode {
|
||||
case parse.Read:
|
||||
dst = 0
|
||||
dst = 0 // stdin
|
||||
case parse.Write, parse.ReadWrite, parse.Append:
|
||||
dst = 1
|
||||
dst = 1 // stdout
|
||||
default:
|
||||
return fm.errorpf(op, "bad RedirMode; parser bug")
|
||||
}
|
||||
} else {
|
||||
} else { // use the destination file-descriptor requested by the user
|
||||
var err error
|
||||
// dst must be a valid fd
|
||||
dst, err = evalForFd(fm, op.dstOp, false, "redirection destination")
|
||||
if err != nil {
|
||||
return fm.errorp(op, err)
|
||||
|
@ -547,15 +557,9 @@ func (op *redirOp) exec(fm *Frame) error {
|
|||
if err != nil {
|
||||
return fm.errorpf(op, "failed to open file %s: %s", vals.Repr(src, vals.NoPretty), err)
|
||||
}
|
||||
fm.ports[dst] = &Port{
|
||||
File: f, Chan: BlackholeChan,
|
||||
CloseFile: true,
|
||||
}
|
||||
fm.ports[dst] = &Port{File: f, CloseFile: true, Chan: op.fileChan()}
|
||||
case vals.File:
|
||||
fm.ports[dst] = &Port{
|
||||
File: src, Chan: BlackholeChan,
|
||||
CloseFile: false,
|
||||
}
|
||||
fm.ports[dst] = &Port{File: src, CloseFile: false, Chan: op.fileChan()}
|
||||
case vals.Pipe:
|
||||
var f *os.File
|
||||
switch op.mode {
|
||||
|
@ -566,10 +570,7 @@ func (op *redirOp) exec(fm *Frame) error {
|
|||
default:
|
||||
return fm.errorpf(op, "can only use < or > with pipes")
|
||||
}
|
||||
fm.ports[dst] = &Port{
|
||||
File: f, Chan: BlackholeChan,
|
||||
CloseFile: false,
|
||||
}
|
||||
fm.ports[dst] = &Port{File: f, CloseFile: false, Chan: op.fileChan()}
|
||||
default:
|
||||
return fm.errorp(op.srcOp, errs.BadValue{
|
||||
What: "redirection source",
|
||||
|
|
|
@ -167,6 +167,12 @@ func TestCompileEffect(t *testing.T) {
|
|||
That(`p = (pipe); echo haha > $p; pwclose $p; slurp < $p; prclose $p`).
|
||||
Puts("haha\n"),
|
||||
|
||||
// We can't read values from a file and shouldn't hang when iterating
|
||||
// over input from a file.
|
||||
// Regression test for https://github.com/elves/elvish/issues/1010
|
||||
That("echo abc > bytes", "each $echo~ < bytes").Prints("abc\n"),
|
||||
That("echo def > bytes", "only-values < bytes | count").Puts("0"),
|
||||
|
||||
// Invalid redirection destination.
|
||||
That("echo []> test").Throws(
|
||||
errs.BadValue{
|
||||
|
|
|
@ -1576,6 +1576,14 @@ Redirections may appear anywhere in the command, except at the beginning,
|
|||
although this may be restricted in future. It's usually good style to write
|
||||
redirections at the end of command forms.
|
||||
|
||||
**Important:** Elvish only supports reading and writing bytes from/to the target
|
||||
of a redirection. Elvish does not support reading values from or writing values
|
||||
to a file or [pipe](builtin.html#pipe) via redirection. Assume a file named
|
||||
_data_ contains a single line with a single word such as "hello". This will
|
||||
output zero even though there is one word in the file:
|
||||
`only-values < data | count`. Whereas `only-bytes < data | count` will report
|
||||
one.
|
||||
|
||||
# Special Commands
|
||||
|
||||
**Special commands** obey the same syntax rules as normal commands, but have
|
||||
|
|
Loading…
Reference in New Issue
Block a user