1// SPDX-License-Identifier: MIT
2
3package executor
4
5import (
6 "strings"
7
8 "github.com/google/uuid"
9
10 "bnema.dev/ermite-actions/expr"
11)
12
13// The job.container and job.services contexts (JobContext.cs:20-47,
14// ContainerOperationProvider.cs:96, :215-232, :237-240). The runner's
15// JobContext.Container and .Services create their dictionary when they are
16// read, which is why a recorded job that ran a docker action has
17// "container": {} (act-docker-image).
18
19// jobSub returns the dictionary at job.<key>, creating it when missing.
20func (s *State) jobSub(key string) *expr.Dictionary {
21 if v, ok := s.job.Get(key); ok {
22 if d, ok := v.(*expr.Dictionary); ok {
23 return d
24 }
25 }
26 d := expr.NewDictionary()
27 s.job = setKey(s.job, key, d)
28 return d
29}
30
31// TouchJobContainer is the read of JobContext.Container: job.container exists
32// from then on.
33func (s *State) TouchJobContainer() { s.jobSub("container") }
34
35// SetJobContainer sets job.container.<key> ("network", "id").
36func (s *State) SetJobContainer(key, value string) {
37 d := s.jobSub("container")
38 if _, ok := d.Get(key); ok {
39 s.job = setKey(s.job, "container", replaceKey(d, key, expr.String(value)))
40 return
41 }
42 d.Add(key, expr.String(value))
43}
44
45// JobContainerNetwork is job.container.network, "" when it is not set.
46func (s *State) JobContainerNetwork() string {
47 if v, ok := s.jobSub("container").Get("network"); ok {
48 return expr.CoerceString(v)
49 }
50 return ""
51}
52
53// SetJobService sets job.services.<alias> ({id, ports, network}).
54func (s *State) SetJobService(alias, id, network string, ports []portMapping) {
55 svc := expr.NewDictionary()
56 svc.Add("id", expr.String(id))
57 pd := expr.NewDictionary()
58 for _, p := range ports {
59 pd.Add(p.container, expr.String(p.host))
60 }
61 svc.Add("ports", pd)
62 svc.Add("network", expr.String(network))
63 d := s.jobSub("services")
64 s.job = setKey(s.job, "services", replaceKey(d, alias, svc))
65}
66
67func replaceKey(d *expr.Dictionary, key string, v expr.Value) *expr.Dictionary {
68 return setKey(d, key, v)
69}
70
71// newRunnerStepID is the context name of a step the runner made itself
72// (Initialize containers, Pull <image>, Build <action>): its Guid in "N" format,
73// which does not start with "__", so the entry {outcome, conclusion, outputs:
74// {}} is visible to the user's steps (JobExtension.cs:439 CreateChild(stepId,
75// ..., stepId.ToString("N"), ...), ExecutionContext.UpdateGlobalStepsContext:644;
76// recorded in ctr-basic, svc-redis, act-docker-image). runStep registers its
77// result under it (qstep.ctxID).
78func newRunnerStepID() string { return strings.ReplaceAll(uuid.NewString(), "-", "") }