Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 52 additions & 18 deletions cmd/lk/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,16 @@ import (
)

var (
template *bootstrap.Template
templateName string
templateURL string
sandboxID string
appName string
appNameRegex = regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_-]*$`)
project *config.ProjectConfig
AppCommands = []*cli.Command{
template *bootstrap.Template
templateName string
templateURL string
sandboxID string
appName string
appNameRegex = regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_-]*$`)
destinationFile string
exampleFile string
project *config.ProjectConfig
AppCommands = []*cli.Command{
{
Name: "app",
Usage: "Initialize and manage applications",
Expand Down Expand Up @@ -102,12 +104,28 @@ var (
},
{
Name: "env",
Usage: "Expand environment variables from the current project, and if present, the .env.example file",
Usage: "Fill environment variables based on .env.example (optional) and project credentials",
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "w",
Aliases: []string{"write"},
Usage: "Write environment variables to .env.local file",
Name: "write",
Aliases: []string{"w"},
Usage: "Write environment variables to file",
},
&cli.StringFlag{
Name: "destination",
Aliases: []string{"d"},
Usage: "Destination file path, when used with --write",
Value: ".env.local",
TakesFile: true,
Destination: &destinationFile,
},
&cli.StringFlag{
Name: "example",
Aliases: []string{"e"},
Usage: "Example file path",
Value: ".env.example",
TakesFile: true,
Destination: &exampleFile,
},
},
ArgsUsage: "[DIR] location of the project directory (default: current directory)",
Expand Down Expand Up @@ -291,16 +309,32 @@ func setupTemplate(ctx context.Context, cmd *cli.Command) error {
return err
}

tf, err := bootstrap.ParseTaskfile(appName)
if err != nil {
return err
}

fmt.Println("Instantiating environment...")
addlEnv := &map[string]string{
"LIVEKIT_SANDBOX_ID": sandboxID,
"NEXT_PUBLIC_LIVEKIT_SANDBOX_ID": sandboxID,
}
env, err := instantiateEnv(ctx, cmd, appName, addlEnv)
envOutputFile := ".env.local"
envExampleFile := ".env.example"
if tf != nil {
if customOutput, ok := tf.Vars.Get("env_file").Value.(string); ok {
envOutputFile = customOutput
}
if customExample, ok := tf.Vars.Get("env_example").Value.(string); ok {
envExampleFile = customExample
}
}
env, err := instantiateEnv(ctx, cmd, appName, addlEnv, envExampleFile)
if err != nil {
return err
}
bootstrap.WriteDotEnv(appName, env)

bootstrap.WriteDotEnv(appName, envOutputFile, env)

if install {
fmt.Println("Installing template...")
Expand Down Expand Up @@ -357,19 +391,19 @@ func manageEnv(ctx context.Context, cmd *cli.Command) error {
rootDir = "."
}

env, err := instantiateEnv(ctx, cmd, rootDir, nil)
env, err := instantiateEnv(ctx, cmd, rootDir, nil, exampleFile)
if err != nil {
return err
}

if cmd.Bool("write") {
return bootstrap.WriteDotEnv(rootDir, env)
return bootstrap.WriteDotEnv(rootDir, destinationFile, env)
} else {
return bootstrap.PrintDotEnv(env)
}
}

func instantiateEnv(ctx context.Context, cmd *cli.Command, rootPath string, addlEnv *map[string]string) (map[string]string, error) {
func instantiateEnv(ctx context.Context, cmd *cli.Command, rootPath string, addlEnv *map[string]string, exampleFile string) (map[string]string, error) {
env := map[string]string{
"LIVEKIT_API_KEY": project.APIKey,
"LIVEKIT_API_SECRET": project.APISecret,
Expand All @@ -396,7 +430,7 @@ func instantiateEnv(ctx context.Context, cmd *cli.Command, rootPath string, addl
return newValue, nil
}

return bootstrap.InstantiateDotEnv(ctx, rootPath, env, cmd.Bool("verbose"), prompt)
return bootstrap.InstantiateDotEnv(ctx, rootPath, exampleFile, env, cmd.Bool("verbose"), prompt)
}

func installTemplate(ctx context.Context, cmd *cli.Command) error {
Expand Down
12 changes: 5 additions & 7 deletions pkg/bootstrap/bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@ import (
)

const (
EnvExampleFile = ".env.example"
EnvLocalFile = ".env.local"
TaskFile = "taskfile.yaml"
TemplateIndexFile = "templates.yaml"
TemplateIndexURL = "https://raw.githubusercontent.com/livekit-examples/index/main"
Expand Down Expand Up @@ -190,16 +188,16 @@ type PromptFunc func(key string, value string) (string, error)

// Read .env.example file if present in rootDir, replacing all `substitutions`,
// prompting for others, and returning the result as a map.
func InstantiateDotEnv(ctx context.Context, rootDir string, substitutions map[string]string, verbose bool, prompt PromptFunc) (map[string]string, error) {
func InstantiateDotEnv(ctx context.Context, rootDir string, exampleFilePath string, substitutions map[string]string, verbose bool, prompt PromptFunc) (map[string]string, error) {
promptedVars := map[string]string{}
envExamplePath := path.Join(rootDir, EnvExampleFile)
envExamplePath := path.Join(rootDir, exampleFilePath)

stat, err := os.Stat(envExamplePath)
if err != nil && !errors.Is(err, fs.ErrNotExist) {
return nil, err
} else if stat != nil {
if stat.IsDir() {
return nil, errors.New("env.example file is a directory")
return nil, errors.New(".env.example file is a directory")
}

envMap, err := godotenv.Read(envExamplePath)
Expand Down Expand Up @@ -239,12 +237,12 @@ func PrintDotEnv(envMap map[string]string) error {
return err
}

func WriteDotEnv(rootDir string, envMap map[string]string) error {
func WriteDotEnv(rootDir string, filePath string, envMap map[string]string) error {
envContents, err := godotenv.Marshal(envMap)
if err != nil {
return err
}
envLocalPath := path.Join(rootDir, EnvLocalFile)
envLocalPath := path.Join(rootDir, filePath)
return os.WriteFile(envLocalPath, []byte(envContents+"\n"), 0700)
}

Expand Down
Loading