fleet/cmd/gitops-migrate/fs.go
Anthony Maxwell 288ea58bce
Feat: GitOps YAML Migration Tool (#32237)
# Overview

This pull request resolves #31165, implementing command-line tooling to
migrate GitOps YAML files following the [changes introduced in the
upcoming 4.74
release](https://github.com/fleetdm/fleet/pull/32237/files#diff-8769f6e90e8bdf15faad8f390fdf3ffb6fd2238b7d6087d83518c21464109119R7).

Aligning with the recommended steps in the `README`; [this is an example
of the first step](https://github.com/Illbjorn/fleet/pull/3/files)
(`gitops-migrate format`) and [this is an example of the second
step](https://github.com/Illbjorn/fleet/pull/4/files) (`gitops-migrate
migrate`).

---------

Signed-off-by: Illbjorn <am@hades.so>
Co-authored-by: Ian Littman <iansltx@gmail.com>
2025-09-08 12:42:25 -04:00

86 lines
1.9 KiB
Go

package main
import (
"fmt"
"iter"
"os"
"path/filepath"
)
const (
fileModeUserRW = 0o600
fileModeUserRWX = 0o700
fileFlagsOverwrite = os.O_CREATE | os.O_WRONLY | os.O_TRUNC
fileFlagsReadWrite = os.O_RDWR
)
type File struct {
Path string
Hash string
Stats os.FileInfo
}
// fsEnum is a very specific file system iterator for the Fleet GitOps migration
// tooling which yields all _files_ under 'root' in relative-path-form (relative
// to 'root').
//
// If the provided 'root' value is a file path, a single yield will occur
// before the iterator returns.
//
// If the provided 'root' value is a directory path, the directory will be
// recursively enumerated and produced.
func fsEnum(root string) iter.Seq2[File, error] {
return func(yield func(File, error) bool) {
// Send the path and yield fn through the recursive enumerator.
fsEnumRec(root, yield)
}
}
func fsEnumRec(path string, yield func(File, error) bool) bool {
stats, err := os.Lstat(path)
switch {
case err != nil:
// Handle failed stats.
yield(File{}, fmt.Errorf(
"failed to stat path(%s) during directory enumeration: %w",
path, err,
))
return false
case stats.IsDir():
// Yield the directory.
if !yield(File{Path: path, Stats: stats}, nil) {
return false
}
// Continue recursive directory enumeration.
items, err := os.ReadDir(path)
if err != nil {
yield(File{}, fmt.Errorf(
"failed to read directory(%s) during enumeration: %w",
path, err,
))
return false
}
// Iterate returned directory items, recursing on each.
for _, item := range items {
// Assemble the nested item's path.
path := filepath.Join(path, item.Name())
if !fsEnumRec(path, yield) {
return false
}
}
case !stats.IsDir():
// Simply yield file items.
if !yield(File{Path: path, Stats: stats}, nil) {
return false
}
default:
panic("impossible")
}
return true
}