public void Restore(BitnamiRedmineStack stack, DatabaseConfiguration configuration, string path) { if (configuration == null) { throw new ArgumentNullException(nameof(configuration)); } try { if (!File.Exists(path)) { throw new FileNotFoundException("インポートする sql ファイルが存在しません。", path); } var connectionString = CreateConnectionString(configuration); this._LogService.Info("Create MySqlConnection"); using (var con = new MySqlConnection(connectionString)) { var text = File.ReadAllText(path); var script = new MySqlScript(con, text); this._LogService.Info("Execute MySqlScript"); var result = script.Execute(); this._LogService.Info($"MySqlScript,Execute returns {result}"); } } catch (Exception e) { this._LogService.Error(e.Message); throw; } }
public IEnumerable <BitnamiRedmineStack> GetBitnamiRedmineStacks() { var stacks = new List <BitnamiRedmineStack>(); try { var registryKeys = new[] { @"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall", @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" }; foreach (var registryKey in registryKeys) { using (var key = Registry.LocalMachine.OpenSubKey(registryKey)) { if (key == null) { continue; } foreach (var subkeyName in key.GetSubKeyNames()) { using (var subkey = key.OpenSubKey(subkeyName)) { var value = subkey?.GetValue("DisplayName") as string; if (value == null) { continue; } if (!value.Equals("Bitnami Redmine Stack", StringComparison.InvariantCultureIgnoreCase)) { continue; } var installLocation = subkey.GetValue("InstallLocation") as string; // Include '"' from 4.0.0 installLocation = installLocation?.Trim('"'); var displayVersion = subkey.GetValue("DisplayVersion") as string; var stack = new BitnamiRedmineStack(installLocation, displayVersion); stacks.Add(stack); } } } } } catch (Exception e) { this._LogService.Error(e.Message); throw; } return(stacks); }
public IEnumerable <ServiceStatus> GetServiceDisplayNames(BitnamiRedmineStack stack, ServiceConfiguration configuration) { var statusList = new List <ServiceStatus>(); try { var services = new[] { new { Path = Path.Combine(stack.InstallLocation, ApachePath), Condition = configuration.Apache }, new { Path = Path.Combine(stack.InstallLocation, MySqlPath), Condition = configuration.MySql }, new { Path = Path.Combine(stack.InstallLocation, RedminePath), Condition = configuration.Redmine }, new { Path = Path.Combine(stack.InstallLocation, SubversionPath), Condition = configuration.Subversion } }; const string registryKey = @"SYSTEM\CurrentControlSet\services"; using (var key = Registry.LocalMachine.OpenSubKey(registryKey)) { if (key == null) { throw new KeyNotFoundException($"サブキー 'HKEY_LOCAL_MACHINE\\{registryKey}' が存在しません。"); } var subKeyNames = key.GetSubKeyNames(); foreach (var subkeyName in subKeyNames) { using (var subkey = key.OpenSubKey(subkeyName)) { var imagePath = subkey?.GetValue("ImagePath") as string; if (string.IsNullOrWhiteSpace(imagePath)) { continue; } var displayName = subkey.GetValue("DisplayName") as string; if (string.IsNullOrWhiteSpace(displayName)) { continue; } // 時々、8.3 形式の短いパスがある // さらに、引数を含むパスがいるため、分解してから長い形式のパスに変換する // が、長い形式のパスを System.IO.Path.GetFullPath で // 変関すると例外を投げるので、Win32 API の GetLongPathName を使う try { var splitArgs = InteropHelper.SplitArgs(imagePath); if (splitArgs == null || splitArgs.Length == 0) { continue; } imagePath = InteropHelper.GetLongPathName(splitArgs[0]); } catch { } if (imagePath == null) { continue; } foreach (var service in services) { if (!service.Condition) { continue; } if (imagePath.Contains(service.Path)) { var startupType = GetStartupType(subkey); var status = new ServiceStatus(this, subkeyName, startupType); statusList.Add(status); } } } } } } catch (Exception e) { this._LogService.Error(e.Message); throw; } return(statusList); }
public void Restore(BitnamiRedmineStack stack, BackupConfiguration configuration, string path, IProgress <ProgressReportsModel> progress = null) { if (!Directory.Exists(path)) { throw new DirectoryNotFoundException($"{path} は存在しません。"); } var databaseName = Resources.Word_Database; var pluginName = Resources.Word_Plugin; var themeName = Resources.Word_Theme; var attachedFileName = Resources.Word_AttachedFile; var report = new ProgressReportsModel(this._DispatcherService, new[] { new ProgressItemModel { Key = databaseName, Progress = ProgressState.NotStart }, new ProgressItemModel { Key = pluginName, Progress = ProgressState.NotStart }, new ProgressItemModel { Key = themeName, Progress = ProgressState.NotStart }, new ProgressItemModel { Key = attachedFileName, Progress = ProgressState.NotStart }, }); // データベースの復元 if (configuration.Database) { report.UpdateProgress(databaseName, ProgressState.InProgress); progress?.Report(report); var databaseConfigurations = this._DatabaseConfigurationService.GetDatabaseConfiguration(stack).ToArray(); foreach (var databaseConfiguration in databaseConfigurations) { var sqlFileName = $"{databaseConfiguration.Mode}.sql"; var sqlFilePath = Path.Combine(path, sqlFileName); if (!File.Exists(sqlFilePath)) { continue; } this._DatabaseService.Restore(stack, databaseConfiguration, sqlFilePath); } report.UpdateProgress(databaseName, ProgressState.Complete); progress?.Report(report); report.AddErrorMessage(databaseName, Resources.Msg_RestoreComplete); } else { report.UpdateProgress(databaseName, ProgressState.NotRequire); report.AddErrorMessage(databaseName, Resources.Msg_RestoreSkip); this._LogService.Info("Database is skipped"); } // プラグイン、テーマ、添付ファイルの復元 var rules = new[] { new { Condition = configuration.Plugins, Target = BackupConfiguration.PluginsPath, Source = PluginsDirectoryName, CheckAction = new Action <ProgressState>(state => { report.UpdateProgress(pluginName, state); progress?.Report(report); switch (state) { case ProgressState.Complete: report.AddErrorMessage(databaseName, Resources.Msg_RestoreComplete); break; case ProgressState.NotRequire: report.AddErrorMessage(databaseName, Resources.Msg_RestoreSkip); break; case ProgressState.Failed: report.AddErrorMessage(databaseName, Resources.Msg_RestoreFailed); break; } }) }, new { Condition = configuration.Themes, Target = BackupConfiguration.ThemesePath, Source = ThemeseDirectoryName, CheckAction = new Action <ProgressState>(state => { report.UpdateProgress(themeName, state); progress?.Report(report); switch (state) { case ProgressState.Complete: report.AddErrorMessage(databaseName, Resources.Msg_RestoreComplete); break; case ProgressState.NotRequire: report.AddErrorMessage(databaseName, Resources.Msg_RestoreSkip); break; case ProgressState.Failed: report.AddErrorMessage(databaseName, Resources.Msg_RestoreFailed); break; } }) }, new { Condition = configuration.Files, Target = BackupConfiguration.FilesPath, Source = FilesDirectoryName, CheckAction = new Action <ProgressState>(state => { report.UpdateProgress(attachedFileName, state); progress?.Report(report); switch (state) { case ProgressState.Complete: report.AddErrorMessage(databaseName, Resources.Msg_RestoreComplete); break; case ProgressState.NotRequire: report.AddErrorMessage(databaseName, Resources.Msg_RestoreSkip); break; case ProgressState.Failed: report.AddErrorMessage(databaseName, Resources.Msg_RestoreFailed); break; } }) } }; foreach (var rule in rules) { if (!rule.Condition) { rule.CheckAction(ProgressState.NotRequire); continue; } var sourceDir = Path.Combine(path, rule.Source); var targetDir = Path.Combine(stack.InstallLocation, rule.Target); var condition = Directory.Exists(sourceDir); if (!condition) { rule.CheckAction(ProgressState.Failed); continue; } rule.CheckAction(ProgressState.InProgress); this.CopyDirectory(sourceDir, targetDir); rule.CheckAction(ProgressState.Complete); } }
public BackupConfiguration CheckRestoreFolder(BitnamiRedmineStack stack, string path) { var configuration = new BackupConfiguration(); // データベース var databaseConfigurations = this._DatabaseConfigurationService.GetDatabaseConfiguration(stack).ToArray(); foreach (var databaseConfiguration in databaseConfigurations) { var sqlFileName = string.Format("{0}.sql", databaseConfiguration.Mode); var sqlFilePath = Path.Combine(path, sqlFileName); if (!File.Exists(sqlFilePath)) { continue; } configuration.Database = true; break; } // プラグイン、テーマ、添付ファイル var rules = new[] { new { Target = BackupConfiguration.PluginsPath, Source = PluginsDirectoryName, CheckAction = new Action(() => { configuration.Plugins = true; }) }, new { Target = BackupConfiguration.ThemesePath, Source = ThemeseDirectoryName, CheckAction = new Action(() => { configuration.Themes = true; }) }, new { Target = BackupConfiguration.FilesPath, Source = FilesDirectoryName, CheckAction = new Action(() => { configuration.Files = true; }) } }; foreach (var rule in rules) { var sourceDir = Path.Combine(path, rule.Source); var condition = Directory.Exists(sourceDir); if (!condition) { continue; } rule.CheckAction(); } return(configuration); }
public void Backup(BitnamiRedmineStack stack, DatabaseConfiguration configuration, string path) { if (configuration == null) { throw new ArgumentNullException(nameof(configuration)); } try { var apppath = CreateMySqlDumpLocation(stack); if (!File.Exists(apppath)) { throw new FileNotFoundException("mysqldump.exe が存在しません。", apppath); } // サポートしている文字コードは // mysql> show character set; を実行 Encoding encoding; switch (configuration.Encoding) { case "utf8": encoding = Encoding.UTF8; break; default: throw new NotSupportedException($"{configuration.Encoding} はサポートしていません。"); } const string format = "--default-character-set={0} --user={1} --password={2} --port={3} --databases {4}"; var arguments = string.Format( format, configuration.Encoding, configuration.Username, configuration.Password, configuration.Port, configuration.Name); var psInfo = new ProcessStartInfo(); psInfo.FileName = apppath; psInfo.Arguments = arguments; psInfo.CreateNoWindow = true; psInfo.UseShellExecute = false; psInfo.RedirectStandardOutput = true; psInfo.StandardOutputEncoding = encoding; this._LogService.Info("Create mysqldump.exe process"); using (var process = Process.Start(psInfo)) { var contents = process.StandardOutput.ReadToEnd(); this._LogService.Info("Start mysqldump.exe"); process.WaitForExit(); this._LogService.Info("End mysqldump.exe"); File.WriteAllText(path, contents, encoding); } } catch (Exception e) { this._LogService.Error(e.Message); throw; } }
private static string CreateMySqlLocation(BitnamiRedmineStack stack) { return(Path.Combine(stack.InstallLocation, MySqlPath)); }
public IEnumerable <DatabaseConfiguration> GetDatabaseConfiguration(BitnamiRedmineStack info) { if (info == null) { throw new ArgumentNullException(nameof(info)); } try { const string databaseYmlPath = @"apps\redmine\htdocs\config\database.yml"; var path = Path.Combine(info.InstallLocation, databaseYmlPath); if (!File.Exists(path)) { throw new FileNotFoundException("database.yml が存在しません。", path); } object[] deserialized; var serializer = new YamlSerializer(); using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) { deserialized = serializer.Deserialize(fs); } var configurations = new List <DatabaseConfiguration>(); foreach (var obj in deserialized) { var dictionary = obj as Dictionary <object, object>; if (dictionary == null) { continue; } // ポート番号は 1 つしか存在しない var port = 0; foreach (var values in (from kvp in dictionary let mode = kvp.Key as string where mode != null select kvp.Value).OfType <Dictionary <object, object> >().Where(values => values.ContainsKey("port"))) { port = (int)values["port"]; } configurations.AddRange(from kvp in dictionary let mode = kvp.Key as string where mode != null let values = kvp.Value as Dictionary <object, object> where values != null let database = values["database"] as string let username = values["username"] as string let password = values["password"] as string let encoding = values["encoding"] as string let host = values["host"] as string select new DatabaseConfiguration(mode, database, host, username, password, encoding, port)); } return(configurations); } catch (Exception e) { this._LogService.Error(e.Message); throw; } }