pyoxidizerlib/starlark/
python_package_resource.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    super::python_resource::ResourceCollectionContext,
7    python_packaging::{
8        resource::{PythonPackageResource, PythonResource},
9        resource_collection::PythonResourceAddCollectionContext,
10    },
11    starlark::values::{
12        error::{RuntimeError, UnsupportedOperation, ValueError},
13        {Mutable, TypedValue, Value, ValueResult},
14    },
15    std::sync::{Arc, Mutex, MutexGuard},
16};
17
18#[derive(Debug)]
19pub struct PythonPackageResourceWrapper {
20    pub r: PythonPackageResource,
21    pub add_context: Option<PythonResourceAddCollectionContext>,
22}
23
24/// Starlark `Value` wrapper for `PythonPackageResource`.
25#[derive(Debug, Clone)]
26pub struct PythonPackageResourceValue {
27    inner: Arc<Mutex<PythonPackageResourceWrapper>>,
28    leaf_package: String,
29    relative_name: String,
30}
31
32impl PythonPackageResourceValue {
33    pub fn new(resource: PythonPackageResource) -> Self {
34        let leaf_package = resource.leaf_package.clone();
35        let relative_name = resource.relative_name.clone();
36
37        Self {
38            inner: Arc::new(Mutex::new(PythonPackageResourceWrapper {
39                r: resource,
40                add_context: None,
41            })),
42            leaf_package,
43            relative_name,
44        }
45    }
46
47    pub fn inner(
48        &self,
49        label: &str,
50    ) -> Result<MutexGuard<PythonPackageResourceWrapper>, ValueError> {
51        self.inner.try_lock().map_err(|e| {
52            ValueError::Runtime(RuntimeError {
53                code: "PYTHON_PACKAGE_RESOURCE",
54                message: format!("failed to acquire lock: {}", e),
55                label: label.to_string(),
56            })
57        })
58    }
59}
60
61impl ResourceCollectionContext for PythonPackageResourceValue {
62    fn add_collection_context(
63        &self,
64    ) -> Result<Option<PythonResourceAddCollectionContext>, ValueError> {
65        Ok(self
66            .inner("PythonPackageResource.add_collection_context()")?
67            .add_context
68            .clone())
69    }
70
71    fn replace_add_collection_context(
72        &mut self,
73        context: PythonResourceAddCollectionContext,
74    ) -> Result<Option<PythonResourceAddCollectionContext>, ValueError> {
75        Ok(self
76            .inner("PythonPackageResource.replace_add_collection_context()")?
77            .add_context
78            .replace(context))
79    }
80
81    fn as_python_resource(&self) -> Result<PythonResource<'_>, ValueError> {
82        Ok(PythonResource::from(
83            self.inner("PythonPackageResource.as_python_resource()")?
84                .r
85                .clone(),
86        ))
87    }
88}
89
90impl TypedValue for PythonPackageResourceValue {
91    type Holder = Mutable<PythonPackageResourceValue>;
92    const TYPE: &'static str = "PythonPackageResource";
93
94    fn values_for_descendant_check_and_freeze(&self) -> Box<dyn Iterator<Item = Value>> {
95        Box::new(std::iter::empty())
96    }
97
98    fn to_str(&self) -> String {
99        format!(
100            "{}<package={}, name={}>",
101            Self::TYPE,
102            self.leaf_package,
103            self.relative_name
104        )
105    }
106
107    fn to_repr(&self) -> String {
108        self.to_str()
109    }
110
111    fn get_attr(&self, attribute: &str) -> ValueResult {
112        let inner = self.inner(&format!("PythonPackageResource.{}", attribute))?;
113
114        let v = match attribute {
115            "is_stdlib" => Value::from(inner.r.is_stdlib),
116            "package" => Value::new(inner.r.leaf_package.clone()),
117            "name" => Value::new(inner.r.relative_name.clone()),
118            // TODO expose raw data
119            attr => {
120                drop(inner);
121
122                return if self.add_collection_context_attrs().contains(&attr) {
123                    self.get_attr_add_collection_context(attr)
124                } else {
125                    Err(ValueError::OperationNotSupported {
126                        op: UnsupportedOperation::GetAttr(attr.to_string()),
127                        left: Self::TYPE.to_string(),
128                        right: None,
129                    })
130                };
131            }
132        };
133
134        Ok(v)
135    }
136
137    fn has_attr(&self, attribute: &str) -> Result<bool, ValueError> {
138        Ok(match attribute {
139            "is_stdlib" => true,
140            "package" => true,
141            "name" => true,
142            // TODO expose raw data
143            attr => self.add_collection_context_attrs().contains(&attr),
144        })
145    }
146
147    fn set_attr(&mut self, attribute: &str, value: Value) -> Result<(), ValueError> {
148        if self.add_collection_context_attrs().contains(&attribute) {
149            self.set_attr_add_collection_context(attribute, value)
150        } else {
151            Err(ValueError::OperationNotSupported {
152                op: UnsupportedOperation::SetAttr(attribute.to_string()),
153                left: Self::TYPE.to_owned(),
154                right: None,
155            })
156        }
157    }
158}