Run executes the program.
(ctx context.Context, args []string)
| 118 | |
| 119 | // Run executes the program. |
| 120 | func (m *Main) Run(ctx context.Context, args []string) (err error) { |
| 121 | // Execute replication command if running as a Windows service. |
| 122 | if isService, err := isWindowsService(); err != nil { |
| 123 | return err |
| 124 | } else if isService { |
| 125 | return runWindowsService(ctx) |
| 126 | } |
| 127 | |
| 128 | // Copy "LITESTEAM" environment credentials. |
| 129 | applyLitestreamEnv() |
| 130 | |
| 131 | // Extract command name. |
| 132 | var cmd string |
| 133 | if len(args) > 0 { |
| 134 | cmd, args = args[0], args[1:] |
| 135 | } |
| 136 | |
| 137 | switch cmd { |
| 138 | case "databases": |
| 139 | return (&DatabasesCommand{}).Run(ctx, args) |
| 140 | case "replicate": |
| 141 | c := NewReplicateCommand() |
| 142 | if err := c.ParseFlags(ctx, args); err != nil { |
| 143 | return err |
| 144 | } |
| 145 | |
| 146 | // Setup signal handler. |
| 147 | signalCh := signalChan() |
| 148 | |
| 149 | // Create done channel for interrupt during shutdown. It will be |
| 150 | // closed when a second signal arrives, allowing each database's |
| 151 | // retry loop to observe the interrupt. |
| 152 | done := make(chan struct{}) |
| 153 | c.SetDone(done) |
| 154 | |
| 155 | if err := c.Run(ctx); err != nil { |
| 156 | return err |
| 157 | } |
| 158 | |
| 159 | // Wait for signal to stop program. |
| 160 | select { |
| 161 | case err = <-c.execCh: |
| 162 | if c.cmd != nil { |
| 163 | slog.Info("subprocess exited, litestream shutting down") |
| 164 | } else { |
| 165 | slog.Info("replication complete, litestream shutting down") |
| 166 | } |
| 167 | case sig := <-signalCh: |
| 168 | slog.Info("signal received, litestream shutting down", "signal", sig) |
| 169 | |
| 170 | if c.cmd != nil { |
| 171 | slog.Info("sending signal to exec process") |
| 172 | if err := c.cmd.Process.Signal(sig); err != nil { |
| 173 | return fmt.Errorf("cannot signal exec process: %w", err) |
| 174 | } |
| 175 | |
| 176 | slog.Info("waiting for exec process to close") |
| 177 | if err := <-c.execCh; err != nil && !strings.HasPrefix(err.Error(), "signal:") { |