Skip to content

Commit

Permalink
internal/ci: use writefs
Browse files Browse the repository at this point in the history
Signed-off-by: Paul Jolly <[email protected]>
Change-Id: Ia9203e2138ad74947ba49614df3298d84b7aa860
Dispatch-Trailer: {"type":"trybot","CL":1170145,"patchset":1,"ref":"refs/changes/45/1170145/1","targetBranch":"alpha"}
  • Loading branch information
myitcv authored and cueckoo committed Sep 30, 2023
1 parent 40b69f4 commit fa69370
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 0 deletions.
34 changes: 34 additions & 0 deletions internal/ci/github/workflows.cue
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@
// package github declares the workflows for this project.
package github

import (
"encoding/yaml"

"github.com/cue-lang/cuelang.org/internal/ci/base"
)

// Note: the name of the workflows (and hence the corresponding .yml filenames)
// correspond to the environment variable names for gerritstatusupdater.
// Therefore, this filename must only be change in combination with also
Expand Down Expand Up @@ -55,3 +61,31 @@ _linuxWorkflow: {
dummyDispatch: _repo.#dispatch & {
type: _repo.trybot.key
}

// #writefs mirrors the type of the arguments expected by
// internal/cmd/writefs
#writefs: {
Remove: [...string]
Create: [string]: {
Type: "symlink" | *"file"
Contents: *"" | string
}
}

fs: #writefs & {
// TODO: do not hardcode this to ci_tool
let donotedit = base.doNotEditMessage & {#generatedBy: "internal/ci/ci_tool.cue", _}

Remove: [
"../../.github/workflows/*.yml",
]

Create: {
for _name, _workflow in workflows {
"\(_name).yml": {
Contents: "# \(donotedit)\n\n\(yaml.Marshal(_workflow))"
}
}
"../../codereview.cfg":
}
}
89 changes: 89 additions & 0 deletions internal/cmd/writefs/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package main

import (
"bytes"
"encoding/json"
"log"
"os"
"path/filepath"
)

type file struct {
Type string

// If typ == "symlink" this is the filepath of the target
// otherwise it is the Contents of the file
Contents string
}

type args struct {
// Remove is a list of globs of files to remove. File
// removal happens before file creation.
Remove []string

// Create is a map of file path (in Unix format) to contents.
Create map[string]file
}

func main() {
var todo args
dec := json.NewDecoder(os.Stdin)
if err := dec.Decode(&todo); err != nil {
log.Fatalf("failed to decode arguments from stdin: %v", err)
}
for _, glob := range todo.Remove {
files, err := filepath.Glob(glob)
if err != nil {
log.Fatalf("failed to glob %q: %v", glob, err)
}
if len(files) == 0 {
continue
}
for _, f := range files {
if err := os.Remove(f); err != nil {
log.Fatalf("failed to remove %s: %v", f, err)
}
}
}
for fp, f := range todo.Create {
fp = filepath.FromSlash(fp)
dir := filepath.Dir(fp)
if err := os.MkdirAll(dir, 0o777); err != nil {
log.Fatalf("failed to mkdir %s: %v", dir, err)
}
switch f.Type {
case "symlink":
target := filepath.FromSlash(f.Contents)
actualTarget, err := os.Readlink(fp)
if err == nil && actualTarget == target {
continue
}
if err := os.Symlink(target, fp); err != nil {
log.Fatalf("failed to symlink %s -> %s: %v", fp, target, err)
}
case "file":
// If we have a .json file, normalise the contents first
// as a special case.
//
// TODO: this actually belongs as an option in CUE.
contents := []byte(f.Contents)
if filepath.Ext(fp) == ".json" {
var i any
err := json.Unmarshal(contents, &i)
if err == nil {
var b bytes.Buffer
enc := json.NewEncoder(&b)
enc.SetEscapeHTML(false)
enc.SetIndent("", " ")
if err := enc.Encode(i); err == nil {
// Add a trailing newline
contents = b.Bytes()
}
}
}
if err := os.WriteFile(fp, []byte(contents), 0o666); err != nil {
log.Fatalf("failed to write file %s: %v", fp, err)
}
}
}
}

0 comments on commit fa69370

Please sign in to comment.