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}