aboutsummaryrefslogblamecommitdiff
path: root/pkg/flake/lock/main.go
blob: 7edf61fcd2172fd7f481c79f60da080b7237adbf (plain) (tree)
1
2
3
4
5
6
7





                       
              






















































































                                                                                                   














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