~hristoast/openmw-validator

ref: 16f8ae329052dc7b12b3a3c2296f3e00002fce77 openmw-validator/paths.go -rw-r--r-- 3.8 KiB
16f8ae32Hristos N. Triantafillou Better output 3 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
package main

import (
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"
)

// Represents attributes related to a configured data path: `files` for strings
// representing full paths to files within a data path, `plugins` for strings
// representing found plugin files, `order` an int for the numerical load order
// of the data path, and `path` which a string that is the path itself.
type dataDir struct {
	files   []*dataFile
	plugins []*dataFile
	order   int
	path    string
}

// Given a string `d` that represents a data path root, a string `p` that represents a
// top-level data directory, and a struct pointer `dp` that represents tha `dataDir`
// object: do `filepath.Walk` on `p` and list out all files within it, recursively.
// func checkDataDirs(d string, p string, dp *dataDir, gc *gameConfig) error {
func (d *dataDir) checkDataDirs(gc *gameConfig) error {
	pathContent, err := ioutil.ReadDir(d.path)
	if err != nil {
		return err
	}

	for _, pc := range pathContent {
		if pc.IsDir() {
			err = filepath.Walk(filepath.Join(d.path, pc.Name()),
				func(filePath string, info os.FileInfo, err error) error {
					if err != nil {
						return err
					}

					localPath := strings.Replace(filePath, d.path, "", -1)
					nfo, err := os.Stat(filePath)
					if err != nil {
						return err
					}

					if !nfo.IsDir() && !ignoredFile(filePath) {
						df := &dataFile{
							path:      filePath,
							localPath: localPath,
						}
						d.files = append(d.files, df)

						// Does gc.dataFiles already have this localPath stored as a key? If
						// so, check for an overwrite and log as needed.
						// THANKS: https://stackoverflow.com/a/2050629
						val, ok := alreadySaved(df.localPath, gc.dataFiles)
						if ok {
							gc.registerReplacement(df, val)
						}
						gc.dataFiles[localPath] = df

					}
					return nil
				})
			if err != nil {
				return err
			}

		} else {
			// This is a file, not a dir.
			path := filepath.Join(d.path, pc.Name())
			if !ignoredFile(path) {
				df := &dataFile{
					path:      path,
					localPath: pc.Name(),
				}
				val, ok := alreadySaved(df.localPath, gc.dataFiles)
				if ok {
					gc.registerReplacement(df, val)
				}

				if df.isPlugin() {
					d.plugins = append(d.plugins, df)
					gc.foundPlugins = append(gc.foundPlugins, df.path)
				}

				gc.dataFiles[df.localPath] = df
			}
		}
	}
	return err
}

// Helper method to detect if a particular data path `path` has already been stored.
func alreadyFound(path string, found map[string]bool) bool {
	if _, ok := found[path]; ok {
		return ok // true
	}
	return false
}

// Helper method to detect if a particular `localPath` has already been stored.
func alreadySaved(localPath string, files map[string]*dataFile) (*dataFile, bool) {
	if val, ok := files[localPath]; ok {
		return val, ok
	}
	return &dataFile{}, false
}

// Format a given string `dp` which is a `data=` entry from an openmw.cfg file
// as just the path with no extra quotes or anything. Check that it's a real
// thing, then scan it for files.
func checkDataPath(dp string, dataOrder int, gc *gameConfig) (*dataDir, error) {
	// Format the path...
	p := strings.Replace(dp, "data=", "", -1)
	p = strings.TrimPrefix(p, "'")
	p = strings.TrimPrefix(p, "\"")
	p = strings.TrimSuffix(p, "\r")
	p = strings.TrimSuffix(p, "'")
	p = strings.TrimSuffix(p, "\"")

	if !gc.runCfg.quiet {
		log.Printf("Checking: %v", p)
	}

	found := alreadyFound(p, gc.foundPaths)
	if found {
		log.Printf("Path already configured: %s", p)
		gc.duplicatePaths = append(gc.duplicatePaths, p)
	} else {
		gc.foundPaths[p] = true
	}

	_, err := os.Stat(p)
	if os.IsNotExist(err) {
		gc.badPaths = append(gc.badPaths, p)
		return &dataDir{}, err
	}

	d := &dataDir{
		files:   []*dataFile{},
		plugins: []*dataFile{},
		order:   dataOrder,
		path:    p,
	}
	d.checkDataDirs(gc)

	return d, err
}