pyoxidizerlib/starlark/
python_embedded_resources.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
5use {
6    crate::{
7        py_packaging::binary::PythonBinaryBuilder,
8        starlark::env::{get_context, PyOxidizerEnvironmentContext},
9    },
10    anyhow::{anyhow, Context, Result},
11    log::warn,
12    starlark::{
13        environment::TypeValues,
14        values::{
15            error::{RuntimeError, ValueError},
16            {Mutable, TypedValue, Value, ValueResult},
17        },
18        {
19            starlark_fun, starlark_module, starlark_parse_param_type, starlark_signature,
20            starlark_signature_extraction, starlark_signatures,
21        },
22    },
23    starlark_dialect_build_targets::{ResolvedTarget, ResolvedTargetValue, RunMode},
24    std::sync::Arc,
25};
26
27fn error_context<F, T>(label: &str, f: F) -> Result<T, ValueError>
28where
29    F: FnOnce() -> anyhow::Result<T>,
30{
31    f().map_err(|e| {
32        ValueError::Runtime(RuntimeError {
33            code: "PYOXIDIZER_PYTHON_EMBEDDED_RESOURCES",
34            message: format!("{:?}", e),
35            label: label.to_string(),
36        })
37    })
38}
39
40pub struct PythonEmbeddedResourcesValue {
41    pub exe: Arc<dyn PythonBinaryBuilder>,
42}
43
44impl TypedValue for PythonEmbeddedResourcesValue {
45    type Holder = Mutable<PythonEmbeddedResourcesValue>;
46    const TYPE: &'static str = "PythonEmbeddedResources";
47
48    fn values_for_descendant_check_and_freeze(&self) -> Box<dyn Iterator<Item = Value>> {
49        Box::new(std::iter::empty())
50    }
51}
52
53impl PythonEmbeddedResourcesValue {
54    fn build(
55        &self,
56        type_values: &TypeValues,
57        target: &str,
58        context: &PyOxidizerEnvironmentContext,
59    ) -> Result<ResolvedTarget> {
60        let output_path = context
61            .get_output_path(type_values, target)
62            .map_err(|_| anyhow!("unable to resolve output path"))?;
63
64        warn!(
65            "writing Python embedded artifacts to {}",
66            output_path.display()
67        );
68
69        let embedded = self
70            .exe
71            .to_embedded_python_context(context.env(), &context.build_opt_level)?;
72
73        std::fs::create_dir_all(&output_path)
74            .with_context(|| format!("creating output directory: {}", output_path.display()))?;
75        embedded.write_files(&output_path)?;
76
77        Ok(ResolvedTarget {
78            run_mode: RunMode::None,
79            output_path,
80        })
81    }
82
83    fn build_starlark(&self, type_values: &TypeValues, target: String) -> ValueResult {
84        let pyoxidizer_context_value = get_context(type_values)?;
85        let pyoxidizer_context = pyoxidizer_context_value
86            .downcast_ref::<PyOxidizerEnvironmentContext>()
87            .ok_or(ValueError::IncorrectParameterType)?;
88
89        let inner = error_context("PythonEmbeddedResources.build()", || {
90            self.build(type_values, &target, &pyoxidizer_context)
91        })?;
92
93        Ok(Value::new(ResolvedTargetValue { inner }))
94    }
95}
96
97starlark_module! { python_embedded_resources_module =>
98    PythonEmbeddedResources.build(
99        env env,
100        this,
101        target: String
102    ) {
103        let this = this.downcast_ref::<PythonEmbeddedResourcesValue>().unwrap();
104        this.build_starlark(env, target)
105    }
106}