This is the 9th day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021
Mr Yuan feels he is in good shape and is ready to work on frontends. Before the editor automatically installed the dependency, can’t wait to set out.
If you navigate directly to the build subcommand, you’ll find that the entry function to the subcommand is buildAction:
func buildAction(clicontext *cli.Context) error {
c, err := bccommon.ResolveClient(clicontext)
iferr ! =nil {
return err
}
...
eg, ctx := errgroup.WithContext(bccommon.CommandContext(clicontext))
solveOpt := client.SolveOpt{
Exports: exports,
// LocalDirs is set later
Frontend: clicontext.String("frontend"),
// FrontendAttrs is set later
CacheExports: cacheExports,
CacheImports: cacheImports,
Session: attachable,
AllowedEntitlements: allowed,
}
...
var def *llb.Definition
if clicontext.String("frontend") = ="" {
iffi, _ := os.Stdin.Stat(); (fi.Mode() & os.ModeCharDevice) ! =0 {
return errors.Errorf("please specify --frontend or pipe LLB definition to stdin")
}
def, err = read(os.Stdin, clicontext)
iferr ! =nil {
return err
}
if len(def.Def) == 0 {
return errors.Errorf("empty definition sent to build. Specify --frontend instead?")}}else {
if clicontext.Bool("no-cache") {
solveOpt.FrontendAttrs["no-cache"] = ""}}... eg.Go(func(a) error{... resp, err := c.Solve(ctx, def, solveOpt, progresswriter.ResetTime(mw.WithPrefix("".false)).Status())
...
return nil})...return eg.Wait()
}
Copy the code
The main flow here is:
- Obtain the client client –
bccommon.ResolveClient(clicontext)
- Prepare solveOpt, which contains Frontend
- Check whether “frontend” is passed to the command line, if not, as in the example given by Longfei
./example | buildctl build
, then the data is read from os.stdin standard input, which corresponds todef, err = read(os.Stdin, clicontext)
. If there are Settings, like in the command line instructions$ buildctl build --frontend dockerfile.v0 --opt target=foo --opt build-arg:foo=bar --local context=. --local dockerfile=. --output type=image,name=docker.io/username/image,push=true
To see if there are cache-related configurations - The last to
c.Solve
Unified handling
Well, so far so clear.
Solve. Go is entered under the Client package. If the configuration of the Frontend parameter is not designed, then def cannot be empty, that is, read from os.stdin. If Frontend is not, like dockerfile.v0, then def must be null, because it will not accept standard input and will be taken from –local dockerfile=. To read the build information.
Notice that the next step is to go to lowercasesolve
This function, in Golang, is case sensitive, which means these are two functions. In addition, Golang believes that uppercase functions are equivalent to public functions, while lowercase functions are private functions, which makes it easy to adapt.With the first two ‘solve’, the third ‘solve’ appearsc.controlClient().Solve(...)
.
When we jump directly to the third Solve, we come to the interface definition:What if I do a global search and I find a lot of solve? Suddenly remembered this is byc.controlClient()
Method of the returned object, then look at what is returned:This means that the structure implements the solve method, as it were:Solve appears again, this time a remote callc.cc.Invoke(ctx, "/moby.buildkit.v1.Control/Solve", ...)
Well, where are we going to find c.C., frontend is missing. Looking at the cold tea, my stomach growled a few times. Let’s go ask Longfei tomorrow and see if he has any suggestions.