graphviz_rust_bla/
cmd.rs

1//! It allows to execute cmd engine passing extra parameters
2//!
3//! *It is important*: to execute it properly it needs to have an [`executable package`] on the system
4//!
5//! The extra information can be found in [`layouts`] and [`outputs`]
6//!
7//! [`layouts`]: https://graphviz.org/docs/layouts/
8//! [`outputs`]:https://graphviz.org/docs/outputs/
9//! [`executable package`]: https://graphviz.org/download/
10//! # Example:
11//! ```no_run
12//!     use dot_structures::*;
13//!     use dot_generator::*;
14//!     use graphviz_rust::attributes::*;
15//!     use graphviz_rust::cmd::{CommandArg, Format};
16//!     use graphviz_rust::exec;
17//!     use graphviz_rust::printer::{PrinterContext,DotPrinter};
18//!
19//!  fn graph_to_output(){
20//!     let mut g = graph!(id!("id");
21//!             node!("nod"),
22//!             subgraph!("sb";
23//!                 edge!(node_id!("a") => subgraph!(;
24//!                    node!("n";
25//!                    NodeAttributes::color(color_name::black), NodeAttributes::shape(shape::egg))
26//!                ))
27//!            ),
28//!            edge!(node_id!("a1") => node_id!(esc "a2"))
29//!        );
30//!        let graph_svg = exec(g, &mut PrinterContext::default(), vec![
31//!            CommandArg::Format(Format::Svg),
32//!        ]).unwrap();
33//!
34//!  }
35//!  fn graph_to_file(){
36//!     let mut g = graph!(id!("id"));
37//!         let mut ctx = PrinterContext::default();
38//!         ctx.always_inline();
39//!         let empty = exec(g, &mut ctx, vec![
40//!            CommandArg::Format(Format::Svg),
41//!            CommandArg::Output("1.svg".to_string())
42//!        ]).unwrap();
43//!
44//!  }
45//! ```
46use tempfile::NamedTempFile;
47use std::io::{self, Error, Write};
48use std::process::{Command, Output};
49use std::str;
50
51pub(crate) fn exec(graph: String, args: Vec<CommandArg>) -> io::Result<String> {
52    let args = args.into_iter().map(|a| a.prepare()).collect();
53    temp_file(graph).and_then(|f| {
54        let path = f.path().to_string_lossy().to_string();
55        do_exec(path, args).map(|o| {
56            if o.status.code().map(|c| c != 0).unwrap_or(true) {
57                String::from_utf8_lossy(&*o.stderr).to_string()
58            } else {
59                String::from_utf8_lossy(&*o.stdout).to_string()
60            }
61        })
62    })
63}
64
65
66fn do_exec(input: String, args: Vec<String>) -> std::io::Result<Output> {
67    let mut command = Command::new("dot");
68
69    for arg in args {
70        command.arg(arg);
71    }
72    command
73        .arg(input)
74        .output()
75}
76
77fn temp_file(ctx: String) -> io::Result<NamedTempFile> {
78    let mut file = NamedTempFile::new()?;
79    file.write_all(ctx.as_bytes())
80        .map(|_x| file)
81}
82
83/// Command arguments that can be passed to exec.
84/// The list of possible [`commands`]
85///
86/// [`commands`]:https://graphviz.org/doc/info/command.html
87pub enum CommandArg {
88    /// any custom argument.
89    ///
90    /// _Note_: it does not manage any prefixes and thus '-' or the prefix must be passed as well.
91    Custom(String),
92    /// Regulates the output file with -o prefix
93    Output(String),
94    /// [`Layouts`] in cmd
95    ///
96    /// [`Layouts`]: https://graphviz.org/docs/layouts/
97    Layout(Layout),
98    /// [`Output`] formats in cmd
99    ///
100    /// [`Output`]:https://graphviz.org/docs/outputs/
101    Format(Format),
102}
103
104impl CommandArg {
105    fn prepare(&self) -> String {
106        match self {
107            CommandArg::Custom(s) => s.clone(),
108            CommandArg::Output(p) => format!("-o{}", p),
109            CommandArg::Layout(l) => format!("-K{}", format!("{:?}", l).to_lowercase()),
110            CommandArg::Format(f) => {
111                let str = match f {
112                    Format::Xdot12 => "xdot1.2".to_string(),
113                    Format::Xdot14 => "xdot1.4".to_string(),
114                    Format::ImapNp => "imap_np".to_string(),
115                    Format::CmapxNp => "cmapx_np".to_string(),
116                    Format::DotJson => "dot_json".to_string(),
117                    Format::XdotJson => "xdot_json".to_string(),
118                    Format::PlainExt => "plain-ext".to_string(),
119                    _ => format!("{:?}", f).to_lowercase()
120                };
121                format!("-T{}", str)
122            }
123        }
124    }
125}
126
127#[derive(Debug)]
128pub enum Layout {
129    Dot,
130    Neato,
131    Twopi,
132    Circo,
133    Fdp,
134    Asage,
135    Patchwork,
136    Sfdp,
137}
138
139
140#[derive(Debug)]
141pub enum Format {
142    Bmp,
143    Cgimage,
144    Canon,
145    Dot,
146    Gv,
147    Xdot,
148    Xdot12,
149    Xdot14,
150    Eps,
151    Exr,
152    Fig,
153    Gd,
154    Gd2,
155    Gif,
156    Gtk,
157    Ico,
158    Cmap,
159    Ismap,
160    Imap,
161    Cmapx,
162    ImapNp,
163    CmapxNp,
164    Jpg,
165    Jpeg,
166    Jpe,
167    Jp2,
168    Json,
169    Json0,
170    DotJson,
171    XdotJson,
172    Pdf,
173    Pic,
174    Pct,
175    Pict,
176    Plain,
177    PlainExt,
178    Png,
179    Pov,
180    Ps,
181    Ps2,
182    Psd,
183    Sgi,
184    Svg,
185    Svgz,
186    Tga,
187    Tif,
188    Tiff,
189    Tk,
190    Vml,
191    Vmlz,
192    Vrml,
193    Vbmp,
194    Webp,
195    Xlib,
196    X11,
197}