pyoxidizerlib/starlark/
file.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::PythonResource, resource_collection::PythonResourceAddCollectionContext,
9    },
10    simple_file_manifest::File,
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 FileWrapper {
20    pub file: File,
21    pub add_context: Option<PythonResourceAddCollectionContext>,
22}
23
24/// Starlark value wrapper for `File`.
25#[derive(Clone, Debug)]
26pub struct FileValue {
27    inner: Arc<Mutex<FileWrapper>>,
28    path: String,
29}
30
31impl FileValue {
32    pub fn new(file: File) -> Self {
33        let path = file.path_string();
34
35        Self {
36            inner: Arc::new(Mutex::new(FileWrapper {
37                file,
38                add_context: None,
39            })),
40            path,
41        }
42    }
43
44    pub fn inner(&self, label: &str) -> Result<MutexGuard<FileWrapper>, ValueError> {
45        self.inner.try_lock().map_err(|e| {
46            ValueError::Runtime(RuntimeError {
47                code: "FILE",
48                message: format!("failed to acquire lock: {}", e),
49                label: label.to_string(),
50            })
51        })
52    }
53}
54
55impl ResourceCollectionContext for FileValue {
56    fn add_collection_context(
57        &self,
58    ) -> Result<Option<PythonResourceAddCollectionContext>, ValueError> {
59        Ok(self
60            .inner("File.add_collection_context()")?
61            .add_context
62            .clone())
63    }
64
65    fn replace_add_collection_context(
66        &mut self,
67        context: PythonResourceAddCollectionContext,
68    ) -> Result<Option<PythonResourceAddCollectionContext>, ValueError> {
69        Ok(self
70            .inner("File.replace_add_collection_context()")?
71            .add_context
72            .replace(context))
73    }
74
75    fn as_python_resource(&self) -> Result<PythonResource<'_>, ValueError> {
76        Ok(PythonResource::from(
77            self.inner("File.as_python_resource()")?.file.clone(),
78        ))
79    }
80}
81
82impl TypedValue for FileValue {
83    type Holder = Mutable<FileValue>;
84    const TYPE: &'static str = "File";
85
86    fn values_for_descendant_check_and_freeze(&self) -> Box<dyn Iterator<Item = Value>> {
87        Box::new(std::iter::empty())
88    }
89
90    fn to_str(&self) -> String {
91        format!("{}<path={}>", Self::TYPE, self.path,)
92    }
93
94    fn to_repr(&self) -> String {
95        self.to_str()
96    }
97
98    fn get_attr(&self, attribute: &str) -> ValueResult {
99        let inner = self.inner(&format!("File.{}", attribute))?;
100
101        let v = match attribute {
102            "path" => Value::from(inner.file.path_string()),
103            "is_executable" => Value::from(inner.file.entry().is_executable()),
104            attr => {
105                drop(inner);
106
107                return if self.add_collection_context_attrs().contains(&attr) {
108                    self.get_attr_add_collection_context(attr)
109                } else {
110                    Err(ValueError::OperationNotSupported {
111                        op: UnsupportedOperation::GetAttr(attr.to_string()),
112                        left: Self::TYPE.to_string(),
113                        right: None,
114                    })
115                };
116            }
117        };
118
119        Ok(v)
120    }
121
122    fn has_attr(&self, attribute: &str) -> Result<bool, ValueError> {
123        Ok(match attribute {
124            "path" => true,
125            "is_executable" => true,
126            attr => self.add_collection_context_attrs().contains(&attr),
127        })
128    }
129
130    fn set_attr(&mut self, attribute: &str, value: Value) -> Result<(), ValueError> {
131        self.set_attr_add_collection_context(attribute, value)
132    }
133}