forgejo-runner

git clone git://git.lin.moe/forgejo-runner.git

  1// Copyright 2023 The Gitea Authors. All rights reserved.
  2// SPDX-License-Identifier: MIT
  3
  4package labels
  5
  6import (
  7	"fmt"
  8	"strings"
  9)
 10
 11const (
 12	SchemeHost   = "host"
 13	SchemeDocker = "docker"
 14	SchemeQemu   = "qemu"
 15	SchemeSSH    = "ssh"
 16	SchemeLXC    = "lxc"
 17)
 18
 19type Label struct {
 20	Name   string
 21	Schema string
 22	Arg    string
 23}
 24
 25func Parse(str string) (*Label, error) {
 26	splits := strings.SplitN(str, ":", 3)
 27	label := &Label{
 28		Name:   splits[0],
 29		Schema: "host",
 30		Arg:    "",
 31	}
 32	if len(splits) >= 2 {
 33		label.Schema = splits[1]
 34	}
 35	if len(splits) >= 3 {
 36		label.Arg = splits[2]
 37	}
 38	if label.Schema != SchemeHost && label.Schema != SchemeDocker && label.Schema != SchemeLXC && label.Schema != SchemeQemu && label.Schema != SchemeSSH {
 39		return nil, fmt.Errorf("unsupported schema: %s", label.Schema)
 40	}
 41	return label, nil
 42}
 43
 44type Labels []*Label
 45
 46func (l Labels) RequireDocker() bool {
 47	for _, label := range l {
 48		if label.Schema == SchemeDocker {
 49			return true
 50		}
 51	}
 52	return false
 53}
 54
 55func (l Labels) PickPlatform(runsOn []string) string {
 56	platforms := make(map[string]string, len(l))
 57	for _, label := range l {
 58		switch label.Schema {
 59		case SchemeDocker:
 60			// "//" will be ignored
 61			platforms[label.Name] = strings.TrimPrefix(label.Arg, "//")
 62		case SchemeHost:
 63			platforms[label.Name] = "-self-hosted"
 64		case SchemeLXC:
 65			platforms[label.Name] = "lxc:" + strings.TrimPrefix(label.Arg, "//")
 66		case SchemeQemu:
 67			platforms[label.Name] = strings.TrimPrefix(label.Arg, "//")
 68		case SchemeSSH:
 69			platforms[label.Name] = strings.TrimPrefix(label.Arg, "//")
 70		default:
 71			// It should not happen, because Parse has checked it.
 72			continue
 73		}
 74		platforms[label.Name] = fmt.Sprintf("%s://%s", label.Schema, platforms[label.Name])
 75	}
 76	for _, v := range runsOn {
 77		if v, ok := platforms[v]; ok {
 78			return v
 79		}
 80	}
 81
 82	// TODO: support multiple labels
 83	// like:
 84	//   ["ubuntu-22.04"] => "ubuntu:22.04"
 85	//   ["with-gpu"] => "linux:with-gpu"
 86	//   ["ubuntu-22.04", "with-gpu"] => "ubuntu:22.04_with-gpu"
 87
 88	// return default.
 89	// So the runner receives a task with a label that the runner doesn't have,
 90	// it happens when the user have edited the label of the runner in the web UI.
 91	// TODO: it may be not correct, what if the runner is used as host mode only?
 92	return "node:20-bullseye"
 93}
 94
 95func (l Labels) Names() []string {
 96	names := make([]string, 0, len(l))
 97	for _, label := range l {
 98		names = append(names, label.Name)
 99	}
100	return names
101}
102
103func (l Labels) ToStrings() []string {
104	ls := make([]string, 0, len(l))
105	for _, label := range l {
106		lbl := label.Name
107		if label.Schema != "" {
108			lbl += ":" + label.Schema
109			if label.Arg != "" {
110				lbl += ":" + label.Arg
111			}
112		}
113		ls = append(ls, lbl)
114	}
115	return ls
116}