blob: 9bb6693f8744fa30c65139a8a0e13cd76fcf0e56 [file] [log] [blame]
Brian Silvermancc09f182022-03-09 15:40:20 -08001// 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
15use std::fs::File;
16use std::io::{BufRead, BufReader, Read};
17
Brian Silverman5f6f2762022-08-13 19:30:05 -070018pub(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 Silvermancc09f182022-03-09 15:40:20 -080028 read_to_array(file)
29}
30
31pub(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
36fn 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
68fn 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 Snaider1c095c92023-07-08 02:09:58 -040075 .ok_or_else(|| format!("wrong workspace status file format for \"{l}\""))?;
Brian Silvermancc09f182022-03-09 15:40:20 -080076 Ok((s1.to_owned(), s2.to_owned()))
77 })
78 .collect()
79}
80
81#[cfg(test)]
82mod test {
83 use super::*;
84
85 #[test]
86 fn test_read_to_array() {
87 let input = r#"some escaped \\\
88string
89with other lines"#
90 .to_owned();
91 let expected = vec![
92 r#"some escaped \
93string"#,
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}