scratch_io/
itch_manifest.rs

1use crate::{errors::FilesystemError, filesystem, itch_api::types::*};
2use std::path::{Path, PathBuf};
3
4const MANIFEST_FILENAME: &str = ".itch.toml";
5const MANIFEST_PLAY_ACTION: &str = "play";
6
7impl ManifestAction {
8  pub async fn get_canonical_path(&self, folder: &Path) -> Result<PathBuf, FilesystemError> {
9    filesystem::get_canonical_path(&folder.join(&self.path)).await
10  }
11}
12
13/// Read the manifest from a folder and parse it (if any)
14pub async fn read_manifest(upload_folder: &Path) -> Result<Option<Manifest>, String> {
15  let manifest_path = upload_folder.join(MANIFEST_FILENAME);
16
17  if !filesystem::exists(&manifest_path).await? {
18    return Ok(None);
19  }
20
21  let manifest_text: String = tokio::fs::read_to_string(&manifest_path)
22    .await
23    .map_err(|e| e.to_string())?;
24
25  toml::from_str::<Manifest>(&manifest_text)
26    .map(Some)
27    .map_err(|e| {
28      format!(
29        "Couldn't parse itch manifest: {}\n{e}",
30        manifest_path.to_string_lossy()
31      )
32    })
33}
34
35/// Returns an itch.io [`ManifestAction`] given its name and the folder where the game manifest is located
36pub async fn launch_action(
37  upload_folder: &Path,
38  action_name: Option<&str>,
39) -> Result<Option<ManifestAction>, String> {
40  let Some(manifest) = read_manifest(upload_folder).await? else {
41    return Ok(None);
42  };
43
44  let action_name = action_name.unwrap_or(MANIFEST_PLAY_ACTION);
45
46  Ok(
47    manifest
48      .actions
49      .unwrap_or_default()
50      .into_iter()
51      .find(|a| a.name == action_name),
52  )
53}