about summary refs log tree commit diff
path: root/pkg/flake/lock/main.go
blob: 7edf61fcd2172fd7f481c79f60da080b7237adbf (plain) (blame)
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
package lock

import (
	"encoding/json"
	"fmt"
	"os"
	"time"
)

type FlakeLock struct {
	// Version of the lock file
	Version int
	// Root is the root node for the flake, containing all the inputs
	Root RootNode
	// Nodes represent all the inputs node for a flake
	Nodes map[string]Node
}

type Node struct {
	// Flake indicate whether the input is a flake
	Flake bool `json:"flake"`
	// Locked represent the locked attribute of the input
	Locked repoLocked `json:"locked"`
	// Original represent the user supplied attributes for the input
	Original repoOriginal `json:"original"`
}

type repoLocked struct {
	// LastModified represent the timestamp of when the input was updated last
	LastModified int64 `json:"lastModified"`
	// NarHash is the NAR hash for the input
	NarHash string `json:"narHash"`
	// Owner of the repository
	Owner string `json:"owner"`
	// Repository of the input
	Repo string `json:"repo"`
	// Revision of the input
	Rev string `json:"rev"`
	// Type of input
	Type string `json:"type"`
}

type repoOriginal struct {
	Owner string `json:"owner"`
	Ref   string `json:"ref"`
	Repo  string `json:"repo"`
	Type  string `json:"type"`
}

// RootNode is a mapping of input
type RootNode struct {
	// Inputs contains the mapping of input
	Inputs map[string]string `json:"inputs"`
}

// New return a representation of a flake lock
func New(flakeLockPath string) (*FlakeLock, error) {
	content, err := os.ReadFile(flakeLockPath)
	if err != nil {
		return nil, fmt.Errorf("failed to read %s: %v", flakeLockPath, err)
	}

	var lock struct {
		Version int                        `json:"version"`
		Root    string                     `json:"root"`
		Nodes   map[string]json.RawMessage `json:"nodes"`
	}

	if err := json.Unmarshal(content, &lock); err != nil {
		return nil, fmt.Errorf("failed to parse %s: %v", flakeLockPath, err)
	}

	var flakeLock FlakeLock
	flakeLock.Version = lock.Version
	flakeLock.Nodes = map[string]Node{}

	for nodeName, node := range lock.Nodes {
		if nodeName != lock.Root {
			var n Node
			if err := json.Unmarshal(node, &n); err != nil {
				return nil, fmt.Errorf("failed to read node %s: %v", nodeName, err)
			}
			flakeLock.Nodes[nodeName] = n
		} else {
			var r RootNode
			if err := json.Unmarshal(node, &r); err != nil {
				return nil, fmt.Errorf("failed to read the root node: %v", err)
			}
			flakeLock.Root = r
		}
	}

	return &flakeLock, nil
}

func (l repoLocked) LastModifiedRFC3339() string {
	date := time.Unix(l.LastModified, 0)
	unitTimeInRFC3339 := date.Format(time.RFC3339)
	return unitTimeInRFC3339
}

func (l repoLocked) Repository() string {
	switch l.Type {
	case "github":
		return fmt.Sprintf("https://github.com/%s/%s", l.Owner, l.Repo)
	default:
		return fmt.Sprintf("%s/%s", l.Repo, l.Owner)
	}
}