-
Notifications
You must be signed in to change notification settings - Fork 222
/
laravel.go
174 lines (151 loc) · 4.26 KB
/
laravel.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
package scanner
import (
"bufio"
"encoding/base64"
"fmt"
"github.com/superfly/flyctl/helpers"
"os"
"os/exec"
"regexp"
"strconv"
"strings"
)
type ComposerLock struct {
Platform PhpVersion `json:"platform,omitempty"`
}
type PhpVersion struct {
Version string `json:"php"`
}
// setup Laravel with a sqlite database
func configureLaravel(sourceDir string, config *ScannerConfig) (*SourceInfo, error) {
// Laravel projects contain the `artisan` command
if !checksPass(sourceDir, fileExists("artisan")) {
return nil, nil
}
files := templates("templates/laravel")
s := &SourceInfo{
Env: map[string]string{
"APP_ENV": "production",
"LOG_CHANNEL": "stderr",
"LOG_LEVEL": "info",
"LOG_STDERR_FORMATTER": "Monolog\\Formatter\\JsonFormatter",
"SESSION_DRIVER": "cookie",
"SESSION_SECURE_COOKIE": "true",
},
Family: "Laravel",
Files: files,
Port: 8080,
Secrets: []Secret{
{
Key: "APP_KEY",
Help: "Laravel needs a unique application key.",
Generate: func() (string, error) {
// Method used in RandBytes never returns an error
r, _ := helpers.RandBytes(32)
return "base64:" + base64.StdEncoding.EncodeToString(r), nil
},
},
},
SkipDatabase: true,
ConsoleCommand: "php /var/www/html/artisan tinker",
}
phpVersion, err := extractPhpVersion()
if err != nil || phpVersion == "" {
// Fallback to 8.0, which has
// the broadest compatibility
phpVersion = "8.0"
}
s.BuildArgs = map[string]string{
"PHP_VERSION": phpVersion,
"NODE_VERSION": "18",
}
// Extract DB, Redis config from dotenv
db, redis, skipDB := extractConnections(".env")
s.SkipDatabase = skipDB
s.RedisDesired = redis
if db != 0 {
s.DatabaseDesired = db
}
return s, nil
}
func extractPhpVersion() (string, error) {
/* Example Output:
PHP 8.1.8 (cli) (built: Jul 8 2022 10:58:31) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.1.8, Copyright (c) Zend Technologies
with Zend OPcache v8.1.8, Copyright (c), by Zend Technologies
*/
cmd := exec.Command("php", "-v")
out, err := cmd.CombinedOutput()
if err != nil {
return "", err
}
// Capture major/minor version (leaving out revision version)
re := regexp.MustCompile(`PHP ([0-9]+\.[0-9]+)\.[0-9]`)
match := re.FindStringSubmatch(string(out))
if len(match) > 1 {
// If the PHP version is below 7.4, we won't have a
// container for it, so we'll use PHP 7.4
if match[1][0:1] == "7" {
vers, err := strconv.ParseFloat(match[1], 32)
if err != nil {
return "7.4", nil
}
if vers < 7.4 {
return "7.4", nil
}
}
return match[1], nil
}
return "", fmt.Errorf("could not find php version")
}
var dbRegStr = "^ *(DB_CONNECTION|DATABASE_URL) *= *(\"|')? *[a-zA-Z]+(\"|')?"
var redisRegStr = "^[^#]*redis"
// extractConnections detects the database connection of a laravel fly app
// by checking the .env file in the project's base directory for connection keywords.
// This ignores commented out lines and prioritizes the first connection occurance over others.
//
// Returns three variables:
//
// db - DatabaseKind of the connection extracted
// redis - reports whether redis was detected
// skipDb - reports whether a connection or redis was detected
func extractConnections(path string) (db DatabaseKind, redis bool, skipDb bool) {
// Get File Content
file, err := os.Open(path)
if err != nil {
return 0, false, true
}
defer file.Close() //skipcq: GO-S2307
// Set up Regex to match
// -not commented out, with DB_CONNECTION
dbReg := regexp.MustCompile(dbRegStr)
// -not commented out with redis keyword
redisReg := regexp.MustCompile(redisRegStr)
// Default Return Variables
db = 0
redis = false
skipDb = true
// Check each line for
// match on redis or db regex
scanner := bufio.NewScanner(file)
for scanner.Scan() {
text := scanner.Text()
if redisReg.MatchString(text) {
redis = true
skipDb = false
} else if db == 0 && dbReg.MatchString(text) {
if strings.Contains(text, "mysql") {
db = DatabaseKindMySQL
skipDb = false
} else if strings.Contains(text, "pgsql") || strings.Contains(text, "postgres") {
db = DatabaseKindPostgres
skipDb = false
} else if strings.Contains(text, "sqlite") {
db = DatabaseKindSqlite
skipDb = false
}
}
}
return db, redis, skipDb
}