Skip to content

Commit 5d804d4

Browse files
committed
wip
1 parent 183326e commit 5d804d4

File tree

1 file changed

+116
-18
lines changed

1 file changed

+116
-18
lines changed

src/cmd/cli/command/commands.go

Lines changed: 116 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
package command
22

33
import (
4+
"archive/tar"
5+
"compress/gzip"
46
"context"
7+
"encoding/json"
58
"errors"
69
"fmt"
710
"io"
811
"math/rand"
12+
"net/http"
913
"os"
1014
"os/exec"
1115
"regexp"
@@ -424,16 +428,66 @@ var generateCmd = &cobra.Command{
424428
return errors.New("cannot run in non-interactive mode")
425429
}
426430

431+
var language string
432+
if err := survey.AskOne(&survey.Select{
433+
Message: "Choose the language you'd like to use:",
434+
Options: []string{"Nodejs", "Golang", "Python"},
435+
Default: "Nodejs",
436+
Help: "The generated code will be in the language you choose here.",
437+
}, &language); err != nil {
438+
return err
439+
}
440+
441+
var samples []struct {
442+
Name string `json:"name"`
443+
Category string `json:"category"`
444+
Readme string `json:"readme"`
445+
}
446+
req, err := http.NewRequestWithContext(cmd.Context(), http.MethodGet, "https://docs.defang.io/samples.json", nil)
447+
if err != nil {
448+
return err
449+
}
450+
req.Header.Set("Accept-Encoding", "gzip")
451+
resp, err := httpClient.Do(req)
452+
if err == nil {
453+
defer resp.Body.Close()
454+
term.Debug(resp.Header)
455+
// Check that the server actually sent compressed data
456+
reader := resp.Body
457+
if resp.Header.Get("Content-Encoding") == "gzip" {
458+
reader, err = gzip.NewReader(resp.Body)
459+
if err != nil {
460+
return err
461+
}
462+
defer reader.Close()
463+
}
464+
if json.NewDecoder(reader).Decode(&samples) != nil {
465+
term.Debug(" - unable to decode samples.json:", err)
466+
}
467+
}
468+
469+
const generateWithAI = "Generate with AI"
470+
471+
language = strings.ToLower(language) // make it match the category strings
472+
sampleNames := []string{generateWithAI}
473+
// sampleDescriptions := []string{"Generate a sample from scratch using a language prompt"}
474+
for _, sample := range samples {
475+
if sample.Category == language {
476+
sampleNames = append(sampleNames, sample.Name)
477+
// sampleDescriptions = append(sampleDescriptions, sample.Readme)
478+
}
479+
}
480+
481+
var sample string
482+
if err := survey.AskOne(&survey.Select{
483+
Message: "Choose a sample service:",
484+
Options: sampleNames,
485+
Help: "The generated code will be based on the sample you choose here.",
486+
}, &sample); err != nil {
487+
return err
488+
}
489+
427490
var qs = []*survey.Question{
428-
{
429-
Name: "language",
430-
Prompt: &survey.Select{
431-
Message: "Choose the language you'd like to use:",
432-
Options: []string{"Nodejs", "Golang", "Python"},
433-
Default: "Nodejs",
434-
Help: "The generated code will be in the language you choose here.",
435-
},
436-
},
437491
{
438492
Name: "description",
439493
Prompt: &survey.Input{
@@ -457,14 +511,17 @@ Generate will write files in the current folder. You can edit them and then depl
457511
},
458512
}
459513

514+
if sample != generateWithAI {
515+
qs = qs[1:] // skip the description question
516+
}
517+
460518
prompt := struct {
461-
Language string // or you can tag fields to match a specific name
462-
Description string
519+
Description string // or you can tag fields to match a specific name
463520
Folder string
464521
}{}
465522

466-
// ask the questions
467-
err := survey.Ask(qs, &prompt)
523+
// ask the remaining questions
524+
err = survey.Ask(qs, &prompt)
468525
if err != nil {
469526
return err
470527
}
@@ -479,7 +536,7 @@ Generate will write files in the current folder. You can edit them and then depl
479536
}
480537
}
481538

482-
Track("Generate Started", P{"language", prompt.Language}, P{"description", prompt.Description}, P{"folder", prompt.Folder})
539+
Track("Generate Started", P{"language", language}, P{"sample", sample}, P{"description", prompt.Description}, P{"folder", prompt.Folder})
483540

484541
// create the folder if needed
485542
cd := ""
@@ -496,10 +553,51 @@ Generate will write files in the current folder. You can edit them and then depl
496553
term.Warn(" ! The folder is not empty. Files may be overwritten. Press Ctrl+C to abort.")
497554
}
498555

499-
term.Info(" * Working on it. This may take 1 or 2 minutes...")
500-
_, err = cli.Generate(cmd.Context(), client, prompt.Language, prompt.Description)
501-
if err != nil {
502-
return err
556+
if prompt.Description != "" {
557+
term.Info(" * Working on it. This may take 1 or 2 minutes...")
558+
_, err = cli.Generate(cmd.Context(), client, language, prompt.Description)
559+
if err != nil {
560+
return err
561+
}
562+
} else {
563+
term.Info(" * Fetching sample from the Defang repository...")
564+
resp, err := http.Get("https://github.com/defang-io/defang/archive/refs/heads/main.tar.gz")
565+
if err != nil {
566+
return err
567+
}
568+
defer resp.Body.Close()
569+
term.Debug(resp.Header)
570+
body, err := gzip.NewReader(resp.Body)
571+
if err != nil {
572+
return err
573+
}
574+
defer body.Close()
575+
tarReader := tar.NewReader(body)
576+
term.Info(" * Writing files to disk...")
577+
for {
578+
h, err := tarReader.Next()
579+
if err != nil {
580+
if err == io.EOF {
581+
break
582+
}
583+
return err
584+
}
585+
586+
if base, ok := strings.CutPrefix(h.Name, "defang-main/samples/"+language+"/"+sample+"/"); ok && len(base) > 0 {
587+
fmt.Println(" -", base)
588+
if h.FileInfo().IsDir() {
589+
os.MkdirAll(base, 0755)
590+
continue
591+
}
592+
f, err := os.Create(base)
593+
if err != nil {
594+
return err
595+
}
596+
if _, err := io.Copy(f, tarReader); err != nil {
597+
return err
598+
}
599+
}
600+
}
503601
}
504602

505603
term.Info(" * Code generated successfully in folder", prompt.Folder)

0 commit comments

Comments
 (0)