Skip to content

Commit

Permalink
Build UI artifacts (stashapp#4824)
Browse files Browse the repository at this point in the history
* Flag/env var for stash UI location
* Include UI in build artifacts
  • Loading branch information
WithoutPants authored and halkeye committed Sep 1, 2024
1 parent ca704dc commit 5424d75
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 29 deletions.
15 changes: 14 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,16 @@ jobs:
docker exec -t build /bin/bash -c "make build-cc-linux-arm32v6"
docker exec -t build /bin/bash -c "make build-cc-freebsd"
- name: Zip UI
run: docker exec -t build /bin/bash -c "make zip-ui"

- name: Cleanup build container
run: docker rm -f -v build

- name: Generate checksums
run: |
git describe --tags --exclude latest_develop | tee CHECKSUMS_SHA1
sha1sum dist/Stash.app.zip dist/stash-* | sed 's/dist\///g' | tee -a CHECKSUMS_SHA1
sha1sum dist/Stash.app.zip dist/stash-* dist/stash-ui.zip | sed 's/dist\///g' | tee -a CHECKSUMS_SHA1
echo "STASH_VERSION=$(git describe --tags --exclude latest_develop)" >> $GITHUB_ENV
echo "RELEASE_DATE=$(date +'%Y-%m-%d %H:%M:%S %Z')" >> $GITHUB_ENV
Expand Down Expand Up @@ -126,6 +129,14 @@ jobs:
name: stash-linux
path: dist/stash-linux

- name: Upload UI
# only upload for pull requests
if: ${{ github.event_name == 'pull_request' && github.base_ref != 'refs/heads/develop' && github.base_ref != 'refs/heads/master'}}
uses: actions/upload-artifact@v2
with:
name: stash-ui.zip
path: dist/stash-ui.zip

- name: Update latest_develop tag
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/develop' }}
run : git tag -f latest_develop; git push -f --tags
Expand All @@ -147,6 +158,7 @@ jobs:
dist/stash-linux-arm32v7
dist/stash-linux-arm32v6
dist/stash-freebsd
dist/stash-ui.zip
CHECKSUMS_SHA1
- name: Master release
Expand All @@ -166,6 +178,7 @@ jobs:
dist/stash-linux-arm32v7
dist/stash-linux-arm32v6
dist/stash-freebsd
dist/stash-ui.zip
CHECKSUMS_SHA1
gzip: false

Expand Down
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,11 @@ endif
ui: ui-env
cd ui/v2.5 && yarn build

.PHONY: zip-ui
zip-ui:
rm -f dist/stash-ui.zip
cd ui/v2.5/build && zip -r ../../../dist/stash-ui.zip .

.PHONY: ui-start
ui-start: ui-env
cd ui/v2.5 && yarn start --host
Expand Down
53 changes: 39 additions & 14 deletions internal/api/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,28 @@ type Server struct {
manager *manager.Manager
}

// TODO - os.DirFS doesn't implement ReadDir, so re-implement it here
// This can be removed when we upgrade go
type osFS string

func (dir osFS) ReadDir(name string) ([]os.DirEntry, error) {
fullname := string(dir) + "/" + name
entries, err := os.ReadDir(fullname)
if err != nil {
var e *os.PathError
if errors.As(err, &e) {
// See comment in dirFS.Open.
e.Path = name
}
return nil, err
}
return entries, nil
}

func (dir osFS) Open(name string) (fs.File, error) {
return os.DirFS(string(dir)).Open(name)
}

// Called at startup
func Initialize() (*Server, error) {
mgr := manager.GetInstance()
Expand Down Expand Up @@ -213,25 +235,31 @@ func Initialize() (*Server, error) {
r.Mount("/custom", getCustomRoutes(customServedFolders))
}

customUILocation := cfg.GetCustomUILocation()
staticUI := statigz.FileServer(ui.UIBox.(fs.ReadDirFS))
var uiFS fs.FS
var staticUI *statigz.Server
customUILocation := cfg.GetUILocation()
if customUILocation != "" {
logger.Debugf("Serving UI from %s", customUILocation)
uiFS = osFS(customUILocation)
staticUI = statigz.FileServer(uiFS.(fs.ReadDirFS))
} else {
logger.Debug("Serving embedded UI")
uiFS = ui.UIBox
staticUI = statigz.FileServer(ui.UIBox.(fs.ReadDirFS))
}

// Serve the web app
r.HandleFunc("/*", func(w http.ResponseWriter, r *http.Request) {
ext := path.Ext(r.URL.Path)

if customUILocation != "" {
if r.URL.Path == "index.html" || ext == "" {
r.URL.Path = "/"
}

http.FileServer(http.Dir(customUILocation)).ServeHTTP(w, r)
return
if ext == ".html" || ext == "" {
w.Header().Set("Content-Type", "text/html")
setPageSecurityHeaders(w, r, pluginCache.ListPlugins())
}

if ext == ".html" || ext == "" {
if ext == "" || r.URL.Path == "/" || r.URL.Path == "/index.html" {
themeColor := cfg.GetThemeColor()
data, err := fs.ReadFile(ui.UIBox, "index.html")
data, err := fs.ReadFile(uiFS, "index.html")
if err != nil {
panic(err)
}
Expand All @@ -241,9 +269,6 @@ func Initialize() (*Server, error) {
indexHtml = strings.ReplaceAll(indexHtml, "%COLOR%", themeColor)
indexHtml = strings.Replace(indexHtml, `<base href="/"`, fmt.Sprintf(`<base href="%s/"`, prefix), 1)

w.Header().Set("Content-Type", "text/html")
setPageSecurityHeaders(w, r, pluginCache.ListPlugins())

utils.ServeStaticContent(w, r, []byte(indexHtml))
} else {
isStatic, _ := path.Match("/assets/*", r.URL.Path)
Expand Down
13 changes: 10 additions & 3 deletions internal/manager/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,10 @@ const (

// UI directory. Overrides to serve the UI from a specific location
// rather than use the embedded UI.
CustomUILocation = "custom_ui_location"
UILocation = "ui_location"

// backwards compatible name
LegacyCustomUILocation = "custom_ui_location"

// Gallery Cover Regex
GalleryCoverRegex = "gallery_cover_regex"
Expand Down Expand Up @@ -1057,8 +1060,12 @@ func (i *Config) GetCustomServedFolders() utils.URLMap {
return i.getStringMapString(CustomServedFolders)
}

func (i *Config) GetCustomUILocation() string {
return i.getString(CustomUILocation)
func (i *Config) GetUILocation() string {
if ret := i.getString(UILocation); ret != "" {
return ret
}

return i.getString(LegacyCustomUILocation)
}

// Interface options
Expand Down
2 changes: 1 addition & 1 deletion internal/manager/config/config_concurrency_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ func TestConcurrentConfigAccess(t *testing.T) {
i.GetCredentials()
i.Set(MaxSessionAge, i.GetMaxSessionAge())
i.Set(CustomServedFolders, i.GetCustomServedFolders())
i.Set(CustomUILocation, i.GetCustomUILocation())
i.Set(LegacyCustomUILocation, i.GetUILocation())
i.Set(MenuItems, i.GetMenuItems())
i.Set(SoundOnPreview, i.GetSoundOnPreview())
i.Set(WallShowTitle, i.GetWallShowTitle())
Expand Down
31 changes: 21 additions & 10 deletions internal/manager/config/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"net"
"os"
"path/filepath"
"strings"

"github.com/spf13/pflag"
"github.com/spf13/viper"
Expand All @@ -26,6 +27,7 @@ func init() {
pflag.Int("port", 9999, "port to serve from")
pflag.StringVarP(&flags.configFilePath, "config", "c", "", "config file to use")
pflag.BoolVar(&flags.nobrowser, "nobrowser", false, "Don't open a browser window after launch")
pflag.StringP("ui-location", "u", "", "path to the webui")
}

// Called at startup
Expand Down Expand Up @@ -82,27 +84,36 @@ func InitializeEmpty() *Config {
return instance
}

func bindEnv(v *viper.Viper, key string) {
if err := v.BindEnv(key); err != nil {
func bindEnv(v *viper.Viper, key ...string) {
if err := v.BindEnv(key...); err != nil {
panic(fmt.Sprintf("unable to set environment key (%v): %v", key, err))
}
}

func (i *Config) initOverrides() {
v := i.overrides

// replace dashes with underscores in the flag names
normalizeFn := pflag.CommandLine.GetNormalizeFunc()
pflag.CommandLine.SetNormalizeFunc(func(f *pflag.FlagSet, name string) pflag.NormalizedName {
result := normalizeFn(f, name)
name = strings.ReplaceAll(string(result), "-", "_")
return pflag.NormalizedName(name)
})

if err := v.BindPFlags(pflag.CommandLine); err != nil {
logger.Infof("failed to bind flags: %v", err)
}

v.SetEnvPrefix("stash") // will be uppercased automatically
bindEnv(v, "host") // STASH_HOST
bindEnv(v, "port") // STASH_PORT
bindEnv(v, "external_host") // STASH_EXTERNAL_HOST
bindEnv(v, "generated") // STASH_GENERATED
bindEnv(v, "metadata") // STASH_METADATA
bindEnv(v, "cache") // STASH_CACHE
bindEnv(v, "stash") // STASH_STASH
v.SetEnvPrefix("stash") // will be uppercased automatically
bindEnv(v, "host") // STASH_HOST
bindEnv(v, "port") // STASH_PORT
bindEnv(v, "external_host") // STASH_EXTERNAL_HOST
bindEnv(v, "generated") // STASH_GENERATED
bindEnv(v, "metadata") // STASH_METADATA
bindEnv(v, "cache") // STASH_CACHE
bindEnv(v, "stash") // STASH_STASH
bindEnv(v, "ui_location", "STASH_UI") // STASH_UI
}

func (i *Config) initConfig() error {
Expand Down

0 comments on commit 5424d75

Please # to comment.