smart_patcher/
python_exec.rs

1use anyhow::{anyhow, bail};
2use pyo3::prelude::*;
3use pyo3::types::PyList;
4use std::env;
5use std::path::Path;
6
7pub fn find_by(
8  patch_dir: &Path,
9  path: &Path,
10  content: &str,
11  start_pos: Option<usize>,
12  end_pos: Option<usize>,
13) -> anyhow::Result<(usize, usize, bool)> {
14  let patch_path = patch_dir.to_path_buf().join(path);
15
16  if !patch_path.is_file() {
17    bail!("Python script path ({:?}) has to be a file.", patch_path)
18  }
19  let module_name = patch_path.file_stem().unwrap();
20  let mut root_dir = patch_path.canonicalize()?;
21  root_dir.pop();
22  let root_dir = root_dir.to_string_lossy().to_string();
23
24  let res: PyResult<(usize, usize, bool)> = Python::with_gil(|py| {
25    let rev = env::current_dir()?;
26    env::set_current_dir(patch_dir)?;
27
28    let sys = PyModule::import(py, "sys")?;
29    let sys_path = sys.getattr("path")?;
30    let sys_path = sys_path.downcast::<PyList>()?;
31    if !sys_path.contains(root_dir.clone())? {
32      sys_path.insert(0, root_dir)?;
33    }
34    dbg!(sys_path);
35
36    let module = PyModule::import(py, module_name)?;
37
38    let content = content.to_owned();
39    let result: (usize, usize, bool) = module
40      .getattr("find")?
41      .call1((content, start_pos, end_pos))?
42      .extract()?;
43
44    env::set_current_dir(rev)?;
45
46    Ok(result)
47  });
48
49  Ok(res?)
50}
51
52pub fn replace_by(patch_dir: &Path, path: &Path, content: &str) -> anyhow::Result<String> {
53  let patch_path = patch_dir.to_path_buf().join(path);
54
55  if !patch_path.is_file() {
56    bail!("Python script path ({:?}) has to be a file.", patch_path)
57  }
58  let module_name = patch_path.file_stem().unwrap();
59  let mut root_dir = patch_path.canonicalize()?;
60  root_dir.pop();
61  let root_dir = root_dir.to_string_lossy().to_string();
62
63  let res: PyResult<Option<String>> = Python::with_gil(|py| {
64    let rev = env::current_dir()?;
65    env::set_current_dir(patch_dir)?;
66
67    let sys = PyModule::import(py, "sys")?;
68    let sys_path = sys.getattr("path")?;
69    let sys_path = sys_path.downcast::<PyList>()?;
70    if !sys_path.contains(root_dir.clone())? {
71      sys_path.insert(0, root_dir)?;
72    }
73
74    let module = PyModule::import(py, module_name)?;
75
76    let content = content.to_owned();
77    let result: Option<String> = module.getattr("replace")?.call1((content,))?.extract()?;
78
79    env::set_current_dir(rev)?;
80
81    Ok(result)
82  });
83
84  res?.ok_or(anyhow!("No content!"))
85}
86
87pub fn decode_by(patch_dir: &Path, path: &Path, content: &[u8]) -> anyhow::Result<String> {
88  let patch_path = patch_dir.to_path_buf().join(path);
89
90  if !patch_path.is_file() {
91    bail!("Python script path ({:?}) has to be a file.", patch_path)
92  }
93  let module_name = patch_path.file_stem().unwrap();
94  let mut root_dir = patch_path.canonicalize()?;
95  root_dir.pop();
96  let root_dir = root_dir.to_string_lossy().to_string();
97
98  let res: PyResult<Option<String>> = Python::with_gil(|py| {
99    let rev = env::current_dir()?;
100    env::set_current_dir(patch_dir)?;
101
102    let sys = PyModule::import(py, "sys")?;
103    let sys_path = sys.getattr("path")?;
104    let sys_path = sys_path.downcast::<PyList>()?;
105    if !sys_path.contains(root_dir.clone())? {
106      sys_path.insert(0, root_dir)?;
107    }
108
109    let module = PyModule::import(py, module_name)?;
110
111    let content = content.to_owned();
112    let result: Option<String> = module.getattr("decode")?.call1((content,))?.extract()?;
113
114    env::set_current_dir(rev)?;
115
116    Ok(result)
117  });
118
119  res?.ok_or(anyhow!("No content!"))
120}
121
122pub fn encode_by(patch_dir: &Path, path: &Path, content: &str) -> anyhow::Result<Vec<u8>> {
123  let patch_path = patch_dir.to_path_buf().join(path);
124
125  if !patch_path.is_file() {
126    bail!("Python script path ({:?}) has to be a file.", patch_path)
127  }
128  let module_name = patch_path.file_stem().unwrap();
129  let mut root_dir = patch_path.canonicalize()?;
130  root_dir.pop();
131  let root_dir = root_dir.to_string_lossy().to_string();
132
133  let res: PyResult<Option<Vec<u8>>> = Python::with_gil(|py| {
134    let rev = env::current_dir()?;
135    env::set_current_dir(patch_dir)?;
136
137    let sys = PyModule::import(py, "sys")?;
138    let sys_path = sys.getattr("path")?;
139    let sys_path = sys_path.downcast::<PyList>()?;
140    if !sys_path.contains(root_dir.clone())? {
141      sys_path.insert(0, root_dir)?;
142    }
143
144    let module = PyModule::import(py, module_name)?;
145
146    let content = content.to_owned();
147    let result: Option<Vec<u8>> = module.getattr("encode")?.call1((content,))?.extract()?;
148
149    env::set_current_dir(rev)?;
150
151    Ok(result)
152  });
153
154  res?.ok_or(anyhow!("No content!"))
155}