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