package filesystem import ( "encoding/base64" "fmt" "os" "path/filepath" "strings" "golang.org/x/mod/semver" ) type DirEntry struct { Name string Content string IsFile bool Permissions os.FileMode } // FilterDirForEntryFile filers the given dirEntries, returns entries of the entryFile and .env file func FilterDirForEntryFile(dirEntries []DirEntry, entryFile string) []DirEntry { var filteredDirEntries []DirEntry dotEnvFile := filepath.Join(filepath.Dir(entryFile), ".env") filters := []string{entryFile, dotEnvFile} for _, dirEntry := range dirEntries { match := false if dirEntry.IsFile { for _, filter := range filters { if filter == dirEntry.Name { match = true break } } } else { for _, filter := range filters { if strings.HasPrefix(filter, dirEntry.Name) { match = true break } } } if match { filteredDirEntries = append(filteredDirEntries, dirEntry) } } return filteredDirEntries } // FilterDirForCompatibility returns the content of the entry file if agent version is less than 2.19.0 func FilterDirForCompatibility(dirEntries []DirEntry, entryFilePath, agentVersion string) (string, error) { if semver.Compare("v"+agentVersion, "v2.19.0") == -1 { for _, dirEntry := range dirEntries { if dirEntry.IsFile { if dirEntry.Name == entryFilePath { return DecodeFileContent(dirEntry.Content) } } } return "", fmt.Errorf("Entry file %s not found in dir entries", entryFilePath) } return "", nil } // LoadDir reads all files and folders recursively from the given directory // File content is base64-encoded func LoadDir(dir string) ([]DirEntry, error) { var dirEntries []DirEntry err := filepath.WalkDir( dir, func(path string, d os.DirEntry, err error) error { if err != nil { return err } fileInfo, err := d.Info() if err != nil { return err } relativePath, err := filepath.Rel(dir, path) if err != nil { return err } if relativePath == "." { return nil } dirEntry := DirEntry{ Name: relativePath, Permissions: fileInfo.Mode().Perm(), } if !fileInfo.IsDir() { // Read file contents fileContent, err := os.ReadFile(path) if err != nil { return err } dirEntry.Content = base64.StdEncoding.EncodeToString(fileContent) dirEntry.IsFile = true } dirEntries = append(dirEntries, dirEntry) return nil }) if err != nil { return nil, err } return dirEntries, nil } // PersistDir writes the provided array of files and folders back to the given directory. func PersistDir(dir string, dirEntries []DirEntry) error { for _, dirEntry := range dirEntries { path := filepath.Join(dir, dirEntry.Name) if dirEntry.IsFile { // Create the directory path if it doesn't exist err := os.MkdirAll(filepath.Dir(path), 0744) if err != nil { return err } // Write file contents err = os.WriteFile(path, []byte(dirEntry.Content), dirEntry.Permissions) if err != nil { return err } } else { // Create the directory err := os.MkdirAll(path, dirEntry.Permissions) if err != nil { return err } } } return nil } func DecodeFileContent(encodedFileContent string) (string, error) { decodedBytes, err := base64.StdEncoding.DecodeString(encodedFileContent) if err != nil { return "", err } return string(decodedBytes), nil } func DecodeDirEntries(dirEntries []DirEntry) error { for index, dirEntry := range dirEntries { if dirEntry.IsFile && dirEntry.Content != "" { decodedFile, err := DecodeFileContent(dirEntry.Content) if err != nil { return err } dirEntries[index].Content = decodedFile } } return nil }