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) } }