1use super::{scope, Entity, Node, Result, Scope};
5
6use std::collections::BTreeMap;
7use std::io::Seek;
8use std::ops::Deref;
9use std::path::Path;
10
11use drawbridge_jose::jws::Jws;
12use drawbridge_jose::MediaTyped;
13use drawbridge_type::TreeContent::{Directory, File};
14use drawbridge_type::{TagEntry, TagName, Tree, TreeEntry, TreePath};
15
16use anyhow::Context;
17use ureq::serde::Serialize;
18
19#[derive(Clone, Debug)]
20pub struct Tag<'a, S: Scope>(Entity<'a, S, scope::Tag>);
21
22impl<'a, S: Scope> Deref for Tag<'a, S> {
23 type Target = Entity<'a, S, scope::Tag>;
24
25 fn deref(&self) -> &Self::Target {
26 &self.0
27 }
28}
29
30impl<'a, S: Scope> Tag<'a, S> {
31 pub fn new(entity: Entity<'a, S, scope::Repository>, name: &TagName) -> Self {
32 Tag(entity.child(&name.to_string()))
33 }
34
35 pub fn create(&self, entry: &TagEntry<impl Serialize>) -> Result<bool> {
36 let mime = match entry {
37 TagEntry::Unsigned(..) => TreeEntry::<()>::TYPE,
38 TagEntry::Signed(..) => Jws::TYPE,
39 }
40 .parse()
41 .expect("failed to parse tag entry media type");
42 self.0.create_json(&mime, entry)
43 }
44
45 pub fn create_from_path_unsigned(
47 &self,
48 path: impl AsRef<Path>,
49 ) -> Result<(bool, BTreeMap<TreePath, bool>)> {
50 let tree = Tree::from_path_sync(path)?;
51 let tag_created = self.create(&TagEntry::Unsigned(tree.root()))?;
52 let tree_created = tree
53 .into_iter()
54 .map(|(path, TreeEntry { meta, content, .. })| {
55 let node = Node::new(self.child("tree"), &path);
56 let created = match content {
57 File(mut file) => {
58 file.rewind().context("failed to rewind file")?;
59 node.create_from(&meta, file)?
60 }
61 Directory(buf) => node.create_from(&meta, buf.as_slice())?,
62 };
63 Ok((path, created))
64 })
65 .collect::<Result<_>>()?;
66 Ok((tag_created, tree_created))
67 }
68
69 pub fn get(&self) -> Result<TagEntry> {
70 self.0.get_json(u64::MAX).map(|(_, v)| v)
73 }
74
75 pub fn path(&self, path: &TreePath) -> Node<'a, S> {
76 Node::new(self.child("tree"), path)
77 }
78}