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