1use std::io::{Error, ErrorKind};
12use std::path::{Path};
13use std::process::Command;
14
15pub type Result<T> = std::io::Result<T>;
17
18#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
20pub struct Archive<'a> {
21 pub java_home: Option<&'a Path>,
22
23 pub jar_file: Option<&'a Path>,
24 pub manifest_file: Option<&'a Path>,
25 pub entry_point: Option<String>,
26
27 pub verbose: bool,
28 pub pack200_normalization: bool,
29 pub uncompressed: bool,
30 pub preserve_original_filenames: bool,
31 pub no_manifest: bool,
32
33 pub files: &'a [(&'a Path, &'a [&'a Path])],
34
35 #[doc(hidden)] pub _non_exhaustive: (),
36}
37
38impl<'a> std::default::Default for Archive<'a> {
39 fn default() -> Self {
40 Self {
41 java_home: None,
42
43 jar_file: None,
44 manifest_file: None,
45 entry_point: None,
46
47 verbose: false,
48 pack200_normalization: false,
49 uncompressed: false,
50 preserve_original_filenames: false,
51 no_manifest: false,
52
53 files: &[][..],
54
55 _non_exhaustive: (),
56 }
57 }
58}
59
60impl<'a> Archive<'a> {
61 pub fn new() -> Self {
62 Default::default()
63 }
64
65 pub fn create(&self) -> Result<()> {
69 self.exec('c')
70 }
71
72 pub fn update(&self) -> Result<()> {
76 self.exec('u')
77 }
78
79 fn exec(&self, create_or_update: char) -> Result<()> {
80 let mut java_home_buf = None;
81 let java_home = self.java_home.or_else(||{
82 java_home_buf = Some(crate::search::find_java_home()?);
83 java_home_buf.as_ref().map(|p| &**p)
84 }).ok_or_else(||
85 Error::new(ErrorKind::NotFound, "JAVA_HOME not set and could not be found, unable to run")
86 )?;
87
88 let mut flags_arg = String::new();
89 for (flag, cond) in [
90 (create_or_update, true),
91 ('v', self.verbose),
92 ('f', self.jar_file.is_some()),
93 ('m', self.manifest_file.is_some()),
94 ('n', self.pack200_normalization),
95 ('e', self.entry_point.is_some()),
96 ('0', self.uncompressed),
97 ('P', self.preserve_original_filenames),
98 ('M', self.no_manifest),
99 ].iter().copied() {
100 if cond {
101 flags_arg.push(flag);
102 }
103 }
104
105 let mut cmd = Command::new(java_home.join("bin/jar"));
106 cmd.arg(&flags_arg);
107
108 if let Some(jar_file) = self.jar_file.as_ref() { cmd.arg(jar_file); }
109 if let Some(manifest_file) = self.manifest_file.as_ref() { cmd.arg(manifest_file); }
110 if let Some(entry_point) = self.entry_point.as_ref() { cmd.arg(entry_point); }
111
112 for (dir, files) in self.files {
113 cmd.arg("-C").arg(dir);
114 for file in *files {
115 cmd.arg(file);
116 }
117 }
118
119 let status = cmd.status()?;
120 if status.success() {
121 Ok(())
122 } else {
123 Err(Error::new(ErrorKind::Other, format!("jar {} ... failed: {:?}", &flags_arg, status)))
124 }
125 }
126}