Skip to content

Commit 7e26689

Browse files
authored
Merge pull request #143 from jjw24/add_enable_portablemode_setting
Enable/disable portable mode setting
2 parents d6f1d13 + cb0a4de commit 7e26689

File tree

19 files changed

+328
-45
lines changed

19 files changed

+328
-45
lines changed

Plugins/Wox.Plugin.Program/Logger/ProgramLogger.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using NLog;
1+
using NLog;
22
using NLog.Config;
33
using NLog.Targets;
44
using System;
@@ -7,6 +7,7 @@
77
using System.Runtime.CompilerServices;
88
using System.Security;
99
using Wox.Infrastructure;
10+
using Wox.Infrastructure.UserSettings;
1011

1112
namespace Wox.Plugin.Program.Logger
1213
{
@@ -21,7 +22,7 @@ internal static class ProgramLogger
2122

2223
static ProgramLogger()
2324
{
24-
var path = Path.Combine(Constant.DataDirectory, DirectoryName, Constant.Version);
25+
var path = Path.Combine(DataLocation.DataDirectory(), DirectoryName, Constant.Version);
2526
if (!Directory.Exists(path))
2627
{
2728
Directory.CreateDirectory(path);

Wox.Core/Configuration/IPortable.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+

2+
namespace Wox.Core.Configuration
3+
{
4+
public interface IPortable
5+
{
6+
void EnablePortableMode();
7+
void DisablePortableMode();
8+
void RemoveShortcuts();
9+
void RemoveUninstallerEntry();
10+
void CreateShortcuts();
11+
void CreateUninstallerEntry();
12+
void MoveUserDataFolder(string fromLocation, string toLocation);
13+
void VerifyUserDataAfterMove(string fromLocation, string toLocation);
14+
bool CanUpdatePortability();
15+
}
16+
}

Wox.Core/Configuration/Portable.cs

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
using Microsoft.Win32;
2+
using Squirrel;
3+
using System;
4+
using System.IO;
5+
using System.Reflection;
6+
using System.Windows;
7+
using Wox.Infrastructure;
8+
using Wox.Infrastructure.Logger;
9+
using Wox.Infrastructure.UserSettings;
10+
using Wox.Plugin.SharedCommands;
11+
12+
namespace Wox.Core.Configuration
13+
{
14+
public class Portable : IPortable
15+
{
16+
/// <summary>
17+
/// As at Squirrel.Windows version 1.5.2, UpdateManager needs to be disposed after finish
18+
/// </summary>
19+
/// <returns></returns>
20+
private UpdateManager NewUpdateManager()
21+
{
22+
return new UpdateManager(string.Empty, Constant.Wox, Constant.RootDirectory);
23+
}
24+
25+
public void DisablePortableMode()
26+
{
27+
try
28+
{
29+
MoveUserDataFolder(DataLocation.PortableDataPath, DataLocation.RoamingDataPath);
30+
#if DEBUG
31+
// Create shortcuts and uninstaller are not required in debug mode,
32+
// otherwise will repoint the path of the actual installed production version to the debug version
33+
#else
34+
CreateShortcuts();
35+
CreateUninstallerEntry();
36+
#endif
37+
IndicateDeletion(DataLocation.PortableDataPath);
38+
39+
MessageBox.Show("Wox needs to restart to finish disabling portable mode, " +
40+
"after the restart your portable data profile will be deleted and roaming data profile kept");
41+
42+
UpdateManager.RestartApp();
43+
}
44+
catch (Exception e)
45+
{
46+
#if !DEBUG
47+
Log.Exception("Portable", "Error occured while disabling portable mode", e);
48+
#endif
49+
throw;
50+
}
51+
}
52+
53+
public void EnablePortableMode()
54+
{
55+
try
56+
{
57+
MoveUserDataFolder(DataLocation.RoamingDataPath, DataLocation.PortableDataPath);
58+
#if DEBUG
59+
// Remove shortcuts and uninstaller are not required in debug mode,
60+
// otherwise will delete the actual installed production version
61+
#else
62+
RemoveShortcuts();
63+
RemoveUninstallerEntry();
64+
#endif
65+
IndicateDeletion(DataLocation.RoamingDataPath);
66+
67+
MessageBox.Show("Wox needs to restart to finish enabling portable mode, " +
68+
"after the restart your roaming data profile will be deleted and portable data profile kept");
69+
70+
UpdateManager.RestartApp();
71+
}
72+
catch (Exception e)
73+
{
74+
#if !DEBUG
75+
Log.Exception("Portable", "Error occured while enabling portable mode", e);
76+
#endif
77+
throw;
78+
}
79+
}
80+
81+
public void RemoveShortcuts()
82+
{
83+
using (var portabilityUpdater = NewUpdateManager())
84+
{
85+
var exeName = Constant.Wox + ".exe";
86+
portabilityUpdater.RemoveShortcutsForExecutable(exeName, ShortcutLocation.StartMenu);
87+
portabilityUpdater.RemoveShortcutsForExecutable(exeName, ShortcutLocation.Desktop);
88+
portabilityUpdater.RemoveShortcutsForExecutable(exeName, ShortcutLocation.Startup);
89+
}
90+
}
91+
92+
public void RemoveUninstallerEntry()
93+
{
94+
using (var portabilityUpdater = NewUpdateManager())
95+
{
96+
portabilityUpdater.RemoveUninstallerRegistryEntry();
97+
}
98+
}
99+
100+
public void MoveUserDataFolder(string fromLocation, string toLocation)
101+
{
102+
FilesFolders.Copy(fromLocation, toLocation);
103+
VerifyUserDataAfterMove(fromLocation, toLocation);
104+
}
105+
106+
public void VerifyUserDataAfterMove(string fromLocation, string toLocation)
107+
{
108+
FilesFolders.VerifyBothFolderFilesEqual(fromLocation, toLocation);
109+
}
110+
111+
public void CreateShortcuts()
112+
{
113+
using (var portabilityUpdater = NewUpdateManager())
114+
{
115+
var exeName = Constant.Wox + ".exe";
116+
portabilityUpdater.CreateShortcutsForExecutable(exeName, ShortcutLocation.StartMenu, false);
117+
portabilityUpdater.CreateShortcutsForExecutable(exeName, ShortcutLocation.Desktop, false);
118+
portabilityUpdater.CreateShortcutsForExecutable(exeName, ShortcutLocation.Startup, false);
119+
}
120+
}
121+
122+
public void CreateUninstallerEntry()
123+
{
124+
var uninstallRegSubKey = @"Software\Microsoft\Windows\CurrentVersion\Uninstall";
125+
// NB: Sometimes the Uninstall key doesn't exist
126+
using (var parentKey =
127+
RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Default)
128+
.CreateSubKey("Uninstall", RegistryKeyPermissionCheck.ReadWriteSubTree)) {; }
129+
130+
var key = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Default)
131+
.CreateSubKey(uninstallRegSubKey + "\\" + Constant.Wox, RegistryKeyPermissionCheck.ReadWriteSubTree);
132+
key.SetValue("DisplayIcon", Constant.ApplicationDirectory + "\\app.ico", RegistryValueKind.String);
133+
134+
using (var portabilityUpdater = NewUpdateManager())
135+
{
136+
portabilityUpdater.CreateUninstallerRegistryEntry();
137+
}
138+
}
139+
140+
internal void IndicateDeletion(string filePathTodelete)
141+
{
142+
using (StreamWriter sw = File.CreateText(filePathTodelete + "\\" + DataLocation.DeletionIndicatorFile)){}
143+
}
144+
145+
///<summary>
146+
///This method should be run at first before all methods during start up and should be run before determining which data location
147+
///will be used for Wox.
148+
///</summary>
149+
public void PreStartCleanUpAfterPortabilityUpdate()
150+
{
151+
// Specify here so this method does not rely on other environment variables to initialise
152+
var portableDataPath = Path.Combine(Directory.GetParent(Assembly.GetExecutingAssembly().Location.NonNull()).ToString(), "UserData");
153+
var roamingDataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Wox");
154+
155+
bool DataLocationPortableDeleteRequired = false;
156+
bool DataLocationRoamingDeleteRequired = false;
157+
158+
if ((roamingDataPath + "\\" + DataLocation.DeletionIndicatorFile).FileExits())
159+
DataLocationRoamingDeleteRequired = true;
160+
161+
if ((portableDataPath + "\\" + DataLocation.DeletionIndicatorFile).FileExits())
162+
DataLocationPortableDeleteRequired = true;
163+
164+
if (DataLocationRoamingDeleteRequired)
165+
{
166+
if(roamingDataPath.LocationExists())
167+
MessageBox.Show("Wox detected you restarted after enabling portable mode, " +
168+
"your roaming data profile will now be deleted");
169+
170+
FilesFolders.RemoveFolderIfExists(roamingDataPath);
171+
172+
return;
173+
}
174+
175+
if(DataLocationPortableDeleteRequired)
176+
{
177+
MessageBox.Show("Wox detected you restarted after disabling portable mode, " +
178+
"your portable data profile will now be deleted");
179+
180+
FilesFolders.RemoveFolderIfExists(portableDataPath);
181+
182+
return;
183+
}
184+
}
185+
186+
public bool CanUpdatePortability()
187+
{
188+
var roamingLocationExists = DataLocation.RoamingDataPath.LocationExists();
189+
var portableLocationExists = DataLocation.PortableDataPath.LocationExists();
190+
191+
if(roamingLocationExists && portableLocationExists)
192+
{
193+
MessageBox.Show(string.Format("Wox detected your user data exists both in {0} and " +
194+
"{1}. {2}{2}Please delete {1} in order to proceed. No changes have occured.",
195+
DataLocation.PortableDataPath, DataLocation.RoamingDataPath, Environment.NewLine));
196+
197+
return false;
198+
}
199+
200+
return true;
201+
}
202+
}
203+
}

Wox.Core/Plugin/PluginInstaller.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ internal static void Install(string path)
3434
return;
3535
}
3636

37-
string pluginFolerPath = Infrastructure.Constant.PluginsDirectory;
37+
string pluginFolerPath = Infrastructure.UserSettings.DataLocation.PluginsDirectory;
3838

3939
string newPluginName = plugin.Name
4040
.Replace("/", "_")

Wox.Core/Plugin/PluginManager.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,20 +32,20 @@ public static class PluginManager
3232
// todo happlebao, this should not be public, the indicator function should be embeded
3333
public static PluginsSettings Settings;
3434
private static List<PluginMetadata> _metadatas;
35-
private static readonly string[] Directories = { Constant.PreinstalledDirectory, Constant.PluginsDirectory };
35+
private static readonly string[] Directories = { Constant.PreinstalledDirectory, DataLocation.PluginsDirectory };
3636

3737
private static void ValidateUserDirectory()
3838
{
39-
if (!Directory.Exists(Constant.PluginsDirectory))
39+
if (!Directory.Exists(DataLocation.PluginsDirectory))
4040
{
41-
Directory.CreateDirectory(Constant.PluginsDirectory);
41+
Directory.CreateDirectory(DataLocation.PluginsDirectory);
4242
}
4343
}
4444

4545
private static void DeletePythonBinding()
4646
{
4747
const string binding = "wox.py";
48-
var directory = Constant.PluginsDirectory;
48+
var directory = DataLocation.PluginsDirectory;
4949
foreach (var subDirectory in Directory.GetDirectories(directory))
5050
{
5151
var path = Path.Combine(subDirectory, binding);

Wox.Core/Resource/Theme.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public class Theme
2323
private const string Folder = "Themes";
2424
private const string Extension = ".xaml";
2525
private string DirectoryPath => Path.Combine(Constant.ProgramDirectory, Folder);
26-
private string UserDirectoryPath => Path.Combine(Constant.DataDirectory, Folder);
26+
private string UserDirectoryPath => Path.Combine(DataLocation.DataDirectory(), Folder);
2727

2828
public Theme()
2929
{

Wox.Core/Updater.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
using Wox.Infrastructure.Http;
1616
using Wox.Infrastructure.Logger;
1717
using System.IO;
18+
using Wox.Infrastructure.UserSettings;
1819

1920
namespace Wox.Core
2021
{
@@ -80,13 +81,13 @@ public async Task UpdateApp(bool silentIfLatestVersion = true)
8081

8182
await updateManager.ApplyReleases(newUpdateInfo);
8283

83-
if (Constant.IsPortableMode)
84+
if (DataLocation.PortableDataLocationInUse())
8485
{
85-
var targetDestination = updateManager.RootAppDirectory + $"\\app-{newReleaseVersion.ToString()}\\{Constant.PortableFolderName}";
86-
FilesFolders.Copy(Constant.PortableDataPath, targetDestination);
87-
if (!FilesFolders.VerifyBothFolderFilesEqual(Constant.PortableDataPath, targetDestination))
86+
var targetDestination = updateManager.RootAppDirectory + $"\\app-{newReleaseVersion.ToString()}\\{DataLocation.PortableFolderName}";
87+
FilesFolders.Copy(DataLocation.PortableDataPath, targetDestination);
88+
if (!FilesFolders.VerifyBothFolderFilesEqual(DataLocation.PortableDataPath, targetDestination))
8889
MessageBox.Show(string.Format("Wox was not able to move your user profile data to the new update version. Please manually" +
89-
"move your profile data folder from {0} to {1}", Constant.PortableDataPath, targetDestination));
90+
"move your profile data folder from {0} to {1}", DataLocation.PortableDataPath, targetDestination));
9091
}
9192
else
9293
{

Wox.Core/Wox.Core.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@
5151
<Compile Include="..\SolutionAssemblyInfo.cs">
5252
<Link>Properties\SolutionAssemblyInfo.cs</Link>
5353
</Compile>
54+
<Compile Include="Configuration\IPortable.cs" />
55+
<Compile Include="Configuration\Portable.cs" />
5456
<Compile Include="Plugin\ExecutablePlugin.cs" />
5557
<Compile Include="Plugin\PluginsLoader.cs" />
5658
<Compile Include="Resource\LocalizationConverter.cs" />

Wox.Infrastructure/Wox.cs renamed to Wox.Infrastructure/Constant.cs

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
using System;
21
using System.Diagnostics;
32
using System.IO;
43
using System.Reflection;
@@ -13,25 +12,9 @@ public static class Constant
1312
private static readonly Assembly Assembly = Assembly.GetExecutingAssembly();
1413
public static readonly string ProgramDirectory = Directory.GetParent(Assembly.Location.NonNull()).ToString();
1514
public static readonly string ExecutablePath = Path.Combine(ProgramDirectory, Wox + ".exe");
16-
17-
public static bool IsPortableMode;
18-
public const string PortableFolderName = "UserData";
19-
public static string PortableDataPath = Path.Combine(ProgramDirectory, PortableFolderName);
20-
public static string DetermineDataDirectory()
21-
{
22-
if (Directory.Exists(PortableDataPath))
23-
{
24-
IsPortableMode = true;
25-
return PortableDataPath;
26-
}
27-
else
28-
{
29-
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), Wox);
30-
}
31-
}
32-
33-
public static readonly string DataDirectory = DetermineDataDirectory();
34-
public static readonly string PluginsDirectory = Path.Combine(DataDirectory, Plugins);
15+
public static readonly string ApplicationDirectory = Directory.GetParent(ProgramDirectory).ToString();
16+
public static readonly string RootDirectory = Directory.GetParent(ApplicationDirectory).ToString();
17+
3518
public static readonly string PreinstalledDirectory = Path.Combine(ProgramDirectory, Plugins);
3619
public const string Issue = "https://github.com/jjw24/Wox/issues/new";
3720
public static readonly string Version = FileVersionInfo.GetVersionInfo(Assembly.Location.NonNull()).ProductVersion;

Wox.Infrastructure/Logger/Log.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using NLog;
55
using NLog.Config;
66
using NLog.Targets;
7+
using Wox.Infrastructure.UserSettings;
78

89
namespace Wox.Infrastructure.Logger
910
{
@@ -15,7 +16,7 @@ public static class Log
1516

1617
static Log()
1718
{
18-
CurrentLogDirectory = Path.Combine(Constant.DataDirectory, DirectoryName, Constant.Version);
19+
CurrentLogDirectory = Path.Combine(DataLocation.DataDirectory(), DirectoryName, Constant.Version);
1920
if (!Directory.Exists(CurrentLogDirectory))
2021
{
2122
Directory.CreateDirectory(CurrentLogDirectory);

0 commit comments

Comments
 (0)