quintodrome/cmd/svc.go

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

269 lines
6.7 KiB
Go
Raw Permalink Normal View History

feat: Windows MSI installer and service support (#3125) * First version/rough layout of the required wix to build an MSI that embeds everything * Don't need revision number * produced exe from existing build process is navidrome not Navidrome * Adding Kardianos wrapper around Cobra so the callbacks are handled automatically (this is basically only for windows) * Adding pointless check to shut up lint for now * make format * Revert disabling npm tidy * Using Kardianos always will result in the application hanging so it needs only be wrapped to handle the callbacks if it's being used in the service context, otherwise use cobra directly * Copying in service installation etc from https://github.com/navidrome/navidrome/pull/2295 * Under Linux this installs a user service (I don't think this is correct, but lets get this working first). User units/services cannot depends on system units, so previously this bombed out with Exit Code 5. * Under Windows we can install both the x86 and x64 builds, they will install to different folders, but previously they would overwrite the service as they were both called Navidrome. Now, it will install 2 services. This will still be weird/broken as they will attempt to listen on the same port, however uninstalling the "wrong" arch will not cause the "right" one to be partially uninstalled anymore * Reverting changes to the context as they don't really seem necessary anyway * Need to consistently name the service * Fixing broken context * The included files should be removed when the app is uninstalled * Reverting back to the original context here, I don't think it makes any difference to running under kardianos * Let's see what we have immediately available * OK, the build takes ages so let's just try and do the whole thing in one go, maybe we'll get lucky * Need -r on directory copy, plus we'll probably need to install wixl * No sudo cmd, so I assume this runs as root * WORKSPACE! * Moving the version to be a single variable, we'll probably be able to pull it from the github tag or whatever * Might as well put the msi in the right folder, it's tidier * Writing the version number into the msi, from the output of goreleaser * Using jq to parse the goreleaser metadata, so need to install it * MSI only supports numerical version numbers, so I'll make the "snapshot" version .1 minor patch greater * -r or --raw (on newer versions) means we don't get the "" around the value * Running as a user service I think makes limited sense for this * Will now ask for configuration settings during install. MSI/WiX only supports writing out INI files, Toml is almost INI compatable, except that the INI needs to write out a section first, so we need to have a script to strip that off. We are forced to display a License.rtf file by the UI so I think the build process should probably rename the default licence file and that will suffice. Uninstalling works cleanly, howvever upgrades seem to leave the old version installed in "programs and features" currently. Adding the UI has introduced a requirement for WiX 0.103 * Updating the build to include --ext ui for the new config ui * Configuration dialog should not display for upgrades as the config file is already written * Making description consistent with the systemd service and making the build process produce the required License.rtf * Fixing " non-constant format string in call to fmt.Errorf (govet)" * Its a string, not an int; read better. * Wixl 103 is required for --ext ui, so we need 24.04 * OK this is still installing Wix 0.101, maybe it all needs to be 24.04? * Switching the builds back to ubuntu-latest (22.04 at current) as it runs on a custom container, it's actually debian anyway Moving msi build into its own job so it can run on 24.04 so we have access to wixl 0.103 for --ext ui support * Forcing build * Whitespace fix * Adding sudo I guess * Gotta checkout as well * Adding debugging for when there's soemthing wrong with the paths * Adding more ls to see if the output has worked * The msi's are in subdirs * Actually they're in the ./wix directory * Still can't find these msi's? * I think that was being treated literally previously * No idea why this isn't working, give it a relative path instead? * Making explicit on the dialogue that the configuration file will be where the installation dir is * The lint keeps failing and it's just getting in the way so I'll turn this off for now and we'll edit out this commit from the merge * Cutting more out of the build to get more stuff out of the way * Need to increase the width to fit the text in * Calling everything License.rtf, presumably one of them is correct * I am pretty sure the License.rtf loading is broken under Wixl; so let's just bypass the EULA from the UI which is a nicer experience for the users anyway * This needs to be after WelcomeDlg now the Eula isn't displayed * You're supposed to be able to use <WixVariable> to override the location that the bmp's are loaded from, I can't get this to work under wixl so I'm guessing given that the ui extension is new, it hasn't been implemented with that in mind. So we'll hack it by overwriting the files installed with the package. * We should make this less brittle so when wixl is updated it still works * Re-enabling the lint and tests etc * Improving the scaling quality and removing borders from images to tidy them up a tad * Pretty sure this isn't necessary as MY_PROPERTY will always be false * Without publishing this event, we can't continue to the next dialogue however I think we should be able to get away without the property * Refactoring out the duplication so we only have one service defined and we can run that either way * Pushing the Interactive check into the root commmand? Feels like it is probably getting closer to the right place at least * go tidy * OK this didn't work under windows, I'm guessing it's because it's lacking all the metadata about the service it needs to report back to Windows on. * We need to run service execute now so that the windows service will behave (hopefully)! * Lint * go tidy * Renaming service to "navidrome" rather than "Navidrome" as this is the filename that systemd writes and it's unusual to have capital letters in service names under Linux. Switching to use service execute for Linux to mirror Windows * Need to provide the arguments to append * Without passing the context around, the DB isn't closed gracefully so we end up with with .db-shm and .db-wal files for recovery * We should log fatal rather than outputting directly to stdout * go tidy * refactor: small nitpicks * fix: terminate service gracefully --------- Co-authored-by: Deluan Quintão <deluan@navidrome.org>
2024-10-01 15:40:53 -08:00
package cmd
import (
"context"
"fmt"
"os"
"path/filepath"
"sync"
"time"
"github.com/kardianos/service"
"github.com/navidrome/navidrome/conf"
"github.com/navidrome/navidrome/log"
"github.com/spf13/cobra"
)
var (
svcStatusLabels = map[service.Status]string{
service.StatusUnknown: "Unknown",
service.StatusStopped: "Stopped",
service.StatusRunning: "Running",
}
installUser string
workingDirectory string
feat: Windows MSI installer and service support (#3125) * First version/rough layout of the required wix to build an MSI that embeds everything * Don't need revision number * produced exe from existing build process is navidrome not Navidrome * Adding Kardianos wrapper around Cobra so the callbacks are handled automatically (this is basically only for windows) * Adding pointless check to shut up lint for now * make format * Revert disabling npm tidy * Using Kardianos always will result in the application hanging so it needs only be wrapped to handle the callbacks if it's being used in the service context, otherwise use cobra directly * Copying in service installation etc from https://github.com/navidrome/navidrome/pull/2295 * Under Linux this installs a user service (I don't think this is correct, but lets get this working first). User units/services cannot depends on system units, so previously this bombed out with Exit Code 5. * Under Windows we can install both the x86 and x64 builds, they will install to different folders, but previously they would overwrite the service as they were both called Navidrome. Now, it will install 2 services. This will still be weird/broken as they will attempt to listen on the same port, however uninstalling the "wrong" arch will not cause the "right" one to be partially uninstalled anymore * Reverting changes to the context as they don't really seem necessary anyway * Need to consistently name the service * Fixing broken context * The included files should be removed when the app is uninstalled * Reverting back to the original context here, I don't think it makes any difference to running under kardianos * Let's see what we have immediately available * OK, the build takes ages so let's just try and do the whole thing in one go, maybe we'll get lucky * Need -r on directory copy, plus we'll probably need to install wixl * No sudo cmd, so I assume this runs as root * WORKSPACE! * Moving the version to be a single variable, we'll probably be able to pull it from the github tag or whatever * Might as well put the msi in the right folder, it's tidier * Writing the version number into the msi, from the output of goreleaser * Using jq to parse the goreleaser metadata, so need to install it * MSI only supports numerical version numbers, so I'll make the "snapshot" version .1 minor patch greater * -r or --raw (on newer versions) means we don't get the "" around the value * Running as a user service I think makes limited sense for this * Will now ask for configuration settings during install. MSI/WiX only supports writing out INI files, Toml is almost INI compatable, except that the INI needs to write out a section first, so we need to have a script to strip that off. We are forced to display a License.rtf file by the UI so I think the build process should probably rename the default licence file and that will suffice. Uninstalling works cleanly, howvever upgrades seem to leave the old version installed in "programs and features" currently. Adding the UI has introduced a requirement for WiX 0.103 * Updating the build to include --ext ui for the new config ui * Configuration dialog should not display for upgrades as the config file is already written * Making description consistent with the systemd service and making the build process produce the required License.rtf * Fixing " non-constant format string in call to fmt.Errorf (govet)" * Its a string, not an int; read better. * Wixl 103 is required for --ext ui, so we need 24.04 * OK this is still installing Wix 0.101, maybe it all needs to be 24.04? * Switching the builds back to ubuntu-latest (22.04 at current) as it runs on a custom container, it's actually debian anyway Moving msi build into its own job so it can run on 24.04 so we have access to wixl 0.103 for --ext ui support * Forcing build * Whitespace fix * Adding sudo I guess * Gotta checkout as well * Adding debugging for when there's soemthing wrong with the paths * Adding more ls to see if the output has worked * The msi's are in subdirs * Actually they're in the ./wix directory * Still can't find these msi's? * I think that was being treated literally previously * No idea why this isn't working, give it a relative path instead? * Making explicit on the dialogue that the configuration file will be where the installation dir is * The lint keeps failing and it's just getting in the way so I'll turn this off for now and we'll edit out this commit from the merge * Cutting more out of the build to get more stuff out of the way * Need to increase the width to fit the text in * Calling everything License.rtf, presumably one of them is correct * I am pretty sure the License.rtf loading is broken under Wixl; so let's just bypass the EULA from the UI which is a nicer experience for the users anyway * This needs to be after WelcomeDlg now the Eula isn't displayed * You're supposed to be able to use <WixVariable> to override the location that the bmp's are loaded from, I can't get this to work under wixl so I'm guessing given that the ui extension is new, it hasn't been implemented with that in mind. So we'll hack it by overwriting the files installed with the package. * We should make this less brittle so when wixl is updated it still works * Re-enabling the lint and tests etc * Improving the scaling quality and removing borders from images to tidy them up a tad * Pretty sure this isn't necessary as MY_PROPERTY will always be false * Without publishing this event, we can't continue to the next dialogue however I think we should be able to get away without the property * Refactoring out the duplication so we only have one service defined and we can run that either way * Pushing the Interactive check into the root commmand? Feels like it is probably getting closer to the right place at least * go tidy * OK this didn't work under windows, I'm guessing it's because it's lacking all the metadata about the service it needs to report back to Windows on. * We need to run service execute now so that the windows service will behave (hopefully)! * Lint * go tidy * Renaming service to "navidrome" rather than "Navidrome" as this is the filename that systemd writes and it's unusual to have capital letters in service names under Linux. Switching to use service execute for Linux to mirror Windows * Need to provide the arguments to append * Without passing the context around, the DB isn't closed gracefully so we end up with with .db-shm and .db-wal files for recovery * We should log fatal rather than outputting directly to stdout * go tidy * refactor: small nitpicks * fix: terminate service gracefully --------- Co-authored-by: Deluan Quintão <deluan@navidrome.org>
2024-10-01 15:40:53 -08:00
)
func init() {
svcCmd.AddCommand(buildInstallCmd())
svcCmd.AddCommand(buildUninstallCmd())
svcCmd.AddCommand(buildStartCmd())
svcCmd.AddCommand(buildStopCmd())
svcCmd.AddCommand(buildStatusCmd())
svcCmd.AddCommand(buildExecuteCmd())
rootCmd.AddCommand(svcCmd)
}
var svcCmd = &cobra.Command{
Use: "service",
Aliases: []string{"svc"},
Short: "Manage Navidrome as a service",
Long: fmt.Sprintf("Manage Navidrome as a service, using the OS service manager (%s)", service.Platform()),
Run: runServiceCmd,
}
type svcControl struct {
ctx context.Context
cancel context.CancelFunc
done chan struct{}
}
func (p *svcControl) Start(service.Service) error {
p.done = make(chan struct{})
p.ctx, p.cancel = context.WithCancel(context.Background())
go func() {
runNavidrome(p.ctx)
close(p.done)
}()
return nil
}
func (p *svcControl) Stop(service.Service) error {
log.Info("Stopping service")
p.cancel()
select {
case <-p.done:
log.Info("Service stopped gracefully")
case <-time.After(10 * time.Second):
log.Error("Service did not stop in time. Killing it.")
}
return nil
}
var svcInstance = sync.OnceValue(func() service.Service {
options := make(service.KeyValue)
options["Restart"] = "on-failure"
feat: Windows MSI installer and service support (#3125) * First version/rough layout of the required wix to build an MSI that embeds everything * Don't need revision number * produced exe from existing build process is navidrome not Navidrome * Adding Kardianos wrapper around Cobra so the callbacks are handled automatically (this is basically only for windows) * Adding pointless check to shut up lint for now * make format * Revert disabling npm tidy * Using Kardianos always will result in the application hanging so it needs only be wrapped to handle the callbacks if it's being used in the service context, otherwise use cobra directly * Copying in service installation etc from https://github.com/navidrome/navidrome/pull/2295 * Under Linux this installs a user service (I don't think this is correct, but lets get this working first). User units/services cannot depends on system units, so previously this bombed out with Exit Code 5. * Under Windows we can install both the x86 and x64 builds, they will install to different folders, but previously they would overwrite the service as they were both called Navidrome. Now, it will install 2 services. This will still be weird/broken as they will attempt to listen on the same port, however uninstalling the "wrong" arch will not cause the "right" one to be partially uninstalled anymore * Reverting changes to the context as they don't really seem necessary anyway * Need to consistently name the service * Fixing broken context * The included files should be removed when the app is uninstalled * Reverting back to the original context here, I don't think it makes any difference to running under kardianos * Let's see what we have immediately available * OK, the build takes ages so let's just try and do the whole thing in one go, maybe we'll get lucky * Need -r on directory copy, plus we'll probably need to install wixl * No sudo cmd, so I assume this runs as root * WORKSPACE! * Moving the version to be a single variable, we'll probably be able to pull it from the github tag or whatever * Might as well put the msi in the right folder, it's tidier * Writing the version number into the msi, from the output of goreleaser * Using jq to parse the goreleaser metadata, so need to install it * MSI only supports numerical version numbers, so I'll make the "snapshot" version .1 minor patch greater * -r or --raw (on newer versions) means we don't get the "" around the value * Running as a user service I think makes limited sense for this * Will now ask for configuration settings during install. MSI/WiX only supports writing out INI files, Toml is almost INI compatable, except that the INI needs to write out a section first, so we need to have a script to strip that off. We are forced to display a License.rtf file by the UI so I think the build process should probably rename the default licence file and that will suffice. Uninstalling works cleanly, howvever upgrades seem to leave the old version installed in "programs and features" currently. Adding the UI has introduced a requirement for WiX 0.103 * Updating the build to include --ext ui for the new config ui * Configuration dialog should not display for upgrades as the config file is already written * Making description consistent with the systemd service and making the build process produce the required License.rtf * Fixing " non-constant format string in call to fmt.Errorf (govet)" * Its a string, not an int; read better. * Wixl 103 is required for --ext ui, so we need 24.04 * OK this is still installing Wix 0.101, maybe it all needs to be 24.04? * Switching the builds back to ubuntu-latest (22.04 at current) as it runs on a custom container, it's actually debian anyway Moving msi build into its own job so it can run on 24.04 so we have access to wixl 0.103 for --ext ui support * Forcing build * Whitespace fix * Adding sudo I guess * Gotta checkout as well * Adding debugging for when there's soemthing wrong with the paths * Adding more ls to see if the output has worked * The msi's are in subdirs * Actually they're in the ./wix directory * Still can't find these msi's? * I think that was being treated literally previously * No idea why this isn't working, give it a relative path instead? * Making explicit on the dialogue that the configuration file will be where the installation dir is * The lint keeps failing and it's just getting in the way so I'll turn this off for now and we'll edit out this commit from the merge * Cutting more out of the build to get more stuff out of the way * Need to increase the width to fit the text in * Calling everything License.rtf, presumably one of them is correct * I am pretty sure the License.rtf loading is broken under Wixl; so let's just bypass the EULA from the UI which is a nicer experience for the users anyway * This needs to be after WelcomeDlg now the Eula isn't displayed * You're supposed to be able to use <WixVariable> to override the location that the bmp's are loaded from, I can't get this to work under wixl so I'm guessing given that the ui extension is new, it hasn't been implemented with that in mind. So we'll hack it by overwriting the files installed with the package. * We should make this less brittle so when wixl is updated it still works * Re-enabling the lint and tests etc * Improving the scaling quality and removing borders from images to tidy them up a tad * Pretty sure this isn't necessary as MY_PROPERTY will always be false * Without publishing this event, we can't continue to the next dialogue however I think we should be able to get away without the property * Refactoring out the duplication so we only have one service defined and we can run that either way * Pushing the Interactive check into the root commmand? Feels like it is probably getting closer to the right place at least * go tidy * OK this didn't work under windows, I'm guessing it's because it's lacking all the metadata about the service it needs to report back to Windows on. * We need to run service execute now so that the windows service will behave (hopefully)! * Lint * go tidy * Renaming service to "navidrome" rather than "Navidrome" as this is the filename that systemd writes and it's unusual to have capital letters in service names under Linux. Switching to use service execute for Linux to mirror Windows * Need to provide the arguments to append * Without passing the context around, the DB isn't closed gracefully so we end up with with .db-shm and .db-wal files for recovery * We should log fatal rather than outputting directly to stdout * go tidy * refactor: small nitpicks * fix: terminate service gracefully --------- Co-authored-by: Deluan Quintão <deluan@navidrome.org>
2024-10-01 15:40:53 -08:00
options["SuccessExitStatus"] = "1 2 8 SIGKILL"
options["UserService"] = false
refactor(conf): replace eager dir creation with lazy Dir type (#5495) * feat(conf): add Dir type with lazy directory creation Introduces the Dir type that wraps a directory path string and defers os.MkdirAll until the first call to Path() or MustPath(), using sync.Once to ensure the creation happens exactly once. Implements fmt.Stringer, encoding.TextMarshaler, and encoding.TextUnmarshaler for config integration. Includes Ginkgo/Gomega tests covering all methods and error paths. * refactor(conf): replace eager dir creation with lazy Dir type Change DataFolder, CacheFolder, Plugins.Folder, and Backup.Path from string to Dir. Remove all os.MkdirAll calls from Load() so directories are created lazily on first Path()/MustPath() call. Artwork folder creation was already handled at point-of-use in image_upload.go. Add SnapshotConfig() to conf package for safe test config save/restore that avoids copying sync.Once inside Dir fields. Fix copy-lock vet warning in nativeapi/config.go by marshalling pointer instead of value. * refactor(conf): migrate tests and db init to lazy Dir type Update all test files to use conf.NewDir() for Dir field assignments. Ensure DataFolder is created lazily when the database is first opened in db.Db(). Remove eager directory creation from conf.Load() tests. * fix(conf): address review findings for Dir type - Use os.ModePerm for DataFolder/CacheFolder (was 0700, should match original behavior). Add NewDirWithPerm for PluginsFolder (0700). - Use Path() instead of MustPath() in db.Prune() to avoid logFatal from background cron job. - Panic on marshal/unmarshal errors in SnapshotConfig (test helper). - Clean up redundant String()/MustPath() calls in plugin manager. - Remove dead code in dir_test.go. Signed-off-by: Deluan <deluan@navidrome.org> * fix(conf): add GoString to Dir for clean config dump output Implement fmt.GoStringer on Dir so pretty.Sprintf shows the path string instead of internal struct fields (sync.Once, perm, err). Also add TODO comment to configtest about removing the indirection. * fix(dir): improve error logging in MustPath method Signed-off-by: Deluan <deluan@navidrome.org> * refactor(tests): remove redundant tests for unwritable DataFolder and CacheFolder Signed-off-by: Deluan <deluan@navidrome.org> * fix(conf): address PR review feedback - Ensure Plugins.Folder always uses 0700, even when user-configured (previously only the derived default got restrictive permissions). - Create LogFile parent directory before opening, so LogFile paths inside a not-yet-created DataFolder work correctly. --------- Signed-off-by: Deluan <deluan@navidrome.org>
2026-05-13 12:44:22 -08:00
options["LogDirectory"] = conf.Server.DataFolder.String()
options["SystemdScript"] = systemdScript
feat(build): MSI installer improvements (#3376) * feat(build): add a make target to build a msi installer locally * Testing wrapping the executable in cmd * build(ci): build msis in parallel * feat(server): add LogFile config option * Revert "Testing wrapping the executable in cmd" This reverts commit be29592254cb903fd4904f2f50d4d1a860795d33. * Adding --log-file for service executable * feat(ini): wip * feat(ini): parse nested ini section * fix(conf): fix fatal error messages * Now navidrome supports INI, we can use the built-in msi ini system and not require the VBScript to convert it into toml * File needs to be called .ini to be parsed as an INI and correct filename needs to be passed to the service * fix(msi): build msi locally * fix(msi): pipeline * fix(msi): pipeline * fix(msi): pipeline * fix(msi): pipeline * fix(msi): pipeline * fix(msi): Makefile * fix(msi): more clean up * fix(log): convert LF to CRLF on Windows * fix(msi): config filename should be case-insensitive * fix(msi): make it a little more idiomatic * Including the latest windows release of ffmpeg into the msi as built by https://www.gyan.dev/ffmpeg/builds/ (linked to on the official ffmpeg source) * This should version independent * Need bash expansion for the * to work * This will run twice, once for x86 and once for x64, I'll make it cache the executable for now as it'll be quicker * Silencing wget * Add ffmpeg path to the config so Navidrome knows where to find it * refactor: download ffmpeg from our repository * When going back from the "Are you ready to install?" it should go back to the Settings dialogue that you just came from * fix: comments --------- Co-authored-by: Deluan <deluan@navidrome.org>
2024-10-22 15:32:56 -08:00
if conf.Server.LogFile != "" {
options["LogOutput"] = false
} else {
options["LogOutput"] = true
refactor(conf): replace eager dir creation with lazy Dir type (#5495) * feat(conf): add Dir type with lazy directory creation Introduces the Dir type that wraps a directory path string and defers os.MkdirAll until the first call to Path() or MustPath(), using sync.Once to ensure the creation happens exactly once. Implements fmt.Stringer, encoding.TextMarshaler, and encoding.TextUnmarshaler for config integration. Includes Ginkgo/Gomega tests covering all methods and error paths. * refactor(conf): replace eager dir creation with lazy Dir type Change DataFolder, CacheFolder, Plugins.Folder, and Backup.Path from string to Dir. Remove all os.MkdirAll calls from Load() so directories are created lazily on first Path()/MustPath() call. Artwork folder creation was already handled at point-of-use in image_upload.go. Add SnapshotConfig() to conf package for safe test config save/restore that avoids copying sync.Once inside Dir fields. Fix copy-lock vet warning in nativeapi/config.go by marshalling pointer instead of value. * refactor(conf): migrate tests and db init to lazy Dir type Update all test files to use conf.NewDir() for Dir field assignments. Ensure DataFolder is created lazily when the database is first opened in db.Db(). Remove eager directory creation from conf.Load() tests. * fix(conf): address review findings for Dir type - Use os.ModePerm for DataFolder/CacheFolder (was 0700, should match original behavior). Add NewDirWithPerm for PluginsFolder (0700). - Use Path() instead of MustPath() in db.Prune() to avoid logFatal from background cron job. - Panic on marshal/unmarshal errors in SnapshotConfig (test helper). - Clean up redundant String()/MustPath() calls in plugin manager. - Remove dead code in dir_test.go. Signed-off-by: Deluan <deluan@navidrome.org> * fix(conf): add GoString to Dir for clean config dump output Implement fmt.GoStringer on Dir so pretty.Sprintf shows the path string instead of internal struct fields (sync.Once, perm, err). Also add TODO comment to configtest about removing the indirection. * fix(dir): improve error logging in MustPath method Signed-off-by: Deluan <deluan@navidrome.org> * refactor(tests): remove redundant tests for unwritable DataFolder and CacheFolder Signed-off-by: Deluan <deluan@navidrome.org> * fix(conf): address PR review feedback - Ensure Plugins.Folder always uses 0700, even when user-configured (previously only the derived default got restrictive permissions). - Create LogFile parent directory before opening, so LogFile paths inside a not-yet-created DataFolder work correctly. --------- Signed-off-by: Deluan <deluan@navidrome.org>
2026-05-13 12:44:22 -08:00
options["LogDirectory"] = conf.Server.DataFolder.String()
feat(build): MSI installer improvements (#3376) * feat(build): add a make target to build a msi installer locally * Testing wrapping the executable in cmd * build(ci): build msis in parallel * feat(server): add LogFile config option * Revert "Testing wrapping the executable in cmd" This reverts commit be29592254cb903fd4904f2f50d4d1a860795d33. * Adding --log-file for service executable * feat(ini): wip * feat(ini): parse nested ini section * fix(conf): fix fatal error messages * Now navidrome supports INI, we can use the built-in msi ini system and not require the VBScript to convert it into toml * File needs to be called .ini to be parsed as an INI and correct filename needs to be passed to the service * fix(msi): build msi locally * fix(msi): pipeline * fix(msi): pipeline * fix(msi): pipeline * fix(msi): pipeline * fix(msi): pipeline * fix(msi): Makefile * fix(msi): more clean up * fix(log): convert LF to CRLF on Windows * fix(msi): config filename should be case-insensitive * fix(msi): make it a little more idiomatic * Including the latest windows release of ffmpeg into the msi as built by https://www.gyan.dev/ffmpeg/builds/ (linked to on the official ffmpeg source) * This should version independent * Need bash expansion for the * to work * This will run twice, once for x86 and once for x64, I'll make it cache the executable for now as it'll be quicker * Silencing wget * Add ffmpeg path to the config so Navidrome knows where to find it * refactor: download ffmpeg from our repository * When going back from the "Are you ready to install?" it should go back to the Settings dialogue that you just came from * fix: comments --------- Co-authored-by: Deluan <deluan@navidrome.org>
2024-10-22 15:32:56 -08:00
}
feat: Windows MSI installer and service support (#3125) * First version/rough layout of the required wix to build an MSI that embeds everything * Don't need revision number * produced exe from existing build process is navidrome not Navidrome * Adding Kardianos wrapper around Cobra so the callbacks are handled automatically (this is basically only for windows) * Adding pointless check to shut up lint for now * make format * Revert disabling npm tidy * Using Kardianos always will result in the application hanging so it needs only be wrapped to handle the callbacks if it's being used in the service context, otherwise use cobra directly * Copying in service installation etc from https://github.com/navidrome/navidrome/pull/2295 * Under Linux this installs a user service (I don't think this is correct, but lets get this working first). User units/services cannot depends on system units, so previously this bombed out with Exit Code 5. * Under Windows we can install both the x86 and x64 builds, they will install to different folders, but previously they would overwrite the service as they were both called Navidrome. Now, it will install 2 services. This will still be weird/broken as they will attempt to listen on the same port, however uninstalling the "wrong" arch will not cause the "right" one to be partially uninstalled anymore * Reverting changes to the context as they don't really seem necessary anyway * Need to consistently name the service * Fixing broken context * The included files should be removed when the app is uninstalled * Reverting back to the original context here, I don't think it makes any difference to running under kardianos * Let's see what we have immediately available * OK, the build takes ages so let's just try and do the whole thing in one go, maybe we'll get lucky * Need -r on directory copy, plus we'll probably need to install wixl * No sudo cmd, so I assume this runs as root * WORKSPACE! * Moving the version to be a single variable, we'll probably be able to pull it from the github tag or whatever * Might as well put the msi in the right folder, it's tidier * Writing the version number into the msi, from the output of goreleaser * Using jq to parse the goreleaser metadata, so need to install it * MSI only supports numerical version numbers, so I'll make the "snapshot" version .1 minor patch greater * -r or --raw (on newer versions) means we don't get the "" around the value * Running as a user service I think makes limited sense for this * Will now ask for configuration settings during install. MSI/WiX only supports writing out INI files, Toml is almost INI compatable, except that the INI needs to write out a section first, so we need to have a script to strip that off. We are forced to display a License.rtf file by the UI so I think the build process should probably rename the default licence file and that will suffice. Uninstalling works cleanly, howvever upgrades seem to leave the old version installed in "programs and features" currently. Adding the UI has introduced a requirement for WiX 0.103 * Updating the build to include --ext ui for the new config ui * Configuration dialog should not display for upgrades as the config file is already written * Making description consistent with the systemd service and making the build process produce the required License.rtf * Fixing " non-constant format string in call to fmt.Errorf (govet)" * Its a string, not an int; read better. * Wixl 103 is required for --ext ui, so we need 24.04 * OK this is still installing Wix 0.101, maybe it all needs to be 24.04? * Switching the builds back to ubuntu-latest (22.04 at current) as it runs on a custom container, it's actually debian anyway Moving msi build into its own job so it can run on 24.04 so we have access to wixl 0.103 for --ext ui support * Forcing build * Whitespace fix * Adding sudo I guess * Gotta checkout as well * Adding debugging for when there's soemthing wrong with the paths * Adding more ls to see if the output has worked * The msi's are in subdirs * Actually they're in the ./wix directory * Still can't find these msi's? * I think that was being treated literally previously * No idea why this isn't working, give it a relative path instead? * Making explicit on the dialogue that the configuration file will be where the installation dir is * The lint keeps failing and it's just getting in the way so I'll turn this off for now and we'll edit out this commit from the merge * Cutting more out of the build to get more stuff out of the way * Need to increase the width to fit the text in * Calling everything License.rtf, presumably one of them is correct * I am pretty sure the License.rtf loading is broken under Wixl; so let's just bypass the EULA from the UI which is a nicer experience for the users anyway * This needs to be after WelcomeDlg now the Eula isn't displayed * You're supposed to be able to use <WixVariable> to override the location that the bmp's are loaded from, I can't get this to work under wixl so I'm guessing given that the ui extension is new, it hasn't been implemented with that in mind. So we'll hack it by overwriting the files installed with the package. * We should make this less brittle so when wixl is updated it still works * Re-enabling the lint and tests etc * Improving the scaling quality and removing borders from images to tidy them up a tad * Pretty sure this isn't necessary as MY_PROPERTY will always be false * Without publishing this event, we can't continue to the next dialogue however I think we should be able to get away without the property * Refactoring out the duplication so we only have one service defined and we can run that either way * Pushing the Interactive check into the root commmand? Feels like it is probably getting closer to the right place at least * go tidy * OK this didn't work under windows, I'm guessing it's because it's lacking all the metadata about the service it needs to report back to Windows on. * We need to run service execute now so that the windows service will behave (hopefully)! * Lint * go tidy * Renaming service to "navidrome" rather than "Navidrome" as this is the filename that systemd writes and it's unusual to have capital letters in service names under Linux. Switching to use service execute for Linux to mirror Windows * Need to provide the arguments to append * Without passing the context around, the DB isn't closed gracefully so we end up with with .db-shm and .db-wal files for recovery * We should log fatal rather than outputting directly to stdout * go tidy * refactor: small nitpicks * fix: terminate service gracefully --------- Co-authored-by: Deluan Quintão <deluan@navidrome.org>
2024-10-01 15:40:53 -08:00
svcConfig := &service.Config{
UserName: installUser,
feat: Windows MSI installer and service support (#3125) * First version/rough layout of the required wix to build an MSI that embeds everything * Don't need revision number * produced exe from existing build process is navidrome not Navidrome * Adding Kardianos wrapper around Cobra so the callbacks are handled automatically (this is basically only for windows) * Adding pointless check to shut up lint for now * make format * Revert disabling npm tidy * Using Kardianos always will result in the application hanging so it needs only be wrapped to handle the callbacks if it's being used in the service context, otherwise use cobra directly * Copying in service installation etc from https://github.com/navidrome/navidrome/pull/2295 * Under Linux this installs a user service (I don't think this is correct, but lets get this working first). User units/services cannot depends on system units, so previously this bombed out with Exit Code 5. * Under Windows we can install both the x86 and x64 builds, they will install to different folders, but previously they would overwrite the service as they were both called Navidrome. Now, it will install 2 services. This will still be weird/broken as they will attempt to listen on the same port, however uninstalling the "wrong" arch will not cause the "right" one to be partially uninstalled anymore * Reverting changes to the context as they don't really seem necessary anyway * Need to consistently name the service * Fixing broken context * The included files should be removed when the app is uninstalled * Reverting back to the original context here, I don't think it makes any difference to running under kardianos * Let's see what we have immediately available * OK, the build takes ages so let's just try and do the whole thing in one go, maybe we'll get lucky * Need -r on directory copy, plus we'll probably need to install wixl * No sudo cmd, so I assume this runs as root * WORKSPACE! * Moving the version to be a single variable, we'll probably be able to pull it from the github tag or whatever * Might as well put the msi in the right folder, it's tidier * Writing the version number into the msi, from the output of goreleaser * Using jq to parse the goreleaser metadata, so need to install it * MSI only supports numerical version numbers, so I'll make the "snapshot" version .1 minor patch greater * -r or --raw (on newer versions) means we don't get the "" around the value * Running as a user service I think makes limited sense for this * Will now ask for configuration settings during install. MSI/WiX only supports writing out INI files, Toml is almost INI compatable, except that the INI needs to write out a section first, so we need to have a script to strip that off. We are forced to display a License.rtf file by the UI so I think the build process should probably rename the default licence file and that will suffice. Uninstalling works cleanly, howvever upgrades seem to leave the old version installed in "programs and features" currently. Adding the UI has introduced a requirement for WiX 0.103 * Updating the build to include --ext ui for the new config ui * Configuration dialog should not display for upgrades as the config file is already written * Making description consistent with the systemd service and making the build process produce the required License.rtf * Fixing " non-constant format string in call to fmt.Errorf (govet)" * Its a string, not an int; read better. * Wixl 103 is required for --ext ui, so we need 24.04 * OK this is still installing Wix 0.101, maybe it all needs to be 24.04? * Switching the builds back to ubuntu-latest (22.04 at current) as it runs on a custom container, it's actually debian anyway Moving msi build into its own job so it can run on 24.04 so we have access to wixl 0.103 for --ext ui support * Forcing build * Whitespace fix * Adding sudo I guess * Gotta checkout as well * Adding debugging for when there's soemthing wrong with the paths * Adding more ls to see if the output has worked * The msi's are in subdirs * Actually they're in the ./wix directory * Still can't find these msi's? * I think that was being treated literally previously * No idea why this isn't working, give it a relative path instead? * Making explicit on the dialogue that the configuration file will be where the installation dir is * The lint keeps failing and it's just getting in the way so I'll turn this off for now and we'll edit out this commit from the merge * Cutting more out of the build to get more stuff out of the way * Need to increase the width to fit the text in * Calling everything License.rtf, presumably one of them is correct * I am pretty sure the License.rtf loading is broken under Wixl; so let's just bypass the EULA from the UI which is a nicer experience for the users anyway * This needs to be after WelcomeDlg now the Eula isn't displayed * You're supposed to be able to use <WixVariable> to override the location that the bmp's are loaded from, I can't get this to work under wixl so I'm guessing given that the ui extension is new, it hasn't been implemented with that in mind. So we'll hack it by overwriting the files installed with the package. * We should make this less brittle so when wixl is updated it still works * Re-enabling the lint and tests etc * Improving the scaling quality and removing borders from images to tidy them up a tad * Pretty sure this isn't necessary as MY_PROPERTY will always be false * Without publishing this event, we can't continue to the next dialogue however I think we should be able to get away without the property * Refactoring out the duplication so we only have one service defined and we can run that either way * Pushing the Interactive check into the root commmand? Feels like it is probably getting closer to the right place at least * go tidy * OK this didn't work under windows, I'm guessing it's because it's lacking all the metadata about the service it needs to report back to Windows on. * We need to run service execute now so that the windows service will behave (hopefully)! * Lint * go tidy * Renaming service to "navidrome" rather than "Navidrome" as this is the filename that systemd writes and it's unusual to have capital letters in service names under Linux. Switching to use service execute for Linux to mirror Windows * Need to provide the arguments to append * Without passing the context around, the DB isn't closed gracefully so we end up with with .db-shm and .db-wal files for recovery * We should log fatal rather than outputting directly to stdout * go tidy * refactor: small nitpicks * fix: terminate service gracefully --------- Co-authored-by: Deluan Quintão <deluan@navidrome.org>
2024-10-01 15:40:53 -08:00
Name: "navidrome",
DisplayName: "Navidrome",
Description: "Your Personal Streaming Service",
Dependencies: []string{
"After=remote-fs.target network.target",
},
feat: Windows MSI installer and service support (#3125) * First version/rough layout of the required wix to build an MSI that embeds everything * Don't need revision number * produced exe from existing build process is navidrome not Navidrome * Adding Kardianos wrapper around Cobra so the callbacks are handled automatically (this is basically only for windows) * Adding pointless check to shut up lint for now * make format * Revert disabling npm tidy * Using Kardianos always will result in the application hanging so it needs only be wrapped to handle the callbacks if it's being used in the service context, otherwise use cobra directly * Copying in service installation etc from https://github.com/navidrome/navidrome/pull/2295 * Under Linux this installs a user service (I don't think this is correct, but lets get this working first). User units/services cannot depends on system units, so previously this bombed out with Exit Code 5. * Under Windows we can install both the x86 and x64 builds, they will install to different folders, but previously they would overwrite the service as they were both called Navidrome. Now, it will install 2 services. This will still be weird/broken as they will attempt to listen on the same port, however uninstalling the "wrong" arch will not cause the "right" one to be partially uninstalled anymore * Reverting changes to the context as they don't really seem necessary anyway * Need to consistently name the service * Fixing broken context * The included files should be removed when the app is uninstalled * Reverting back to the original context here, I don't think it makes any difference to running under kardianos * Let's see what we have immediately available * OK, the build takes ages so let's just try and do the whole thing in one go, maybe we'll get lucky * Need -r on directory copy, plus we'll probably need to install wixl * No sudo cmd, so I assume this runs as root * WORKSPACE! * Moving the version to be a single variable, we'll probably be able to pull it from the github tag or whatever * Might as well put the msi in the right folder, it's tidier * Writing the version number into the msi, from the output of goreleaser * Using jq to parse the goreleaser metadata, so need to install it * MSI only supports numerical version numbers, so I'll make the "snapshot" version .1 minor patch greater * -r or --raw (on newer versions) means we don't get the "" around the value * Running as a user service I think makes limited sense for this * Will now ask for configuration settings during install. MSI/WiX only supports writing out INI files, Toml is almost INI compatable, except that the INI needs to write out a section first, so we need to have a script to strip that off. We are forced to display a License.rtf file by the UI so I think the build process should probably rename the default licence file and that will suffice. Uninstalling works cleanly, howvever upgrades seem to leave the old version installed in "programs and features" currently. Adding the UI has introduced a requirement for WiX 0.103 * Updating the build to include --ext ui for the new config ui * Configuration dialog should not display for upgrades as the config file is already written * Making description consistent with the systemd service and making the build process produce the required License.rtf * Fixing " non-constant format string in call to fmt.Errorf (govet)" * Its a string, not an int; read better. * Wixl 103 is required for --ext ui, so we need 24.04 * OK this is still installing Wix 0.101, maybe it all needs to be 24.04? * Switching the builds back to ubuntu-latest (22.04 at current) as it runs on a custom container, it's actually debian anyway Moving msi build into its own job so it can run on 24.04 so we have access to wixl 0.103 for --ext ui support * Forcing build * Whitespace fix * Adding sudo I guess * Gotta checkout as well * Adding debugging for when there's soemthing wrong with the paths * Adding more ls to see if the output has worked * The msi's are in subdirs * Actually they're in the ./wix directory * Still can't find these msi's? * I think that was being treated literally previously * No idea why this isn't working, give it a relative path instead? * Making explicit on the dialogue that the configuration file will be where the installation dir is * The lint keeps failing and it's just getting in the way so I'll turn this off for now and we'll edit out this commit from the merge * Cutting more out of the build to get more stuff out of the way * Need to increase the width to fit the text in * Calling everything License.rtf, presumably one of them is correct * I am pretty sure the License.rtf loading is broken under Wixl; so let's just bypass the EULA from the UI which is a nicer experience for the users anyway * This needs to be after WelcomeDlg now the Eula isn't displayed * You're supposed to be able to use <WixVariable> to override the location that the bmp's are loaded from, I can't get this to work under wixl so I'm guessing given that the ui extension is new, it hasn't been implemented with that in mind. So we'll hack it by overwriting the files installed with the package. * We should make this less brittle so when wixl is updated it still works * Re-enabling the lint and tests etc * Improving the scaling quality and removing borders from images to tidy them up a tad * Pretty sure this isn't necessary as MY_PROPERTY will always be false * Without publishing this event, we can't continue to the next dialogue however I think we should be able to get away without the property * Refactoring out the duplication so we only have one service defined and we can run that either way * Pushing the Interactive check into the root commmand? Feels like it is probably getting closer to the right place at least * go tidy * OK this didn't work under windows, I'm guessing it's because it's lacking all the metadata about the service it needs to report back to Windows on. * We need to run service execute now so that the windows service will behave (hopefully)! * Lint * go tidy * Renaming service to "navidrome" rather than "Navidrome" as this is the filename that systemd writes and it's unusual to have capital letters in service names under Linux. Switching to use service execute for Linux to mirror Windows * Need to provide the arguments to append * Without passing the context around, the DB isn't closed gracefully so we end up with with .db-shm and .db-wal files for recovery * We should log fatal rather than outputting directly to stdout * go tidy * refactor: small nitpicks * fix: terminate service gracefully --------- Co-authored-by: Deluan Quintão <deluan@navidrome.org>
2024-10-01 15:40:53 -08:00
WorkingDirectory: executablePath(),
Option: options,
}
arguments := []string{"service", "execute"}
if conf.Server.ConfigFile != "" {
arguments = append(arguments, "-c", conf.Server.ConfigFile)
}
svcConfig.Arguments = arguments
prg := &svcControl{}
svc, err := service.New(prg, svcConfig)
if err != nil {
log.Fatal(err)
}
return svc
})
func runServiceCmd(cmd *cobra.Command, _ []string) {
_ = cmd.Help()
}
func executablePath() string {
if workingDirectory != "" {
return workingDirectory
}
feat: Windows MSI installer and service support (#3125) * First version/rough layout of the required wix to build an MSI that embeds everything * Don't need revision number * produced exe from existing build process is navidrome not Navidrome * Adding Kardianos wrapper around Cobra so the callbacks are handled automatically (this is basically only for windows) * Adding pointless check to shut up lint for now * make format * Revert disabling npm tidy * Using Kardianos always will result in the application hanging so it needs only be wrapped to handle the callbacks if it's being used in the service context, otherwise use cobra directly * Copying in service installation etc from https://github.com/navidrome/navidrome/pull/2295 * Under Linux this installs a user service (I don't think this is correct, but lets get this working first). User units/services cannot depends on system units, so previously this bombed out with Exit Code 5. * Under Windows we can install both the x86 and x64 builds, they will install to different folders, but previously they would overwrite the service as they were both called Navidrome. Now, it will install 2 services. This will still be weird/broken as they will attempt to listen on the same port, however uninstalling the "wrong" arch will not cause the "right" one to be partially uninstalled anymore * Reverting changes to the context as they don't really seem necessary anyway * Need to consistently name the service * Fixing broken context * The included files should be removed when the app is uninstalled * Reverting back to the original context here, I don't think it makes any difference to running under kardianos * Let's see what we have immediately available * OK, the build takes ages so let's just try and do the whole thing in one go, maybe we'll get lucky * Need -r on directory copy, plus we'll probably need to install wixl * No sudo cmd, so I assume this runs as root * WORKSPACE! * Moving the version to be a single variable, we'll probably be able to pull it from the github tag or whatever * Might as well put the msi in the right folder, it's tidier * Writing the version number into the msi, from the output of goreleaser * Using jq to parse the goreleaser metadata, so need to install it * MSI only supports numerical version numbers, so I'll make the "snapshot" version .1 minor patch greater * -r or --raw (on newer versions) means we don't get the "" around the value * Running as a user service I think makes limited sense for this * Will now ask for configuration settings during install. MSI/WiX only supports writing out INI files, Toml is almost INI compatable, except that the INI needs to write out a section first, so we need to have a script to strip that off. We are forced to display a License.rtf file by the UI so I think the build process should probably rename the default licence file and that will suffice. Uninstalling works cleanly, howvever upgrades seem to leave the old version installed in "programs and features" currently. Adding the UI has introduced a requirement for WiX 0.103 * Updating the build to include --ext ui for the new config ui * Configuration dialog should not display for upgrades as the config file is already written * Making description consistent with the systemd service and making the build process produce the required License.rtf * Fixing " non-constant format string in call to fmt.Errorf (govet)" * Its a string, not an int; read better. * Wixl 103 is required for --ext ui, so we need 24.04 * OK this is still installing Wix 0.101, maybe it all needs to be 24.04? * Switching the builds back to ubuntu-latest (22.04 at current) as it runs on a custom container, it's actually debian anyway Moving msi build into its own job so it can run on 24.04 so we have access to wixl 0.103 for --ext ui support * Forcing build * Whitespace fix * Adding sudo I guess * Gotta checkout as well * Adding debugging for when there's soemthing wrong with the paths * Adding more ls to see if the output has worked * The msi's are in subdirs * Actually they're in the ./wix directory * Still can't find these msi's? * I think that was being treated literally previously * No idea why this isn't working, give it a relative path instead? * Making explicit on the dialogue that the configuration file will be where the installation dir is * The lint keeps failing and it's just getting in the way so I'll turn this off for now and we'll edit out this commit from the merge * Cutting more out of the build to get more stuff out of the way * Need to increase the width to fit the text in * Calling everything License.rtf, presumably one of them is correct * I am pretty sure the License.rtf loading is broken under Wixl; so let's just bypass the EULA from the UI which is a nicer experience for the users anyway * This needs to be after WelcomeDlg now the Eula isn't displayed * You're supposed to be able to use <WixVariable> to override the location that the bmp's are loaded from, I can't get this to work under wixl so I'm guessing given that the ui extension is new, it hasn't been implemented with that in mind. So we'll hack it by overwriting the files installed with the package. * We should make this less brittle so when wixl is updated it still works * Re-enabling the lint and tests etc * Improving the scaling quality and removing borders from images to tidy them up a tad * Pretty sure this isn't necessary as MY_PROPERTY will always be false * Without publishing this event, we can't continue to the next dialogue however I think we should be able to get away without the property * Refactoring out the duplication so we only have one service defined and we can run that either way * Pushing the Interactive check into the root commmand? Feels like it is probably getting closer to the right place at least * go tidy * OK this didn't work under windows, I'm guessing it's because it's lacking all the metadata about the service it needs to report back to Windows on. * We need to run service execute now so that the windows service will behave (hopefully)! * Lint * go tidy * Renaming service to "navidrome" rather than "Navidrome" as this is the filename that systemd writes and it's unusual to have capital letters in service names under Linux. Switching to use service execute for Linux to mirror Windows * Need to provide the arguments to append * Without passing the context around, the DB isn't closed gracefully so we end up with with .db-shm and .db-wal files for recovery * We should log fatal rather than outputting directly to stdout * go tidy * refactor: small nitpicks * fix: terminate service gracefully --------- Co-authored-by: Deluan Quintão <deluan@navidrome.org>
2024-10-01 15:40:53 -08:00
ex, err := os.Executable()
if err != nil {
log.Fatal(err)
}
return filepath.Dir(ex)
}
func buildInstallCmd() *cobra.Command {
runInstallCmd := func(_ *cobra.Command, _ []string) {
var err error
println("Installing service with:")
println(" working directory: " + executablePath())
println(" music folder: " + conf.Server.MusicFolder)
refactor(conf): replace eager dir creation with lazy Dir type (#5495) * feat(conf): add Dir type with lazy directory creation Introduces the Dir type that wraps a directory path string and defers os.MkdirAll until the first call to Path() or MustPath(), using sync.Once to ensure the creation happens exactly once. Implements fmt.Stringer, encoding.TextMarshaler, and encoding.TextUnmarshaler for config integration. Includes Ginkgo/Gomega tests covering all methods and error paths. * refactor(conf): replace eager dir creation with lazy Dir type Change DataFolder, CacheFolder, Plugins.Folder, and Backup.Path from string to Dir. Remove all os.MkdirAll calls from Load() so directories are created lazily on first Path()/MustPath() call. Artwork folder creation was already handled at point-of-use in image_upload.go. Add SnapshotConfig() to conf package for safe test config save/restore that avoids copying sync.Once inside Dir fields. Fix copy-lock vet warning in nativeapi/config.go by marshalling pointer instead of value. * refactor(conf): migrate tests and db init to lazy Dir type Update all test files to use conf.NewDir() for Dir field assignments. Ensure DataFolder is created lazily when the database is first opened in db.Db(). Remove eager directory creation from conf.Load() tests. * fix(conf): address review findings for Dir type - Use os.ModePerm for DataFolder/CacheFolder (was 0700, should match original behavior). Add NewDirWithPerm for PluginsFolder (0700). - Use Path() instead of MustPath() in db.Prune() to avoid logFatal from background cron job. - Panic on marshal/unmarshal errors in SnapshotConfig (test helper). - Clean up redundant String()/MustPath() calls in plugin manager. - Remove dead code in dir_test.go. Signed-off-by: Deluan <deluan@navidrome.org> * fix(conf): add GoString to Dir for clean config dump output Implement fmt.GoStringer on Dir so pretty.Sprintf shows the path string instead of internal struct fields (sync.Once, perm, err). Also add TODO comment to configtest about removing the indirection. * fix(dir): improve error logging in MustPath method Signed-off-by: Deluan <deluan@navidrome.org> * refactor(tests): remove redundant tests for unwritable DataFolder and CacheFolder Signed-off-by: Deluan <deluan@navidrome.org> * fix(conf): address PR review feedback - Ensure Plugins.Folder always uses 0700, even when user-configured (previously only the derived default got restrictive permissions). - Create LogFile parent directory before opening, so LogFile paths inside a not-yet-created DataFolder work correctly. --------- Signed-off-by: Deluan <deluan@navidrome.org>
2026-05-13 12:44:22 -08:00
println(" data folder: " + conf.Server.DataFolder.String())
feat(build): MSI installer improvements (#3376) * feat(build): add a make target to build a msi installer locally * Testing wrapping the executable in cmd * build(ci): build msis in parallel * feat(server): add LogFile config option * Revert "Testing wrapping the executable in cmd" This reverts commit be29592254cb903fd4904f2f50d4d1a860795d33. * Adding --log-file for service executable * feat(ini): wip * feat(ini): parse nested ini section * fix(conf): fix fatal error messages * Now navidrome supports INI, we can use the built-in msi ini system and not require the VBScript to convert it into toml * File needs to be called .ini to be parsed as an INI and correct filename needs to be passed to the service * fix(msi): build msi locally * fix(msi): pipeline * fix(msi): pipeline * fix(msi): pipeline * fix(msi): pipeline * fix(msi): pipeline * fix(msi): Makefile * fix(msi): more clean up * fix(log): convert LF to CRLF on Windows * fix(msi): config filename should be case-insensitive * fix(msi): make it a little more idiomatic * Including the latest windows release of ffmpeg into the msi as built by https://www.gyan.dev/ffmpeg/builds/ (linked to on the official ffmpeg source) * This should version independent * Need bash expansion for the * to work * This will run twice, once for x86 and once for x64, I'll make it cache the executable for now as it'll be quicker * Silencing wget * Add ffmpeg path to the config so Navidrome knows where to find it * refactor: download ffmpeg from our repository * When going back from the "Are you ready to install?" it should go back to the Settings dialogue that you just came from * fix: comments --------- Co-authored-by: Deluan <deluan@navidrome.org>
2024-10-22 15:32:56 -08:00
if conf.Server.LogFile != "" {
println(" log file: " + conf.Server.LogFile)
} else {
refactor(conf): replace eager dir creation with lazy Dir type (#5495) * feat(conf): add Dir type with lazy directory creation Introduces the Dir type that wraps a directory path string and defers os.MkdirAll until the first call to Path() or MustPath(), using sync.Once to ensure the creation happens exactly once. Implements fmt.Stringer, encoding.TextMarshaler, and encoding.TextUnmarshaler for config integration. Includes Ginkgo/Gomega tests covering all methods and error paths. * refactor(conf): replace eager dir creation with lazy Dir type Change DataFolder, CacheFolder, Plugins.Folder, and Backup.Path from string to Dir. Remove all os.MkdirAll calls from Load() so directories are created lazily on first Path()/MustPath() call. Artwork folder creation was already handled at point-of-use in image_upload.go. Add SnapshotConfig() to conf package for safe test config save/restore that avoids copying sync.Once inside Dir fields. Fix copy-lock vet warning in nativeapi/config.go by marshalling pointer instead of value. * refactor(conf): migrate tests and db init to lazy Dir type Update all test files to use conf.NewDir() for Dir field assignments. Ensure DataFolder is created lazily when the database is first opened in db.Db(). Remove eager directory creation from conf.Load() tests. * fix(conf): address review findings for Dir type - Use os.ModePerm for DataFolder/CacheFolder (was 0700, should match original behavior). Add NewDirWithPerm for PluginsFolder (0700). - Use Path() instead of MustPath() in db.Prune() to avoid logFatal from background cron job. - Panic on marshal/unmarshal errors in SnapshotConfig (test helper). - Clean up redundant String()/MustPath() calls in plugin manager. - Remove dead code in dir_test.go. Signed-off-by: Deluan <deluan@navidrome.org> * fix(conf): add GoString to Dir for clean config dump output Implement fmt.GoStringer on Dir so pretty.Sprintf shows the path string instead of internal struct fields (sync.Once, perm, err). Also add TODO comment to configtest about removing the indirection. * fix(dir): improve error logging in MustPath method Signed-off-by: Deluan <deluan@navidrome.org> * refactor(tests): remove redundant tests for unwritable DataFolder and CacheFolder Signed-off-by: Deluan <deluan@navidrome.org> * fix(conf): address PR review feedback - Ensure Plugins.Folder always uses 0700, even when user-configured (previously only the derived default got restrictive permissions). - Create LogFile parent directory before opening, so LogFile paths inside a not-yet-created DataFolder work correctly. --------- Signed-off-by: Deluan <deluan@navidrome.org>
2026-05-13 12:44:22 -08:00
println(" logs folder: " + conf.Server.DataFolder.String())
feat(build): MSI installer improvements (#3376) * feat(build): add a make target to build a msi installer locally * Testing wrapping the executable in cmd * build(ci): build msis in parallel * feat(server): add LogFile config option * Revert "Testing wrapping the executable in cmd" This reverts commit be29592254cb903fd4904f2f50d4d1a860795d33. * Adding --log-file for service executable * feat(ini): wip * feat(ini): parse nested ini section * fix(conf): fix fatal error messages * Now navidrome supports INI, we can use the built-in msi ini system and not require the VBScript to convert it into toml * File needs to be called .ini to be parsed as an INI and correct filename needs to be passed to the service * fix(msi): build msi locally * fix(msi): pipeline * fix(msi): pipeline * fix(msi): pipeline * fix(msi): pipeline * fix(msi): pipeline * fix(msi): Makefile * fix(msi): more clean up * fix(log): convert LF to CRLF on Windows * fix(msi): config filename should be case-insensitive * fix(msi): make it a little more idiomatic * Including the latest windows release of ffmpeg into the msi as built by https://www.gyan.dev/ffmpeg/builds/ (linked to on the official ffmpeg source) * This should version independent * Need bash expansion for the * to work * This will run twice, once for x86 and once for x64, I'll make it cache the executable for now as it'll be quicker * Silencing wget * Add ffmpeg path to the config so Navidrome knows where to find it * refactor: download ffmpeg from our repository * When going back from the "Are you ready to install?" it should go back to the Settings dialogue that you just came from * fix: comments --------- Co-authored-by: Deluan <deluan@navidrome.org>
2024-10-22 15:32:56 -08:00
}
feat: Windows MSI installer and service support (#3125) * First version/rough layout of the required wix to build an MSI that embeds everything * Don't need revision number * produced exe from existing build process is navidrome not Navidrome * Adding Kardianos wrapper around Cobra so the callbacks are handled automatically (this is basically only for windows) * Adding pointless check to shut up lint for now * make format * Revert disabling npm tidy * Using Kardianos always will result in the application hanging so it needs only be wrapped to handle the callbacks if it's being used in the service context, otherwise use cobra directly * Copying in service installation etc from https://github.com/navidrome/navidrome/pull/2295 * Under Linux this installs a user service (I don't think this is correct, but lets get this working first). User units/services cannot depends on system units, so previously this bombed out with Exit Code 5. * Under Windows we can install both the x86 and x64 builds, they will install to different folders, but previously they would overwrite the service as they were both called Navidrome. Now, it will install 2 services. This will still be weird/broken as they will attempt to listen on the same port, however uninstalling the "wrong" arch will not cause the "right" one to be partially uninstalled anymore * Reverting changes to the context as they don't really seem necessary anyway * Need to consistently name the service * Fixing broken context * The included files should be removed when the app is uninstalled * Reverting back to the original context here, I don't think it makes any difference to running under kardianos * Let's see what we have immediately available * OK, the build takes ages so let's just try and do the whole thing in one go, maybe we'll get lucky * Need -r on directory copy, plus we'll probably need to install wixl * No sudo cmd, so I assume this runs as root * WORKSPACE! * Moving the version to be a single variable, we'll probably be able to pull it from the github tag or whatever * Might as well put the msi in the right folder, it's tidier * Writing the version number into the msi, from the output of goreleaser * Using jq to parse the goreleaser metadata, so need to install it * MSI only supports numerical version numbers, so I'll make the "snapshot" version .1 minor patch greater * -r or --raw (on newer versions) means we don't get the "" around the value * Running as a user service I think makes limited sense for this * Will now ask for configuration settings during install. MSI/WiX only supports writing out INI files, Toml is almost INI compatable, except that the INI needs to write out a section first, so we need to have a script to strip that off. We are forced to display a License.rtf file by the UI so I think the build process should probably rename the default licence file and that will suffice. Uninstalling works cleanly, howvever upgrades seem to leave the old version installed in "programs and features" currently. Adding the UI has introduced a requirement for WiX 0.103 * Updating the build to include --ext ui for the new config ui * Configuration dialog should not display for upgrades as the config file is already written * Making description consistent with the systemd service and making the build process produce the required License.rtf * Fixing " non-constant format string in call to fmt.Errorf (govet)" * Its a string, not an int; read better. * Wixl 103 is required for --ext ui, so we need 24.04 * OK this is still installing Wix 0.101, maybe it all needs to be 24.04? * Switching the builds back to ubuntu-latest (22.04 at current) as it runs on a custom container, it's actually debian anyway Moving msi build into its own job so it can run on 24.04 so we have access to wixl 0.103 for --ext ui support * Forcing build * Whitespace fix * Adding sudo I guess * Gotta checkout as well * Adding debugging for when there's soemthing wrong with the paths * Adding more ls to see if the output has worked * The msi's are in subdirs * Actually they're in the ./wix directory * Still can't find these msi's? * I think that was being treated literally previously * No idea why this isn't working, give it a relative path instead? * Making explicit on the dialogue that the configuration file will be where the installation dir is * The lint keeps failing and it's just getting in the way so I'll turn this off for now and we'll edit out this commit from the merge * Cutting more out of the build to get more stuff out of the way * Need to increase the width to fit the text in * Calling everything License.rtf, presumably one of them is correct * I am pretty sure the License.rtf loading is broken under Wixl; so let's just bypass the EULA from the UI which is a nicer experience for the users anyway * This needs to be after WelcomeDlg now the Eula isn't displayed * You're supposed to be able to use <WixVariable> to override the location that the bmp's are loaded from, I can't get this to work under wixl so I'm guessing given that the ui extension is new, it hasn't been implemented with that in mind. So we'll hack it by overwriting the files installed with the package. * We should make this less brittle so when wixl is updated it still works * Re-enabling the lint and tests etc * Improving the scaling quality and removing borders from images to tidy them up a tad * Pretty sure this isn't necessary as MY_PROPERTY will always be false * Without publishing this event, we can't continue to the next dialogue however I think we should be able to get away without the property * Refactoring out the duplication so we only have one service defined and we can run that either way * Pushing the Interactive check into the root commmand? Feels like it is probably getting closer to the right place at least * go tidy * OK this didn't work under windows, I'm guessing it's because it's lacking all the metadata about the service it needs to report back to Windows on. * We need to run service execute now so that the windows service will behave (hopefully)! * Lint * go tidy * Renaming service to "navidrome" rather than "Navidrome" as this is the filename that systemd writes and it's unusual to have capital letters in service names under Linux. Switching to use service execute for Linux to mirror Windows * Need to provide the arguments to append * Without passing the context around, the DB isn't closed gracefully so we end up with with .db-shm and .db-wal files for recovery * We should log fatal rather than outputting directly to stdout * go tidy * refactor: small nitpicks * fix: terminate service gracefully --------- Co-authored-by: Deluan Quintão <deluan@navidrome.org>
2024-10-01 15:40:53 -08:00
if cfgFile != "" {
conf.Server.ConfigFile, err = filepath.Abs(cfgFile)
if err != nil {
log.Fatal(err)
}
println(" config file: " + conf.Server.ConfigFile)
}
err = svcInstance().Install()
if err != nil {
log.Fatal(err)
}
println("Service installed. Use 'navidrome svc start' to start it.")
}
cmd := &cobra.Command{
feat: Windows MSI installer and service support (#3125) * First version/rough layout of the required wix to build an MSI that embeds everything * Don't need revision number * produced exe from existing build process is navidrome not Navidrome * Adding Kardianos wrapper around Cobra so the callbacks are handled automatically (this is basically only for windows) * Adding pointless check to shut up lint for now * make format * Revert disabling npm tidy * Using Kardianos always will result in the application hanging so it needs only be wrapped to handle the callbacks if it's being used in the service context, otherwise use cobra directly * Copying in service installation etc from https://github.com/navidrome/navidrome/pull/2295 * Under Linux this installs a user service (I don't think this is correct, but lets get this working first). User units/services cannot depends on system units, so previously this bombed out with Exit Code 5. * Under Windows we can install both the x86 and x64 builds, they will install to different folders, but previously they would overwrite the service as they were both called Navidrome. Now, it will install 2 services. This will still be weird/broken as they will attempt to listen on the same port, however uninstalling the "wrong" arch will not cause the "right" one to be partially uninstalled anymore * Reverting changes to the context as they don't really seem necessary anyway * Need to consistently name the service * Fixing broken context * The included files should be removed when the app is uninstalled * Reverting back to the original context here, I don't think it makes any difference to running under kardianos * Let's see what we have immediately available * OK, the build takes ages so let's just try and do the whole thing in one go, maybe we'll get lucky * Need -r on directory copy, plus we'll probably need to install wixl * No sudo cmd, so I assume this runs as root * WORKSPACE! * Moving the version to be a single variable, we'll probably be able to pull it from the github tag or whatever * Might as well put the msi in the right folder, it's tidier * Writing the version number into the msi, from the output of goreleaser * Using jq to parse the goreleaser metadata, so need to install it * MSI only supports numerical version numbers, so I'll make the "snapshot" version .1 minor patch greater * -r or --raw (on newer versions) means we don't get the "" around the value * Running as a user service I think makes limited sense for this * Will now ask for configuration settings during install. MSI/WiX only supports writing out INI files, Toml is almost INI compatable, except that the INI needs to write out a section first, so we need to have a script to strip that off. We are forced to display a License.rtf file by the UI so I think the build process should probably rename the default licence file and that will suffice. Uninstalling works cleanly, howvever upgrades seem to leave the old version installed in "programs and features" currently. Adding the UI has introduced a requirement for WiX 0.103 * Updating the build to include --ext ui for the new config ui * Configuration dialog should not display for upgrades as the config file is already written * Making description consistent with the systemd service and making the build process produce the required License.rtf * Fixing " non-constant format string in call to fmt.Errorf (govet)" * Its a string, not an int; read better. * Wixl 103 is required for --ext ui, so we need 24.04 * OK this is still installing Wix 0.101, maybe it all needs to be 24.04? * Switching the builds back to ubuntu-latest (22.04 at current) as it runs on a custom container, it's actually debian anyway Moving msi build into its own job so it can run on 24.04 so we have access to wixl 0.103 for --ext ui support * Forcing build * Whitespace fix * Adding sudo I guess * Gotta checkout as well * Adding debugging for when there's soemthing wrong with the paths * Adding more ls to see if the output has worked * The msi's are in subdirs * Actually they're in the ./wix directory * Still can't find these msi's? * I think that was being treated literally previously * No idea why this isn't working, give it a relative path instead? * Making explicit on the dialogue that the configuration file will be where the installation dir is * The lint keeps failing and it's just getting in the way so I'll turn this off for now and we'll edit out this commit from the merge * Cutting more out of the build to get more stuff out of the way * Need to increase the width to fit the text in * Calling everything License.rtf, presumably one of them is correct * I am pretty sure the License.rtf loading is broken under Wixl; so let's just bypass the EULA from the UI which is a nicer experience for the users anyway * This needs to be after WelcomeDlg now the Eula isn't displayed * You're supposed to be able to use <WixVariable> to override the location that the bmp's are loaded from, I can't get this to work under wixl so I'm guessing given that the ui extension is new, it hasn't been implemented with that in mind. So we'll hack it by overwriting the files installed with the package. * We should make this less brittle so when wixl is updated it still works * Re-enabling the lint and tests etc * Improving the scaling quality and removing borders from images to tidy them up a tad * Pretty sure this isn't necessary as MY_PROPERTY will always be false * Without publishing this event, we can't continue to the next dialogue however I think we should be able to get away without the property * Refactoring out the duplication so we only have one service defined and we can run that either way * Pushing the Interactive check into the root commmand? Feels like it is probably getting closer to the right place at least * go tidy * OK this didn't work under windows, I'm guessing it's because it's lacking all the metadata about the service it needs to report back to Windows on. * We need to run service execute now so that the windows service will behave (hopefully)! * Lint * go tidy * Renaming service to "navidrome" rather than "Navidrome" as this is the filename that systemd writes and it's unusual to have capital letters in service names under Linux. Switching to use service execute for Linux to mirror Windows * Need to provide the arguments to append * Without passing the context around, the DB isn't closed gracefully so we end up with with .db-shm and .db-wal files for recovery * We should log fatal rather than outputting directly to stdout * go tidy * refactor: small nitpicks * fix: terminate service gracefully --------- Co-authored-by: Deluan Quintão <deluan@navidrome.org>
2024-10-01 15:40:53 -08:00
Use: "install",
Short: "Install Navidrome service.",
Run: runInstallCmd,
}
cmd.Flags().StringVarP(&installUser, "user", "u", "", "user to run service")
cmd.Flags().StringVarP(&workingDirectory, "working-directory", "w", "", "working directory of service")
return cmd
feat: Windows MSI installer and service support (#3125) * First version/rough layout of the required wix to build an MSI that embeds everything * Don't need revision number * produced exe from existing build process is navidrome not Navidrome * Adding Kardianos wrapper around Cobra so the callbacks are handled automatically (this is basically only for windows) * Adding pointless check to shut up lint for now * make format * Revert disabling npm tidy * Using Kardianos always will result in the application hanging so it needs only be wrapped to handle the callbacks if it's being used in the service context, otherwise use cobra directly * Copying in service installation etc from https://github.com/navidrome/navidrome/pull/2295 * Under Linux this installs a user service (I don't think this is correct, but lets get this working first). User units/services cannot depends on system units, so previously this bombed out with Exit Code 5. * Under Windows we can install both the x86 and x64 builds, they will install to different folders, but previously they would overwrite the service as they were both called Navidrome. Now, it will install 2 services. This will still be weird/broken as they will attempt to listen on the same port, however uninstalling the "wrong" arch will not cause the "right" one to be partially uninstalled anymore * Reverting changes to the context as they don't really seem necessary anyway * Need to consistently name the service * Fixing broken context * The included files should be removed when the app is uninstalled * Reverting back to the original context here, I don't think it makes any difference to running under kardianos * Let's see what we have immediately available * OK, the build takes ages so let's just try and do the whole thing in one go, maybe we'll get lucky * Need -r on directory copy, plus we'll probably need to install wixl * No sudo cmd, so I assume this runs as root * WORKSPACE! * Moving the version to be a single variable, we'll probably be able to pull it from the github tag or whatever * Might as well put the msi in the right folder, it's tidier * Writing the version number into the msi, from the output of goreleaser * Using jq to parse the goreleaser metadata, so need to install it * MSI only supports numerical version numbers, so I'll make the "snapshot" version .1 minor patch greater * -r or --raw (on newer versions) means we don't get the "" around the value * Running as a user service I think makes limited sense for this * Will now ask for configuration settings during install. MSI/WiX only supports writing out INI files, Toml is almost INI compatable, except that the INI needs to write out a section first, so we need to have a script to strip that off. We are forced to display a License.rtf file by the UI so I think the build process should probably rename the default licence file and that will suffice. Uninstalling works cleanly, howvever upgrades seem to leave the old version installed in "programs and features" currently. Adding the UI has introduced a requirement for WiX 0.103 * Updating the build to include --ext ui for the new config ui * Configuration dialog should not display for upgrades as the config file is already written * Making description consistent with the systemd service and making the build process produce the required License.rtf * Fixing " non-constant format string in call to fmt.Errorf (govet)" * Its a string, not an int; read better. * Wixl 103 is required for --ext ui, so we need 24.04 * OK this is still installing Wix 0.101, maybe it all needs to be 24.04? * Switching the builds back to ubuntu-latest (22.04 at current) as it runs on a custom container, it's actually debian anyway Moving msi build into its own job so it can run on 24.04 so we have access to wixl 0.103 for --ext ui support * Forcing build * Whitespace fix * Adding sudo I guess * Gotta checkout as well * Adding debugging for when there's soemthing wrong with the paths * Adding more ls to see if the output has worked * The msi's are in subdirs * Actually they're in the ./wix directory * Still can't find these msi's? * I think that was being treated literally previously * No idea why this isn't working, give it a relative path instead? * Making explicit on the dialogue that the configuration file will be where the installation dir is * The lint keeps failing and it's just getting in the way so I'll turn this off for now and we'll edit out this commit from the merge * Cutting more out of the build to get more stuff out of the way * Need to increase the width to fit the text in * Calling everything License.rtf, presumably one of them is correct * I am pretty sure the License.rtf loading is broken under Wixl; so let's just bypass the EULA from the UI which is a nicer experience for the users anyway * This needs to be after WelcomeDlg now the Eula isn't displayed * You're supposed to be able to use <WixVariable> to override the location that the bmp's are loaded from, I can't get this to work under wixl so I'm guessing given that the ui extension is new, it hasn't been implemented with that in mind. So we'll hack it by overwriting the files installed with the package. * We should make this less brittle so when wixl is updated it still works * Re-enabling the lint and tests etc * Improving the scaling quality and removing borders from images to tidy them up a tad * Pretty sure this isn't necessary as MY_PROPERTY will always be false * Without publishing this event, we can't continue to the next dialogue however I think we should be able to get away without the property * Refactoring out the duplication so we only have one service defined and we can run that either way * Pushing the Interactive check into the root commmand? Feels like it is probably getting closer to the right place at least * go tidy * OK this didn't work under windows, I'm guessing it's because it's lacking all the metadata about the service it needs to report back to Windows on. * We need to run service execute now so that the windows service will behave (hopefully)! * Lint * go tidy * Renaming service to "navidrome" rather than "Navidrome" as this is the filename that systemd writes and it's unusual to have capital letters in service names under Linux. Switching to use service execute for Linux to mirror Windows * Need to provide the arguments to append * Without passing the context around, the DB isn't closed gracefully so we end up with with .db-shm and .db-wal files for recovery * We should log fatal rather than outputting directly to stdout * go tidy * refactor: small nitpicks * fix: terminate service gracefully --------- Co-authored-by: Deluan Quintão <deluan@navidrome.org>
2024-10-01 15:40:53 -08:00
}
func buildUninstallCmd() *cobra.Command {
return &cobra.Command{
Use: "uninstall",
Short: "Uninstall Navidrome service. Does not delete the music or data folders",
Run: func(cmd *cobra.Command, args []string) {
err := svcInstance().Uninstall()
if err != nil {
log.Fatal(err)
}
println("Service uninstalled. Music and data folders are still intact.")
},
}
}
func buildStartCmd() *cobra.Command {
return &cobra.Command{
Use: "start",
Short: "Start Navidrome service",
Run: func(cmd *cobra.Command, args []string) {
err := svcInstance().Start()
if err != nil {
log.Fatal(err)
}
println("Service started. Use 'navidrome svc status' to check its status.")
},
}
}
func buildStopCmd() *cobra.Command {
return &cobra.Command{
Use: "stop",
Short: "Stop Navidrome service",
Run: func(cmd *cobra.Command, args []string) {
err := svcInstance().Stop()
if err != nil {
log.Fatal(err)
}
println("Service stopped. Use 'navidrome svc status' to check its status.")
},
}
}
func buildStatusCmd() *cobra.Command {
return &cobra.Command{
Use: "status",
Short: "Show Navidrome service status",
Run: func(cmd *cobra.Command, args []string) {
status, err := svcInstance().Status()
if err != nil {
log.Fatal(err)
}
fmt.Printf("Navidrome is %s.\n", svcStatusLabels[status])
},
}
}
func buildExecuteCmd() *cobra.Command {
return &cobra.Command{
Use: "execute",
Short: "Run navidrome as a service in the foreground (it is very unlikely you want to run this, you are better off running just navidrome)",
Run: func(cmd *cobra.Command, args []string) {
err := svcInstance().Run()
if err != nil {
log.Fatal(err)
}
},
}
}
const systemdScript = `[Unit]
Description={{.Description}}
ConditionFileIsExecutable={{.Path|cmdEscape}}
{{range $i, $dep := .Dependencies}}
{{$dep}} {{end}}
[Service]
StartLimitInterval=5
StartLimitBurst=10
ExecStart={{.Path|cmdEscape}}{{range .Arguments}} {{.|cmd}}{{end}}
{{if .WorkingDirectory}}WorkingDirectory={{.WorkingDirectory|cmdEscape}}{{end}}
{{if .UserName}}User={{.UserName}}{{end}}
{{if .Restart}}Restart={{.Restart}}{{end}}
{{if .SuccessExitStatus}}SuccessExitStatus={{.SuccessExitStatus}}{{end}}
TimeoutStopSec=20
RestartSec=120
EnvironmentFile=-/etc/sysconfig/{{.Name}}
Environment="ND_SYSTEMD_PRIORITY_LOGGING=1"
DevicePolicy=closed
NoNewPrivileges=yes
PrivateTmp=yes
ProtectControlGroups=yes
ProtectKernelModules=yes
ProtectKernelTunables=yes
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
RestrictNamespaces=yes
RestrictRealtime=yes
SystemCallFilter=~@clock @debug @module @mount @obsolete @reboot @setuid @swap
{{if .WorkingDirectory}}ReadWritePaths={{.WorkingDirectory|cmdEscape}}{{end}}
ProtectSystem=full
[Install]
WantedBy=multi-user.target
`