packrinth/
lib.rs

1#![warn(clippy::pedantic)]
2#![allow(clippy::missing_errors_doc, clippy::missing_panics_doc)]
3
4pub mod config;
5pub mod modrinth;
6
7use crate::config::Modpack;
8
9/// Checks if the modpack is dirty by checking whether the directory of the modpack
10/// has uncommitted changes. If any errors occur (for example, if no Git repository exists),
11/// `false` will be returned.
12#[must_use]
13pub fn modpack_is_dirty(modpack: &Modpack) -> bool {
14    let git_repo = match gix::open(&modpack.directory) {
15        Ok(git_repo) => git_repo,
16        Err(_error) => return false,
17    };
18
19    git_repo.is_dirty().unwrap_or(false)
20}
21
22/// An error that can occur while performing Packrinth operations.
23#[derive(Debug)]
24pub enum PackrinthError {
25    PathIsFile {
26        path: String,
27    },
28    FailedToCreateDir {
29        dir_to_create: String,
30        error_message: String,
31    },
32    FailedToReadToString {
33        path_to_read: String,
34        error_message: String,
35    },
36    FailedToParseConfigJson {
37        config_path: String,
38        error_message: String,
39    },
40    FailedToParseModrinthResponseJson {
41        modrinth_endpoint: String,
42        error_message: String,
43    },
44    FailedToSerialize {
45        error_message: String,
46    },
47    ProjectIsNotAdded {
48        project: String,
49    },
50    OverrideDoesNotExist {
51        project: String,
52        branch: String,
53    },
54    NoOverridesForProject {
55        project: String,
56    },
57    NoExclusionsForProject {
58        project: String,
59    },
60    NoInclusionsForProject {
61        project: String,
62    },
63    ProjectAlreadyHasExclusions {
64        project: String,
65    },
66    ProjectAlreadyHasInclusions {
67        project: String,
68    },
69    FailedToWriteFile {
70        path_to_write_to: String,
71        error_message: String,
72    },
73    FailedToInitializeFileType {
74        file_to_create: String,
75        error_message: String,
76    },
77    DirectoryExpected {
78        path_that_should_have_been_dir: String,
79    },
80    FailedToStartZipFile {
81        file_to_start: String,
82        error_message: String,
83    },
84    FailedToWriteToZip {
85        to_write: String,
86        error_message: String,
87    },
88    FailedToGetWalkDirEntry {
89        error_message: String,
90    },
91    FailedToStripPath {
92        path: String,
93    },
94    FailedToCopyIntoBuffer,
95    FailedToAddZipDir {
96        zip_dir_path: String,
97    },
98    FailedToFinishZip,
99    BranchDoesNotExist {
100        branch: String,
101        error_message: String,
102    },
103    AttemptedToAddOtherModpack,
104    NoModrinthFilesFoundForProject {
105        project: String,
106    },
107    RequestFailed {
108        url: String,
109        error_message: String,
110    },
111    FailedToGetCurrentDirectory {
112        error_message: String,
113    },
114    InvalidPackFormat {
115        used_pack_format: u16,
116    },
117    NoBranchSpecified,
118    NoInclusionsSpecified,
119    NoExclusionsSpecified,
120    RepoIsDirtyWhileUpdating,
121    FailedToInitGitRepoWhileInitModpack {
122        error_message: String,
123    },
124    ModpackAlreadyExists {
125        directory: String,
126    },
127    MainModLoaderProvidedButNoVersion,
128}
129
130impl PackrinthError {
131    /// Returns a message and tip for a [`PackrinthError`], in the form of (message, tip).
132    /// It uses the relevant data in the enum value.
133    #[must_use]
134    pub fn message_and_tip(&self) -> (String, String) {
135        let file_an_issue: String =
136            "file an issue at https://github.com/Thijzert123/packrinth/issues".to_string();
137        match self {
138            PackrinthError::PathIsFile { path } => (format!("path {path} is a file"), "remove the file or change the target directory".to_string()),
139            PackrinthError::FailedToCreateDir{ dir_to_create, error_message } => (format!("failed to create directory {dir_to_create}: {error_message}"), "check if you have sufficient permissions and if the path already exists".to_string()),
140            PackrinthError::FailedToReadToString { path_to_read, error_message } => (format!("failed to read file {path_to_read}: {error_message}"), "check if you have sufficient permissions and if the file exists".to_string()),
141            PackrinthError::FailedToParseConfigJson { config_path, error_message } => (format!("config file {config_path} is invalid: {error_message}"), "fix it according to JSON standards".to_string()),
142            PackrinthError::FailedToParseModrinthResponseJson { modrinth_endpoint, error_message } => (format!("modrinth response from endpoint {modrinth_endpoint} is invalid: {error_message}"), file_an_issue),
143            PackrinthError::FailedToSerialize{ error_message } => (format!("failed to serialize to a JSON: {error_message}"), file_an_issue),
144            PackrinthError::ProjectIsNotAdded { project } => (format!("project {project} is not added to this modpack"), "add it with subcommand: project add".to_string()),
145            PackrinthError::OverrideDoesNotExist { project, branch } => (format!("{project} does not have an override for branch {branch}"), "add one with subcommand: project override add".to_string()),
146            PackrinthError::NoOverridesForProject { project } => (format!("project {project} doesn't have any overrides"), "add one with subcommand: project override add".to_string()),
147            PackrinthError::NoExclusionsForProject { project } => (format!("project {project} doesn't have any exclusions"), "add exclusions with subcommand: project exclude add".to_string()),
148            PackrinthError::NoInclusionsForProject { project } => (format!("project {project} doesn't have any inclusions"), "add inclusions with subcommand: project include add".to_string()),
149            PackrinthError::ProjectAlreadyHasExclusions { project } => (format!("project {project} already has exclusions"), "you can't have both inclusions and exclusions for one project".to_string()),
150            PackrinthError::ProjectAlreadyHasInclusions { project } => (format!("project {project} already has inclusions"), "you can't have both inclusions and exclusions for one project".to_string()),
151            PackrinthError::FailedToWriteFile { path_to_write_to, error_message } => (format!("failed to write to file {path_to_write_to}: {error_message}"), "check if you have sufficient permissions and if the file exists".to_string()),
152            PackrinthError::FailedToInitializeFileType { file_to_create, error_message } => (format!("failed to create file {file_to_create}: {error_message}"), "check if you have sufficient permissions and if the path already exists".to_string()),
153            PackrinthError::DirectoryExpected { path_that_should_have_been_dir } => (format!("expected a directory at {path_that_should_have_been_dir}"), "remove the path if possible".to_string()),
154            PackrinthError::FailedToStartZipFile { file_to_start, error_message } => (format!("failed to start zip file at {file_to_start}: {error_message}"), file_an_issue),
155            PackrinthError::FailedToWriteToZip { to_write, error_message } => (format!("failed to write {to_write} to zip: {error_message}"), file_an_issue),
156            PackrinthError::FailedToGetWalkDirEntry { error_message } => (format!("failed to get entry from WalkDir: {error_message}"), file_an_issue),
157            PackrinthError::FailedToStripPath { path } => (format!("failed to strip path {path}"), file_an_issue),
158            PackrinthError::FailedToCopyIntoBuffer => ("failed to copy data into buffer for zip".to_string(), file_an_issue),
159            PackrinthError::FailedToAddZipDir { zip_dir_path } => (format!("failed to add zip directory {zip_dir_path}"), file_an_issue),
160            PackrinthError::FailedToFinishZip => ("failed to finish zip".to_string(), file_an_issue),
161            PackrinthError::BranchDoesNotExist { branch, error_message } => (format!("branch {branch} doesn't exist: {error_message}"), "add a branch with subcommand: branch add".to_string()),
162            PackrinthError::AttemptedToAddOtherModpack => ("one of the projects is another modpack".to_string(), "remove the modpack project with subcommand: project remove <MODPACK_PROJECT>".to_string()),
163            PackrinthError::NoModrinthFilesFoundForProject { project } => (format!("no files found for project {project}"), "check if the project id is spelled correctly or try to remove or add project inclusions, exclusions or overrides".to_string()),
164            PackrinthError::RequestFailed { url, error_message } => (format!("request to {url} failed: {error_message}"), format!("check your internet connection or {file_an_issue}")),
165            PackrinthError::FailedToGetCurrentDirectory { error_message } => (format!("couldn't get the current directory: {error_message}"), "the current directory may not exist or you have insufficient permissions to access the current directory".to_string()),
166            PackrinthError::InvalidPackFormat { used_pack_format } => (format!("pack format {used_pack_format} is not supported by this Packrinth version"), format!("please use a configuration with pack format {}", config::CURRENT_PACK_FORMAT)),
167            PackrinthError::NoBranchSpecified => ("no branch specified".to_string(), "specify a branch or remove all with the --all flag".to_string()),
168            PackrinthError::NoInclusionsSpecified => ("no inclusions specified".to_string(), "specify inclusions or remove all with the --all flag".to_string()),
169            PackrinthError::NoExclusionsSpecified => ("no exclusions specified".to_string(), "specify exclusions or remove all with the --all flag".to_string()),
170            PackrinthError::RepoIsDirtyWhileUpdating => ("git repository has uncommitted changes".to_string(), "pass the --allow-dirty flag to force updating".to_string()),
171            PackrinthError::FailedToInitGitRepoWhileInitModpack { error_message } => (format!("failed to initialize Git repository: {error_message}"), "the modpack itself was initialized successfully, so you can try to initialize a Git repository yourself".to_string()),
172            PackrinthError::ModpackAlreadyExists { directory } => (format!("a modpack instance already exists in {directory}"), "to force initializing a new repository, pass the --force flag".to_string()),
173            PackrinthError::MainModLoaderProvidedButNoVersion => ("a main mod loader was specified for a branch, but no version was provided".to_string(), "add the loader_version to branch.json".to_string()),
174        }
175    }
176}