mirror of
https://github.com/runbear-io/beardrive.git
synced 2026-08-25 08:08:08 +02:00
review fixes: gate init next-steps on background mode, shared stdinIsTTY, daemon reconnects on token change, whoami surfaces settings errors, doc staleness (#41)
- init -f no longer prints 'daemon now keeps this folder in sync' after the foreground daemon has exited - one stdinIsTTY() helper (TTY or Cygwin pty) shared by init's prompt gate and login's headless fallback — the two sites disagreed on Cygwin - the daemon drops its remote backend when the device token changes, so an account switch mid-run reconnects with the new credential instead of pushing with the old one (httpBackend captures the token at open) - whoami reports a settings read error instead of claiming 'not signed in' - self-hosting/authentication and manual/setup-by-hand now describe the automatic device-code fallback instead of presenting --device as required Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
2b9beaf41a
commit
220e27a9c2
@@ -6,12 +6,20 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/mattn/go-isatty"
|
||||
|
||||
"github.com/runbear-io/beardrive/internal/config"
|
||||
"github.com/runbear-io/beardrive/internal/remote"
|
||||
"github.com/runbear-io/beardrive/internal/store"
|
||||
"github.com/runbear-io/beardrive/internal/syncer"
|
||||
)
|
||||
|
||||
// stdinIsTTY is the one answer to "is this an interactive shell?" — used both
|
||||
// to decide whether init may prompt and whether login can drive a browser.
|
||||
func stdinIsTTY() bool {
|
||||
return isatty.IsTerminal(os.Stdin.Fd()) || isatty.IsCygwinTerminal(os.Stdin.Fd())
|
||||
}
|
||||
|
||||
func absFolder(args []string) (string, error) {
|
||||
arg := "."
|
||||
if len(args) > 0 {
|
||||
|
||||
+4
-2
@@ -14,7 +14,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/mattn/go-isatty"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/runbear-io/beardrive/internal/config"
|
||||
@@ -97,7 +96,7 @@ the folder was renamed or moved.`,
|
||||
}
|
||||
server := settings.Server
|
||||
|
||||
interactive := isatty.IsTerminal(os.Stdin.Fd()) && !yes
|
||||
interactive := stdinIsTTY() && !yes
|
||||
|
||||
// Which project?
|
||||
var p serverProject
|
||||
@@ -159,6 +158,9 @@ the folder was renamed or moved.`,
|
||||
if err := startSync(cmd.Context(), folder, proj, foreground, 3*time.Second, 10*time.Second); err != nil {
|
||||
return err
|
||||
}
|
||||
if foreground {
|
||||
return nil // daemon already ran and exited; "syncing automatically" would be false now
|
||||
}
|
||||
fmt.Printf(`
|
||||
done — the daemon now keeps this folder in sync automatically.
|
||||
|
||||
|
||||
+1
-2
@@ -17,7 +17,6 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/mattn/go-isatty"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/runbear-io/beardrive/internal/config"
|
||||
@@ -167,7 +166,7 @@ func runLogin(server string, cfg serverConfig, useDevice bool) error {
|
||||
// Headless shells (agents, CI, SSH) can't complete the loopback-callback
|
||||
// flow — the browser would open nowhere and the CLI would hang. Fall back
|
||||
// to the device-code flow automatically instead of waiting.
|
||||
if !useDevice && !isatty.IsTerminal(os.Stdin.Fd()) && !isatty.IsCygwinTerminal(os.Stdin.Fd()) {
|
||||
if !useDevice && !stdinIsTTY() {
|
||||
fmt.Println("no interactive terminal detected — using the device-code sign-in flow")
|
||||
useDevice = true
|
||||
}
|
||||
|
||||
+4
-1
@@ -79,7 +79,10 @@ func whoamiCmd() *cobra.Command {
|
||||
}
|
||||
fmt.Printf("device id: %s\n", dev.ID)
|
||||
fmt.Printf("device name: %s\n", dev.Name)
|
||||
if settings, _ := config.LoadSettings(); settings.Email != "" {
|
||||
settings, serr := config.LoadSettings()
|
||||
if serr != nil {
|
||||
fmt.Printf("account: unknown — cannot read settings: %v\n", serr)
|
||||
} else if settings.Email != "" {
|
||||
who := settings.Email
|
||||
if settings.Name != "" {
|
||||
who = settings.Name + " <" + settings.Email + ">"
|
||||
|
||||
@@ -144,6 +144,7 @@ func Run(folder string, scanInterval, remoteInterval time.Duration) error {
|
||||
}
|
||||
}()
|
||||
var lastRemote time.Time
|
||||
var lastToken string
|
||||
|
||||
for {
|
||||
// Re-read the project config each tick: picks up `bdrive remote set`
|
||||
@@ -177,6 +178,21 @@ func Run(folder string, scanInterval, remoteInterval time.Duration) error {
|
||||
}
|
||||
proj = cur
|
||||
|
||||
// Re-read settings each tick too, so a login/logout/account switch
|
||||
// after the daemon started is reflected in op authorship — otherwise
|
||||
// a long-lived daemon stamps every change with a stale identity. The
|
||||
// http backend captures its credential at open, so drop it when the
|
||||
// token changes and reconnect with the new one.
|
||||
settings, _ := config.LoadSettings()
|
||||
if settings.Token != lastToken {
|
||||
if be != nil {
|
||||
be.Close()
|
||||
be = nil
|
||||
}
|
||||
lastToken = settings.Token
|
||||
lastRemote = time.Time{}
|
||||
}
|
||||
|
||||
doRemote := proj.Remote != "" && time.Since(lastRemote) >= remoteInterval
|
||||
if doRemote && be == nil {
|
||||
b, err := remote.Open(ctx, proj.Remote)
|
||||
@@ -189,10 +205,6 @@ func Run(folder string, scanInterval, remoteInterval time.Duration) error {
|
||||
}
|
||||
}
|
||||
|
||||
// Re-read settings each tick too, so a login/logout/account switch
|
||||
// after the daemon started is reflected in op authorship — otherwise
|
||||
// a long-lived daemon stamps every change with a stale identity.
|
||||
settings, _ := config.LoadSettings()
|
||||
sess := &syncer.Session{Folder: folder, MountID: proj.ID, Store: st, Device: dev, Account: settings}
|
||||
if doRemote {
|
||||
sess.Backend = be
|
||||
|
||||
@@ -28,8 +28,9 @@ bdrive login https://your-hub
|
||||
```
|
||||
|
||||
This opens your browser, and the terminal finishes on its own. On a headless or
|
||||
SSH machine, `bdrive login --device` prints a short code you approve from any
|
||||
signed-in browser instead.
|
||||
SSH machine login falls back to the device-code flow automatically (no TTY, or
|
||||
no browser can open): it prints a short code you approve from any signed-in
|
||||
browser. `bdrive login --device` forces that flow.
|
||||
|
||||
`bdrive login --status` shows the current server and account.
|
||||
|
||||
|
||||
@@ -63,8 +63,9 @@ right there if needed. When the user signs in, the page bounces a one-time code
|
||||
to the CLI's loopback listener and the terminal finishes on its own, storing a
|
||||
long-lived per-device token that is revocable server-side.
|
||||
|
||||
On headless or SSH machines, `bdrive login --device` prints a short code to
|
||||
approve from any signed-in browser instead.
|
||||
On headless or SSH machines login falls back to the device-code flow
|
||||
automatically (no TTY, or no browser can open): it prints a short code to
|
||||
approve from any signed-in browser. `bdrive login --device` forces that flow.
|
||||
|
||||
Every sync and every `bdrive init` then authenticates with that token. The hub's
|
||||
device registry records per-device name, OS, account, and the IP the server
|
||||
|
||||
Reference in New Issue
Block a user