package cssmerger import ( "fmt" "io" "log" "os" "path/filepath" ) // Первый аргумент - путь до директории, с которой будет начат рекурсивный поиск и склейка css файлов. // Второй аргумент - путь к мыходному файлу. // Третий аргумент - список имен файлов/директорий, которые надо проигнорировать. Если такого списка нет, стоит указать nil func Merge(root, output string, skipfiles []string) error { outFile, err := os.Create(output) if err != nil { log.Fatal("Output file create error") } defer outFile.Close() // Передаваемая вторым аргументам функция должна быть определенной сигнатуры (такой как тут) if err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { // Не работаем с файлам из skipfiles if stringSliceContains(skipfiles, info.Name()) { if !info.IsDir() { // Если это не директория, то сигнализируем, что работа с файлом завершена return nil } else { // Если это директория, то в нее не заходим return filepath.SkipDir } } // Работа с каждым css файлом if !info.IsDir() && filepath.Ext(info.Name()) == ".css" { file, err := os.Open(path) if err != nil { fmt.Printf("Failed to open %s file\n", path) return nil } data, err := io.ReadAll(file) if err != nil { fmt.Printf("Failed to read %s file\n", path) return nil } file.Close() n, err := outFile.Write(data) if err != nil { fmt.Printf("Failed to write %s file in %s\n", path, root) return nil } // Если был пустой css, то не добавится перенос строки if n > 0 { outFile.WriteString("\n") } } // Если возвращаемое значение nil, то обход продолжится return nil }); err != nil { return err } return nil } // Проверяет есть ли строка в срезе строк func stringSliceContains(s []string, e string) bool { for _, a := range s { if a == e { return true } } return false }