tauri_build/codegen/context.rs
1// Copyright 2019-2021 Tauri Programme within The Commons Conservancy
2// SPDX-License-Identifier: Apache-2.0
3// SPDX-License-Identifier: MIT
4
5use anyhow::{Context, Result};
6use std::{
7 env::var,
8 fs::{create_dir_all, File},
9 io::{BufWriter, Write},
10 path::PathBuf,
11};
12use tauri_codegen::{context_codegen, ContextData};
13
14// TODO docs
15/// A builder for generating a Tauri application context during compile time.
16#[cfg_attr(doc_cfg, doc(cfg(feature = "codegen")))]
17#[derive(Debug)]
18pub struct CodegenContext {
19 dev: bool,
20 config_path: PathBuf,
21 out_file: PathBuf,
22}
23
24impl Default for CodegenContext {
25 fn default() -> Self {
26 Self {
27 dev: false,
28 config_path: PathBuf::from("tauri.conf.json"),
29 out_file: PathBuf::from("tauri-build-context.rs"),
30 }
31 }
32}
33
34impl CodegenContext {
35 /// Create a new [`CodegenContext`] builder that is already filled with the default options.
36 pub fn new() -> Self {
37 Self::default()
38 }
39
40 /// Set the path to the `tauri.conf.json` (relative to the package's directory).
41 ///
42 /// This defaults to a file called `tauri.conf.json` inside of the current working directory of
43 /// the package compiling; does not need to be set manually if that config file is in the same
44 /// directory as your `Cargo.toml`.
45 pub fn config_path(mut self, config_path: impl Into<PathBuf>) -> Self {
46 self.config_path = config_path.into();
47 self
48 }
49
50 /// Sets the output file's path.
51 ///
52 /// **Note:** This path should be relative to the `OUT_DIR`.
53 ///
54 /// Don't set this if you are using [`tauri::include_codegen_context!`] as that helper macro
55 /// expects the default value. This option can be useful if you are not using the helper and
56 /// instead using [`std::include!`] on the generated code yourself.
57 ///
58 /// Defaults to `tauri-build-context.rs`.
59 ///
60 /// [`tauri::include_codegen_context!`]: https://docs.rs/tauri/0.12/tauri/macro.include_codegen_context.html
61 pub fn out_file(mut self, filename: PathBuf) -> Self {
62 self.out_file = filename;
63 self
64 }
65
66 /// Run the codegen in a `dev` context, meaning that Tauri is using a dev server or local file for development purposes,
67 /// usually with the `tauri dev` CLI command.
68 pub fn dev(mut self) -> Self {
69 self.dev = true;
70 self
71 }
72
73 /// Generate the code and write it to the output file - returning the path it was saved to.
74 ///
75 /// Unless you are doing something special with this builder, you don't need to do anything with
76 /// the returned output path.
77 ///
78 /// # Panics
79 ///
80 /// If any parts of the codegen fail, this will panic with the related error message. This is
81 /// typically desirable when running inside a build script; see [`Self::try_build`] for no panics.
82 pub fn build(self) -> PathBuf {
83 match self.try_build() {
84 Ok(out) => out,
85 Err(error) => panic!("Error found during Codegen::build: {}", error),
86 }
87 }
88
89 /// Non-panicking [`Self::build`]
90 pub fn try_build(self) -> Result<PathBuf> {
91 let (config, config_parent) = tauri_codegen::get_config(&self.config_path)?;
92 let code = context_codegen(ContextData {
93 dev: self.dev,
94 config,
95 config_parent,
96 // it's very hard to have a build script for unit tests, so assume this is always called from
97 // outside the tauri crate, making the ::tauri root valid.
98 root: quote::quote!(::tauri::Context),
99 })?;
100
101 // get the full output file path
102 let out = var("OUT_DIR")
103 .map(PathBuf::from)
104 .map(|path| path.join(&self.out_file))
105 .with_context(|| "unable to find OUT_DIR during tauri-build")?;
106
107 // make sure any nested directories in OUT_DIR are created
108 let parent = out.parent().with_context(|| {
109 "`Codegen` could not find the parent to `out_file` while creating the file"
110 })?;
111 create_dir_all(parent)?;
112
113 let mut file = File::create(&out).map(BufWriter::new).with_context(|| {
114 format!(
115 "Unable to create output file during tauri-build {}",
116 out.display()
117 )
118 })?;
119
120 writeln!(&mut file, "{}", code).with_context(|| {
121 format!(
122 "Unable to write tokenstream to out file during tauri-build {}",
123 out.display()
124 )
125 })?;
126
127 Ok(out)
128 }
129}