diff --git a/.changes/resource-path-cur-dir.md b/.changes/resource-path-cur-dir.md new file mode 100644 index 000000000000..be4df9b3a88b --- /dev/null +++ b/.changes/resource-path-cur-dir.md @@ -0,0 +1,5 @@ +--- +"tauri-utils": patch:bug +--- + +Fix resource path handles `./` path differently (e.g. `./some-folder` should be the same as `some-folder`) diff --git a/.github/workflows/test-core.yml b/.github/workflows/test-core.yml index b84f4e09eb8c..59f393c314ef 100644 --- a/.github/workflows/test-core.yml +++ b/.github/workflows/test-core.yml @@ -93,11 +93,23 @@ jobs: prefix-key: v3 save-if: ${{ matrix.features.key == 'all' }} - - name: test + - name: test tauri-utils + if: ${{ !matrix.platform.cross }} + # Using --lib --bins --tests to skip doc tests + run: cargo ${{ matrix.platform.command }} --target ${{ matrix.platform.target }} ${{ matrix.features.args }} --lib --bins --tests --manifest-path crates/tauri-utils/Cargo.toml + + - name: test tauri-utils (using cross) + if: ${{ matrix.platform.cross }} + # Using --lib --bins --tests to skip doc tests + run: | + cargo install cross --git https://github.com/cross-rs/cross --rev 51f46f296253d8122c927c5bb933e3c4f27cc317 --locked + cross ${{ matrix.platform.command }} --target ${{ matrix.platform.target }} ${{ matrix.features.args }} --lib --bins --tests --manifest-path crates/tauri-utils/Cargo.toml + + - name: test tauri if: ${{ !matrix.platform.cross }} run: cargo ${{ matrix.features.key == 'no-default' && 'check' || matrix.platform.command }} --target ${{ matrix.platform.target }} ${{ matrix.features.args }} --manifest-path crates/tauri/Cargo.toml - - name: test (using cross) + - name: test tauri (using cross) if: ${{ matrix.platform.cross }} run: | cargo install cross --git https://github.com/cross-rs/cross --rev 51f46f296253d8122c927c5bb933e3c4f27cc317 --locked diff --git a/crates/tauri-utils/src/resources.rs b/crates/tauri-utils/src/resources.rs index dfba0746c960..3fd0290b78ac 100644 --- a/crates/tauri-utils/src/resources.rs +++ b/crates/tauri-utils/src/resources.rs @@ -97,9 +97,8 @@ impl<'a> ResourcePaths<'a> { iter: ResourcePathsIter { pattern_iter: PatternIter::Slice(patterns.iter()), allow_walk, - current_pattern: None, - walk_iter: None, - glob_iter: None, + current_dest: None, + current_iter: None, }, } } @@ -110,9 +109,8 @@ impl<'a> ResourcePaths<'a> { iter: ResourcePathsIter { pattern_iter: PatternIter::Map(patterns.iter()), allow_walk, - current_pattern: None, - walk_iter: None, - glob_iter: None, + current_dest: None, + current_iter: None, }, } } @@ -132,122 +130,139 @@ pub struct ResourcePathsIter<'a> { /// whether the resource paths allows directories or not. allow_walk: bool, - /// The (key, value) of map when `pattern_iter` is a [`PatternIter::Map`], + /// The value of map when [`Self::pattern_iter`] is a [`PatternIter::Map`], /// used for determining [`Resource::target`] - current_pattern: Option<(String, PathBuf)>, - - walk_iter: Option, - glob_iter: Option, + current_dest: Option, + /// The iter for the current pattern. The cycle goes like this: + /// [`ResourcePaths::next`] -> [`Self::next`] -> [`Self::pattern_iter::next`] -> [`Self::current_iter::next`] + current_iter: Option, } -impl ResourcePathsIter<'_> { - fn next_glob_iter(&mut self) -> Option> { - let entry = self.glob_iter.as_mut().unwrap().next()?; +#[derive(Debug)] +enum ResourcePathsInnerIter { + Walk { + iter: walkdir::IntoIter, + /// The key of map when [`ResourcePathsIter::pattern_iter`] is a [`PatternIter::Map`], + /// used for determining [`Resource::target`] + current_pattern: Option, + }, + Glob { + iter: glob::Paths, + }, +} - let entry = match entry { - Ok(entry) => entry, - Err(err) => return Some(Err(err.into())), - }; +impl Iterator for ResourcePathsInnerIter { + type Item = crate::Result; - self.next_current_path(normalize(&entry)) + fn next(&mut self) -> Option> { + match self { + ResourcePathsInnerIter::Walk { iter, .. } => Some( + iter + .next()? + .map(|entry| entry.into_path()) + .map_err(Into::into), + ), + ResourcePathsInnerIter::Glob { iter } => Some(iter.next()?.map_err(Into::into)), + } } +} - fn next_walk_iter(&mut self) -> Option> { - let entry = self.walk_iter.as_mut().unwrap().next()?; - - let entry = match entry { - Ok(entry) => entry, - Err(err) => return Some(Err(err.into())), - }; - - self.next_current_path(normalize(entry.path())) +impl ResourcePathsIter<'_> { + fn next_current_iter(&mut self) -> Option> { + let current_iter = self.current_iter.as_mut().unwrap(); + let entry = current_iter.next()?; + + Some(match entry { + Ok(entry) => { + // Skip directories + if entry.is_dir() { + self.next_current_iter()? + } else { + self.resource_from_path(normalize(&entry)) + } + } + Err(error) => Err(error), + }) } - fn resource_from_path(&mut self, path: &Path) -> crate::Result { + fn resource_from_path(&self, path: PathBuf) -> crate::Result { if !path.exists() { - return Err(crate::Error::ResourcePathNotFound(path.to_path_buf())); + return Err(crate::Error::ResourcePathNotFound(path)); } Ok(Resource { - path: path.to_path_buf(), - target: if let Some((pattern, dest)) = &self.current_pattern { - // if processing a directory, preserve directory structure under current_dest - if self.walk_iter.is_some() { - dest.join(path.strip_prefix(pattern).unwrap_or(path)) - } else if dest.components().count() == 0 { - // if current_dest is empty while processing a file pattern or glob - // we preserve the file name as it is - PathBuf::from(path.file_name().unwrap()) - } else if self.glob_iter.is_some() { - // if processing a glob and current_dest is not empty - // we put all globbed paths under current_dest - // preserving the file name as it is - dest.join(path.file_name().unwrap()) - } else { - dest.clone() + target: if let Some(dest) = &self.current_dest { + match &self.current_iter { + Some(current_iter) => match current_iter { + // if processing a directory, preserve directory structure under current_dest + ResourcePathsInnerIter::Walk { + current_pattern, .. + } => { + if let Some(pattern) = current_pattern { + dest.join(path.strip_prefix(pattern).unwrap_or(&path)) + } else { + dest.join(&path) + } + } + // if processing a glob and current_dest is not empty + // we put all globbed paths under current_dest + // preserving the file name as it is + ResourcePathsInnerIter::Glob { .. } => dest.join(path.file_name().unwrap()), + }, + None => dest.clone(), } } else { - // If `pattern_iter` is a [`PatternIter::Slice`] - resource_relpath(path) + // If [`ResourcePathsIter::pattern_iter`] is a [`PatternIter::Slice`] + resource_relpath(&path) }, + path, }) } - fn next_current_path(&mut self, path: PathBuf) -> Option> { - let is_dir = path.is_dir(); - - if is_dir { - if self.glob_iter.is_some() { - return self.next(); - } - - if !self.allow_walk { - return Some(Err(crate::Error::NotAllowedToWalkDir(path.to_path_buf()))); - } - - if self.walk_iter.is_none() { - self.walk_iter = Some(WalkDir::new(&path).into_iter()); - } - - match self.next_walk_iter() { - Some(resource) => Some(resource), - None => { - self.walk_iter = None; - self.next() - } - } - } else { - Some(self.resource_from_path(&path)) - } - } - fn next_pattern(&mut self) -> Option> { - self.current_pattern = None; + self.current_dest = None; let pattern = match &mut self.pattern_iter { PatternIter::Slice(iter) => iter.next()?, PatternIter::Map(iter) => { let (pattern, dest) = iter.next()?; - self.current_pattern = Some((pattern.clone(), resource_relpath(Path::new(dest)))); + self.current_dest = Some(resource_relpath(Path::new(dest))); pattern } }; if pattern.contains('*') { - self.glob_iter = match glob::glob(pattern) { - Ok(glob) => Some(glob), + self.current_iter = match glob::glob(pattern) { + Ok(glob) => Some(ResourcePathsInnerIter::Glob { iter: glob }), Err(error) => return Some(Err(error.into())), }; - match self.next_glob_iter() { + match self.next_current_iter() { Some(r) => return Some(r), None => { - self.glob_iter = None; + self.current_iter = None; return Some(Err(crate::Error::GlobPathNotFound(pattern.clone()))); } } + } else { + let path = normalize(Path::new(pattern)); + if path.is_dir() { + if !self.allow_walk { + return Some(Err(crate::Error::NotAllowedToWalkDir(path))); + } + self.current_iter = Some(ResourcePathsInnerIter::Walk { + iter: WalkDir::new(&path).into_iter(), + current_pattern: if matches!(self.pattern_iter, PatternIter::Map(_)) { + Some(path) + } else { + None + }, + }); + } else { + return Some(self.resource_from_path(path)); + } } - self.next_current_path(normalize(Path::new(pattern))) + self.next_current_iter() } } @@ -263,17 +278,10 @@ impl Iterator for ResourcePathsIter<'_> { type Item = crate::Result; fn next(&mut self) -> Option> { - if self.walk_iter.is_some() { - match self.next_walk_iter() { + if self.current_iter.is_some() { + match self.next_current_iter() { Some(r) => return Some(r), - None => self.walk_iter = None, - } - } - - if self.glob_iter.is_some() { - match self.next_glob_iter() { - Some(r) => return Some(r), - None => self.glob_iter = None, + None => self.current_iter = None, } } @@ -322,6 +330,7 @@ mod tests { "src-tauri/Cargo.toml", "src-tauri/Tauri.toml", "src-tauri/build.rs", + "src-tauri/some-folder/some-file.txt", "src/assets/javascript.svg", "src/assets/tauri.svg", "src/assets/rust.svg", @@ -403,11 +412,11 @@ mod tests { // From `../src/textures/**/*` ( "../src/textures/ground/earth.tex", - "_up_/src/textures/earth.tex", + "_up_/src/textures/ground/earth.tex", ), ( "../src/textures/ground/sand.tex", - "_up_/src/textures/sand.tex", + "_up_/src/textures/ground/sand.tex", ), ("../src/textures/water.tex", "_up_/src/textures/water.tex"), ("../src/textures/fire.tex", "_up_/src/textures/fire.tex"), @@ -483,6 +492,7 @@ mod tests { ("../src/tiles/**/*", "tiles"), ("*.toml", ""), ("*.conf.json", "json"), + ("./some-folder/", "some-target-folder/"), ("../non-existent-file", "asd"), // invalid case ("../non/*", "asd"), // invalid case ]), @@ -511,6 +521,10 @@ mod tests { ("Cargo.toml", "Cargo.toml"), ("Tauri.toml", "Tauri.toml"), ("tauri.conf.json", "json/tauri.conf.json"), + ( + "some-folder/some-file.txt", + "some-target-folder/some-file.txt", + ), ]); assert_eq!(resources.len(), expected.len()); @@ -584,7 +598,7 @@ mod tests { .iter() .collect::>(); - assert_eq!(resources.len(), 4); + assert_eq!(resources.len(), 5); assert!(resources.iter().all(|r| r.is_err())); @@ -617,7 +631,7 @@ mod tests { .iter() .filter(|r| matches!(r, Err(crate::Error::GlobPathNotFound(_)))) .count(), - 1 + 2 ); } }