1use globset::{Glob, GlobMatcher, GlobSet, GlobSetBuilder};
50use std::env;
51use std::fs::create_dir_all;
52use std::path::{Path, PathBuf};
53use walkdir::WalkDir;
54
55pub fn copy_glob(glob: impl AsRef<str>, output_dir: impl AsRef<Path>) {
56 let options = CopyGlobOptionsBuilder::new().build();
57 copy_glob_with(glob, output_dir, &options);
58}
59
60pub fn copy_glob_with(
61 glob: impl AsRef<str>,
62 output_dir: impl AsRef<Path>,
63 options: &CopyGlobOptions,
64) {
65 let glob = glob.as_ref();
66 let matcher = new_glob(glob);
67 let current_dir = options.root.as_ref();
68
69 if !output_dir.as_ref().exists() {
70 create_dir_all(&output_dir).unwrap();
71 }
72
73 for entry in WalkDir::new(¤t_dir) {
74 let entry = entry.expect("Unable to read dir");
75 if options.exclude.is_match(entry.path()) || !matcher.is_match(entry.path()) {
76 continue;
77 }
78
79 let path = entry.path().display();
80 println!("cargo:rerun-if-changed={path}");
81
82 let metadata = entry.metadata().expect("Unable to get metadata");
83 let dirname = get_str(entry.path())
84 .strip_prefix(get_str(current_dir))
85 .expect("Unable to strip a string")
86 .trim_start_matches("\\")
87 .trim_start_matches("/");
88 let output_path = output_dir.as_ref().join(dirname);
89
90 if metadata.is_dir() {
91 create_dir_all(output_path).expect("Unable to create output dir");
92 } else if metadata.is_file() {
93 let parent = output_path.parent().unwrap();
94
95 if parent.exists() {
96 std::fs::copy(entry.path(), output_path).expect("Unable to copy file");
97 } else {
98 std::fs::copy(entry.path(), output_dir.as_ref().join(entry.file_name()))
99 .expect("Unable to copy file");
100 }
101 }
102 }
103}
104
105pub struct CopyGlobOptions {
106 root: PathBuf,
107 exclude: GlobSet,
108}
109
110pub struct CopyGlobOptionsBuilder {
111 root: PathBuf,
112 exclude: GlobSetBuilder,
113}
114
115impl CopyGlobOptionsBuilder {
116 pub fn new() -> Self {
117 let root = get_root_path();
118 let mut exclude = GlobSet::builder();
119
120 exclude.add(Glob::new("**/target/*").unwrap());
121
122 Self { root, exclude }
123 }
124}
125
126impl CopyGlobOptionsBuilder {
127 pub fn set_root_path(mut self, root: impl AsRef<Path>) -> Self {
128 self.root = root.as_ref().to_path_buf();
129 self
130 }
131
132 pub fn add_exclude(mut self, glob: impl AsRef<str>) -> Self {
133 self.exclude.add(Glob::new(glob.as_ref()).unwrap());
134 self
135 }
136
137 pub fn build(self) -> CopyGlobOptions {
138 CopyGlobOptions {
139 root: self.root,
140 exclude: self.exclude.build().unwrap(),
141 }
142 }
143}
144
145pub fn new_glob(glob: impl AsRef<str>) -> GlobMatcher {
146 Glob::new(glob.as_ref())
147 .expect("Wrong pattern")
148 .compile_matcher()
149}
150
151pub fn get_target_folder() -> PathBuf {
152 let path = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()).join("target");
153
154 #[cfg(debug_assertions)]
155 return path.join("debug");
156
157 #[cfg(not(debug_assertions))]
158 return path.join("release");
159}
160
161pub fn get_root_path() -> PathBuf {
162 PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap())
163}
164
165fn get_str(path: &Path) -> &str {
166 path.to_str().expect("Unable to convert path to str")
167}