Brian Silverman | cc09f18 | 2022-03-09 15:40:20 -0800 | [diff] [blame] | 1 | // Copyright 2020 The Bazel Authors. All rights reserved. |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | |
| 15 | use std::fs::File; |
| 16 | use std::io::{BufRead, BufReader, Read}; |
| 17 | |
Brian Silverman | 5f6f276 | 2022-08-13 19:30:05 -0700 | [diff] [blame] | 18 | pub(crate) fn read_file_to_array(path: &str) -> Result<Vec<String>, String> { |
| 19 | let file = File::open(path).map_err(|e| e.to_string()).map_err(|err| { |
| 20 | format!( |
| 21 | "{} reading path: {:?}, current directory: {:?}", |
| 22 | err, |
| 23 | path, |
| 24 | std::env::current_dir() |
| 25 | ) |
| 26 | })?; |
| 27 | |
Brian Silverman | cc09f18 | 2022-03-09 15:40:20 -0800 | [diff] [blame] | 28 | read_to_array(file) |
| 29 | } |
| 30 | |
| 31 | pub(crate) fn read_stamp_status_to_array(path: String) -> Result<Vec<(String, String)>, String> { |
| 32 | let file = File::open(path).map_err(|e| e.to_string())?; |
| 33 | stamp_status_to_array(file) |
| 34 | } |
| 35 | |
| 36 | fn read_to_array(reader: impl Read) -> Result<Vec<String>, String> { |
| 37 | let reader = BufReader::new(reader); |
| 38 | let mut ret = vec![]; |
| 39 | let mut escaped_line = String::new(); |
| 40 | for l in reader.lines() { |
| 41 | let line = l.map_err(|e| e.to_string())?; |
| 42 | if line.is_empty() { |
| 43 | continue; |
| 44 | } |
| 45 | // a \ at the end of a line allows us to escape the new line break, |
| 46 | // \\ yields a single \, so \\\ translates to a single \ and a new line |
| 47 | // escape |
| 48 | let end_backslash_count = line.chars().rev().take_while(|&c| c == '\\').count(); |
| 49 | // a 0 or even number of backslashes do not lead to a new line escape |
| 50 | let escape = end_backslash_count % 2 == 1; |
| 51 | // remove backslashes and add back two for every one |
| 52 | let l = line.trim_end_matches('\\'); |
| 53 | escaped_line.push_str(l); |
| 54 | for _ in 0..end_backslash_count / 2 { |
| 55 | escaped_line.push('\\'); |
| 56 | } |
| 57 | if escape { |
| 58 | // we add a newline as we expect a line after this |
| 59 | escaped_line.push('\n'); |
| 60 | } else { |
| 61 | ret.push(escaped_line); |
| 62 | escaped_line = String::new(); |
| 63 | } |
| 64 | } |
| 65 | Ok(ret) |
| 66 | } |
| 67 | |
| 68 | fn stamp_status_to_array(reader: impl Read) -> Result<Vec<(String, String)>, String> { |
| 69 | let escaped_lines = read_to_array(reader)?; |
| 70 | escaped_lines |
| 71 | .into_iter() |
| 72 | .map(|l| { |
| 73 | let (s1, s2) = l |
| 74 | .split_once(' ') |
Adam Snaider | 1c095c9 | 2023-07-08 02:09:58 -0400 | [diff] [blame^] | 75 | .ok_or_else(|| format!("wrong workspace status file format for \"{l}\""))?; |
Brian Silverman | cc09f18 | 2022-03-09 15:40:20 -0800 | [diff] [blame] | 76 | Ok((s1.to_owned(), s2.to_owned())) |
| 77 | }) |
| 78 | .collect() |
| 79 | } |
| 80 | |
| 81 | #[cfg(test)] |
| 82 | mod test { |
| 83 | use super::*; |
| 84 | |
| 85 | #[test] |
| 86 | fn test_read_to_array() { |
| 87 | let input = r#"some escaped \\\ |
| 88 | string |
| 89 | with other lines"# |
| 90 | .to_owned(); |
| 91 | let expected = vec![ |
| 92 | r#"some escaped \ |
| 93 | string"#, |
| 94 | "with other lines", |
| 95 | ]; |
| 96 | let got = read_to_array(input.as_bytes()).unwrap(); |
| 97 | assert_eq!(expected, got); |
| 98 | } |
| 99 | |
| 100 | #[test] |
| 101 | fn test_stamp_status_to_array() { |
| 102 | let lines = "aaa bbb\\\nvvv\nccc ddd\neee fff"; |
| 103 | let got = stamp_status_to_array(lines.as_bytes()).unwrap(); |
| 104 | let expected = vec![ |
| 105 | ("aaa".to_owned(), "bbb\nvvv".to_owned()), |
| 106 | ("ccc".to_owned(), "ddd".to_owned()), |
| 107 | ("eee".to_owned(), "fff".to_owned()), |
| 108 | ]; |
| 109 | assert_eq!(expected, got); |
| 110 | } |
| 111 | } |