Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
ion
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Deploy
Releases
Package Registry
Container Registry
Model registry
Operate
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Enzo Cioppettini
ion
Commits
a66d3c64
Commit
a66d3c64
authored
5 years ago
by
AdminXVII
Browse files
Options
Downloads
Patches
Plain Diff
Bubble errors when failure to redirection rather than printing to stdout
parent
c1a0b445
No related branches found
Branches containing commit
No related tags found
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
src/lib/parser/pipelines/mod.rs
+1
-52
1 addition, 52 deletions
src/lib/parser/pipelines/mod.rs
src/lib/shell/pipe_exec/mod.rs
+129
-17
129 additions, 17 deletions
src/lib/shell/pipe_exec/mod.rs
with
130 additions
and
69 deletions
src/lib/parser/pipelines/mod.rs
+
1
−
52
View file @
a66d3c64
...
@@ -9,12 +9,7 @@ use crate::{
...
@@ -9,12 +9,7 @@ use crate::{
};
};
use
itertools
::
Itertools
;
use
itertools
::
Itertools
;
use
small
;
use
small
;
use
std
::{
use
std
::
fmt
;
fmt
,
fs
::
File
,
io
::{
self
,
Write
},
os
::
unix
::
io
::{
FromRawFd
,
RawFd
},
};
#[derive(Debug,
PartialEq,
Clone,
Copy)]
#[derive(Debug,
PartialEq,
Clone,
Copy)]
pub
enum
RedirectFrom
{
pub
enum
RedirectFrom
{
...
@@ -42,52 +37,6 @@ pub enum Input {
...
@@ -42,52 +37,6 @@ pub enum Input {
HereString
(
small
::
String
),
HereString
(
small
::
String
),
}
}
/// Create an OS pipe and write the contents of a byte slice to one end
/// such that reading from this pipe will produce the byte slice. Return
/// A file descriptor representing the read end of the pipe.
pub
unsafe
fn
stdin_of
<
T
:
AsRef
<
[
u8
]
>>
(
input
:
T
)
->
Result
<
RawFd
,
io
::
Error
>
{
let
(
reader
,
writer
)
=
sys
::
pipe2
(
sys
::
O_CLOEXEC
)
?
;
let
mut
infile
=
File
::
from_raw_fd
(
writer
);
// Write the contents; make sure to use write_all so that we block until
// the entire string is written
infile
.write_all
(
input
.as_ref
())
?
;
infile
.flush
()
?
;
// `infile` currently owns the writer end RawFd. If we just return the reader
// end and let `infile` go out of scope, it will be closed, sending EOF to
// the reader!
Ok
(
reader
)
}
impl
Input
{
pub
fn
get_infile
(
&
mut
self
)
->
Result
<
File
,
()
>
{
match
self
{
Input
::
File
(
ref
filename
)
=>
match
File
::
open
(
filename
.as_str
())
{
Ok
(
file
)
=>
Ok
(
file
),
Err
(
e
)
=>
{
eprintln!
(
"ion: failed to redirect '{}' to stdin: {}"
,
filename
,
e
);
Err
(())
}
},
Input
::
HereString
(
ref
mut
string
)
=>
{
if
!
string
.ends_with
(
'\n'
)
{
string
.push
(
'\n'
);
}
match
unsafe
{
stdin_of
(
&
string
)
}
{
Ok
(
stdio
)
=>
Ok
(
unsafe
{
File
::
from_raw_fd
(
stdio
)
}),
Err
(
e
)
=>
{
eprintln!
(
"ion: failed to redirect herestring '{}' to stdin: {}"
,
string
,
e
);
Err
(())
}
}
}
}
}
}
impl
<
'a
>
fmt
::
Display
for
Input
{
impl
<
'a
>
fmt
::
Display
for
Input
{
fn
fmt
(
&
self
,
f
:
&
mut
fmt
::
Formatter
)
->
fmt
::
Result
{
fn
fmt
(
&
self
,
f
:
&
mut
fmt
::
Formatter
)
->
fmt
::
Result
{
match
self
{
match
self
{
...
...
This diff is collapsed.
Click to expand it.
src/lib/shell/pipe_exec/mod.rs
+
129
−
17
View file @
a66d3c64
...
@@ -30,6 +30,7 @@ use crate::{
...
@@ -30,6 +30,7 @@ use crate::{
};
};
use
smallvec
::
SmallVec
;
use
smallvec
::
SmallVec
;
use
std
::{
use
std
::{
fmt
,
fs
::{
File
,
OpenOptions
},
fs
::{
File
,
OpenOptions
},
io
::{
self
,
Write
},
io
::{
self
,
Write
},
iter
,
iter
,
...
@@ -38,6 +39,111 @@ use std::{
...
@@ -38,6 +39,111 @@ use std::{
process
::{
self
,
exit
},
process
::{
self
,
exit
},
};
};
#[derive(Debug,
Error)]
pub
enum
InputError
{
#[error(display
=
"ion: failed to redirect '{}' to stdin: {}"
,
file,
why)]
File
{
file
:
String
,
why
:
io
::
Error
},
#[error(display
=
"ion: failed to redirect herestring '{}' to stdin: {}"
,
string,
why)]
HereString
{
string
:
String
,
why
:
io
::
Error
},
}
#[derive(Debug)]
pub
struct
OutputError
{
redirect
:
RedirectFrom
,
file
:
String
,
why
:
io
::
Error
,
}
#[derive(Debug)]
pub
enum
RedirectError
{
Input
(
InputError
),
Output
(
OutputError
),
}
impl
fmt
::
Display
for
OutputError
{
fn
fmt
(
&
self
,
f
:
&
mut
fmt
::
Formatter
)
->
fmt
::
Result
{
write!
(
f
,
"ion: failed to redirect {} to file '{}': {}"
,
match
self
.redirect
{
RedirectFrom
::
Both
=>
"both stdout and stderr"
,
RedirectFrom
::
Stdout
=>
"stdout"
,
RedirectFrom
::
Stderr
=>
"stderr"
,
_
=>
unreachable!
(),
},
self
.file
,
self
.why
,
)
}
}
impl
std
::
error
::
Error
for
OutputError
{
fn
source
(
&
self
)
->
Option
<&
(
dyn
std
::
error
::
Error
+
'static
)
>
{
Some
(
&
self
.why
)
}
}
impl
fmt
::
Display
for
RedirectError
{
fn
fmt
(
&
self
,
f
:
&
mut
fmt
::
Formatter
)
->
fmt
::
Result
{
match
self
{
RedirectError
::
Output
(
why
)
=>
write!
(
f
,
"ion: failed to redirect {}"
,
why
),
RedirectError
::
Input
(
why
)
=>
write!
(
f
,
"ion: failed to redirect {}"
,
why
),
}
}
}
impl
std
::
error
::
Error
for
RedirectError
{
fn
source
(
&
self
)
->
Option
<&
(
dyn
std
::
error
::
Error
+
'static
)
>
{
Some
(
match
self
{
RedirectError
::
Output
(
why
)
=>
why
,
RedirectError
::
Input
(
why
)
=>
why
,
})
}
}
impl
From
<
OutputError
>
for
RedirectError
{
fn
from
(
error
:
OutputError
)
->
Self
{
RedirectError
::
Output
(
error
)
}
}
impl
From
<
InputError
>
for
RedirectError
{
fn
from
(
error
:
InputError
)
->
Self
{
RedirectError
::
Input
(
error
)
}
}
/// Create an OS pipe and write the contents of a byte slice to one end
/// such that reading from this pipe will produce the byte slice. Return
/// A file descriptor representing the read end of the pipe.
pub
unsafe
fn
stdin_of
<
T
:
AsRef
<
[
u8
]
>>
(
input
:
T
)
->
Result
<
RawFd
,
io
::
Error
>
{
let
(
reader
,
writer
)
=
sys
::
pipe2
(
sys
::
O_CLOEXEC
)
?
;
let
mut
infile
=
File
::
from_raw_fd
(
writer
);
// Write the contents; make sure to use write_all so that we block until
// the entire string is written
infile
.write_all
(
input
.as_ref
())
?
;
infile
.flush
()
?
;
// `infile` currently owns the writer end RawFd. If we just return the reader
// end and let `infile` go out of scope, it will be closed, sending EOF to
// the reader!
Ok
(
reader
)
}
impl
Input
{
pub
fn
get_infile
(
&
mut
self
)
->
Result
<
File
,
InputError
>
{
match
self
{
Input
::
File
(
ref
filename
)
=>
match
File
::
open
(
filename
.as_str
())
{
Ok
(
file
)
=>
Ok
(
file
),
Err
(
why
)
=>
Err
(
InputError
::
File
{
file
:
filename
.to_string
(),
why
}),
},
Input
::
HereString
(
ref
mut
string
)
=>
{
if
!
string
.ends_with
(
'\n'
)
{
string
.push
(
'\n'
);
}
match
unsafe
{
stdin_of
(
&
string
)
}
{
Ok
(
stdio
)
=>
Ok
(
unsafe
{
File
::
from_raw_fd
(
stdio
)
}),
Err
(
why
)
=>
Err
(
InputError
::
HereString
{
string
:
string
.to_string
(),
why
}),
}
}
}
}
}
/// Determines if the supplied command implicitly defines to change the directory.
/// Determines if the supplied command implicitly defines to change the directory.
///
///
/// This is detected by first checking if the argument starts with a '.' or an '/', or ends
/// This is detected by first checking if the argument starts with a '.' or an '/', or ends
...
@@ -79,7 +185,7 @@ fn do_tee<'a>(
...
@@ -79,7 +185,7 @@ fn do_tee<'a>(
job
:
&
mut
RefinedJob
<
'a
>
,
job
:
&
mut
RefinedJob
<
'a
>
,
stdout
:
&
mut
dyn
FnMut
(
&
mut
RefinedJob
<
'a
>
,
File
),
stdout
:
&
mut
dyn
FnMut
(
&
mut
RefinedJob
<
'a
>
,
File
),
stderr
:
&
mut
dyn
FnMut
(
&
mut
RefinedJob
<
'a
>
,
File
),
stderr
:
&
mut
dyn
FnMut
(
&
mut
RefinedJob
<
'a
>
,
File
),
)
->
Result
<
(),
()
>
{
)
->
Result
<
(),
OutputError
>
{
// XXX: Possibly add an assertion here for correctness
// XXX: Possibly add an assertion here for correctness
for
output
in
outputs
{
for
output
in
outputs
{
match
OpenOptions
::
new
()
match
OpenOptions
::
new
()
...
@@ -88,27 +194,30 @@ fn do_tee<'a>(
...
@@ -88,27 +194,30 @@ fn do_tee<'a>(
.append
(
output
.append
)
.append
(
output
.append
)
.open
(
output
.file
.as_str
())
.open
(
output
.file
.as_str
())
{
{
Ok
(
f
)
=>
match
output
.from
{
Ok
(
f
ile
)
=>
match
output
.from
{
RedirectFrom
::
None
=>
(),
RedirectFrom
::
None
=>
(),
RedirectFrom
::
Stdout
=>
stdout
(
job
,
f
),
RedirectFrom
::
Stdout
=>
stdout
(
job
,
f
ile
),
RedirectFrom
::
Stderr
=>
stderr
(
job
,
f
),
RedirectFrom
::
Stderr
=>
stderr
(
job
,
f
ile
),
RedirectFrom
::
Both
=>
match
f
.try_clone
()
{
RedirectFrom
::
Both
=>
match
f
ile
.try_clone
()
{
Ok
(
f_copy
)
=>
{
Ok
(
f_copy
)
=>
{
stdout
(
job
,
f
);
stdout
(
job
,
f
ile
);
stderr
(
job
,
f_copy
);
stderr
(
job
,
f_copy
);
}
}
Err
(
e
)
=>
{
Err
(
why
)
=>
{
eprintln!
(
return
Err
(
OutputError
{
"ion: failed to redirect both stdout and stderr to file '{:?}': {}"
,
redirect
:
output
.from
,
f
,
e
f
ile
:
output
.file
.to_string
(),
);
why
,
return
Err
(()
);
}
);
}
}
},
},
},
},
Err
(
e
)
=>
{
Err
(
why
)
=>
{
eprintln!
(
"ion: failed to redirect output into {}: {}"
,
output
.file
,
e
);
return
Err
(
OutputError
{
return
Err
(());
redirect
:
output
.from
,
file
:
output
.file
.to_string
(),
why
,
});
}
}
}
}
}
}
...
@@ -120,7 +229,7 @@ fn do_tee<'a>(
...
@@ -120,7 +229,7 @@ fn do_tee<'a>(
fn
prepare
<
'a
,
'b
>
(
fn
prepare
<
'a
,
'b
>
(
shell
:
&
'a
Shell
<
'b
>
,
shell
:
&
'a
Shell
<
'b
>
,
pipeline
:
Pipeline
<
'b
>
,
pipeline
:
Pipeline
<
'b
>
,
)
->
Result
<
impl
IntoIterator
<
Item
=
(
RefinedJob
<
'b
>
,
RedirectFrom
)
>
,
()
>
{
)
->
Result
<
impl
IntoIterator
<
Item
=
(
RefinedJob
<
'b
>
,
RedirectFrom
)
>
,
RedirectError
>
{
// Real logic begins here
// Real logic begins here
let
mut
new_commands
=
SmallVec
::
<
[
_
;
16
]
>
::
with_capacity
(
2
*
pipeline
.items
.len
());
let
mut
new_commands
=
SmallVec
::
<
[
_
;
16
]
>
::
with_capacity
(
2
*
pipeline
.items
.len
());
let
mut
prev_kind
=
RedirectFrom
::
None
;
let
mut
prev_kind
=
RedirectFrom
::
None
;
...
@@ -349,7 +458,10 @@ impl<'b> Shell<'b> {
...
@@ -349,7 +458,10 @@ impl<'b> Shell<'b> {
fn
pipe
(
&
mut
self
,
pipeline
:
Pipeline
<
'b
>
)
->
Status
{
fn
pipe
(
&
mut
self
,
pipeline
:
Pipeline
<
'b
>
)
->
Status
{
let
mut
commands
=
match
prepare
(
self
,
pipeline
)
{
let
mut
commands
=
match
prepare
(
self
,
pipeline
)
{
Ok
(
c
)
=>
c
.into_iter
()
.peekable
(),
Ok
(
c
)
=>
c
.into_iter
()
.peekable
(),
Err
(
_
)
=>
return
Status
::
COULD_NOT_EXEC
,
Err
(
why
)
=>
{
eprintln!
(
"{}"
,
why
);
return
Status
::
COULD_NOT_EXEC
;
}
};
};
if
let
Some
((
mut
parent
,
mut
kind
))
=
commands
.next
()
{
if
let
Some
((
mut
parent
,
mut
kind
))
=
commands
.next
()
{
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment