/// ------------------------------------------------------------------------------------ /// <summary> /// Initializes a new instance of the <see cref="RestoreProjectSettings"/> class from /// a list of command-line options as created from the <see cref="CommandLineOptions"/> /// property. /// </summary> /// <param name="projectsRootFolder"></param> /// <param name="projectName">Name of the project.</param> /// <param name="backupZipFileName">Name of the backup zip file.</param> /// <param name="commandLineOptions">The command line options.</param> /// ------------------------------------------------------------------------------------ public RestoreProjectSettings(string projectsRootFolder, string projectName, string backupZipFileName, string commandLineOptions) : this(projectsRootFolder) { if (string.IsNullOrEmpty(projectName)) { throw new ArgumentNullException("projectName"); } if (string.IsNullOrEmpty(backupZipFileName)) { throw new ArgumentNullException("backupZipFileName"); } if (commandLineOptions == null) { throw new ArgumentNullException("commandLineOptions"); } ProjectName = projectName; Backup = new BackupFileSettings(backupZipFileName, false); commandLineOptions = commandLineOptions.ToLowerInvariant(); IncludeConfigurationSettings = (commandLineOptions.IndexOf('c') >= 0); IncludeSupportingFiles = (commandLineOptions.IndexOf('f') >= 0); IncludeLinkedFiles = (commandLineOptions.IndexOf('l') >= 0); IncludeSpellCheckAdditions = (commandLineOptions.IndexOf('s') >= 0); }
private void ImportFrom6_0Backup(BackupFileSettings fileSettings, IThreadedProgress progressDlg) { var importer = new ImportFrom6_0(progressDlg, m_converterConsolePath, m_dbPath); bool importSuccessful; try { string projFile; importSuccessful = importer.Import(fileSettings.File, m_restoreSettings.ProjectName, m_restoreSettings.ProjectsRootFolder, out projFile); } catch (CannotConvertException) { FailedImportCleanUp(importer); throw; } if (!importSuccessful) { FailedImportCleanUp(importer); if (!importer.HaveOldFieldWorks || !importer.HaveFwSqlServer) { throw new MissingOldFwException("Error restoring from FieldWorks 6.0 (or earlier) backup", importer.HaveFwSqlServer, importer.HaveOldFieldWorks); } throw new FailedFwRestoreException("Error restoring from FieldWorks 6.0 (or earlier) backup"); } }
/// ------------------------------------------------------------------------------------ /// <summary> /// Determines whether the specified backup is valid. /// </summary> /// <param name="backup">The backup settings.</param> /// ------------------------------------------------------------------------------------ private static bool IsBackupValid(BackupFileSettings backup) { try { backup.Validate(); return(true); } catch // Any errors during validate should be treated as not being valid { return(false); } }
/// ------------------------------------------------------------------------------------ /// <summary> /// Gets a BackupFileSettings object representing the requested backup file for the /// given project. /// </summary> /// <param name="sProjectName">Name of the project.</param> /// <param name="version">The requested version.</param> /// <param name="checkValidity">if set to <c>true</c> check validity.</param> /// <returns>The BackupFileSettings object or <c>null</c> if the requested backup file /// was found to be invalid</returns> /// <exception cref="KeyNotFoundException">sProjectName is not one of the available /// projects (as returned by AvailableProjectNames) or requested version does not /// correspond to one of the avilable versions (as returned by GetAvailableVersions) /// </exception> /// ------------------------------------------------------------------------------------ public BackupFileSettings GetBackupFile(string sProjectName, DateTime version, bool checkValidity) { BackupFileSettings settings = m_availableBackups[sProjectName][version]; if (checkValidity && !IsBackupValid(settings)) { m_availableBackups[sProjectName].Remove(version); return(null); } return(settings); }
/// <summary> /// Completes initialization after deserializing the backup settings xml /// </summary> private void CompleteInitialization(BackupFileSettings settings) { m_backupTime = settings.BackupTime; m_comment = settings.Comment; m_projectName = settings.ProjectName; m_linkedFilesPathRelative = LinkedFilesRelativePathHelper.FixPathSlashesIfNeeded(settings.LinkedFilesPathRelativePersisted); m_linkedFilesPathActual = LinkedFilesRelativePathHelper.FixPathSlashesIfNeeded(settings.LinkedFilesPathActualPersisted); m_projectPathPersisted = LinkedFilesRelativePathHelper.FixPathSlashesIfNeeded(settings.ProjectPathPersisted); m_configurationSettings = settings.IncludeConfigurationSettings; m_linkedFiles = settings.IncludeLinkedFiles; m_supportingFiles = settings.IncludeSupportingFiles; m_spellCheckAdditions = settings.IncludeSpellCheckAdditions; m_dbVersion = settings.DbVersion; m_fwVersion = settings.FwVersion; }
/// <summary> /// Reads in the backup settings from a given archive entry, usually from a fwbackup archive. /// This includes a replacement operation on the xml namespace attribute to the expected namespace. /// </summary> /// <param name="zipEntry">The entry for the zip fwbackup folder.</param> /// <exception cref="InvalidOperationException">An error occurred during deserialization. /// </exception> private void InitializeFromZipEntry(ZipEntry zipEntry) { using (FileStream fs = System.IO.File.OpenRead(m_sZipFileName)) { ZipFile zf = new ZipFile(fs); Stream zipStream = zf.GetInputStream(zipEntry); XDocument xDoc = XDocument.Load(zipStream); string backupXml = xDoc.ToString(); string xmlNamespace = @"\s+xmlns="".+\.BackupRestore"""; string expectedNamespace = @" xmlns=""http://schemas.datacontract.org/2004/07/SIL.LCModel.DomainServices.BackupRestore"""; backupXml = Regex.Replace(backupXml, xmlNamespace, expectedNamespace); BackupFileSettings settings = CreateFromXml(backupXml); CompleteInitialization(settings); } }
/// ------------------------------------------------------------------------------------ /// <summary> /// Persists the dialog settings as an XML file. /// </summary> /// ------------------------------------------------------------------------------------ private void PersistBackupFileSettings() { string backupSettingsFile = Path.Combine(LcmFileHelper.GetBackupSettingsDir( m_settings.ProjectPath), LcmFileHelper.ksBackupSettingsFilename); string settingsDir = Path.GetDirectoryName(backupSettingsFile); if (!Directory.Exists(settingsDir)) { Directory.CreateDirectory(settingsDir); } using (FileStream fs = new FileStream(backupSettingsFile, FileMode.Create)) { BackupFileSettings.SaveToStream(m_settings, fs); } }
/// ------------------------------------------------------------------------------------ /// <summary> /// Perform a restore of the project specified in the settings. /// </summary> /// <param name="progressDlg">The progress dialog.</param> /// <exception cref="IOException">File does not exist, or some such problem</exception> /// <exception cref="InvalidBackupFileException">XML deserialization problem or required /// files not found in zip file</exception> /// ------------------------------------------------------------------------------------ public void RestoreProject(IThreadedProgress progressDlg) { BackupFileSettings fileSettings = m_restoreSettings.Backup; fileSettings.Validate(); // Normally, this will already have been done, so this will do nothing. //First of all, if the project exists and we are overwriting it, then make a copy of the project. That way //if the restoration fails part way through, we can put it back the way it was. if (Directory.Exists(m_restoreSettings.ProjectPath)) { // If the project already exists using the fwdata extension, either we're not sharing, // or it is a project for which sharing is suppressed. In any case we don't want to // convert the new project. CreateACopyOfTheProject(); } //When restoring a project, ensure all the normal folders are there even if some //of those folders had nothing from them in the backup. Directory.CreateDirectory(m_restoreSettings.ProjectPath); LcmCache.CreateProjectSubfolders(m_restoreSettings.ProjectPath); try { //Import from FW version 6.0 based on the file extension. var extension = Path.GetExtension(fileSettings.File).ToLowerInvariant(); if (extension == LcmFileHelper.ksFw60BackupFileExtension || extension == ".xml") { ImportFrom6_0Backup(fileSettings, progressDlg); } else //Restore from FW version 7.0 and newer backup. { RestoreFrom7_0AndNewerBackup(fileSettings); } } catch (Exception error) { if (error is IOException || error is InvalidBackupFileException || error is UnauthorizedAccessException) { CleanupAfterRestore(false); } throw; } CleanupAfterRestore(true); }
private void RestoreFrom7_0AndNewerBackup(BackupFileSettings fileSettings) { // Get rid of any saved settings, since they may not be consistent with something about the data // or settings we are restoring. (This extension is also known to RecordView.GetClerkPersistPathname()). var tempDirectory = Path.Combine(m_restoreSettings.ProjectPath, LcmFileHelper.ksSortSequenceTempDir); if (Directory.Exists(tempDirectory)) { foreach (var sortSeqFile in Directory.GetFiles(tempDirectory, "*.fwss")) { File.Delete(sortSeqFile); } } UncompressDataFiles(); // We can't use Path.Combine here, because the zip files stores all file paths with '/'s UncompressFilesMatchingPath(LcmFileHelper.ksWritingSystemsDir + "/", m_restoreSettings.WritingSystemStorePath); UncompressFilesMatchingPath(LexiconSettingsFileHelper.SharedSettingsFolder + "/", m_restoreSettings.SharedSettingsPath); if (m_restoreSettings.IncludeSupportingFiles) { Debug.Assert(fileSettings.IncludeSupportingFiles, "The option to include supporting files should not be allowed if they aren't available in the backup settings"); var zipEntryStartsWith = LcmFileHelper.ksSupportingFilesDir; UncompressFilesContainedInFolderandSubFolders(LcmFileHelper.GetZipfileFormattedPath(zipEntryStartsWith), m_restoreSettings.ProjectSupportingFilesPath); } if (m_restoreSettings.IncludeConfigurationSettings) { UncompressFilesMatchingPath(LcmFileHelper.ksConfigurationSettingsDir + "/", m_restoreSettings.FlexConfigurationSettingsPath); } if (m_restoreSettings.IncludeLinkedFiles) { RestoreLinkedFiles(fileSettings); } if (m_restoreSettings.IncludeSpellCheckAdditions) { UncompressFilesMatchingPath(BackupSettings.ksSpellingDictionariesDir + "/", m_restoreSettings.SpellingDictionariesPath); CopySpellingOverrideFilesFromBackupToLocal(); } }
private void RestoreLinkedFiles(BackupFileSettings fileSettings) { Debug.Assert(fileSettings.LinkedFilesAvailable, "The option to include linked files should not be allowed if they aren't available in the backup settings"); var proposedDestinationLinkedFilesPath = LinkedFilesRelativePathHelper.GetLinkedFilesFullPathFromRelativePath(m_restoreSettings.ProjectsRootFolder, fileSettings.LinkedFilesPathRelativePersisted, m_restoreSettings.ProjectPath); var linkedFilesPathInZip = fileSettings.LinkedFilesPathActualPersisted; if (fileSettings.LinkedFilesPathRelativePersisted.StartsWith(LinkedFilesRelativePathHelper.ksProjectRelPath)) { // We store any files inside the project folder as a relative path from the project's directory. // Make sure we don't attempt to search for the whole directory structure in the zip file. (FWR-2909) linkedFilesPathInZip = fileSettings.LinkedFilesPathRelativePersisted.Substring( LinkedFilesRelativePathHelper.ksProjectRelPath.Length + 1); } var filesContainedInLinkdFilesFolder = GetAllFilesUnderFolderInZipFileAndDateTimes(linkedFilesPathInZip); //If the proposed location is not in the default location under the project, then ask the user if they want //to restore the files to the default location instead. Otherwise just go ahead and restore the files. var defaultLinkedFilesPath = LcmFileHelper.GetDefaultLinkedFilesDir(m_restoreSettings.ProjectPath); if (proposedDestinationLinkedFilesPath.Equals(defaultLinkedFilesPath)) { if (!Directory.Exists(defaultLinkedFilesPath)) { Directory.CreateDirectory(proposedDestinationLinkedFilesPath); } ExternalLinksDirectoryExits(linkedFilesPathInZip, proposedDestinationLinkedFilesPath, filesContainedInLinkdFilesFolder); } else { //LinkedFiles folder does not exist which means it was not in the default location when the backup was made. //Therefore, ask the user if we can restore these files to the default location in the project's folder. RestoreLinkedFiles(CanRestoreLinkedFilesToProjectsFolder(), filesContainedInLinkdFilesFolder, linkedFilesPathInZip, proposedDestinationLinkedFilesPath); } }
/// ------------------------------------------------------------------------------------ /// <summary> /// Reads in backup settings from the given stream, which will normally be a file, /// but for testing we can use a memory stream. /// </summary> /// <param name="persistenceStream">The persistence stream.</param> /// <exception cref="InvalidOperationException">An error occurred during deserialization. /// </exception> /// <exception cref="SerializationException">Deserialization issue, likely from a mismatching namespace. /// </exception> /// ------------------------------------------------------------------------------------ private void InitializeFromStream(Stream persistenceStream) { BackupFileSettings settings = CreateFromStream(persistenceStream); CompleteInitialization(settings); }
/// ------------------------------------------------------------------------------------ /// <summary> /// The constructor initializes the dictionary for the default backup directory. /// ENHANCE: If we want this class to be able to be used for any arbitrary directory, /// we'll need to pass in the directory name or have a way to change it. /// </summary> /// ------------------------------------------------------------------------------------ public BackupFileRepository(string defaultBackupDir) { string[] backups; try { backups = FileUtils.GetFilesInDirectory(defaultBackupDir); } catch (Exception) { return; } Regex regex = new Regex(@" \d\d\d\d-\d\d?-\d\d(-| )\d\d\d\d"); foreach (string backup in backups) { string ext = Path.GetExtension(backup); if (ext != LcmFileHelper.ksFwBackupFileExtension && ext != LcmFileHelper.ksFw60BackupFileExtension) { continue; } string filename = Path.GetFileNameWithoutExtension(backup); MatchCollection matches = regex.Matches(filename); Debug.Assert(matches.Count <= 1, "Maybe there was a date in the comment or (perish the thought) in the project name."); if (matches.Count >= 1) { Match match = matches[0]; string projectName = filename.Substring(0, match.Index); StringBuilder date = new StringBuilder(match.Value); date.Replace("-", CultureInfo.InvariantCulture.DateTimeFormat.DateSeparator); // These next three lines are fairly ugly, but we need them to account for backups that have // a dash between the date and the time. int ichShouldBeASpace = BackupSettings.ksBackupDateFormat.Length - BackupSettings.ksBackupDateFormat.LastIndexOf(' '); Debug.Assert(ichShouldBeASpace == 5, "Rather than hard-coding a 5 here, we try to calculate this from the constant, but if this is ever not 5, someone should make sure this logic is still correct."); date[date.Length - ichShouldBeASpace] = ' '; DateTime dateOfBackup; if (DateTime.TryParseExact(date.ToString(), s_dateFormatForParsing, CultureInfo.InvariantCulture, DateTimeStyles.AllowWhiteSpaces, out dateOfBackup)) { SortedDictionary <DateTime, BackupFileSettings> versions = GetOrCreateProjectVersions(projectName); string comment; if (ext == LcmFileHelper.ksFw60BackupFileExtension) { comment = Properties.Resources.kstidFw60OrEarlierBackupComment; } else { int ichStartOfComment = match.Index + match.Length + 1; comment = (ichStartOfComment < filename.Length) ? filename.Substring(ichStartOfComment) : string.Empty; } versions[dateOfBackup] = new BackupFileSettings(backup, dateOfBackup, comment); continue; } } // Try to read the contents of the zip file to see if it really is a valid FW // zip file whose filename just got mangled. BackupFileSettings settings = new BackupFileSettings(backup, false); if (IsBackupValid(settings)) { SortedDictionary <DateTime, BackupFileSettings> versions = GetOrCreateProjectVersions(settings.ProjectName); versions[settings.BackupTime] = settings; } } }