From e20bee14dda37241ac0115c20d33a6e66296d35d Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Sat, 21 Apr 2012 14:20:55 +0100 Subject: [PATCH] When creating a service reference use and update the app.config file that is open in the text editor. --- .../Project/ICSharpCode.SharpDevelop.csproj | 2 + .../ServiceReference/ActiveTextEditors.cs | 45 +++++ .../ServiceReference/IActiveTextEditors.cs | 14 ++ .../ServiceReference/IFileSystem.cs | 4 + .../IServiceReferenceProxyGenerator.cs | 2 + .../ServiceReferenceFileGenerator.cs | 5 + .../ServiceReferenceFileSystem.cs | 23 +++ .../ServiceReferenceGenerator.cs | 54 +++++- .../ServiceReferenceProxyGenerator.cs | 10 + .../ServiceReference/SvcUtilRunner.cs | 15 +- .../ServiceReferenceGeneratorTests.cs | 175 +++++++++++++++++- 11 files changed, 343 insertions(+), 6 deletions(-) create mode 100644 src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/ActiveTextEditors.cs create mode 100644 src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/IActiveTextEditors.cs diff --git a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj index 7c06c5241f..036b53695b 100644 --- a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj +++ b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj @@ -261,6 +261,7 @@ + AddServiceReferenceDialog.xaml Code @@ -272,6 +273,7 @@ + diff --git a/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/ActiveTextEditors.cs b/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/ActiveTextEditors.cs new file mode 100644 index 0000000000..d11256eb8b --- /dev/null +++ b/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/ActiveTextEditors.cs @@ -0,0 +1,45 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using ICSharpCode.SharpDevelop.Editor; + +namespace ICSharpCode.SharpDevelop.Gui.Dialogs.ReferenceDialog.ServiceReference +{ + public class ActiveTextEditors : IActiveTextEditors + { + public string GetTextForOpenFile(string fileName) + { + ITextEditor textEditor = GetTextEditor(fileName); + if (textEditor != null) { + return textEditor.Document.Text; + } + return null; + } + + ITextEditor GetTextEditor(string fileName) + { + IViewContent viewContent = FileService.GetOpenFile(fileName); + var textEditorProvider = viewContent as ITextEditorProvider; + if (textEditorProvider != null) { + return textEditorProvider.TextEditor; + } + return null; + } + + public void UpdateTextForOpenFile(string fileName, string text) + { + ITextEditor textEditor = GetTextEditor(fileName); + if (textEditor != null) { + using (IDisposable undoGroup = textEditor.Document.OpenUndoGroup()) { + textEditor.Document.Text = text; + } + } + } + + public bool IsFileOpen(string fileName) + { + return FileService.IsOpen(fileName); + } + } +} diff --git a/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/IActiveTextEditors.cs b/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/IActiveTextEditors.cs new file mode 100644 index 0000000000..606856c24d --- /dev/null +++ b/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/IActiveTextEditors.cs @@ -0,0 +1,14 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; + +namespace ICSharpCode.SharpDevelop.Gui.Dialogs.ReferenceDialog.ServiceReference +{ + public interface IActiveTextEditors + { + string GetTextForOpenFile(string fileName); + void UpdateTextForOpenFile(string fileName, string text); + bool IsFileOpen(string fileName); + } +} diff --git a/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/IFileSystem.cs b/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/IFileSystem.cs index 1614e97327..03dbaa0f5e 100644 --- a/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/IFileSystem.cs +++ b/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/IFileSystem.cs @@ -8,5 +8,9 @@ namespace ICSharpCode.SharpDevelop.Gui.Dialogs.ReferenceDialog.ServiceReference public interface IFileSystem { void CreateDirectoryIfMissing(string path); + string CreateTempFile(string text); + string ReadAllFileText(string fileName); + void DeleteFile(string fileName); + void WriteAllText(string fileName, string text); } } diff --git a/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/IServiceReferenceProxyGenerator.cs b/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/IServiceReferenceProxyGenerator.cs index e5eab2f37b..3dbe51caf7 100644 --- a/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/IServiceReferenceProxyGenerator.cs +++ b/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/IServiceReferenceProxyGenerator.cs @@ -10,5 +10,7 @@ namespace ICSharpCode.SharpDevelop.Gui.Dialogs.ReferenceDialog.ServiceReference { ServiceReferenceGeneratorOptions Options { get; set; } void GenerateProxyFile(); + + event EventHandler Complete; } } diff --git a/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/ServiceReferenceFileGenerator.cs b/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/ServiceReferenceFileGenerator.cs index ba54756fca..a970b0eaf2 100644 --- a/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/ServiceReferenceFileGenerator.cs +++ b/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/ServiceReferenceFileGenerator.cs @@ -40,5 +40,10 @@ namespace ICSharpCode.SharpDevelop.Gui.Dialogs.ReferenceDialog.ServiceReference { mapGenerator.GenerateServiceReferenceMapFile(mapFile); } + + public event EventHandler Complete { + add { proxyGenerator.Complete += value; } + remove { proxyGenerator.Complete += value; } + } } } diff --git a/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/ServiceReferenceFileSystem.cs b/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/ServiceReferenceFileSystem.cs index 1455e129c1..523931707d 100644 --- a/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/ServiceReferenceFileSystem.cs +++ b/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/ServiceReferenceFileSystem.cs @@ -14,5 +14,28 @@ namespace ICSharpCode.SharpDevelop.Gui.Dialogs.ReferenceDialog.ServiceReference Directory.CreateDirectory(path); } } + + public string CreateTempFile(string text) + { + string folder = Path.GetTempPath(); + string fileName = Path.Combine(folder, "app.config"); + File.WriteAllText(fileName, text); + return fileName; + } + + public string ReadAllFileText(string fileName) + { + return File.ReadAllText(fileName); + } + + public void DeleteFile(string fileName) + { + File.Delete(fileName); + } + + public void WriteAllText(string fileName, string text) + { + File.WriteAllText(fileName, text); + } } } diff --git a/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/ServiceReferenceGenerator.cs b/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/ServiceReferenceGenerator.cs index 2ac5a1942e..5d1d706b71 100644 --- a/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/ServiceReferenceGenerator.cs +++ b/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/ServiceReferenceGenerator.cs @@ -16,6 +16,8 @@ namespace ICSharpCode.SharpDevelop.Gui.Dialogs.ReferenceDialog.ServiceReference IProjectWithServiceReferences project; IServiceReferenceFileGenerator fileGenerator; IFileSystem fileSystem; + IActiveTextEditors activeTextEditors; + string tempAppConfigFileName; public ServiceReferenceGenerator(IProject project) : this(new ProjectWithServiceReferences(project)) @@ -26,18 +28,21 @@ namespace ICSharpCode.SharpDevelop.Gui.Dialogs.ReferenceDialog.ServiceReference : this( project, new ServiceReferenceFileGenerator(), - new ServiceReferenceFileSystem()) + new ServiceReferenceFileSystem(), + new ActiveTextEditors()) { } public ServiceReferenceGenerator( IProjectWithServiceReferences project, IServiceReferenceFileGenerator fileGenerator, - IFileSystem fileSystem) + IFileSystem fileSystem, + IActiveTextEditors activeTextEditors) { this.project = project; this.fileGenerator = fileGenerator; this.fileSystem = fileSystem; + this.activeTextEditors = activeTextEditors; } public ServiceReferenceGeneratorOptions Options { @@ -68,18 +73,38 @@ namespace ICSharpCode.SharpDevelop.Gui.Dialogs.ReferenceDialog.ServiceReference ServiceReferenceFileName referenceFileName = project.GetServiceReferenceFileName(fileGenerator.Options.ServiceName); CreateFolderForFileIfFolderMissing(referenceFileName.Path); + CreateTempAppConfigFileIfOpenInTextEditor(); + Options.OutputFileName = referenceFileName.Path; - Options.AppConfigFileName = project.GetAppConfigFileName(); + Options.AppConfigFileName = GetAppConfigFileName(); Options.NoAppConfig = false; Options.MergeAppConfig = project.HasAppConfigFile(); Options.MapProjectLanguage(project.Language); Options.GenerateNamespace(project.RootNamespace); Options.AddProjectReferencesIfUsingTypesFromProjectReferences(project.GetReferences()); + + fileGenerator.Complete += ProxyFileGenerationComplete; fileGenerator.GenerateProxyFile(); return referenceFileName; } + string GetAppConfigFileName() + { + if (tempAppConfigFileName != null) { + return tempAppConfigFileName; + } + return project.GetAppConfigFileName(); + } + + void CreateTempAppConfigFileIfOpenInTextEditor() + { + string appConfigText = activeTextEditors.GetTextForOpenFile(project.GetAppConfigFileName()); + if (appConfigText != null) { + tempAppConfigFileName = fileSystem.CreateTempFile(appConfigText); + } + } + ServiceReferenceMapFileName CreateServiceReferenceMapFile() { ServiceReferenceMapFileName mapFileName = project.GetServiceReferenceMapFileName(fileGenerator.Options.ServiceName); @@ -94,6 +119,29 @@ namespace ICSharpCode.SharpDevelop.Gui.Dialogs.ReferenceDialog.ServiceReference fileSystem.CreateDirectoryIfMissing(folder); } + void ProxyFileGenerationComplete(object sender, EventArgs e) + { + if (tempAppConfigFileName != null) { + UpdateAppConfigInTextEditor(); + DeleteTempAppConfigFile(); + } + } + + void DeleteTempAppConfigFile() + { + fileSystem.DeleteFile(tempAppConfigFileName); + } + + void UpdateAppConfigInTextEditor() + { + string text = fileSystem.ReadAllFileText(tempAppConfigFileName); + if (activeTextEditors.IsFileOpen(project.GetAppConfigFileName())) { + activeTextEditors.UpdateTextForOpenFile(project.GetAppConfigFileName(), text); + } else { + fileSystem.WriteAllText(project.GetAppConfigFileName(), text); + } + } + public IEnumerable GetCheckableAssemblyReferences() { return GetUnsortedCheckableAssemblyReferences() diff --git a/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/ServiceReferenceProxyGenerator.cs b/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/ServiceReferenceProxyGenerator.cs index c56892b146..ccaae41cac 100644 --- a/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/ServiceReferenceProxyGenerator.cs +++ b/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/ServiceReferenceProxyGenerator.cs @@ -20,7 +20,17 @@ namespace ICSharpCode.SharpDevelop.Gui.Dialogs.ReferenceDialog.ServiceReference public void GenerateProxyFile() { var runner = new SvcUtilRunner(options); + runner.ProcessExited += OnComplete; runner.Run(); } + + public event EventHandler Complete; + + void OnComplete(object sender, EventArgs e) + { + if (Complete != null) { + Complete(this, e); + } + } } } diff --git a/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/SvcUtilRunner.cs b/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/SvcUtilRunner.cs index 072af8617e..c33cbf0632 100644 --- a/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/SvcUtilRunner.cs +++ b/src/Main/Base/Project/Src/Gui/Dialogs/ReferenceDialog/ServiceReference/SvcUtilRunner.cs @@ -13,6 +13,8 @@ namespace ICSharpCode.SharpDevelop.Gui.Dialogs.ReferenceDialog.ServiceReference this.Options = options; } + public event EventHandler ProcessExited; + public ServiceReferenceGeneratorOptions Options { get; private set; } public void Run() @@ -48,7 +50,7 @@ namespace ICSharpCode.SharpDevelop.Gui.Dialogs.ReferenceDialog.ServiceReference runner.LogStandardOutputAndError = false; runner.OutputLineReceived += LineReceived; runner.ErrorLineReceived += LineReceived; - runner.ProcessExited += ProcessExited; + runner.ProcessExited += SvcUtilProcessExited; return runner; } @@ -57,9 +59,18 @@ namespace ICSharpCode.SharpDevelop.Gui.Dialogs.ReferenceDialog.ServiceReference SvcUtilMessageView.AppendLine(e.Line); } - void ProcessExited(object sender, EventArgs e) + void SvcUtilProcessExited(object sender, EventArgs e) { SvcUtilMessageView.AppendLine("SvcUtil finished."); + + WorkbenchSingleton.SafeThreadAsyncCall(() => OnProcessExited()); + } + + void OnProcessExited() + { + if (ProcessExited != null) { + ProcessExited(this, new EventArgs()); + } } } } diff --git a/src/Main/Base/Test/ServiceReferences/ServiceReferenceGeneratorTests.cs b/src/Main/Base/Test/ServiceReferences/ServiceReferenceGeneratorTests.cs index e3fc6565c0..52840a4106 100644 --- a/src/Main/Base/Test/ServiceReferences/ServiceReferenceGeneratorTests.cs +++ b/src/Main/Base/Test/ServiceReferences/ServiceReferenceGeneratorTests.cs @@ -23,6 +23,7 @@ namespace ICSharpCode.SharpDevelop.Tests.ServiceReferences IFileSystem fakeFileSystem; ServiceReferenceGeneratorOptions options; List projectReferences; + IActiveTextEditors fakeActiveTextEditors; void CreateGenerator() { @@ -35,8 +36,9 @@ namespace ICSharpCode.SharpDevelop.Tests.ServiceReferences fakeReferenceMapGenerator = MockRepository.GenerateStub(); fileGenerator = new ServiceReferenceFileGenerator(fakeProxyGenerator, fakeReferenceMapGenerator); fakeFileSystem = MockRepository.GenerateStub(); + fakeActiveTextEditors = MockRepository.GenerateStub(); - generator = new ServiceReferenceGenerator(fakeProject, fileGenerator, fakeFileSystem); + generator = new ServiceReferenceGenerator(fakeProject, fileGenerator, fakeFileSystem, fakeActiveTextEditors); } void SetProjectRootNamespace(string rootNamespace) @@ -133,6 +135,45 @@ namespace ICSharpCode.SharpDevelop.Tests.ServiceReferences return projectItem; } + void AppConfigIsOpenInTextEditor(string fileName, string appConfigText) + { + fakeActiveTextEditors + .Stub(editors => editors.GetTextForOpenFile(fileName)) + .Return(appConfigText); + + fakeActiveTextEditors + .Stub(editors => editors.IsFileOpen(fileName)) + .Return(true); + } + + void AppConfigIsClosedInTextEditor(string fileName) + { + fakeActiveTextEditors.BackToRecord(BackToRecordOptions.All); + fakeActiveTextEditors.Replay(); + fakeActiveTextEditors + .Stub(editors => editors.IsFileOpen(fileName)) + .Return(false); + } + + void SetTempFileNameCreated(string tempFileName) + { + fakeFileSystem.Stub(fs => fs.CreateTempFile(Arg.Is.Anything)) + .Return(tempFileName); + } + + void SvcUtilRunCompleted() + { + fakeProxyGenerator.Raise(g => g.Complete += null, fakeProxyGenerator, new EventArgs()); + } + + void SetTempFileText(string fileName, string text) + { + SetTempFileNameCreated(fileName); + fakeFileSystem + .Stub(fs => fs.ReadAllFileText(fileName)) + .Return(text); + } + [Test] public void AddServiceReference_GeneratesServiceReference_ProxyFileIsGenerated() { @@ -450,5 +491,137 @@ namespace ICSharpCode.SharpDevelop.Tests.ServiceReferences CollectionAssert.AreEqual(expectedAssemblies, generator.Options.Assemblies); } + + [Test] + public void AddServiceReference_AppConfigIsOpenInTextEditor_TempFileCreatedWithAppConfigText() + { + CreateGenerator(); + AddProxyFileNameForServiceName("MyService"); + AddMapFileNameForServiceName("MyService"); + generator.Options.ServiceName = "MyService"; + string appConfigFileName = @"d:\projects\MyProject\app.config"; + SetProjectAppConfigFileName(appConfigFileName); + ProjectHasAppConfigFile(); + AppConfigIsOpenInTextEditor(appConfigFileName, "appconfig text"); + + generator.AddServiceReference(); + + fakeFileSystem.AssertWasCalled(fs => fs.CreateTempFile("appconfig text")); + } + + [Test] + public void AddServiceReference_AppConfigIsNotOpenInTextEditor_TempFileNotCreated() + { + CreateGenerator(); + AddProxyFileNameForServiceName("MyService"); + AddMapFileNameForServiceName("MyService"); + generator.Options.ServiceName = "MyService"; + string appConfigFileName = @"d:\projects\MyProject\app.config"; + SetProjectAppConfigFileName(appConfigFileName); + ProjectHasAppConfigFile(); + + generator.AddServiceReference(); + + fakeFileSystem.AssertWasNotCalled(fs => fs.CreateTempFile(Arg.Is.Anything)); + } + + [Test] + public void AddServiceReference_AppConfigIsOpenInTextEditor_TempFileAppConfigPassedUsedWhenGeneratingProxy() + { + CreateGenerator(); + AddProxyFileNameForServiceName("MyService"); + AddMapFileNameForServiceName("MyService"); + generator.Options.ServiceName = "MyService"; + string appConfigFileName = @"d:\projects\MyProject\app.config"; + SetProjectAppConfigFileName(appConfigFileName); + ProjectHasAppConfigFile(); + AppConfigIsOpenInTextEditor(appConfigFileName, "appconfig text"); + SetTempFileNameCreated(@"d:\temp\test.tmp"); + + generator.AddServiceReference(); + + Assert.AreEqual(@"d:\temp\test.tmp", fakeProxyGenerator.Options.AppConfigFileName); + } + + [Test] + public void AddServiceReference_AppConfigIsOpenInTextEditorAndSvcUtilHasFinished_TempFileAppConfigContentReplacesTextInTextEditor() + { + CreateGenerator(); + AddProxyFileNameForServiceName("MyService"); + AddMapFileNameForServiceName("MyService"); + generator.Options.ServiceName = "MyService"; + string appConfigFileName = @"d:\projects\MyProject\app.config"; + SetProjectAppConfigFileName(appConfigFileName); + ProjectHasAppConfigFile(); + AppConfigIsOpenInTextEditor(appConfigFileName, "appconfig text"); + SetTempFileText(@"d:\temp\test.tmp", "New appconfig text"); + + generator.AddServiceReference(); + + SvcUtilRunCompleted(); + + fakeActiveTextEditors.AssertWasCalled(editors => editors.UpdateTextForOpenFile(appConfigFileName, "New appconfig text")); + } + + [Test] + public void AddServiceReference_AppConfigIsNotOpenInTextEditor_TextInTextEditorNotUpdated() + { + CreateGenerator(); + AddProxyFileNameForServiceName("MyService"); + AddMapFileNameForServiceName("MyService"); + generator.Options.ServiceName = "MyService"; + string appConfigFileName = @"d:\projects\MyProject\app.config"; + SetProjectAppConfigFileName(appConfigFileName); + ProjectHasAppConfigFile(); + + generator.AddServiceReference(); + + SvcUtilRunCompleted(); + + fakeActiveTextEditors.AssertWasNotCalled(editors => editors.UpdateTextForOpenFile(Arg.Is.Anything, Arg.Is.Anything)); + } + + [Test] + public void AddServiceReference_AppConfigIsOpenInTextEditorAndSvcUtilHasFinished_TempFileIsDeleted() + { + CreateGenerator(); + AddProxyFileNameForServiceName("MyService"); + AddMapFileNameForServiceName("MyService"); + generator.Options.ServiceName = "MyService"; + string appConfigFileName = @"d:\projects\MyProject\app.config"; + SetProjectAppConfigFileName(appConfigFileName); + ProjectHasAppConfigFile(); + AppConfigIsOpenInTextEditor(appConfigFileName, "appconfig text"); + SetTempFileNameCreated(@"d:\temp\test.tmp"); + + generator.AddServiceReference(); + + SvcUtilRunCompleted(); + + fakeFileSystem.AssertWasCalled(fs => fs.DeleteFile(@"d:\temp\test.tmp")); + } + + [Test] + public void AddServiceReference_AppConfigIsOriginallyOpenInTextEditorButIsClosedWhenSvcUtilHasFinished_TempFileAppConfigContentReplacesAppConfigOnFileSystem() + { + CreateGenerator(); + AddProxyFileNameForServiceName("MyService"); + AddMapFileNameForServiceName("MyService"); + generator.Options.ServiceName = "MyService"; + string appConfigFileName = @"d:\projects\MyProject\app.config"; + SetProjectAppConfigFileName(appConfigFileName); + ProjectHasAppConfigFile(); + AppConfigIsOpenInTextEditor(appConfigFileName, "appconfig text"); + SetTempFileText(@"d:\temp\test.tmp", "New appconfig text"); + + generator.AddServiceReference(); + + AppConfigIsClosedInTextEditor(appConfigFileName); + + SvcUtilRunCompleted(); + + fakeFileSystem.AssertWasCalled(fs => fs.WriteAllText(appConfigFileName, "New appconfig text")); + fakeActiveTextEditors.AssertWasNotCalled(editors => editors.UpdateTextForOpenFile(Arg.Is.Anything, Arg.Is.Anything)); + } } }