@@ -12,6 +12,7 @@ import (
1212
1313 "go.uber.org/zap"
1414
15+ "github.com/fatih/color"
1516 "github.com/sqlrsync/sqlrsync.com/auth"
1617 "github.com/sqlrsync/sqlrsync.com/bridge"
1718 "github.com/sqlrsync/sqlrsync.com/remote"
@@ -40,7 +41,7 @@ type Config struct {
4041 ReplicaPath string // For LOCAL TO LOCAL sync
4142 Version string
4243 Operation Operation
43- SetPublic bool
44+ SetVisibility int
4445 DryRun bool
4546 Logger * zap.Logger
4647 Verbose bool
@@ -101,6 +102,64 @@ func (c *Coordinator) Execute() error {
101102 }
102103}
103104
105+ // displayDryRunInfo displays dry run information for different operations
106+ func (c * Coordinator ) displayDryRunInfo (operation string , authResult * auth.ResolveResult , absLocalPath , serverURL , remotePath , localHostname string ) {
107+ fmt .Println ("SQLRsync Dry Run:" )
108+
109+ switch operation {
110+ case "push" :
111+ fmt .Printf (" - Mode: %s the LOCAL ORIGIN file up to the REMOTE REPLICA\n " , color .YellowString ("PUSHing" ))
112+ fmt .Printf (" - LOCAL ORIGIN: %s\n " , color .GreenString (absLocalPath ))
113+ if remotePath == "" {
114+ fmt .Println (" - REMOTE REPLICA: " + color .YellowString ("(None - the server will assign a path using this hostname)" ))
115+ fmt .Printf (" - Hostname: %s\n " , color .GreenString (localHostname ))
116+ } else {
117+ fmt .Printf (" - REMOTE REPLICA: %s\n " , color .GreenString (remotePath ))
118+ }
119+ case "pull" :
120+ fmt .Printf (" - Mode: %s the REMOTE ORIGIN file down to LOCAL REPLICA\n " , color .YellowString ("PULLing" ))
121+ fmt .Printf (" - REMOTE ORIGIN: %s\n " , color .GreenString (remotePath ))
122+ fmt .Printf (" - LOCAL REPLICA: %s\n " , color .GreenString (absLocalPath ))
123+ case "subscribe" :
124+ fmt .Printf (" - Mode: %s to REMOTE ORIGIN to PULL down current and future updates\n " , color .YellowString ("SUBSCRIBing" ))
125+ fmt .Printf (" - REMOTE ORIGIN: %s\n " , color .GreenString (remotePath ))
126+ fmt .Printf (" - LOCAL REPLICA: %s\n " , color .GreenString (absLocalPath ))
127+ case "local" :
128+ fmt .Printf (" - Mode: %s between two databases\n " , color .YellowString ("LOCAL ONLY" ))
129+ }
130+
131+ if operation != "local" {
132+ fmt .Printf (" - Server: %s\n " , color .GreenString (serverURL ))
133+
134+ fmt .Printf (" - Auth Token: %s\n " , color .GreenString (authResult .AuthToken ))
135+
136+ if operation == "push" {
137+ switch c .config .SetVisibility {
138+ case 0 :
139+ fmt .Println (" - Visibility: " + color .YellowString ("PRIVATE" ) + " (only accessible with access key)" )
140+ case 1 :
141+ fmt .Println (" - Visibility: " + color .YellowString ("UNLISTED" ) + " (anyone with the link can access)" )
142+ case 2 :
143+ fmt .Println (" - Visibility: " + color .GreenString ("PUBLIC" ) + " (anyone can access)" )
144+ }
145+ }
146+
147+ if c .authResolver .CheckNeedsDashFile (c .config .LocalPath , remotePath ) {
148+ fmt .Println (" - A shareable config (the -sqlrsync file) " + color .GreenString ("WILL BE" ) + " created for future PULLs and SUBSCRIBEs" )
149+ } else {
150+ fmt .Println (" - A shareable config (the -sqlrsync file) will " + color .RedString ("NOT" ) + " be created" )
151+ }
152+ } else {
153+ // For local sync, show the replica path
154+ if c .config .ReplicaPath != "" {
155+ absReplicaPath , _ := filepath .Abs (c .config .ReplicaPath )
156+ fmt .Printf (" - LOCAL ORIGIN: %s\n " , color .GreenString (absLocalPath ))
157+ fmt .Printf (" - LOCAL REPLICA: %s\n " , color .GreenString (absReplicaPath ))
158+ }
159+ }
160+ fmt .Println ("\n After running this command, REPLICA will become a copy of ORIGIN at the moment the command begins." )
161+ }
162+
104163// resolveAuth resolves authentication for the given operation
105164func (c * Coordinator ) resolveAuth (operation string ) (* auth.ResolveResult , error ) {
106165 req := & auth.ResolveRequest {
@@ -154,6 +213,28 @@ func (c *Coordinator) executeSubscribe() error {
154213 return fmt .Errorf ("authentication failed: %w" , err )
155214 }
156215
216+ // Check for dry run mode
217+ if c .config .DryRun {
218+ absLocalPath , err := filepath .Abs (c .config .LocalPath )
219+ if err != nil {
220+ return fmt .Errorf ("failed to get absolute path: %w" , err )
221+ }
222+ localHostname , _ := os .Hostname ()
223+
224+ serverURL := authResult .ServerURL
225+ if c .config .ServerURL != "" && c .config .ServerURL != "wss://sqlrsync.com" {
226+ serverURL = c .config .ServerURL
227+ }
228+
229+ remotePath := authResult .RemotePath
230+ if c .config .RemotePath != "" {
231+ remotePath = c .config .RemotePath
232+ }
233+
234+ c .displayDryRunInfo ("subscribe" , authResult , absLocalPath , serverURL , remotePath , localHostname )
235+ return nil
236+ }
237+
157238 // Create subscription manager with reconnection configuration
158239 c .subManager = subscription .NewManager (& subscription.Config {
159240 ServerURL : authResult .ServerURL ,
@@ -196,7 +277,7 @@ func (c *Coordinator) executeSubscribe() error {
196277 }
197278
198279 // Wait for new version notification
199- var version string ;
280+ var version string
200281 for {
201282 version , err = c .subManager .WaitForNewVersionMsg ()
202283 if err != nil {
@@ -258,6 +339,18 @@ func (c *Coordinator) executePull(isSubscription bool) error {
258339 remotePath = c .config .RemotePath
259340 }
260341
342+ // Get absolute path and hostname for dry run display
343+ absLocalPath , err := filepath .Abs (c .config .LocalPath )
344+ if err != nil {
345+ return fmt .Errorf ("failed to get absolute path: %w" , err )
346+ }
347+ localHostname , _ := os .Hostname ()
348+
349+ if c .config .DryRun {
350+ c .displayDryRunInfo ("pull" , authResult , absLocalPath , serverURL , remotePath , localHostname )
351+ return nil
352+ }
353+
261354 if ! isSubscription {
262355 fmt .Printf ("PULLing down from %s/%s@%s ...\n " , serverURL , remotePath , version )
263356 }
@@ -275,7 +368,7 @@ func (c *Coordinator) executePull(isSubscription bool) error {
275368 InspectionDepth : 5 ,
276369 Version : version ,
277370 SendConfigCmd : true ,
278- SendKeyRequest : c .authResolver .CheckNeedsDashFile (c .config .LocalPath , remotePath ),
371+ SendKeyRequest : c .authResolver .CheckNeedsDashFile (c .config .LocalPath , remotePath ),
279372 //ProgressCallback: remote.DefaultProgressCallback(remote.FormatSimple),
280373 ProgressCallback : nil ,
281374 ProgressConfig : & remote.ProgressConfig {
@@ -359,8 +452,6 @@ func (c *Coordinator) executePush() error {
359452 remotePath = c .config .RemotePath
360453 }
361454
362- fmt .Printf ("PUSHing up to %s/%s ...\n " , serverURL , remotePath )
363-
364455 // Create local client for SQLite operations
365456 localClient , err := bridge .New (& bridge.Config {
366457 DatabasePath : c .config .LocalPath ,
@@ -380,6 +471,13 @@ func (c *Coordinator) executePush() error {
380471
381472 localHostname , _ := os .Hostname ()
382473
474+ if c .config .DryRun {
475+ c .displayDryRunInfo ("push" , authResult , absLocalPath , serverURL , remotePath , localHostname )
476+ return nil
477+ }
478+
479+ fmt .Printf ("PUSHing up to %s/%s ...\n " , serverURL , remotePath )
480+
383481 // Create remote client for WebSocket transport
384482 remoteClient , err := remote .New (& remote.Config {
385483 ServerURL : serverURL + "/sapi/push/" + remotePath ,
@@ -393,7 +491,7 @@ func (c *Coordinator) executePush() error {
393491 InspectionDepth : 5 ,
394492 SendKeyRequest : c .authResolver .CheckNeedsDashFile (c .config .LocalPath , remotePath ),
395493 SendConfigCmd : true ,
396- SetPublic : c .config .SetPublic ,
494+ SetVisibility : c .config .SetVisibility ,
397495 ProgressCallback : nil , //remote.DefaultProgressCallback(remote.FormatSimple),
398496 ProgressConfig : & remote.ProgressConfig {
399497 Enabled : true ,
@@ -454,10 +552,6 @@ func (c *Coordinator) executePush() error {
454552 }
455553 }
456554
457- if c .config .SetPublic {
458- fmt .Printf ("🌐 This replica is now publicly accessible at sqlrsync.com/%s\n " , remoteClient .GetReplicaPath ())
459- }
460-
461555 c .logger .Info ("Push synchronization completed successfully" )
462556 return nil
463557}
@@ -523,6 +617,11 @@ func (c *Coordinator) executeLocalSync() error {
523617 return fmt .Errorf ("failed to get absolute path for replica: %w" , err )
524618 }
525619
620+ if c .config .DryRun {
621+ c .displayDryRunInfo ("local" , nil , absOriginPath , "" , "" , "" )
622+ return nil
623+ }
624+
526625 fmt .Printf ("Syncing LOCAL to LOCAL: %s → %s\n " , absOriginPath , absReplicaPath )
527626
528627 // Create local client for SQLite operations
0 commit comments