summaryrefslogtreecommitdiffstats
path: root/modules/util
diff options
context:
space:
mode:
authorwxiaoguang <wxiaoguang@gmail.com>2023-04-12 18:16:45 +0800
committerGitHub <noreply@github.com>2023-04-12 18:16:45 +0800
commit50a72e7a83a16d183a264e969a73cdbc7fb808f4 (patch)
tree013456110621c36edb3fa0d1bb77906ba8d4e013 /modules/util
parent42919ccb7cd32ab67d0878baf2bac6cd007899a8 (diff)
downloadgitea-50a72e7a83a16d183a264e969a73cdbc7fb808f4.tar.gz
gitea-50a72e7a83a16d183a264e969a73cdbc7fb808f4.zip
Use a general approach to access custom/static/builtin assets (#24022)
The idea is to use a Layered Asset File-system (modules/assetfs/layered.go) For example: when there are 2 layers: "custom", "builtin", when access to asset "my/page.tmpl", the Layered Asset File-system will first try to use "custom" assets, if not found, then use "builtin" assets. This approach will hugely simplify a lot of code, make them testable. Other changes: * Simplify the AssetsHandlerFunc code * Simplify the `gitea embedded` sub-command code --------- Co-authored-by: Jason Song <i@wolfogre.com> Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Diffstat (limited to 'modules/util')
-rw-r--r--modules/util/path.go19
-rw-r--r--modules/util/path_test.go2
-rw-r--r--modules/util/timer.go28
-rw-r--r--modules/util/timer_test.go30
4 files changed, 68 insertions, 11 deletions
diff --git a/modules/util/path.go b/modules/util/path.go
index 37d06e9813..1a68bc7488 100644
--- a/modules/util/path.go
+++ b/modules/util/path.go
@@ -74,29 +74,28 @@ const pathSeparator = string(os.PathSeparator)
//
// {`/foo`, ``, `bar`} => `/foo/bar`
// {`/foo`, `..`, `bar`} => `/foo/bar`
-func FilePathJoinAbs(elem ...string) string {
- elems := make([]string, len(elem))
+func FilePathJoinAbs(base string, sub ...string) string {
+ elems := make([]string, 1, len(sub)+1)
- // POISX filesystem can have `\` in file names. Windows: `\` and `/` are both used for path separators
+ // POSIX filesystem can have `\` in file names. Windows: `\` and `/` are both used for path separators
// to keep the behavior consistent, we do not allow `\` in file names, replace all `\` with `/`
if isOSWindows() {
- elems[0] = filepath.Clean(elem[0])
+ elems[0] = filepath.Clean(base)
} else {
- elems[0] = filepath.Clean(strings.ReplaceAll(elem[0], "\\", pathSeparator))
+ elems[0] = filepath.Clean(strings.ReplaceAll(base, "\\", pathSeparator))
}
if !filepath.IsAbs(elems[0]) {
// This shouldn't happen. If there is really necessary to pass in relative path, return the full path with filepath.Abs() instead
panic(fmt.Sprintf("FilePathJoinAbs: %q (for path %v) is not absolute, do not guess a relative path based on current working directory", elems[0], elems))
}
-
- for i := 1; i < len(elem); i++ {
- if elem[i] == "" {
+ for _, s := range sub {
+ if s == "" {
continue
}
if isOSWindows() {
- elems[i] = filepath.Clean(pathSeparator + elem[i])
+ elems = append(elems, filepath.Clean(pathSeparator+s))
} else {
- elems[i] = filepath.Clean(pathSeparator + strings.ReplaceAll(elem[i], "\\", pathSeparator))
+ elems = append(elems, filepath.Clean(pathSeparator+strings.ReplaceAll(s, "\\", pathSeparator)))
}
}
// the elems[0] must be an absolute path, just join them together
diff --git a/modules/util/path_test.go b/modules/util/path_test.go
index 1d27c9bf0c..6a38bf4ace 100644
--- a/modules/util/path_test.go
+++ b/modules/util/path_test.go
@@ -207,6 +207,6 @@ func TestCleanPath(t *testing.T) {
}
}
for _, c := range cases {
- assert.Equal(t, c.expected, FilePathJoinAbs(c.elems...), "case: %v", c.elems)
+ assert.Equal(t, c.expected, FilePathJoinAbs(c.elems[0], c.elems[1:]...), "case: %v", c.elems)
}
}
diff --git a/modules/util/timer.go b/modules/util/timer.go
index daf96bda7e..d598fde73a 100644
--- a/modules/util/timer.go
+++ b/modules/util/timer.go
@@ -4,6 +4,7 @@
package util
import (
+ "sync"
"time"
)
@@ -18,3 +19,30 @@ func StopTimer(t *time.Timer) bool {
}
return stopped
}
+
+func Debounce(d time.Duration) func(f func()) {
+ type debouncer struct {
+ mu sync.Mutex
+ t *time.Timer
+ }
+ db := &debouncer{}
+
+ return func(f func()) {
+ db.mu.Lock()
+ defer db.mu.Unlock()
+
+ if db.t != nil {
+ db.t.Stop()
+ }
+ var trigger *time.Timer
+ trigger = time.AfterFunc(d, func() {
+ db.mu.Lock()
+ defer db.mu.Unlock()
+ if trigger == db.t {
+ f()
+ db.t = nil
+ }
+ })
+ db.t = trigger
+ }
+}
diff --git a/modules/util/timer_test.go b/modules/util/timer_test.go
new file mode 100644
index 0000000000..602800c248
--- /dev/null
+++ b/modules/util/timer_test.go
@@ -0,0 +1,30 @@
+// Copyright 2023 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package util
+
+import (
+ "sync/atomic"
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestDebounce(t *testing.T) {
+ var c int64
+ d := Debounce(50 * time.Millisecond)
+ d(func() { atomic.AddInt64(&c, 1) })
+ assert.EqualValues(t, 0, atomic.LoadInt64(&c))
+ d(func() { atomic.AddInt64(&c, 1) })
+ d(func() { atomic.AddInt64(&c, 1) })
+ time.Sleep(100 * time.Millisecond)
+ assert.EqualValues(t, 1, atomic.LoadInt64(&c))
+ d(func() { atomic.AddInt64(&c, 1) })
+ assert.EqualValues(t, 1, atomic.LoadInt64(&c))
+ d(func() { atomic.AddInt64(&c, 1) })
+ d(func() { atomic.AddInt64(&c, 1) })
+ d(func() { atomic.AddInt64(&c, 1) })
+ time.Sleep(100 * time.Millisecond)
+ assert.EqualValues(t, 2, atomic.LoadInt64(&c))
+}