2023-06-19 14:42:47 -07:00
// SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
2018-01-02 22:04:48 -08:00
2023-08-10 19:46:45 -07:00
package cli // import "miniflux.app/v2/internal/cli"
2018-01-02 22:04:48 -08:00
import (
2024-08-12 19:27:08 -07:00
"errors"
2018-01-02 22:04:48 -08:00
"flag"
"fmt"
2023-09-24 16:32:09 -07:00
"io"
"log/slog"
"os"
2018-01-02 22:04:48 -08:00
2023-08-10 19:46:45 -07:00
"miniflux.app/v2/internal/config"
"miniflux.app/v2/internal/database"
"miniflux.app/v2/internal/locale"
"miniflux.app/v2/internal/storage"
"miniflux.app/v2/internal/ui/static"
"miniflux.app/v2/internal/version"
2018-01-02 22:04:48 -08:00
)
2018-10-08 21:00:00 -07:00
const (
2023-06-25 11:23:23 -07:00
flagInfoHelp = "Show build information"
2018-11-11 15:32:48 -08:00
flagVersionHelp = "Show application version"
flagMigrateHelp = "Run SQL migrations"
2019-09-25 18:55:16 -07:00
flagFlushSessionsHelp = "Flush all sessions (disconnect users)"
2024-03-23 14:05:05 -07:00
flagCreateAdminHelp = "Create an admin user from an interactive terminal"
2018-11-11 15:32:48 -08:00
flagResetPasswordHelp = "Reset user password"
2018-10-08 21:00:00 -07:00
flagResetFeedErrorsHelp = "Clear all feed errors for all users"
2018-11-11 15:32:48 -08:00
flagDebugModeHelp = "Show debug logs"
2019-06-02 18:20:59 -07:00
flagConfigFileHelp = "Load configuration file"
flagConfigDumpHelp = "Print parsed configuration values"
2021-02-20 12:42:15 -08:00
flagHealthCheckHelp = ` Perform a health check on the given endpoint (the value "auto" try to guess the health check endpoint). `
2023-06-25 11:23:23 -07:00
flagRefreshFeedsHelp = "Refresh a batch of feeds and exit"
flagRunCleanupTasksHelp = "Run cleanup tasks (delete old sessions and archives old entries)"
2023-09-27 21:15:32 -07:00
flagExportUserFeedsHelp = "Export user feeds (provide the username as argument)"
2018-10-08 21:00:00 -07:00
)
2018-01-02 22:04:48 -08:00
// Parse parses command line arguments.
func Parse ( ) {
2018-10-08 21:00:00 -07:00
var (
2019-06-02 18:20:59 -07:00
err error
2018-11-11 15:32:48 -08:00
flagInfo bool
flagVersion bool
flagMigrate bool
flagFlushSessions bool
flagCreateAdmin bool
flagResetPassword bool
2018-10-08 21:00:00 -07:00
flagResetFeedErrors bool
2018-11-11 15:32:48 -08:00
flagDebugMode bool
2019-06-02 18:20:59 -07:00
flagConfigFile string
flagConfigDump bool
2021-02-20 12:42:15 -08:00
flagHealthCheck string
2023-06-25 11:23:23 -07:00
flagRefreshFeeds bool
flagRunCleanupTasks bool
2023-09-27 21:15:32 -07:00
flagExportUserFeeds string
2018-10-08 21:00:00 -07:00
)
flag . BoolVar ( & flagInfo , "info" , false , flagInfoHelp )
flag . BoolVar ( & flagInfo , "i" , false , flagInfoHelp )
flag . BoolVar ( & flagVersion , "version" , false , flagVersionHelp )
flag . BoolVar ( & flagVersion , "v" , false , flagVersionHelp )
flag . BoolVar ( & flagMigrate , "migrate" , false , flagMigrateHelp )
2019-09-25 18:55:16 -07:00
flag . BoolVar ( & flagFlushSessions , "flush-sessions" , false , flagFlushSessionsHelp )
2018-10-08 21:00:00 -07:00
flag . BoolVar ( & flagCreateAdmin , "create-admin" , false , flagCreateAdminHelp )
flag . BoolVar ( & flagResetPassword , "reset-password" , false , flagResetPasswordHelp )
flag . BoolVar ( & flagResetFeedErrors , "reset-feed-errors" , false , flagResetFeedErrorsHelp )
2018-11-11 15:32:48 -08:00
flag . BoolVar ( & flagDebugMode , "debug" , false , flagDebugModeHelp )
2019-06-02 18:20:59 -07:00
flag . StringVar ( & flagConfigFile , "config-file" , "" , flagConfigFileHelp )
flag . StringVar ( & flagConfigFile , "c" , "" , flagConfigFileHelp )
flag . BoolVar ( & flagConfigDump , "config-dump" , false , flagConfigDumpHelp )
2021-02-20 12:42:15 -08:00
flag . StringVar ( & flagHealthCheck , "healthcheck" , "" , flagHealthCheckHelp )
2023-06-25 11:23:23 -07:00
flag . BoolVar ( & flagRefreshFeeds , "refresh-feeds" , false , flagRefreshFeedsHelp )
flag . BoolVar ( & flagRunCleanupTasks , "run-cleanup-tasks" , false , flagRunCleanupTasksHelp )
2023-09-27 21:15:32 -07:00
flag . StringVar ( & flagExportUserFeeds , "export-user-feeds" , "" , flagExportUserFeedsHelp )
2018-01-02 22:04:48 -08:00
flag . Parse ( )
2019-06-02 18:20:59 -07:00
cfg := config . NewParser ( )
if flagConfigFile != "" {
config . Opts , err = cfg . ParseFile ( flagConfigFile )
if err != nil {
2023-09-24 16:32:09 -07:00
printErrorAndExit ( err )
2019-06-02 18:20:59 -07:00
}
}
config . Opts , err = cfg . ParseEnvironmentVariables ( )
if err != nil {
2023-09-24 16:32:09 -07:00
printErrorAndExit ( err )
2019-06-01 18:18:09 -07:00
}
2018-02-23 18:26:34 -08:00
2019-06-02 18:20:59 -07:00
if flagConfigDump {
fmt . Print ( config . Opts )
return
}
2023-09-24 16:32:09 -07:00
if flagDebugMode {
config . Opts . SetLogLevel ( "debug" )
2019-06-08 17:16:12 -07:00
}
2023-09-24 16:32:09 -07:00
logFile := config . Opts . LogFile ( )
var logFileHandler io . Writer
switch logFile {
case "stdout" :
logFileHandler = os . Stdout
case "stderr" :
logFileHandler = os . Stderr
default :
logFileHandler , err = os . OpenFile ( logFile , os . O_CREATE | os . O_WRONLY | os . O_APPEND , 0600 )
if err != nil {
printErrorAndExit ( fmt . Errorf ( "unable to open log file: %v" , err ) )
}
defer logFileHandler . ( * os . File ) . Close ( )
}
if err := InitializeDefaultLogger ( config . Opts . LogLevel ( ) , logFileHandler , config . Opts . LogFormat ( ) , config . Opts . LogDateTime ( ) ) ; err != nil {
printErrorAndExit ( err )
2018-02-23 18:26:34 -08:00
}
2021-02-20 12:42:15 -08:00
if flagHealthCheck != "" {
doHealthCheck ( flagHealthCheck )
return
}
2018-10-08 21:00:00 -07:00
if flagInfo {
2018-01-02 22:04:48 -08:00
info ( )
return
}
2018-10-08 21:00:00 -07:00
if flagVersion {
2018-01-02 22:04:48 -08:00
fmt . Println ( version . Version )
return
}
2019-06-01 18:18:09 -07:00
if config . Opts . IsDefaultDatabaseURL ( ) {
2023-09-24 16:32:09 -07:00
slog . Info ( "The default value for DATABASE_URL is used" )
2019-06-01 18:18:09 -07:00
}
2021-02-16 22:58:44 -08:00
if err := locale . LoadCatalogMessages ( ) ; err != nil {
2023-09-24 16:32:09 -07:00
printErrorAndExit ( fmt . Errorf ( "unable to load translations: %v" , err ) )
2021-02-16 22:58:44 -08:00
}
2021-02-17 21:58:04 -08:00
if err := static . CalculateBinaryFileChecksums ( ) ; err != nil {
2023-09-24 16:32:09 -07:00
printErrorAndExit ( fmt . Errorf ( "unable to calculate binary file checksums: %v" , err ) )
2021-02-17 21:58:04 -08:00
}
if err := static . GenerateStylesheetsBundles ( ) ; err != nil {
2023-09-24 16:32:09 -07:00
printErrorAndExit ( fmt . Errorf ( "unable to generate stylesheets bundles: %v" , err ) )
2021-02-18 20:34:58 -08:00
}
if err := static . GenerateJavascriptBundles ( ) ; err != nil {
2023-09-24 16:32:09 -07:00
printErrorAndExit ( fmt . Errorf ( "unable to generate javascript bundles: %v" , err ) )
2021-02-17 21:58:04 -08:00
}
2019-06-01 18:18:09 -07:00
db , err := database . NewConnectionPool (
config . Opts . DatabaseURL ( ) ,
config . Opts . DatabaseMinConns ( ) ,
config . Opts . DatabaseMaxConns ( ) ,
2021-05-23 19:32:34 -07:00
config . Opts . DatabaseConnectionLifetime ( ) ,
2019-06-01 18:18:09 -07:00
)
2018-12-02 21:19:09 -08:00
if err != nil {
2023-09-24 16:32:09 -07:00
printErrorAndExit ( fmt . Errorf ( "unable to connect to database: %v" , err ) )
2018-12-02 21:19:09 -08:00
}
defer db . Close ( )
2021-02-19 18:47:50 -08:00
store := storage . NewStorage ( db )
if err := store . Ping ( ) ; err != nil {
2023-09-24 16:32:09 -07:00
printErrorAndExit ( err )
2021-02-19 18:47:50 -08:00
}
2018-10-08 21:00:00 -07:00
if flagMigrate {
2021-02-21 13:42:49 -08:00
if err := database . Migrate ( db ) ; err != nil {
2023-09-24 16:32:09 -07:00
printErrorAndExit ( err )
2021-02-21 13:42:49 -08:00
}
2018-01-02 22:04:48 -08:00
return
}
2018-10-08 21:00:00 -07:00
if flagResetFeedErrors {
2018-06-30 14:22:45 -07:00
store . ResetFeedErrors ( )
return
}
2023-09-27 21:15:32 -07:00
if flagExportUserFeeds != "" {
exportUserFeeds ( store , flagExportUserFeeds )
return
}
2018-10-08 21:00:00 -07:00
if flagFlushSessions {
2018-01-02 22:04:48 -08:00
flushSessions ( store )
return
}
2018-10-08 21:00:00 -07:00
if flagCreateAdmin {
2024-03-23 14:05:05 -07:00
createAdminUserFromInteractiveTerminal ( store )
2018-01-02 22:04:48 -08:00
return
}
2018-10-08 21:00:00 -07:00
if flagResetPassword {
2018-01-02 22:18:24 -08:00
resetPassword ( store )
return
}
2021-05-13 14:38:32 +01:00
// Run migrations and start the daemon.
2019-06-01 18:18:09 -07:00
if config . Opts . RunMigrations ( ) {
2021-01-02 16:33:41 -08:00
if err := database . Migrate ( db ) ; err != nil {
2023-09-24 16:32:09 -07:00
printErrorAndExit ( err )
2021-01-02 16:33:41 -08:00
}
2018-04-15 20:27:10 -07:00
}
2020-03-21 15:01:16 -07:00
if err := database . IsSchemaUpToDate ( db ) ; err != nil {
2023-09-24 16:32:09 -07:00
printErrorAndExit ( err )
2020-03-21 15:01:16 -07:00
}
2019-06-01 18:18:09 -07:00
if config . Opts . CreateAdmin ( ) {
2024-03-23 14:05:05 -07:00
createAdminUserFromEnvironmentVariables ( store )
2018-04-15 20:27:10 -07:00
}
2023-06-25 11:23:23 -07:00
if flagRefreshFeeds {
refreshFeeds ( store )
return
}
if flagRunCleanupTasks {
runCleanupTasks ( store )
2023-06-24 22:06:48 -07:00
return
}
2024-08-12 19:27:08 -07:00
if config . Opts . DisableLocalAuth ( ) {
switch {
case config . Opts . OAuth2Provider ( ) == "" && config . Opts . AuthProxyHeader ( ) == "" :
printErrorAndExit ( errors . New ( "DISABLE_LOCAL_AUTH is enabled but neither OAUTH2_PROVIDER nor AUTH_PROXY_HEADER is not set. Please enable at least one authentication source" ) )
case config . Opts . OAuth2Provider ( ) != "" && ! config . Opts . IsOAuth2UserCreationAllowed ( ) :
printErrorAndExit ( errors . New ( "DISABLE_LOCAL_AUTH is enabled and an OAUTH2_PROVIDER is configured, but OAUTH2_USER_CREATION is not enabled" ) )
case config . Opts . AuthProxyHeader ( ) != "" && ! config . Opts . IsAuthProxyUserCreationAllowed ( ) :
printErrorAndExit ( errors . New ( "DISABLE_LOCAL_AUTH is enabled and an AUTH_PROXY_HEADER is configured, but AUTH_PROXY_USER_CREATION is not enabled" ) )
}
}
2019-06-01 18:18:09 -07:00
startDaemon ( store )
2018-01-02 22:04:48 -08:00
}
2023-09-24 16:32:09 -07:00
func printErrorAndExit ( err error ) {
fmt . Fprintf ( os . Stderr , "%v\n" , err )
os . Exit ( 1 )
}