1use std::path::{Path, PathBuf, StripPrefixError};
2
3use pyo3::prelude::*;
4use pyo3::types::IntoPyDict;
5use thiserror::Error;
6
7use crate::stpa::constraints::Constraint;
8
9#[derive(Error, Debug)]
10pub enum RootError {
11 #[error("Could not find the root")]
12 NoRootFound,
13}
14
15pub fn find_root(location: &Path) -> Result<PathBuf, RootError> {
16 if location.is_dir() && location.join(".git").exists() {
17 return Ok(location.to_owned());
18 }
19 if let Some(parent) = location.parent() {
20 find_root(parent)
21 } else {
22 Err(RootError::NoRootFound)
23 }
24}
25
26#[derive(Error, Debug)]
27pub enum RootRelativeError {
28 #[error("Root and to relative did not match")]
29 StripPrefixError(#[from] StripPrefixError),
30 #[error("Root could not be made canonical")]
31 NotPathRootError(std::io::Error),
32 #[error("Target could not be made canonical")]
33 NotPathTargetError(std::io::Error),
34}
35
36pub fn rooted_relative_path(root: &Path, to_relitive: &Path) -> Result<PathBuf, RootRelativeError> {
37 let root = root
38 .canonicalize()
39 .map_err(RootRelativeError::NotPathRootError)?;
40 let to_relitive = to_relitive
41 .canonicalize()
42 .map_err(RootRelativeError::NotPathTargetError)?;
43 Ok(to_relitive.strip_prefix(root)?.to_owned())
44}
45
46#[derive(Error, Debug)]
47pub enum TrudagError {
48 #[error("Python trudag error")]
49 ErrorPython(#[from] PyErr),
50}
51
52pub fn create_node(
54 root: &Path,
55 trudag_graph: &Py<PyAny>,
56 group: &str,
57 parent: Option<&str>,
58 directory: &Path,
59 constraint: &Constraint,
60) -> Result<(), TrudagError> {
61 Ok(Python::with_gil(|py| {
62 let graph = trudag_graph.bind(py);
63
64 let trudag_manage = py.import("trudag.manage")?;
65 trudag_manage.call_method1(
66 "create_new_item",
67 (
68 group,
69 directory,
70 parent.unwrap_or(""),
71 constraint.trudag_id(),
72 root.join(".dotstop.dot"),
73 graph,
74 ),
75 )?;
76 let save = graph.getattr("to_file")?;
77 save.call((root.join(".dotstop.dot"),), None)?;
78 PyResult::Ok(())
79 })?)
80}
81
82pub fn remove_node(
84 root: &Path,
85 trudag_graph: &Py<PyAny>,
86 item_name: &str,
87) -> Result<(), TrudagError> {
88 Ok(Python::with_gil(|py| {
89 let graph = trudag_graph.bind(py);
90 graph.call_method1("remove_item", (item_name,))?;
91 graph.call_method1("to_file", (root.join(".dotstop.dot"),))?;
92 PyResult::Ok(())
93 })?)
94}
95
96pub fn set_node(
98 root: &Path,
99 trudag_graph: &Py<PyAny>,
100 group: &str,
101 constraint: &Constraint,
102) -> Result<(), TrudagError> {
103 Ok(Python::with_gil(|py| {
104 let graph = trudag_graph.bind(py);
105 graph.call_method(
106 "set_review_status",
107 (constraint.trudag_name(group),),
108 Some(&[("status", true)].into_py_dict(py)?),
109 )?;
110 graph.call_method1("to_file", (root.join(".dotstop.dot"),))?;
111 PyResult::Ok(())
112 })?)
113}
114
115pub fn set_node_links(
117 root: &Path,
118 trudag_graph: &Py<PyAny>,
119 group: &str,
120 constraint: &Constraint,
121) -> Result<(), TrudagError> {
122 Ok(Python::with_gil(|py| {
123 let graph = trudag_graph.bind(py);
124
125 let trudag_manage = py.import("trudag.manage")?;
126 let trustable_graph = py.import("trudag.dotstop.core.graph.trustable_graph")?;
127 let link_status = trustable_graph.getattr("LinkStatus")?;
128 let linked = link_status.getattr("LINKED")?;
129 trudag_manage.call_method(
130 "set_all_link_status",
131 (trudag_graph, constraint.trudag_name(group), linked),
132 None,
133 )?;
134
135 graph.call_method1("to_file", (root.join(".dotstop.dot"),))?;
136 PyResult::Ok(())
137 })?)
138}
139
140pub fn create_link(
142 root: &Path,
143 trudag_graph: &Py<PyAny>,
144 group: &str,
145 constraint: &Constraint,
146 link: &str,
147) -> Result<(), TrudagError> {
148 Ok(Python::with_gil(|py| {
149 let module = PyModule::import(py, "trudag.dotstop.core.graph")?;
150 let link_status = module.getattr("LinkStatus")?;
151 let linked = link_status.getattr("LINKED")?;
152
153 let graph = trudag_graph.bind(py);
154
155 graph.call_method1(
156 "set_link_status",
157 (link, constraint.trudag_name(group), linked),
158 )?;
159 graph.call_method1("to_file", (root.join(".dotstop.dot"),))?;
160 PyResult::Ok(())
161 })?)
162}