package main // yaml.v3 doesn't serialize multi-line strings // correctly for some reason, so we use v2. import ( "fmt" "gemif/pkg/gamemanager" "io/ioutil" "log" "os" "path/filepath" "regexp" "gopkg.in/yaml.v2" ) func readFile(path string) (string, error) { contents, err := ioutil.ReadFile(path) if err != nil { return "", fmt.Errorf("couldn't read file: %w", err) } return string(contents), nil } func findFilesWithExtension(root, pattern string) ([]string, error) { var matches []string err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { if err != nil { return fmt.Errorf("couldn't load directory %s: %w", root, err) } if info.IsDir() { return nil } if matched, err := filepath.Match(pattern, filepath.Base(path)); err != nil { return fmt.Errorf("couldn't check name of file %s: %w", path, err) } else if matched { matches = append(matches, path) } return nil }) if err != nil { return nil, fmt.Errorf("problem walking directory: %w", err) } return matches, nil } func processFile(path string) ([]gamemanager.Room, error) { roomParser := newRoomParser() fileRooms := []gamemanager.Room{} thisFile, err := readFile(path) if err != nil { return fileRooms, fmt.Errorf("couldn't read .gemif file: %w", err) } sceneSeparator := regexp.MustCompile("(?m)^---") for _, room := range sceneSeparator.Split(thisFile, -1) { if room == "" { continue } currentRoom, err := roomParser.findRoomInfo(room) if err != nil { log.Fatal(err) } currentRoom.Exits, err = roomParser.processExits(room) if err != nil { log.Fatal(err) } currentRoom.Description = roomParser.getRoomDescription(room) fileRooms = append(fileRooms, currentRoom) currentRoom = gamemanager.Room{} } return fileRooms, nil } func writeStory(story *gamemanager.Story, file string) error { storyOut, err := yaml.Marshal(story) if err != nil { return fmt.Errorf("couldn't serialize story: %w", err) } err = ioutil.WriteFile(file, storyOut, 0644) // #nosec G306 if err != nil { return fmt.Errorf("couldn't write compiled output: %w", err) } return nil } func main() { correctNumArguments := 3 if len(os.Args) != correctNumArguments { log.Fatal("Usage: gemifc [input_path] [output_path]") } inputPath := os.Args[1] outputPath := os.Args[2] fmt.Printf("Compiling story %s to %s\n", inputPath, outputPath) fileContents, err := readFile(fmt.Sprintf("%s/metadata.yml", inputPath)) if err != nil { log.Fatalf("Couldn't read metadata file: %s", err) } var metadata *gamemanager.StoryMetadata if err := yaml.Unmarshal([]byte(fileContents), &metadata); err != nil { log.Fatalf("Malformed metadata.yml: %s", err) } files, err := findFilesWithExtension(inputPath, "*.gemif") if err != nil { log.Fatalf("Couldn't load *.gemif files %s", err) } storyRooms := []gamemanager.Room{} for _, file := range files { fileRooms, err := processFile(file) if err != nil { log.Fatalf("Couldn't process file %s: %s", file, err) } storyRooms = append(storyRooms, fileRooms...) } story := gamemanager.Story{ Metadata: *metadata, Rooms: storyRooms, } fmt.Printf(` Finished loading story: Name: %s Author: %s Descriptions: %s Number of Rooms: %d `, story.Metadata.Name, story.Metadata.Author, story.Metadata.Description, len(story.Rooms)) fmt.Println("Serializing and writing to disk...") if err := writeStory(&story, fmt.Sprintf("%s/%s.yml", outputPath, story.Metadata.ID)); err != nil { log.Fatalf("Couldn't save story: %s", err) } fmt.Println("Done!") }