1use std::collections::BTreeMap;
2use std::ffi::OsStr;
3use std::fs;
4use std::path;
5use std::process::Command;
6
7use serde::{Deserialize, Serialize};
8
9use crate::build_system::FlatpakBuildSystem;
10use crate::format::FlatpakManifestFormat;
11use crate::source::{FlatpakSourceItem, FlatpakSourceType};
12
13#[derive(Clone)]
14#[derive(Deserialize)]
15#[derive(Serialize)]
16#[derive(Debug)]
17#[derive(Hash)]
18#[serde(untagged)]
19pub enum FlatpakModuleItem {
22 Path(String),
23 Description(FlatpakModule),
24}
25
26#[derive(Clone)]
27#[derive(Deserialize)]
28#[derive(Serialize)]
29#[derive(Debug)]
30#[derive(Default)]
31#[derive(Hash)]
32#[serde(rename_all = "kebab-case")]
33#[serde(default)]
34pub struct FlatpakModule {
40 #[serde(skip_serializing)]
41 pub format: FlatpakManifestFormat,
42
43 pub name: String,
47
48 #[serde(skip_serializing_if = "Option::is_none")]
50 pub disabled: Option<bool>,
51
52 #[serde(skip_serializing_if = "Vec::is_empty")]
56 pub sources: Vec<FlatpakSourceItem>,
57
58 #[serde(skip_serializing_if = "Vec::is_empty")]
60 pub config_opts: Vec<String>,
61
62 #[serde(skip_serializing_if = "Vec::is_empty")]
64 pub make_args: Vec<String>,
65
66 #[serde(skip_serializing_if = "Vec::is_empty")]
68 pub make_install_args: Vec<String>,
69
70 #[serde(skip_serializing_if = "Option::is_none")]
72 pub rm_configure: Option<bool>,
73
74 #[serde(skip_serializing_if = "Option::is_none")]
76 pub no_autogen: Option<bool>,
77
78 #[serde(skip_serializing_if = "Option::is_none")]
80 pub no_parallel_make: Option<bool>,
81
82 #[serde(skip_serializing_if = "String::is_empty")]
84 pub install_rule: String,
85
86 #[serde(skip_serializing_if = "Option::is_none")]
88 pub no_make_install: Option<bool>,
89
90 #[serde(skip_serializing_if = "Option::is_none")]
92 pub no_python_timestamp_fix: Option<bool>,
93
94 #[serde(skip_serializing_if = "Option::is_none")]
96 pub cmake: Option<bool>,
97
98 #[serde(deserialize_with = "crate::build_system::FlatpakBuildSystem::deserialize")]
100 #[serde(serialize_with = "crate::build_system::FlatpakBuildSystem::serialize")]
101 #[serde(skip_serializing_if = "Option::is_none")]
102 pub buildsystem: Option<FlatpakBuildSystem>,
103
104 #[serde(skip_serializing_if = "Option::is_none")]
106 pub builddir: Option<bool>,
107
108 #[serde(skip_serializing_if = "String::is_empty")]
110 pub subdir: String,
111
112 #[serde(skip_serializing_if = "Option::is_none")]
114 pub build_options: Option<FlatpakBuildOptions>,
115
116 #[serde(skip_serializing_if = "Vec::is_empty")]
120 pub build_commands: Vec<String>,
121
122 #[serde(skip_serializing_if = "Vec::is_empty")]
125 pub post_install: Vec<String>,
126
127 #[serde(skip_serializing_if = "Vec::is_empty")]
132 pub cleanup: Vec<String>,
133
134 #[serde(skip_serializing_if = "Vec::is_empty")]
139 pub ensure_writable: Vec<String>,
140
141 #[serde(skip_serializing_if = "Vec::is_empty")]
143 pub only_arches: Vec<String>,
144
145 #[serde(skip_serializing_if = "Vec::is_empty")]
147 pub skip_arches: Vec<String>,
148
149 #[serde(skip_serializing_if = "Vec::is_empty")]
151 pub cleanup_platform: Vec<String>,
152
153 #[serde(skip_serializing_if = "Option::is_none")]
155 pub run_tests: Option<bool>,
156
157 #[serde(skip_serializing_if = "String::is_empty")]
160 pub test_rule: String,
161
162 #[serde(skip_serializing_if = "Vec::is_empty")]
164 pub test_commands: Vec<String>,
165
166 #[serde(skip_serializing_if = "Vec::is_empty")]
170 pub modules: Vec<FlatpakModuleItem>,
171}
172impl FlatpakModule {
173 pub fn uses_external_data_checker(&self) -> bool {
174 for source in &self.sources {
175 let source_description = match source {
176 FlatpakSourceItem::Description(d) => d,
177 FlatpakSourceItem::Path(_) => continue,
178 };
179 if source_description.x_checker_data.is_some() {
180 return true;
181 }
182 }
183 return false;
184 }
185
186 pub fn get_mirror_urls(&self) -> Vec<String> {
187 let mut mirror_urls = vec![];
188 for module in &self.modules {
189 if let FlatpakModuleItem::Description(module_description) = module {
190 mirror_urls.append(&mut module_description.get_mirror_urls());
191 }
192 }
193 for source in &self.sources {
194 let source_description = match source {
195 FlatpakSourceItem::Description(d) => d,
196 FlatpakSourceItem::Path(_p) => continue,
197 };
198 for url in source_description.get_mirror_urls() {
199 mirror_urls.push(url.to_string());
200 }
201 }
202 mirror_urls
203 }
204
205 pub fn get_buildsystem(&self) -> Option<String> {
206 if self.cmake.unwrap_or(false) {
207 return Some(crate::build_system::CMAKE.to_string());
208 }
209 if let Some(buildsystem) = &self.buildsystem {
210 return Some(buildsystem.to_string());
211 }
212 None
213 }
214
215 pub fn is_patched(&self) -> bool {
216 for source in &self.sources {
217 if let FlatpakSourceItem::Description(sd) = source {
218 if sd.get_type() == Some(FlatpakSourceType::Patch) {
219 return true;
220 }
221 }
222 }
223 false
224 }
225
226 pub fn load_from_file(path: String) -> Result<FlatpakModule, String> {
227 let file_path = path::Path::new(&path);
228 if !file_path.is_file() {
229 return Err(format!("{} is not a file.", path));
230 }
231
232 let manifest_format = match FlatpakManifestFormat::from_path(&path) {
233 Some(f) => f,
234 None => return Err(format!("{} is not a Flatpak module manifest.", path)),
235 };
236
237 let manifest_content = match fs::read_to_string(file_path) {
238 Ok(content) => content,
239 Err(e) => {
240 return Err(format!("Could not read module manifest at {}: {}", &path, e));
241 }
242 };
243 match FlatpakModule::parse(manifest_format, &manifest_content) {
244 Ok(m) => Ok(m),
245 Err(e) => Err(format!(
246 "Failed to parse Flatpak module manifest at {}: {}",
247 path, e
248 )),
249 }
250 }
251
252 pub fn parse(format: FlatpakManifestFormat, manifest_content: &str) -> Result<FlatpakModule, String> {
253 let mut flatpak_module: FlatpakModule = match format.parse(manifest_content) {
254 Ok(m) => m,
255 Err(e) => {
256 return Err(format!("Failed to parse the Flatpak module manifest: {}.", e));
257 }
258 };
259 flatpak_module.format = format;
260
261 if flatpak_module.name.is_empty() {
262 return Err("Required top-level field name is missing from Flatpak module.".to_string());
263 }
264 if flatpak_module.sources.is_empty() {
265 return Err("Required sources were not found in Flatpak module.".to_string());
266 }
267 for source in &flatpak_module.sources {
268 let source_path = match source {
269 FlatpakSourceItem::Description(_) => continue,
270 FlatpakSourceItem::Path(p) => p,
271 };
272 if source_path.starts_with("http://") || source_path.starts_with("https://") {
275 return Err("Sources provided as strings cannot be URLs!".to_string());
276 }
277 }
278 for source in &flatpak_module.sources {
279 let source_description = match source {
280 FlatpakSourceItem::Path(_) => continue,
281 FlatpakSourceItem::Description(d) => d,
282 };
283 if let Err(e) = source_description.is_valid() {
284 return Err(e);
285 }
286 }
287
288 Ok(flatpak_module)
289 }
290
291 pub fn dump(&self) -> Result<String, String> {
292 match self.format.dump(self) {
293 Ok(d) => Ok(d),
294 Err(e) => return Err(format!("Failed to dump the Flatpak manifest: {}.", e)),
295 }
296 }
297
298 pub fn file_path_matches(path: &str) -> bool {
299 crate::filename::extension_is_valid(path)
302 }
303
304 pub fn get_urls(
305 &self,
306 include_mirror_urls: bool,
307 include_source_types: Option<Vec<FlatpakSourceType>>,
308 ) -> Vec<String> {
309 let mut urls = vec![];
310 for module in &self.modules {
311 if let FlatpakModuleItem::Description(module_description) = module {
312 urls.append(
313 &mut module_description.get_urls(include_mirror_urls, include_source_types.clone()),
314 );
315 }
316 }
317 for source in &self.sources {
318 let source_description = match source {
319 FlatpakSourceItem::Description(d) => d,
320 FlatpakSourceItem::Path(_p) => continue,
321 };
322 for url in source_description.get_urls(include_mirror_urls, include_source_types.clone()) {
323 urls.push(url);
324 }
325 }
326 urls
327 }
328
329 pub fn get_max_depth(&self) -> i32 {
330 let mut max_depth: i32 = 0;
331 for module in &self.modules {
332 if let FlatpakModuleItem::Description(module_description) = module {
333 let module_depth = module_description.get_max_depth();
334 if module_depth > max_depth {
335 max_depth = module_depth;
336 }
337 }
338 }
339 return max_depth + 1;
340 }
341
342 pub fn get_main_url(&self) -> Option<String> {
343 if self.sources.len() < 1 {
344 return None;
345 }
346
347 let main_module_source = self.sources.first().unwrap();
350
351 let main_module_source_description = match main_module_source {
352 FlatpakSourceItem::Description(d) => d,
353 FlatpakSourceItem::Path(_p) => return None,
354 };
355
356 let main_module_source_url: Option<String> = main_module_source_description.get_url();
357
358 match &main_module_source_url {
359 Some(s) => Some(s.to_string()),
360 None => None,
361 }
362 }
363
364 pub fn get_all_modules_recursively(&self) -> Vec<&FlatpakModuleItem> {
365 let mut all_modules: Vec<&FlatpakModuleItem> = vec![];
366 let mut next_modules: Vec<&FlatpakModuleItem> = vec![];
367 for module in &self.modules {
368 next_modules.push(module);
369 }
370 while !next_modules.is_empty() {
371 let module = next_modules.pop().unwrap();
372 all_modules.push(module);
373
374 let module = match module {
375 FlatpakModuleItem::Description(d) => d,
376 FlatpakModuleItem::Path(_) => continue,
377 };
378 for next_module in &module.modules {
379 next_modules.push(next_module);
380 }
381 }
382 all_modules
383 }
384
385 pub fn is_composite(&self) -> bool {
388 let mut code_sources_count = 0;
389 for source in &self.sources {
390 let source_description = match source {
391 FlatpakSourceItem::Description(d) => d,
392 FlatpakSourceItem::Path(_) => continue,
393 };
394
395 let source_type = match source_description.get_type() {
396 Some(t) => t,
397 None => continue,
398 };
399
400 if source_type.is_code() {
401 code_sources_count += 1;
402 }
403 if code_sources_count > 1 {
404 return true;
405 }
406 }
407 false
408 }
409
410 pub fn get_commands<I, S>(
412 &self,
413 args: I,
414 reconfigure: bool,
415 root_path: &str,
416 build_path: &str,
417 out_path: Option<&str>,
418 num_cpus: i64,
419 ) -> Vec<Command>
420 where
421 I: IntoIterator<Item = S>,
422 S: AsRef<OsStr>,
423 {
424 let args: Vec<_> = args.into_iter().collect();
425
426 let out_path = out_path.unwrap_or("/app");
427
428 let build_system = self
429 .buildsystem
430 .to_owned()
431 .unwrap_or(FlatpakBuildSystem::default());
432
433 match build_system {
434 FlatpakBuildSystem::Autotools => {
435 let mut commands = Vec::new();
436
437 if !reconfigure {
438 let mut cmd = Command::new("./configure");
439 cmd.arg(format!("--prefix={}", out_path));
440 cmd.args(self.config_opts.clone());
441 cmd.current_dir(root_path);
442 commands.push(cmd);
443 }
444
445 let mut cmd = Command::new("make");
446 cmd.args(&["-p", "-n", "-s"]);
447 cmd.current_dir(root_path);
448 commands.push(cmd);
449
450 let mut cmd = Command::new("make");
451 cmd.arg("V=0");
452 cmd.arg(format!("-j{}", num_cpus));
453 cmd.arg("install");
454 cmd.args(args);
455 cmd.current_dir(root_path);
456 commands.push(cmd);
457
458 commands
459 }
460 FlatpakBuildSystem::CMake | FlatpakBuildSystem::CMakeNinja => {
461 let mut commands = Vec::new();
462
463 if !reconfigure {
464 let mut cmd = Command::new("mkdir");
465 cmd.arg("-p").arg(build_path);
466 commands.push(cmd);
467
468 let mut cmd = Command::new("cmake");
469 cmd.args(&["-G", "Ninja", "..", "."]);
470 cmd.arg("-DCMAKE_EXPORT_COMPILE_COMMANDS=1");
471 cmd.arg("-DCMAKE_BUILD_TYPE=RelWithDebInfo");
472 cmd.arg(format!("-DCMAKE_INSTALL_PREFIX={}", out_path));
473 cmd.args(self.config_opts.clone());
474 cmd.current_dir(build_path);
475 commands.push(cmd);
476 }
477
478 let mut cmd = Command::new("ninja");
479 cmd.current_dir(build_path);
480 commands.push(cmd);
481
482 let mut cmd = Command::new("ninja");
483 cmd.arg("install");
484 cmd.current_dir(build_path);
485 commands.push(cmd);
486
487 commands
488 }
489 FlatpakBuildSystem::Meson => {
490 let mut commands = Vec::new();
491
492 if !reconfigure {
493 let mut cmd = Command::new("meson");
494 cmd.arg(format!("--prefix={}", out_path));
495 cmd.arg(build_path);
496 cmd.args(self.config_opts.clone());
497 cmd.current_dir(root_path);
498 commands.push(cmd);
499 }
500
501 let mut cmd = Command::new("ninja");
502 cmd.arg("-C");
503 cmd.arg(build_path);
504 cmd.current_dir(root_path);
505 commands.push(cmd);
506
507 let mut cmd = Command::new("meson");
508 cmd.args(args);
509 cmd.args(&["install", "-C"]);
510 cmd.arg(build_path);
511 cmd.current_dir(root_path);
512 commands.push(cmd);
513
514 commands
515 }
516 FlatpakBuildSystem::QMake => panic!("Not implemented yet."),
517 FlatpakBuildSystem::Simple => self
518 .build_commands
519 .iter()
520 .map(|step| {
521 let mut cmd = Command::new("/bin/sh");
522 cmd.arg("-c");
523 cmd.arg(step);
524 cmd.current_dir(root_path);
525 cmd
526 })
527 .collect(),
528 }
529 }
530}
531
532#[derive(Clone)]
533#[derive(Deserialize)]
534#[derive(Serialize)]
535#[derive(Debug)]
536#[derive(Hash)]
537#[serde(untagged)]
538pub enum FlatpakBuildOptionsEnv {
544 Dict(BTreeMap<String, String>),
545 Array(Vec<String>),
546}
547impl Default for FlatpakBuildOptionsEnv {
548 fn default() -> Self {
549 FlatpakBuildOptionsEnv::Array(vec![])
550 }
551}
552
553#[derive(Clone)]
554#[derive(Deserialize)]
555#[derive(Serialize)]
556#[derive(Debug)]
557#[derive(Default)]
558#[derive(Hash)]
559#[serde(rename_all = "kebab-case")]
560#[serde(default)]
561pub struct FlatpakBuildOptions {
565 #[serde(skip_serializing_if = "String::is_empty")]
568 pub cflags: String,
569
570 #[serde(skip_serializing_if = "Option::is_none")]
572 pub cflags_override: Option<bool>,
573
574 #[serde(skip_serializing_if = "String::is_empty")]
577 pub cppflags: String,
578
579 #[serde(skip_serializing_if = "Option::is_none")]
581 pub cppflags_override: Option<bool>,
582
583 #[serde(skip_serializing_if = "String::is_empty")]
586 pub cxxflags: String,
587
588 #[serde(skip_serializing_if = "Option::is_none")]
590 pub cxxflags_override: Option<bool>,
591
592 #[serde(skip_serializing_if = "String::is_empty")]
596 pub ldflags: String,
597
598 #[serde(skip_serializing_if = "Option::is_none")]
600 pub ldflags_override: Option<bool>,
601
602 #[serde(skip_serializing_if = "String::is_empty")]
604 pub prefix: String,
605
606 #[serde(skip_serializing_if = "String::is_empty")]
608 pub libdir: String,
609
610 #[serde(skip_serializing_if = "String::is_empty")]
612 pub append_path: String,
613
614 #[serde(skip_serializing_if = "String::is_empty")]
616 pub prepend_path: String,
617
618 #[serde(skip_serializing_if = "String::is_empty")]
620 pub append_ld_library_path: String,
621
622 #[serde(skip_serializing_if = "String::is_empty")]
624 pub prepend_ld_library_path: String,
625
626 #[serde(skip_serializing_if = "String::is_empty")]
628 pub append_pkg_config_path: String,
629
630 #[serde(skip_serializing_if = "String::is_empty")]
632 pub prepend_pkg_config_path: String,
633
634 pub env: FlatpakBuildOptionsEnv,
635
636 #[serde(skip_serializing_if = "Vec::is_empty")]
638 pub build_args: Vec<String>,
639
640 #[serde(skip_serializing_if = "Vec::is_empty")]
642 pub test_args: Vec<String>,
643
644 #[serde(skip_serializing_if = "Vec::is_empty")]
646 pub config_opts: Vec<String>,
647
648 #[serde(skip_serializing_if = "Vec::is_empty")]
650 pub make_args: Vec<String>,
651
652 #[serde(skip_serializing_if = "Vec::is_empty")]
654 pub make_install_args: Vec<String>,
655
656 #[serde(skip_serializing_if = "Option::is_none")]
658 pub strip: Option<bool>,
659
660 #[serde(skip_serializing_if = "Option::is_none")]
664 pub no_debuginfo: Option<bool>,
665
666 #[serde(skip_serializing_if = "Option::is_none")]
669 pub no_debuginfo_compression: Option<bool>,
670
671 #[serde(skip_serializing_if = "BTreeMap::is_empty")]
673 pub arch: BTreeMap<String, FlatpakBuildOptions>,
674}
675
676#[cfg(test)]
677mod tests {
678 use super::*;
679
680 #[test]
681 pub fn test_parse_build_options() {
682 let module_manifest = r###"
683 name: "flatpak-rs"
684 buildsystem: simple
685 cleanup: [ "*" ]
686 build-options:
687 cflags: "-O2 -g"
688 cxxflags: "-O2 -g"
689 env:
690 V: "1"
691 X: "2"
692 arch:
693 x86_64:
694 cflags: "-O3 -g"
695 config-opts: []
696 sources:
697 -
698 "shared-modules/linux-audio/lv2.json"
699 "###;
700 match FlatpakModule::parse(FlatpakManifestFormat::YAML, module_manifest) {
701 Err(e) => std::panic::panic_any(e),
702 Ok(module) => {
703 assert_eq!(module.name, "flatpak-rs");
704 assert!(module.build_options.is_some());
705 let env: BTreeMap<String, String> = match module.build_options.unwrap().env {
706 FlatpakBuildOptionsEnv::Dict(env) => env,
707 FlatpakBuildOptionsEnv::Array(env) => panic!("Env should be a dict."),
708 };
709 assert_eq!(env.get("V").unwrap(), "1");
710 assert_eq!(env.get("X").unwrap(), "2");
711 }
712 }
713 }
714
715 #[test]
716 pub fn test_parse_build_options_env() {
717 let module_manifest = r###"
718 name: "flatpak-rs"
719 buildsystem: simple
720 cleanup: [ "*" ]
721 build-options:
722 cflags: "-O2 -g"
723 cxxflags: "-O2 -g"
724 env:
725 - "V=1"
726 - "Y=2"
727 arch:
728 x86_64:
729 cflags: "-O3 -g"
730 config-opts: []
731 sources:
732 -
733 "shared-modules/linux-audio/lv2.json"
734 "###;
735 match FlatpakModule::parse(FlatpakManifestFormat::YAML, module_manifest) {
736 Err(e) => std::panic::panic_any(e),
737 Ok(module) => {
738 assert_eq!(module.name, "flatpak-rs");
739 assert!(module.build_options.is_some());
740 let env: Vec<String> = match module.build_options.unwrap().env {
741 FlatpakBuildOptionsEnv::Array(env) => env,
742 FlatpakBuildOptionsEnv::Dict(env) => panic!("Env should be an array."),
743 };
744 assert_eq!(env, vec!["V=1", "Y=2"]);
745 }
746 }
747 }
748
749 #[test]
750 #[ignore]
751 pub fn test_parse_builddir() {
752 let module_manifest = r###"
755 name: fmt
756 buildsystem: cmake-ninja
757 builddir: yes
758 config-opts:
759 - "-DFMT_TEST=OFF"
760 sources:
761 - type: git
762 url: https://github.com/fmtlib/fmt.git
763 commit: 561834650aa77ba37b15f7e5c9d5726be5127df9
764 "###;
765 match FlatpakModule::parse(FlatpakManifestFormat::YAML, module_manifest) {
766 Err(e) => std::panic::panic_any(e),
767 Ok(module) => {
768 assert_eq!(module.name, "fmt");
769 }
770 }
771 }
772
773 #[test]
774 pub fn test_parse_extra_data() {
775 let module_manifest = r###"
776 name: wps
777 buildsystem: simple
778 build-commands:
779 - install -Dm755 apply_extra.sh /app/bin/apply_extra
780 - install -Dm755 wps.sh /app/bin/wps
781 - ln -s wps /app/bin/et
782 - ln -s wps /app/bin/wpp
783 - ln -s wps /app/bin/wpspdf
784 - install -Dm644 ${FLATPAK_ID}.metainfo.xml -t /app/share/metainfo/
785 - install -Dm755 /usr/bin/desktop-file-edit -t /app/bin/
786 - install -Dm755 /usr/bin/ar -t /app/bin/
787 - install -Dm755 /usr/lib/$(gcc -print-multiarch)/libbfd-*.so -t /app/lib/
788 sources:
789 - type: file
790 path: apply_extra.sh
791
792 - type: file
793 path: com.wps.Office.metainfo.xml
794
795 - type: file
796 path: wps.sh
797
798 - type: extra-data
799 filename: wps-office.deb
800 only-arches:
801 - x86_64
802 url: https://wdl1.pcfg.cache.wpscdn.com/wps-office_11.1.0.10702.XA_amd64.deb
803 sha256: 390a8b358aaccdfda54740d10d5306c2543c5cd42a7a8fd5c776ccff38492992
804 size: 275210770
805 installed-size: 988671247
806 x-checker-data:
807 type: html
808 url: https://linux.wps.com/js/meta.js
809 version-pattern: version\s*=\s*"([\d.-]+)"
810 url-pattern: download_link_deb\s*=\s*"(http[s]?://[\w\d$-_@.&+]+)"
811 "###;
812 let module = FlatpakModule::parse(FlatpakManifestFormat::YAML, module_manifest).unwrap();
813 assert_eq!(module.name, "wps");
814 }
815
816 #[test]
817 pub fn test_parse_helm_files() {
818 let helm_file = r###"
819 name: wps
820 sources:
821 - "https://github.com/user/repo"
822 "###;
823 assert!(FlatpakModule::parse(FlatpakManifestFormat::YAML, helm_file,).is_err())
824 }
825
826 #[test]
827 pub fn test_parse_invalid_source() {
828 let file = r###"
829 name: wps
830 sources:
831 - path: "^empty\\.c$"
832 isGenerated: false
833 sourceGroupName: "Source Files",
834 compileGroupLanguage: C
835 "###;
836 assert!(FlatpakModule::parse(FlatpakManifestFormat::YAML, file).is_err())
837 }
838
839 #[test]
840 pub fn test_parse_no_buildsystem() {
841 let module_manifest = r###"
842 name: dbus-glib
843 sources:
844 - type: archive
845 url: "https://dbus.freedesktop.org/releases/dbus-glib/dbus-glib-0.110.tar.gz"
846 sha256: 7ce4760cf66c69148f6bd6c92feaabb8812dee30846b24cd0f7395c436d7e825
847 config-opts:
848 - "--disable-static"
849 - "--disable-gtk-doc"
850 cleanup:
851 - "*.la"
852 - /bin
853 - /etc
854 - /include
855 - /libexec
856 - /share/gtk-doc
857 - /share/man
858 "###;
859 let flatpak_application = FlatpakModule::parse(FlatpakManifestFormat::YAML, module_manifest).unwrap();
860 assert!(flatpak_application.buildsystem.is_none());
861
862 let application_dump = flatpak_application.dump().unwrap();
863 assert!(!application_dump.contains("buildsystem"))
864 }
865}