Docs: Add command that generates an overview of YAML config values

see https://docs.photoprism.app/getting-started/config-files/

Signed-off-by: Michael Mayer <michael@photoprism.app>
This commit is contained in:
Michael Mayer
2023-01-15 15:36:20 +01:00
parent 6d8030f122
commit aca929e3c9
6 changed files with 187 additions and 34 deletions

View File

@@ -7,9 +7,10 @@ import (
// ShowCommand registers the show subcommands.
var ShowCommand = cli.Command{
Name: "show",
Usage: "Shows supported formats, standards, and features",
Usage: "Shows supported formats, features, and config options",
Subcommands: []cli.Command{
ShowConfigCommand,
ShowFlagsCommand,
ShowOptionsCommand,
ShowFiltersCommand,
ShowFormatsCommand,

View File

@@ -0,0 +1,112 @@
package commands
import (
"fmt"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
"github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/pkg/report"
)
// ShowFlagsCommand configures the command name, flags, and action.
var ShowFlagsCommand = cli.Command{
Name: "flags",
Usage: "Displays supported environment variables and CLI flags",
Flags: report.CliFlags,
Action: showFlagsAction,
}
var faceFlagsInfo = `!!! info ""
To [recognize faces](https://docs.photoprism.app/user-guide/organize/people/), PhotoPrism first extracts crops from your images using a [library](https://github.com/esimov/pigo) based on [pixel intensity comparisons](https://dl.photoprism.app/pdf/20140820-Pixel_Intensity_Comparisons.pdf). These are then fed into TensorFlow to compute [512-dimensional vectors](https://dl.photoprism.app/pdf/20150101-FaceNet.pdf) for characterization. In the final step, the [DBSCAN algorithm](https://en.wikipedia.org/wiki/DBSCAN) attempts to cluster these so-called face embeddings, so they can be matched to persons with just a few clicks. A reasonable range for the similarity distance between face embeddings is between 0.60 and 0.70, with a higher value being more aggressive and leading to larger clusters with more false positives. To cluster a smaller number of faces, you can reduce the core to 3 or 2 similar faces.
We recommend that only advanced users change these parameters:`
// showFlagsAction shows environment variable command-line parameter names.
func showFlagsAction(ctx *cli.Context) error {
conf := config.NewConfig(ctx)
conf.SetLogLevel(logrus.FatalLevel)
rows, cols := config.Flags.Report()
// CSV Export?
if ctx.Bool("csv") || ctx.Bool("tsv") {
result, err := report.RenderFormat(rows, cols, report.CliFormat(ctx))
fmt.Println(result)
return err
}
type Section struct {
Start string
Title string
Info string
}
s := []Section{
{Start: "PHOTOPRISM_ADMIN_PASSWORD", Title: "Authentication"},
{Start: "PHOTOPRISM_LOG_LEVEL", Title: "Logging"},
{Start: "PHOTOPRISM_CONFIG_PATH", Title: "Storage"},
{Start: "PHOTOPRISM_WORKERS", Title: "Index Workers"},
{Start: "PHOTOPRISM_READONLY", Title: "Feature Flags"},
{Start: "PHOTOPRISM_DEFAULT_LOCALE", Title: "Customization"},
{Start: "PHOTOPRISM_CDN_URL", Title: "Site Information"},
{Start: "PHOTOPRISM_TRUSTED_PROXY", Title: "Web Server"},
{Start: "PHOTOPRISM_DATABASE_DRIVER", Title: "Database Connection"},
{Start: "PHOTOPRISM_DARKTABLE_BIN", Title: "File Converters"},
{Start: "PHOTOPRISM_DOWNLOAD_TOKEN", Title: "Security Tokens"},
{Start: "PHOTOPRISM_THUMB_COLOR", Title: "Image Quality"},
{Start: "PHOTOPRISM_FACE_SIZE", Title: "Face Recognition",
Info: faceFlagsInfo},
{Start: "PHOTOPRISM_PID_FILENAME", Title: "Daemon Mode",
Info: "If you start the server as a *daemon* in the background, you can additionally specify a filename for the log and the process ID:"},
}
j := 0
for i, sec := range s {
fmt.Printf("### %s ###\n\n", sec.Title)
if sec.Info != "" && ctx.Bool("md") {
fmt.Printf("%s\n\n", sec.Info)
}
secRows := make([][]string, 0, len(rows))
for {
row := rows[j]
if len(row) < 1 {
continue
}
if i < len(s)-1 {
if s[i+1].Start == row[0] {
break
}
}
secRows = append(secRows, row)
j++
if j >= len(rows) {
break
}
}
result, err := report.RenderFormat(secRows, cols, report.CliFormat(ctx))
if err != nil {
return err
}
fmt.Println(result)
if j >= len(rows) {
break
}
}
return nil
}

View File

@@ -12,24 +12,18 @@ import (
// ShowOptionsCommand configures the command name, flags, and action.
var ShowOptionsCommand = cli.Command{
Name: "options",
Aliases: []string{"flags"},
Usage: "Displays supported config flags and variable names",
Flags: report.CliFlags,
Action: showOptionsAction,
Name: "options",
Usage: "Displays supported YAML config options and CLI flags",
Flags: report.CliFlags,
Action: showOptionsAction,
}
var faceOptionsInfo = `!!! info ""
To [recognize faces](https://docs.photoprism.app/user-guide/organize/people/), PhotoPrism first extracts crops from your images using a [library](https://github.com/esimov/pigo) based on [pixel intensity comparisons](https://dl.photoprism.app/pdf/20140820-Pixel_Intensity_Comparisons.pdf). These are then fed into TensorFlow to compute [512-dimensional vectors](https://dl.photoprism.app/pdf/20150101-FaceNet.pdf) for characterization. In the final step, the [DBSCAN algorithm](https://en.wikipedia.org/wiki/DBSCAN) attempts to cluster these so-called face embeddings, so they can be matched to persons with just a few clicks. A reasonable range for the similarity distance between face embeddings is between 0.60 and 0.70, with a higher value being more aggressive and leading to larger clusters with more false positives. To cluster a smaller number of faces, you can reduce the core to 3 or 2 similar faces.
We recommend that only advanced users change these parameters:`
// showOptionsAction shows environment variable command-line parameter names.
// showOptionsAction shows supported YAML config file options.
func showOptionsAction(ctx *cli.Context) error {
conf := config.NewConfig(ctx)
conf.SetLogLevel(logrus.FatalLevel)
conf.SetLogLevel(logrus.TraceLevel)
rows, cols := config.Flags.Report()
rows, cols := conf.Options().Report()
// CSV Export?
if ctx.Bool("csv") || ctx.Bool("tsv") {
@@ -47,21 +41,19 @@ func showOptionsAction(ctx *cli.Context) error {
}
s := []Section{
{Start: "PHOTOPRISM_ADMIN_PASSWORD", Title: "Authentication"},
{Start: "PHOTOPRISM_LOG_LEVEL", Title: "Logging"},
{Start: "PHOTOPRISM_CONFIG_PATH", Title: "Storage"},
{Start: "PHOTOPRISM_WORKERS", Title: "Index Workers"},
{Start: "PHOTOPRISM_READONLY", Title: "Feature Flags"},
{Start: "PHOTOPRISM_DEFAULT_LOCALE", Title: "Customization"},
{Start: "PHOTOPRISM_CDN_URL", Title: "Site Information"},
{Start: "PHOTOPRISM_TRUSTED_PROXY", Title: "Web Server"},
{Start: "PHOTOPRISM_DATABASE_DRIVER", Title: "Database Connection"},
{Start: "PHOTOPRISM_DARKTABLE_BIN", Title: "File Converters"},
{Start: "PHOTOPRISM_DOWNLOAD_TOKEN", Title: "Security Tokens"},
{Start: "PHOTOPRISM_THUMB_COLOR", Title: "Image Quality"},
{Start: "PHOTOPRISM_FACE_SIZE", Title: "Face Recognition",
Info: faceOptionsInfo},
{Start: "PHOTOPRISM_PID_FILENAME", Title: "Daemon Mode",
{Start: "AuthMode", Title: "Authentication"},
{Start: "LogLevel", Title: "Logging"},
{Start: "ConfigPath", Title: "Storage"},
{Start: "Workers", Title: "Index Workers"},
{Start: "ReadOnly", Title: "Feature Flags"},
{Start: "DefaultTheme", Title: "Customization"},
{Start: "CdnUrl", Title: "Site Information"},
{Start: "TrustedProxies", Title: "Web Server"},
{Start: "DatabaseDriver", Title: "Database Connection"},
{Start: "DarktableBin", Title: "File Converters"},
{Start: "DownloadToken", Title: "Security Tokens"},
{Start: "ThumbColor", Title: "Image Quality"},
{Start: "PIDFilename", Title: "Daemon Mode",
Info: "If you start the server as a *daemon* in the background, you can additionally specify a filename for the log and the process ID:"},
}

View File

@@ -451,6 +451,22 @@ var Flags = CliFlags{
Usage: "disable HTTPS even if a certificate is available",
EnvVar: "PHOTOPRISM_DISABLE_TLS",
}}, {
Flag: cli.StringFlag{
Name: "tls-email",
Usage: "`EMAIL` address to enable automatic HTTPS via Let's Encrypt",
EnvVar: "PHOTOPRISM_TLS_EMAIL",
Hidden: true,
}}, {
Flag: cli.StringFlag{
Name: "tls-cert",
Usage: "public HTTPS certificate `FILE` (.crt)",
EnvVar: "PHOTOPRISM_TLS_CERT",
}}, {
Flag: cli.StringFlag{
Name: "tls-key",
Usage: "private HTTPS key `FILE` (.key)",
EnvVar: "PHOTOPRISM_TLS_KEY",
}}, {
Flag: cli.StringFlag{
Name: "database-driver, db",
Usage: "database `DRIVER` (sqlite, mysql)",

View File

@@ -38,10 +38,8 @@ type Options struct {
Trace bool `yaml:"Trace" json:"Trace" flag:"trace"`
Test bool `yaml:"-" json:"Test,omitempty" flag:"test"`
Unsafe bool `yaml:"-" json:"-" flag:"unsafe"`
Demo bool `yaml:"Demo" json:"-" flag:"demo"`
Demo bool `yaml:"-" json:"-" flag:"demo"`
Sponsor bool `yaml:"-" json:"-" flag:"sponsor"`
ReadOnly bool `yaml:"ReadOnly" json:"ReadOnly" flag:"read-only"`
Experimental bool `yaml:"Experimental" json:"Experimental" flag:"experimental"`
ConfigPath string `yaml:"ConfigPath" json:"-" flag:"config-path"`
DefaultsYaml string `json:"-" yaml:"-" flag:"defaults-yaml"`
OriginalsPath string `yaml:"OriginalsPath" json:"-" flag:"originals-path"`
@@ -61,6 +59,8 @@ type Options struct {
WakeupInterval time.Duration `yaml:"WakeupInterval" json:"WakeupInterval" flag:"wakeup-interval"`
AutoIndex int `yaml:"AutoIndex" json:"AutoIndex" flag:"auto-index"`
AutoImport int `yaml:"AutoImport" json:"AutoImport" flag:"auto-import"`
ReadOnly bool `yaml:"ReadOnly" json:"ReadOnly" flag:"read-only"`
Experimental bool `yaml:"Experimental" json:"Experimental" flag:"experimental"`
DisableWebDAV bool `yaml:"DisableWebDAV" json:"DisableWebDAV" flag:"disable-webdav"`
DisableBackups bool `yaml:"DisableBackups" json:"DisableBackups" flag:"disable-backups"`
DisableSettings bool `yaml:"DisableSettings" json:"-" flag:"disable-settings"`
@@ -102,7 +102,7 @@ type Options struct {
HttpHost string `yaml:"HttpHost" json:"-" flag:"http-host"`
HttpPort int `yaml:"HttpPort" json:"-" flag:"http-port"`
DisableTLS bool `yaml:"DisableTLS" json:"DisableTLS" flag:"disable-tls"`
TLSEmail string `yaml:"TLSEmail" json:"TLSEmail" flag:"tls-email"` // TLSEmail enabled automatic HTTPS via Let's Encrypt if set a valid email address.
TLSEmail string `yaml:"TLSEmail" json:"TLSEmail" flag:"tls-email"`
TLSCert string `yaml:"TLSCert" json:"TLSCert" flag:"tls-cert"`
TLSKey string `yaml:"TLSKey" json:"TLSKey" flag:"tls-key"`
DatabaseDriver string `yaml:"DatabaseDriver" json:"-" flag:"database-driver"`
@@ -126,7 +126,6 @@ type Options struct {
FFmpegEncoder string `yaml:"FFmpegEncoder" json:"FFmpegEncoder" flag:"ffmpeg-encoder"`
FFmpegBitrate int `yaml:"FFmpegBitrate" json:"FFmpegBitrate" flag:"ffmpeg-bitrate"`
ExifToolBin string `yaml:"ExifToolBin" json:"-" flag:"exiftool-bin"`
DetachServer bool `yaml:"DetachServer" json:"-" flag:"detach-server"`
DownloadToken string `yaml:"DownloadToken" json:"-" flag:"download-token"`
PreviewToken string `yaml:"PreviewToken" json:"-" flag:"preview-token"`
ThumbColor string `yaml:"ThumbColor" json:"ThumbColor" flag:"thumb-color"`
@@ -146,6 +145,7 @@ type Options struct {
FaceMatchDist float64 `yaml:"-" json:"-" flag:"face-match-dist"`
PIDFilename string `yaml:"PIDFilename" json:"-" flag:"pid-filename"`
LogFilename string `yaml:"LogFilename" json:"-" flag:"log-filename"`
DetachServer bool `yaml:"DetachServer" json:"-" flag:"detach-server"`
}
// NewOptions creates a new configuration entity by using two methods:

View File

@@ -0,0 +1,32 @@
package config
import (
"fmt"
"reflect"
)
// Report returns global config values as a table for reporting.
func (c Options) Report() (rows [][]string, cols []string) {
v := reflect.ValueOf(c)
cols = []string{"Name", "Type", "CLI Flag"}
rows = make([][]string, 0, v.NumField())
// Iterate through all config fields.
for i := 0; i < v.NumField(); i++ {
fieldValue := v.Field(i)
yamlName := v.Type().Field(i).Tag.Get("yaml")
flagName := v.Type().Field(i).Tag.Get("flag")
if yamlName == "" || yamlName == "-" || flagName == "" {
continue
}
fieldType := fmt.Sprintf("%T", fieldValue.Interface())
rows = append(rows, []string{yamlName, fieldType, "--" + flagName})
}
return rows, cols
}