gra/
descriptor.rs

1// SPDX-License-Identifier: GPL-3.0-or-later
2
3use std::{collections::HashMap, fs::File, io::Read, path::Path};
4
5use serde::Deserialize;
6use toml::Value;
7
8#[derive(Debug, Clone)]
9pub struct ProjectDescriptor {
10    pub package: PackageDescriptor,
11    pub app: AppDescriptor,
12    pub settings: Option<HashMap<String, Value>>,
13    pub actions: Option<HashMap<String, ActionDescriptor>>,
14}
15
16#[derive(Debug, Deserialize, Clone)]
17#[serde(rename(serialize = "component"))]
18pub struct CargoToml {
19    pub package: PackageDescriptor,
20}
21
22#[derive(Debug, Deserialize, Clone)]
23#[serde(rename(serialize = "component"))]
24pub struct AppToml {
25    pub app: AppDescriptor,
26    pub settings: Option<HashMap<String, Value>>,
27    pub actions: Option<HashMap<String, ActionDescriptor>>,
28}
29
30#[derive(Debug, Deserialize, Clone)]
31pub struct PackageDescriptor {
32    pub name: String,
33    pub version: String,
34    pub authors: Option<Vec<String>>,
35    pub homepage: Option<String>,
36    pub license: Option<String>,
37    pub repository: Option<String>,
38}
39
40#[derive(Debug, Deserialize, Clone)]
41#[serde(rename_all = "kebab-case")]
42pub struct AppDescriptor {
43    // appdata
44    pub id: String,
45    pub name: Option<String>,
46    pub generic_name: Option<String>,
47    pub summary: String,
48    pub description: String,
49    pub categories: Vec<String>,
50    pub metadata_license: String,
51    pub screenshots: Option<Vec<Screenshot>>,
52    pub releases: Option<Vec<Release>>,
53    pub content_rating: Option<Vec<ContentRating>>,
54    pub requires: Vec<Recommend>,
55    pub recommends: Vec<Recommend>,
56    pub permissions: Vec<String>,
57    pub mimetype: Option<String>,
58
59    // flatpak manifest
60    pub flatpak_runtime_version: Option<String>,
61    pub flatpak_modules: Option<Vec<String>>,
62
63    // misc
64    pub resources: Option<String>,
65}
66
67#[derive(Debug, Deserialize, Clone)]
68pub struct Release {
69    pub version: String,
70    pub date: String,
71    pub description: String,
72}
73
74#[derive(Debug, Deserialize, Clone)]
75pub struct Screenshot {
76    #[serde(rename = "type")]
77    pub type_: Option<String>,
78    pub url: String,
79}
80
81#[derive(Debug, Deserialize, Clone)]
82#[serde(rename_all = "kebab-case")]
83pub struct ContentRating {
84    pub id: String,
85    pub value: String,
86}
87
88#[derive(Debug, Deserialize, Clone)]
89#[serde(rename_all = "kebab-case")]
90pub enum Recommend {
91    Display(String),
92    DisplayLength(String),
93    Control(String),
94}
95
96#[derive(Debug, Deserialize, Clone)]
97pub struct ActionDescriptor {
98    pub state: Option<String>,
99    #[serde(rename = "type")]
100    pub type_: Option<String>,
101    pub accelerators: Option<Vec<String>>,
102}
103
104pub fn parse_project_descriptor(
105    cargo_toml_path: &Path,
106    app_toml_path: &Path,
107) -> std::io::Result<ProjectDescriptor> {
108    let mut cargo_file = match File::open(cargo_toml_path) {
109        Ok(f) => f,
110        Err(e) => {
111            eprintln!("[gra] Could not read {:?}: {}", cargo_toml_path, e);
112            return Err(e);
113        }
114    };
115    let mut app_file = match File::open(app_toml_path) {
116        Ok(f) => f,
117        Err(e) => {
118            eprintln!("[gra] Could not read {:?}: {}", app_toml_path, e);
119            return Err(e);
120        }
121    };
122    let mut cargo_toml_content = String::new();
123    cargo_file.read_to_string(&mut cargo_toml_content)?;
124    let mut app_toml_content = String::new();
125    app_file.read_to_string(&mut app_toml_content)?;
126    match parse_project_descriptor_str(&cargo_toml_content, &app_toml_content) {
127        Err(e) => {
128            eprintln!("[gra] Error: {}.\n{}", e, cargo_toml_content);
129            Err(e)
130        }
131        Ok(p) => Ok(p),
132    }
133}
134
135pub fn parse_project_descriptor_str(
136    cargo_toml: &str,
137    app_toml: &str,
138) -> std::io::Result<ProjectDescriptor> {
139    let cargo_toml: CargoToml = toml::from_str(cargo_toml)
140        .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, format!("{}.", e)))?;
141    let app_toml: AppToml = toml::from_str(app_toml)
142        .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, format!("{}.", e)))?;
143    Ok(ProjectDescriptor {
144        package: cargo_toml.package,
145        app: app_toml.app,
146        settings: app_toml.settings,
147        actions: app_toml.actions,
148    })
149}