@@ -2,9 +2,15 @@ package cli
22
33import (
44 "bytes"
5+ "errors"
56 "fmt"
7+ "io"
68 "os"
79 "path/filepath"
10+ "sort"
11+
12+ "golang.org/x/exp/maps"
13+ "golang.org/x/xerrors"
814
915 "github.com/coder/coder/cli/clibase"
1016 "github.com/coder/coder/cli/cliui"
@@ -14,38 +20,60 @@ import (
1420)
1521
1622func (* RootCmd ) templateInit () * clibase.Cmd {
17- return & clibase.Cmd {
23+ var templateID string
24+ exampleList , err := examples .List ()
25+ if err != nil {
26+ // This should not happen. If it does, something is very wrong.
27+ panic (err )
28+ }
29+ var templateIDs []string
30+ for _ , ex := range exampleList {
31+ templateIDs = append (templateIDs , ex .ID )
32+ }
33+ sort .Strings (templateIDs )
34+ cmd := & clibase.Cmd {
1835 Use : "init [directory]" ,
1936 Short : "Get started with a templated template." ,
2037 Middleware : clibase .RequireRangeArgs (0 , 1 ),
2138 Handler : func (inv * clibase.Invocation ) error {
22- exampleList , err := examples .List ()
23- if err != nil {
24- return err
25- }
26- exampleNames := []string {}
27- exampleByName := map [string ]codersdk.TemplateExample {}
28- for _ , example := range exampleList {
29- name := fmt .Sprintf (
30- "%s\n %s\n %s\n " ,
31- cliui .Styles .Bold .Render (example .Name ),
32- cliui .Styles .Wrap .Copy ().PaddingLeft (6 ).Render (example .Description ),
33- cliui .Styles .Keyword .Copy ().PaddingLeft (6 ).Render (example .URL ),
34- )
35- exampleNames = append (exampleNames , name )
36- exampleByName [name ] = example
39+ // If the user didn't specify any template, prompt them to select one.
40+ if templateID == "" {
41+ optsToID := map [string ]string {}
42+ for _ , example := range exampleList {
43+ name := fmt .Sprintf (
44+ "%s\n %s\n %s\n " ,
45+ cliui .Styles .Bold .Render (example .Name ),
46+ cliui .Styles .Wrap .Copy ().PaddingLeft (6 ).Render (example .Description ),
47+ cliui .Styles .Keyword .Copy ().PaddingLeft (6 ).Render (example .URL ),
48+ )
49+ optsToID [name ] = example .ID
50+ }
51+ opts := maps .Keys (optsToID )
52+ sort .Strings (opts )
53+ _ , _ = fmt .Fprintln (inv .Stdout , cliui .Styles .Wrap .Render (
54+ "A template defines infrastructure as code to be provisioned " +
55+ "for individual developer workspaces. Select an example to be copied to the active directory:\n " ))
56+ selected , err := cliui .Select (inv , cliui.SelectOptions {
57+ Options : opts ,
58+ })
59+ if err != nil {
60+ if errors .Is (err , io .EOF ) {
61+ return xerrors .Errorf (
62+ "Couldn't find a matching template!\n " +
63+ "Tip: if you're trying to automate template creation, try\n " +
64+ "coder templates init --id <template_id> instead!" ,
65+ )
66+ }
67+ return err
68+ }
69+ templateID = optsToID [selected ]
3770 }
3871
39- _ , _ = fmt .Fprintln (inv .Stdout , cliui .Styles .Wrap .Render (
40- "A template defines infrastructure as code to be provisioned " +
41- "for individual developer workspaces. Select an example to be copied to the active directory:\n " ))
42- option , err := cliui .Select (inv , cliui.SelectOptions {
43- Options : exampleNames ,
44- })
45- if err != nil {
46- return err
72+ selectedTemplate , ok := templateByID (templateID , exampleList )
73+ if ! ok {
74+ // clibase.EnumOf would normally handle this.
75+ return xerrors .Errorf ("template not found: %q" , templateID )
4776 }
48- selectedTemplate := exampleByName [option ]
4977 archive , err := examples .Archive (selectedTemplate .ID )
5078 if err != nil {
5179 return err
@@ -81,4 +109,23 @@ func (*RootCmd) templateInit() *clibase.Cmd {
81109 return nil
82110 },
83111 }
112+
113+ cmd .Options = clibase.OptionSet {
114+ {
115+ Flag : "id" ,
116+ Description : "Specify a given example template by ID." ,
117+ Value : clibase .EnumOf (& templateID , templateIDs ... ),
118+ },
119+ }
120+
121+ return cmd
122+ }
123+
124+ func templateByID (templateID string , tes []codersdk.TemplateExample ) (codersdk.TemplateExample , bool ) {
125+ for _ , te := range tes {
126+ if te .ID == templateID {
127+ return te , true
128+ }
129+ }
130+ return codersdk.TemplateExample {}, false
84131}
0 commit comments