github.com/joomcode/cue@v0.4.4-0.20221111115225-539fe3512047/internal/cmd/embedpkg/embedpkg.go (about)

     1  // Copyright 2021 CUE Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // embedpkg accepts a [packages] argument (see 'go help packages') and creates
    16  // a map[string][]byte for each package argument, a map that represents the
    17  // GoFiles for that package. The principal use case here is the embedding
    18  // of the github.com/joomcode/cue/cmd/cue/cmd/interfaces used by cue get go.
    19  package main
    20  
    21  import (
    22  	"bytes"
    23  	"flag"
    24  	"io/ioutil"
    25  	"log"
    26  	"path/filepath"
    27  	"text/template"
    28  
    29  	"golang.org/x/tools/go/packages"
    30  )
    31  
    32  const genTmpl = `// Code generated by internal/cmd/embedpkg. DO NOT EDIT.
    33  
    34  package cmd
    35  
    36  // {{ .Basename }}Files is the result of embedding GoFiles from the
    37  // {{ .PkgPath }} package.
    38  var {{ .Basename }}Files = map[string][]byte {
    39  {{- range $fn, $content := .GoFiles }}
    40  	"{{ $fn }}": {{ printf "%#v" $content }},
    41  {{- end }}
    42  }
    43  `
    44  
    45  func main() {
    46  	log.SetFlags(0)
    47  	flag.Parse()
    48  
    49  	cfg := &packages.Config{
    50  		Mode: packages.NeedName | packages.NeedFiles |
    51  			packages.NeedCompiledGoFiles | packages.NeedModule,
    52  	}
    53  	pkgs, err := packages.Load(cfg, flag.Args()...)
    54  	if err != nil {
    55  		log.Fatal(err)
    56  	}
    57  
    58  	// parse template
    59  	tmpl, err := template.New("embedpkg").Parse(genTmpl)
    60  	if err != nil {
    61  		log.Fatal(err)
    62  	}
    63  
    64  	for _, p := range pkgs {
    65  		if packages.PrintErrors(pkgs) > 0 {
    66  			// The errors will already have been printed
    67  			log.Fatalln("error loading packages")
    68  		}
    69  		files := map[string][]byte{}
    70  		for _, fn := range p.GoFiles {
    71  			// Because of https://github.com/golang/go/issues/38445 we don't have p.Dir
    72  			content, err := ioutil.ReadFile(fn)
    73  			if err != nil {
    74  				log.Fatal(err)
    75  			}
    76  			relFile, err := filepath.Rel(p.Module.Dir, fn)
    77  			if err != nil {
    78  				log.Fatal(err)
    79  			}
    80  			files[relFile] = content
    81  		}
    82  		data := struct {
    83  			Basename string
    84  			PkgPath  string
    85  			GoFiles  map[string][]byte
    86  		}{
    87  			Basename: p.Name,
    88  			PkgPath:  p.PkgPath,
    89  			GoFiles:  files,
    90  		}
    91  		var b bytes.Buffer
    92  		err = tmpl.Execute(&b, data)
    93  		if err != nil {
    94  			log.Fatal(err)
    95  		}
    96  		err = ioutil.WriteFile(filepath.Join(p.Name+"_gen.go"), b.Bytes(), 0666)
    97  		if err != nil {
    98  			log.Fatal(err)
    99  		}
   100  	}
   101  }