pkg/firebase/envvars/envvars.go (67 lines of code) (raw):
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package envvars handles the writing of .env-esque files to disk for use in subsequent
// Cloud Build steps.
package envvars
import (
"bufio"
"encoding/json"
"fmt"
"io/ioutil"
"os"
"sort"
"strconv"
"strings"
"github.com/GoogleCloudPlatform/buildpacks/pkg/firebase/apphostingschema"
"github.com/GoogleCloudPlatform/buildpacks/pkg/firebase/faherror"
)
// Write produces a file where each line has the format KEY=VALUE. We aren't using the
// godotenv library as its output isn't compatible with the `pack build --env-file` command.
func Write(env map[string]string, fileName string) error {
content, err := marshal(env)
if err != nil {
return err
}
err = ioutil.WriteFile(fileName, []byte(content+"\n"), 0644)
if err != nil {
return err
}
return nil
}
// Read reads in the custom env file to a map. This is a very dumb function that
// just splits each line with the format KEY=VALUE and adds it to the output map.
func Read(filename string) (map[string]string, error) {
file, err := os.Open(filename)
if err != nil {
return nil, err
}
defer file.Close()
envMap := make(map[string]string)
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
if equalSignIndex := strings.Index(line, "="); equalSignIndex != -1 {
key := line[:equalSignIndex]
value := line[equalSignIndex+1:]
envMap[key] = value
} else if line != "" {
return nil, faherror.UserErrorf("invalid line format: %s", line)
}
}
if err := scanner.Err(); err != nil {
return nil, err
}
return envMap, nil
}
func marshal(envMap map[string]string) (string, error) {
var lines []string
for k, v := range envMap {
if d, err := strconv.Atoi(v); err == nil {
lines = append(lines, fmt.Sprintf(`%s=%d`, k, d))
} else {
// String replacement is needed to properly escape the newline character
lines = append(lines, fmt.Sprintf(`%s=%s`, k, strings.ReplaceAll(v, "\n", "\\n")))
}
}
// Sorting as the iteration order of a map is not guaranteed to be the same every time.
// Needed for some test assertions.
sort.Strings(lines)
return strings.Join(lines, "\n"), nil
}
// ParseEnvVarsFromString parses the server side environment variables from a string to a list of EnvironmentVariables.
func ParseEnvVarsFromString(serverSideEnvVars string) ([]apphostingschema.EnvironmentVariable, error) {
var parsedServerSideEnvVars []apphostingschema.EnvironmentVariable
err := json.Unmarshal([]byte(serverSideEnvVars), &parsedServerSideEnvVars)
if err != nil {
return parsedServerSideEnvVars, fmt.Errorf("unmarshalling server side env var %v: %w", serverSideEnvVars, err)
}
return parsedServerSideEnvVars, nil
}