1mod build;
2mod dependency;
3mod deploy;
4mod partial;
5mod platform;
6mod rock_source;
7mod serde_util;
8mod test_spec;
9
10use std::{
11 collections::HashMap, convert::Infallible, fmt::Display, io, path::PathBuf, str::FromStr,
12};
13
14use mlua::{FromLua, IntoLua, Lua, LuaSerdeExt, UserData, Value};
15use serde::{de::DeserializeOwned, Deserialize, Serialize};
16
17pub use build::*;
18pub use dependency::*;
19pub use deploy::*;
20pub use partial::*;
21pub use platform::*;
22pub use rock_source::*;
23pub use serde_util::*;
24use ssri::Integrity;
25pub use test_spec::*;
26use thiserror::Error;
27use url::Url;
28
29use crate::{
30 config::{LuaVersion, LuaVersionUnset},
31 hash::HasIntegrity,
32 package::{PackageName, PackageSpec, PackageVersion, PackageVersionReq},
33 project::project_toml::ProjectTomlError,
34 project::ProjectRoot,
35 rockspec::{lua_dependency::LuaDependencySpec, Rockspec},
36};
37
38#[derive(Error, Debug)]
39pub enum LuaRockspecError {
40 #[error("could not parse rockspec: {0}")]
41 MLua(#[from] mlua::Error),
42 #[error("{}copy_directories cannot contain the rockspec name", ._0.as_ref().map(|p| format!("{p}: ")).unwrap_or_default())]
43 CopyDirectoriesContainRockspecName(Option<String>),
44 #[error("could not parse rockspec: {0}")]
45 LuaTable(#[from] LuaTableError),
46 #[error("cannot create Lua rockspec with off-spec dependency: {0}")]
47 OffSpecDependency(PackageName),
48 #[error("cannot create Lua rockspec with off-spec build dependency: {0}")]
49 OffSpecBuildDependency(PackageName),
50 #[error("cannot create Lua rockspec with off-spec test dependency: {0}")]
51 OffSpecTestDependency(PackageName),
52 #[error(transparent)]
53 ProjectToml(#[from] ProjectTomlError),
54}
55
56#[derive(Clone, Debug)]
57#[cfg_attr(test, derive(PartialEq))]
58pub struct LocalLuaRockspec {
59 rockspec_format: Option<RockspecFormat>,
61 package: PackageName,
63 version: PackageVersion,
65 description: RockDescription,
66 supported_platforms: PlatformSupport,
67 lua: PackageVersionReq,
69 dependencies: PerPlatform<Vec<LuaDependencySpec>>,
70 build_dependencies: PerPlatform<Vec<LuaDependencySpec>>,
71 external_dependencies: PerPlatform<HashMap<String, ExternalDependencySpec>>,
72 test_dependencies: PerPlatform<Vec<LuaDependencySpec>>,
73 build: PerPlatform<BuildSpec>,
74 source: PerPlatform<RemoteRockSource>,
75 test: PerPlatform<TestSpec>,
76 deploy: PerPlatform<DeploySpec>,
77 raw_content: String,
79}
80
81impl UserData for LocalLuaRockspec {
82 fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
83 methods.add_method("package", |_, this, _: ()| Ok(this.package.clone()));
84 methods.add_method("version", |_, this, _: ()| Ok(this.version.clone()));
85 methods.add_method("description", |_, this, _: ()| Ok(this.description.clone()));
86 methods.add_method("supported_platforms", |_, this, _: ()| {
87 Ok(this.supported_platforms.clone())
88 });
89 methods.add_method("lua", |_, this, _: ()| Ok(this.lua.clone()));
90 methods.add_method("dependencies", |_, this, _: ()| {
91 Ok(this.dependencies.clone())
92 });
93 methods.add_method("build_dependencies", |_, this, _: ()| {
94 Ok(this.build_dependencies.clone())
95 });
96 methods.add_method("external_dependencies", |_, this, _: ()| {
97 Ok(this.external_dependencies.clone())
98 });
99 methods.add_method("test_dependencies", |_, this, _: ()| {
100 Ok(this.test_dependencies.clone())
101 });
102 methods.add_method("build", |_, this, _: ()| Ok(this.build.clone()));
103 methods.add_method("source", |_, this, _: ()| Ok(this.source.clone()));
104 methods.add_method("test", |_, this, _: ()| Ok(this.test.clone()));
105 methods.add_method("format", |_, this, _: ()| Ok(this.rockspec_format.clone()));
106
107 methods.add_method("to_lua_rockspec_string", |_, this, _: ()| {
108 this.to_lua_remote_rockspec_string()
109 .map_err(|err| mlua::Error::RuntimeError(err.to_string()))
110 });
111 }
112}
113
114impl LocalLuaRockspec {
115 pub fn new(
116 rockspec_content: &str,
117 project_root: ProjectRoot,
118 ) -> Result<Self, LuaRockspecError> {
119 let lua = Lua::new();
120 lua.load(rockspec_content).exec()?;
121
122 let globals = lua.globals();
123
124 let dependencies: PerPlatform<Vec<LuaDependencySpec>> = globals.get("dependencies")?;
125
126 let lua_version_req = dependencies
127 .current_platform()
128 .iter()
129 .find(|dep| dep.name().to_string() == "lua")
130 .cloned()
131 .map(|dep| dep.version_req().clone())
132 .unwrap_or(PackageVersionReq::Any);
133
134 fn strip_lua(
135 dependencies: PerPlatform<Vec<LuaDependencySpec>>,
136 ) -> PerPlatform<Vec<LuaDependencySpec>> {
137 dependencies.map(|deps| {
138 deps.iter()
139 .filter(|dep| dep.name().to_string() != "lua")
140 .cloned()
141 .collect()
142 })
143 }
144
145 let build_dependencies: PerPlatform<Vec<LuaDependencySpec>> =
146 globals.get("build_dependencies")?;
147
148 let test_dependencies: PerPlatform<Vec<LuaDependencySpec>> =
149 globals.get("test_dependencies")?;
150
151 let rockspec = LocalLuaRockspec {
152 rockspec_format: globals.get("rockspec_format")?,
153 package: globals.get("package")?,
154 version: globals.get("version")?,
155 description: parse_lua_tbl_or_default(&lua, "description")?,
156 supported_platforms: parse_lua_tbl_or_default(&lua, "supported_platforms")?,
157 lua: lua_version_req,
158 dependencies: strip_lua(dependencies),
159 build_dependencies: strip_lua(build_dependencies),
160 test_dependencies: strip_lua(test_dependencies),
161 external_dependencies: globals.get("external_dependencies")?,
162 build: globals.get("build")?,
163 test: globals.get("test")?,
164 deploy: globals.get("deploy")?,
165 raw_content: rockspec_content.into(),
166
167 source: globals
168 .get::<Option<PerPlatform<RemoteRockSource>>>("source")?
169 .unwrap_or_else(|| {
170 PerPlatform::new(RockSourceSpec::File(project_root.to_path_buf()).into())
171 }),
172 };
173
174 let rockspec_file_name = format!("{}-{}.rockspec", rockspec.package(), rockspec.version());
175 if rockspec
176 .build()
177 .default
178 .copy_directories
179 .contains(&PathBuf::from(&rockspec_file_name))
180 {
181 return Err(LuaRockspecError::CopyDirectoriesContainRockspecName(None));
182 }
183
184 for (platform, build_override) in &rockspec.build().per_platform {
185 if build_override
186 .copy_directories
187 .contains(&PathBuf::from(&rockspec_file_name))
188 {
189 return Err(LuaRockspecError::CopyDirectoriesContainRockspecName(Some(
190 platform.to_string(),
191 )));
192 }
193 }
194 Ok(rockspec)
195 }
196}
197
198impl Rockspec for LocalLuaRockspec {
199 type Error = Infallible;
200
201 fn package(&self) -> &PackageName {
202 &self.package
203 }
204
205 fn version(&self) -> &PackageVersion {
206 &self.version
207 }
208
209 fn description(&self) -> &RockDescription {
210 &self.description
211 }
212
213 fn supported_platforms(&self) -> &PlatformSupport {
214 &self.supported_platforms
215 }
216
217 fn lua(&self) -> &PackageVersionReq {
218 &self.lua
219 }
220
221 fn dependencies(&self) -> &PerPlatform<Vec<LuaDependencySpec>> {
222 &self.dependencies
223 }
224
225 fn build_dependencies(&self) -> &PerPlatform<Vec<LuaDependencySpec>> {
226 &self.build_dependencies
227 }
228
229 fn external_dependencies(&self) -> &PerPlatform<HashMap<String, ExternalDependencySpec>> {
230 &self.external_dependencies
231 }
232
233 fn test_dependencies(&self) -> &PerPlatform<Vec<LuaDependencySpec>> {
234 &self.test_dependencies
235 }
236
237 fn build(&self) -> &PerPlatform<BuildSpec> {
238 &self.build
239 }
240
241 fn test(&self) -> &PerPlatform<TestSpec> {
242 &self.test
243 }
244
245 fn source(&self) -> &PerPlatform<RemoteRockSource> {
246 &self.source
247 }
248
249 fn deploy(&self) -> &PerPlatform<DeploySpec> {
250 &self.deploy
251 }
252
253 fn build_mut(&mut self) -> &mut PerPlatform<BuildSpec> {
254 &mut self.build
255 }
256
257 fn test_mut(&mut self) -> &mut PerPlatform<TestSpec> {
258 &mut self.test
259 }
260
261 fn source_mut(&mut self) -> &mut PerPlatform<RemoteRockSource> {
262 &mut self.source
263 }
264
265 fn deploy_mut(&mut self) -> &mut PerPlatform<DeploySpec> {
266 &mut self.deploy
267 }
268
269 fn format(&self) -> &Option<RockspecFormat> {
270 &self.rockspec_format
271 }
272
273 fn to_lua_remote_rockspec_string(&self) -> Result<String, Self::Error> {
274 Ok(self.raw_content.clone())
275 }
276}
277
278impl HasIntegrity for LocalLuaRockspec {
279 fn hash(&self) -> io::Result<Integrity> {
280 Ok(Integrity::from(&self.raw_content))
281 }
282}
283
284#[derive(Clone, Debug)]
285#[cfg_attr(test, derive(PartialEq))]
286pub struct RemoteLuaRockspec {
287 local: LocalLuaRockspec,
288 source: PerPlatform<RemoteRockSource>,
289}
290
291impl UserData for RemoteLuaRockspec {
292 fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
293 methods.add_method("package", |_, this, _: ()| Ok(this.local.package.clone()));
294 methods.add_method("version", |_, this, _: ()| Ok(this.local.version.clone()));
295 methods.add_method("description", |_, this, _: ()| {
296 Ok(this.local.description.clone())
297 });
298 methods.add_method("supported_platforms", |_, this, _: ()| {
299 Ok(this.local.supported_platforms.clone())
300 });
301 methods.add_method("lua", |_, this, _: ()| Ok(this.local.lua.clone()));
302 methods.add_method("dependencies", |_, this, _: ()| {
303 Ok(this.local.dependencies.clone())
304 });
305 methods.add_method("build_dependencies", |_, this, _: ()| {
306 Ok(this.local.build_dependencies.clone())
307 });
308 methods.add_method("external_dependencies", |_, this, _: ()| {
309 Ok(this.local.external_dependencies.clone())
310 });
311 methods.add_method("test_dependencies", |_, this, _: ()| {
312 Ok(this.local.test_dependencies.clone())
313 });
314 methods.add_method("build", |_, this, _: ()| Ok(this.local.build.clone()));
315 methods.add_method("source", |_, this, _: ()| Ok(this.source.clone()));
316 methods.add_method("test", |_, this, _: ()| Ok(this.local.test.clone()));
317 methods.add_method("format", |_, this, _: ()| {
318 Ok(this.local.rockspec_format.clone())
319 });
320
321 methods.add_method("to_lua_rockspec_string", |_, this, _: ()| {
322 this.to_lua_remote_rockspec_string()
323 .map_err(|err| mlua::Error::RuntimeError(err.to_string()))
324 });
325 }
326}
327
328impl RemoteLuaRockspec {
329 pub fn new(rockspec_content: &str) -> Result<Self, LuaRockspecError> {
330 let lua = Lua::new();
331 lua.load(rockspec_content).exec()?;
332
333 let globals = lua.globals();
334 let source = globals.get("source")?;
335
336 let rockspec = RemoteLuaRockspec {
337 local: LocalLuaRockspec::new(rockspec_content, ProjectRoot::new())?,
338 source,
339 };
340
341 Ok(rockspec)
342 }
343
344 pub fn from_package_and_source_spec(
345 package_spec: PackageSpec,
346 source_spec: RockSourceSpec,
347 ) -> Self {
348 let version = package_spec.version().clone();
349 let rockspec_format: RockspecFormat = "3.0".into();
350 let raw_content = format!(
351 r#"
352rockspec_format = "{}"
353package = "{}"
354version = "{}"
355{}
356build = {{
357 type = "source"
358}}"#,
359 &rockspec_format,
360 package_spec.name(),
361 &version,
362 &source_spec.display_lua(),
363 );
364
365 let source: RemoteRockSource = source_spec.into();
366
367 let local = LocalLuaRockspec {
368 rockspec_format: Some(rockspec_format),
369 package: package_spec.name().clone(),
370 version,
371 description: RockDescription::default(),
372 supported_platforms: PlatformSupport::default(),
373 lua: PackageVersionReq::Any,
374 dependencies: PerPlatform::default(),
375 build_dependencies: PerPlatform::default(),
376 external_dependencies: PerPlatform::default(),
377 test_dependencies: PerPlatform::default(),
378 build: PerPlatform::new(BuildSpec {
379 build_backend: Some(BuildBackendSpec::Source),
380 install: InstallSpec::default(),
381 copy_directories: Vec::new(),
382 patches: HashMap::new(),
383 }),
384 source: PerPlatform::new(source.clone()),
385 test: PerPlatform::default(),
386 deploy: PerPlatform::default(),
387 raw_content,
388 };
389 Self {
390 local,
391 source: PerPlatform::new(source),
392 }
393 }
394}
395
396impl Rockspec for RemoteLuaRockspec {
397 type Error = Infallible;
398
399 fn package(&self) -> &PackageName {
400 self.local.package()
401 }
402
403 fn version(&self) -> &PackageVersion {
404 self.local.version()
405 }
406
407 fn description(&self) -> &RockDescription {
408 self.local.description()
409 }
410
411 fn supported_platforms(&self) -> &PlatformSupport {
412 self.local.supported_platforms()
413 }
414
415 fn lua(&self) -> &PackageVersionReq {
416 self.local.lua()
417 }
418
419 fn dependencies(&self) -> &PerPlatform<Vec<LuaDependencySpec>> {
420 self.local.dependencies()
421 }
422
423 fn build_dependencies(&self) -> &PerPlatform<Vec<LuaDependencySpec>> {
424 match self.format() {
425 Some(RockspecFormat::_1_0 | RockspecFormat::_2_0)
428 if self
429 .build()
430 .current_platform()
431 .build_backend
432 .as_ref()
433 .is_some_and(|build_backend| build_backend.can_use_build_dependencies()) =>
434 {
435 self.local.dependencies()
436 }
437 _ => self.local.build_dependencies(),
438 }
439 }
440
441 fn external_dependencies(&self) -> &PerPlatform<HashMap<String, ExternalDependencySpec>> {
442 self.local.external_dependencies()
443 }
444
445 fn test_dependencies(&self) -> &PerPlatform<Vec<LuaDependencySpec>> {
446 self.local.test_dependencies()
447 }
448
449 fn build(&self) -> &PerPlatform<BuildSpec> {
450 self.local.build()
451 }
452
453 fn test(&self) -> &PerPlatform<TestSpec> {
454 self.local.test()
455 }
456
457 fn source(&self) -> &PerPlatform<RemoteRockSource> {
458 &self.source
459 }
460
461 fn deploy(&self) -> &PerPlatform<DeploySpec> {
462 self.local.deploy()
463 }
464
465 fn build_mut(&mut self) -> &mut PerPlatform<BuildSpec> {
466 self.local.build_mut()
467 }
468
469 fn test_mut(&mut self) -> &mut PerPlatform<TestSpec> {
470 self.local.test_mut()
471 }
472
473 fn source_mut(&mut self) -> &mut PerPlatform<RemoteRockSource> {
474 &mut self.source
475 }
476
477 fn deploy_mut(&mut self) -> &mut PerPlatform<DeploySpec> {
478 self.local.deploy_mut()
479 }
480
481 fn format(&self) -> &Option<RockspecFormat> {
482 self.local.format()
483 }
484
485 fn to_lua_remote_rockspec_string(&self) -> Result<String, Self::Error> {
486 Ok(self.local.raw_content.clone())
487 }
488}
489
490#[derive(Error, Debug)]
491pub enum LuaVersionError {
492 #[error("The lua version {0} is not supported by {1} version {1}!")]
493 LuaVersionUnsupported(LuaVersion, PackageName, PackageVersion),
494 #[error(transparent)]
495 LuaVersionUnset(#[from] LuaVersionUnset),
496}
497
498impl HasIntegrity for RemoteLuaRockspec {
499 fn hash(&self) -> io::Result<Integrity> {
500 Ok(Integrity::from(&self.local.raw_content))
501 }
502}
503
504#[derive(Clone, Deserialize, Debug, PartialEq, Default)]
505pub struct RockDescription {
506 pub summary: Option<String>,
508 pub detailed: Option<String>,
510 pub license: Option<String>,
512 #[serde(default, deserialize_with = "deserialize_url")]
514 pub homepage: Option<Url>,
515 pub issues_url: Option<String>,
517 pub maintainer: Option<String>,
519 #[serde(default)]
521 pub labels: Vec<String>,
522}
523
524fn deserialize_url<'de, D>(deserializer: D) -> Result<Option<Url>, D::Error>
525where
526 D: serde::Deserializer<'de>,
527{
528 let s = Option::<String>::deserialize(deserializer)?;
529 s.map(|s| Url::parse(&s).map_err(serde::de::Error::custom))
530 .transpose()
531}
532
533impl DisplayAsLuaKV for RockDescription {
534 fn display_lua(&self) -> DisplayLuaKV {
535 let mut description = Vec::new();
536
537 if let Some(summary) = &self.summary {
538 description.push(DisplayLuaKV {
539 key: "summary".to_string(),
540 value: DisplayLuaValue::String(summary.clone()),
541 })
542 }
543 if let Some(detailed) = &self.detailed {
544 description.push(DisplayLuaKV {
545 key: "detailed".to_string(),
546 value: DisplayLuaValue::String(detailed.clone()),
547 })
548 }
549 if let Some(license) = &self.license {
550 description.push(DisplayLuaKV {
551 key: "license".to_string(),
552 value: DisplayLuaValue::String(license.clone()),
553 })
554 }
555 if let Some(homepage) = &self.homepage {
556 description.push(DisplayLuaKV {
557 key: "homepage".to_string(),
558 value: DisplayLuaValue::String(homepage.to_string()),
559 })
560 }
561 if let Some(issues_url) = &self.issues_url {
562 description.push(DisplayLuaKV {
563 key: "issues_url".to_string(),
564 value: DisplayLuaValue::String(issues_url.clone()),
565 })
566 }
567 if let Some(maintainer) = &self.maintainer {
568 description.push(DisplayLuaKV {
569 key: "maintainer".to_string(),
570 value: DisplayLuaValue::String(maintainer.clone()),
571 })
572 }
573 if !self.labels.is_empty() {
574 description.push(DisplayLuaKV {
575 key: "labels".to_string(),
576 value: DisplayLuaValue::List(
577 self.labels
578 .iter()
579 .cloned()
580 .map(DisplayLuaValue::String)
581 .collect(),
582 ),
583 })
584 }
585
586 DisplayLuaKV {
587 key: "description".to_string(),
588 value: DisplayLuaValue::Table(description),
589 }
590 }
591}
592
593impl UserData for RockDescription {
594 fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
595 methods.add_method("summary", |_, this, _: ()| Ok(this.summary.clone()));
596 methods.add_method("detailed", |_, this, _: ()| Ok(this.detailed.clone()));
597 methods.add_method("license", |_, this, _: ()| Ok(this.license.clone()));
598 methods.add_method("homepage", |_, this, _: ()| {
599 Ok(this.homepage.clone().map(|url| url.to_string()))
600 });
601 methods.add_method("issues_url", |_, this, _: ()| Ok(this.issues_url.clone()));
602 methods.add_method("maintainer", |_, this, _: ()| Ok(this.maintainer.clone()));
603 methods.add_method("labels", |_, this, _: ()| Ok(this.labels.clone()));
604 }
605}
606
607#[derive(Error, Debug)]
608#[error("invalid rockspec format: {0}")]
609pub struct InvalidRockspecFormat(String);
610
611#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
612pub enum RockspecFormat {
613 #[serde(rename = "1.0")]
614 _1_0,
615 #[serde(rename = "2.0")]
616 _2_0,
617 #[serde(rename = "3.0")]
618 _3_0,
619}
620
621impl FromStr for RockspecFormat {
622 type Err = InvalidRockspecFormat;
623
624 fn from_str(s: &str) -> Result<Self, Self::Err> {
625 match s {
626 "1.0" => Ok(Self::_1_0),
627 "2.0" => Ok(Self::_2_0),
628 "3.0" => Ok(Self::_3_0),
629 txt => Err(InvalidRockspecFormat(txt.to_string())),
630 }
631 }
632}
633
634impl From<&str> for RockspecFormat {
635 fn from(s: &str) -> Self {
636 Self::from_str(s).unwrap()
637 }
638}
639
640impl FromLua for RockspecFormat {
641 fn from_lua(
642 value: mlua::prelude::LuaValue,
643 lua: &mlua::prelude::Lua,
644 ) -> mlua::prelude::LuaResult<Self> {
645 let s = String::from_lua(value, lua)?;
646 Self::from_str(&s).map_err(|err| mlua::Error::DeserializeError(err.to_string()))
647 }
648}
649
650impl IntoLua for RockspecFormat {
651 fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {
652 self.to_string().into_lua(lua)
653 }
654}
655
656impl Display for RockspecFormat {
657 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
658 match self {
659 Self::_1_0 => write!(f, "1.0"),
660 Self::_2_0 => write!(f, "2.0"),
661 Self::_3_0 => write!(f, "3.0"),
662 }
663 }
664}
665
666#[derive(Error, Debug)]
667pub enum LuaTableError {
668 #[error("could not parse {variable}. Expected list, but got {invalid_type}")]
669 ParseError {
670 variable: String,
671 invalid_type: String,
672 },
673 #[error(transparent)]
674 MLua(#[from] mlua::Error),
675}
676
677fn parse_lua_tbl_or_default<T>(lua: &Lua, lua_var_name: &str) -> Result<T, LuaTableError>
678where
679 T: Default,
680 T: DeserializeOwned,
681{
682 let ret = match lua.globals().get(lua_var_name)? {
683 Value::Nil => T::default(),
684 value @ Value::Table(_) => lua.from_value(value)?,
685 value => Err(LuaTableError::ParseError {
686 variable: lua_var_name.to_string(),
687 invalid_type: value.type_name().to_string(),
688 })?,
689 };
690 Ok(ret)
691}
692
693#[cfg(test)]
694mod tests {
695
696 use std::path::PathBuf;
697
698 use crate::git::GitSource;
699 use crate::lua_rockspec::PlatformIdentifier;
700 use crate::package::PackageSpec;
701
702 use super::*;
703
704 #[tokio::test]
705 pub async fn parse_rockspec() {
706 let rockspec_content = "
707 rockspec_format = '1.0'\n
708 package = 'foo'\n
709 version = '1.0.0-1'\n
710 source = {\n
711 url = 'https://github.com/nvim-neorocks/rocks.nvim/archive/1.0.0/rocks.nvim.zip',\n
712 }\n
713 "
714 .to_string();
715 let rockspec = RemoteLuaRockspec::new(&rockspec_content).unwrap();
716 assert_eq!(rockspec.local.rockspec_format, Some("1.0".into()));
717 assert_eq!(rockspec.local.package, "foo".into());
718 assert_eq!(rockspec.local.version, "1.0.0-1".parse().unwrap());
719 assert_eq!(rockspec.local.description, RockDescription::default());
720
721 let rockspec_content = "
722 package = 'bar'\n
723 version = '2.0.0-1'\n
724 description = {}\n
725 source = {\n
726 url = 'https://github.com/nvim-neorocks/rocks.nvim/archive/1.0.0/rocks.nvim.zip',\n
727 }\n
728 "
729 .to_string();
730 let rockspec = RemoteLuaRockspec::new(&rockspec_content).unwrap();
731 assert_eq!(rockspec.local.rockspec_format, None);
732 assert_eq!(rockspec.local.package, "bar".into());
733 assert_eq!(rockspec.local.version, "2.0.0-1".parse().unwrap());
734 assert_eq!(rockspec.local.description, RockDescription::default());
735
736 let rockspec_content = "
737 package = 'rocks.nvim'\n
738 version = '3.0.0-1'\n
739 description = {\n
740 summary = 'some summary',
741 detailed = 'some detailed description',
742 license = 'MIT',
743 homepage = 'https://github.com/nvim-neorocks/rocks.nvim',
744 issues_url = 'https://github.com/nvim-neorocks/rocks.nvim/issues',
745 maintainer = 'neorocks',
746 }\n
747 source = {\n
748 url = 'https://github.com/nvim-neorocks/rocks.nvim/archive/1.0.0/rocks.nvim.zip',\n
749 }\n
750 "
751 .to_string();
752 let rockspec = RemoteLuaRockspec::new(&rockspec_content).unwrap();
753 assert_eq!(rockspec.local.rockspec_format, None);
754 assert_eq!(rockspec.local.package, "rocks.nvim".into());
755 assert_eq!(rockspec.local.version, "3.0.0-1".parse().unwrap());
756 let expected_description = RockDescription {
757 summary: Some("some summary".into()),
758 detailed: Some("some detailed description".into()),
759 license: Some("MIT".into()),
760 homepage: Some(Url::parse("https://github.com/nvim-neorocks/rocks.nvim").unwrap()),
761 issues_url: Some("https://github.com/nvim-neorocks/rocks.nvim/issues".into()),
762 maintainer: Some("neorocks".into()),
763 labels: Vec::new(),
764 };
765 assert_eq!(rockspec.local.description, expected_description);
766
767 let rockspec_content = "
768 package = 'rocks.nvim'\n
769 version = '3.0.0-1'\n
770 description = {\n
771 summary = 'some summary',
772 detailed = 'some detailed description',
773 license = 'MIT',
774 homepage = 'https://github.com/nvim-neorocks/rocks.nvim',
775 issues_url = 'https://github.com/nvim-neorocks/rocks.nvim/issues',
776 maintainer = 'neorocks',
777 labels = {},
778 }\n
779 external_dependencies = { FOO = { library = 'foo' } }\n
780 source = {\n
781 url = 'https://github.com/nvim-neorocks/rocks.nvim/archive/1.0.0/rocks.nvim.zip',\n
782 }\n
783 "
784 .to_string();
785 let rockspec = RemoteLuaRockspec::new(&rockspec_content).unwrap();
786 assert_eq!(rockspec.local.rockspec_format, None);
787 assert_eq!(rockspec.local.package, "rocks.nvim".into());
788 assert_eq!(rockspec.local.version, "3.0.0-1".parse().unwrap());
789 let expected_description = RockDescription {
790 summary: Some("some summary".into()),
791 detailed: Some("some detailed description".into()),
792 license: Some("MIT".into()),
793 homepage: Some(Url::parse("https://github.com/nvim-neorocks/rocks.nvim").unwrap()),
794 issues_url: Some("https://github.com/nvim-neorocks/rocks.nvim/issues".into()),
795 maintainer: Some("neorocks".into()),
796 labels: Vec::new(),
797 };
798 assert_eq!(rockspec.local.description, expected_description);
799 assert_eq!(
800 *rockspec
801 .local
802 .external_dependencies
803 .default
804 .get("FOO")
805 .unwrap(),
806 ExternalDependencySpec {
807 library: Some("foo".into()),
808 header: None
809 }
810 );
811
812 let rockspec_content = "
813 package = 'rocks.nvim'\n
814 version = '3.0.0-1'\n
815 description = {\n
816 summary = 'some summary',
817 detailed = 'some detailed description',
818 license = 'MIT',
819 homepage = 'https://github.com/nvim-neorocks/rocks.nvim',
820 issues_url = 'https://github.com/nvim-neorocks/rocks.nvim/issues',
821 maintainer = 'neorocks',
822 labels = { 'package management', },
823 }\n
824 supported_platforms = { 'unix', '!windows' }\n
825 dependencies = { 'neorg ~> 6' }\n
826 build_dependencies = { 'foo' }\n
827 external_dependencies = { FOO = { header = 'foo.h' } }\n
828 test_dependencies = { 'busted >= 2.0.0' }\n
829 source = {\n
830 url = 'git+https://github.com/nvim-neorocks/rocks.nvim',\n
831 hash = 'sha256-uU0nuZNNPgilLlLX2n2r+sSE7+N6U4DukIj3rOLvzek=',\n
832 }\n
833 "
834 .to_string();
835 let rockspec = RemoteLuaRockspec::new(&rockspec_content).unwrap();
836 assert_eq!(rockspec.local.rockspec_format, None);
837 assert_eq!(rockspec.local.package, "rocks.nvim".into());
838 assert_eq!(rockspec.local.version, "3.0.0-1".parse().unwrap());
839 let expected_description = RockDescription {
840 summary: Some("some summary".into()),
841 detailed: Some("some detailed description".into()),
842 license: Some("MIT".into()),
843 homepage: Some(Url::parse("https://github.com/nvim-neorocks/rocks.nvim").unwrap()),
844 issues_url: Some("https://github.com/nvim-neorocks/rocks.nvim/issues".into()),
845 maintainer: Some("neorocks".into()),
846 labels: vec!["package management".into()],
847 };
848 assert_eq!(rockspec.local.description, expected_description);
849 assert!(rockspec
850 .local
851 .supported_platforms
852 .is_supported(&PlatformIdentifier::Unix));
853 assert!(!rockspec
854 .local
855 .supported_platforms
856 .is_supported(&PlatformIdentifier::Windows));
857 let neorg = PackageSpec::parse("neorg".into(), "6.0.0".into()).unwrap();
858 assert!(rockspec
859 .local
860 .dependencies
861 .default
862 .into_iter()
863 .any(|dep| dep.matches(&neorg)));
864 let foo = PackageSpec::parse("foo".into(), "1.0.0".into()).unwrap();
865 assert!(rockspec
866 .local
867 .build_dependencies
868 .default
869 .into_iter()
870 .any(|dep| dep.matches(&foo)));
871 let busted = PackageSpec::parse("busted".into(), "2.2.0".into()).unwrap();
872 assert_eq!(
873 *rockspec
874 .local
875 .external_dependencies
876 .default
877 .get("FOO")
878 .unwrap(),
879 ExternalDependencySpec {
880 header: Some("foo.h".into()),
881 library: None
882 }
883 );
884 assert!(rockspec
885 .local
886 .test_dependencies
887 .default
888 .into_iter()
889 .any(|dep| dep.matches(&busted)));
890
891 let rockspec_content = "
892 rockspec_format = '1.0'\n
893 package = 'foo'\n
894 version = '1.0.0-1'\n
895 source = {\n
896 url = 'git+https://hub.com/example-project/',\n
897 branch = 'bar',\n
898 }\n
899 "
900 .to_string();
901 let rockspec = RemoteLuaRockspec::new(&rockspec_content).unwrap();
902 assert_eq!(
903 rockspec.local.source.default.source_spec,
904 RockSourceSpec::Git(GitSource {
905 url: "https://hub.com/example-project/".parse().unwrap(),
906 checkout_ref: Some("bar".into())
907 })
908 );
909 assert_eq!(rockspec.local.test, PerPlatform::default());
910 let rockspec_content = "
911 rockspec_format = '1.0'\n
912 package = 'foo'\n
913 version = '1.0.0-1'\n
914 source = {\n
915 url = 'git+https://hub.com/example-project/',\n
916 tag = 'bar',\n
917 }\n
918 "
919 .to_string();
920 let rockspec = RemoteLuaRockspec::new(&rockspec_content).unwrap();
921 assert_eq!(
922 rockspec.local.source.default.source_spec,
923 RockSourceSpec::Git(GitSource {
924 url: "https://hub.com/example-project/".parse().unwrap(),
925 checkout_ref: Some("bar".into())
926 })
927 );
928 let rockspec_content = "
929 rockspec_format = '1.0'\n
930 package = 'foo'\n
931 version = '1.0.0-1'\n
932 source = {\n
933 url = 'git+https://hub.com/example-project/',\n
934 branch = 'bar',\n
935 tag = 'baz',\n
936 }\n
937 "
938 .to_string();
939 let _rockspec = RemoteLuaRockspec::new(&rockspec_content).unwrap_err();
940 let rockspec_content = "
941 rockspec_format = '1.0'\n
942 package = 'foo'\n
943 version = '1.0.0-1'\n
944 source = {\n
945 url = 'git+https://hub.com/example-project/',\n
946 tag = 'bar',\n
947 file = 'foo.tar.gz',\n
948 }\n
949 build = {\n
950 install = {\n
951 conf = {['foo.bar'] = 'config/bar.toml'},\n
952 },\n
953 }\n
954 "
955 .to_string();
956 let rockspec = RemoteLuaRockspec::new(&rockspec_content).unwrap();
957 assert_eq!(
958 rockspec.local.source.default.archive_name,
959 Some("foo.tar.gz".into())
960 );
961 let foo_bar_path = rockspec
962 .local
963 .build
964 .default
965 .install
966 .conf
967 .get("foo.bar")
968 .unwrap();
969 assert_eq!(*foo_bar_path, PathBuf::from("config/bar.toml"));
970 let rockspec_content = "
971 rockspec_format = '1.0'\n
972 package = 'foo'\n
973 version = '1.0.0-1'\n
974 source = {\n
975 url = 'git+https://hub.com/example-project/foo.zip',\n
976 }\n
977 build = {\n
978 install = {\n
979 lua = {['foo.bar'] = 'src/bar.lua'},\n
980 bin = {['foo.bar'] = 'bin/bar'},\n
981 },\n
982 }\n
983 "
984 .to_string();
985 let rockspec = RemoteLuaRockspec::new(&rockspec_content).unwrap();
986 assert!(matches!(
987 rockspec.local.build.default.build_backend,
988 Some(BuildBackendSpec::Builtin { .. })
989 ));
990 let foo_bar_path = rockspec
991 .local
992 .build
993 .default
994 .install
995 .lua
996 .get(&LuaModule::from_str("foo.bar").unwrap())
997 .unwrap();
998 assert_eq!(*foo_bar_path, PathBuf::from("src/bar.lua"));
999 let foo_bar_path = rockspec
1000 .local
1001 .build
1002 .default
1003 .install
1004 .bin
1005 .get("foo.bar")
1006 .unwrap();
1007 assert_eq!(*foo_bar_path, PathBuf::from("bin/bar"));
1008 let rockspec_content = "
1009 rockspec_format = '1.0'\n
1010 package = 'foo'\n
1011 version = '1.0.0-1'\n
1012 source = {\n
1013 url = 'git+https://hub.com/example-project/',\n
1014 }\n
1015 build = {\n
1016 copy_directories = { 'lua' },\n
1017 }\n
1018 "
1019 .to_string();
1020 let _rockspec = RemoteLuaRockspec::new(&rockspec_content).unwrap_err();
1021 let rockspec_content = "
1022 rockspec_format = '1.0'\n
1023 package = 'foo'\n
1024 version = '1.0.0-1'\n
1025 source = {\n
1026 url = 'git+https://hub.com/example-project/',\n
1027 }\n
1028 build = {\n
1029 copy_directories = { 'lib' },\n
1030 }\n
1031 "
1032 .to_string();
1033 let _rockspec = RemoteLuaRockspec::new(&rockspec_content).unwrap_err();
1034 let rockspec_content = "
1035 rockspec_format = '1.0'\n
1036 package = 'foo'\n
1037 version = '1.0.0-1'\n
1038 source = {\n
1039 url = 'git+https://hub.com/example-project/',\n
1040 }\n
1041 build = {\n
1042 copy_directories = { 'rock_manifest' },\n
1043 }\n
1044 "
1045 .to_string();
1046 let _rockspec = RemoteLuaRockspec::new(&rockspec_content).unwrap_err();
1047 let rockspec_content = "
1048 rockspec_format = '1.0'\n
1049 package = 'foo'\n
1050 version = '1.0.0-1'\n
1051 source = {\n
1052 url = 'git+https://hub.com/example-project/foo.zip',\n
1053 dir = 'baz',\n
1054 }\n
1055 build = {\n
1056 type = 'make',\n
1057 install = {\n
1058 lib = {['foo.bar'] = 'lib/bar.so'},\n
1059 },\n
1060 copy_directories = {\n
1061 'plugin',\n
1062 'ftplugin',\n
1063 },\n
1064 patches = {\n
1065 ['lua51-support.diff'] = [[\n
1066 --- before.c\n
1067 +++ path/to/after.c\n
1068 ]],\n
1069 },\n
1070 }\n
1071 "
1072 .to_string();
1073 let rockspec = RemoteLuaRockspec::new(&rockspec_content).unwrap();
1074 assert_eq!(rockspec.local.source.default.unpack_dir, Some("baz".into()));
1075 assert_eq!(
1076 rockspec.local.build.default.build_backend,
1077 Some(BuildBackendSpec::Make(MakeBuildSpec::default()))
1078 );
1079 let foo_bar_path = rockspec
1080 .local
1081 .build
1082 .default
1083 .install
1084 .lib
1085 .get(&LuaModule::from_str("foo.bar").unwrap())
1086 .unwrap();
1087 assert_eq!(*foo_bar_path, PathBuf::from("lib/bar.so"));
1088 let copy_directories = rockspec.local.build.default.copy_directories;
1089 assert_eq!(
1090 copy_directories,
1091 vec![PathBuf::from("plugin"), PathBuf::from("ftplugin")]
1092 );
1093 let patches = rockspec.local.build.default.patches;
1094 let _patch = patches.get(&PathBuf::from("lua51-support.diff")).unwrap();
1095 let rockspec_content = "
1096 rockspec_format = '1.0'\n
1097 package = 'foo'\n
1098 version = '1.0.0-1'\n
1099 source = {\n
1100 url = 'git+https://hub.com/example-project/foo.zip',\n
1101 }\n
1102 build = {\n
1103 type = 'cmake',\n
1104 }\n
1105 "
1106 .to_string();
1107 let rockspec = RemoteLuaRockspec::new(&rockspec_content).unwrap();
1108 assert_eq!(
1109 rockspec.local.build.default.build_backend,
1110 Some(BuildBackendSpec::CMake(CMakeBuildSpec::default()))
1111 );
1112 let rockspec_content = "
1113 rockspec_format = '1.0'\n
1114 package = 'foo'\n
1115 version = '1.0.0-1'\n
1116 source = {\n
1117 url = 'git+https://hub.com/example-project/foo.zip',\n
1118 }\n
1119 build = {\n
1120 type = 'command',\n
1121 build_command = 'foo',\n
1122 install_command = 'bar',\n
1123 }\n
1124 "
1125 .to_string();
1126 let rockspec = RemoteLuaRockspec::new(&rockspec_content).unwrap();
1127 assert!(matches!(
1128 rockspec.local.build.default.build_backend,
1129 Some(BuildBackendSpec::Command(CommandBuildSpec { .. }))
1130 ));
1131 let rockspec_content = "
1132 rockspec_format = '1.0'\n
1133 package = 'foo'\n
1134 version = '1.0.0-1'\n
1135 source = {\n
1136 url = 'git+https://hub.com/example-project/foo.zip',\n
1137 }\n
1138 build = {\n
1139 type = 'command',\n
1140 install_command = 'foo',\n
1141 }\n
1142 "
1143 .to_string();
1144 RemoteLuaRockspec::new(&rockspec_content).unwrap();
1145 let rockspec_content = "
1146 rockspec_format = '1.0'\n
1147 package = 'foo'\n
1148 version = '1.0.0-1'\n
1149 source = {\n
1150 url = 'git+https://hub.com/example-project/foo.zip',\n
1151 }\n
1152 build = {\n
1153 type = 'command',\n
1154 build_command = 'foo',\n
1155 }\n
1156 "
1157 .to_string();
1158 RemoteLuaRockspec::new(&rockspec_content).unwrap();
1159 let rockspec_content = "
1161 package = 'rocks'\n
1162 version = '3.0.0-1'\n
1163 dependencies = {\n
1164 'neorg ~> 6',\n
1165 'toml-edit ~> 1',\n
1166 platforms = {\n
1167 windows = {\n
1168 'neorg = 5.0.0',\n
1169 'toml = 1.0.0',\n
1170 },\n
1171 unix = {\n
1172 'neorg = 5.0.0',\n
1173 },\n
1174 linux = {\n
1175 'toml = 1.0.0',\n
1176 },\n
1177 },\n
1178 }\n
1179 source = {\n
1180 url = 'git+https://github.com/nvim-neorocks/rocks.nvim',\n
1181 hash = 'sha256-uU0nuZNNPgilLlLX2n2r+sSE7+N6U4DukIj3rOLvzek=',\n
1182 }\n
1183 "
1184 .to_string();
1185 let rockspec = RemoteLuaRockspec::new(&rockspec_content).unwrap();
1186 let neorg_override = PackageSpec::parse("neorg".into(), "5.0.0".into()).unwrap();
1187 let toml_edit = PackageSpec::parse("toml-edit".into(), "1.0.0".into()).unwrap();
1188 let toml = PackageSpec::parse("toml".into(), "1.0.0".into()).unwrap();
1189 assert_eq!(rockspec.local.dependencies.default.len(), 2);
1190 let per_platform = &rockspec.local.dependencies.per_platform;
1191 assert_eq!(
1192 per_platform
1193 .get(&PlatformIdentifier::Windows)
1194 .unwrap()
1195 .iter()
1196 .filter(|dep| dep.matches(&neorg_override)
1197 || dep.matches(&toml_edit)
1198 || dep.matches(&toml))
1199 .count(),
1200 3
1201 );
1202 assert_eq!(
1203 per_platform
1204 .get(&PlatformIdentifier::Unix)
1205 .unwrap()
1206 .iter()
1207 .filter(|dep| dep.matches(&neorg_override)
1208 || dep.matches(&toml_edit)
1209 || dep.matches(&toml))
1210 .count(),
1211 2
1212 );
1213 assert_eq!(
1214 per_platform
1215 .get(&PlatformIdentifier::Linux)
1216 .unwrap()
1217 .iter()
1218 .filter(|dep| dep.matches(&neorg_override)
1219 || dep.matches(&toml_edit)
1220 || dep.matches(&toml))
1221 .count(),
1222 3
1223 );
1224 let rockspec_content = "
1225 package = 'rocks'\n
1226 version = '3.0.0-1'\n
1227 external_dependencies = {\n
1228 FOO = { library = 'foo' },\n
1229 platforms = {\n
1230 windows = {\n
1231 FOO = { library = 'foo.dll' },\n
1232 },\n
1233 unix = {\n
1234 BAR = { header = 'bar.h' },\n
1235 },\n
1236 linux = {\n
1237 FOO = { library = 'foo.so' },\n
1238 },\n
1239 },\n
1240 }\n
1241 source = {\n
1242 url = 'https://github.com/nvim-neorocks/rocks.nvim/archive/1.0.0/rocks.nvim.zip',\n
1243 }\n
1244 "
1245 .to_string();
1246 let rockspec = RemoteLuaRockspec::new(&rockspec_content).unwrap();
1247 assert_eq!(
1248 *rockspec
1249 .local
1250 .external_dependencies
1251 .default
1252 .get("FOO")
1253 .unwrap(),
1254 ExternalDependencySpec {
1255 library: Some("foo".into()),
1256 header: None
1257 }
1258 );
1259 let per_platform = rockspec.local.external_dependencies.per_platform;
1260 assert_eq!(
1261 *per_platform
1262 .get(&PlatformIdentifier::Windows)
1263 .and_then(|it| it.get("FOO"))
1264 .unwrap(),
1265 ExternalDependencySpec {
1266 library: Some("foo.dll".into()),
1267 header: None
1268 }
1269 );
1270 assert_eq!(
1271 *per_platform
1272 .get(&PlatformIdentifier::Unix)
1273 .and_then(|it| it.get("FOO"))
1274 .unwrap(),
1275 ExternalDependencySpec {
1276 library: Some("foo".into()),
1277 header: None
1278 }
1279 );
1280 assert_eq!(
1281 *per_platform
1282 .get(&PlatformIdentifier::Unix)
1283 .and_then(|it| it.get("BAR"))
1284 .unwrap(),
1285 ExternalDependencySpec {
1286 header: Some("bar.h".into()),
1287 library: None
1288 }
1289 );
1290 assert_eq!(
1291 *per_platform
1292 .get(&PlatformIdentifier::Linux)
1293 .and_then(|it| it.get("BAR"))
1294 .unwrap(),
1295 ExternalDependencySpec {
1296 header: Some("bar.h".into()),
1297 library: None
1298 }
1299 );
1300 assert_eq!(
1301 *per_platform
1302 .get(&PlatformIdentifier::Linux)
1303 .and_then(|it| it.get("FOO"))
1304 .unwrap(),
1305 ExternalDependencySpec {
1306 library: Some("foo.so".into()),
1307 header: None
1308 }
1309 );
1310 let rockspec_content = "
1311 rockspec_format = '1.0'\n
1312 package = 'foo'\n
1313 version = '1.0.0-1'\n
1314 source = {\n
1315 url = 'git+https://hub.com/example-project/.git',\n
1316 branch = 'bar',\n
1317 platforms = {\n
1318 macosx = {\n
1319 branch = 'mac',\n
1320 },\n
1321 windows = {\n
1322 url = 'git+https://winhub.com/example-project/.git',\n
1323 branch = 'win',\n
1324 },\n
1325 },\n
1326 }\n
1327 "
1328 .to_string();
1329 let rockspec = RemoteLuaRockspec::new(&rockspec_content).unwrap();
1330 assert_eq!(
1331 rockspec.local.source.default.source_spec,
1332 RockSourceSpec::Git(GitSource {
1333 url: "https://hub.com/example-project/.git".parse().unwrap(),
1334 checkout_ref: Some("bar".into())
1335 })
1336 );
1337 assert_eq!(
1338 rockspec
1339 .source
1340 .per_platform
1341 .get(&PlatformIdentifier::MacOSX)
1342 .map(|it| it.source_spec.clone())
1343 .unwrap(),
1344 RockSourceSpec::Git(GitSource {
1345 url: "https://hub.com/example-project/.git".parse().unwrap(),
1346 checkout_ref: Some("mac".into())
1347 })
1348 );
1349 assert_eq!(
1350 rockspec
1351 .source
1352 .per_platform
1353 .get(&PlatformIdentifier::Windows)
1354 .map(|it| it.source_spec.clone())
1355 .unwrap(),
1356 RockSourceSpec::Git(GitSource {
1357 url: "https://winhub.com/example-project/.git".parse().unwrap(),
1358 checkout_ref: Some("win".into())
1359 })
1360 );
1361 let rockspec_content = "
1362 rockspec_format = '1.0'\n
1363 package = 'foo'\n
1364 version = '1.0.0-1'\n
1365 source = { url = 'git+https://hub.com/example-project/foo.zip' }\n
1366 build = {\n
1367 type = 'make',\n
1368 install = {\n
1369 lib = {['foo.bar'] = 'lib/bar.so'},\n
1370 },\n
1371 copy_directories = { 'plugin' },\n
1372 platforms = {\n
1373 unix = {\n
1374 copy_directories = { 'ftplugin' },\n
1375 },\n
1376 linux = {\n
1377 copy_directories = { 'foo' },\n
1378 },\n
1379 },\n
1380 }\n
1381 "
1382 .to_string();
1383 let rockspec = RemoteLuaRockspec::new(&rockspec_content).unwrap();
1384 let per_platform = rockspec.local.build.per_platform;
1385 let unix = per_platform.get(&PlatformIdentifier::Unix).unwrap();
1386 assert_eq!(
1387 unix.copy_directories,
1388 vec![PathBuf::from("plugin"), PathBuf::from("ftplugin")]
1389 );
1390 let linux = per_platform.get(&PlatformIdentifier::Linux).unwrap();
1391 assert_eq!(
1392 linux.copy_directories,
1393 vec![
1394 PathBuf::from("plugin"),
1395 PathBuf::from("foo"),
1396 PathBuf::from("ftplugin")
1397 ]
1398 );
1399 let rockspec_content = "
1400 package = 'foo'\n
1401 version = '1.0.0-1'\n
1402 source = { url = 'git+https://hub.com/example-project/foo.zip' }\n
1403 build = {\n
1404 type = 'builtin',\n
1405 modules = {\n
1406 cjson = {\n
1407 sources = { 'lua_cjson.c', 'strbuf.c', 'fpconv.c' },\n
1408 }\n
1409 },\n
1410 platforms = {\n
1411 win32 = { modules = { cjson = { defines = {\n
1412 'DISABLE_INVALID_NUMBERS', 'USE_INTERNAL_ISINF'\n
1413 } } } }\n
1414 },\n
1415 }\n
1416 "
1417 .to_string();
1418 let rockspec = RemoteLuaRockspec::new(&rockspec_content).unwrap();
1419 let per_platform = &rockspec.local.build.per_platform;
1420 let win32 = per_platform.get(&PlatformIdentifier::Windows).unwrap();
1421 assert_eq!(
1422 win32.build_backend,
1423 Some(BuildBackendSpec::Builtin(BuiltinBuildSpec {
1424 modules: vec![(
1425 LuaModule::from_str("cjson").unwrap(),
1426 ModuleSpec::ModulePaths(ModulePaths {
1427 sources: vec!["lua_cjson.c".into(), "strbuf.c".into(), "fpconv.c".into()],
1428 libraries: Vec::default(),
1429 defines: vec![
1430 ("DISABLE_INVALID_NUMBERS".into(), None),
1431 ("USE_INTERNAL_ISINF".into(), None)
1432 ],
1433 incdirs: Vec::default(),
1434 libdirs: Vec::default(),
1435 })
1436 )]
1437 .into_iter()
1438 .collect()
1439 }))
1440 );
1441 let rockspec_content = "
1442 rockspec_format = '1.0'\n
1443 package = 'foo'\n
1444 version = '1.0.0-1'\n
1445 deploy = {\n
1446 wrap_bin_scripts = false,\n
1447 }\n
1448 source = { url = 'git+https://hub.com/example-project/foo.zip' }\n
1449 ";
1450 let rockspec = RemoteLuaRockspec::new(rockspec_content).unwrap();
1451 let deploy_spec = &rockspec.deploy().current_platform();
1452 assert!(!deploy_spec.wrap_bin_scripts);
1453 }
1454
1455 #[tokio::test]
1456 pub async fn parse_scm_rockspec() {
1457 let rockspec_content = "
1458 package = 'foo'\n
1459 version = 'scm-1'\n
1460 source = {\n
1461 url = 'https://github.com/nvim-neorocks/rocks.nvim/archive/1.0.0/rocks.nvim.zip',\n
1462 }\n
1463 "
1464 .to_string();
1465 let rockspec = RemoteLuaRockspec::new(&rockspec_content).unwrap();
1466 assert_eq!(rockspec.local.package, "foo".into());
1467 assert_eq!(rockspec.local.version, "scm-1".parse().unwrap());
1468 }
1469
1470 #[tokio::test]
1471 pub async fn regression_luasystem() {
1472 let rockspec_content =
1473 String::from_utf8(std::fs::read("resources/test/luasystem-0.4.4-1.rockspec").unwrap())
1474 .unwrap();
1475 let rockspec = RemoteLuaRockspec::new(&rockspec_content).unwrap();
1476 let build_spec = rockspec.local.build.current_platform();
1477 assert!(matches!(
1478 build_spec.build_backend,
1479 Some(BuildBackendSpec::Builtin { .. })
1480 ));
1481 if let Some(BuildBackendSpec::Builtin(BuiltinBuildSpec { modules })) =
1482 &build_spec.build_backend
1483 {
1484 assert_eq!(
1485 modules.get(&LuaModule::from_str("system.init").unwrap()),
1486 Some(&ModuleSpec::SourcePath("system/init.lua".into()))
1487 );
1488 assert_eq!(
1489 modules.get(&LuaModule::from_str("system.core").unwrap()),
1490 Some(&ModuleSpec::ModulePaths(ModulePaths {
1491 sources: vec![
1492 "src/core.c".into(),
1493 "src/compat.c".into(),
1494 "src/time.c".into(),
1495 "src/environment.c".into(),
1496 "src/random.c".into(),
1497 "src/term.c".into(),
1498 "src/bitflags.c".into(),
1499 "src/wcwidth.c".into(),
1500 ],
1501 defines: luasystem_expected_defines(),
1502 libraries: luasystem_expected_libraries(),
1503 incdirs: luasystem_expected_incdirs(),
1504 libdirs: luasystem_expected_libdirs(),
1505 }))
1506 );
1507 }
1508 if let Some(BuildBackendSpec::Builtin(BuiltinBuildSpec { modules })) = &rockspec
1509 .local
1510 .build
1511 .get(&PlatformIdentifier::Windows)
1512 .build_backend
1513 {
1514 if let ModuleSpec::ModulePaths(paths) = modules
1515 .get(&LuaModule::from_str("system.core").unwrap())
1516 .unwrap()
1517 {
1518 assert_eq!(paths.libraries, luasystem_expected_windows_libraries());
1519 };
1520 }
1521 if let Some(BuildBackendSpec::Builtin(BuiltinBuildSpec { modules })) = &rockspec
1522 .local
1523 .build
1524 .get(&PlatformIdentifier::Win32)
1525 .build_backend
1526 {
1527 if let ModuleSpec::ModulePaths(paths) = modules
1528 .get(&LuaModule::from_str("system.core").unwrap())
1529 .unwrap()
1530 {
1531 assert_eq!(paths.libraries, luasystem_expected_windows_libraries());
1532 };
1533 }
1534 }
1535
1536 fn luasystem_expected_defines() -> Vec<(String, Option<String>)> {
1537 if cfg!(target_os = "windows") {
1538 vec![
1539 ("WINVER".into(), Some("0x0600".into())),
1540 ("_WIN32_WINNT".into(), Some("0x0600".into())),
1541 ]
1542 } else {
1543 Vec::default()
1544 }
1545 }
1546
1547 fn luasystem_expected_windows_libraries() -> Vec<PathBuf> {
1548 vec!["advapi32".into(), "winmm".into()]
1549 }
1550 fn luasystem_expected_libraries() -> Vec<PathBuf> {
1551 if cfg!(target_os = "linux") {
1552 vec!["rt".into()]
1553 } else if cfg!(target_os = "windows") {
1554 luasystem_expected_windows_libraries()
1555 } else {
1556 Vec::default()
1557 }
1558 }
1559
1560 fn luasystem_expected_incdirs() -> Vec<PathBuf> {
1561 Vec::default()
1562 }
1563
1564 fn luasystem_expected_libdirs() -> Vec<PathBuf> {
1565 Vec::default()
1566 }
1567
1568 #[tokio::test]
1569 pub async fn rust_mlua_rockspec() {
1570 let rockspec_content = "
1571 package = 'foo'\n
1572 version = 'scm-1'\n
1573 source = {\n
1574 url = 'https://github.com/nvim-neorocks/rocks.nvim/archive/1.0.0/rocks.nvim.zip',\n
1575 }\n
1576 build = {
1577 type = 'rust-mlua',
1578 modules = {
1579 'foo',
1580 bar = 'baz',
1581 },
1582 target_path = 'path/to/cargo/target/directory',
1583 default_features = false,
1584 include = {
1585 'file.lua',
1586 ['path/to/another/file.lua'] = 'another-file.lua',
1587 },
1588 features = {'extra', 'features'},
1589 }
1590 ";
1591 let rockspec = RemoteLuaRockspec::new(rockspec_content).unwrap();
1592 let build_spec = rockspec.local.build.current_platform();
1593 if let Some(BuildBackendSpec::RustMlua(build_spec)) = build_spec.build_backend.to_owned() {
1594 assert_eq!(
1595 build_spec.modules.get("foo").unwrap(),
1596 &PathBuf::from(format!("libfoo.{}", std::env::consts::DLL_EXTENSION))
1597 );
1598 assert_eq!(
1599 build_spec.modules.get("bar").unwrap(),
1600 &PathBuf::from(format!("libbaz.{}", std::env::consts::DLL_EXTENSION))
1601 );
1602 assert_eq!(
1603 build_spec.include.get(&PathBuf::from("file.lua")).unwrap(),
1604 &PathBuf::from("file.lua")
1605 );
1606 assert_eq!(
1607 build_spec
1608 .include
1609 .get(&PathBuf::from("path/to/another/file.lua"))
1610 .unwrap(),
1611 &PathBuf::from("another-file.lua")
1612 );
1613 } else {
1614 panic!("Expected RustMlua build backend");
1615 }
1616 }
1617
1618 #[tokio::test]
1619 pub async fn regression_ltui() {
1620 let content =
1621 String::from_utf8(std::fs::read("resources/test/ltui-2.8-2.rockspec").unwrap())
1622 .unwrap();
1623 RemoteLuaRockspec::new(&content).unwrap();
1624 }
1625
1626 #[tokio::test]
1629 pub async fn regression_off_spec_install_binaries() {
1630 let rockspec_content = r#"
1631 package = "WSAPI"
1632 version = "1.7-1"
1633
1634 source = {
1635 url = "git://github.com/keplerproject/wsapi",
1636 tag = "v1.7",
1637 }
1638
1639 build = {
1640 type = "builtin",
1641 modules = {
1642 ["wsapi"] = "src/wsapi.lua",
1643 },
1644 -- Offending Line
1645 install = { bin = { "src/launcher/wsapi.cgi" } }
1646 }
1647 "#;
1648
1649 let rockspec = RemoteLuaRockspec::new(rockspec_content).unwrap();
1650
1651 assert_eq!(
1652 rockspec.build().current_platform().install.bin,
1653 HashMap::from([("wsapi".into(), PathBuf::from("src/launcher/wsapi.cgi"))])
1654 );
1655 }
1656
1657 #[tokio::test]
1658 pub async fn regression_external_dependencies() {
1659 let content =
1660 String::from_utf8(std::fs::read("resources/test/luaossl-20220711-0.rockspec").unwrap())
1661 .unwrap();
1662 let rockspec = RemoteLuaRockspec::new(&content).unwrap();
1663 if cfg!(target_family = "unix") {
1664 assert_eq!(
1665 rockspec
1666 .local
1667 .external_dependencies
1668 .current_platform()
1669 .get("OPENSSL")
1670 .unwrap(),
1671 &ExternalDependencySpec {
1672 library: Some("ssl".into()),
1673 header: Some("openssl/ssl.h".into()),
1674 }
1675 );
1676 }
1677 let per_platform = rockspec.local.external_dependencies.per_platform;
1678 assert_eq!(
1679 *per_platform
1680 .get(&PlatformIdentifier::Windows)
1681 .and_then(|it| it.get("OPENSSL"))
1682 .unwrap(),
1683 ExternalDependencySpec {
1684 library: Some("libeay32".into()),
1685 header: Some("openssl/ssl.h".into()),
1686 }
1687 );
1688 }
1689
1690 #[tokio::test]
1691 pub async fn remote_lua_rockspec_from_package_and_source_spec() {
1692 let package_req = "foo@1.0.5".parse().unwrap();
1693 let source = GitSource {
1694 url: "https://hub.com/example-project.git".parse().unwrap(),
1695 checkout_ref: Some("1.0.5".into()),
1696 };
1697 let source_spec = RockSourceSpec::Git(source);
1698 let rockspec =
1699 RemoteLuaRockspec::from_package_and_source_spec(package_req, source_spec.clone());
1700 let generated_rockspec_str = rockspec.local.raw_content;
1701 let rockspec2 = RemoteLuaRockspec::new(&generated_rockspec_str).unwrap();
1702 assert_eq!(rockspec2.local.package, "foo".into());
1703 assert_eq!(rockspec2.local.version, "1.0.5".parse().unwrap());
1704 assert_eq!(rockspec2.local.source, PerPlatform::new(source_spec.into()));
1705 }
1706}