@@ -2,12 +2,12 @@ package step
22
33import (
44 "fmt"
5- "log"
65 "os"
76 "os/user"
87 "path/filepath"
98 "runtime"
109 "strings"
10+ "sync"
1111 "time"
1212)
1313
@@ -24,55 +24,65 @@ var (
2424 name = "Smallstep CLI"
2525 buildTime = "N/A"
2626 version = "N/A"
27+ )
2728
28- // stepBasePath will be populated in init() with the proper STEPPATH.
29- stepBasePath string
29+ var cache struct {
30+ sync.Once
31+ err error
32+ stepBasePath string // stepBasePath will be populated in init() with the proper STEPPATH.
33+ homePath string // homePath will be populated in init() with the proper HOME.
34+ }
3035
31- // homePath will be populated in init() with the proper HOME.
32- homePath string
33- )
36+ // Init initializes the step environment.
37+ //
38+ // A program calling this function should fail because the step variables would
39+ // be undefined.
40+ func Init () error {
41+ if err := initStepPath (); err != nil {
42+ return err
43+ }
44+ return Contexts ().Init ()
45+ }
46+
47+ func initStepPath () error {
48+ cache .Do (func () {
49+ // Get home path from environment or from the user object.
50+ homePath := os .Getenv (HomeEnv )
51+ if homePath == "" {
52+ usr , err := user .Current ()
53+ if err == nil && usr .HomeDir != "" {
54+ homePath = usr .HomeDir
55+ } else {
56+ cache .err = fmt .Errorf ("error obtaining home directory, please define environment variable %s" , HomeEnv )
57+ return
58+ }
59+ }
3460
35- func init () {
36- l := log .New (os .Stderr , "" , 0 )
37-
38- // Get home path from environment or from the user object.
39- homePath = os .Getenv (HomeEnv )
40- if homePath == "" {
41- usr , err := user .Current ()
42- if err == nil && usr .HomeDir != "" {
43- homePath = usr .HomeDir
44- } else {
45- l .Fatalf ("Error obtaining home directory, please define environment variable %s." , HomeEnv )
61+ // Get step path from environment or relative to home.
62+ stepBasePath := os .Getenv (PathEnv )
63+ if stepBasePath == "" {
64+ stepBasePath = filepath .Join (homePath , ".step" )
4665 }
47- }
4866
49- // Get step path from environment or relative to home.
50- stepBasePath = os .Getenv (PathEnv )
51- if stepBasePath == "" {
52- stepBasePath = filepath .Join (homePath , ".step" )
53- }
67+ // cleanup and add paths to cache
68+ cache .homePath = filepath .Clean (homePath )
69+ cache .stepBasePath = filepath .Clean (stepBasePath )
70+ })
5471
55- // cleanup
56- homePath = filepath .Clean (homePath )
57- stepBasePath = filepath .Clean (stepBasePath )
58-
59- // Check for presence or attempt to create it if necessary.
60- //
61- // Some environments (e.g. third party docker images) might fail creating
62- // the directory, so this should not panic if it can't.
63- if fi , err := os .Stat (stepBasePath ); err != nil {
64- os .MkdirAll (stepBasePath , 0700 )
65- } else if ! fi .IsDir () {
66- l .Fatalf ("File '%s' is not a directory." , stepBasePath )
67- }
72+ return cache .err
73+ }
6874
69- // Initialize context state.
70- Contexts ().Init ()
75+ // Home returns the user home directory using the environment variable HOME or
76+ // the os/user package.
77+ func Home () string {
78+ _ = initStepPath ()
79+ return cache .homePath
7180}
7281
7382// BasePath returns the base path for the step configuration directory.
7483func BasePath () string {
75- return stepBasePath
84+ _ = initStepPath ()
85+ return cache .stepBasePath
7686}
7787
7888// Path returns the path for the step configuration directory.
@@ -153,12 +163,6 @@ func CurrentContextFile() string {
153163 return filepath .Join (BasePath (), "current-context.json" )
154164}
155165
156- // Home returns the user home directory using the environment variable HOME or
157- // the os/user package.
158- func Home () string {
159- return homePath
160- }
161-
162166// Abs returns the given path relative to the STEPPATH if it's not an
163167// absolute path, relative to the home directory using the special string "~/",
164168// or relative to the working directory using "./"
@@ -176,7 +180,7 @@ func Abs(path string) string {
176180 slashed := filepath .ToSlash (path )
177181 switch {
178182 case strings .HasPrefix (slashed , "~/" ):
179- return filepath .Join (homePath , path [2 :])
183+ return filepath .Join (Home () , path [2 :])
180184 case strings .HasPrefix (slashed , "./" ), strings .HasPrefix (slashed , "../" ):
181185 if abs , err := filepath .Abs (path ); err == nil {
182186 return abs
0 commit comments