diff --git a/go.mod b/go.mod index 2fc50e7..2a3ea91 100644 --- a/go.mod +++ b/go.mod @@ -39,7 +39,7 @@ require ( github.com/x448/float16 v0.8.4 golang.org/x/exp v0.0.0-20231006140011-7918f672742d golang.org/x/image v0.0.0-20191214001246-9130b4cfad52 - golang.org/x/sync v0.4.0 + golang.org/x/sync v0.5.0 modernc.org/sqlite v1.27.0 zombiezen.com/go/sqlite v0.13.1 ) @@ -81,10 +81,10 @@ require ( github.com/tdewolff/parse/v2 v2.4.2 // indirect github.com/wcharczuk/go-chart v2.0.2-0.20191206192251-962b9abdec2b+incompatible // indirect go.uber.org/atomic v1.7.0 // indirect - golang.org/x/mod v0.13.0 // indirect - golang.org/x/sys v0.14.0 // indirect - golang.org/x/text v0.3.7 // indirect - golang.org/x/tools v0.14.0 // indirect + golang.org/x/mod v0.14.0 // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/text v0.14.0 // indirect + golang.org/x/tools v0.16.1 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect gonum.org/v1/plot v0.0.0-20190410204940-3a5f52653745 // indirect google.golang.org/protobuf v1.26.0 // indirect diff --git a/go.sum b/go.sum index 0e0b68d..d48075d 100644 --- a/go.sum +++ b/go.sum @@ -731,8 +731,8 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= -golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -804,8 +804,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= -golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180224232135-f6cff0780e54/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -875,8 +875,8 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210521090106-6ca3eb03dfc2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= -golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -887,8 +887,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20170424234030-8be79e1e0910/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -956,8 +956,8 @@ golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= -golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= +golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA= +golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/internal/fs/rewrite/fs.go b/internal/fs/rewrite/fs.go new file mode 100644 index 0000000..56c7582 --- /dev/null +++ b/internal/fs/rewrite/fs.go @@ -0,0 +1,81 @@ +package rewrite + +import ( + "io" + "io/fs" + "regexp" + "strings" + "testing/fstest" + "time" +) + +type FileSystem struct { + FS fs.FS + rewritten fstest.MapFS +} + +func FS(fs fs.FS, exts []string, regex string, replace string) (*FileSystem, error) { + rfs := &FileSystem{ + FS: fs, + rewritten: make(fstest.MapFS), + } + var err error + re, err := regexp.Compile(regex) + if err != nil { + return nil, err + } + err = rfs.replace(exts, re, replace) + if err != nil { + return nil, err + } + return rfs, nil +} + +func (rfs *FileSystem) Open(name string) (fs.File, error) { + if f, err := rfs.rewritten.Open(name); err == nil { + return f, nil + } + return rfs.FS.Open(name) +} + +func (rfs *FileSystem) replace(exts []string, re *regexp.Regexp, repl string) error { + fs.WalkDir(rfs.FS, ".", func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + if d.IsDir() { + return nil + } + + if !strings.HasSuffix(path, ".html") && + !strings.HasSuffix(path, ".css") && + !strings.HasSuffix(path, ".js") { + return nil + } + + f, err := rfs.FS.Open(path) + if err != nil { + return err + } + defer f.Close() + + data, err := io.ReadAll(f) + if err != nil { + return err + } + + str := string(data) + + r := re.ReplaceAllString(str, repl) + contains := str != r + if contains { + rfs.rewritten[path] = &fstest.MapFile{ + Data: []byte(r), + Mode: 0644, + ModTime: time.Now(), + } + } + return nil + }) + return nil +} diff --git a/main.go b/main.go index 5736512..fb6919e 100644 --- a/main.go +++ b/main.go @@ -54,6 +54,7 @@ import ( "photofield/internal/codec" "photofield/internal/collection" + "photofield/internal/fs/rewrite" "photofield/internal/geo" "photofield/internal/image" "photofield/internal/layout" @@ -647,17 +648,17 @@ func (*Api) PostTasks(w http.ResponseWriter, r *http.Request) { } func (*Api) GetCapabilities(w http.ResponseWriter, r *http.Request) { - docsUrl := os.Getenv("PHOTOFIELD_DOCS_URL") - if docsUrl == "" { - docsUrl = "/docs/usage" + docsurl := os.Getenv("PHOTOFIELD_DOCS_URL") + if docsurl == "" { + docsurl = "/docs/usage" } capabilities := openapi.Capabilities{} if imageSource != nil { capabilities.Search.Supported = imageSource.AI.Available() } capabilities.Tags.Supported = tagsEnabled - capabilities.Docs.Supported = docsUrl != "" - capabilities.Docs.Url = docsUrl + capabilities.Docs.Supported = docsurl != "" + capabilities.Docs.Url = docsurl respond(w, r, http.StatusOK, capabilities) } @@ -1483,6 +1484,24 @@ func main() { if err != nil { panic(err) } + docspath := os.Getenv("PHOTOFIELD_DOCS_PATH") + if docspath != "" { + // rewriteDocs(docfs, docsurl) + var err error + docfs, err = rewrite.FS( + docfs, + []string{ + "html", + "css", + "js", + }, + `("|url\()(/docs/)`, + `${1}`+docspath, + ) + if err != nil { + panic(err) + } + } dochandler := gzipped.FileServer(http.FS(docfs)) r.HandleFunc("/docs/*", func(w http.ResponseWriter, r *http.Request) { if ext := path.Ext(r.URL.Path); ext == "" {