Example #1
0
 public RepositorySetup(string userName, string projectfolder)
 {
     Progress      = new NullProgress();
     ProjectFolder = new TemporaryFolder(projectfolder + "-" + Guid.NewGuid());
     MakeRepositoryForTest(ProjectFolder.Path, userName, Progress);
     ProjectFolderConfig = new ProjectFolderConfiguration(ProjectFolder.Path);
 }
Example #2
0
        public void ReportingProgressUpdateHasNoSideEffects()
        {
            IProgress <int> instance = new NullProgress <int>();
            int             hashCode = instance.GetHashCode();

            instance.Report(240);
            Assert.Equal(hashCode, instance.GetHashCode());
        }
Example #3
0
        public void MsarSaveNowSavesAll()
        {
            var progress = new NullProgress();

            _msar.SaveNowIfNeeded(progress);
            Assert.That(_primary.ProgressPassedToSaveNow, Is.EqualTo(progress), "SaveNow not forwarded properly to _primary");
            Assert.That(_other1.ProgressPassedToSaveNow, Is.EqualTo(progress), "SaveNow not forwarded properly to first other");
            Assert.That(_other2.ProgressPassedToSaveNow, Is.EqualTo(progress), "SaveNow not forwarded properly to second other");
        }
        /// <summary>
        /// Process the input PDF file by compressing images and/or by converting color to CMYK.  The operations
        /// to perform are established by the constructor.
        /// </summary>
        public void ProcessPdfFile(string inputFile, string outputFile)
        {
            _inputPdfPath  = inputFile;
            _outputPdfPath = outputFile;
            var exePath = "/usr/bin/gs";

            if (SIL.PlatformUtilities.Platform.IsWindows)
            {
                exePath = FindGhostcriptOnWindows();
            }
            if (!String.IsNullOrWhiteSpace(exePath) && File.Exists(exePath))
            {
                if (_worker != null)
                {
                    _worker.ReportProgress(0, GetSpecificStatus());
                }
                using (var tempPdfFile = TempFile.WithExtension(".pdf"))
                {
                    var runner        = new CommandLineRunner();
                    var arguments     = GetArguments(tempPdfFile.Path);
                    var fromDirectory = String.Empty;
                    var progress      = new NullProgress();                     // I can't figure out how to use any IProgress based code, but we show progress okay as is.
                    var res           = runner.Start(exePath, arguments, Encoding.UTF8, fromDirectory, 3600, progress, ProcessGhostcriptReporting);
                    if (res.DidTimeOut || !RobustFile.Exists(tempPdfFile.Path))
                    {
                        if (_inputPdfPath != _outputPdfPath)
                        {
                            RobustFile.Copy(_inputPdfPath, _outputPdfPath, true);
                        }
                        return;
                    }
                    // If the process made the file larger and didn't change the color scheme, ignore the result.
                    var oldInfo = new FileInfo(_inputPdfPath);
                    var newInfo = new FileInfo(tempPdfFile.Path);
                    if (newInfo.Length < oldInfo.Length || _type == OutputType.Printshop)
                    {
                        RobustFile.Copy(tempPdfFile.Path, _outputPdfPath, true);
                    }
                    else if (_inputPdfPath != _outputPdfPath)
                    {
                        RobustFile.Copy(_inputPdfPath, _outputPdfPath, true);
                    }
                }
            }
            else
            {
                // This shouldn't happen.  Linux Bloom package depends on the ghostscript package, and we'll include
                // ghostscript files in our installer to ensure it's available on Windows.  But we have this code here
                // as a failsafe fallback reminding the developers to ensure this installation work happens.
                Debug.WriteLine("ghostscript is not installed, so Bloom cannot process the PDF file.");
                if (_inputPdfPath != _outputPdfPath)
                {
                    RobustFile.Copy(_inputPdfPath, _outputPdfPath, true);
                }
            }
        }
Example #5
0
        public void MsarAddsObserverToAll()
        {
            var progress = new NullProgress();
            var observer = new MockObserver();

            _msar.AddObserver(observer, progress);

            Assert.That(_primary.Observer, Is.EqualTo(observer));
            Assert.That(_other1.Observer, Is.EqualTo(observer));
            Assert.That(_primary.ProgressPassedToAddObserver, Is.EqualTo(progress));
            Assert.That(_other2.ProgressPassedToAddObserver, Is.EqualTo(progress));
        }
Example #6
0
 public void UserCancelledBreakupShouldThrow()
 {
     using (var tempFile = TempFile.WithFilename("foo" + Utilities.FwXmlExtension))
     {
         var progress = new NullProgress
         {
             CancelRequested = true
         };
         var pathname = tempFile.Path;
         Assert.Throws <UserCancelledException>(() => FLExProjectSplitter.PushHumptyOffTheWall(progress, pathname));
     }
 }
Example #7
0
		private static int Main(string[] args)
		{
			SetUpErrorHandling();
			var pathname = args[0];
			using (var prog = new NullProgress())
			{
				var data = new FwDataFixer(pathname, prog, logger);
				data.FixErrorsAndSave();
			}
			if (errorsOccurred)
				return 1;
			return 0;
		}
Example #8
0
 public void EnsureAllNotesRepositoriesLoaded()
 {
     if (!_searchedForAllExistingNotesFiles)
     {
         var progress = new NullProgress();
         foreach (var repo in AnnotationRepository.CreateRepositoriesFromFolder(_dataFolderPath, progress))
         {
             if (!_annotationRepositories.ContainsKey(repo.AnnotationFilePath))
             {
                 _annotationRepositories.Add(repo.AnnotationFilePath, repo);
             }
         }
         _searchedForAllExistingNotesFiles = true;
     }
 }
Example #9
0
        private static int Main(string[] args)
        {
            SetUpErrorHandling();
            var pathname = args[0];

            using (var prog = new NullProgress())
            {
                var data = new FwDataFixer(pathname, prog, logger, counter);
                data.FixErrorsAndSave();
            }
            if (errorsOccurred)
            {
                return(1);
            }
            return(0);
        }
Example #10
0
        public void UpdateToLongHashOnNonExistantLongHashReturns_UpdateResults_NoSuchRevision()
        {
            using (var testRoot = new TemporaryFolder("RepositoryTests"))
            {
                var progress = new NullProgress();
                HgRepository.CreateRepositoryInExistingDir(testRoot.Path, progress);
                // fileX and fileXRev are zero based indexing, since those local commit numbers in Hg are zero based indexing.
                using (var file0 = testRoot.GetNewTempFile(true))
                {
                    var repo = new HgRepository(testRoot.Path, new NullProgress());
                    repo.AddAndCheckinFile(file0.Path);

                    // SUT
                    Assert.That(repo.UpdateToLongHash("12345678901234567890BAD0HASH000000000000"), Is.EqualTo(HgRepository.UpdateResults.NoSuchRevision));
                }
            }
        }
Example #11
0
        public void UpdateToLongHashOnSameLongHashReturns_UpdateResults_AlreadyOnIt()
        {
            using (var testRoot = new TemporaryFolder("RepositoryTests"))
            {
                var progress = new NullProgress();
                HgRepository.CreateRepositoryInExistingDir(testRoot.Path, progress);
                // fileX and fileXRev are zero based indexing, since those local commit numbers in Hg are zero based indexing.
                using (var file0 = testRoot.GetNewTempFile(true))
                {
                    var repo = new HgRepository(testRoot.Path, new NullProgress());
                    repo.AddAndCheckinFile(file0.Path);
                    var file0Rev = repo.GetRevisionWorkingSetIsBasedOn();

                    // SUT
                    Assert.That(repo.UpdateToLongHash(file0Rev.Number.LongHash), Is.EqualTo(HgRepository.UpdateResults.AlreadyOnIt));
                }
            }
        }
        /// <summary>
        /// Process the input PDF file by compressing images and/or by converting color to CMYK.  The operations
        /// to perform are established by the constructor.
        /// </summary>
        public void ProcessPdfFile(string inputFile, string outputFile, bool removeEvenPages = false)
        {
            _inputPdfPath  = inputFile;
            _outputPdfPath = outputFile;
            var exePath = "/usr/bin/gs";

            if (SIL.PlatformUtilities.Platform.IsWindows)
            {
                exePath = FindGhostcriptOnWindows();
            }
            if (!String.IsNullOrWhiteSpace(exePath) && File.Exists(exePath))
            {
                if (_worker != null)
                {
                    _worker.ReportProgress(0, GetSpecificStatus());
                }
                using (var tempPdfFile = TempFile.WithExtension(".pdf"))
                {
                    var runner        = new CommandLineRunner();
                    var arguments     = GetArguments(tempPdfFile.Path, null, removeEvenPages);
                    var fromDirectory = String.Empty;
                    var progress      = new NullProgress();                     // I can't figure out how to use any IProgress based code, but we show progress okay as is.
                    var res           = runner.Start(exePath, arguments, Encoding.UTF8, fromDirectory, 3600, progress, ProcessGhostcriptReporting);
                    if (res.ExitCode != 0)
                    {
                        // On Linux, ghostscript doesn't deal well with some Unicode filenames.  Try renaming the input
                        // file temporarily to something innocuous to see if this makes the ghostscript process succeed.
                        // See https://issues.bloomlibrary.org/youtrack/issue/BL-7177.
                        using (var tempInputFile = TempFile.WithExtension(".pdf"))
                        {
                            RobustFile.Delete(tempInputFile.Path);                                      // Move won't replace even empty files.
                            RobustFile.Move(_inputPdfPath, tempInputFile.Path);
                            arguments = GetArguments(tempPdfFile.Path, tempInputFile.Path, removeEvenPages);
                            res       = runner.Start(exePath, arguments, Encoding.UTF8, fromDirectory, 3600, progress, ProcessGhostcriptReporting);
                            RobustFile.Move(tempInputFile.Path, _inputPdfPath);
                        }
                    }
                    if (res.ExitCode != 0 || res.DidTimeOut || !RobustFile.Exists(tempPdfFile.Path))
                    {
                        if (_inputPdfPath != _outputPdfPath)
                        {
                            RobustFile.Copy(_inputPdfPath, _outputPdfPath, true);
                        }
                        return;
                    }
                    // If the process made the file larger and didn't change the color scheme and we're not removing blank pages, ignore the result.
                    var oldInfo = new FileInfo(_inputPdfPath);
                    var newInfo = new FileInfo(tempPdfFile.Path);
                    if (newInfo.Length < oldInfo.Length || _type == OutputType.Printshop || removeEvenPages)
                    {
                        RobustFile.Copy(tempPdfFile.Path, _outputPdfPath, true);
                    }
                    else if (_inputPdfPath != _outputPdfPath)
                    {
                        RobustFile.Copy(_inputPdfPath, _outputPdfPath, true);
                    }
                }
            }
            else
            {
                // This shouldn't happen.  Linux Bloom package depends on the ghostscript package, and we'll include
                // ghostscript files in our installer to ensure it's available on Windows.  But we have this code here
                // as a failsafe fallback reminding the developers to ensure this installation work happens.
                Debug.WriteLine("ghostscript is not installed, so Bloom cannot process the PDF file.");
                if (_inputPdfPath != _outputPdfPath)
                {
                    RobustFile.Copy(_inputPdfPath, _outputPdfPath, true);
                }
            }
        }
Example #13
0
        public static void TestThatALargeFileIsNotInRepository(string extension)
        {
            var pathToTestRoot = Path.Combine(Path.GetTempPath(), "LargeFileFilterTestFolder_" + extension + "_" + Guid.NewGuid());

            try
            {
                if (Directory.Exists(pathToTestRoot))
                {
                    Thread.Sleep(2000);
                    Directory.Delete(pathToTestRoot, true);
                }
                Directory.CreateDirectory(pathToTestRoot);

                var allHandlers = ChorusFileTypeHandlerCollection.CreateWithInstalledHandlers().Handlers.ToList();
                allHandlers.Add(new ChorusTestFileHandler());
                var handlerForExtension = allHandlers.FirstOrDefault(handler => handler.GetExtensionsOfKnownTextFileTypes().Contains(extension.ToLowerInvariant()))
                                          ?? new DefaultFileTypeHandler();

                var goodFileName = "smallfry." + extension;
                var goodPathname = Path.Combine(pathToTestRoot, goodFileName);
                var goodFile     = TempFile.WithFilename(goodPathname);
                File.WriteAllText(goodFile.Path, "Nice, short text.");

                var whopperFileName = "whopper." + extension;
                var whopperPathname = Path.Combine(pathToTestRoot, whopperFileName);
                var whopperFile     = TempFile.WithFilename(whopperPathname);
                var whopperData     = "whopperdata ";
                while (whopperData.Length < handlerForExtension.MaximumFileSize)
                {
                    whopperData += whopperData;
                }
                File.WriteAllText(whopperFile.Path, whopperData);

                var progress = new NullProgress();
                var projectFolderConfiguration = new ProjectFolderConfiguration(pathToTestRoot);
                projectFolderConfiguration.IncludePatterns.Clear();
                projectFolderConfiguration.ExcludePatterns.Clear();
                projectFolderConfiguration.IncludePatterns.Add("*.*");
                RepositorySetup.MakeRepositoryForTest(pathToTestRoot, "Pesky", progress);
                var synchronizer = Synchronizer.FromProjectConfiguration(projectFolderConfiguration, progress);
                synchronizer.Repository.SetUserNameInIni("Pesky", progress);
                var syncOptions = new SyncOptions
                {
                    // Basic commit. Nothing fancy.
                    DoPullFromOthers   = false,
                    DoMergeWithOthers  = false,
                    DoSendToOthers     = false,
                    CheckinDescription = "Added"
                };

                var syncResults = synchronizer.SyncNow(syncOptions);
                Assert.IsTrue(syncResults.Succeeded);

                projectFolderConfiguration.ExcludePatterns.Remove(ProjectFolderConfiguration.BareFolderReadmeFileName);
                Assert.AreEqual(2, projectFolderConfiguration.ExcludePatterns.Count);
                Assert.IsTrue(projectFolderConfiguration.ExcludePatterns[0].Contains(whopperFileName));

                var repo = new HgRepository(pathToTestRoot, progress);
                Assert.IsTrue(repo.GetFileExistsInRepo(goodFileName), goodFileName);
                Assert.IsFalse(repo.GetFileExistsInRepo(whopperFileName), whopperFileName);
            }
            finally
            {
                if (Directory.Exists(pathToTestRoot))
                {
                    Thread.Sleep(2000);
                    Directory.Delete(pathToTestRoot, true);
                }
            }
        }
Example #14
0
        // e.g. http://bobeaton:[email protected]/snwmtn-test
        // or \\Bob-StudioXPS\Backup\Storying\snwmtn-test
        public static void SyncWithRepository(string strProjectFolder, bool bIsOpening)
        {
            // the project folder name has come here bogus at times...
            if (!Directory.Exists(strProjectFolder))
            {
                return;
            }

            string strProjectName = Path.GetFileNameWithoutExtension(strProjectFolder);

            // if there's no repo yet, then create one (even if we aren't going
            //  to ultimately push with an internet repo, we still want one locally)
            var projectConfig = new Chorus.sync.ProjectFolderConfiguration(strProjectFolder);

            projectConfig.IncludePatterns.Add("*.onestory");
            projectConfig.IncludePatterns.Add("*.xml");             // the P7 key terms list
            projectConfig.IncludePatterns.Add("*.bad");             // if we write a bad file, commit that as well
            projectConfig.IncludePatterns.Add("*.conflict");        // include the conflicts file as well so we can fix them
            projectConfig.IncludePatterns.Add("*.ChorusNotes");     // the new conflict file

            string strHgUsername, strRepoUrl, strSharedNetworkUrl;

            if (GetHgRepoParameters(strProjectName, out strHgUsername, out strRepoUrl, out strSharedNetworkUrl))
            {
                if (!String.IsNullOrEmpty(strRepoUrl))
                {
                    var nullProgress = new NullProgress();
                    var repo         = new HgRepository(strProjectFolder, nullProgress);
                    if (!repo.GetCanConnectToRemote(strRepoUrl, nullProgress))
                    {
                        if (MessageBox.Show(Properties.Resources.IDS_ConnectToInternet,
                                            Properties.Resources.IDS_Caption,
                                            MessageBoxButtons.OKCancel) ==
                            DialogResult.Cancel)
                        {
                            strRepoUrl = null;
                            if (String.IsNullOrEmpty(strSharedNetworkUrl))
                            {
                                return;
                            }
                        }
                    }
                }

                // for when we launch the program, just do a quick & dirty send/receive,
                //  but for closing (or if we have a network drive also), then we want to
                //  be more informative
                SyncUIDialogBehaviors suidb = SyncUIDialogBehaviors.Lazy;
                SyncUIFeatures        suif  = SyncUIFeatures.NormalRecommended;

                /*
                 * if (bIsOpening && String.IsNullOrEmpty(strSharedNetworkUrl))
                 * {
                 *      suidb = SyncUIDialogBehaviors.StartImmediatelyAndCloseWhenFinished;
                 *      suif = SyncUIFeatures.Minimal;
                 * }
                 * else
                 * {
                 *      suidb = SyncUIDialogBehaviors.Lazy;
                 *      suif = SyncUIFeatures.NormalRecommended;
                 * }
                 */

                using (var dlg = new SyncDialog(projectConfig, suidb, suif))
                {
                    dlg.UseTargetsAsSpecifiedInSyncOptions = true;
                    if (!String.IsNullOrEmpty(strRepoUrl))
                    {
                        dlg.SyncOptions.RepositorySourcesToTry.Add(RepositoryAddress.Create(CstrInternetName, strRepoUrl));
                    }
                    if (!String.IsNullOrEmpty(strSharedNetworkUrl))
                    {
                        dlg.SyncOptions.RepositorySourcesToTry.Add(RepositoryAddress.Create(CstrNetworkDriveName, strSharedNetworkUrl));
                    }

                    dlg.Text = "Synchronizing OneStory Project: " + strProjectName;
                    dlg.ShowDialog();
                }
            }
            else if (!bIsOpening)
            {
                // even if the user doesn't want to go to the internet, we
                //  at least want to back up locally (when the user closes)
                using (var dlg = new SyncDialog(projectConfig,
                                                SyncUIDialogBehaviors.StartImmediatelyAndCloseWhenFinished,
                                                SyncUIFeatures.Minimal))
                {
                    dlg.Text = "OneStory Automatic Backup";
                    dlg.SyncOptions.DoMergeWithOthers = false;
                    dlg.SyncOptions.DoPullFromOthers  = false;
                    dlg.SyncOptions.DoSendToOthers    = false;
                    dlg.ShowDialog();
                }
            }
        }
Example #15
0
        public void UpdateToLongHashOnNonEmptyRepoReturns_UpdateResults_Success()
        {
            using (var testRoot = new TemporaryFolder("RepositoryTests"))
            {
                var progress = new NullProgress();
                HgRepository.CreateRepositoryInExistingDir(testRoot.Path, progress);
                // fileX and fileXRev are zero based indexing, since those local commit numbers in Hg are zero based indexing.
                using (var file0 = testRoot.GetNewTempFile(true))
                {
                    var repo = new HgRepository(testRoot.Path, new NullProgress());

                    repo.AddAndCheckinFile(file0.Path);
                    var file0Rev = repo.GetRevisionWorkingSetIsBasedOn();
                    using (var file1 = testRoot.GetNewTempFile(true))
                    {
                        // On same branch.
                        repo.AddAndCheckinFile(file1.Path);
                        var file1Rev = repo.GetRevisionWorkingSetIsBasedOn();
                        using (var file2 = testRoot.GetNewTempFile(true))
                        {
                            // Make new branch.
                            repo.BranchingHelper.Branch(progress, "newbranch");
                            repo.AddAndCheckinFile(file2.Path);
                            var file2Rev = repo.GetRevisionWorkingSetIsBasedOn();

                            // Round 1: update from rev 0 to rev 2.
                            // Switch back to rev 0, using old method.
                            repo.Update("0");
                            var testRev = repo.GetRevisionWorkingSetIsBasedOn();
                            // It did move.
                            Assert.That(testRev.Number.LongHash, Is.EqualTo(file0Rev.Number.LongHash));
                            Assert.That(testRev.Branch, Is.EqualTo(string.Empty));                             // default branch returns string.Empty in mercurial.
                            // SUT
                            Assert.That(repo.UpdateToLongHash(file2Rev.Number.LongHash), Is.EqualTo(HgRepository.UpdateResults.Success));
                            testRev = repo.GetRevisionWorkingSetIsBasedOn();
                            Assert.That(testRev.Number.LongHash, Is.EqualTo(file2Rev.Number.LongHash));
                            Assert.That(testRev.Branch, Is.EqualTo("newbranch"));

                            // Round 2: update from rev 1 to rev 2.
                            // Set up for another pass to update to file2Rev from file3Rev
                            // Switch back to rev 1 (default branch), using old method.
                            repo.Update("1");
                            testRev = repo.GetRevisionWorkingSetIsBasedOn();
                            // It did move.
                            Assert.That(testRev.Number.LongHash, Is.EqualTo(file1Rev.Number.LongHash));
                            Assert.That(testRev.Branch, Is.EqualTo(string.Empty));                             // default branch returns string.Empty in mercurial.
                            // SUT
                            Assert.That(repo.UpdateToLongHash(file2Rev.Number.LongHash), Is.EqualTo(HgRepository.UpdateResults.Success));
                            testRev = repo.GetRevisionWorkingSetIsBasedOn();
                            Assert.That(testRev.Number.LongHash, Is.EqualTo(file2Rev.Number.LongHash));
                            Assert.That(testRev.Branch, Is.EqualTo("newbranch"));

                            // Round 3: downgrade from rev 2 to rev 0.
                            // Set up for another pass to update to file0Rev from file2Rev
                            // Switch back to rev 2 (newbranch branch), using old method.
                            repo.Update("2");
                            testRev = repo.GetRevisionWorkingSetIsBasedOn();
                            // It did move.
                            Assert.That(testRev.Number.LongHash, Is.EqualTo(file2Rev.Number.LongHash));
                            Assert.That(testRev.Branch, Is.EqualTo("newbranch"));
                            // SUT
                            Assert.That(repo.UpdateToLongHash(file0Rev.Number.LongHash), Is.EqualTo(HgRepository.UpdateResults.Success));
                            testRev = repo.GetRevisionWorkingSetIsBasedOn();
                            Assert.That(testRev.Number.LongHash, Is.EqualTo(file0Rev.Number.LongHash));
                            Assert.That(testRev.Branch, Is.EqualTo(string.Empty));                             // default branch returns string.Empty in mercurial.

                            // Round 4: downgrade from rev 2 to rev 1.
                            // Set up for another pass to update to file2Rev from file1Rev
                            // Switch back to rev 2 (newbranch branch), using old method.
                            repo.Update("2");
                            testRev = repo.GetRevisionWorkingSetIsBasedOn();
                            // It did move.
                            Assert.That(testRev.Number.LongHash, Is.EqualTo(file2Rev.Number.LongHash));
                            Assert.That(testRev.Branch, Is.EqualTo("newbranch"));
                            // SUT
                            Assert.That(repo.UpdateToLongHash(file1Rev.Number.LongHash), Is.EqualTo(HgRepository.UpdateResults.Success));
                            testRev = repo.GetRevisionWorkingSetIsBasedOn();
                            Assert.That(testRev.Number.LongHash, Is.EqualTo(file1Rev.Number.LongHash));
                            Assert.That(testRev.Branch, Is.EqualTo(string.Empty));                             // default branch returns string.Empty in mercurial.

                            // Round 5: downgrade from rev 1 to rev 0.
                            // Set up for another pass to update to file0Rev from file1Rev
                            // Switch back to rev 0 (default branch), using old method.
                            repo.Update("1");
                            testRev = repo.GetRevisionWorkingSetIsBasedOn();
                            // It did move.
                            Assert.That(testRev.Number.LongHash, Is.EqualTo(file1Rev.Number.LongHash));
                            Assert.That(testRev.Branch, Is.EqualTo(string.Empty));                             // default branch returns string.Empty in mercurial.
                            // SUT
                            Assert.That(repo.UpdateToLongHash(file0Rev.Number.LongHash), Is.EqualTo(HgRepository.UpdateResults.Success));
                            testRev = repo.GetRevisionWorkingSetIsBasedOn();
                            Assert.That(testRev.Number.LongHash, Is.EqualTo(file0Rev.Number.LongHash));
                            Assert.That(testRev.Branch, Is.EqualTo(string.Empty));                             // default branch returns string.Empty in mercurial.
                        }
                    }
                }
            }
        }
Example #16
0
        public void MakePdf(PdfMakingSpecs specs, Control owner, BackgroundWorker worker,
                            DoWorkEventArgs doWorkEventArgs)
        {
            _worker = worker;
#if !__MonoCS__
            // Mono doesn't current provide System.Printing.  Leave the 'if' here to emphasize the
            // system specific nature of the following check.
            if (Platform.IsWindows)
            {
                // Check whether we have a default printer set (or for that matter, any printers).
                // Gecko on Windows requires a default printer for any print operation, even one
                // to a file.  See https://jira.sil.org/browse/BL-1237.
                string errorMessage = null;
                System.Printing.LocalPrintServer printServer = null;
                try
                {
                    printServer = new System.Printing.LocalPrintServer();
                }
                catch (Exception)                 // System.Printing.PrintQueueException isn't in our System.Printing assembly, so... using Exception
                {
                    // http://issues.bloomlibrary.org/youtrack/issue/BL-4060
                    Logger.WriteEvent("reproduced BL-4060 when trying to create LocalPrinterServer");
                }
                if (printServer == null || !printServer.GetPrintQueues().Any())
                {
                    errorMessage = GetNoDefaultPrinterErrorMessage();
                }
                else
                {
                    System.Printing.PrintQueue defaultPrinter;
                    // BL-2535 it's possible get past the above printQueues.Any() but then get
                    // a System.Printing.PrintQueueException exception with "Access Denied" error here, if
                    // the default printer for some reason is no longer "allowed".
                    try
                    {
                        defaultPrinter = System.Printing.LocalPrintServer.GetDefaultPrintQueue();

                        if (defaultPrinter == null || String.IsNullOrEmpty(defaultPrinter.FullName))
                        {
                            errorMessage = GetNoDefaultPrinterErrorMessage();
                        }
                    }
                    catch (Exception error)                    // System.Printing.PrintQueueException isn't in our System.Printing assembly, so... using Exception
                    {
                        defaultPrinter = null;
                        errorMessage   = L10NSharp.LocalizationManager.GetString(@"PublishTab.PDF.Error.PrinterError",
                                                                                 "Bloom requires access to a printer in order to make a PDF, even though you are not printing.  Windows gave this error when Bloom tried to access the default printer: {0}",
                                                                                 @"Error message displayed in a message dialog box");
                        errorMessage = string.Format(errorMessage, error.Message);
                    }
                }

                if (errorMessage != null)
                {
                    var exception = new ApplicationException(errorMessage);
                    // Note that if we're being run by a BackgroundWorker, it will catch the exception.
                    // If not, but the caller provides a DoWorkEventArgs, pass the exception through
                    // that object rather than throwing it.
                    if (worker != null || doWorkEventArgs == null)
                    {
                        throw exception;
                    }
                    doWorkEventArgs.Result = exception;
                    return;
                }
            }
#endif
            if (_worker != null)
            {
                _worker.ReportProgress(0, L10NSharp.LocalizationManager.GetString(@"PublishTab.PdfMaker.MakingFromHtml",
                                                                                  "Making PDF from HTML",
                                                                                  @"Message displayed in a progress report dialog box"));
            }

            var    runner = new CommandLineRunner();
            string exePath;
            var    bldr = new StringBuilder();
            // Codebase is reliable even when Resharper copies the EXE somewhere else for testing.
            var execDir       = BloomFileLocator.GetCodeBaseFolder();
            var fromDirectory = String.Empty;
            var filePath      = Path.Combine(execDir, "BloomPdfMaker.exe");
            if (!RobustFile.Exists(filePath))
            {
                var msg = LocalizationManager.GetString("InstallProblem.BloomPdfMaker",
                                                        "A component of Bloom, BloomPdfMaker.exe, seems to be missing. This prevents previews and printing. Antivirus software sometimes does this. You may need technical help to repair the Bloom installation and protect this file from being deleted again.");
                throw new FileNotFoundException(msg, "BloomPdfMaker.exe");                 // must be this class to trigger the right reporting mechanism.
            }
            if (Platform.IsMono)
            {
                exePath = Path.ChangeExtension(filePath, "sh");
            }
            else
            {
                exePath = filePath;
            }

            SetArguments(bldr, specs);
            var arguments = bldr.ToString();
            var progress  = new NullProgress();
            var res       = runner.Start(exePath, arguments, Encoding.UTF8, fromDirectory, 3600, progress,
                                         ProcessGeckofxReporting);
            if (res.DidTimeOut || !RobustFile.Exists(specs.OutputPdfPath))
            {
                Logger.WriteEvent(@"***ERROR PDF generation failed: res.StandardOutput = " + res.StandardOutput);

                var msg = L10NSharp.LocalizationManager.GetString(@"PublishTab.PDF.Error.Failed",
                                                                  "Bloom was not able to create the PDF file ({0}).{1}{1}Details: BloomPdfMaker (command line) did not produce the expected document.",
                                                                  @"Error message displayed in a message dialog box. {0} is the filename, {1} is a newline character.");

                // This message string is intentionally separate because it was added after the previous string had already been localized in most languages.
                // It's not useful to add if we're already in save memory mode.
                var msg2 = specs.SaveMemoryMode ? "" : L10NSharp.LocalizationManager.GetString(@"PublishTab.PDF.Error.TrySinglePage",
                                                                                               "The book's images might have exceeded the amount of RAM memory available. Please turn on the \"Use Less Memory\" option which is slower but uses less memory.",
                                                                                               @"Error message displayed in a message dialog box") + Environment.NewLine;

                var fullMsg = String.Format(msg, specs.OutputPdfPath, Environment.NewLine) + Environment.NewLine +
                              msg2 + res.StandardOutput;

                var except = new ApplicationException(fullMsg);
                // Note that if we're being run by a BackgroundWorker, it will catch the exception.
                // If not, but the caller provides a DoWorkEventArgs, pass the exception through
                // that object rather than throwing it.
                if (worker != null || doWorkEventArgs == null)
                {
                    throw except;
                }
                else
                {
                    doWorkEventArgs.Result = except;
                }
            }
        }
        private void MakeAceByDaisyReport(ApiRequest request)
        {
            // First check whether ace has been installed.
            var daisyDirectory = FindAceByDaisyOrTellUser(request);             // this method does the request.fail() if needed

            if (string.IsNullOrEmpty(daisyDirectory))
            {
                return;
            }
            // As of version 1.0.2, the ace report has stylesheets on the internet.  See https://issues.bloomlibrary.org/youtrack/issue/BL-6118.
            // To be specific, https://cdn.datatables.net/1.10.15/css/dataTables.bootstrap4.min.css and
            // https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css.
            if (!UrlLookup.CheckGeneralInternetAvailability(true))
            {
                _webSocketProgress.ErrorWithoutLocalizing(
                    "Sorry, you must have an internet connection in order to view the Ace by DAISY report.");
                request.Failed();
                return;
            }

            var reportRootDirectory = Path.Combine(System.IO.Path.GetTempPath(), "daisy-ace-reports");

            // Do our best at clearing out previous runs.
            // This call is ok if the directory does not exist at all.
            SIL.IO.RobustIO.DeleteDirectoryAndContents(reportRootDirectory);
            // This call is ok if the above failed and it still exists
            Directory.CreateDirectory(reportRootDirectory);

            // was having a problem with some files from previous reports getting locked.
            // so give new folder names if needed
            var haveReportedError = false;
            var errorMessage      = "Unknown Error";

            var version = GetAceByDaisyVersion(daisyDirectory);

            if (version.old)
            {
                _webSocketProgress.MessageWithoutLocalizing(
                    $"You appear to have an older version ({version.version}) of ACE by Daisy. This may cause problems.",
                    ProgressKind.Warning);
                _webSocketProgress.MessageWithoutLocalizing(
                    "We recommend you run \"npm install @daisy/ace -g\" from a command line to get the latest.",
                    ProgressKind.Warning);
            }

            var started = DateTime.Now;

            var epubPath = MakeEpub(reportRootDirectory, _webSocketProgress);

            // Try 3 times. It could be that this is no longer needed, but working on a developer
            // machine isn't proof.
            for (var i = 0; i < 3; i++)
            {
                var randomName      = Guid.NewGuid().ToString();
                var reportDirectory = Path.Combine(reportRootDirectory, randomName);

                var       arguments             = $"ace.js --verbose -o \"{reportDirectory}\" \"{epubPath}\"";
                const int kSecondsBeforeTimeout = 60;
                var       progress = new NullProgress();
                _webSocketProgress.MessageWithoutLocalizing("Running Ace by DAISY");

                ExecutionResult res    = null;
                string          ldpath = null;
                try
                {
                    // Without this variable switching on Linux, the chrome inside ace finds the
                    // wrong version of a library as part of our mozilla code.
                    ldpath = Environment.GetEnvironmentVariable("LD_LIBRARY_PATH");
                    Environment.SetEnvironmentVariable("LD_LIBRARY_PATH", null);
                    res = CommandLineRunner.Run("node", arguments, Encoding.UTF8, daisyDirectory, kSecondsBeforeTimeout,
                                                progress,
                                                (dummy) => { });
                }
                finally
                {
                    // Restore the variable for our next geckofx browser to find.
                    if (!String.IsNullOrEmpty(ldpath))
                    {
                        Environment.SetEnvironmentVariable("LD_LIBRARY_PATH", ldpath);
                    }
                }

                if (res.DidTimeOut)
                {
                    errorMessage = $"Daisy Ace timed out after {kSecondsBeforeTimeout} seconds.";
                    _webSocketProgress.ErrorWithoutLocalizing(errorMessage);
                    continue;
                }

                var answerPath = Path.Combine(reportDirectory, "report.html");
                if (!File.Exists(answerPath))
                {
                    // This hasn't been effectively reproduced, but there was a case where this would fail at least
                    // half the time on a book, reproducable. That book had 2 pages pointing at placeholder.png,
                    // and we were getting an error related to it being locked. So we deduce that ace was trying
                    // to copy the file twice, at the same time (normal nodejs code is highly async).
                    // Now the problem is not reproducable, but I'm leaving in this code that tried to deal with it.
                    errorMessage = $"Exit code{res.ExitCode}{Environment.NewLine}" +
                                   $"Standard Error{Environment.NewLine}{res.StandardError}{Environment.NewLine}" +
                                   $"Standard Out{res.StandardOutput}";

                    _webSocketProgress.ErrorWithoutLocalizing(errorMessage);

                    continue;                     // something went wrong, try again
                }

                // The html client is set to treat a text reply as a url of the report. Make sure it's valid for being a URL.
                // See https://silbloom.myjetbrains.com/youtrack/issue/BL-6197.
                request.ReplyWithText("/bloom/" + answerPath.EscapeFileNameForHttp());
                if (version.old)
                {
                    // If we displayed an important message about updating ACE, make sure the user
                    // has SOME time to see it.
                    // Review: is this long enough? Should we look for some other way to show the
                    // problem? At present the problems caused by an old version (1.1 is the oldest
                    // contemporary with Bloom) is fairly minor.
                    while (DateTime.Now - started < new TimeSpan(0, 0, 0, 5))
                    {
                        Thread.Sleep(100);
                    }
                }
                return;
            }

            // If we get this far, we give up.
            ReportErrorAndFailTheRequest(request, errorMessage);
        }
Example #18
0
        public void UpdateToBranchHeadCallsReturnExpected_UpdateResults()
        {
            using (var testRoot = new TemporaryFolder("RepositoryTests"))
            {
                var progress = new NullProgress();
                HgRepository.CreateRepositoryInExistingDir(testRoot.Path, progress);
                // fileX and fileXRev are zero based indexing, since those local commit numbers in Hg are zero based indexing.
                using (var file0 = testRoot.GetNewTempFile(true))
                {
                    var repo = new HgRepository(testRoot.Path, new NullProgress());

                    // SUT
                    Assert.That(repo.UpdateToBranchHead("fakebranchname"), Is.EqualTo(HgRepository.UpdateResults.NoCommitsInRepository));

                    repo.AddAndCheckinFile(file0.Path);
                    var file0Rev = repo.GetRevisionWorkingSetIsBasedOn();

                    // SUT
                    Assert.That(repo.UpdateToBranchHead(file0Rev.Branch), Is.EqualTo(HgRepository.UpdateResults.AlreadyOnIt));

                    // SUT
                    Assert.That(repo.UpdateToBranchHead("NoSuchBranch"), Is.EqualTo(HgRepository.UpdateResults.NoSuchBranch));

                    using (var file1 = testRoot.GetNewTempFile(true))
                    {
                        // Make new branch.
                        repo.BranchingHelper.Branch(progress, "newbranch");
                        repo.AddAndCheckinFile(file1.Path);
                        var file1Rev = repo.GetRevisionWorkingSetIsBasedOn();
                        Assert.That(repo.UpdateToBranchHead(file1Rev.Branch), Is.EqualTo(HgRepository.UpdateResults.AlreadyOnIt));

                        // Go back to commit 0 and create another "newbranch", which should then be a two headed monster.
                        repo.Update("0");
                        repo.BranchingHelper.Branch(progress, "newbranch");
                        File.WriteAllText(file1.Path, @"new contents");
                        repo.Commit(true, "Force double headed branch");
                        var heads = repo.GetHeads().ToList();
                        Assert.That(heads.Count, Is.EqualTo(3));

                        // SUT
                        Assert.That(repo.UpdateToBranchHead(file1Rev.Branch), Is.EqualTo(HgRepository.UpdateResults.AlreadyOnIt));
                        var testRev = repo.GetRevisionWorkingSetIsBasedOn();
                        Assert.That(testRev.Branch, Is.EqualTo("newbranch"));
                        Assert.That(testRev.Number.LocalRevisionNumber, Is.EqualTo("2"));

                        // Switch to older head of 'newbranch'
                        // (Goes from rev 2 back to rev 1, both of which are on the same branch (newbranch).)
                        repo.Update("1");

                        // SUT
                        // Returns "Success", because we moved from rev 1 to rev 2 (higher rev number) in the same branch, which branch has two heads.)
                        Assert.That(repo.UpdateToBranchHead(file1Rev.Branch), Is.EqualTo(HgRepository.UpdateResults.Success));
                        testRev = repo.GetRevisionWorkingSetIsBasedOn();
                        Assert.That(testRev.Branch, Is.EqualTo("newbranch"));
                        Assert.That(testRev.Number.LocalRevisionNumber, Is.EqualTo("2"));

                        // Switch to commit 0.
                        repo.Update("0");
                        testRev = repo.GetRevisionWorkingSetIsBasedOn();
                        Assert.That(testRev.Branch, Is.EqualTo(string.Empty));
                        Assert.That(testRev.Number.LocalRevisionNumber, Is.EqualTo("0"));

                        // SUT
                        Assert.That(repo.UpdateToBranchHead(file1Rev.Branch), Is.EqualTo(HgRepository.UpdateResults.Success));
                        testRev = repo.GetRevisionWorkingSetIsBasedOn();
                        Assert.That(testRev.Branch, Is.EqualTo("newbranch"));
                        Assert.That(testRev.Number.LocalRevisionNumber, Is.EqualTo("2"));
                    }
                }
            }
        }