diff --git a/.github/workflows/cron.yml b/.github/workflows/cron.yml new file mode 100644 index 0000000..63aa708 --- /dev/null +++ b/.github/workflows/cron.yml @@ -0,0 +1,35 @@ +name: Auto-update firmware + +on: + push: + branches: + - main + schedule: + # daily, hour and minute chosen arbitrarily + - cron: "32 14 * * *" + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + submodules: true + + - name: Set up Go + uses: actions/setup-go@v2 + with: + go-version: 1.18 + + - name: Check latest kernel version from https://archive.raspberrypi.org/debian/ + id: check + run: echo "::set-output name=version::$(go run ./cmd/check-update/main.go)" + + - name: Fetch latest kernel + if: steps.check.outputs.version != '' + run: echo "checkout ${{steps.check.outputs.version}}" + + - name: Commit the new kernel + uses: stefanzweifel/git-auto-commit-action@v4 + with: + commit_message: kernel ${{steps.check.outputs.version}} diff --git a/cmd/check-update/main.go b/cmd/check-update/main.go new file mode 100644 index 0000000..c0a7631 --- /dev/null +++ b/cmd/check-update/main.go @@ -0,0 +1,104 @@ +package main + +import ( + "bufio" + "errors" + "fmt" + "log" + "net/http" + "os" + "os/exec" + "strings" +) + +func main() { + if err := run(); err != nil { + log.Println(err) + + os.Exit(1) + } +} + +const baseURL = "https://archive.raspberrypi.org/debian/" +const packagesURL = baseURL + "dists/buster/main/binary-armhf/Packages" + +func run() error { + log.Println("checking:", packagesURL) + kernelPrefix := "Filename: pool/main/r/raspberrypi-firmware/raspberrypi-kernel_" + version := "" + versionPrefix := "Version: " + err := scanOnlineTextFile(packagesURL, func(s string) bool { + if strings.HasPrefix(s, versionPrefix) { + version = s[len(versionPrefix):] + } + if strings.HasPrefix(s, kernelPrefix) { + return true + } + return false + }) + if version == "" { + if err != nil { + return err + } + return errors.New("could not find kernel version in package list") + } + + before, after, found := strings.Cut(version, ":") + if !found { + after = before + } + tagName, _, _ := strings.Cut(after, "~") + + log.Println("latest version:", tagName) + + tags, err := gitTags("linux-sources") + if err != nil { + return err + } + for _, tag := range tags { + if tagName == tag { + log.Println("already up to date") + return nil + } + } + log.Println("outdated tag", tags) + fmt.Println(tagName) + + return nil +} + +func gitTags(folder string) ([]string, error) { + current, err := os.Getwd() + if err != nil { + return nil, err + } + defer os.Chdir(current) + + err = os.Chdir(folder) + if err != nil { + return nil, err + } + cmd := exec.Command("git", "tag", "--points-at", "HEAD") + cmd.Stderr = os.Stderr + out, err := cmd.Output() + if err != nil { + return nil, err + } + return strings.Split(strings.TrimSpace(string(out)), "\n"), nil +} + +func scanOnlineTextFile(url string, stopScanning func(string) bool) error { + resp, err := http.Get(url) + if err != nil { + return err + } + defer resp.Body.Close() + + scanner := bufio.NewScanner(resp.Body) + for scanner.Scan() { + if stopScanning(scanner.Text()) { + break + } + } + return scanner.Err() +}