History

[tempfile] handle interrupts and assure there is an end to it

Sebastian Thiel committed 5 years ago

Commit dc0afbd1 parent b01faa91 file · +37 −9Browse files

Unified · Split

git-tempfile/src/create_dir.rs+37−9
@@ -1,6 +1,20 @@
1#![allow(missing_docs)]1#![allow(missing_docs)]
2use std::path::Path;2use std::path::Path;
3 3
4#[derive(Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq)]
5pub struct Options {
6 /// How often to retry if an interrupt happens.
7 retries_on_interrupt: usize,
8}
9
10impl Default for Options {
11 fn default() -> Self {
12 Options {
13 retries_on_interrupt: 10,
14 }
15 }
16}
17
4mod error {18mod error {
5 use quick_error::quick_error;19 use quick_error::quick_error;
6 use std::path::PathBuf;20 use std::path::PathBuf;
@@ -37,20 +51,28 @@ pub use error::Error; · 30 unmodified lines
37/// * `Some(Err(Error::Permanent))` is yielded exactly once on failure.51/// * `Some(Err(Error::Permanent))` is yielded exactly once on failure.
38pub struct Iter<'a> {52pub struct Iter<'a> {
39 cursors: Vec<&'a Path>,53 cursors: Vec<&'a Path>,
54 options: Options,
40}55}
41 56
42impl<'a> Iter<'a> {57impl<'a> Iter<'a> {
43 pub fn new(target: &'a Path) -> Self {58 pub fn new(target: &'a Path) -> Self {
44 Iter { cursors: vec![target] }59 Iter {
60 cursors: vec![target],
61 options: Default::default(),
62 }
45 }63 }
46 64
47 fn fail_permanently(&mut self, dir: &Path, err: impl Into<std::io::Error>) -> Option<Result<&'a Path, Error>> {65 fn pernanent_failure(&mut self, dir: &Path, err: impl Into<std::io::Error>) -> Option<Result<&'a Path, Error>> {
48 self.cursors.clear();66 self.cursors.clear();
49 Some(Err(Error::Permanent {67 Some(Err(Error::Permanent {
50 err: err.into(),68 err: err.into(),
51 dir: dir.to_owned(),69 dir: dir.to_owned(),
52 }))70 }))
53 }71 }
72
73 fn intermediate_failure(&self, err: std::io::Error) -> Option<Result<&'a Path, Error>> {
74 Some(Err(Error::Intermediate(err.kind())))
75 }
54}76}
55 77
56impl<'a> Iterator for Iter<'a> {78impl<'a> Iterator for Iter<'a> {
@@ -59,17 +81,23 @@ impl<'a> Iterator for Iter<'a> { · 2 unmodified lines
59 fn next(&mut self) -> Option<Self::Item> {81 fn next(&mut self) -> Option<Self::Item> {
60 use std::io::ErrorKind::*;82 use std::io::ErrorKind::*;
61 match self.cursors.pop() {83 match self.cursors.pop() {
62 Some(cursor) => match std::fs::create_dir(cursor) {84 Some(dir) => match std::fs::create_dir(dir) {
63 Ok(()) => Some(Ok(cursor)),85 Ok(()) => Some(Ok(dir)),
64 Err(err) => match err.kind() {86 Err(err) => match err.kind() {
65 AlreadyExists => Some(Ok(cursor)),87 AlreadyExists => Some(Ok(dir)),
66 NotFound => {88 NotFound => {
67 self.cursors.push(cursor);89 self.cursors.push(dir);
68 self.cursors.push(match cursor.parent() {90 self.cursors.push(match dir.parent() {
69 None => return self.fail_permanently(cursor, InvalidInput),91 None => return self.pernanent_failure(dir, InvalidInput),
70 Some(parent) => parent,92 Some(parent) => parent,
71 });93 });
72 Some(Err(Error::Intermediate(err.kind())))94 self.intermediate_failure(err)
95 }
96 Interrupted if self.options.retries_on_interrupt == 0 => self.pernanent_failure(dir, Interrupted),
97 Interrupted => {
98 self.options.retries_on_interrupt -= 1;
99 self.cursors.push(dir);
100 self.intermediate_failure(err)
73 }101 }
74 kind => todo!("{:?}", kind),102 kind => todo!("{:?}", kind),
75 },103 },