/
init.go
191 lines (175 loc) · 5.5 KB
/
init.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
package command
import (
"errors"
"fmt"
"os"
"path/filepath"
"github.com/ysugimoto/go-args"
"github.com/ysugimoto/ginger/config"
"github.com/ysugimoto/ginger/input"
"github.com/ysugimoto/ginger/internal/colors"
"github.com/ysugimoto/ginger/logger"
)
const awsRegionInquiry = `[AWS region]
Region name which you want to deploy resources.
`
const lambdaRoleInquiry = `[Need lambda execution role]
If you will use Lambda function, Need to set "LambdaExecutionRole".
This is because lambda requires permission to run function itself or external service.
`
const s3BucketInquiry = `[S3 bucket name]
If you will use S3 storage for static file serve, We recommend to set 'S3BucketName'.
`
// Init is the struct for initalize ginger project.
// This command generates config file and some
// directory structure.
type Init struct {
Command
log *logger.Logger
}
func NewInit() *Init {
return &Init{
log: logger.WithNamespace("ginger.init"),
}
}
// Display init command help.
func (i *Init) Help() string {
return "No Help"
}
// Run the init command.
//
// >>> doc
//
// ## Initialize project
//
// Initialize ginger project at current directory.
//
// ```
// $ ginger init [options]
// ```
//
// If you want to use (probably almost case yes) external Go package, we suggest you should put project directory under the `$GOPATH` to enable to detect vendor tree.
//
// For example:
//
// ```
// cd $GOATH/src/github.com/your/project
// ginger init
// ```
//
// The ginger init command will work as following:
//
// - Create `Ginger.toml` file which is used for project configuration
// - Create `functions` directory which is used for function management
// - Create `stages` directory which is used for stage variable management
// - Create `.ginger` directory which is used for put dependency packags. Those packages will be loaded on deploy phase..
// - Install dependency packages.
//
// Note that the `Ginger.toml` is readable and configurable, but almost values are added or updated via subcommands.
// So we don't recommend you change this file manually.
//
// And, when initializing project, ginger asks some questions.
//
// #### LambdaExecutionRole
//
// When ginger deploys function to AWS Lambda, execution role is necessary.
// So you should input lambda exection role to use as default. You can create role on AWS IAM.
// See: https://docs.aws.amazon.com/lambda/latest/dg/with-s3-example-create-iam-role.html
//
// Or, you can use specific role by each function by adding `Function.toml`.
//
// #### S3BucketName
//
// ginger uses S3 bucket name project directory name as defaut. You can change this name.
// #### Region
//
// Destination AWS region which ginger create resources.
//
// <<< doc
func (i *Init) Run(ctx *args.Context) error {
c := config.Load()
if c.Exists() {
i.log.Warn("Config file found. Project has already initialized.")
return errors.New("")
}
if _, err := os.Stat(c.FunctionPath); err != nil {
i.log.Printf("Create functions directory: %s\n", c.FunctionPath)
if err := os.Mkdir(c.FunctionPath, 0755); err != nil {
i.log.Error("Failed to create directory: " + c.FunctionPath)
return err
}
i.ensureKeepFile(c.FunctionPath)
}
if _, err := os.Stat(c.StoragePath); err != nil {
i.log.Printf("Create storage directory: %s\n", c.StoragePath)
if err := os.Mkdir(c.StoragePath, 0755); err != nil {
i.log.Error("Failed to create directory: " + c.StoragePath)
return err
}
i.ensureKeepFile(c.StoragePath)
}
if _, err := os.Stat(c.StagePath); err != nil {
i.log.Printf("Create stages directory: %s\n", c.StagePath)
if err := os.Mkdir(c.StagePath, 0755); err != nil {
i.log.Error("Failed to create directory: " + c.StagePath)
return err
}
i.ensureKeepFile(c.StagePath)
}
if _, err := os.Stat(c.SchedulerPath); err != nil {
i.log.Printf("Create scheduler directory: %s\n", c.SchedulerPath)
if err := os.Mkdir(c.SchedulerPath, 0755); err != nil {
i.log.Error("Failed to create directory: " + c.SchedulerPath)
return err
}
i.ensureKeepFile(c.SchedulerPath)
}
c.ProjectName = filepath.Base(c.Root)
c.Profile = ""
c.DefaultLambdaRole = ""
c.Region = "us-east-1"
if p := ctx.String("profile"); p != "" {
c.Profile = p
}
if r := ctx.String("role"); r != "" {
c.DefaultLambdaRole = r
}
if b := ctx.String("bucket"); b != "" {
c.S3BucketName = b
}
if c.DefaultLambdaRole == "" {
fmt.Println(colors.Yellow(lambdaRoleInquiry))
if role := input.String("Input lambda execution role ARN (empty to skip)"); role == "" {
i.log.Print("Lambda Execution Role isn't set. If you want to set, run 'ginger config --role [role name]'\n")
} else {
c.DefaultLambdaRole = role
}
}
if c.S3BucketName == "" {
fmt.Println(colors.Yellow(s3BucketInquiry))
if bucketName := input.String(fmt.Sprintf("Input bucket name (default: ginger-%s, empty to skip)", c.ProjectName)); bucketName == "" {
c.S3BucketName = fmt.Sprintf("ginger-%s", c.ProjectName)
} else {
c.S3BucketName = bucketName
}
}
fmt.Println(colors.Yellow(awsRegionInquiry))
if region := input.String(fmt.Sprintf("Input region name (default: %s)", c.Region)); region != "" {
c.Region = region
}
c.Write()
NewInstall().Run(ctx)
i.log.Info("ginger initalized successfully!")
return nil
}
// Ensure .keep file and create if not exist
// The .keep file is needed for adding directory to git
func (i *Init) ensureKeepFile(dir string) {
keepFile := filepath.Join(dir, ".keep")
if _, err := os.Stat(keepFile); err == nil {
return
}
// Create empty file
fp, _ := os.OpenFile(keepFile, os.O_CREATE|os.O_RDONLY, 0666)
fp.Close()
}