@@ -3,6 +3,7 @@ package config
33import (
44 "errors"
55 "fmt"
6+ "io"
67 "log"
78 "net/url"
89 "os"
@@ -62,6 +63,9 @@ func Init() {
6263 LogLevel = normalizeLogLevel (viper .GetString ("log_level" ))
6364 StaticPath = normalizeStaticURLPath (viper .GetString ("static_path" ))
6465 StaticFilePath = filepath .Join (configRootPath , strings .TrimPrefix (StaticPath , "/" ))
66+ if err = ensureConfiguredStaticFiles (); err != nil {
67+ panic (err )
68+ }
6569 RuntimePath = resolvePathFromBase (configRootPath , viper .GetString ("runtime_root_path" ), filepath .Join (configRootPath , "runtime" ))
6670 LogSavePath = resolvePathFromBase (RuntimePath , viper .GetString ("log_save_path" ), filepath .Join (RuntimePath , "logs" ))
6771 mustMkdir (RuntimePath )
@@ -82,6 +86,93 @@ func mustMkdir(path string) {
8286 }
8387}
8488
89+ func ensureConfiguredStaticFiles () error {
90+ if strings .TrimSpace (StaticFilePath ) == "" {
91+ return nil
92+ }
93+ exePath , err := os .Executable ()
94+ if err != nil {
95+ return err
96+ }
97+ exePath , err = filepath .EvalSymlinks (exePath )
98+ if err != nil {
99+ return err
100+ }
101+
102+ srcDir := filepath .Join (filepath .Dir (exePath ), "static" )
103+ srcInfo , err := os .Stat (srcDir )
104+ if err != nil {
105+ if errors .Is (err , os .ErrNotExist ) {
106+ return nil
107+ }
108+ return err
109+ }
110+ if ! srcInfo .IsDir () {
111+ return nil
112+ }
113+
114+ srcAbs , err := filepath .Abs (srcDir )
115+ if err != nil {
116+ return err
117+ }
118+ dstAbs , err := filepath .Abs (StaticFilePath )
119+ if err != nil {
120+ return err
121+ }
122+ if srcAbs == dstAbs {
123+ return nil
124+ }
125+
126+ return copyMissingStaticFiles (srcAbs , dstAbs )
127+ }
128+
129+ func copyMissingStaticFiles (srcDir , dstDir string ) error {
130+ return filepath .WalkDir (srcDir , func (path string , d os.DirEntry , err error ) error {
131+ if err != nil {
132+ return err
133+ }
134+ rel , err := filepath .Rel (srcDir , path )
135+ if err != nil {
136+ return err
137+ }
138+ dstPath := filepath .Join (dstDir , rel )
139+ if d .IsDir () {
140+ return os .MkdirAll (dstPath , 0o755 )
141+ }
142+ if _ , err = os .Stat (dstPath ); err == nil {
143+ return nil
144+ } else if ! errors .Is (err , os .ErrNotExist ) {
145+ return err
146+ }
147+ if err = os .MkdirAll (filepath .Dir (dstPath ), 0o755 ); err != nil {
148+ return err
149+ }
150+ return copyFile (path , dstPath )
151+ })
152+ }
153+
154+ func copyFile (srcPath , dstPath string ) error {
155+ in , err := os .Open (srcPath )
156+ if err != nil {
157+ return err
158+ }
159+ defer in .Close ()
160+
161+ out , err := os .OpenFile (dstPath , os .O_CREATE | os .O_EXCL | os .O_WRONLY , 0o644 )
162+ if err != nil {
163+ if errors .Is (err , os .ErrExist ) {
164+ return nil
165+ }
166+ return err
167+ }
168+
169+ if _ , err = io .Copy (out , in ); err != nil {
170+ _ = out .Close ()
171+ return err
172+ }
173+ return out .Close ()
174+ }
175+
85176func normalizeLogLevel (level string ) string {
86177 switch strings .ToLower (strings .TrimSpace (level )) {
87178 case "debug" , "info" , "warn" , "error" :
0 commit comments