z_mirror/fmm

git clone https://git.raiguard.me/z_mirror/fmm

Caleb HeuerCheck against factorio_version field when validating base version50e96b6

updating
2.1 KiB103 linesraw
1package fmm
2
3import (
4	"archive/zip"
5	"encoding/json"
6	"errors"
7	"io"
8	"os"
9	"path/filepath"
10	"strings"
11)
12
13type Release struct {
14	Name         string
15	Dependencies []*Dependency
16	Path         string
17	Version      Version
18}
19
20func releaseFromFile(path string) (*Release, error) {
21	info, err := os.Stat(path)
22	if err != nil {
23		return nil, errors.Join(errors.New("unable to get file info"), err)
24	}
25	filename := filepath.Base(path)
26	var infoJson infoJson
27	if info.Mode().IsRegular() {
28		infoJson, err = readZipInfoJson(path)
29	} else if info.IsDir() || isSymlink(info) {
30		file, err := os.Open(filepath.Join(path, "info.json"))
31		if err == nil {
32			infoJson, err = readInfoJson(file)
33		}
34	}
35
36	if err != nil {
37		return nil, errors.Join(errors.New("error when parsing info.json"), err)
38	}
39
40	ident := NewModIdent(filename)
41	if ident.Name == infoJson.Name && infoJson.Version.Cmp(ident.Version) != VersionEq {
42		return nil, errors.New("invalid release filename")
43	}
44
45	return &Release{
46		infoJson.Name,
47		infoJson.Dependencies,
48		filename,
49		infoJson.Version,
50	}, nil
51}
52
53type infoJson struct {
54	Dependencies    []*Dependency `json:"dependencies"`
55	Name            string        `json:"name"`
56	Version         Version       `json:"version"`
57	FactorioVersion Version       `json:"factorio_version"`
58}
59
60func isSymlink(info os.FileInfo) bool {
61	return info.Mode()&os.ModeSymlink > 0
62}
63
64func readInfoJson(rc io.ReadCloser) (infoJson, error) {
65	var infoJson infoJson
66
67	content, err := io.ReadAll(rc)
68	if err != nil {
69		return infoJson, err
70	}
71
72	err = json.Unmarshal(content, &infoJson)
73	return infoJson, err
74}
75
76func readZipInfoJson(path string) (infoJson, error) {
77	r, err := zip.OpenReader(path)
78	if err != nil {
79		return infoJson{}, err
80	}
81
82	var file *zip.File
83
84	for _, existing := range r.File {
85		parts := strings.Split(existing.Name, "/")
86		if len(parts) == 2 && parts[1] == "info.json" {
87			file = existing
88			break
89		}
90	}
91
92	if file == nil {
93		return infoJson{}, errors.New("could not locate info.json file")
94	}
95
96	rc, err := file.Open()
97	if err != nil {
98		return infoJson{}, err
99	}
100	defer rc.Close()
101
102	return readInfoJson(rc)
103}