fix: add find-files (#109)
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				Update alr-git / changelog (push) Successful in 31s
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	Update alr-git / changelog (push) Successful in 31s
				
			closes #96 Reviewed-on: #109 Co-authored-by: Maxim Slipenko <no-reply@maxim.slipenko.com> Co-committed-by: Maxim Slipenko <no-reply@maxim.slipenko.com>
This commit is contained in:
		
							
								
								
									
										178
									
								
								internal/shutils/helpers/files_find.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										178
									
								
								internal/shutils/helpers/files_find.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,178 @@ | ||||
| // ALR - Any Linux Repository | ||||
| // Copyright (C) 2025 The ALR Authors | ||||
| // | ||||
| // This program is free software: you can redistribute it and/or modify | ||||
| // it under the terms of the GNU General Public License as published by | ||||
| // the Free Software Foundation, either version 3 of the License, or | ||||
| // (at your option) any later version. | ||||
| // | ||||
| // This program is distributed in the hope that it will be useful, | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| // GNU General Public License for more details. | ||||
| // | ||||
| // You should have received a copy of the GNU General Public License | ||||
| // along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  | ||||
| package helpers | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"log/slog" | ||||
| 	"os" | ||||
| 	"path" | ||||
| 	"path/filepath" | ||||
|  | ||||
| 	"github.com/bmatcuk/doublestar/v4" | ||||
| 	"mvdan.cc/sh/v3/interp" | ||||
| ) | ||||
|  | ||||
| func matchNamePattern(name, pattern string) bool { | ||||
| 	matched, err := filepath.Match(pattern, name) | ||||
| 	if err != nil { | ||||
| 		return false | ||||
| 	} | ||||
| 	return matched | ||||
| } | ||||
|  | ||||
| func validateDir(dirPath, commandName string) error { | ||||
| 	info, err := os.Stat(dirPath) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("%s: %w", commandName, err) | ||||
| 	} | ||||
| 	if !info.IsDir() { | ||||
| 		return fmt.Errorf("%s: %s is not a directory", commandName, dirPath) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func outputFiles(hc interp.HandlerContext, files []string) { | ||||
| 	for _, file := range files { | ||||
| 		fmt.Fprintln(hc.Stdout, file) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func makeRelativePath(basePath, fullPath string) (string, error) { | ||||
| 	relPath, err := filepath.Rel(basePath, fullPath) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	return "./" + relPath, nil | ||||
| } | ||||
|  | ||||
| func filesFindLangCmd(hc interp.HandlerContext, cmd string, args []string) error { | ||||
| 	namePattern := "*.mo" | ||||
| 	if len(args) > 0 { | ||||
| 		namePattern = args[0] + ".mo" | ||||
| 	} | ||||
|  | ||||
| 	localePath := "./usr/share/locale/" | ||||
| 	realPath := path.Join(hc.Dir, localePath) | ||||
|  | ||||
| 	if err := validateDir(realPath, "files-find-lang"); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	var langFiles []string | ||||
| 	err := filepath.Walk(realPath, func(p string, info os.FileInfo, err error) error { | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|  | ||||
| 		if !info.IsDir() && matchNamePattern(info.Name(), namePattern) { | ||||
| 			relPath, relErr := makeRelativePath(hc.Dir, p) | ||||
| 			if relErr != nil { | ||||
| 				return relErr | ||||
| 			} | ||||
| 			langFiles = append(langFiles, relPath) | ||||
| 		} | ||||
| 		return nil | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("files-find-lang: %w", err) | ||||
| 	} | ||||
|  | ||||
| 	outputFiles(hc, langFiles) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func filesFindDocCmd(hc interp.HandlerContext, cmd string, args []string) error { | ||||
| 	namePattern := "*" | ||||
| 	if len(args) > 0 { | ||||
| 		namePattern = args[0] | ||||
| 	} | ||||
|  | ||||
| 	docPath := "./usr/share/doc/" | ||||
| 	docRealPath := path.Join(hc.Dir, docPath) | ||||
|  | ||||
| 	if err := validateDir(docRealPath, "files-find-doc"); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	var docFiles []string | ||||
|  | ||||
| 	entries, err := os.ReadDir(docRealPath) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("files-find-doc: %w", err) | ||||
| 	} | ||||
|  | ||||
| 	for _, entry := range entries { | ||||
| 		if matchNamePattern(entry.Name(), namePattern) { | ||||
| 			targetPath := filepath.Join(docRealPath, entry.Name()) | ||||
| 			targetInfo, err := os.Stat(targetPath) | ||||
| 			if err != nil { | ||||
| 				return fmt.Errorf("files-find-doc: %w", err) | ||||
| 			} | ||||
| 			if targetInfo.IsDir() { | ||||
| 				err := filepath.Walk(targetPath, func(subPath string, subInfo os.FileInfo, subErr error) error { | ||||
| 					if subErr != nil { | ||||
| 						return subErr | ||||
| 					} | ||||
| 					relPath, err := makeRelativePath(hc.Dir, subPath) | ||||
| 					if err != nil { | ||||
| 						return err | ||||
| 					} | ||||
| 					docFiles = append(docFiles, relPath) | ||||
| 					return nil | ||||
| 				}) | ||||
| 				if err != nil { | ||||
| 					return fmt.Errorf("files-find-doc: %w", err) | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	outputFiles(hc, docFiles) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func filesFindCmd(hc interp.HandlerContext, cmd string, args []string) error { | ||||
| 	if len(args) == 0 { | ||||
| 		return fmt.Errorf("find-files: at least one glob pattern is required") | ||||
| 	} | ||||
|  | ||||
| 	var foundFiles []string | ||||
|  | ||||
| 	for _, globPattern := range args { | ||||
| 		searchPath := path.Join(hc.Dir, globPattern) | ||||
|  | ||||
| 		basepath, pattern := doublestar.SplitPattern(searchPath) | ||||
| 		fsys := os.DirFS(basepath) | ||||
| 		matches, err := doublestar.Glob(fsys, pattern, doublestar.WithNoFollow()) | ||||
| 		if err != nil { | ||||
| 			slog.Warn("find-files: invalid glob pattern", "pattern", globPattern, "error", err) | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		for _, match := range matches { | ||||
| 			relPath, err := makeRelativePath(hc.Dir, path.Join(basepath, match)) | ||||
| 			if err != nil { | ||||
| 				continue | ||||
| 			} | ||||
| 			foundFiles = append(foundFiles, relPath) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	outputFiles(hc, foundFiles) | ||||
| 	return nil | ||||
| } | ||||
		Reference in New Issue
	
	Block a user