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