فهرست منبع

Use an 'install count' to determine whether to update Syncthing

When the installer runs, it will increment a number in 'InstallCount.txt'.
SyncTrayzor keeps a record of the last number it saw, and uses this to determine
whether to update the Syncthing.exe copy in AppData. This is more robust than trying
to use file mtimes.

Fixes #63
Antony Male 10 سال پیش
والد
کامیت
cc4c6a68a3

+ 21 - 0
installer/x64/installer-x64.iss

@@ -86,12 +86,32 @@ begin
   result := not exists or (release < 378758);
 end;
 
+procedure BumpInstallCount;
+var
+  fileContents: AnsiString;
+  installCount: integer;
+begin
+  { Increment the install count in InstallCount.txt if it exists, or create it with the contents '1' if it doesn't }
+  if LoadStringFromFile(ExpandConstant('{app}\InstallCount.txt'), fileContents) then
+  begin
+    installCount := StrTointDef(Trim(string(fileContents)), 0) + 1;
+  end
+  else
+  begin
+    installCount := 1;
+  end;
+
+  SaveStringToFile(ExpandConstant('{app}\InstallCount.txt'), IntToStr(installCount), False);
+end;
+
 procedure CurStepChanged(CurStep: TSetupStep);
 var
   ResultCode: integer;
 begin
   if CurStep = ssInstall then
   begin
+    BumpInstallCount();
+
     { We might be being run from ProcessRunner.exe, *and* we might be trying to update it. Funsies. Let's rename it (which Windows lets us do) }
     DeleteFile(ExpandConstant('{app}\ProcessRunner.exe.old'));
     RenameFile(ExpandConstant('{app}\ProcessRunner.exe'), ExpandConstant('{app}\ProcessRunner.exe.old'));
@@ -114,5 +134,6 @@ end;
 
 [UninstallDelete]
 Type: files; Name: "{app}\ProcessRunner.exe.old"
+Type: files; Name: "{app}\InstallCount.txt"
 Type: filesandordirs; Name: "{userappdata}\{#AppDataFolder}"
 Type: filesandordirs; Name: "{userappdata}\{#AppDataFolder}"

+ 21 - 0
installer/x86/installer-x86.iss

@@ -84,12 +84,32 @@ begin
   result := not exists or (release < 378758);
 end;
 
+procedure BumpInstallCount;
+var
+  fileContents: AnsiString;
+  installCount: integer;
+begin
+  { Increment the install count in InstallCount.txt if it exists, or create it with the contents '1' if it doesn't }
+  if LoadStringFromFile(ExpandConstant('{app}\InstallCount.txt'), fileContents) then
+  begin
+    installCount := StrTointDef(Trim(string(fileContents)), 0) + 1;
+  end
+  else
+  begin
+    installCount := 1;
+  end;
+
+  SaveStringToFile(ExpandConstant('{app}\InstallCount.txt'), IntToStr(installCount), False);
+end;
+
 procedure CurStepChanged(CurStep: TSetupStep);
 var
   ResultCode: integer;
 begin
   if CurStep = ssInstall then
   begin
+    BumpInstallCount();
+
     { We might be being run from ProcessRunner.exe, *and* we might be trying to update it. Funsies. Let's rename it (which Windows lets us do) }
     DeleteFile(ExpandConstant('{app}\ProcessRunner.exe.old'));
     RenameFile(ExpandConstant('{app}\ProcessRunner.exe'), ExpandConstant('{app}\ProcessRunner.exe.old'));
@@ -112,5 +132,6 @@ end;
 
 [UninstallDelete]
 Type: files; Name: "{app}\ProcessRunner.exe.old"
+Type: files; Name: "{app}\InstallCount.txt"
 Type: filesandordirs; Name: "{userappdata}\{#AppDataFolder}"
 Type: filesandordirs; Name: "{userappdata}\{#AppDataFolder}"

+ 1 - 0
src/SyncTrayzor/App.config

@@ -64,6 +64,7 @@
                         <UseComputerCulture>true</UseComputerCulture>
                         <SyncthingConsoleHeight>100</SyncthingConsoleHeight>
                         <SyncthingWebBrowserZoomLevel>0</SyncthingWebBrowserZoomLevel>
+                        <LastSeenInstallCount>0</LastSeenInstallCount>
                     </Configuration>
                 </value>
             </setting>

+ 1 - 0
src/SyncTrayzor/Properties/Settings.Designer.cs

@@ -134,6 +134,7 @@ namespace SyncTrayzor.Properties {
   <UseComputerCulture>true</UseComputerCulture>
   <SyncthingConsoleHeight>100</SyncthingConsoleHeight>
   <SyncthingWebBrowserZoomLevel>0</SyncthingWebBrowserZoomLevel>
+  <LastSeenInstallCount>0</LastSeenInstallCount>
 </Configuration>")]
         public global::SyncTrayzor.Services.Config.Configuration DefaultUserConfiguration {
             get {

+ 1 - 0
src/SyncTrayzor/Properties/Settings.settings

@@ -52,6 +52,7 @@
   &lt;UseComputerCulture&gt;true&lt;/UseComputerCulture&gt;
   &lt;SyncthingConsoleHeight&gt;100&lt;/SyncthingConsoleHeight&gt;
   &lt;SyncthingWebBrowserZoomLevel&gt;0&lt;/SyncthingWebBrowserZoomLevel&gt;
+  &lt;LastSeenInstallCount&gt;0&lt;/LastSeenInstallCount&gt;
 &lt;/Configuration&gt;</Value>
     </Setting>
     <Setting Name="PathConfiguration" Type="SyncTrayzor.Services.Config.PathConfiguration" Scope="Application">

+ 6 - 0
src/SyncTrayzor/Services/Config/ApplicationPathsProvider.cs

@@ -17,6 +17,7 @@ namespace SyncTrayzor.Services.Config
         string ConfigurationFilePath { get; }
         string ConfigurationFileBackupPath { get; }
         string UpdatesDownloadPath { get; }
+        string InstallCountFilePath { get; }
 
         void Initialize(PathConfiguration pathConfiguration);
     }
@@ -84,5 +85,10 @@ namespace SyncTrayzor.Services.Config
         {
             get { return Path.Combine(Path.GetTempPath(), "SyncTrayzor"); }
         }
+
+        public string InstallCountFilePath
+        {
+            get { return Path.Combine(this.ExePath, "InstallCount.txt"); }
+        }
     }
 }

+ 5 - 2
src/SyncTrayzor/Services/Config/Configuration.cs

@@ -120,6 +120,7 @@ namespace SyncTrayzor.Services.Config
         public double SyncthingConsoleHeight { get; set; }
         public WindowPlacement WindowPlacement { get; set; }
         public double SyncthingWebBrowserZoomLevel { get; set; }
+        public int LastSeenInstallCount { get; set; }
 
         public Configuration()
         {
@@ -145,6 +146,7 @@ namespace SyncTrayzor.Services.Config
             this.SyncthingConsoleHeight = Configuration.DefaultSyncthingConsoleHeight;
             this.WindowPlacement = null;
             this.SyncthingWebBrowserZoomLevel = 0;
+            this.LastSeenInstallCount = 0;
         }
 
         public Configuration(Configuration other)
@@ -169,6 +171,7 @@ namespace SyncTrayzor.Services.Config
             this.SyncthingConsoleHeight = other.SyncthingConsoleHeight;
             this.WindowPlacement = other.WindowPlacement;
             this.SyncthingWebBrowserZoomLevel = other.SyncthingWebBrowserZoomLevel;
+            this.LastSeenInstallCount = other.LastSeenInstallCount;
         }
 
         public override string ToString()
@@ -177,12 +180,12 @@ namespace SyncTrayzor.Services.Config
                 "ShowDeviceConnectivityBalloons={4} SyncthingAddress={5} StartSyncthingAutomatically={6} SyncthingApiKey={7} SyncthingEnvironmentalVariables=[{8}] " +
                 "SyncthingUseCustomHome={9} SyncthingDenyUpgrade={10} SyncthingRunLowPriority={11} Folders=[{12}] NotifyOfNewVersions={13} " +
                 "LastNotifiedVersion={14} ObfuscateDeviceIDs={15} UseComputerCulture={16} SyncthingConsoleHeight={17} WindowPlacement={18} " +
-                "SyncthingWebBrowserZoomLevel={19}>",
+                "SyncthingWebBrowserZoomLevel={19} LastSeenInstallCount={20}>",
                 this.ShowTrayIconOnlyOnClose, this.MinimizeToTray, this.CloseToTray, this.ShowSynchronizedBalloon, this.ShowDeviceConnectivityBalloons,
                 this.SyncthingAddress, this.StartSyncthingAutomatically, this.SyncthingApiKey, String.Join(" ", this.SyncthingEnvironmentalVariables.Select(x => String.Format("{0}={1}", x.Key, x.Value))),
                 this.SyncthingUseCustomHome, this.SyncthingDenyUpgrade, this.SyncthingRunLowPriority, String.Join(", ", this.Folders), this.NotifyOfNewVersions,
                 this.LatestNotifiedVersion, this.ObfuscateDeviceIDs, this.UseComputerCulture, this.SyncthingConsoleHeight, this.WindowPlacement,
-                this.SyncthingWebBrowserZoomLevel);
+                this.SyncthingWebBrowserZoomLevel, this.LastSeenInstallCount);
         }
     }
 }

+ 46 - 12
src/SyncTrayzor/Services/Config/ConfigurationProvider.cs

@@ -80,25 +80,59 @@ namespace SyncTrayzor.Services.Config
             if (!File.Exists(Path.GetDirectoryName(this.paths.ConfigurationFilePath)))
                 Directory.CreateDirectory(Path.GetDirectoryName(this.paths.ConfigurationFilePath));
 
-            if (!File.Exists(this.paths.SyncthingPath))
+            this.currentConfig = this.LoadFromDisk(defaultConfiguration);
+
+            bool installCountChanged = false;
+            bool updateConfigInstallCount = false;
+            int latestInstallCount = 0;
+            // Might be portable, in which case this file won't exist
+            if (File.Exists(this.paths.InstallCountFilePath))
             {
-                if (File.Exists(this.paths.SyncthingBackupPath))
+                latestInstallCount = Int32.Parse(File.ReadAllText(this.paths.InstallCountFilePath).Trim());
+                if (latestInstallCount != this.currentConfig.LastSeenInstallCount)
                 {
-                    logger.Info("Syncthing doesn't exist at {0}, so copying from {1}", this.paths.SyncthingPath, this.paths.SyncthingBackupPath);
-                    File.Copy(this.paths.SyncthingBackupPath, this.paths.SyncthingPath);
+                    installCountChanged = true;
+                    updateConfigInstallCount = true;
                 }
-                else
-                    throw new Exception(String.Format("Unable to find Syncthing at {0} or {1}", this.paths.SyncthingPath, this.paths.SyncthingBackupPath));
             }
-            else if (this.paths.SyncthingPath != this.paths.SyncthingBackupPath && File.Exists(this.paths.SyncthingBackupPath) &&
-                File.GetLastWriteTimeUtc(this.paths.SyncthingPath) < File.GetLastWriteTimeUtc(this.paths.SyncthingBackupPath))
+
+            // They're the same if we're portable, in which case, nothing to do
+            if (this.paths.SyncthingPath != this.paths.SyncthingBackupPath)
             {
-                logger.Info("Syncthing at {0} is older ({1}) than at {2} ({3}, so overwriting from backup",
-                    this.paths.SyncthingPath, File.GetLastWriteTimeUtc(this.paths.SyncthingPath), this.paths.SyncthingBackupPath, File.GetLastWriteTimeUtc(this.paths.SyncthingBackupPath));
-                File.Copy(this.paths.SyncthingBackupPath, this.paths.SyncthingPath, true);
+                if (!File.Exists(this.paths.SyncthingPath))
+                {
+                    if (File.Exists(this.paths.SyncthingBackupPath))
+                    {
+                        logger.Info("Syncthing doesn't exist at {0}, so copying from {1}", this.paths.SyncthingPath, this.paths.SyncthingBackupPath);
+                        File.Copy(this.paths.SyncthingBackupPath, this.paths.SyncthingPath);
+                    }
+                    else
+                    {
+                        throw new Exception(String.Format("Unable to find Syncthing at {0} or {1}", this.paths.SyncthingPath, this.paths.SyncthingBackupPath));
+                    }
+                }
+                else if (installCountChanged)
+                {
+                    // If we hit this, then latestInstallCount is set to a real value
+                    logger.Info("Install Count changed, so updating Syncthing at {0} from {1}", this.paths.SyncthingPath, this.paths.SyncthingBackupPath);
+                    try
+                    {
+                        File.Copy(this.paths.SyncthingBackupPath, this.paths.SyncthingPath, true);
+                    }
+                    catch (IOException e)
+                    {
+                        // Syncthing.exe was probably running. We'll try again next time
+                        updateConfigInstallCount = false;
+                        logger.Error(String.Format("Failed to copy Syncthing from {0} to {1}", this.paths.SyncthingBackupPath, this.paths.SyncthingPath), e);
+                    }
+                }
             }
 
-            this.currentConfig = this.LoadFromDisk(defaultConfiguration);
+            if (updateConfigInstallCount)
+            {
+                this.currentConfig.LastSeenInstallCount = latestInstallCount;
+                this.SaveToFile(this.currentConfig);
+            }
         }
 
         private Configuration LoadFromDisk(Configuration defaultConfiguration)