Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

优化 HE 输出以及修复 依赖库无法发出通知的 BUG #343

Merged
merged 1 commit into from
Jul 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,15 @@ void ISourceGenerator.Execute(GeneratorExecutionContext context)

string coreScript = "HEProxy.SetProjectKind(HEProjectKind.Console);";
string winformAndwpfLoggerScript = @"
string debugFilePath = Path.Combine(VSCSharpProjectInfomation.MainCsprojPath,""HEDebug.txt"");
if(File.Exists(debugFilePath)){ File.Delete(debugFilePath); }
string debugFilePath = Path.Combine(VSCSharpProjectInfomation.HEOutputPath,""Debug.txt"");
if (Directory.Exists(VSCSharpProjectInfomation.HEOutputPath))
{
var files = Directory.GetFiles(VSCSharpProjectInfomation.HEOutputPath);
foreach (var file in files)
{
File.Delete(file);
}
}
Comment on lines +21 to +29
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tip

Codebase Verification

Issues found in file deletion logic.

The file deletion logic does not explicitly handle edge cases such as read-only files, hidden files, or files in use. This could lead to incomplete deletion of files in the output path.

  • src/Natasha.CSharp/Extension/HotExecutor/Natasha.CSharp.HotExecutor.SG/HotExecutorGenerator.cs: File deletion logic at line 25.
Analysis chain

Verify the correctness of file deletion logic.

The changes ensure that all files in the output path are deleted before creating a new logger. Verify that the deletion logic handles all edge cases and does not leave any files undeleted.


Verify the robustness of file deletion logic.

The changes ensure that all files in the output path are deleted before creating a new logger. Verify that the deletion logic correctly handles edge cases such as read-only files, hidden files, or files in use.

Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the correctness of file deletion logic.

# Test: Search for the method usage. Expect: Proper deletion of all files in the output path.
rg --type cs 'Directory.GetFiles'

Length of output: 1930


Script:

#!/bin/bash
# Description: Verify the robustness of file deletion logic by checking for edge cases.

# Test: Search for additional handling of edge cases in file deletion logic.
rg --type cs 'File.Delete'

Length of output: 805

HEFileLogger logger = new HEFileLogger(debugFilePath);
HEProxy.ShowMessage = async msg => {
await logger.WriteUtf8FileAsync(msg);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,55 +44,56 @@ internal static class WinformRewriter

if (runNode != null)
{

return blockSyntax.ReplaceNode(runNode, [SyntaxFactory.ParseStatement(@$"
HEProxy.SetAftHotExecut(() =>
{{
Task.Run(() =>
System.Threading.Tasks.Task.Run(() =>
{{
Application.ExitThread();
System.Windows.Forms.Application.ExitThread();
while(!DiposeWindows()){{}};
var __heProxInstance = {runArgumentScript};
Form tempForm;
if (__heProxInstance is Form)
System.Windows.Forms.Form tempForm;
if (__heProxInstance is System.Windows.Forms.Form)
{{
tempForm = ((object)__heProxInstance as Form)!;
tempForm = ((object)__heProxInstance as System.Windows.Forms.Form)!;
}}
else
{{
tempForm = (Form)(typeof(ApplicationContext).GetProperty(""MainForm"")!.GetValue(__heProxInstance)!);
tempForm = (System.Windows.Forms.Form)(typeof(System.Windows.Forms.ApplicationContext).GetProperty(""MainForm"")!.GetValue(__heProxInstance)!);
}}
tempForm.FormClosed += (s, e) =>
{{
if (!HEProxy.IsHotCompiling)
{{
var result = MessageBox.Show(""请确认是否退出主程序?"", ""HotExecutor 提醒"", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning);
if (result.HasFlag(DialogResult.OK))
var result = System.Windows.Forms.MessageBox.Show(""请确认是否退出主程序?"", ""HotExecutor 提醒"", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning);
if (result.HasFlag(System.Windows.Forms.DialogResult.OK))
{{
Application.Exit();
System.Windows.Forms.Application.Exit();
}}
}}
}};

try{{
Application.Run(__heProxInstance);
}}catch(Exception ex)

System.Windows.Forms.Application.Run(__heProxInstance);

}}catch(System.Exception ex)
{{
HEProxy.ShowMessage(ex.Message);
}}

static bool DiposeWindows()
{{
try{{
for (int i = 0; i < Application.OpenForms.Count; i++)
for (int i = 0; i < System.Windows.Forms.Application.OpenForms.Count; i++)
{{
try{{
var form = Application.OpenForms[i];
var form = System.Windows.Forms.Application.OpenForms[i];
if (form!=null)
{{
HEProxy.ShowMessage($""当前将被注销的开放窗体 {{form.Name}}"");
form.Dispose();
DelegateHelper<FormCollection, Form>.Execute.Invoke(Application.OpenForms, form);
Natasha.CSharp.HotExecutor.Component.DelegateHelper<System.Windows.Forms.FormCollection, System.Windows.Forms.Form>.Execute.Invoke(System.Windows.Forms.Application.OpenForms, form);
}}
}}catch{{
}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;

namespace Natasha.CSharp.HotExecutor.Component.SyntaxUtils
Expand All @@ -10,31 +11,50 @@ internal static class WpfWriter
{
public static BlockSyntax? Handle(BlockSyntax blockSyntax)
{
return blockSyntax.WithStatements([SyntaxFactory.ParseStatement(@$"HEProxy.SetAftHotExecut(() => {{
Task.Run(() => {{

while(!DiposeWindows()){{}};
Application.Current.Run();
var mainStatement = SyntaxFactory.ParseStatement(@"

System.Windows.Application.Current.Dispatcher.Invoke(()=>{

while(!DiposeWindows()){};

static bool DiposeWindows()
{{
try{{
for (int i = 0; i < Application.Current.Windows.Count; i++)
{{
var window = Application.Current.Windows[i];
try{{
window.Close();
}}catch{{

}}
}}
}}catch{{
return false;
}}
{
try{
//HEProxy.ShowMessage($""当前将被注销的开放窗体个数 {System.Windows.Application.Current.Windows.Count}"");
for (int i = 0; i < System.Windows.Application.Current.Windows.Count; i++)
{

try{
var window = System.Windows.Application.Current.Windows[i];
window.Dispatcher.Invoke(()=>{ window.Close(); });
}catch{

}
}

}catch(System.Exception ex){

HEProxy.ShowMessage($""出现异常 {ex.GetType()}{ex.Message}"");
if(ex is not System.InvalidOperationException){
return false;
}

}
return true;
}}
}});
}});")]);
}
});
System.Windows.Application.Current.Shutdown();
");

var newStatement = SyntaxFactory.ParseStatement(@$"

HEProxy.SetAftHotExecut(() => {{

{blockSyntax.Statements.ToFullString()}

}});");
Debug.WriteLine(mainStatement.ToFullString());
return blockSyntax.WithStatements([newStatement]);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public static class VSCSharpProjectInfomation
public static readonly HashSet<string> ExpectFiles;
public static readonly bool EnableImplicitUsings;
public static IEnumerable<string>? MainAssemblyUsings;
public static readonly string HEOutputPath;
static VSCSharpProjectInfomation()
{
ExpectFiles = [];
Expand All @@ -29,6 +30,7 @@ static VSCSharpProjectInfomation()
ExecutePath = new FileInfo(currentExeFilePath).Directory!.FullName;
var currentDirectoryInfo = new DirectoryInfo(ExecutePath);
MainCsprojPath = FindFileDirectory(currentDirectoryInfo,"*.csproj");
HEOutputPath = Path.Combine(MainCsprojPath, "HEOutput");
var files = Directory.GetFiles(MainCsprojPath,"*.csproj");
CSProjFilePath = files[0];
BinPath = Path.Combine(MainCsprojPath, "bin");
Expand Down Expand Up @@ -93,9 +95,13 @@ public static bool CheckFileAvailiable(string file)
return CheckFileAvivaliable(file, BinPath, ObjPath);
}

public static bool IsXamlAndResxFile(string file)
{
return file.EndsWith(".xaml") || file.EndsWith(".resx");
}
Comment on lines +98 to +101
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tip

Codebase Verification

Improve the IsXamlAndResxFile method to handle edge cases.

The current implementation does not account for different casing or additional extensions. Consider using StringComparison.OrdinalIgnoreCase to handle case insensitivity and regex to match the exact extensions.

  • Update the method to handle case insensitivity and exact matches for .xaml and .resx files:

    public static bool IsXamlAndResxFile(string file)
    {
        return file.EndsWith(".xaml", StringComparison.OrdinalIgnoreCase) || file.EndsWith(".resx", StringComparison.OrdinalIgnoreCase);
    }
  • Consider using regex for more robust matching:

    using System.Text.RegularExpressions;
    
    public static bool IsXamlAndResxFile(string file)
    {
        return Regex.IsMatch(file, @"\.xaml(\?.*)?$", RegexOptions.IgnoreCase) || Regex.IsMatch(file, @"\.resx(\?.*)?$", RegexOptions.IgnoreCase);
    }
Analysis chain

Verify the correctness of file type check.

The method ensures that the file extension is either .xaml or .resx. Verify that the file type check handles all edge cases.

Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the correctness of file type check.

# Test: Search for the method usage. Expect: Proper handling of XAML and RESX file types.
rg --type cs 'IsXamlAndResxFile'

Length of output: 844


Script:

#!/bin/bash
# Extract the code snippets from VSCSharpMainFileWatcher.cs where IsXamlAndResxFile method is used

# Search for the method usage and display 5 lines of context around each match
rg --type cs 'IsXamlAndResxFile' -A 5 -B 5 src/Natasha.CSharp/Extension/HotExecutor/Natasha.CSharp.HotExecutor/Component/WatcherUtils/VSCSharpMainFileWatcher.cs

Length of output: 1284


Script:

#!/bin/bash
# Verify the correctness of file type check in IsXamlAndResxFile method by testing edge cases

# Create a temporary C# file to test the method
cat <<EOF > /tmp/TestIsXamlAndResxFile.cs
using System;

public class Test
{
    public static bool IsXamlAndResxFile(string file)
    {
        return file.EndsWith(".xaml", StringComparison.OrdinalIgnoreCase) || file.EndsWith(".resx", StringComparison.OrdinalIgnoreCase);
    }

    public static void Main()
    {
        string[] testFiles = {
            "file.xaml",
            "file.resx",
            "file.XAML",
            "file.RESX",
            "file.xaml.bak",
            "file.resx.bak",
            "file.xaml?version=1",
            "file.resx?version=1"
        };

        foreach (var file in testFiles)
        {
            Console.WriteLine($"\{file}: {IsXamlAndResxFile(file)}");
        }
    }
}
EOF

# Compile and run the temporary C# file
mcs /tmp/TestIsXamlAndResxFile.cs -out:/tmp/TestIsXamlAndResxFile.exe
mono /tmp/TestIsXamlAndResxFile.exe

Length of output: 260


Script:

#!/bin/bash
# Search for the IsXamlAndResxFile method definition and its usage in the repository

# Find the method definition
rg --type cs 'public static bool IsXamlAndResxFile' -A 10

# Find all usages of the IsXamlAndResxFile method
rg --type cs 'IsXamlAndResxFile'

Length of output: 2481

public static bool CheckFileAvivaliable(string file, string binPath, string objPath)
{
if (file.EndsWith(".cs") || file.EndsWith(".xaml") || file.EndsWith(".resx"))
if (file.EndsWith(".cs"))
{
if (file.StartsWith(binPath))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,12 @@ public void DeployMonitor()
{
return;
}
if (VSCSharpProjectInfomation.IsXamlAndResxFile(e.FullPath))
{
await ExecuteAfterFunction();

if (VSCSharpProjectInfomation.CheckFileAvailiable(e.FullPath))
}
else if (VSCSharpProjectInfomation.CheckFileAvailiable(e.FullPath))
{
#if DEBUG
HEProxy.ShowMessage($"Created: {e.FullPath}");
Expand All @@ -62,6 +66,7 @@ public void DeployMonitor()
_compileLock.GetAndWaitLock();
CreateFileAction(e.FullPath);
_compileLock.ReleaseLock();

await ExecuteAfterFunction();
}

Expand All @@ -73,7 +78,12 @@ public void DeployMonitor()
{
return;
}
if (VSCSharpProjectInfomation.CheckFileAvailiable(e.FullPath))
if (VSCSharpProjectInfomation.IsXamlAndResxFile(e.FullPath))
{
await ExecuteAfterFunction();

}
else if (VSCSharpProjectInfomation.CheckFileAvailiable(e.FullPath))
{
#if DEBUG
HEProxy.ShowMessage($"Deleted: {e.FullPath}");
Expand All @@ -83,7 +93,7 @@ public void DeployMonitor()
_compileLock.ReleaseLock();
await ExecuteAfterFunction();
}

};

_mainWatcher.Renamed += async (sender, e) =>
Expand All @@ -92,10 +102,13 @@ public void DeployMonitor()
{
return;
}
if (VSCSharpProjectInfomation.IsXamlAndResxFile(e.OldFullPath) || VSCSharpProjectInfomation.IsXamlAndResxFile(e.FullPath))
{
await ExecuteAfterFunction();

if (e.OldFullPath.EndsWith(".cs") || e.OldFullPath.EndsWith(".xaml"))
}else if (e.OldFullPath.EndsWith(".cs"))
{
if (e.FullPath.EndsWith(".cs") || e.FullPath.EndsWith(".xaml"))
if (e.FullPath.EndsWith(".cs"))
{
#if DEBUG
HEProxy.ShowMessage($"Renamed: {e.OldFullPath} -> {e.FullPath}");
Expand Down Expand Up @@ -150,10 +163,10 @@ private async Task ExecuteAfterFunction()
catch
{


}
}

private static void Error(object sender, ErrorEventArgs e)
{
PrintException(e.GetException());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public void SetExecute(Func<Task> execute)
public void Notify()
{
#if DEBUG
Console.WriteLine($"接收重建通知!");
Debug.WriteLine($"接收重建通知!");
#endif
_timeStamp = DateTime.UtcNow.Ticks / 10000;
_needExecuted = true;
Expand All @@ -46,7 +46,7 @@ public void StartMonitor()
{
Clean();
#if DEBUG
Console.WriteLine($"时间戳差值: {DateTime.UtcNow.Ticks / 10000 - _timeStamp}");
Debug.WriteLine($"时间戳差值: {DateTime.UtcNow.Ticks / 10000 - _timeStamp}");
#endif
if (DateTime.UtcNow.Ticks / 10000 - _timeStamp > 2000)
{
Expand Down Expand Up @@ -129,21 +129,36 @@ public VSCSharpProjectFileInternalWatcher(string csprojPath, ConcurrentDictionar
var fileName = Path.GetFileName(csprojPath);
var binFolder = Path.Combine(folder, "bin");
var objFolder = Path.Combine(folder, "obj");
FileSystemEventHandler handler = (sender, e) => {
FileSystemEventHandler csFileHandler = (sender, e) => {

if (VSCSharpProjectInfomation.CheckFileAvivaliable(e.FullPath, binFolder, objFolder))
{
_notify?.Invoke();
}

};
RenamedEventHandler reNameHandler = (sender, e) => {
RenamedEventHandler csRenameHandler = (sender, e) => {

if (VSCSharpProjectInfomation.CheckFileAvivaliable(e.FullPath, binFolder, objFolder))
{
_notify?.Invoke();
}
};
FileSystemEventHandler csprojFileHandler = (sender, e) => {

if (e.FullPath == csprojPath)
{
_notify?.Invoke();
}

};
RenamedEventHandler csprojRenameHandler = (sender, e) => {

if (e.FullPath == csprojPath)
{
_notify?.Invoke();
}
};

var csfileWatcher = new FileSystemWatcher()
{
Expand All @@ -152,10 +167,10 @@ public VSCSharpProjectFileInternalWatcher(string csprojPath, ConcurrentDictionar
EnableRaisingEvents = true,
IncludeSubdirectories = true,
};
csfileWatcher.Changed += handler;
csfileWatcher.Deleted += handler;
csfileWatcher.Created += handler;
csfileWatcher.Renamed += reNameHandler;
csfileWatcher.Changed += csFileHandler;
csfileWatcher.Deleted += csFileHandler;
csfileWatcher.Created += csFileHandler;
csfileWatcher.Renamed += csRenameHandler;

var csprojWatcher = new FileSystemWatcher()
{
Expand All @@ -166,8 +181,8 @@ public VSCSharpProjectFileInternalWatcher(string csprojPath, ConcurrentDictionar
NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.CreationTime | NotifyFilters.DirectoryName | NotifyFilters.LastAccess
};

csprojWatcher.Changed += handler;
csprojWatcher.Renamed += reNameHandler;
csprojWatcher.Changed += csprojFileHandler;
csprojWatcher.Renamed += csprojRenameHandler;
csprojWatcher.Deleted += (sender, e) =>
{
if (e.FullPath == csprojPath)
Expand Down
Loading
Loading