mirror of
https://github.com/stashapp/stash.git
synced 2025-12-15 04:44:28 +01:00
Fix initial setup issue issues (#1380)
* Refactor initial setup behaviour * Adjust wizard
This commit is contained in:
parent
5a37e6cf52
commit
e0623eb302
6 changed files with 133 additions and 34 deletions
|
|
@ -12,5 +12,6 @@ query SystemStatus {
|
|||
databasePath
|
||||
appSchema
|
||||
status
|
||||
configPath
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,6 +116,7 @@ enum SystemStatusEnum {
|
|||
type SystemStatus {
|
||||
databaseSchema: Int
|
||||
databasePath: String
|
||||
configPath: String
|
||||
appSchema: Int!
|
||||
status: SystemStatusEnum!
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,7 +141,9 @@ func (e MissingConfigError) Error() string {
|
|||
return fmt.Sprintf("missing the following mandatory settings: %s", strings.Join(e.missingFields, ", "))
|
||||
}
|
||||
|
||||
type Instance struct{}
|
||||
type Instance struct {
|
||||
isNewSystem bool
|
||||
}
|
||||
|
||||
var instance *Instance
|
||||
|
||||
|
|
@ -152,6 +154,10 @@ func GetInstance() *Instance {
|
|||
return instance
|
||||
}
|
||||
|
||||
func (i *Instance) IsNewSystem() bool {
|
||||
return i.isNewSystem
|
||||
}
|
||||
|
||||
func (i *Instance) SetConfigFile(fn string) {
|
||||
viper.SetConfigFile(fn)
|
||||
}
|
||||
|
|
@ -687,29 +693,26 @@ func (i *Instance) Validate() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (i *Instance) setDefaultValues() {
|
||||
func (i *Instance) setDefaultValues() error {
|
||||
viper.SetDefault(ParallelTasks, parallelTasksDefault)
|
||||
viper.SetDefault(PreviewSegmentDuration, previewSegmentDurationDefault)
|
||||
viper.SetDefault(PreviewSegments, previewSegmentsDefault)
|
||||
viper.SetDefault(PreviewExcludeStart, previewExcludeStartDefault)
|
||||
viper.SetDefault(PreviewExcludeEnd, previewExcludeEndDefault)
|
||||
|
||||
// #1356 - only set these defaults once config file exists
|
||||
if i.GetConfigFile() != "" {
|
||||
viper.SetDefault(Database, i.GetDefaultDatabaseFilePath())
|
||||
viper.SetDefault(Database, i.GetDefaultDatabaseFilePath())
|
||||
|
||||
// Set generated to the metadata path for backwards compat
|
||||
viper.SetDefault(Generated, viper.GetString(Metadata))
|
||||
// Set generated to the metadata path for backwards compat
|
||||
viper.SetDefault(Generated, viper.GetString(Metadata))
|
||||
|
||||
// Set default scrapers and plugins paths
|
||||
viper.SetDefault(ScrapersPath, i.GetDefaultScrapersPath())
|
||||
viper.SetDefault(PluginsPath, i.GetDefaultPluginsPath())
|
||||
viper.WriteConfig()
|
||||
}
|
||||
// Set default scrapers and plugins paths
|
||||
viper.SetDefault(ScrapersPath, i.GetDefaultScrapersPath())
|
||||
viper.SetDefault(PluginsPath, i.GetDefaultPluginsPath())
|
||||
return viper.WriteConfig()
|
||||
}
|
||||
|
||||
// SetInitialConfig fills in missing required config fields
|
||||
func (i *Instance) SetInitialConfig() {
|
||||
func (i *Instance) SetInitialConfig() error {
|
||||
// generate some api keys
|
||||
const apiKeyLength = 32
|
||||
|
||||
|
|
@ -723,5 +726,9 @@ func (i *Instance) SetInitialConfig() {
|
|||
i.Set(SessionStoreKey, sessionStoreKey)
|
||||
}
|
||||
|
||||
i.setDefaultValues()
|
||||
return i.setDefaultValues()
|
||||
}
|
||||
|
||||
func (i *Instance) FinalizeSetup() {
|
||||
i.isNewSystem = false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"sync"
|
||||
|
|
@ -24,8 +25,22 @@ func Initialize() (*Instance, error) {
|
|||
instance = &Instance{}
|
||||
|
||||
flags := initFlags()
|
||||
err = initConfig(flags)
|
||||
if err = initConfig(flags); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
initEnvs()
|
||||
|
||||
if instance.isNewSystem {
|
||||
if instance.Validate() == nil {
|
||||
// system has been initialised by the environment
|
||||
instance.isNewSystem = false
|
||||
}
|
||||
}
|
||||
|
||||
if !instance.isNewSystem {
|
||||
err = instance.SetInitialConfig()
|
||||
}
|
||||
})
|
||||
return instance, err
|
||||
}
|
||||
|
|
@ -34,26 +49,47 @@ func initConfig(flags flagStruct) error {
|
|||
// The config file is called config. Leave off the file extension.
|
||||
viper.SetConfigName("config")
|
||||
|
||||
if flagConfigFileExists, _ := utils.FileExists(flags.configFilePath); flagConfigFileExists {
|
||||
viper.SetConfigFile(flags.configFilePath)
|
||||
}
|
||||
viper.AddConfigPath(".") // Look for config in the working directory
|
||||
viper.AddConfigPath("$HOME/.stash") // Look for the config in the home directory
|
||||
|
||||
// for Docker compatibility, if STASH_CONFIG_FILE is set, then touch the
|
||||
// given filename
|
||||
configFile := ""
|
||||
envConfigFile := os.Getenv("STASH_CONFIG_FILE")
|
||||
if envConfigFile != "" {
|
||||
utils.Touch(envConfigFile)
|
||||
viper.SetConfigFile(envConfigFile)
|
||||
|
||||
if flags.configFilePath != "" {
|
||||
configFile = flags.configFilePath
|
||||
} else if envConfigFile != "" {
|
||||
configFile = envConfigFile
|
||||
}
|
||||
|
||||
if configFile != "" {
|
||||
viper.SetConfigFile(configFile)
|
||||
|
||||
// if file does not exist, assume it is a new system
|
||||
if exists, _ := utils.FileExists(configFile); !exists {
|
||||
instance.isNewSystem = true
|
||||
|
||||
// ensure we can write to the file
|
||||
if err := utils.Touch(configFile); err != nil {
|
||||
return fmt.Errorf(`could not write to provided config path "%s": %s`, configFile, err.Error())
|
||||
} else {
|
||||
// remove the file
|
||||
os.Remove(configFile)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
err := viper.ReadInConfig() // Find and read the config file
|
||||
// continue, but set an error to be handled by caller
|
||||
// if not found, assume its a new system
|
||||
if _, isMissing := err.(viper.ConfigFileNotFoundError); isMissing {
|
||||
instance.isNewSystem = true
|
||||
return nil
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
instance.SetInitialConfig()
|
||||
|
||||
return err
|
||||
return nil
|
||||
}
|
||||
|
||||
func initFlags() flagStruct {
|
||||
|
|
|
|||
|
|
@ -49,6 +49,11 @@ func Initialize() *singleton {
|
|||
once.Do(func() {
|
||||
_ = utils.EnsureDir(paths.GetStashHomeDirectory())
|
||||
cfg, err := config.Initialize()
|
||||
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("error initializing configuration: %s", err.Error()))
|
||||
}
|
||||
|
||||
initLog()
|
||||
|
||||
instance = &singleton{
|
||||
|
|
@ -59,8 +64,7 @@ func Initialize() *singleton {
|
|||
TxnManager: sqlite.NewTransactionManager(),
|
||||
}
|
||||
|
||||
cfgFile := cfg.GetConfigFile()
|
||||
if cfgFile != "" {
|
||||
if !cfg.IsNewSystem() {
|
||||
logger.Infof("using config file: %s", cfg.GetConfigFile())
|
||||
|
||||
if err == nil {
|
||||
|
|
@ -75,7 +79,11 @@ func Initialize() *singleton {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
logger.Warn("config file not found. Assuming new system...")
|
||||
cfgFile := cfg.GetConfigFile()
|
||||
if cfgFile != "" {
|
||||
cfgFile = cfgFile + " "
|
||||
}
|
||||
logger.Warnf("config file %snot found. Assuming new system...", cfgFile)
|
||||
}
|
||||
|
||||
initFFMPEG()
|
||||
|
|
@ -235,6 +243,8 @@ func (s *singleton) Setup(input models.SetupInput) error {
|
|||
return fmt.Errorf("error initializing the database: %s", err.Error())
|
||||
}
|
||||
|
||||
s.Config.FinalizeSetup()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -283,8 +293,9 @@ func (s *singleton) GetSystemStatus() *models.SystemStatus {
|
|||
dbSchema := int(database.Version())
|
||||
dbPath := database.DatabasePath()
|
||||
appSchema := int(database.AppSchemaVersion())
|
||||
configFile := s.Config.GetConfigFile()
|
||||
|
||||
if s.Config.GetConfigFile() == "" {
|
||||
if s.Config.IsNewSystem() {
|
||||
status = models.SystemStatusEnumSetup
|
||||
} else if dbSchema < appSchema {
|
||||
status = models.SystemStatusEnumNeedsMigration
|
||||
|
|
@ -295,5 +306,6 @@ func (s *singleton) GetSystemStatus() *models.SystemStatus {
|
|||
DatabasePath: &dbPath,
|
||||
AppSchema: appSchema,
|
||||
Status: status,
|
||||
ConfigPath: &configFile,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useState } from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import {
|
||||
Alert,
|
||||
Button,
|
||||
|
|
@ -27,6 +27,12 @@ export const Setup: React.FC = () => {
|
|||
|
||||
const { data: systemStatus, loading: statusLoading } = useSystemStatus();
|
||||
|
||||
useEffect(() => {
|
||||
if (systemStatus?.systemStatus.configPath) {
|
||||
setConfigLocation(systemStatus.systemStatus.configPath);
|
||||
}
|
||||
}, [systemStatus]);
|
||||
|
||||
const discordLink = (
|
||||
<a href="https://discord.gg/2TsNFKt" target="_blank" rel="noreferrer">
|
||||
Discord
|
||||
|
|
@ -59,6 +65,38 @@ export const Setup: React.FC = () => {
|
|||
setStep(step + 1);
|
||||
}
|
||||
|
||||
function renderWelcomeSpecificConfig() {
|
||||
return (
|
||||
<>
|
||||
<section>
|
||||
<h2 className="mb-5">Welcome to Stash</h2>
|
||||
<p className="lead text-center">
|
||||
If you're reading this, then Stash couldn't find the
|
||||
configuration file specified at the command line or the environment.
|
||||
This wizard will guide you through the process of setting up a new
|
||||
configuration.
|
||||
</p>
|
||||
<p>
|
||||
Stash will use the following configuration file path:{" "}
|
||||
<code>{configLocation}</code>
|
||||
</p>
|
||||
<p>
|
||||
When you're ready to proceed with setting up a new system,
|
||||
click Next.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section className="mt-5">
|
||||
<div className="d-flex justify-content-center">
|
||||
<Button variant="primary mx-2 p-5" onClick={() => next()}>
|
||||
Next
|
||||
</Button>
|
||||
</div>
|
||||
</section>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function renderWelcome() {
|
||||
return (
|
||||
<>
|
||||
|
|
@ -433,8 +471,6 @@ export const Setup: React.FC = () => {
|
|||
return renderSuccess();
|
||||
}
|
||||
|
||||
const steps = [renderWelcome, renderSetPaths, renderConfirm, renderFinish];
|
||||
|
||||
// only display setup wizard if system is not setup
|
||||
if (statusLoading) {
|
||||
return <LoadingIndicator />;
|
||||
|
|
@ -450,6 +486,12 @@ export const Setup: React.FC = () => {
|
|||
return <LoadingIndicator />;
|
||||
}
|
||||
|
||||
const welcomeStep =
|
||||
systemStatus && systemStatus.systemStatus.configPath !== ""
|
||||
? renderWelcomeSpecificConfig
|
||||
: renderWelcome;
|
||||
const steps = [welcomeStep, renderSetPaths, renderConfirm, renderFinish];
|
||||
|
||||
return (
|
||||
<Container>
|
||||
{maybeRenderGeneratedSelectDialog()}
|
||||
|
|
|
|||
Loading…
Reference in a new issue