pyoxidizerlib/starlark/
python_package_distribution_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::{PythonPackageDistributionResource, 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 PythonPackageDistributionResourceWrapper {
20    pub r: PythonPackageDistributionResource,
21    pub add_context: Option<PythonResourceAddCollectionContext>,
22}
23
24/// Starlark `Value` wrapper for `PythonPackageDistributionResource`.
25#[derive(Debug, Clone)]
26pub struct PythonPackageDistributionResourceValue {
27    inner: Arc<Mutex<PythonPackageDistributionResourceWrapper>>,
28    package: String,
29    name: String,
30}
31
32impl PythonPackageDistributionResourceValue {
33    pub fn new(resource: PythonPackageDistributionResource) -> Self {
34        let package = resource.package.clone();
35        let name = resource.name.clone();
36
37        Self {
38            inner: Arc::new(Mutex::new(PythonPackageDistributionResourceWrapper {
39                r: resource,
40                add_context: None,
41            })),
42            package,
43            name,
44        }
45    }
46
47    pub fn inner(
48        &self,
49        label: &str,
50    ) -> Result<MutexGuard<PythonPackageDistributionResourceWrapper>, ValueError> {
51        self.inner.try_lock().map_err(|e| {
52            ValueError::Runtime(RuntimeError {
53                code: "PYTHON_PACKAGE_DISTRIBUTION_RESOURCE",
54                message: format!("failed to acquire lock: {}", e),
55                label: label.to_string(),
56            })
57        })
58    }
59}
60
61impl ResourceCollectionContext for PythonPackageDistributionResourceValue {
62    fn add_collection_context(
63        &self,
64    ) -> Result<Option<PythonResourceAddCollectionContext>, ValueError> {
65        Ok(self
66            .inner("PythonPackageDistributionResource.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("PythonPackageDistributionResource.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("PythonPackageDistributionResource.as_python_resource()")?
84                .r
85                .clone(),
86        ))
87    }
88}
89
90impl TypedValue for PythonPackageDistributionResourceValue {
91    type Holder = Mutable<PythonPackageDistributionResourceValue>;
92    const TYPE: &'static str = "PythonPackageDistributionResource";
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.package,
103            self.name
104        )
105    }
106
107    fn to_repr(&self) -> String {
108        self.to_str()
109    }
110
111    fn to_bool(&self) -> bool {
112        true
113    }
114
115    fn get_attr(&self, attribute: &str) -> ValueResult {
116        let inner = self.inner(&format!("PythonPackageDistributionResource.{}", attribute))?;
117
118        let v = match attribute {
119            "is_stdlib" => Value::from(false),
120            "package" => Value::new(inner.r.package.clone()),
121            "name" => Value::new(inner.r.name.clone()),
122            // TODO expose raw data
123            attr => {
124                drop(inner);
125
126                return if self.add_collection_context_attrs().contains(&attr) {
127                    self.get_attr_add_collection_context(attr)
128                } else {
129                    Err(ValueError::OperationNotSupported {
130                        op: UnsupportedOperation::GetAttr(attr.to_string()),
131                        left: Self::TYPE.to_string(),
132                        right: None,
133                    })
134                };
135            }
136        };
137
138        Ok(v)
139    }
140
141    fn has_attr(&self, attribute: &str) -> Result<bool, ValueError> {
142        Ok(match attribute {
143            "is_stdlib" => true,
144            "package" => true,
145            "name" => true,
146            // TODO expose raw data
147            attr => self.add_collection_context_attrs().contains(&attr),
148        })
149    }
150
151    fn set_attr(&mut self, attribute: &str, value: Value) -> Result<(), ValueError> {
152        if self.add_collection_context_attrs().contains(&attribute) {
153            self.set_attr_add_collection_context(attribute, value)
154        } else {
155            Err(ValueError::OperationNotSupported {
156                op: UnsupportedOperation::SetAttr(attribute.to_string()),
157                left: Self::TYPE.to_owned(),
158                right: None,
159            })
160        }
161    }
162}