From b5ee47e701259575f22745f920fb4e7013eb0412 Mon Sep 17 00:00:00 2001 From: Franck Cuny Date: Sun, 21 Jan 2024 13:11:33 -0800 Subject: initial version of the flake-info command A tool to display information about a flake. For now we shows all the inputs and when they were updated last. --- cmd/flake-info/main.go | 43 +++++++++++++++++++++++ go.mod | 3 ++ pkg/flake/lock/main.go | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 139 insertions(+) create mode 100644 cmd/flake-info/main.go create mode 100644 go.mod create mode 100644 pkg/flake/lock/main.go diff --git a/cmd/flake-info/main.go b/cmd/flake-info/main.go new file mode 100644 index 0000000..d41f321 --- /dev/null +++ b/cmd/flake-info/main.go @@ -0,0 +1,43 @@ +package main + +import ( + "errors" + "flag" + "fmt" + "os" + "time" + + "github.com/fcuny/world/pkg/flake/lock" +) + +func main() { + var flakeLockPath string + + flag.StringVar(&flakeLockPath, "flake-lock", "flake.lock", "path to the flake lock file") + + flag.Parse() + + if _, err := os.Stat(flakeLockPath); err != nil { + if errors.Is(err, os.ErrNotExist) { + fmt.Fprintf(os.Stderr, "%s does not exists\n", flakeLockPath) + } else { + fmt.Fprintf(os.Stderr, "failed to check if %s exists: %v\n", flakeLockPath, err) + } + os.Exit(1) + } + + lock, err := lock.New(flakeLockPath) + if err != nil { + fmt.Fprintf(os.Stderr, "failed to parse the lockfile for %s: %+v\n", flakeLockPath, err) + os.Exit(1) + } + + fmt.Printf("%s info:\n", flakeLockPath) + fmt.Printf("version: %d\n", lock.Version) + fmt.Printf("all nodes:\n") + for nodeName, node := range lock.Nodes { + date := time.Unix(node.Locked.LastModified, 0) + unitTimeInRFC3339 := date.Format(time.RFC3339) + fmt.Printf("- %s was updated on %s\n", nodeName, unitTimeInRFC3339) + } +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..c28fd3c --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module github.com/fcuny/world + +go 1.21.4 diff --git a/pkg/flake/lock/main.go b/pkg/flake/lock/main.go new file mode 100644 index 0000000..0fa21f4 --- /dev/null +++ b/pkg/flake/lock/main.go @@ -0,0 +1,93 @@ +package lock + +import ( + "encoding/json" + "fmt" + "os" +) + +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 +} -- cgit 1.4.1