smart_patcher/
python_exec.rs1use 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}