Skip to main content

lux_lib/rockspec/
mod.rs

1use std::{
2    collections::HashMap,
3    fmt::Display,
4    ops::{Deref, DerefMut},
5    path::PathBuf,
6};
7
8use itertools::Itertools;
9use lua_dependency::LuaDependencySpec;
10use serde::{Deserialize, Serialize};
11pub mod lua_dependency;
12
13use crate::{
14    config::{Config, LuaVersion},
15    lua_rockspec::{
16        BuildSpec, DeploySpec, ExternalDependencySpec, LuaVersionError, PerPlatform,
17        PlatformSupport, RemoteRockSource, RockDescription, RockspecFormat, TestSpec,
18    },
19    package::{PackageName, PackageVersion, PackageVersionReq},
20};
21
22pub trait Rockspec {
23    type Error: Display + std::fmt::Debug;
24
25    fn package(&self) -> &PackageName;
26    fn version(&self) -> &PackageVersion;
27    fn description(&self) -> &RockDescription;
28    fn supported_platforms(&self) -> &PlatformSupport;
29    fn lua(&self) -> &PackageVersionReq;
30    fn dependencies(&self) -> &PerPlatform<Vec<LuaDependencySpec>>;
31    fn build_dependencies(&self) -> &PerPlatform<Vec<LuaDependencySpec>>;
32    fn external_dependencies(&self) -> &PerPlatform<HashMap<String, ExternalDependencySpec>>;
33    fn test_dependencies(&self) -> &PerPlatform<Vec<LuaDependencySpec>>;
34
35    fn build(&self) -> &PerPlatform<BuildSpec>;
36    fn test(&self) -> &PerPlatform<TestSpec>;
37    fn source(&self) -> &PerPlatform<RemoteRockSource>;
38    fn deploy(&self) -> &PerPlatform<DeploySpec>;
39
40    fn build_mut(&mut self) -> &mut PerPlatform<BuildSpec>;
41    fn test_mut(&mut self) -> &mut PerPlatform<TestSpec>;
42    fn source_mut(&mut self) -> &mut PerPlatform<RemoteRockSource>;
43    fn deploy_mut(&mut self) -> &mut PerPlatform<DeploySpec>;
44
45    fn format(&self) -> &Option<RockspecFormat>;
46
47    /// Shorthand to extract the binaries that are part of the rockspec.
48    fn binaries(&self) -> RockBinaries {
49        RockBinaries(
50            self.build()
51                .current_platform()
52                .install
53                .bin
54                .keys()
55                .map_into()
56                .collect(),
57        )
58    }
59
60    /// Converts the rockspec to a string that can be uploaded to a luarocks server.
61    fn to_lua_remote_rockspec_string(&self) -> Result<String, Self::Error>;
62}
63
64pub trait LuaVersionCompatibility {
65    /// Ensures that the rockspec is compatible with the specified lua version.
66    /// Returns an error if the rockspec is not compatible.
67    fn validate_lua_version(&self, lua_version: &LuaVersion) -> Result<(), LuaVersionError>;
68
69    /// Ensures that the rockspec is compatible with the lua version established in the config.
70    /// Returns an error if the rockspec is not compatible.
71    fn validate_lua_version_from_config(&self, config: &Config) -> Result<(), LuaVersionError>;
72
73    /// Ensures that the rockspec is compatible with the lua version established in the config,
74    /// and returns the lua version from the config if it is compatible.
75    fn lua_version_matches(&self, config: &Config) -> Result<LuaVersion, LuaVersionError>;
76
77    /// Checks if the rockspec supports the given lua version.
78    fn supports_lua_version(&self, lua_version: &LuaVersion) -> bool;
79
80    /// Returns the lua version required by the rockspec.
81    fn lua_version(&self) -> Option<LuaVersion>;
82}
83
84impl<T: Rockspec> LuaVersionCompatibility for T {
85    fn validate_lua_version(&self, version: &LuaVersion) -> Result<(), LuaVersionError> {
86        if self.supports_lua_version(version) {
87            Ok(())
88        } else {
89            Err(LuaVersionError::LuaVersionUnsupported(
90                version.clone(),
91                self.package().to_owned(),
92                self.version().to_owned(),
93            ))
94        }
95    }
96
97    fn validate_lua_version_from_config(&self, config: &Config) -> Result<(), LuaVersionError> {
98        let _ = self.lua_version_matches(config)?;
99        Ok(())
100    }
101
102    fn lua_version_matches(&self, config: &Config) -> Result<LuaVersion, LuaVersionError> {
103        let version = LuaVersion::from(config)?.clone();
104        if self.supports_lua_version(&version) {
105            Ok(version)
106        } else {
107            Err(LuaVersionError::LuaVersionUnsupported(
108                version,
109                self.package().to_owned(),
110                self.version().to_owned(),
111            ))
112        }
113    }
114
115    fn supports_lua_version(&self, lua_version: &LuaVersion) -> bool {
116        self.lua().matches(&lua_version.as_version())
117    }
118
119    fn lua_version(&self) -> Option<LuaVersion> {
120        for (possibility, version) in [
121            ("5.5.0", LuaVersion::Lua54),
122            ("5.4.0", LuaVersion::Lua54),
123            ("5.3.0", LuaVersion::Lua53),
124            ("5.2.0", LuaVersion::Lua52),
125            ("5.1.0", LuaVersion::Lua51),
126        ] {
127            let possibility = unsafe { possibility.parse().unwrap_unchecked() };
128            if self.lua().matches(&possibility) {
129                return Some(version);
130            }
131        }
132        None
133    }
134}
135
136#[derive(Debug, Default, Serialize, Deserialize, Clone, PartialOrd, Ord, Hash, PartialEq, Eq)]
137pub struct RockBinaries(Vec<PathBuf>);
138
139impl Deref for RockBinaries {
140    type Target = Vec<PathBuf>;
141
142    fn deref(&self) -> &Self::Target {
143        &self.0
144    }
145}
146
147impl DerefMut for RockBinaries {
148    fn deref_mut(&mut self) -> &mut Self::Target {
149        &mut self.0
150    }
151}