private static TestFolderTeamCollection MakeAndRenameBook(TemporaryFolder collectionFolder, TemporaryFolder repoFolder, out string bookPath, out string newBookFolderPath) { var mockTcManager = new Mock <ITeamCollectionManager>(); var tc = new TestFolderTeamCollection(mockTcManager.Object, collectionFolder.FolderPath, repoFolder.FolderPath); var bookFolderPath = Path.Combine(collectionFolder.FolderPath, "My book"); Directory.CreateDirectory(bookFolderPath); bookPath = Path.Combine(bookFolderPath, "My book.htm"); RobustFile.WriteAllText(bookPath, "This is just a dummy"); tc.PutBook(bookFolderPath); tc.AttemptLock("My book", "*****@*****.**"); RobustFile.WriteAllText(bookPath, "This is the edited content"); var newBookPath = Path.Combine(bookFolderPath, "Renamed book"); RobustFile.Move(bookPath, newBookPath); newBookFolderPath = Path.Combine(collectionFolder.FolderPath, "Renamed book"); Directory.Move(bookFolderPath, newBookFolderPath); tc.HandleBookRename("My book", "Renamed book"); return(tc); }
public void CopyBiggerThanBuffer() { using (var temp = new TempFile()) { var bldr = new StringBuilder(); for (int i = 0; i < 512; i++) { bldr.AppendLine("This is a test"); } var input = bldr.ToString(); Assert.That(input.Length > 4096); var oldBufSize = RobustFile.BufferSize; RobustFile.BufferSize = 4096; // To avoid writing a large file in a unit test RobustFile.WriteAllText(temp.Path, input); using (var output = new TempFile()) { RobustFile.Delete(output.Path); // apparently we can encounter a left-over temp file RobustFile.Copy(temp.Path, output.Path); Assert.That(File.ReadAllText(output.Path), Is.EqualTo(input)); } RobustFile.BufferSize = oldBufSize; } }
public void NewBook_RaisesNewBookEvent() { var newBookPath = Path.Combine(_repoFolder.FolderPath, "Books", "A new book.bloom"); var newBookName = ""; _collection.StartMonitoring(); // used to wait for the OS notification to raise the event ManualResetEvent newbookRaised = new ManualResetEvent(false); _collection.NewBook += (sender, args) => { newBookName = args.BookFileName; newbookRaised.Set(); }; RobustFile.WriteAllText(newBookPath, @"Newly added book"); // no, not a zip at all var waitSucceeded = newbookRaised.WaitOne(1000); _collection.StopMonitoring(); RobustFile.Delete(newBookPath); Assert.IsTrue(waitSucceeded, "New book was not raised"); Assert.That(newBookName, Is.EqualTo("A new book.bloom")); }
/// <summary>Gets the contents of a Text file</summary> /// <param name="fileName"></param> /// <param name="wordFileType"></param> private string GetTextFileContents(string fileName, WordFileType wordFileType) { var path = Path.Combine(Path.GetDirectoryName(CurrentBook.CollectionSettings.SettingsFilePath), wordFileType == WordFileType.AllowedWordsFile ? "Allowed Words" : "Sample Texts"); path = Path.Combine(path, fileName); if (!RobustFile.Exists(path)) { return(String.Empty); } // first try utf-8/ascii encoding (the .Net default) var text = RobustFile.ReadAllText(path); // If the "unknown" character (65533) is present, C# did not sucessfully decode the file. Try the system default encoding and codepage. if (text.Contains((char)65533)) { text = RobustFile.ReadAllText(path, Encoding.Default); } return(text); }
private void ForceDocumentCompleted() { Cleanup(); while (_pending.Count > 0) { var task = _pending[0]; _pending.RemoveAt(0); // If the file doesn't exist, calling _current.Browser.Navigate() results in the program // silently stopping on Linux. This should never happen with the check made above for // superceded navigation requests before posting a pending navigation, but a race could // occur between the old file being deleted, the next pending request being handled, and // the new file being sent as a navigation requesting. So we have this check as a backstop. // (I always believe in both belts and suspenders, don't you?) This is part of the fix // for https://jira.sil.org/browse/BL-863. if (!task.Url.StartsWith("http://") && !RobustFile.Exists(task.Url)) { Debug.Assert(false, String.Format(@"DEBUG: NavigationIsolator.ForceDocumentCompleted(): new file to display (""{0}"") does not exist!??", task.Url)); continue; } StartTask(task); return; } }
public void ForgetChanges_HtmlChangeAndRename_UndoesBoth() { using (var collectionFolder = new TemporaryFolder("ForgetChanges_HtmlChangeAndRename_UndoesBoth_Collection")) { using (var repoFolder = new TemporaryFolder("ForgetChanges_HtmlChangeAndRename_UndoesBoth_Repo")) { var tc = MakeAndRenameBook(collectionFolder, repoFolder, out var bookPath, out var newBookFolderPath); var changedFolders = tc.ForgetChangesCheckin("Renamed book"); Assert.That(changedFolders.Count, Is.EqualTo(2)); Assert.That(RobustFile.Exists(bookPath)); Assert.That(Directory.Exists(newBookFolderPath), Is.False); Assert.That(RobustFile.ReadAllText(bookPath), Is.EqualTo("This is just a dummy")); Assert.That(tc.GetStatus("My book").lockedBy, Is.Null); Assert.That(changedFolders[1], Is.EqualTo(newBookFolderPath)); Assert.That(changedFolders[0], Is.EqualTo(Path.GetDirectoryName(bookPath))); } } }
private static void RemoveUnwantedVideoFiles(string destDirName, IEnumerable <string> videoFilesToInclude) { // If videoFilesToInclude is null or empty, ALL video files in the video subdirectory will be deleted. // This likely means that they aren't referenced in the Book's .htm file, although someday there could be // other reasons to not include them. var videoDir = BookStorage.GetVideoFolderPath(destDirName); if (!Directory.Exists(videoDir)) { return; } foreach (var videoFilePath in Directory.EnumerateFiles(videoDir)) { // videoFilesToInclude strings do not include timings, but do include "video/" prefix, // so include the prefix in our Contains() test. var fileName = BookStorage.GetNormalizedPathForOS(Path.GetFileName(videoFilePath)); if (videoFilesToInclude == null || !videoFilesToInclude.Contains(BookStorage.GetVideoFolderName + fileName)) { RobustFile.Delete(videoFilePath); } } }
new[] { "another-image.svg", "another-image.png" })] // use default svg if no landscape public void InjectXMatter_BrandingApi_SelectsRightOrientationImage(string orientation, string expectedFileName, string expectedImageContent, string[] imageFilesToCreate) { using (var tempFolder = new TemporaryFolder("InjectXMatter_Landscape_PrefersLandscapeImage" + new Random().Next())) { var bookFolder = Path.Combine(tempFolder.FolderPath, "book"); Directory.CreateDirectory(bookFolder); var srcFolder = Path.Combine(tempFolder.FolderPath, "source"); Directory.CreateDirectory(srcFolder); foreach (var fileName in imageFilesToCreate) { var srcImagePath = Path.Combine(srcFolder, fileName); // yes, write the file name as its content, so we can identify which file was copied. File.WriteAllText(srcImagePath, fileName); } var frontMatterDom = new XmlDocument(); frontMatterDom.LoadXml(@"<html><head> <link href='file://blahblah\\a5portrait.css' type='text/css' /></head><body> <div class='bloom-page cover coverColor bloom-frontMatter' data-page='required'> <img class='branding' src='/bloom/api/branding/image?id=" + Path.Combine(srcFolder, expectedFileName) + @"' type='image/svg'/> </div></body></html>" ); var helper = CreatePaperSaverHelper(); helper.XMatterDom = frontMatterDom; var layout = new Layout() { SizeAndOrientation = SizeAndOrientation.FromString(orientation) }; helper.InjectXMatter(_dataSet.WritingSystemAliases, layout, "Default", bookFolder); AssertThatXmlIn.Dom(_dom.RawDom).HasSpecifiedNumberOfMatchesForXpath("//img[@src='" + expectedFileName + "']", 1); var outputImagePath = Path.Combine(bookFolder, expectedFileName); Assert.That(File.Exists(outputImagePath)); Assert.That(RobustFile.ReadAllText(outputImagePath), Is.EqualTo(expectedImageContent)); } }
public static string GetBestDeviceXMatterAvailable(string xmatterName, IFileLocator fileLocator) { if (xmatterName.EndsWith("Device")) { return(xmatterName); } // Look to see if there is a special Device version of this xmatter var deviceXmatterName = $"{xmatterName}-Device"; var directoryPath = GetXMatterDirectory(deviceXmatterName, fileLocator, null, false, true); if (directoryPath != null) { return(deviceXmatterName); } // Look in the stylesheet and see if it already handles device layout try { var plainXmatterDirectory = GetXMatterDirectory(xmatterName, fileLocator, null, false, true); if (plainXmatterDirectory != null) { var cssPath = Path.Combine(plainXmatterDirectory, GetStyleSheetFileName(xmatterName)); if (RobustFile.ReadAllText(cssPath).Contains(".Device16x9")) { return(xmatterName); } } } catch (Exception) { // swallow and fall back to dedicated device xmatter } // use the default Device xmatter which is just named "Device" return("Device"); }
public static void WriteSpreadsheet(InternalSpreadsheet spreadsheet, string path) { using (var package = new ExcelPackage()) { var worksheet = package.Workbook.Worksheets.Add("BloomBook"); int r = 0; foreach (var row in spreadsheet.AllRows()) { r++; for (var c = 0; c < row.Count; c++) { // Enhance: Excel complains about cells that contain pure numbers // but are created as strings. We could possibly tell it that cells // that contain simple numbers can be treated accordingly. // It might be helpful for some uses of the group-on-page-index // if Excel knew to treat them as numbers. worksheet.Cells[r, c + 1].Value = row.GetCell(c).Content; } } // Review: is this helpful? Excel typically makes very small cells, so almost // nothing of a cell's content can be seen, and that only markup. But it also // starts out with very narrow cells, so WrapText makes them almost unmanageably tall. worksheet.Cells[1, 1, r, spreadsheet.ColumnCount].Style.WrapText = true; try { RobustFile.Delete(path); var xlFile = new FileInfo(path); package.SaveAs(xlFile); } catch (Exception ex) { Console.WriteLine("Writing Spreadsheet failed. Do you have it open in Excel?"); Console.WriteLine(ex.Message); Console.WriteLine(ex.StackTrace); } } }
/// <summary> /// Fix the standard CSS files to replace any fonts listed in badFonts with the defaultFont value. /// </summary> public static void FixCssReferencesForBadFonts(string cssFolderPath, string defaultFont, HashSet <string> badFonts) { // Note that the font may be referred to in defaultLangStyles.css, in customCollectionStyles.css, or in a style defined in the HTML. // This method handles the .css files. var defaultLangStyles = Path.Combine(cssFolderPath, "defaultLangStyles.css"); if (RobustFile.Exists(defaultLangStyles)) { var cssTextOrig = RobustFile.ReadAllText(defaultLangStyles); var cssText = cssTextOrig; foreach (var font in badFonts) { var cssRegex = new System.Text.RegularExpressions.Regex($"font-family:\\s*'?{font}'?;"); cssText = cssRegex.Replace(cssText, $"font-family: '{defaultFont}';"); } if (cssText != cssTextOrig) { RobustFile.WriteAllText(defaultLangStyles, cssText); } } var customCollectionStyles = Path.Combine(cssFolderPath, "customCollectionStyles.css"); if (RobustFile.Exists(customCollectionStyles)) { var cssTextOrig = RobustFile.ReadAllText(customCollectionStyles); var cssText = cssTextOrig; foreach (var font in badFonts) { var cssRegex = new System.Text.RegularExpressions.Regex($"font-family:\\s*'?{font}'?;"); cssText = cssRegex.Replace(cssText, $"font-family: '{defaultFont}';"); } if (cssText != cssTextOrig) { RobustFile.WriteAllText(customCollectionStyles, cssText); } } }
public static string GetDropboxFolderPath() { try { // Prefer a "business" dropbox to a "personal" dropbox if one exists. var pathPrefixes = new[] { "\"business\":\\s*{[^{}]*", "\"personal\":\\s*{[^{}]*" }; foreach (var jsonPath in s_jsonPaths) { var fixedPath = Environment.ExpandEnvironmentVariables(jsonPath); if (RobustFile.Exists(fixedPath)) { var json = RobustFile.ReadAllText(fixedPath, Encoding.UTF8); foreach (var prefix in pathPrefixes) { var pathMatch = prefix + s_pathMatchPattern; foreach (var match in new Regex(pathMatch).Matches(json).Cast <Match>()) { var dropboxRoot = match.Groups[1].Value; if (!Platform.IsLinux) { dropboxRoot = dropboxRoot.Replace(@"\\", @"\"); } if (System.IO.Directory.Exists(dropboxRoot)) { return(dropboxRoot); } } } } } } catch (Exception ex) { NonFatalProblem.ReportSentryOnly(ex); } return(null); }
private void SetupCssTests() { // create collection directory Directory.CreateDirectory(_collectionPath); // customCollectionStyles.css var cssFile = Path.Combine(_collectionPath, "customCollectionStyles.css"); RobustFile.WriteAllText(cssFile, @".customCollectionStylesCssTest{}"); // create book directory var bookPath = Path.Combine(_collectionPath, "TestBook"); Directory.CreateDirectory(bookPath); // defaultLangStyles.css cssFile = Path.Combine(bookPath, "defaultLangStyles.css"); RobustFile.WriteAllText(cssFile, @".defaultLangStylesCssTest{}"); cssFile = Path.Combine(bookPath, "customCollectionStyles.css"); RobustFile.WriteAllText(cssFile, @".customCollectionStylesCssTest{}"); cssFile = Path.Combine(bookPath, "ForUnitTest-XMatter.css"); RobustFile.WriteAllText(cssFile, @"This is the one in the book"); // Factory-XMatter.css cssFile = Path.Combine(bookPath, "Factory-XMatter.css"); RobustFile.WriteAllText(cssFile, @".factoryXmatterCssTest{}"); // customBookStyles.css cssFile = Path.Combine(bookPath, "customBookStyles.css"); RobustFile.WriteAllText(cssFile, @".customBookStylesCssTest{}"); // miscStyles.css - a file name not distributed with or created by Bloom cssFile = Path.Combine(bookPath, "miscStyles.css"); RobustFile.WriteAllText(cssFile, @".miscStylesCssTest{}"); }
private void HandleVideoStatisticsRequest(ApiRequest request) { if (request.HttpMethod != HttpMethods.Get) { throw new ApplicationException(request.LocalPath() + " only implements 'get'"); } lock (request) { string videoFilePath; decimal[] timings; if (!GetVideoDetailsFromRequest(request, false, out videoFilePath, out timings)) { return; // request.Failed was called inside the above method } if (!RobustFile.Exists(videoFilePath)) { request.Failed("Cannot find video file (" + videoFilePath + ")"); return; } if (string.IsNullOrEmpty(FfmpegProgram)) { request.Failed("Cannot find ffmpeg program"); return; } var fileInfo = new FileInfo(videoFilePath); var sizeInBytes = fileInfo.Length; var output = RunFfmpegOnVideoToGetStatistics(request, videoFilePath); var statistics = ParseFfmpegStatistics(output, sizeInBytes); statistics.Add("startSeconds", timings[0].ToString("F1")); statistics.Add("endSeconds", timings[1].ToString("F1")); request.ReplyWithJson(statistics); } }
public void CreateZipFile_NonAsciiEntryNames() { // this test is to make sure non-ascii file names are being stored and retrieved correctly const string fileName = "मराठी मैथिली संस्कृत हिन्.htm"; const string fileContents = @"File contents."; using (var tempFile = TempFile.WithFilenameInTempFolder(fileName)) { RobustFile.WriteAllText(tempFile.Path, fileContents); using (var bookZip = TempFile.WithExtension(".zip")) { var zip = new BloomZipFile(bookZip.Path); zip.AddTopLevelFile(tempFile.Path); zip.Save(); using (var zip2 = new ZipFile(bookZip.Path)) { foreach (ZipEntry zipEntry in zip2) { Console.Out.WriteLine(zipEntry.Name); Assert.That(zipEntry.Name, Is.EqualTo(fileName)); using (var inStream = zip2.GetInputStream(zipEntry)) { byte[] buffer = new byte[zipEntry.Size]; ICSharpCode.SharpZipLib.Core.StreamUtils.ReadFully(inStream, buffer); var testStr = Encoding.Default.GetString(buffer); Assert.That(testStr, Is.EqualTo(fileContents)); } } } } } }
/// <summary> /// Get the image metadata from the file as reliably as possible. /// </summary> public static Metadata MetadataFromFile(string path) { // Books sometimes use image files that are mislabeled. JPEG files sometimes have been given // .png extensions, and it's likely that PNG files have been given .jpg extensions. TagLib crashes // trying to read the metadata in such cases, so we prevent that particular crash in this method. if (Path.GetExtension(path).ToLowerInvariant() == ".png" && ImageUtils.IsJpegFile(path)) { using (var jpegFile = TempFile.WithExtension(".jpg")) { RobustFile.Copy(path, jpegFile.Path, true); return(MetadataFromFileInternal(jpegFile.Path)); } } if (ImageUtils.HasJpegExtension(path) && ImageUtils.IsPngFile(path)) { using (var pngFile = TempFile.WithExtension(".png")) { RobustFile.Copy(path, pngFile.Path, true); return(MetadataFromFileInternal(pngFile.Path)); } } // Assume everything is okay. return(MetadataFromFileInternal(path)); }
public void Setup() { var locations = new List <string>(); locations.Add(BloomFileLocator.GetFactoryXMatterDirectory()); _xMatterParentFolder = new TemporaryFolder("UserCollection"); _xMatterFolder = new TemporaryFolder(_xMatterParentFolder, "User-XMatter"); locations.Add(_xMatterParentFolder.Path); RobustFile.WriteAllText(Path.Combine(_xMatterFolder.Path, "SomeRandomXYZABCStyles.css"), "Some arbitrary test data"); RobustFile.WriteAllText(Path.Combine(_xMatterFolder.Path, "Decodable Reader.css"), "Fake DR test data"); //locations.Add(XMatterAppDataFolder); //locations.Add(XMatterCommonDataFolder); _xMatterFinder = new XMatterPackFinder(locations); _otherFilesForTestingFolder = new TemporaryFolder("BloomFileLocatorTests"); var userInstalledSearchPaths = new List <string>(ProjectContext.GetFoundFileLocations()); userInstalledSearchPaths.Add(_otherFilesForTestingFolder.Path); _fileLocator = new BloomFileLocator(new CollectionSettings(), _xMatterFinder, ProjectContext.GetFactoryFileLocations(), userInstalledSearchPaths, ProjectContext.GetAfterXMatterFileLocations()); //Without this, tests can interact with one another, leaving the language set as something unexpected. LocalizationManager.SetUILanguage("en", false); }
private (string version, bool old) GetAceByDaisyVersion(string daisyDirectory) { try { // The path typically ends in something like \ace\bin\, at least on Windows. // We're looking for the ace directory. One GetDirectoryName just strips of the // final slash, so we need two to get to ace. var packagePath = Path.Combine(Path.GetDirectoryName(Path.GetDirectoryName(daisyDirectory)), "package.json"); var packageJson = DynamicJson.Parse(RobustFile.ReadAllText(packagePath)); string versionString = packageJson.version; var match = new Regex(@"(\d+)\.(\d+)").Match(versionString); if (match.Success) { var old = int.Parse(match.Groups[1].Value) * 100 + int.Parse(match.Groups[2].Value) < 102; return(versionString, old); } } catch (Exception ex) { // just ignore not being able to get the version. } return("unknown", true); }
/// <summary> /// branding folders can optionally contain a settings.json file which aligns with this Settings class /// </summary> /// <param name="brandingNameOrFolderPath"> Normally, the branding is just a name, which we look up in the official branding folder //but unit tests can instead provide a path to the folder. /// </param> public static Settings GetSettings(string brandingNameOrFolderPath) { try { var settingsPath = BloomFileLocator.GetOptionalBrandingFile(brandingNameOrFolderPath, "settings.json"); if (!string.IsNullOrEmpty(settingsPath)) { var content = RobustFile.ReadAllText(settingsPath); var settings = JsonConvert.DeserializeObject <Settings>(content); if (settings == null) { NonFatalProblem.Report(ModalIf.Beta, PassiveIf.All, "Trouble reading branding settings", "settings.json of the branding " + brandingNameOrFolderPath + " may be corrupt. It had: " + content); return(null); } return(settings); } } catch (Exception e) { NonFatalProblem.Report(ModalIf.Beta, PassiveIf.All, "Trouble reading branding settings", exception: e); } return(null); }
public void CopyAllBooksFromSharedToLocalFolder_RetrievesExpectedBooks_AndChecksums() { using (var destFolder = new TemporaryFolder("GetBooks_Retrieves")) { _collection.CopyAllBooksFromRepoToLocalFolder(destFolder.FolderPath); var destBookFolder = Path.Combine(destFolder.FolderPath, "My book"); var destBookPath = Path.Combine(destBookFolder, "My book.htm"); Assert.That(RobustFile.ReadAllText(destBookPath), Is.EqualTo("This is just a dummy")); var destCssPath = Path.Combine(destBookFolder, "BasicLayout.css"); Assert.That(RobustFile.ReadAllText(destCssPath), Is.EqualTo("This is another dummy")); var destAudioDirectory = Path.Combine(destBookFolder, "audio"); var destMp3Path = Path.Combine(destAudioDirectory, "rubbish.mp3"); Assert.That(RobustFile.ReadAllText(destMp3Path), Is.EqualTo("Fake mp3")); var anotherDestBookFolder = Path.Combine(destFolder.FolderPath, kAnotherBook); var anotherDestBookPath = Path.Combine(anotherDestBookFolder, kAnotherBook + ".htm"); Assert.That(RobustFile.ReadAllText(anotherDestBookPath), Is.EqualTo("This is just a dummy for another book")); Assert.That(Directory.EnumerateDirectories(destFolder.FolderPath).Count(), Is.EqualTo(2)); AssertStatusMatch(destFolder.FolderPath, "My book"); AssertStatusMatch(destFolder.FolderPath, kAnotherBook); } }
private void Recorder_Stopped(IAudioRecorder arg1, ErrorEventArgs arg2) { Recorder.Stopped -= Recorder_Stopped; Directory.CreateDirectory(System.IO.Path.GetDirectoryName(PathToRecordableAudioForCurrentSegment)); // make sure audio directory exists try { var minimum = TimeSpan.FromMilliseconds(300); // this is arbitrary AudioRecorder.TrimWavFile(PathToTemporaryWav, PathToRecordableAudioForCurrentSegment, new TimeSpan(), TimeSpan.FromMilliseconds(_collectionAudioTrimEndMilliseconds), minimum); RobustFile.Delete(PathToTemporaryWav); // Otherwise, these continue to clutter up the temp directory. } catch (Exception error) { Logger.WriteEvent(error.Message); RobustFile.Copy(PathToTemporaryWav, PathToRecordableAudioForCurrentSegment, true); } //We could put this off entirely until we make the ePUB. //I'm just gating this for now because maybe the thought was that it's better to do it a little at a time? //That's fine so long as it doesn't make the UI unresponsive on slow machines. var mp3Path = _mp3Encoder.Encode(PathToRecordableAudioForCurrentSegment); // Got a good new recording, can safely clean up all backups related to old one. foreach (var path in Directory.EnumerateFiles( Path.GetDirectoryName(PathToRecordableAudioForCurrentSegment), Path.GetFileNameWithoutExtension(PathToRecordableAudioForCurrentSegment) + "*" + ".bak")) { RobustFile.Delete(path); } // BL-7617 Don't keep .wav file after .mp3 is created successfully. if (!string.IsNullOrEmpty(mp3Path) && File.Exists(mp3Path)) { RobustFile.Delete(PathToRecordableAudioForCurrentSegment); } _completingRecording.Set(); // will release HandleAudioFileRequest if it is waiting. }
private void RestartBloom(string newInstallDir) { Control ancestor = Parent; while (ancestor != null && !(ancestor is Shell)) { ancestor = ancestor.Parent; } if (ancestor == null) { return; } var shell = (Shell)ancestor; var pathToNewExe = Path.Combine(newInstallDir, Path.ChangeExtension(Application.ProductName, ".exe")); if (!RobustFile.Exists(pathToNewExe)) { return; // aargh! } shell.QuitForVersionUpdate = true; Process.Start(pathToNewExe); Thread.Sleep(2000); shell.Close(); }
/// <summary> /// Delete a recording segment, as requested by the Clear button in the talking book tool. /// The corresponding mp3 should also be deleted. /// </summary> /// <param name="fileUrl"></param> private void HandleDeleteSegment(ApiRequest request) { var path = GetPathToSegment(request.RequiredParam("id")); var mp3Path = Path.ChangeExtension(path, "mp3"); var success = true; if (RobustFile.Exists(path)) { success = DeleteFileReportingAnyProblem(path); } if (RobustFile.Exists(mp3Path)) { success &= DeleteFileReportingAnyProblem(mp3Path); } if (success) { request.PostSucceeded(); } else { request.Failed("could not delete at least one file"); } }
/// <summary> /// Delete a file (typically a recording, as requested by the Clear button in the talking book tool) /// </summary> /// <param name="fileUrl"></param> private void HandleDeleteSegment(ApiRequest request) { var path = GetPathToSegment(request.RequiredParam("id")); if (!RobustFile.Exists(path)) { request.Succeeded(); } else { try { RobustFile.Delete(path); request.Succeeded(); } catch (IOException e) { var msg = string.Format( LocalizationManager.GetString("Errors.ProblemDeletingFile", "Bloom had a problem deleting this file: {0}"), path); ErrorReport.NotifyUserOfProblem(e, msg + Environment.NewLine + e.Message); } } }
private static string GetLocalPathWithoutQuery(string localPath) { if (localPath.StartsWith(BloomUrlPrefix)) { localPath = localPath.Substring(BloomUrlPrefix.Length); #if __MonoCS__ if (localPath.StartsWith("tmp/ePUB")) { localPath = "/" + localPath; // restore leading slash for full path } #endif } // and if the file is using localhost:1234/foo.js, at this point it will say "/foo.js", so let's strip off that leading slash else if (localPath.StartsWith("/")) { localPath = localPath.Substring(1); } if (localPath.Contains("?") && !RobustFile.Exists(localPath)) { var idx = localPath.LastIndexOf("?", StringComparison.Ordinal); return(localPath.Substring(0, idx)); } return(localPath); }
// We want to move the file specified in the first path to a new location to use // as a backup while we typically replace it. // A previous backup, possibly of the same or another file, is no longer needed (if it exists) // and should be deleted, if possible, on a background thread. // The path to the backup will be updated to the new backup. // Typically the new name matches the original with the extension changed to .bak. // If necessary (because the desired backup file already exists), we will add a counter // to get the a name that is not in use. // A goal is (for performance reasons) not to have to wait while a file is deleted // (and definitely not while one is copied). private static bool PrepareBackupFile(string path, ref string backupPath, ApiRequest request) { int counter = 0; backupPath = path + ".bak"; var originalExtension = Path.GetExtension(path); var pathWithNoExtension = Path.GetFileNameWithoutExtension(path); while (File.Exists(backupPath)) { counter++; backupPath = pathWithNoExtension + counter + originalExtension + ".bak"; } // An earlier version copied the file to a temp file. We can't MOVE to a file in the system temp // directory, though, because we're not sure it is on the same volume. And sometimes the time // required to copy the file was noticeable and resulted in the user starting to speak before // the system started recording. So we pay the price of a small chance of backups being left // around the book directory to avoid that danger. if (RobustFile.Exists(path)) { try { RobustFile.Move(path, backupPath); } catch (Exception err) { ErrorReport.NotifyUserOfProblem(err, "The old copy of the recording at " + path + " is locked up, so Bloom can't record over it at the moment. If it remains stuck, you may need to restart your computer."); request.Failed("Audio file locked"); return(false); } } return(true); }
private void SaveSettingsCollectionStylesCss() { string path = FolderPath.CombineForPath("settingsCollectionStyles.css"); try { var sb = new StringBuilder(); sb.AppendLine("/* These styles are controlled by the Settings dialog box in Bloom. */"); sb.AppendLine("/* They many be over-ridden by rules in customCollectionStyles.css or customBookStyles.css */"); AddFontCssRule(sb, "BODY", GetDefaultFontName(), 0); AddFontCssRule(sb, "[lang='" + Language1Iso639Code + "']", DefaultLanguage1FontName, Language1LineHeight); AddFontCssRule(sb, "[lang='" + Language2Iso639Code + "']", DefaultLanguage2FontName, Language2LineHeight); if (!string.IsNullOrEmpty(Language3Iso639Code)) { AddFontCssRule(sb, "[lang='" + Language3Iso639Code + "']", DefaultLanguage3FontName, Language3LineHeight); } AddNumberingStyleCssRule(sb, PageNumberStyle); RobustFile.WriteAllText(path, sb.ToString()); } catch (Exception error) { SIL.Reporting.ErrorReport.NotifyUserOfProblem(error, "Bloom was unable to update this file: {0}", path); } }
static PublishSettings MigrateSettings(string bookFolderPath) { // See if we can migrate data from an old metaData. var metaDataPath = BookMetaData.MetaDataPath(bookFolderPath); var settings = new PublishSettings(); try { if (!RobustFile.Exists(metaDataPath)) { return(settings); } var metaDataString = RobustFile.ReadAllText(metaDataPath, Encoding.UTF8); // I chose to do this using DynamicJson, rather than just BloomMetaData.FromString() and // reading the obsolete properties, in hopes that we can eventually retire the obsolete // properties. However, that may not be possible without breaking things when we attempt // to load an old meta.json with JsonConvert. Still, at least this approach makes for // fewer warnings about use of obsolete methods. var metaDataJson = DynamicJson.Parse(metaDataString) as DynamicJson; if (metaDataJson.IsDefined("features")) { if (metaDataJson.TryGet("features", out string[] features))
/// <summary> /// Causes the specified book contents to be created on disk. /// </summary> /// <returns>A string containing the path to the book folder</returns> /// <remarks>This is a little different than a normal DataBuilder Build(), because we're not really /// returning a "book" object like we normally would (we don't have a book object), /// but instead we're causing the book to be written to disk. /// </remarks> public BookFolderBuilder Build() { Debug.Assert(_containingFolder != null, "_containingFolder is required! Set it via InFolder(...)"); Debug.Assert(_bookTitle != null, "BookTitle is required. Set it either via WithTitle() or via WithDefaultValues()"); var bookFolderPath = Path.Combine(_containingFolder, _bookFolderName ?? _bookTitle); Directory.CreateDirectory(bookFolderPath); BuiltBookFolderPath = bookFolderPath; if (_htmContents != null) { var htmPath = Path.Combine(bookFolderPath, $"{_bookTitle}.htm"); RobustFile.WriteAllText(htmPath, _htmContents); BuiltBookHtmPath = htmPath; } var meta = new BookMetaData(); meta.WriteToFolder(bookFolderPath); // Returns the builder object again so that callers can call post-build properties return(this); }
public static void DeleteFolderThatMayBeInUseAndIfNotFailSilently(string folder) { if (Directory.Exists(folder)) { try { RobustIO.DeleteDirectory(folder, true); } catch (Exception e) { try { Debug.WriteLine(e.Message); //maybe we can at least clear it out a bit string[] files = Directory.GetFiles(folder, "*.*", SearchOption.AllDirectories); foreach (string s in files) { try { RobustFile.Delete(s); } catch (Exception) { } } //sleep and try again (in case some other thread will let go of them) Thread.Sleep(1000); RobustIO.DeleteDirectory(folder, true); } catch (Exception) { } } } }