├── .gitignore ├── LICENSE ├── README.md ├── docs └── images │ ├── screen1.png │ └── screen2.png └── src ├── Base ├── TurboBase.IO │ ├── IoTools.cs │ └── TurboBase.IO.csproj └── TurboBase.UI │ ├── Env.cs │ ├── TurboBase.UI.csproj │ └── Visuals.cs ├── Build ├── TurboDot.Lib │ ├── Core │ │ ├── BuildCommand.cs │ │ ├── BuildCommandParser.cs │ │ ├── CleanCommand.cs │ │ ├── CleanCommandParser.cs │ │ ├── RestoreCommand.cs │ │ └── RestoreCommandParser.cs │ ├── DotCli.cs │ ├── Tools │ │ ├── Defaults.cs │ │ ├── DotUtil.cs │ │ ├── LogSink.cs │ │ └── Parser.cs │ └── TurboDot.Lib.csproj ├── TurboDot │ ├── Program.cs │ └── TurboDot.csproj ├── build.sh └── start.sh ├── Core ├── TurboCompile.API │ ├── AssemblyMeta.cs │ ├── CompileArgs.cs │ ├── CompileResult.cs │ ├── ICompiler.cs │ ├── IRefLoader.cs │ ├── OutputType.cs │ └── TurboCompile.API.csproj ├── TurboCompile.CSharp │ ├── CSharpCompiler.cs │ ├── CsGlobals.cs │ └── TurboCompile.CSharp.csproj ├── TurboCompile.Common │ ├── AssemblyCache.cs │ ├── BaseRefs.cs │ ├── CompileError.cs │ ├── Globals.cs │ ├── Internals.cs │ ├── ObservableFileWatcher.cs │ ├── References.cs │ └── TurboCompile.Common.csproj ├── TurboCompile.Roslyn │ ├── BaseCompiler.cs │ ├── MetaRefLoader.cs │ ├── OptionTool.cs │ └── TurboCompile.Roslyn.csproj ├── TurboCompile.VBasic │ ├── TurboCompile.VBasic.csproj │ ├── VBasicCompiler.cs │ └── VbGlobals.cs ├── TurboMeta.API │ ├── File │ │ ├── BaseFileLoader.cs │ │ ├── IFileLoader.cs │ │ └── MultiFileLoader.cs │ ├── Proj │ │ ├── Extensions.cs │ │ ├── IProject.cs │ │ └── OutputMode.cs │ ├── Ref │ │ ├── ContentReference.cs │ │ ├── IFileReference.cs │ │ ├── LocalReference.cs │ │ ├── PackageReference.cs │ │ └── ProjectReference.cs │ ├── Sol │ │ ├── ISolution.cs │ │ └── MemSolution.cs │ └── TurboMeta.API.csproj ├── TurboMeta.CSharp │ ├── CSProjectLoader.cs │ ├── CSScript.cs │ ├── CSScriptLoader.cs │ └── TurboMeta.CSharp.csproj ├── TurboMeta.Common │ ├── File │ │ ├── Script.cs │ │ └── ScriptLoader.cs │ ├── Proj │ │ ├── Project.cs │ │ └── ProjectLoader.cs │ ├── Sol │ │ ├── Solution.cs │ │ └── SolutionLoader.cs │ ├── TurboMeta.Common.csproj │ └── Util │ │ ├── Defaults.cs │ │ └── ScriptTools.cs ├── TurboMeta.Tests │ ├── MetaTest.cs │ ├── Resources │ │ ├── multi │ │ │ ├── Resty.zip │ │ │ └── Xmly.zip │ │ └── single │ │ │ ├── askname.zip │ │ │ ├── mincon.zip │ │ │ ├── weather.zip │ │ │ └── xmly.zip │ ├── TestUtil.cs │ └── TurboMeta.Tests.csproj ├── TurboMeta.VBasic │ ├── TurboMeta.VBasic.csproj │ ├── VBProjectLoader.cs │ ├── VBScript.cs │ └── VBScriptLoader.cs ├── TurboRepo.API │ ├── External │ │ ├── AssemblyRef.cs │ │ ├── IExternalRef.cs │ │ ├── LocalRef.cs │ │ ├── NameRef.cs │ │ └── NuGetRef.cs │ ├── FuncExtRefResolver.cs │ ├── IExtRefResolver.cs │ └── TurboRepo.API.csproj └── TurboRepo.Nuget │ ├── Externals.cs │ ├── NuGet.cs │ ├── NuGetResolver.cs │ └── TurboRepo.Nuget.csproj ├── IDE ├── TurboSharp.Lib │ ├── Core │ │ ├── Defaults.cs │ │ └── MainCommand.cs │ ├── SharpCli.cs │ ├── TurboSharp.Lib.csproj │ └── View │ │ └── MainTopLevel.cs ├── TurboSharp │ ├── Program.cs │ └── TurboSharp.csproj ├── build.sh └── start.sh ├── Run ├── TurboRun.Lib │ ├── API │ │ └── IRunner.cs │ ├── Core │ │ ├── LocalResolver.cs │ │ ├── LocalRunner.cs │ │ ├── Streams.cs │ │ └── UnloadableContext.cs │ ├── RunCli.cs │ ├── Tools │ │ └── Interactive.cs │ └── TurboRun.Lib.csproj ├── TurboRun │ ├── Program.cs │ └── TurboRun.csproj ├── build.sh └── start.sh ├── Spy ├── TurboSpy.Lib │ ├── Core │ │ ├── Decompiler.cs │ │ ├── NameTool.cs │ │ └── OneFile.cs │ ├── Model │ │ ├── AssemblyItem.cs │ │ ├── EventItem.cs │ │ ├── FieldItem.cs │ │ ├── MethodItem.cs │ │ ├── NameSpaceItem.cs │ │ ├── PropertyItem.cs │ │ ├── ReferenceItem.cs │ │ ├── ReferencesItem.cs │ │ ├── SpyItem.cs │ │ └── TypeDefItem.cs │ ├── SpyCli.cs │ ├── TurboSpy.Lib.csproj │ └── View │ │ └── MainTopLevel.cs ├── TurboSpy │ ├── Program.cs │ └── TurboSpy.csproj ├── build.sh └── start.sh └── TurboSharp.sln /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Aa][Rr][Mm]/ 27 | [Aa][Rr][Mm]64/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Ll]og/ 32 | [Ll]ogs/ 33 | 34 | # Visual Studio 2015/2017 cache/options directory 35 | .vs/ 36 | # Uncomment if you have tasks that create the project's static files in wwwroot 37 | #wwwroot/ 38 | 39 | # Visual Studio 2017 auto generated files 40 | Generated\ Files/ 41 | 42 | # MSTest test Results 43 | [Tt]est[Rr]esult*/ 44 | [Bb]uild[Ll]og.* 45 | 46 | # NUnit 47 | *.VisualState.xml 48 | TestResult.xml 49 | nunit-*.xml 50 | 51 | # Build Results of an ATL Project 52 | [Dd]ebugPS/ 53 | [Rr]eleasePS/ 54 | dlldata.c 55 | 56 | # Benchmark Results 57 | BenchmarkDotNet.Artifacts/ 58 | 59 | # .NET Core 60 | project.lock.json 61 | project.fragment.lock.json 62 | artifacts/ 63 | 64 | # StyleCop 65 | StyleCopReport.xml 66 | 67 | # Files built by Visual Studio 68 | *_i.c 69 | *_p.c 70 | *_h.h 71 | *.ilk 72 | *.meta 73 | *.obj 74 | *.iobj 75 | *.pch 76 | *.pdb 77 | *.ipdb 78 | *.pgc 79 | *.pgd 80 | *.rsp 81 | *.sbr 82 | *.tlb 83 | *.tli 84 | *.tlh 85 | *.tmp 86 | *.tmp_proj 87 | *_wpftmp.csproj 88 | *.log 89 | *.vspscc 90 | *.vssscc 91 | .builds 92 | *.pidb 93 | *.svclog 94 | *.scc 95 | 96 | # Chutzpah Test files 97 | _Chutzpah* 98 | 99 | # Visual C++ cache files 100 | ipch/ 101 | *.aps 102 | *.ncb 103 | *.opendb 104 | *.opensdf 105 | *.sdf 106 | *.cachefile 107 | *.VC.db 108 | *.VC.VC.opendb 109 | 110 | # Visual Studio profiler 111 | *.psess 112 | *.vsp 113 | *.vspx 114 | *.sap 115 | 116 | # Visual Studio Trace Files 117 | *.e2e 118 | 119 | # TFS 2012 Local Workspace 120 | $tf/ 121 | 122 | # Guidance Automation Toolkit 123 | *.gpState 124 | 125 | # ReSharper is a .NET coding add-in 126 | _ReSharper*/ 127 | *.[Rr]e[Ss]harper 128 | *.DotSettings.user 129 | 130 | # TeamCity is a build add-in 131 | _TeamCity* 132 | 133 | # DotCover is a Code Coverage Tool 134 | *.dotCover 135 | 136 | # AxoCover is a Code Coverage Tool 137 | .axoCover/* 138 | !.axoCover/settings.json 139 | 140 | # Visual Studio code coverage results 141 | *.coverage 142 | *.coveragexml 143 | 144 | # NCrunch 145 | _NCrunch_* 146 | .*crunch*.local.xml 147 | nCrunchTemp_* 148 | 149 | # MightyMoose 150 | *.mm.* 151 | AutoTest.Net/ 152 | 153 | # Web workbench (sass) 154 | .sass-cache/ 155 | 156 | # Installshield output folder 157 | [Ee]xpress/ 158 | 159 | # DocProject is a documentation generator add-in 160 | DocProject/buildhelp/ 161 | DocProject/Help/*.HxT 162 | DocProject/Help/*.HxC 163 | DocProject/Help/*.hhc 164 | DocProject/Help/*.hhk 165 | DocProject/Help/*.hhp 166 | DocProject/Help/Html2 167 | DocProject/Help/html 168 | 169 | # Click-Once directory 170 | publish/ 171 | 172 | # Publish Web Output 173 | *.[Pp]ublish.xml 174 | *.azurePubxml 175 | # Note: Comment the next line if you want to checkin your web deploy settings, 176 | # but database connection strings (with potential passwords) will be unencrypted 177 | *.pubxml 178 | *.publishproj 179 | 180 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 181 | # checkin your Azure Web App publish settings, but sensitive information contained 182 | # in these scripts will be unencrypted 183 | PublishScripts/ 184 | 185 | # NuGet Packages 186 | *.nupkg 187 | # NuGet Symbol Packages 188 | *.snupkg 189 | # The packages folder can be ignored because of Package Restore 190 | **/[Pp]ackages/* 191 | # except build/, which is used as an MSBuild target. 192 | !**/[Pp]ackages/build/ 193 | # Uncomment if necessary however generally it will be regenerated when needed 194 | #!**/[Pp]ackages/repositories.config 195 | # NuGet v3's project.json files produces more ignorable files 196 | *.nuget.props 197 | *.nuget.targets 198 | 199 | # Microsoft Azure Build Output 200 | csx/ 201 | *.build.csdef 202 | 203 | # Microsoft Azure Emulator 204 | ecf/ 205 | rcf/ 206 | 207 | # Windows Store app package directories and files 208 | AppPackages/ 209 | BundleArtifacts/ 210 | Package.StoreAssociation.xml 211 | _pkginfo.txt 212 | *.appx 213 | *.appxbundle 214 | *.appxupload 215 | 216 | # Visual Studio cache files 217 | # files ending in .cache can be ignored 218 | *.[Cc]ache 219 | # but keep track of directories ending in .cache 220 | !?*.[Cc]ache/ 221 | 222 | # Others 223 | ClientBin/ 224 | ~$* 225 | *~ 226 | *.dbmdl 227 | *.dbproj.schemaview 228 | *.jfm 229 | *.pfx 230 | *.publishsettings 231 | orleans.codegen.cs 232 | 233 | # Including strong name files can present a security risk 234 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 235 | #*.snk 236 | 237 | # Since there are multiple workflows, uncomment next line to ignore bower_components 238 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 239 | #bower_components/ 240 | 241 | # RIA/Silverlight projects 242 | Generated_Code/ 243 | 244 | # Backup & report files from converting an old project file 245 | # to a newer Visual Studio version. Backup files are not needed, 246 | # because we have git ;-) 247 | _UpgradeReport_Files/ 248 | Backup*/ 249 | UpgradeLog*.XML 250 | UpgradeLog*.htm 251 | ServiceFabricBackup/ 252 | *.rptproj.bak 253 | 254 | # SQL Server files 255 | *.mdf 256 | *.ldf 257 | *.ndf 258 | 259 | # Business Intelligence projects 260 | *.rdl.data 261 | *.bim.layout 262 | *.bim_*.settings 263 | *.rptproj.rsuser 264 | *- [Bb]ackup.rdl 265 | *- [Bb]ackup ([0-9]).rdl 266 | *- [Bb]ackup ([0-9][0-9]).rdl 267 | 268 | # Microsoft Fakes 269 | FakesAssemblies/ 270 | 271 | # GhostDoc plugin setting file 272 | *.GhostDoc.xml 273 | 274 | # Node.js Tools for Visual Studio 275 | .ntvs_analysis.dat 276 | node_modules/ 277 | 278 | # Visual Studio 6 build log 279 | *.plg 280 | 281 | # Visual Studio 6 workspace options file 282 | *.opt 283 | 284 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 285 | *.vbw 286 | 287 | # Visual Studio LightSwitch build output 288 | **/*.HTMLClient/GeneratedArtifacts 289 | **/*.DesktopClient/GeneratedArtifacts 290 | **/*.DesktopClient/ModelManifest.xml 291 | **/*.Server/GeneratedArtifacts 292 | **/*.Server/ModelManifest.xml 293 | _Pvt_Extensions 294 | 295 | # Paket dependency manager 296 | .paket/paket.exe 297 | paket-files/ 298 | 299 | # FAKE - F# Make 300 | .fake/ 301 | 302 | # CodeRush personal settings 303 | .cr/personal 304 | 305 | # Python Tools for Visual Studio (PTVS) 306 | __pycache__/ 307 | *.pyc 308 | 309 | # Cake - Uncomment if you are using it 310 | # tools/** 311 | # !tools/packages.config 312 | 313 | # Tabs Studio 314 | *.tss 315 | 316 | # Telerik's JustMock configuration file 317 | *.jmconfig 318 | 319 | # BizTalk build output 320 | *.btp.cs 321 | *.btm.cs 322 | *.odx.cs 323 | *.xsd.cs 324 | 325 | # OpenCover UI analysis results 326 | OpenCover/ 327 | 328 | # Azure Stream Analytics local run output 329 | ASALocalRun/ 330 | 331 | # MSBuild Binary and Structured Log 332 | *.binlog 333 | 334 | # NVidia Nsight GPU debugger configuration file 335 | *.nvuser 336 | 337 | # MFractors (Xamarin productivity tool) working folder 338 | .mfractor/ 339 | 340 | # Local History for Visual Studio 341 | .localhistory/ 342 | 343 | # BeatPulse healthcheck temp database 344 | healthchecksdb 345 | 346 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 347 | MigrationBackup/ 348 | 349 | # Ionide (cross platform F# VS Code tools) working folder 350 | .ionide/ 351 | 352 | # Rider 353 | .idea/ 354 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TurboSharp 2 | 3 | It's inspired by Borland Turbo Pascal, but for C# development. 4 | 5 | Primary use case is running on small and/or restricted devices. 6 | 7 | ![Screenshot 1](/docs/images/screen1.png) 8 | 9 | ## TurboSpy 10 | 11 | As part of the bigger project, there's also this TUI clone of ILSpy. 12 | 13 | ![Screenshot 2](/docs/images/screen2.png) 14 | -------------------------------------------------------------------------------- /docs/images/screen1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Open-Inventions/TurboSharp/eae67282757578c89be00f68a7debb1eebf02867/docs/images/screen1.png -------------------------------------------------------------------------------- /docs/images/screen2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Open-Inventions/TurboSharp/eae67282757578c89be00f68a7debb1eebf02867/docs/images/screen2.png -------------------------------------------------------------------------------- /src/Base/TurboBase.IO/IoTools.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | 3 | namespace TurboBase.IO 4 | { 5 | public static class IoTools 6 | { 7 | private static readonly char Sep = Path.DirectorySeparatorChar; 8 | 9 | public static string FixSlash(string path) 10 | { 11 | return Sep switch 12 | { 13 | '\\' => path.Replace('/', Sep), 14 | '/' => path.Replace('\\', Sep), 15 | _ => path 16 | }; 17 | } 18 | 19 | public static string GetPathPart(string name) 20 | { 21 | return $"{Sep}{name}{Sep}"; 22 | } 23 | 24 | public static string GetAbsPath(string term, string file) 25 | { 26 | var relPath = FixSlash(term); 27 | var fileDir = Path.GetDirectoryName(file) ?? string.Empty; 28 | var absPath = Path.Combine(fileDir, relPath); 29 | absPath = Path.GetFullPath(absPath); 30 | return absPath; 31 | } 32 | 33 | public static bool IsValidFile(string fileName) 34 | { 35 | return !string.IsNullOrWhiteSpace(fileName) 36 | && File.Exists(fileName) 37 | && File.GetCreationTime(fileName) != default; 38 | } 39 | 40 | public static string ResolveOrCreate(string folder) 41 | { 42 | if (string.IsNullOrWhiteSpace(folder)) 43 | return null; 44 | var dir = Path.GetFullPath(folder); 45 | if (!Directory.Exists(dir)) 46 | Directory.CreateDirectory(dir); 47 | return dir; 48 | } 49 | 50 | public static string FixSlashFull(string path) 51 | { 52 | var correct = FixSlash(path); 53 | return Path.GetFullPath(correct); 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /src/Base/TurboBase.IO/TurboBase.IO.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/Base/TurboBase.UI/Env.cs: -------------------------------------------------------------------------------- 1 | namespace TurboBase.UI 2 | { 3 | public record Env 4 | { 5 | public string[] Args { get; init; } 6 | 7 | public string Root { get; init; } 8 | } 9 | } -------------------------------------------------------------------------------- /src/Base/TurboBase.UI/TurboBase.UI.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/Base/TurboBase.UI/Visuals.cs: -------------------------------------------------------------------------------- 1 | using Terminal.Gui; 2 | 3 | namespace TurboBase.UI 4 | { 5 | public static class Visuals 6 | { 7 | public static ColorScheme GetBaseColor() 8 | { 9 | return Colors.ColorSchemes[nameof(Colors.Base)]; 10 | } 11 | 12 | public static ColorScheme CreateTextColor() 13 | { 14 | var scheme = new ColorScheme(); 15 | var driver = Application.Driver; 16 | scheme.Normal = driver.MakeAttribute(Color.White, Color.Blue); 17 | scheme.Focus = driver.MakeAttribute(Color.White, Color.Blue); 18 | return scheme; 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /src/Build/TurboDot.Lib/Core/BuildCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.CommandLine.Invocation; 4 | using System.CommandLine.Parsing; 5 | using System.IO; 6 | using System.Linq; 7 | using Nito.AsyncEx; 8 | using System.Threading.Tasks; 9 | using TurboBase.IO; 10 | using TurboCompile.API; 11 | using TurboCompile.CSharp; 12 | using TurboCompile.VBasic; 13 | using TurboDot.Tools; 14 | using TurboMeta.API.Proj; 15 | using TurboRepo.API; 16 | using TurboRepo.API.External; 17 | using TurboRepo.Nuget; 18 | using static TurboDot.Tools.Defaults; 19 | using static TurboDot.Core.RestoreCommand; 20 | 21 | namespace TurboDot.Core 22 | { 23 | public static class BuildCommand 24 | { 25 | public static async Task Run(InvocationContext obj) 26 | { 27 | await Run(obj.ParseResult); 28 | } 29 | 30 | private static async Task Run(ParseResult result) 31 | { 32 | var files = DotCli.GetSlnOrProject(result); 33 | if (files == null) 34 | { 35 | DotCli.ShowSlnOrProjectError(); 36 | return; 37 | } 38 | 39 | var loader = DotUtil.CreateLoader(); 40 | var projects = files.SelectMany(f => 41 | DotCli.ReadSlnOrProject(loader, f).ProjectsInOrder).ToArray(); 42 | 43 | var g = new NuGet(); 44 | 45 | var noRestore = result.GetValueForOption(NoRestoreOption); 46 | if (!noRestore) 47 | { 48 | await Restore(projects, g); 49 | LogSink.Write(" Done with restoring."); 50 | } 51 | 52 | await Build(projects, g); 53 | LogSink.Write(" Done with building."); 54 | } 55 | 56 | private static void DoCompile(IExtRefResolver extResolver, IProject handle) 57 | { 58 | var abs = handle.FilePath; 59 | LogSink.Write(@$" Building project ""{abs}""..."); 60 | var projDir = handle.GetFolder(); 61 | var binDir = GetBinFolder(projDir); 62 | 63 | var projName = handle.Name; 64 | var projBinDll = Path.Combine(binDir, $"{projName}.dll"); 65 | var projBinInfo = new FileInfo(projBinDll); 66 | 67 | var (compiler, paths) = ListFiles(projDir, handle); 68 | if (projBinInfo.Exists) 69 | { 70 | var lastWriteDll = projBinInfo.LastWriteTime; 71 | var lastWriteSrc = paths.Select(File.GetLastWriteTime).Max(); 72 | if (lastWriteSrc <= lastWriteDll) 73 | return; 74 | } 75 | 76 | var packs = handle.PackageReferences 77 | .Select(p => (IExternalRef)new NuGetRef(p.Name, p.Version)); 78 | var projs = handle.ProjectReferences 79 | .Select(p => new LocalRef(handle.GetFullPath(p))); 80 | var locals = handle.LocalReferences 81 | .Select(p => new LocalRef(handle.GetFullPath(p))); 82 | var dependencies = packs.Concat(projs).Concat(locals).ToArray(); 83 | 84 | var resolver = new FuncExtRefResolver(e => 85 | { 86 | var ePath = extResolver.Locate(e); 87 | var eName = Path.GetFileNameWithoutExtension(ePath); 88 | if (ePath.EndsWith("proj")) 89 | { 90 | var depPrj = Path.GetDirectoryName(ePath) ?? string.Empty; 91 | var depBin = Path.Combine(depPrj, "bin", "Debug", "net6.0"); 92 | ePath = Path.Combine(depBin, $"{eName}.dll"); 93 | } 94 | var depDllName = Path.GetFileName(ePath); 95 | var depDestPath = Path.Combine(binDir, depDllName); 96 | File.Copy(ePath, depDestPath, overwrite: true); 97 | return depDestPath; 98 | }); 99 | 100 | var kind = handle.OutputMode.ToKind(); 101 | var meta = new AssemblyMeta(projName); 102 | var args = new CompileArgs(paths, kind, meta, resolver, dependencies); 103 | var compiled = compiler.Compile(args); 104 | File.WriteAllBytes(projBinDll, compiled.RawAssembly); 105 | 106 | if (kind == OutputType.Library) 107 | return; 108 | 109 | var projBinRt = Path.Combine(binDir, $"{projName}.runtimeconfig.json"); 110 | File.WriteAllText(projBinRt, compiled.RuntimeJson); 111 | } 112 | 113 | private static string GetBinFolder(string dir, 114 | string framework = "net6.0", string mode = "Debug") 115 | { 116 | var folder = Path.Combine(dir, "bin", mode, framework); 117 | return Directory.CreateDirectory(folder).FullName; 118 | } 119 | 120 | private static (ICompiler compiler, string[] files) ListFiles( 121 | string dir, IProject project) 122 | { 123 | var lang = Path.GetExtension(project.FilePath)?.TrimStart('.'); 124 | ICompiler compiler; 125 | string[] files; 126 | if (lang is "vbproj" or "vb") 127 | { 128 | compiler = new VBasicCompiler(); 129 | files = project.IncludedItems.ToArray(); 130 | } 131 | else if (lang is "csproj" or "cs") 132 | { 133 | compiler = new CSharpCompiler(); 134 | files = project.IncludedItems.ToArray(); 135 | } 136 | else 137 | { 138 | throw new InvalidOperationException($"{lang} ?!"); 139 | } 140 | var binPart = IoTools.GetPathPart("bin"); 141 | if (!dir.Contains(binPart)) 142 | files = files.Where(f => !f.Contains(binPart)).ToArray(); 143 | return (compiler, files); 144 | } 145 | 146 | private static async Task Build(ICollection projects, NuGet nuGet) 147 | { 148 | var resolver = new NuGetResolver(allowDownload: false, nuGet: nuGet); 149 | 150 | var events = projects.ToDictionary( 151 | k => k.FilePath, 152 | _ => new AsyncManualResetEvent(false)); 153 | 154 | var tasks = projects.Select(f => Task.Run(async () => 155 | { 156 | foreach (var projRef in f.ProjectReferences) 157 | await events[f.GetFullPath(projRef)].WaitAsync(); 158 | DoCompile(resolver, f); 159 | events[f.FilePath].Set(); 160 | })); 161 | await Task.WhenAll(tasks); 162 | 163 | events.Clear(); 164 | } 165 | } 166 | } -------------------------------------------------------------------------------- /src/Build/TurboDot.Lib/Core/BuildCommandParser.cs: -------------------------------------------------------------------------------- 1 | using System.CommandLine; 2 | using static TurboDot.Tools.Defaults; 3 | 4 | namespace TurboDot.Core 5 | { 6 | public static class BuildCommandParser 7 | { 8 | public static Command GetCommand() 9 | { 10 | const string desc = "Build a .NET project"; 11 | var cmd = new Command("build", desc); 12 | cmd.AddArgument(SlnOrProjectArgument); 13 | cmd.AddOption(NoRestoreOption); 14 | cmd.SetHandler(BuildCommand.Run); 15 | return cmd; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/Build/TurboDot.Lib/Core/CleanCommand.cs: -------------------------------------------------------------------------------- 1 | using System.CommandLine.Invocation; 2 | using System.CommandLine.Parsing; 3 | using System.IO; 4 | using System.Linq; 5 | using TurboDot.Tools; 6 | using TurboMeta.API.Proj; 7 | 8 | namespace TurboDot.Core 9 | { 10 | public static class CleanCommand 11 | { 12 | public static void Run(InvocationContext obj) 13 | { 14 | Run(obj.ParseResult); 15 | } 16 | 17 | private static void Run(ParseResult result) 18 | { 19 | var files = DotCli.GetSlnOrProject(result); 20 | if (files == null) 21 | { 22 | DotCli.ShowSlnOrProjectError(); 23 | return; 24 | } 25 | 26 | var loader = DotUtil.CreateLoader(); 27 | foreach (var handle in files.SelectMany(f => 28 | DotCli.ReadSlnOrProject(loader, f).ProjectsInOrder)) 29 | { 30 | var abs = handle.FilePath; 31 | LogSink.Write(@$" Cleaning project ""{abs}""..."); 32 | var dir = handle.GetFolder(); 33 | var bin = Directory.GetDirectories(dir, "bin") 34 | .FirstOrDefault(); 35 | if (bin != null) 36 | CleanFolder(bin); 37 | var obj = Directory.GetDirectories(dir, "obj") 38 | .FirstOrDefault(); 39 | if (obj != null) 40 | CleanFolder(obj); 41 | LogSink.Write(@$" Done with project ""{abs}""."); 42 | } 43 | } 44 | 45 | private static void CleanFolder(string dir) 46 | { 47 | const SearchOption o = SearchOption.AllDirectories; 48 | var files = Directory.GetFiles(dir, "*.*", o); 49 | foreach (var file in files) 50 | { 51 | var txt = @$" Deleting file ""{file}"""; 52 | LogSink.Write(txt); 53 | File.Delete(file); 54 | } 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /src/Build/TurboDot.Lib/Core/CleanCommandParser.cs: -------------------------------------------------------------------------------- 1 | using System.CommandLine; 2 | using static TurboDot.Tools.Defaults; 3 | 4 | namespace TurboDot.Core 5 | { 6 | public static class CleanCommandParser 7 | { 8 | public static Command GetCommand() 9 | { 10 | const string desc = "Clean build outputs of a .NET project"; 11 | var cmd = new Command("clean", desc); 12 | cmd.AddArgument(SlnOrProjectArgument); 13 | cmd.SetHandler(CleanCommand.Run); 14 | return cmd; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /src/Build/TurboDot.Lib/Core/RestoreCommand.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.CommandLine.Invocation; 3 | using System.CommandLine.Parsing; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using TurboDot.Tools; 7 | using TurboMeta.API.Proj; 8 | using TurboMeta.API.Ref; 9 | using TurboRepo.Nuget; 10 | 11 | namespace TurboDot.Core 12 | { 13 | public static class RestoreCommand 14 | { 15 | public static async Task Run(InvocationContext obj) 16 | { 17 | await Run(obj.ParseResult); 18 | } 19 | 20 | private static async Task Run(ParseResult result) 21 | { 22 | var files = DotCli.GetSlnOrProject(result); 23 | if (files == null) 24 | { 25 | DotCli.ShowSlnOrProjectError(); 26 | return; 27 | } 28 | 29 | var g = new NuGet(); 30 | 31 | var loader = DotUtil.CreateLoader(); 32 | var projects = files.SelectMany(f => 33 | DotCli.ReadSlnOrProject(loader, f).ProjectsInOrder); 34 | 35 | await Restore(projects, g); 36 | LogSink.Write(" Done with restoring."); 37 | } 38 | 39 | private static async Task DoRestore(PackageReference packRef, NuGet nuGet) 40 | { 41 | var name = packRef.Name; 42 | var ver = packRef.Version; 43 | LogSink.Write(@$" Restoring {name} v{ver} ..."); 44 | await nuGet.Download(name, ver); 45 | } 46 | 47 | public static async Task Restore(IEnumerable projects, NuGet nuGet) 48 | { 49 | var packages = projects 50 | .SelectMany(p => p.PackageReferences) 51 | .GroupBy(p => $"{p.Name}|{p.Version}"); 52 | 53 | var tasks = packages.Select(f => Task.Run(async () => 54 | { 55 | var packRef = f.First(); 56 | await DoRestore(packRef, nuGet); 57 | })); 58 | 59 | await Task.WhenAll(tasks); 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /src/Build/TurboDot.Lib/Core/RestoreCommandParser.cs: -------------------------------------------------------------------------------- 1 | using System.CommandLine; 2 | using static TurboDot.Tools.Defaults; 3 | 4 | namespace TurboDot.Core 5 | { 6 | public static class RestoreCommandParser 7 | { 8 | public static Command GetCommand() 9 | { 10 | const string desc = "Restore dependencies specified in a .NET project"; 11 | var cmd = new Command("restore", desc); 12 | cmd.AddArgument(SlnOrProjectArgument); 13 | cmd.SetHandler(RestoreCommand.Run); 14 | return cmd; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /src/Build/TurboDot.Lib/DotCli.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using TurboDot.Tools; 3 | using TurboMeta.API.Sol; 4 | using System.CommandLine; 5 | using Parser = TurboDot.Tools.Parser; 6 | using System.CommandLine.Parsing; 7 | using System.IO; 8 | using System; 9 | using System.Linq; 10 | using static TurboDot.Tools.Defaults; 11 | using TurboMeta.API.File; 12 | 13 | namespace TurboDot 14 | { 15 | public static class DotCli 16 | { 17 | public static async Task Main(string[] args) 18 | { 19 | var rootCommand = Parser.Build(Parser.RootCommand); 20 | return await rootCommand.InvokeAsync(args); 21 | } 22 | 23 | public static FileInfo[] GetSlnOrProject(ParseResult result, string root = null) 24 | { 25 | var infos = result.GetValueForArgument(SlnOrProjectArgument) 26 | .Select(i => new FileInfo(i)) 27 | .ToArray(); 28 | if (infos.Length >= 1) 29 | { 30 | return infos; 31 | } 32 | 33 | const SearchOption o = SearchOption.TopDirectoryOnly; 34 | root ??= Environment.CurrentDirectory; 35 | 36 | var sol = Directory.GetFiles(root, "*.sln", o); 37 | if (sol.Length == 1) 38 | { 39 | return new[] { new FileInfo(sol[0]) }; 40 | } 41 | 42 | var prj = Directory.GetFiles(root, "*.??proj", o); 43 | if (prj.Length == 1) 44 | { 45 | return new[] { new FileInfo(prj[0]) }; 46 | } 47 | 48 | return null; 49 | } 50 | 51 | public static void ShowSlnOrProjectError() 52 | { 53 | LogSink.ShowError("Specify a project or solution file. The current working" + 54 | " directory does not contain a project or solution file."); 55 | Environment.ExitCode = -1; 56 | } 57 | 58 | public static ISolution ReadSlnOrProject(MultiFileLoader loader, FileInfo file) 59 | { 60 | var full = file.FullName; 61 | var loaded = loader.Load(full); 62 | return loaded; 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /src/Build/TurboDot.Lib/Tools/Defaults.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.CommandLine; 3 | 4 | namespace TurboDot.Tools 5 | { 6 | internal static class Defaults 7 | { 8 | private const string SolutionOrProjectArgName 9 | = "SCRIPT | PROJECT | SOLUTION"; 10 | 11 | private const string SolutionOrProjectArgument 12 | = "The script or project or solution file to operate on. " + 13 | "If a file is not specified, the command " + 14 | "will search the current directory for one."; 15 | 16 | public static readonly Argument> SlnOrProjectArgument 17 | = new(SolutionOrProjectArgName) 18 | { 19 | Description = SolutionOrProjectArgument, 20 | Arity = ArgumentArity.ZeroOrMore 21 | }; 22 | 23 | private const string NoRestore 24 | = "Do not restore the project before building."; 25 | 26 | public static Option NoRestoreOption 27 | = new("--no-restore", NoRestore); 28 | } 29 | } -------------------------------------------------------------------------------- /src/Build/TurboDot.Lib/Tools/DotUtil.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using TurboCompile.API; 3 | using TurboMeta.API.File; 4 | using TurboMeta.API.Proj; 5 | using TurboMeta.Common.Sol; 6 | using TurboMeta.CSharp; 7 | using TurboMeta.VBasic; 8 | 9 | namespace TurboDot.Tools 10 | { 11 | public static class DotUtil 12 | { 13 | public static MultiFileLoader CreateLoader() 14 | { 15 | var loader = new MultiFileLoader(); 16 | var loaders = loader.Loaders; 17 | loaders.Add(new SolutionLoader()); 18 | loaders.Add(new VBProjectLoader()); 19 | loaders.Add(new VBScriptLoader()); 20 | loaders.Add(new CSProjectLoader()); 21 | loaders.Add(new CSScriptLoader()); 22 | return loader; 23 | } 24 | 25 | public static OutputType ToKind(this OutputMode type) 26 | { 27 | switch (type) 28 | { 29 | case OutputMode.Lib: 30 | return OutputType.Library; 31 | case OutputMode.Exe: 32 | return OutputType.Console; 33 | default: 34 | throw new ArgumentOutOfRangeException(nameof(type), type, null); 35 | } 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /src/Build/TurboDot.Lib/Tools/LogSink.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace TurboDot.Tools 4 | { 5 | internal static class LogSink 6 | { 7 | public static void ShowError(string message, string prefix = "[ERROR] ") 8 | { 9 | Console.Error.WriteLine($"{prefix}{message}"); 10 | } 11 | 12 | public static void Write(string txt) 13 | { 14 | Console.Out.WriteLine(txt); 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /src/Build/TurboDot.Lib/Tools/Parser.cs: -------------------------------------------------------------------------------- 1 | using System.CommandLine; 2 | using TurboDot.Core; 3 | 4 | namespace TurboDot.Tools 5 | { 6 | public static class Parser 7 | { 8 | public static RootCommand RootCommand => 9 | new("Execute a .NET SDK command"); 10 | 11 | private static Command[] SubCommands => new[] 12 | { 13 | BuildCommandParser.GetCommand(), 14 | CleanCommandParser.GetCommand(), 15 | RestoreCommandParser.GetCommand() 16 | }; 17 | 18 | public static RootCommand Build(RootCommand rootCommand) 19 | { 20 | foreach (var subCommand in SubCommands) 21 | { 22 | rootCommand.AddCommand(subCommand); 23 | } 24 | return rootCommand; 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/Build/TurboDot.Lib/TurboDot.Lib.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | TurboDot 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/Build/TurboDot/Program.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace TurboDot 4 | { 5 | internal static class Program 6 | { 7 | private static async Task Main(string[] args) 8 | { 9 | return await DotCli.Main(args); 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /src/Build/TurboDot/TurboDot.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | dot 7 | true 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/Build/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | cd TurboDot 3 | dotnet publish -r linux-x64 -p:PublishSingleFile=true --self-contained true 4 | dotnet publish -r win-x64 -p:PublishSingleFile=true --self-contained true 5 | -------------------------------------------------------------------------------- /src/Build/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | sakura --hold -m -d ./TurboDot -x "dotnet run" 3 | -------------------------------------------------------------------------------- /src/Core/TurboCompile.API/AssemblyMeta.cs: -------------------------------------------------------------------------------- 1 | namespace TurboCompile.API 2 | { 3 | public record AssemblyMeta( 4 | string Name, 5 | string Version = "1.0.0.0", 6 | string Company = null, 7 | string Product = null, 8 | string Title = null 9 | ); 10 | } -------------------------------------------------------------------------------- /src/Core/TurboCompile.API/CompileArgs.cs: -------------------------------------------------------------------------------- 1 | using TurboRepo.API; 2 | using TurboRepo.API.External; 3 | 4 | namespace TurboCompile.API 5 | { 6 | public record CompileArgs( 7 | string[] Paths, 8 | OutputType Kind, 9 | AssemblyMeta Meta = null, 10 | IExtRefResolver Resolver = null, 11 | IExternalRef[] Additional = null, 12 | bool Debug = true 13 | ); 14 | } -------------------------------------------------------------------------------- /src/Core/TurboCompile.API/CompileResult.cs: -------------------------------------------------------------------------------- 1 | namespace TurboCompile.API 2 | { 3 | public record CompileResult( 4 | byte[] RawAssembly, 5 | string RuntimeJson 6 | ); 7 | } -------------------------------------------------------------------------------- /src/Core/TurboCompile.API/ICompiler.cs: -------------------------------------------------------------------------------- 1 | namespace TurboCompile.API 2 | { 3 | public interface ICompiler 4 | { 5 | CompileResult Compile(CompileArgs args); 6 | } 7 | } -------------------------------------------------------------------------------- /src/Core/TurboCompile.API/IRefLoader.cs: -------------------------------------------------------------------------------- 1 | namespace TurboCompile.API 2 | { 3 | public interface IRefLoader 4 | { 5 | T LoadFrom(byte[] bytes); 6 | 7 | T LoadFrom(string path); 8 | } 9 | } -------------------------------------------------------------------------------- /src/Core/TurboCompile.API/OutputType.cs: -------------------------------------------------------------------------------- 1 | namespace TurboCompile.API 2 | { 3 | public enum OutputType 4 | { 5 | None = 0, 6 | 7 | Console, 8 | 9 | Library 10 | } 11 | } -------------------------------------------------------------------------------- /src/Core/TurboCompile.API/TurboCompile.API.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/Core/TurboCompile.CSharp/CSharpCompiler.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.CSharp; 4 | using TurboCompile.API; 5 | using TurboCompile.Roslyn; 6 | using System; 7 | using System.Linq; 8 | using System.Net.Http; 9 | using Microsoft.CSharp.RuntimeBinder; 10 | using TurboRepo.API.External; 11 | 12 | namespace TurboCompile.CSharp 13 | { 14 | public sealed class CSharpCompiler : BaseCompiler 16 | { 17 | protected override AssemblyRef[] GetMinimalRefs() 18 | { 19 | return new AssemblyRef[] 20 | { 21 | GetRuntimeAssembly(), 22 | typeof(Console).Assembly, 23 | typeof(CSharpArgumentInfo).Assembly, 24 | typeof(Queryable).Assembly, 25 | typeof(HttpClient).Assembly 26 | }; 27 | } 28 | 29 | protected override SyntaxTree Parse((string file, string text) source, 30 | CSharpParseOptions options) 31 | { 32 | var code = ReadSource(source.text); 33 | return SyntaxFactory.ParseSyntaxTree(code, options, source.file); 34 | } 35 | 36 | protected override string GetExtraCode(AssemblyMeta meta) 37 | { 38 | var info = new CsGlobals().SetNameAndVer(meta); 39 | var code = info.Generate(); 40 | return code; 41 | } 42 | 43 | protected override CSharpParseOptions CreateParseOpts() 44 | { 45 | const LanguageVersion langVer = LanguageVersion.CSharp10; 46 | var defOpts = CSharpParseOptions.Default; 47 | var options = defOpts.WithLanguageVersion(langVer); 48 | return options; 49 | } 50 | 51 | protected override CSharpCompilationOptions CreateCompileOpts(CompileArgs args) 52 | { 53 | var kind = args.Kind.ToKind(); 54 | var debug = args.Debug; 55 | 56 | var detail = new CSharpCompilationOptions(kind, 57 | optimizationLevel: debug ? OptimizationLevel.Debug : OptimizationLevel.Release, 58 | assemblyIdentityComparer: DesktopAssemblyIdentityComparer.Default); 59 | return detail; 60 | } 61 | 62 | protected override CSharpCompilation CreateCompilation(string name, 63 | IEnumerable trees, IEnumerable references, 64 | CSharpCompilationOptions detail) 65 | { 66 | var result = CSharpCompilation.Create(name, trees, 67 | references: references, options: detail); 68 | return result; 69 | } 70 | } 71 | } -------------------------------------------------------------------------------- /src/Core/TurboCompile.CSharp/CsGlobals.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using TurboCompile.API; 4 | 5 | namespace TurboCompile.CSharp 6 | { 7 | public record CsGlobals( 8 | string FxVer = ".NETCoreApp,Version=v6.0", 9 | string Company = "Demo", 10 | string Product = "Demo", 11 | string Title = "Demo", 12 | string Mode = "Debug", 13 | Version Ver = default 14 | ) 15 | { 16 | public string Generate() 17 | { 18 | var bld = new StringBuilder(); 19 | bld.AppendLine(); 20 | bld.AppendLine("global using global::System;"); 21 | bld.AppendLine("global using global::System.Collections.Generic;"); 22 | bld.AppendLine("global using global::System.IO;"); 23 | bld.AppendLine("global using global::System.Linq;"); 24 | bld.AppendLine("global using global::System.Net.Http;"); 25 | bld.AppendLine("global using global::System.Threading;"); 26 | bld.AppendLine("global using global::System.Threading.Tasks;"); 27 | bld.AppendLine(); 28 | bld.AppendLine("[assembly: global::System.Runtime.Versioning.Target" + 29 | $"FrameworkAttribute(\"{FxVer}\", FrameworkDisplayName = \"\")]"); 30 | bld.AppendLine(); 31 | bld.AppendLine($"[assembly: System.Reflection.AssemblyCompanyAttribute(\"{Company}\")]"); 32 | bld.AppendLine($"[assembly: System.Reflection.AssemblyConfigurationAttribute(\"{Mode}\")]"); 33 | bld.AppendLine($"[assembly: System.Reflection.AssemblyFileVersionAttribute(\"{Ver}\")]"); 34 | bld.AppendLine($"[assembly: System.Reflection.Assembly" + 35 | $"InformationalVersionAttribute(\"{Ver.ToString(3)}\")]"); 36 | bld.AppendLine($"[assembly: System.Reflection.AssemblyProductAttribute(\"{Product}\")]"); 37 | bld.AppendLine($"[assembly: System.Reflection.AssemblyTitleAttribute(\"{Title}\")]"); 38 | bld.AppendLine($"[assembly: System.Reflection.AssemblyVersionAttribute(\"{Ver}\")]"); 39 | bld.AppendLine(); 40 | return bld.ToString(); 41 | } 42 | 43 | public CsGlobals SetNameAndVer(AssemblyMeta meta) 44 | => this with 45 | { 46 | Ver = Version.Parse(meta.Version), 47 | Company = meta.Company ?? meta.Name, 48 | Product = meta.Product ?? meta.Name, 49 | Title = meta.Title ?? meta.Name 50 | }; 51 | } 52 | } -------------------------------------------------------------------------------- /src/Core/TurboCompile.CSharp/TurboCompile.CSharp.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/Core/TurboCompile.Common/AssemblyCache.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Reflection; 5 | using SingleFileExtractor.Core; 6 | using TurboCompile.API; 7 | using TurboRepo.API; 8 | using TurboRepo.API.External; 9 | 10 | namespace TurboCompile.Common 11 | { 12 | public sealed class AssemblyCache 13 | { 14 | private readonly IRefLoader _loader; 15 | private readonly IDictionary _assemblies; 16 | private readonly Manifest _manifest; 17 | 18 | public AssemblyCache(IRefLoader loader) 19 | { 20 | _loader = loader; 21 | _assemblies = new Dictionary(); 22 | var entry = Assembly.GetEntryAssembly()?.Location; 23 | if (!string.IsNullOrWhiteSpace(entry)) 24 | return; 25 | var exe = Environment.ProcessPath!; 26 | var reader = new ExecutableReader(); 27 | _manifest = reader.ReadManifest(exe); 28 | } 29 | 30 | public T[] Locate(IExternalRef[] assemblies, IExtRefResolver ext = null) 31 | { 32 | var references = new T[assemblies.Length]; 33 | for (var i = 0; i < assemblies.Length; i++) 34 | { 35 | var assembly = assemblies[i]; 36 | var full = assembly.FullName!; 37 | if (_assemblies.TryGetValue(full, out var found)) 38 | { 39 | references[i] = found; 40 | continue; 41 | } 42 | var loc = assembly.NameObj.ReplaceWithRef() ?? ext?.Locate(assembly); 43 | if (string.IsNullOrWhiteSpace(loc)) 44 | { 45 | var embedded = _manifest.ReplaceWithRef(assembly.NameObj); 46 | if (embedded != null) 47 | { 48 | var tmpFile = Path.GetFullPath("temp.bin"); 49 | embedded.Extract(tmpFile); 50 | var bytes = File.ReadAllBytes(tmpFile); 51 | File.Delete(tmpFile); 52 | var eRef = _loader.LoadFrom(bytes); 53 | references[i] = _assemblies[full] = eRef; 54 | continue; 55 | } 56 | throw new FileNotFoundException(full); 57 | } 58 | var @ref = _loader.LoadFrom(loc); 59 | references[i] = _assemblies[full] = @ref; 60 | } 61 | return references; 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /src/Core/TurboCompile.Common/BaseRefs.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using TurboRepo.API.External; 3 | 4 | namespace TurboCompile.Common 5 | { 6 | public static class BaseRefs 7 | { 8 | public static HashSet CreateStdSet() 9 | { 10 | var set = new HashSet 11 | { 12 | new NameRef("System.Collections"), 13 | new NameRef("System.Xml.ReaderWriter"), 14 | new NameRef("System.Xml.XmlSerializer") 15 | }; 16 | return set; 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /src/Core/TurboCompile.Common/CompileError.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace TurboCompile.Common 6 | { 7 | public sealed class CompileError : Exception 8 | { 9 | public ICollection<(string, string)> Errors { get; } 10 | 11 | public CompileError(ICollection<(string, string)> errors) : base(ToMessage(errors)) 12 | { 13 | Errors = errors; 14 | } 15 | 16 | private static string ToMessage(IEnumerable<(string, string)> errors) 17 | => string.Join(Environment.NewLine, errors.Select(e => $"{e.Item1}: {e.Item2}")); 18 | } 19 | } -------------------------------------------------------------------------------- /src/Core/TurboCompile.Common/Globals.cs: -------------------------------------------------------------------------------- 1 | namespace TurboCompile.Common 2 | { 3 | public static class Globals 4 | { 5 | public static readonly string Net6RtJson = @"{ 6 | ""runtimeOptions"": { 7 | ""tfm"": ""net6.0"", 8 | ""framework"": { 9 | ""name"": ""Microsoft.NETCore.App"", 10 | ""version"": ""6.0.0"" 11 | } 12 | } 13 | }"; 14 | } 15 | } -------------------------------------------------------------------------------- /src/Core/TurboCompile.Common/Internals.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.IO; 3 | using System.Text; 4 | 5 | namespace TurboCompile.Common 6 | { 7 | public static class Internals 8 | { 9 | private static readonly Encoding Enc = Encoding.UTF8; 10 | 11 | public static IEnumerable<(string, string)> ReadCode(string path) 12 | { 13 | var full = Path.GetFullPath(path); 14 | var code = File.ReadAllText(full, Enc); 15 | var res = (full, code); 16 | yield return res; 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /src/Core/TurboCompile.Common/ObservableFileWatcher.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Reactive.Linq; 4 | 5 | namespace TurboCompile.Common 6 | { 7 | public sealed class ObservableFileWatcher : IDisposable 8 | { 9 | public readonly FileSystemWatcher Watcher; 10 | 11 | public IObservable Changed { get; } 12 | public IObservable Renamed { get; } 13 | public IObservable Deleted { get; } 14 | public IObservable Errors { get; } 15 | public IObservable Created { get; } 16 | 17 | public ObservableFileWatcher(FileSystemWatcher watcher) 18 | { 19 | Watcher = watcher; 20 | 21 | Changed = Observable 22 | .FromEventPattern(h => Watcher.Changed += h, 23 | h => Watcher.Changed -= h) 24 | .Select(x => x.EventArgs); 25 | 26 | Renamed = Observable 27 | .FromEventPattern(h => Watcher.Renamed += h, 28 | h => Watcher.Renamed -= h) 29 | .Select(x => x.EventArgs); 30 | 31 | Deleted = Observable 32 | .FromEventPattern(h => Watcher.Deleted += h, 33 | h => Watcher.Deleted -= h) 34 | .Select(x => x.EventArgs); 35 | 36 | Errors = Observable 37 | .FromEventPattern(h => Watcher.Error += h, h => Watcher.Error -= h) 38 | .Select(x => x.EventArgs); 39 | 40 | Created = Observable 41 | .FromEventPattern(h => Watcher.Created += h, 42 | h => Watcher.Created -= h) 43 | .Select(x => x.EventArgs); 44 | } 45 | 46 | public ObservableFileWatcher(Action configure) 47 | : this(new FileSystemWatcher()) 48 | { 49 | configure(Watcher); 50 | } 51 | 52 | public void Start() 53 | { 54 | Watcher.EnableRaisingEvents = true; 55 | } 56 | 57 | public void Stop() 58 | { 59 | Watcher.EnableRaisingEvents = false; 60 | } 61 | 62 | public void Dispose() 63 | { 64 | Stop(); 65 | Watcher.Dispose(); 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /src/Core/TurboCompile.Common/References.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Linq; 4 | using System.Reflection; 5 | using Microsoft.Extensions.DependencyModel; 6 | using SingleFileExtractor.Core; 7 | 8 | namespace TurboCompile.Common 9 | { 10 | public static class References 11 | { 12 | private static readonly Lazy CompileLibs = new(FindRefs); 13 | 14 | private static string[] FindRefs() 15 | { 16 | var ctx = DependencyContext.Default; 17 | var refs = ctx?.CompileLibraries 18 | .SelectMany(c => c.ResolveReferencePaths()) 19 | .ToArray(); 20 | return refs; 21 | } 22 | 23 | public static string ReplaceWithRef(this AssemblyName assembly) 24 | { 25 | var name = $"{assembly.Name}.dll"; 26 | var found = CompileLibs.Value? 27 | .FirstOrDefault(l => Path.GetFileName(l) == name); 28 | return found; 29 | } 30 | 31 | public static FileEntry ReplaceWithRef(this Manifest manifest, AssemblyName assembly) 32 | { 33 | if (manifest == null) 34 | return null; 35 | 36 | var runName = $"{assembly.Name}.dll"; 37 | var refName = $"refs/{runName}"; 38 | 39 | var embedded = manifest.Files.FirstOrDefault(f => 40 | f.Type == FileType.Assembly && f.RelativePath == refName); 41 | 42 | if (embedded == null) 43 | embedded = manifest.Files.FirstOrDefault(f => 44 | f.Type == FileType.Assembly && f.RelativePath == runName); 45 | 46 | return embedded; 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /src/Core/TurboCompile.Common/TurboCompile.Common.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/Core/TurboCompile.Roslyn/BaseCompiler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using Microsoft.CodeAnalysis; 6 | using Microsoft.CodeAnalysis.Text; 7 | using TurboCompile.API; 8 | using TurboCompile.Common; 9 | using TurboRepo.API.External; 10 | using TurboRepo.Nuget; 11 | using System.IO; 12 | using static TurboCompile.Common.Internals; 13 | using MR = Microsoft.CodeAnalysis.MetadataReference; 14 | 15 | namespace TurboCompile.Roslyn 16 | { 17 | public abstract class BaseCompiler : ICompiler 18 | where TP : ParseOptions 19 | where TC : CompilationOptions 20 | where TB : Compilation 21 | { 22 | private readonly AssemblyCache _cache = OptionTool.CreateCache(); 23 | 24 | public CompileResult Compile(CompileArgs raw) 25 | { 26 | var args = raw with 27 | { 28 | Meta = raw.Meta ?? new AssemblyMeta( 29 | Path.GetFileNameWithoutExtension(raw.Paths.FirstOrDefault()) 30 | ) 31 | }; 32 | var extra = GetExtraCode(args.Meta); 33 | var sources = new List<(string, string)> { (nameof(extra), extra) }; 34 | foreach (var path in args.Paths) 35 | { 36 | foreach (var item in ReadCode(path)) 37 | { 38 | sources.Add(item); 39 | } 40 | } 41 | using var memory = new MemoryStream(); 42 | var compile = GenerateCode(args, sources); 43 | var result = compile.Emit(memory); 44 | if (!result.Success) 45 | { 46 | var failures = result.Diagnostics.Where(d => 47 | d.IsWarningAsError || d.Severity == DiagnosticSeverity.Error); 48 | var fails = new List<(string, string)>(); 49 | foreach (var diagnostic in failures) 50 | fails.Add((diagnostic.Id, diagnostic.GetMessage())); 51 | throw new CompileError(fails); 52 | } 53 | memory.Seek(0, SeekOrigin.Begin); 54 | var rtJson = Globals.Net6RtJson; 55 | return new CompileResult(memory.ToArray(), rtJson); 56 | } 57 | 58 | protected Compilation GenerateCode(CompileArgs args, ICollection<(string, string)> sources) 59 | { 60 | var name = args.Meta.Name; 61 | var paOpt = CreateParseOpts(); 62 | var externals = BaseRefs.CreateStdSet(); 63 | if (args.Additional != null) 64 | Array.ForEach(args.Additional, a => externals.Add(a)); 65 | 66 | var trees = sources.Select(s => Parse(s, paOpt)).ToArray(); 67 | var libs = GetMinimalRefs().Concat(externals).ToArray(); 68 | 69 | var references = _cache.Locate(libs, args.Resolver); 70 | var cmOpt = CreateCompileOpts(args); 71 | return CreateCompilation(name, trees, references, cmOpt); 72 | } 73 | 74 | protected abstract AssemblyRef[] GetMinimalRefs(); 75 | 76 | protected abstract SyntaxTree Parse((string file, string text) source, TP opts); 77 | 78 | protected SourceText ReadSource(string text) => SourceText.From(text); 79 | 80 | protected Assembly GetRuntimeAssembly() => Externals.LoadByName("System.Runtime"); 81 | 82 | protected abstract string GetExtraCode(AssemblyMeta meta); 83 | 84 | protected abstract TP CreateParseOpts(); 85 | 86 | protected abstract TC CreateCompileOpts(CompileArgs args); 87 | 88 | protected abstract TB CreateCompilation(string name, 89 | IEnumerable trees, IEnumerable references, TC detail); 90 | } 91 | } -------------------------------------------------------------------------------- /src/Core/TurboCompile.Roslyn/MetaRefLoader.cs: -------------------------------------------------------------------------------- 1 | using TurboCompile.API; 2 | using MR = Microsoft.CodeAnalysis.MetadataReference; 3 | 4 | namespace TurboCompile.Roslyn 5 | { 6 | public sealed class MetaRefLoader : IRefLoader 7 | { 8 | public MR LoadFrom(byte[] bytes) 9 | { 10 | return MR.CreateFromImage(bytes); 11 | } 12 | 13 | public MR LoadFrom(string path) 14 | { 15 | return MR.CreateFromFile(path); 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/Core/TurboCompile.Roslyn/OptionTool.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.CodeAnalysis; 3 | using TurboCompile.API; 4 | using TurboCompile.Common; 5 | using MR = Microsoft.CodeAnalysis.MetadataReference; 6 | 7 | namespace TurboCompile.Roslyn 8 | { 9 | public static class OptionTool 10 | { 11 | public static OutputKind ToKind(this OutputType type) 12 | { 13 | switch (type) 14 | { 15 | case OutputType.None: 16 | case OutputType.Console: 17 | return OutputKind.ConsoleApplication; 18 | case OutputType.Library: 19 | return OutputKind.DynamicallyLinkedLibrary; 20 | default: 21 | throw new ArgumentOutOfRangeException(nameof(type), type, null); 22 | } 23 | } 24 | 25 | public static AssemblyCache CreateCache() 26 | { 27 | var loader = new MetaRefLoader(); 28 | return new AssemblyCache(loader); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /src/Core/TurboCompile.Roslyn/TurboCompile.Roslyn.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/Core/TurboCompile.VBasic/TurboCompile.VBasic.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/Core/TurboCompile.VBasic/VBasicCompiler.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.VisualBasic; 4 | using TurboCompile.API; 5 | using TurboCompile.Roslyn; 6 | using System; 7 | using System.Linq; 8 | using System.Net.Http; 9 | using Microsoft.VisualBasic; 10 | using TurboRepo.API.External; 11 | 12 | namespace TurboCompile.VBasic 13 | { 14 | public sealed class VBasicCompiler : BaseCompiler 16 | { 17 | protected override AssemblyRef[] GetMinimalRefs() 18 | { 19 | return new AssemblyRef[] 20 | { 21 | GetRuntimeAssembly(), 22 | typeof(Console).Assembly, 23 | typeof(Constants).Assembly, 24 | typeof(Queryable).Assembly, 25 | typeof(HttpClient).Assembly 26 | }; 27 | } 28 | 29 | protected override SyntaxTree Parse((string file, string text) source, 30 | VisualBasicParseOptions options) 31 | { 32 | var code = ReadSource(source.text); 33 | return SyntaxFactory.ParseSyntaxTree(code, options, source.file); 34 | } 35 | 36 | protected override string GetExtraCode(AssemblyMeta meta) 37 | { 38 | var info = new VbGlobals().SetNameAndVer(meta); 39 | var code = info.Generate(); 40 | return code; 41 | } 42 | 43 | protected override VisualBasicParseOptions CreateParseOpts() 44 | { 45 | const LanguageVersion langVer = LanguageVersion.VisualBasic16_9; 46 | var defOpts = VisualBasicParseOptions.Default; 47 | var options = defOpts.WithLanguageVersion(langVer); 48 | return options; 49 | } 50 | 51 | protected override VisualBasicCompilationOptions CreateCompileOpts(CompileArgs args) 52 | { 53 | var kind = args.Kind.ToKind(); 54 | var debug = args.Debug; 55 | 56 | var detail = new VisualBasicCompilationOptions(kind, 57 | optimizationLevel: debug ? OptimizationLevel.Debug : OptimizationLevel.Release, 58 | assemblyIdentityComparer: DesktopAssemblyIdentityComparer.Default); 59 | return detail; 60 | } 61 | 62 | protected override VisualBasicCompilation CreateCompilation(string name, 63 | IEnumerable trees, IEnumerable references, 64 | VisualBasicCompilationOptions detail) 65 | { 66 | var result = VisualBasicCompilation.Create(name, trees, 67 | references: references, options: detail); 68 | return result; 69 | } 70 | } 71 | } -------------------------------------------------------------------------------- /src/Core/TurboCompile.VBasic/VbGlobals.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using TurboCompile.API; 4 | 5 | namespace TurboCompile.VBasic 6 | { 7 | public record VbGlobals( 8 | string FxVer = ".NETCoreApp,Version=v6.0", 9 | string Company = "Demo", 10 | string Product = "Demo", 11 | string Title = "Demo", 12 | string Mode = "Debug", 13 | Version Ver = default 14 | ) 15 | { 16 | public string Generate() 17 | { 18 | var bld = new StringBuilder(); 19 | bld.AppendLine(); 20 | bld.AppendLine(""); 22 | bld.AppendLine(); 23 | bld.AppendLine($" "); 31 | bld.AppendLine(); 32 | return bld.ToString(); 33 | } 34 | 35 | public VbGlobals SetNameAndVer(AssemblyMeta meta) 36 | => this with 37 | { 38 | Ver = Version.Parse(meta.Version), 39 | Company = meta.Company ?? meta.Name, 40 | Product = meta.Product ?? meta.Name, 41 | Title = meta.Title ?? meta.Name 42 | }; 43 | } 44 | } -------------------------------------------------------------------------------- /src/Core/TurboMeta.API/File/BaseFileLoader.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using TurboMeta.API.Sol; 3 | 4 | namespace TurboMeta.API.File 5 | { 6 | public abstract class BaseFileLoader : IFileLoader 7 | { 8 | public abstract string Extension { get; } 9 | 10 | protected abstract ISolution SafeLoad( 11 | string path, IFileLoader parent = null 12 | ); 13 | 14 | public ISolution Load(string path, IFileLoader parent = null) 15 | { 16 | if (!string.IsNullOrWhiteSpace(path) && 17 | Extension.Equals(Path.GetExtension(path))) 18 | { 19 | return SafeLoad(path, parent); 20 | } 21 | return null; 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /src/Core/TurboMeta.API/File/IFileLoader.cs: -------------------------------------------------------------------------------- 1 | namespace TurboMeta.API.File 2 | { 3 | public interface IFileLoader 4 | { 5 | T Load(string path, IFileLoader parent = null); 6 | } 7 | } -------------------------------------------------------------------------------- /src/Core/TurboMeta.API/File/MultiFileLoader.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using TurboMeta.API.Sol; 3 | 4 | namespace TurboMeta.API.File 5 | { 6 | public sealed class MultiFileLoader : IFileLoader 7 | { 8 | public IList> Loaders { get; } 9 | 10 | public MultiFileLoader() 11 | { 12 | Loaders = new List>(); 13 | } 14 | 15 | public ISolution Load(string path, IFileLoader parent = null) 16 | { 17 | foreach (var loader in Loaders) 18 | if (loader.Load(path, parent ?? this) is { } loaded) 19 | return loaded; 20 | 21 | return null; 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /src/Core/TurboMeta.API/Proj/Extensions.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using TurboBase.IO; 3 | using TurboMeta.API.Ref; 4 | 5 | namespace TurboMeta.API.Proj 6 | { 7 | public static class Extensions 8 | { 9 | public static string GetFolder(this IProject proj) 10 | => Path.GetDirectoryName(proj.FilePath); 11 | 12 | public static string GetFullPath(this IProject proj, IFileReference projRef) 13 | => IoTools.GetAbsPath(projRef.FilePath, proj.FilePath); 14 | } 15 | } -------------------------------------------------------------------------------- /src/Core/TurboMeta.API/Proj/IProject.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using TurboMeta.API.Ref; 3 | 4 | namespace TurboMeta.API.Proj 5 | { 6 | public interface IProject 7 | { 8 | string FilePath { get; } 9 | 10 | string Name { get; } 11 | 12 | string Sdk { get; } 13 | 14 | OutputMode OutputMode { get; } 15 | 16 | IEnumerable PackageReferences { get; } 17 | 18 | IEnumerable ProjectReferences { get; } 19 | 20 | IEnumerable LocalReferences { get; } 21 | 22 | IEnumerable ContentReferences { get; } 23 | 24 | IEnumerable IncludedItems { get; } 25 | } 26 | } -------------------------------------------------------------------------------- /src/Core/TurboMeta.API/Proj/OutputMode.cs: -------------------------------------------------------------------------------- 1 | namespace TurboMeta.API.Proj 2 | { 3 | public enum OutputMode 4 | { 5 | Lib = 0, 6 | 7 | Exe 8 | } 9 | } -------------------------------------------------------------------------------- /src/Core/TurboMeta.API/Ref/ContentReference.cs: -------------------------------------------------------------------------------- 1 | namespace TurboMeta.API.Ref 2 | { 3 | public record ContentReference( 4 | string FilePath 5 | ) : IFileReference 6 | { 7 | public override string ToString() => FilePath; 8 | } 9 | } -------------------------------------------------------------------------------- /src/Core/TurboMeta.API/Ref/IFileReference.cs: -------------------------------------------------------------------------------- 1 | namespace TurboMeta.API.Ref 2 | { 3 | public interface IFileReference 4 | { 5 | string FilePath { get; } 6 | } 7 | } -------------------------------------------------------------------------------- /src/Core/TurboMeta.API/Ref/LocalReference.cs: -------------------------------------------------------------------------------- 1 | namespace TurboMeta.API.Ref 2 | { 3 | public record LocalReference( 4 | string Name, 5 | string FilePath 6 | ) : IFileReference 7 | { 8 | public override string ToString() => $"{Name} [{FilePath}]"; 9 | } 10 | } -------------------------------------------------------------------------------- /src/Core/TurboMeta.API/Ref/PackageReference.cs: -------------------------------------------------------------------------------- 1 | namespace TurboMeta.API.Ref 2 | { 3 | public record PackageReference( 4 | string Name, 5 | string Version 6 | ) 7 | { 8 | public override string ToString() => $"{Name} v{Version}"; 9 | } 10 | } -------------------------------------------------------------------------------- /src/Core/TurboMeta.API/Ref/ProjectReference.cs: -------------------------------------------------------------------------------- 1 | namespace TurboMeta.API.Ref 2 | { 3 | public record ProjectReference( 4 | string FilePath 5 | ) : IFileReference 6 | { 7 | public override string ToString() => FilePath; 8 | } 9 | } -------------------------------------------------------------------------------- /src/Core/TurboMeta.API/Sol/ISolution.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using TurboMeta.API.Proj; 3 | 4 | namespace TurboMeta.API.Sol 5 | { 6 | public interface ISolution 7 | { 8 | string FilePath { get; } 9 | 10 | IEnumerable ProjectsInOrder { get; } 11 | } 12 | } -------------------------------------------------------------------------------- /src/Core/TurboMeta.API/Sol/MemSolution.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using TurboMeta.API.Proj; 3 | 4 | namespace TurboMeta.API.Sol 5 | { 6 | public sealed class MemSolution : ISolution 7 | { 8 | public MemSolution(string path, params IProject[] projects) 9 | { 10 | FilePath = path; 11 | ProjectsInOrder = new List(projects); 12 | } 13 | 14 | public string FilePath { get; } 15 | public IEnumerable ProjectsInOrder { get; } 16 | 17 | public override string ToString() => FilePath; 18 | } 19 | } -------------------------------------------------------------------------------- /src/Core/TurboMeta.API/TurboMeta.API.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/Core/TurboMeta.CSharp/CSProjectLoader.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable InconsistentNaming 2 | 3 | using TurboMeta.Common.Proj; 4 | 5 | namespace TurboMeta.CSharp 6 | { 7 | public sealed class CSProjectLoader : ProjectLoader 8 | { 9 | public const string PrjExt = ".csproj"; 10 | 11 | public override string Extension => PrjExt; 12 | 13 | protected override string CodeExtension => CSScriptLoader.CodeExt; 14 | } 15 | } -------------------------------------------------------------------------------- /src/Core/TurboMeta.CSharp/CSScript.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable InconsistentNaming 2 | 3 | using TurboMeta.Common.File; 4 | 5 | namespace TurboMeta.CSharp 6 | { 7 | internal sealed class CSScript : Script 8 | { 9 | public CSScript(string filePath) : base(filePath) 10 | { 11 | ParseCode(FilePath, "//"); 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /src/Core/TurboMeta.CSharp/CSScriptLoader.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable InconsistentNaming 2 | 3 | using TurboMeta.API.Proj; 4 | using TurboMeta.Common.File; 5 | 6 | namespace TurboMeta.CSharp 7 | { 8 | public sealed class CSScriptLoader : ScriptLoader 9 | { 10 | public const string CodeExt = ".cs"; 11 | 12 | public override string Extension => CodeExt; 13 | 14 | protected override IProject LoadScript(string path) 15 | { 16 | var script = new CSScript(path); 17 | return script; 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /src/Core/TurboMeta.CSharp/TurboMeta.CSharp.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/Core/TurboMeta.Common/File/Script.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using TurboBase.IO; 5 | using TurboMeta.API.Proj; 6 | using TurboMeta.API.Ref; 7 | using TurboMeta.Common.Util; 8 | 9 | namespace TurboMeta.Common.File 10 | { 11 | public abstract class Script : IProject 12 | { 13 | protected Script(string filePath) 14 | { 15 | FilePath = IoTools.FixSlashFull(filePath); 16 | 17 | Name = Path.GetFileNameWithoutExtension(FilePath); 18 | OutputMode = OutputMode.Exe; 19 | Sdk = Defaults.StandardSdk; 20 | 21 | ProjectReferences = Array.Empty(); 22 | PackageReferences = new List(); 23 | LocalReferences = new List(); 24 | ContentReferences = new List(); 25 | IncludedItems = new List(); 26 | } 27 | 28 | public string FilePath { get; } 29 | public string Name { get; } 30 | public string Sdk { get; } 31 | public OutputMode OutputMode { get; } 32 | public IEnumerable PackageReferences { get; protected set; } 33 | public IEnumerable ProjectReferences { get; protected set; } 34 | public IEnumerable LocalReferences { get; protected set; } 35 | public IEnumerable ContentReferences { get; protected set; } 36 | public IEnumerable IncludedItems { get; protected set; } 37 | 38 | protected void ParseCode(string filePath, string prefix) 39 | { 40 | ScriptTools.Load(filePath, prefix, l => 41 | { 42 | ScriptTools.ParseRef(l, out var pr, out var lr, out var fr); 43 | if (pr != null && PackageReferences is ICollection cpr) 44 | cpr.Add(pr); 45 | if (lr != null && LocalReferences is ICollection lpr) 46 | lpr.Add(lr); 47 | if (fr != null && ContentReferences is ICollection fpr) 48 | fpr.Add(fr); 49 | }); 50 | 51 | if (IncludedItems is ICollection fpr) 52 | { 53 | fpr.Add(FilePath); 54 | foreach (var cr in ContentReferences) 55 | { 56 | var rcr = IoTools.GetAbsPath(cr.FilePath, filePath); 57 | fpr.Add(rcr); 58 | } 59 | } 60 | } 61 | 62 | public override string ToString() => FilePath; 63 | } 64 | } -------------------------------------------------------------------------------- /src/Core/TurboMeta.Common/File/ScriptLoader.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using TurboMeta.API.File; 3 | using TurboMeta.API.Proj; 4 | using TurboMeta.API.Sol; 5 | using static TurboMeta.Common.Sol.SolutionLoader; 6 | 7 | namespace TurboMeta.Common.File 8 | { 9 | public abstract class ScriptLoader : BaseFileLoader 10 | { 11 | protected override ISolution SafeLoad(string path, 12 | IFileLoader parent = null) 13 | { 14 | var proj = LoadScript(path); 15 | var fake = Path.ChangeExtension(proj.FilePath, SolExt); 16 | var sol = new MemSolution(fake, proj); 17 | return sol; 18 | } 19 | 20 | protected abstract IProject LoadScript(string path); 21 | } 22 | } -------------------------------------------------------------------------------- /src/Core/TurboMeta.Common/Proj/Project.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Xml.Linq; 6 | using ByteDev.DotNet.Project; 7 | using TurboBase.IO; 8 | using TurboMeta.API.Proj; 9 | using TurboMeta.API.Ref; 10 | using PackageReference = TurboMeta.API.Ref.PackageReference; 11 | using ProjectReference = TurboMeta.API.Ref.ProjectReference; 12 | 13 | namespace TurboMeta.Common.Proj 14 | { 15 | internal sealed class Project : IProject 16 | { 17 | public Project(string prjFilePath, string codeExt) 18 | { 19 | FilePath = IoTools.FixSlashFull(prjFilePath); 20 | var doc = XDocument.Load(FilePath); 21 | var real = new DotNetProject(doc); 22 | 23 | Name = Path.GetFileNameWithoutExtension(FilePath); 24 | 25 | var root = doc.Root; 26 | Sdk = root?.Attribute("Sdk")?.Value; 27 | 28 | var props = root?.Element("PropertyGroup"); 29 | var outType = props?.Element("OutputType")?.Value; 30 | if (Enum.TryParse(outType, true, out var ot)) 31 | OutputMode = ot; 32 | 33 | LocalReferences = root?.Descendants("Reference").Select(ParseRef); 34 | PackageReferences = real.PackageReferences.Select(p => 35 | new PackageReference(p.Name, p.Version)); 36 | ProjectReferences = real.ProjectReferences.Select(p => 37 | new ProjectReference(p.FilePath)); 38 | ContentReferences = Array.Empty(); 39 | IncludedItems = ListFiles(ItemDir, codeExt); 40 | } 41 | 42 | public string FilePath { get; } 43 | public string Name { get; } 44 | public string Sdk { get; } 45 | public OutputMode OutputMode { get; } 46 | public IEnumerable PackageReferences { get; } 47 | public IEnumerable ProjectReferences { get; } 48 | public IEnumerable LocalReferences { get; } 49 | public IEnumerable ContentReferences { get; } 50 | public IEnumerable IncludedItems { get; } 51 | 52 | private string ItemDir => Path.GetFullPath(Path.GetDirectoryName(FilePath)!); 53 | 54 | private static IEnumerable ListFiles(string dir, string filter) 55 | { 56 | const SearchOption o = SearchOption.AllDirectories; 57 | var files = Directory.GetFiles(dir, filter, o); 58 | return files; 59 | } 60 | 61 | private static LocalReference ParseRef(XElement element) 62 | { 63 | var name = element.Attribute("Include")?.Value; 64 | var path = element.Element("HintPath")?.Value; 65 | return new LocalReference(Name: name, FilePath: path); 66 | } 67 | 68 | public override string ToString() => FilePath; 69 | } 70 | } -------------------------------------------------------------------------------- /src/Core/TurboMeta.Common/Proj/ProjectLoader.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.IO; 3 | using System.Linq; 4 | using TurboBase.IO; 5 | using TurboMeta.API.File; 6 | using TurboMeta.API.Proj; 7 | using TurboMeta.API.Sol; 8 | using static TurboMeta.Common.Sol.SolutionLoader; 9 | 10 | namespace TurboMeta.Common.Proj 11 | { 12 | public abstract class ProjectLoader : BaseFileLoader 13 | { 14 | protected abstract string CodeExtension { get; } 15 | 16 | protected override ISolution SafeLoad(string path, 17 | IFileLoader parent = null) 18 | { 19 | var proj = new Project(path, $"*{CodeExtension}"); 20 | var projects = new HashSet(); 21 | FindRef(proj, projects, parent ?? this); 22 | 23 | var fake = Path.ChangeExtension(proj.FilePath, SolExt); 24 | var sol = new MemSolution(fake, projects.ToArray()); 25 | return sol; 26 | } 27 | 28 | private static void FindRef(IProject proj, ISet projects, 29 | IFileLoader parent) 30 | { 31 | projects.Add(proj); 32 | 33 | var owner = proj.FilePath; 34 | foreach (var pRef in proj.ProjectReferences) 35 | { 36 | var path = IoTools.GetAbsPath(pRef.FilePath, owner); 37 | var current = parent?.Load(path, parent) 38 | .ProjectsInOrder.First(); 39 | FindRef(current, projects, parent); 40 | } 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /src/Core/TurboMeta.Common/Sol/Solution.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Ionide.ProjInfo.Sln.Construction; 5 | using TurboBase.IO; 6 | using TurboMeta.API.Proj; 7 | using TurboMeta.API.Sol; 8 | 9 | namespace TurboMeta.Common.Sol 10 | { 11 | internal sealed class Solution : ISolution 12 | { 13 | public Solution(string solFilePath, Func load) 14 | { 15 | FilePath = IoTools.FixSlashFull(solFilePath); 16 | var real = SolutionFile.Parse(FilePath); 17 | 18 | ProjectsInOrder = real.ProjectsInOrder 19 | .Where(s => s.ProjectType is 20 | SolutionProjectType.KnownToBeMSBuildFormat or 21 | SolutionProjectType.WebProject) 22 | .Select(p => load(p.AbsolutePath)); 23 | } 24 | 25 | public string FilePath { get; } 26 | public IEnumerable ProjectsInOrder { get; } 27 | 28 | public override string ToString() => FilePath; 29 | } 30 | } -------------------------------------------------------------------------------- /src/Core/TurboMeta.Common/Sol/SolutionLoader.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using TurboMeta.API.File; 3 | using TurboMeta.API.Proj; 4 | using TurboMeta.API.Sol; 5 | 6 | namespace TurboMeta.Common.Sol 7 | { 8 | public sealed class SolutionLoader : BaseFileLoader 9 | { 10 | public const string SolExt = ".sln"; 11 | 12 | public override string Extension => SolExt; 13 | 14 | protected override ISolution SafeLoad(string path, 15 | IFileLoader parent = null) 16 | { 17 | var owner = parent ?? this; 18 | 19 | IProject LoadProj(string p) => owner 20 | .Load(p, owner) 21 | .ProjectsInOrder.First(); 22 | 23 | var sol = new Solution(path, LoadProj); 24 | return sol; 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/Core/TurboMeta.Common/TurboMeta.Common.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/Core/TurboMeta.Common/Util/Defaults.cs: -------------------------------------------------------------------------------- 1 | namespace TurboMeta.Common.Util 2 | { 3 | public static class Defaults 4 | { 5 | public const string StandardSdk = "Microsoft.NET.Sdk"; 6 | } 7 | } -------------------------------------------------------------------------------- /src/Core/TurboMeta.Common/Util/ScriptTools.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Text; 4 | using TurboMeta.API.Ref; 5 | 6 | namespace TurboMeta.Common.Util 7 | { 8 | public static class ScriptTools 9 | { 10 | private static readonly Encoding Utf = Encoding.UTF8; 11 | 12 | public static void Load(string filePath, string prefix, Action handler) 13 | { 14 | using var reader = new StreamReader(filePath, Utf); 15 | string line; 16 | while (!string.IsNullOrWhiteSpace(line = reader.ReadLine())) 17 | { 18 | if (!line.StartsWith(prefix)) 19 | continue; 20 | handler(line[prefix.Length..]); 21 | } 22 | } 23 | 24 | public static void ParseRef(string line, out PackageReference pr, 25 | out LocalReference lr, out ContentReference fr) 26 | { 27 | pr = null; 28 | lr = null; 29 | fr = null; 30 | var tmp = "#r "; 31 | if (line.StartsWith(tmp)) 32 | { 33 | var refLine = line[tmp.Length..].Trim().Trim('"'); 34 | tmp = "nuget: "; 35 | if (refLine.StartsWith(tmp)) 36 | { 37 | var nugLine = refLine[tmp.Length..]; 38 | var nugParts = nugLine.Split(','); 39 | var nugName = nugParts[0].Trim(); 40 | var nugVer = nugParts[1].Trim(); 41 | pr = new PackageReference(nugName, nugVer); 42 | } 43 | else 44 | { 45 | var lrPath = refLine.Trim(); 46 | var lrName = Path.GetFileNameWithoutExtension(lrPath); 47 | lr = new LocalReference(lrName, lrPath); 48 | } 49 | } 50 | tmp = "#load "; 51 | if (line.StartsWith(tmp)) 52 | { 53 | var ldLine = line[tmp.Length..].Trim().Trim('"'); 54 | fr = new ContentReference(ldLine); 55 | } 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /src/Core/TurboMeta.Tests/MetaTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using TurboDot; 6 | using TurboDot.Tools; 7 | using TurboMeta.API.Proj; 8 | using TurboMeta.Common.Util; 9 | using TurboRun; 10 | using TurboRun.Core; 11 | using Xunit; 12 | using static TurboMeta.Common.Sol.SolutionLoader; 13 | using static TurboMeta.Tests.TestUtil; 14 | 15 | namespace TurboMeta.Tests 16 | { 17 | public sealed class MetaTest 18 | { 19 | [Theory] 20 | [InlineData("single/mincon.zip", "mincon.cs", 1, 0, 0, 0, 0, "mincon", 1, 16)] 21 | [InlineData("single/mincon.zip", "mincon.vb", 1, 0, 0, 0, 0, "mincon", 1, 16)] 22 | [InlineData("single/askname.zip", "askname.cs", 1, 0, 0, 0, 0, "askname", 1, 86)] 23 | [InlineData("single/askname.zip", "askname.vb", 1, 0, 0, 0, 0, "askname", 1, 86)] 24 | [InlineData("single/weather.zip", "weather.cs", 1, 0, 2, 0, 0, "weather", 1, 46)] 25 | [InlineData("single/weather.zip", "weather.vb", 1, 0, 2, 0, 0, "weather", 1, 46)] 26 | [InlineData("single/xmly.zip", "app.cs", 1, 1, 0, 0, 1, "app", 2, 172, true)] 27 | [InlineData("single/xmly.zip", "app.vb", 1, 1, 0, 0, 1, "app", 2, 172, true)] 28 | [InlineData("multi/Resty.zip", "Resty.sln", 2, 0, 4, 0, 0, "RestyC RestyV", 2, 46)] 29 | [InlineData("multi/Resty.zip", "RestyC/RestyC.csproj", 1, 0, 2, 0, 0, "RestyC", 1, 46)] 30 | [InlineData("multi/Resty.zip", "RestyV/RestyV.vbproj", 1, 0, 2, 0, 0, "RestyV", 1, 46)] 31 | [InlineData("multi/Xmly.zip", "Xmly.sln", 5, 2, 0, 2, 0, "XmlyC XmlyC.Model XmlyV XmlyV.Model Xmly.Embed", 9, 172, true, "Exe Lib")] 32 | [InlineData("multi/Xmly.zip", "Xmly.Embed/Xmly.Embed.csproj", 1, 0, 0, 0, 0, "Xmly.Embed", 1, null, false, "Lib")] 33 | [InlineData("multi/Xmly.zip", "XmlyC.Model/XmlyC.Model.csproj", 1, 0, 0, 0, 0, "XmlyC.Model", 3, null, false, "Lib")] 34 | [InlineData("multi/Xmly.zip", "XmlyC/XmlyC.csproj", 2, 1, 0, 1, 0, "XmlyC XmlyC.Model", 4, 172, true, "Exe Lib")] 35 | [InlineData("multi/Xmly.zip", "XmlyV.Model/XmlyV.Model.vbproj", 1, 0, 0, 0, 0, "XmlyV.Model", 3, null, false, "Lib")] 36 | [InlineData("multi/Xmly.zip", "XmlyV/XmlyV.vbproj", 2, 1, 0, 1, 0, "XmlyV XmlyV.Model", 4, 172, true, "Exe Lib")] 37 | public async Task ShouldLoad(string rawZipFile, string rawZipPath, 38 | int prjCount, int lrCount, int paCount, int prCount, int coCount, 39 | string names, int itCount, int? len, bool ignoreWeak = false, 40 | string modes = "Exe") 41 | { 42 | var fullPath = ExtractZip(rawZipFile, rawZipPath); 43 | 44 | var loader = DotUtil.CreateLoader(); 45 | var loaded = loader.Load(fullPath); 46 | 47 | Assert.Equal(loaded.FilePath, loaded.ToString()); 48 | Assert.EndsWith(fullPath 49 | .Replace(".csproj", SolExt) 50 | .Replace(".cs", SolExt) 51 | .Replace(".vbproj", SolExt) 52 | .Replace(".vb", SolExt), 53 | loaded.FilePath); 54 | 55 | var projects = loaded.ProjectsInOrder.ToArray(); 56 | Assert.Equal(prjCount, projects.Length); 57 | 58 | var sdk = projects.Select(p => p.Sdk).Distinct(); 59 | Assert.Equal(Defaults.StandardSdk, sdk.Single()); 60 | 61 | var mode = projects.Select(p => p.OutputMode).Distinct(); 62 | Assert.Equal(modes, string.Join(" ", mode)); 63 | 64 | var name = projects.Select(p => p.Name); 65 | Assert.Equal(names, string.Join(" ", name)); 66 | 67 | var fpText = projects.SelectMany(p => p.FilePath); 68 | var toText = projects.SelectMany(p => p.ToString()); 69 | Assert.Equal(fpText, toText); 70 | 71 | var lr = projects 72 | .SelectMany(p => p.LocalReferences).ToArray(); 73 | var pa = projects 74 | .SelectMany(p => p.PackageReferences).ToArray(); 75 | var pr = projects 76 | .SelectMany(p => p.ProjectReferences).ToArray(); 77 | var co = projects 78 | .SelectMany(p => p.ContentReferences).ToArray(); 79 | var it = projects 80 | .SelectMany(p => p.IncludedItems).ToArray(); 81 | Assert.Equal((lrCount, paCount, prCount, coCount, itCount), 82 | (lr.Length, pa.Length, pr.Length, co.Length, it.Length)); 83 | 84 | var dotRes = await DotCli.Main(new[] { "clean", fullPath }); 85 | Assert.Equal(0, dotRes); 86 | 87 | dotRes = await DotCli.Main(new[] { "restore", fullPath }); 88 | Assert.Equal(0, dotRes); 89 | 90 | dotRes = await DotCli.Main(new[] { "build", fullPath }); 91 | Assert.Equal(0, dotRes); 92 | 93 | var projPath = projects.FirstOrDefault(p => 94 | p.OutputMode == OutputMode.Exe)?.FilePath; 95 | if (projPath == null) 96 | return; 97 | Run(projPath, len ?? 1_000_000, ignoreWeak); 98 | } 99 | 100 | private static void Run(string path, int len, bool ignoreWeak) 101 | { 102 | var dir = Path.GetDirectoryName(path) ?? string.Empty; 103 | dir = Path.Combine(dir, "bin", "Debug", "net6.0"); 104 | var exeName = Path.GetFileNameWithoutExtension(path); 105 | var fullPath = Path.Combine(dir, $"{exeName}.dll"); 106 | 107 | var nl = Environment.NewLine; 108 | var @out = new StringWriter(); 109 | var err = new StringWriter(); 110 | var fake = new Streams(new StringReader($"Test{nl}{nl}"), @out, err); 111 | 112 | var args = new[] { fullPath, "Test" }; 113 | var runRes = RunCli.Main(args, fake); 114 | 115 | Assert.Equal(ignoreWeak ? -1 : 0, runRes); 116 | Assert.Equal(0, err.ToString().Length); 117 | var outStr = @out.ToString(); 118 | Assert.True(outStr.Length >= len, $"{outStr.Length} != {len}"); 119 | } 120 | 121 | [Fact] 122 | public void ShouldFailLoad() 123 | { 124 | var loader = DotUtil.CreateLoader(); 125 | var result = loader.Load("test.tmp"); 126 | Assert.Null(result); 127 | } 128 | } 129 | } -------------------------------------------------------------------------------- /src/Core/TurboMeta.Tests/Resources/multi/Resty.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Open-Inventions/TurboSharp/eae67282757578c89be00f68a7debb1eebf02867/src/Core/TurboMeta.Tests/Resources/multi/Resty.zip -------------------------------------------------------------------------------- /src/Core/TurboMeta.Tests/Resources/multi/Xmly.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Open-Inventions/TurboSharp/eae67282757578c89be00f68a7debb1eebf02867/src/Core/TurboMeta.Tests/Resources/multi/Xmly.zip -------------------------------------------------------------------------------- /src/Core/TurboMeta.Tests/Resources/single/askname.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Open-Inventions/TurboSharp/eae67282757578c89be00f68a7debb1eebf02867/src/Core/TurboMeta.Tests/Resources/single/askname.zip -------------------------------------------------------------------------------- /src/Core/TurboMeta.Tests/Resources/single/mincon.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Open-Inventions/TurboSharp/eae67282757578c89be00f68a7debb1eebf02867/src/Core/TurboMeta.Tests/Resources/single/mincon.zip -------------------------------------------------------------------------------- /src/Core/TurboMeta.Tests/Resources/single/weather.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Open-Inventions/TurboSharp/eae67282757578c89be00f68a7debb1eebf02867/src/Core/TurboMeta.Tests/Resources/single/weather.zip -------------------------------------------------------------------------------- /src/Core/TurboMeta.Tests/Resources/single/xmly.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Open-Inventions/TurboSharp/eae67282757578c89be00f68a7debb1eebf02867/src/Core/TurboMeta.Tests/Resources/single/xmly.zip -------------------------------------------------------------------------------- /src/Core/TurboMeta.Tests/TestUtil.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.IO.Compression; 3 | using TurboBase.IO; 4 | 5 | namespace TurboMeta.Tests 6 | { 7 | internal static class TestUtil 8 | { 9 | public static string ExtractZip(string rawZipFile, string rawZipPath) 10 | { 11 | var zipFile = Path.Combine("Resources", IoTools.FixSlash(rawZipFile)); 12 | var zipPath = IoTools.FixSlash(rawZipPath); 13 | 14 | var ownerName = Path.GetFileNameWithoutExtension(zipFile); 15 | var insideName = Path.GetFileName(zipPath).Replace('.', '-'); 16 | var subName = $"{ownerName[..1]}_{insideName}"; 17 | 18 | var outDir = Directory.CreateDirectory("Outputs").Name; 19 | var outPath = Path.Combine(outDir, subName); 20 | if (Directory.Exists(outPath)) 21 | Directory.Delete(outPath, true); 22 | Directory.CreateDirectory(outPath); 23 | 24 | ZipFile.ExtractToDirectory(zipFile, outPath); 25 | 26 | return Path.Combine(outPath, zipPath); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /src/Core/TurboMeta.Tests/TurboMeta.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net6.0 5 | false 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | runtime; build; native; contentfiles; analyzers; buildtransitive 14 | all 15 | 16 | 17 | runtime; build; native; contentfiles; analyzers; buildtransitive 18 | all 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | Always 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /src/Core/TurboMeta.VBasic/TurboMeta.VBasic.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/Core/TurboMeta.VBasic/VBProjectLoader.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable InconsistentNaming 2 | 3 | using TurboMeta.Common.Proj; 4 | 5 | namespace TurboMeta.VBasic 6 | { 7 | public sealed class VBProjectLoader : ProjectLoader 8 | { 9 | public const string PrjExt = ".vbproj"; 10 | 11 | public override string Extension => PrjExt; 12 | 13 | protected override string CodeExtension => VBScriptLoader.CodeExt; 14 | } 15 | } -------------------------------------------------------------------------------- /src/Core/TurboMeta.VBasic/VBScript.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable InconsistentNaming 2 | 3 | using TurboMeta.Common.File; 4 | 5 | namespace TurboMeta.VBasic 6 | { 7 | internal sealed class VBScript : Script 8 | { 9 | public VBScript(string filePath) : base(filePath) 10 | { 11 | ParseCode(FilePath, "'"); 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /src/Core/TurboMeta.VBasic/VBScriptLoader.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable InconsistentNaming 2 | 3 | using TurboMeta.API.Proj; 4 | using TurboMeta.Common.File; 5 | 6 | namespace TurboMeta.VBasic 7 | { 8 | public sealed class VBScriptLoader : ScriptLoader 9 | { 10 | public const string CodeExt = ".vb"; 11 | 12 | public override string Extension => CodeExt; 13 | 14 | protected override IProject LoadScript(string path) 15 | { 16 | var script = new VBScript(path); 17 | return script; 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /src/Core/TurboRepo.API/External/AssemblyRef.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | namespace TurboRepo.API.External 4 | { 5 | public record AssemblyRef(Assembly Assembly) 6 | : IExternalRef 7 | { 8 | public static implicit operator AssemblyRef(Assembly a) => new(a); 9 | 10 | public string FullName => Assembly.FullName; 11 | 12 | public AssemblyName NameObj => Assembly.GetName(); 13 | } 14 | } -------------------------------------------------------------------------------- /src/Core/TurboRepo.API/External/IExternalRef.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | namespace TurboRepo.API.External 4 | { 5 | public interface IExternalRef 6 | { 7 | string FullName { get; } 8 | 9 | AssemblyName NameObj { get; } 10 | } 11 | } -------------------------------------------------------------------------------- /src/Core/TurboRepo.API/External/LocalRef.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Reflection; 3 | 4 | namespace TurboRepo.API.External 5 | { 6 | public record LocalRef(string FilePath) 7 | : IExternalRef 8 | { 9 | public string FullName => NameObj.FullName; 10 | 11 | public AssemblyName NameObj 12 | => new(Path.GetFileNameWithoutExtension(FilePath) ?? "_"); 13 | } 14 | } -------------------------------------------------------------------------------- /src/Core/TurboRepo.API/External/NameRef.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | namespace TurboRepo.API.External 4 | { 5 | public record NameRef(string Name) 6 | : IExternalRef 7 | { 8 | public string FullName => NameObj.FullName; 9 | 10 | public AssemblyName NameObj => new(Name); 11 | } 12 | } -------------------------------------------------------------------------------- /src/Core/TurboRepo.API/External/NuGetRef.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | namespace TurboRepo.API.External 4 | { 5 | public record NuGetRef(string Name, string Version) 6 | : IExternalRef 7 | { 8 | public string FullName => NameObj.FullName; 9 | 10 | public AssemblyName NameObj => new($"nu_{Name}, Version={Version}"); 11 | } 12 | } -------------------------------------------------------------------------------- /src/Core/TurboRepo.API/FuncExtRefResolver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using TurboRepo.API.External; 3 | 4 | namespace TurboRepo.API 5 | { 6 | public sealed class FuncExtRefResolver : IExtRefResolver 7 | { 8 | private readonly Func _func; 9 | 10 | public FuncExtRefResolver(Func func) 11 | { 12 | _func = func; 13 | } 14 | 15 | public string Locate(IExternalRef external) 16 | { 17 | return _func.Invoke(external); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /src/Core/TurboRepo.API/IExtRefResolver.cs: -------------------------------------------------------------------------------- 1 | using TurboRepo.API.External; 2 | 3 | namespace TurboRepo.API 4 | { 5 | public interface IExtRefResolver 6 | { 7 | string Locate(IExternalRef external); 8 | } 9 | } -------------------------------------------------------------------------------- /src/Core/TurboRepo.API/TurboRepo.API.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/Core/TurboRepo.Nuget/Externals.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | namespace TurboRepo.Nuget 4 | { 5 | public static class Externals 6 | { 7 | public static Assembly LoadByName(string name) 8 | => LoadByName(new AssemblyName(name)); 9 | 10 | public static Assembly LoadByName(AssemblyName name) 11 | => Assembly.Load(name); 12 | } 13 | } -------------------------------------------------------------------------------- /src/Core/TurboRepo.Nuget/NuGet.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.IO.Compression; 4 | using System.Net.Http; 5 | using System.Security.Cryptography; 6 | using System.Threading.Tasks; 7 | using TurboBase.IO; 8 | 9 | namespace TurboRepo.Nuget 10 | { 11 | public sealed class NuGet 12 | { 13 | private static readonly HttpClient Client = new(); 14 | 15 | private readonly string _api; 16 | private readonly string _host; 17 | private readonly string _root; 18 | 19 | public NuGet(string root = "nuget") 20 | { 21 | _root = root; 22 | _host = "https://www.nuget.org"; 23 | _api = "https://api.nuget.org/v3/index.json"; 24 | } 25 | 26 | public Task FindMatch(string name, string ver) 27 | { 28 | var pkgPath = GetPath(name, ver); 29 | var pkgDir = Path.GetDirectoryName(pkgPath)!; 30 | return Task.FromResult(pkgDir); 31 | } 32 | 33 | public async Task Download(string name, string ver) 34 | { 35 | var pkgPath = GetPath(name, ver); 36 | if (!File.Exists(pkgPath)) 37 | { 38 | await StoreZip(pkgPath, name, ver); 39 | } 40 | var pkgHashPath = $"{pkgPath}.sha512"; 41 | if (!File.Exists(pkgHashPath)) 42 | { 43 | var checksum = GetCheckSum(pkgPath); 44 | await File.WriteAllTextAsync(pkgHashPath, checksum); 45 | } 46 | var pkgDir = Path.GetDirectoryName(pkgPath)!; 47 | await Extract(pkgPath, pkgDir); 48 | return pkgDir; 49 | } 50 | 51 | private static async Task Extract(string pkgPath, string pkgDir) 52 | { 53 | using var pkgZip = ZipFile.OpenRead(pkgPath); 54 | foreach (var entry in pkgZip.Entries) 55 | { 56 | var entryName = entry.Name; 57 | if (entryName == "[Content_Types].xml") 58 | continue; 59 | var entryFull = entry.FullName; 60 | if (entryFull.StartsWith("_rels/")) 61 | continue; 62 | if (entryFull.StartsWith("package/")) 63 | continue; 64 | 65 | var entryPath = IoTools.FixSlash(entryFull); 66 | var entryDest = Path.Combine(pkgDir, entryPath); 67 | if (File.Exists(entryDest)) 68 | continue; 69 | 70 | var entryDir = Path.GetDirectoryName(entryDest)!; 71 | if (!Directory.Exists(entryDir)) 72 | Directory.CreateDirectory(entryDir!); 73 | 74 | await using var zipOut = File.Create(entryDest); 75 | await using var zipStream = entry.Open(); 76 | await zipStream.CopyToAsync(zipOut); 77 | await zipOut.FlushAsync(); 78 | File.SetLastWriteTime(entryDest, entry.LastWriteTime.DateTime); 79 | } 80 | } 81 | 82 | private async Task StoreZip(string pkgPath, string name, string ver) 83 | { 84 | var baseUrl = new Uri($"{_host}/api/v2/package/{name}/{ver}"); 85 | using var response = await Client.GetAsync(baseUrl); 86 | response.EnsureSuccessStatusCode(); 87 | await using var pkgStream = await response.Content.ReadAsStreamAsync(); 88 | await using var pkgOut = File.Create(pkgPath); 89 | await pkgStream.CopyToAsync(pkgOut); 90 | await pkgOut.FlushAsync(); 91 | } 92 | 93 | private string GetPath(string name, string ver) 94 | { 95 | var nugetDir = Directory.CreateDirectory(_root).FullName; 96 | var label = name.ToLower(); 97 | var pkgDir = Path.Combine(nugetDir, label, ver); 98 | if (!Directory.Exists(pkgDir)) 99 | Directory.CreateDirectory(pkgDir); 100 | var pkgFile = $"{label}.{ver}.nupkg"; 101 | var pkgPath = Path.Combine(pkgDir, pkgFile); 102 | return pkgPath; 103 | } 104 | 105 | private static string GetCheckSum(string filePath) 106 | { 107 | using var hash = SHA512.Create(); 108 | using var stream = File.OpenRead(filePath); 109 | return Convert.ToBase64String(hash.ComputeHash(stream)); 110 | } 111 | } 112 | } -------------------------------------------------------------------------------- /src/Core/TurboRepo.Nuget/NuGetResolver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Linq; 4 | using TurboRepo.API; 5 | using TurboRepo.API.External; 6 | using static TurboRepo.Nuget.Externals; 7 | using static TurboBase.IO.IoTools; 8 | 9 | namespace TurboRepo.Nuget 10 | { 11 | public sealed class NuGetResolver : IExtRefResolver 12 | { 13 | private readonly bool _allowDownload; 14 | private readonly NuGet _nuGet; 15 | 16 | public NuGetResolver(NuGet nuGet = null, bool allowDownload = true) 17 | { 18 | _allowDownload = allowDownload; 19 | _nuGet = nuGet ?? new NuGet(nameof(NuGet).ToLower()); 20 | } 21 | 22 | public string Locate(IExternalRef external) 23 | { 24 | switch (external) 25 | { 26 | case AssemblyRef ar: 27 | var aLoc = ar.Assembly.Location; 28 | return aLoc; 29 | case LocalRef lr: 30 | var lLoc = Path.GetFullPath(FixSlash(lr.FilePath)); 31 | return lLoc; 32 | case NameRef nr: 33 | var nLoc = LoadByName(nr.NameObj).Location; 34 | return nLoc; 35 | case NuGetRef ur: 36 | var uTask = _allowDownload 37 | ? _nuGet.Download(ur.Name, ur.Version) 38 | : _nuGet.FindMatch(ur.Name, ur.Version); 39 | var uPath = uTask.GetAwaiter().GetResult(); 40 | var possible = new[] 41 | { 42 | "net6.0", "netstandard2.1", "netstandard2.0" 43 | }; 44 | var candidate = possible 45 | .Select(p => Path.Combine(uPath, "lib", p)) 46 | .Where(Directory.Exists) 47 | .First(); 48 | var uLoc = Directory.GetFiles(candidate, "*.dll") 49 | .FirstOrDefault(); 50 | return uLoc; 51 | default: 52 | throw new ArgumentOutOfRangeException(nameof(external)); 53 | } 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /src/Core/TurboRepo.Nuget/TurboRepo.Nuget.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/IDE/TurboSharp.Lib/Core/Defaults.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using TurboMeta.Common.Sol; 3 | using TurboMeta.CSharp; 4 | using TurboMeta.VBasic; 5 | 6 | namespace TurboSharp.Core 7 | { 8 | internal static class Defaults 9 | { 10 | internal static List GetAllowedExtensions() 11 | { 12 | return new List 13 | { 14 | CSScriptLoader.CodeExt, 15 | VBScriptLoader.CodeExt, 16 | CSProjectLoader.PrjExt, 17 | VBProjectLoader.PrjExt, 18 | SolutionLoader.SolExt 19 | }; 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /src/IDE/TurboSharp.Lib/Core/MainCommand.cs: -------------------------------------------------------------------------------- 1 | namespace TurboSharp.Core 2 | { 3 | public enum MainCommand 4 | { 5 | None = 0, 6 | 7 | Run, 8 | 9 | Spy, 10 | 11 | Dot 12 | } 13 | } -------------------------------------------------------------------------------- /src/IDE/TurboSharp.Lib/SharpCli.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Terminal.Gui; 3 | using TurboBase.UI; 4 | using TurboSharp.View; 5 | 6 | namespace TurboSharp 7 | { 8 | public static class SharpCli 9 | { 10 | public static int Main(string[] args) 11 | { 12 | var boot = new Env 13 | { 14 | Root = Environment.CurrentDirectory, 15 | Args = args 16 | }; 17 | 18 | Application.Init(); 19 | Application.Run(CreateTop(boot)); 20 | Application.Shutdown(); 21 | 22 | return 0; 23 | } 24 | 25 | public static Toplevel CreateTop(Env boot) => new MainTopLevel(boot); 26 | } 27 | } -------------------------------------------------------------------------------- /src/IDE/TurboSharp.Lib/TurboSharp.Lib.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | TurboSharp 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/IDE/TurboSharp.Lib/View/MainTopLevel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Text; 4 | using Terminal.Gui; 5 | using TurboBase.IO; 6 | using TurboBase.UI; 7 | using TurboDot.Tools; 8 | using TurboMeta.API.File; 9 | using TurboMeta.API.Sol; 10 | using TurboSharp.Core; 11 | using TurboSpy; 12 | 13 | namespace TurboSharp.View 14 | { 15 | internal sealed class MainTopLevel : Toplevel 16 | { 17 | private readonly Env _boot; 18 | 19 | private const string EmptyFile = "Untitled"; 20 | private readonly TextView _textView; 21 | private readonly MultiFileLoader _loader; 22 | private ISolution _currentSol; 23 | 24 | public MainTopLevel(Env boot) 25 | { 26 | _boot = boot; 27 | ColorScheme = Visuals.GetBaseColor(); 28 | MenuBar = CreateMenuBar(); 29 | var blue = Visuals.CreateTextColor(); 30 | var (textWin, textView, statusBar) = CreateTextView(EmptyFile, blue, blue); 31 | _textView = textView; 32 | Add(MenuBar); 33 | Add(textWin); 34 | Add(statusBar); 35 | _loader = DotUtil.CreateLoader(); 36 | } 37 | 38 | private static (Window, TextView, StatusBar) CreateTextView(string title, 39 | ColorScheme wColor, ColorScheme tColor) 40 | { 41 | var win = new Window(title) 42 | { 43 | X = 0, 44 | Y = 1, 45 | Width = Dim.Fill(), 46 | Height = Dim.Fill(), 47 | ColorScheme = wColor 48 | }; 49 | var textView = new TextView 50 | { 51 | X = 0, 52 | Y = 0, 53 | Width = Dim.Fill(), 54 | Height = Dim.Fill(), 55 | BottomOffset = 1, 56 | RightOffset = 1, 57 | ColorScheme = tColor 58 | }; 59 | textView.ClearKeybinding(Key.AltMask | Key.F); 60 | var pos = new StatusItem(Key.Null, "", null); 61 | textView.UnwrappedCursorPosition += e => pos.Title = $"[{e.Y + 1}:{e.X + 1}]"; 62 | var statusBar = new StatusBar(new[] { pos }); 63 | win.Add(textView); 64 | return (win, textView, statusBar); 65 | } 66 | 67 | private MenuBar CreateMenuBar() 68 | { 69 | return new MenuBar(new[] 70 | { 71 | new MenuBarItem("_File", new[] 72 | { 73 | new MenuItem("_New...", null, DoNew, 74 | null, null, Key.CtrlMask | Key.N), 75 | new MenuItem("_Open...", null, DoOpen, 76 | null, null, Key.CtrlMask | Key.O), 77 | new MenuItem("_Save all", null, DoSaveAll, 78 | CanSaveAll, null, Key.CtrlMask | Key.S), 79 | null, 80 | new MenuItem("E_xit", null, DoExit, 81 | null, null, Key.AltMask | Key.X) 82 | }), 83 | new MenuBarItem("_Edit", new[] 84 | { 85 | new MenuItem("Cu_t", null, DoCut, 86 | CanCut, null, Key.CtrlMask | Key.X), 87 | new MenuItem("_Copy", null, DoCopy, 88 | CanCopy, null, Key.CtrlMask | Key.C), 89 | new MenuItem("_Paste", null, DoPaste, 90 | CanPaste, null, Key.CtrlMask | Key.V) 91 | }), 92 | new MenuBarItem("_Search", new[] 93 | { 94 | new MenuItem("_Find...", null, DoFind, 95 | CanFind, null, Key.CtrlMask | Key.T) 96 | }), 97 | new MenuBarItem("_Run", new[] 98 | { 99 | new MenuItem("_Run", null, DoRun, 100 | CanRun, null, Key.CtrlMask | Key.F9) 101 | }), 102 | new MenuBarItem("_Compile", new[] 103 | { 104 | new MenuItem("_Compile", null, DoCompile, 105 | CanCompile, null, Key.CtrlMask | Key.F6) 106 | }), 107 | new MenuBarItem("Too_ls", new[] 108 | { 109 | new MenuItem("Turbo_Spy", null, DoSpy, 110 | null, null, Key.CtrlMask | Key.ShiftMask | Key.F7) 111 | }), 112 | new MenuBarItem("_Help", new[] 113 | { 114 | new MenuItem("_About...", null, DoAbout) 115 | }) 116 | }); 117 | } 118 | 119 | private void DoSpy() 120 | { 121 | var spy = SpyCli.CreateTop(_boot); 122 | Application.Run(spy); 123 | } 124 | 125 | private bool CanSaveAll() 126 | { 127 | return false; // TODO 128 | } 129 | 130 | private void DoSaveAll() 131 | { 132 | throw new NotImplementedException(); 133 | } 134 | 135 | private bool CanBeClosed() 136 | { 137 | return true; // TODO 138 | } 139 | 140 | private void DoOpen() 141 | { 142 | if (!CanBeClosed()) 143 | return; 144 | 145 | var allowed = Defaults.GetAllowedExtensions(); 146 | const string message = "Choose a single file or more."; 147 | var dialog = new OpenDialog("Open", message, allowed) 148 | { 149 | AllowsMultipleSelection = false 150 | }; 151 | Application.Run(dialog); 152 | 153 | if (dialog.Canceled || dialog.FilePaths.Count <= 0) 154 | return; 155 | 156 | var single = dialog.FilePaths[0]; 157 | _currentSol = _loader.Load(single); 158 | LoadFile(); 159 | } 160 | 161 | private string CurrentFileName => _currentSol? 162 | .ProjectsInOrder 163 | .SelectMany(p => p.IncludedItems) 164 | .FirstOrDefault(); 165 | 166 | private void LoadFile() 167 | { 168 | if (string.IsNullOrWhiteSpace(CurrentFileName)) 169 | return; 170 | 171 | _textView.LoadFile(CurrentFileName); 172 | var window = (Window)_textView.SuperView.SuperView; 173 | window.Title = CurrentFileName; 174 | } 175 | 176 | private void DoNew() 177 | { 178 | throw new NotImplementedException(); 179 | } 180 | 181 | private bool CanPaste() 182 | { 183 | return false; // TODO 184 | } 185 | 186 | private bool CanCopy() 187 | { 188 | return false; // TODO 189 | } 190 | 191 | private bool CanCut() 192 | { 193 | return false; // TODO 194 | } 195 | 196 | private void DoPaste() 197 | { 198 | _textView?.Paste(); 199 | } 200 | 201 | private void DoCopy() 202 | { 203 | _textView?.Copy(); 204 | } 205 | 206 | private void DoCut() 207 | { 208 | _textView?.Cut(); 209 | } 210 | 211 | private bool CanFind() 212 | { 213 | return false; // TODO 214 | } 215 | 216 | private void DoFind() 217 | { 218 | throw new NotImplementedException("TODO"); 219 | } 220 | 221 | private bool CanCompile() 222 | { 223 | return IoTools.IsValidFile(CurrentFileName); 224 | } 225 | 226 | private void DoCompile() 227 | { 228 | if (!IoTools.IsValidFile(CurrentFileName)) 229 | return; 230 | 231 | CompileOrRun("Compiler", false); 232 | } 233 | 234 | private bool CanRun() 235 | { 236 | return IoTools.IsValidFile(CurrentFileName); 237 | } 238 | 239 | private void DoRun() 240 | { 241 | if (!IoTools.IsValidFile(CurrentFileName)) 242 | return; 243 | 244 | CompileOrRun("Runner", true); 245 | } 246 | 247 | private void CompileOrRun(string prefix, bool run) 248 | { 249 | var args = Array.Empty(); 250 | Exception error = null; 251 | byte[] assembly = null; 252 | string json = null; 253 | 254 | // TODO 255 | /* try 256 | { 257 | var compiler = new CSharpCompiler(); 258 | var kind = OutputType.Console; 259 | var arg = new CompileArgs(new[] { _currentFileName }, kind); 260 | (assembly, json) = compiler.Compile(arg); 261 | } 262 | catch (Exception e) 263 | { 264 | if (e is TypeInitializationException tie) 265 | error = tie.InnerException; 266 | else 267 | error = e; 268 | } 269 | 270 | var oldOut = Console.Out; 271 | var oldErr = Console.Error; 272 | 273 | using var newOut = new StringWriter(); 274 | using var newErr = new StringWriter(); 275 | Console.SetOut(newOut); 276 | Console.SetOut(newErr); 277 | 278 | var runner = new LocalRunner(); 279 | var okay = assembly != null && error == null 280 | && (!run || runner.Execute(assembly, args)); 281 | 282 | Console.SetOut(oldOut); 283 | Console.SetError(oldErr); 284 | 285 | var nl = Environment.NewLine; 286 | var output = (error?.GetType().Name + nl + error?.Message + nl + newOut + nl + newErr).Trim(); 287 | if (!run && assembly != null) 288 | { 289 | var dir = Path.GetDirectoryName(_currentFileName); 290 | var label = Path.GetFileNameWithoutExtension(_currentFileName); 291 | var exeName = $"{label}.exe"; 292 | var exeMeta = $"{label}.runtimeconfig.json"; 293 | var metaPath = Path.Combine(dir, exeMeta); 294 | File.WriteAllText(metaPath, json, Encoding.UTF8); 295 | var exePath = Path.Combine(dir, exeName); 296 | File.WriteAllBytes(exePath, assembly); 297 | output = (exePath + nl + output).Trim(); 298 | } 299 | var add = okay ? "Success" : "Failure"; 300 | MessageBox.Query($"{prefix} {add}", output, "_OK"); */ 301 | } 302 | 303 | private void DoExit() 304 | { 305 | RequestStop(); 306 | } 307 | 308 | private static void DoAbout() 309 | { 310 | MessageBox.Query("About", GetAboutMessage(), "_OK"); 311 | } 312 | 313 | private static string GetAboutMessage() 314 | { 315 | var message = new StringBuilder(); 316 | message.AppendLine(@""); 317 | message.AppendLine(@"Turbo Sharp"); 318 | message.AppendLine(@""); 319 | message.AppendLine(@"Version 0.1"); 320 | message.AppendLine(@""); 321 | message.AppendLine(@"Copyright (C) 2023 by"); 322 | message.AppendLine(@""); 323 | message.AppendLine(@"Open Inventions, Inc."); 324 | return message.ToString(); 325 | } 326 | } 327 | } -------------------------------------------------------------------------------- /src/IDE/TurboSharp/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using TurboDot; 3 | using TurboRun; 4 | using TurboRun.Tools; 5 | using TurboSharp.Core; 6 | using TurboSpy; 7 | 8 | namespace TurboSharp 9 | { 10 | internal static class Program 11 | { 12 | private static int Main(string[] rawArgs) 13 | { 14 | var split = Interactive.Split(rawArgs); 15 | var cmd = split?.arg; 16 | Enum.TryParse(cmd, ignoreCase: true, out var mode); 17 | 18 | var args = split == null || mode == default 19 | ? rawArgs 20 | : split.Value.args; 21 | 22 | if (mode == MainCommand.Run) 23 | { 24 | return RunCli.Main(args); 25 | } 26 | 27 | if (mode == MainCommand.Dot) 28 | { 29 | return DotCli.Main(args).GetAwaiter().GetResult(); 30 | } 31 | 32 | if (mode == MainCommand.Spy) 33 | { 34 | return SpyCli.Main(args); 35 | } 36 | 37 | return SharpCli.Main(args); 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /src/IDE/TurboSharp/TurboSharp.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | turbo 7 | true 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/IDE/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | cd TurboSharp 3 | dotnet publish -r linux-x64 -p:PublishSingleFile=true --self-contained true 4 | dotnet publish -r win-x64 -p:PublishSingleFile=true --self-contained true 5 | -------------------------------------------------------------------------------- /src/IDE/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | sakura -m -d ./TurboSharp -x "dotnet run" 3 | -------------------------------------------------------------------------------- /src/Run/TurboRun.Lib/API/IRunner.cs: -------------------------------------------------------------------------------- 1 | using TurboRepo.API; 2 | using TurboRun.Core; 3 | 4 | namespace TurboRun.API 5 | { 6 | public interface IRunner 7 | { 8 | bool Execute(byte[] assembly, string[] args, 9 | Streams streams = null, IExtRefResolver resolver = null, 10 | string[] searchPaths = null); 11 | } 12 | } -------------------------------------------------------------------------------- /src/Run/TurboRun.Lib/Core/LocalResolver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using TurboRepo.API; 4 | using TurboRepo.API.External; 5 | 6 | namespace TurboRun.Core 7 | { 8 | public sealed class LocalResolver : IExtRefResolver 9 | { 10 | public string Locate(IExternalRef external) 11 | { 12 | if (external is LocalRef lr) 13 | { 14 | var path = lr.FilePath; 15 | if (File.Exists(path)) 16 | return path; 17 | } 18 | 19 | throw new InvalidOperationException(external?.ToString()); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /src/Run/TurboRun.Lib/Core/LocalRunner.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Reflection; 4 | using System.Runtime.CompilerServices; 5 | using System.Runtime.Loader; 6 | using TurboRepo.API; 7 | using TurboRepo.API.External; 8 | using TurboRun.API; 9 | 10 | namespace TurboRun.Core 11 | { 12 | public sealed class LocalRunner : IRunner 13 | { 14 | public bool Execute(byte[] assembly, string[] args, 15 | Streams streams = null, IExtRefResolver resolver = null, 16 | string[] searchPaths = null) 17 | { 18 | var weakRef = LoadAndExecute(assembly, args, streams, resolver, searchPaths); 19 | for (var i = 0; i < 8 && weakRef.IsAlive; i++) 20 | { 21 | GC.Collect(); 22 | GC.WaitForPendingFinalizers(); 23 | } 24 | return !weakRef.IsAlive; 25 | } 26 | 27 | [MethodImpl(MethodImplOptions.NoInlining)] 28 | private static WeakReference LoadAndExecute(byte[] assembly, string[] args, 29 | Streams con, IExtRefResolver resolver, string[] searchPaths) 30 | { 31 | using var memory = new MemoryStream(assembly); 32 | var context = new UnloadableContext(); 33 | var loaded = context.LoadFromStream(memory); 34 | Load(context, loaded, resolver, searchPaths); 35 | var entry = loaded.EntryPoint; 36 | Streams old = null; 37 | if (con != null) 38 | { 39 | old = Streams.Save(); 40 | con.Load(); 41 | } 42 | _ = entry != null && entry.GetParameters().Length > 0 43 | ? entry.Invoke(null, new object[] { args }) 44 | : entry?.Invoke(null, null); 45 | old?.Load(); 46 | context.Unload(); 47 | return new WeakReference(context); 48 | } 49 | 50 | private static void Load(AssemblyLoadContext ctx, Assembly assembly, 51 | IExtRefResolver resolver, string[] searchPaths = null) 52 | { 53 | foreach (var name in assembly.GetReferencedAssemblies()) 54 | { 55 | Assembly found; 56 | try 57 | { 58 | found = ctx.LoadFromAssemblyName(name); 59 | } 60 | catch (Exception) 61 | { 62 | found = null; 63 | } 64 | if (found != null) 65 | { 66 | Load(ctx, found, resolver, searchPaths); 67 | continue; 68 | } 69 | foreach (var sp in searchPaths ?? Array.Empty()) 70 | { 71 | var spFull = Path.Combine(sp, $"{name.Name}.dll"); 72 | if (!File.Exists(spFull)) 73 | continue; 74 | var locRef = new LocalRef(spFull); 75 | var locPath = resolver.Locate(locRef); 76 | found = ctx.LoadFromAssemblyPath(locPath); 77 | Load(ctx, found, resolver, searchPaths); 78 | break; 79 | } 80 | if (found != null) 81 | continue; 82 | var pkgRef = new NuGetRef(name.Name, name.Version?.ToString()); 83 | var pkgPath = resolver.Locate(pkgRef); 84 | var pkgDll = ctx.LoadFromAssemblyPath(pkgPath); 85 | Load(ctx, pkgDll, resolver, searchPaths); 86 | } 87 | } 88 | } 89 | } -------------------------------------------------------------------------------- /src/Run/TurboRun.Lib/Core/Streams.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | namespace TurboRun.Core 5 | { 6 | public record Streams( 7 | TextReader In, 8 | TextWriter Out, 9 | TextWriter Error 10 | ) 11 | { 12 | public void Load() 13 | { 14 | Console.SetIn(In); 15 | Console.SetOut(Out); 16 | Console.SetError(Error); 17 | } 18 | 19 | public static Streams Save() 20 | { 21 | return new Streams(Console.In, Console.Out, Console.Error); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /src/Run/TurboRun.Lib/Core/UnloadableContext.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.Loader; 3 | 4 | namespace TurboRun.Core 5 | { 6 | public sealed class UnloadableContext : AssemblyLoadContext 7 | { 8 | public UnloadableContext() 9 | : base(true) 10 | { 11 | } 12 | 13 | protected override Assembly Load(AssemblyName assemblyName) 14 | { 15 | return null; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/Run/TurboRun.Lib/RunCli.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using TurboRepo.API; 4 | using TurboRun.API; 5 | using TurboRun.Core; 6 | using TurboRun.Tools; 7 | 8 | namespace TurboRun 9 | { 10 | public static class RunCli 11 | { 12 | public static int Main(string[] rawArgs, Streams streams = null) 13 | { 14 | var pair = Interactive.Split(rawArgs); 15 | if (pair == null) 16 | { 17 | Console.Error.WriteLine("ERROR: No filename to execute given!"); 18 | return -1; 19 | } 20 | 21 | var file = Path.GetFullPath(pair.Value.arg); 22 | var args = pair.Value.args; 23 | 24 | var root = Path.GetDirectoryName(file); 25 | var roots = new[] { root }; 26 | 27 | IRunner runner = new LocalRunner(); 28 | IExtRefResolver find = new LocalResolver(); 29 | var assembly = File.ReadAllBytes(file); 30 | var result = runner.Execute(assembly, args, streams, find, roots); 31 | 32 | return result ? 0 : -1; 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /src/Run/TurboRun.Lib/Tools/Interactive.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | 3 | namespace TurboRun.Tools 4 | { 5 | public static class Interactive 6 | { 7 | public static (string arg, string[] args)? Split(string[] args) 8 | { 9 | if (args == null || args.Length == 0) 10 | { 11 | return null; 12 | } 13 | var first = args.First(); 14 | var second = args.Skip(1).ToArray(); 15 | return (first, second); 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /src/Run/TurboRun.Lib/TurboRun.Lib.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | TurboRun 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Run/TurboRun/Program.cs: -------------------------------------------------------------------------------- 1 | namespace TurboRun 2 | { 3 | internal static class Program 4 | { 5 | private static int Main(string[] args) 6 | { 7 | return RunCli.Main(args); 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /src/Run/TurboRun/TurboRun.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | run 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/Run/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | cd TurboRun 3 | dotnet publish -r linux-x64 -p:PublishSingleFile=true --self-contained true 4 | dotnet publish -r win-x64 -p:PublishSingleFile=true --self-contained true 5 | -------------------------------------------------------------------------------- /src/Run/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | sakura --hold -m -d ./TurboRun -x "dotnet run" 3 | -------------------------------------------------------------------------------- /src/Spy/TurboSpy.Lib/Core/Decompiler.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.IO; 3 | using System.Linq; 4 | using System.Threading; 5 | using ICSharpCode.Decompiler; 6 | using ICSharpCode.Decompiler.CSharp; 7 | using ICSharpCode.Decompiler.CSharp.ProjectDecompiler; 8 | using ICSharpCode.Decompiler.DebugInfo; 9 | using ICSharpCode.Decompiler.Disassembler; 10 | using ICSharpCode.Decompiler.Metadata; 11 | using ICSharpCode.Decompiler.Solution; 12 | using ICSharpCode.Decompiler.TypeSystem; 13 | using ICSharpCode.ILSpyX.PdbProvider; 14 | 15 | namespace TurboSpy.Core 16 | { 17 | internal sealed class Decompiler 18 | { 19 | public LanguageVersion LanguageVersion { get; set; } 20 | public bool RemoveDeadCode { get; set; } 21 | public bool RemoveDeadStores { get; set; } 22 | public bool NestedDirectories { get; set; } 23 | public bool ShowIlSequencePointsFlag { get; set; } 24 | public IList ReferencePaths { get; set; } 25 | 26 | public Decompiler() 27 | { 28 | LanguageVersion = LanguageVersion.Latest; 29 | RemoveDeadCode = true; 30 | RemoveDeadStores = true; 31 | NestedDirectories = true; 32 | ShowIlSequencePointsFlag = false; 33 | ReferencePaths = new List(); 34 | } 35 | 36 | public CSharpDecompiler GetDecompiler(string assemblyFileName) 37 | { 38 | var (config, resolver, debug, _) = PrepareForDecompile(assemblyFileName); 39 | return new CSharpDecompiler(assemblyFileName, resolver, config) { DebugInfoProvider = debug }; 40 | } 41 | 42 | private (DecompilerSettings, UniversalAssemblyResolver, IDebugInfoProvider, PEFile) 43 | PrepareForDecompile(string assemblyFileName) 44 | { 45 | var mod = new PEFile(assemblyFileName); 46 | var meta = mod.Metadata.DetectTargetFrameworkId(); 47 | var resolver = new UniversalAssemblyResolver(assemblyFileName, false, meta); 48 | foreach (var path in ReferencePaths) 49 | { 50 | resolver.AddSearchDirectory(path); 51 | } 52 | var config = GetSettings(mod); 53 | var debug = TryLoadPdb(mod); 54 | return (config, resolver, debug, mod); 55 | } 56 | 57 | private static IDebugInfoProvider TryLoadPdb(PEFile module) 58 | { 59 | var peFile = module.FileName; 60 | var pdbFile = Path.ChangeExtension(peFile, ".pdb"); 61 | if (File.Exists(pdbFile)) 62 | { 63 | return DebugInfoUtils.FromFile(module, pdbFile); 64 | } 65 | return DebugInfoUtils.LoadSymbols(module); 66 | } 67 | 68 | private DecompilerSettings GetSettings(PEFile module) 69 | { 70 | return new DecompilerSettings(LanguageVersion) 71 | { 72 | ThrowOnAssemblyResolveErrors = false, 73 | RemoveDeadCode = RemoveDeadCode, 74 | RemoveDeadStores = RemoveDeadStores, 75 | UseSdkStyleProjectFormat = WholeProjectDecompiler.CanUseSdkStyleProjectFormat(module), 76 | UseNestedDirectoriesForNamespaces = NestedDirectories, 77 | }; 78 | } 79 | 80 | private void DecompileAsSolution(string outputDir, IEnumerable inputAssemblies) 81 | { 82 | var projects = new List(); 83 | foreach (var file in inputAssemblies) 84 | { 85 | var baseName = Path.GetFileNameWithoutExtension(file); 86 | var proj = Path.Combine(outputDir, baseName, $"{baseName}.csproj"); 87 | var projectDir = Path.GetDirectoryName(proj); 88 | Directory.CreateDirectory(projectDir!); 89 | var pid = DecompileAsProject(file, proj); 90 | var item = new ProjectItem(proj, pid.PlatformName, pid.Guid, pid.TypeGuid); 91 | projects.Add(item); 92 | } 93 | var slnFile = $"{Path.GetFileNameWithoutExtension(outputDir)}.sln"; 94 | SolutionCreator.WriteSolutionFile(Path.Combine(outputDir, slnFile), projects); 95 | } 96 | 97 | private ProjectId DecompileAsProject(string assemblyFileName, string projectFileName) 98 | { 99 | var (config, resolver, debug, module) = PrepareForDecompile(assemblyFileName); 100 | var decompiler = new WholeProjectDecompiler(config, resolver, resolver, debug); 101 | using var fileOut = File.OpenWrite(projectFileName); 102 | using var projectWriter = new StreamWriter(fileOut); 103 | var projectDir = Path.GetDirectoryName(projectFileName); 104 | return decompiler.DecompileProject(module, projectDir, projectWriter); 105 | } 106 | 107 | private void ShowIl(string assemblyFileName, TextWriter output) 108 | { 109 | var module = new PEFile(assemblyFileName); 110 | output.WriteLine($"// IL code: {module.Name}"); 111 | var disassembler = new ReflectionDisassembler(new PlainTextOutput(output), CancellationToken.None) 112 | { 113 | DebugInfo = TryLoadPdb(module), 114 | ShowSequencePoints = ShowIlSequencePointsFlag 115 | }; 116 | disassembler.WriteModuleContents(module); 117 | } 118 | 119 | private void ListContent(string assemblyFileName, TextWriter output, ICollection kinds) 120 | { 121 | var decompiler = GetDecompiler(assemblyFileName); 122 | foreach (var type in decompiler.TypeSystem.MainModule.TypeDefinitions) 123 | { 124 | if (!kinds.Contains(type.Kind)) 125 | continue; 126 | output.WriteLine($"{type.Kind} {type.FullName}"); 127 | } 128 | } 129 | 130 | private void Decompile(string assemblyFileName, TextWriter output, string typeName = null) 131 | { 132 | var decompiler = GetDecompiler(assemblyFileName); 133 | if (typeName == null) 134 | { 135 | output.Write(decompiler.DecompileWholeModuleAsString()); 136 | return; 137 | } 138 | var name = new FullTypeName(typeName); 139 | output.Write(decompiler.DecompileTypeAsString(name)); 140 | } 141 | 142 | private string DecompileAsType(string assemblyFileName, string typeName) 143 | { 144 | var fqn = new FullTypeName(typeName); 145 | var decompiler = GetDecompiler(assemblyFileName); 146 | var code = decompiler.DecompileTypeAsString(fqn); 147 | return code; 148 | } 149 | 150 | private string DecompileAsMethod(string assemblyFileName, string typeName) 151 | { 152 | var fqn = new FullTypeName(typeName); 153 | var decompiler = GetDecompiler(assemblyFileName); 154 | var system = decompiler.TypeSystem; 155 | var typeInfo = system.FindType(fqn).GetDefinition()!; 156 | var method = typeInfo.Methods.First(); 157 | var token = method.MetadataToken; 158 | var code = decompiler.DecompileAsString(token); 159 | return code; 160 | } 161 | } 162 | } -------------------------------------------------------------------------------- /src/Spy/TurboSpy.Lib/Core/NameTool.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using ICSharpCode.Decompiler.TypeSystem; 4 | 5 | namespace TurboSpy.Core 6 | { 7 | public static class NameTool 8 | { 9 | public static string ToSimple(this IType type) 10 | { 11 | var known = (type as ITypeDefinition)?.KnownTypeCode 12 | ?? KnownTypeCode.None; 13 | var code = type.GetTypeCode(); 14 | var full = type.FullName; 15 | if (code == TypeCode.Empty && known == KnownTypeCode.None) 16 | { 17 | var prm = string.Join(",", type.TypeArguments 18 | .Select(t => t.ToSimple())); 19 | return prm.Length == 0 ? type.Name : $"{type.Name}<{prm}>"; 20 | } 21 | switch (full) 22 | { 23 | case "System.Boolean": return "bool"; 24 | case "System.Byte": return "byte"; 25 | case "System.Char": return "char"; 26 | case "System.Int32": return "int"; 27 | case "System.UInt32": return "uint"; 28 | case "System.Single": return "float"; 29 | case "System.Void": return "void"; 30 | case "System.String": return "string"; 31 | case "System.Object": return "object"; 32 | case "System.Exception": return "Exception"; 33 | case "System.Collections.IList": return "IList"; 34 | default: throw new InvalidOperationException(full); 35 | } 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /src/Spy/TurboSpy.Lib/Core/OneFile.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Collections.Immutable; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Text; 6 | using ICSharpCode.Decompiler.CSharp; 7 | using ICSharpCode.Decompiler.Metadata; 8 | using ICSharpCode.Decompiler.TypeSystem; 9 | using TurboSpy.Model; 10 | 11 | namespace TurboSpy.Core 12 | { 13 | public record OneFile( 14 | CSharpDecompiler Decompiler 15 | ) 16 | { 17 | public AssemblyName FullAssemblyName 18 | => new(Decompiler.TypeSystem.MainModule.FullAssemblyName); 19 | 20 | public IEnumerable ReferencedModules 21 | => Decompiler.TypeSystem.ReferencedModules 22 | .OrderBy(r => r.Name).Select(mod => new AssemblyName(mod.FullAssemblyName)) 23 | .Where(modName => !modName.Name!.Equals("corlib") && !modName.Name.StartsWith("System.Private.")); 24 | 25 | public IDictionary TopLevelTypeDefs 26 | => Decompiler.TypeSystem.MainModule.TopLevelTypeDefinitions 27 | .OrderBy(r => r.FullName) 28 | .GroupBy(n => string.IsNullOrWhiteSpace(n.Namespace) ? RootNamespace : n.Namespace) 29 | .ToImmutableSortedDictionary(k => k.Key, 30 | v => v.ToArray()); 31 | 32 | public PEFile File => Decompiler.TypeSystem.MainModule.PEFile; 33 | 34 | public const string RootNamespace = "<>"; 35 | 36 | public string GetModuleTxt() 37 | { 38 | var bld = new StringBuilder(); 39 | bld.AppendLine(); 40 | var main = Decompiler.TypeSystem.MainModule; 41 | bld.AppendLine($"// {main.PEFile.FileName}"); 42 | bld.AppendLine($"// {FullAssemblyName}"); 43 | bld.AppendLine(); 44 | var attrs = Decompiler.DecompileModuleAndAssemblyAttributesToString(); 45 | bld.AppendLine(attrs); 46 | bld.AppendLine(); 47 | return bld.ToString(); 48 | } 49 | 50 | public string Decompile(TypeDefItem typeDef) 51 | { 52 | var name = typeDef.TypeName; 53 | var code = Decompiler.DecompileTypeAsString(name); 54 | 55 | if (name.TopLevelTypeName.ToString() == "" && 56 | string.IsNullOrWhiteSpace(code)) 57 | { 58 | var bld = new StringBuilder(); 59 | bld.AppendLine($"internal class {name}"); 60 | bld.AppendLine("{"); 61 | bld.AppendLine("}"); 62 | code = bld.ToString(); 63 | } 64 | 65 | return code; 66 | } 67 | 68 | public string Decompile(IEntity entity) 69 | { 70 | var bld = new StringBuilder(); 71 | var handle = entity.MetadataToken; 72 | bld.AppendLine($"// {entity.DeclaringType?.FullName}"); 73 | var code = Decompiler.DecompileAsString(handle); 74 | bld.AppendLine(code); 75 | return bld.ToString(); 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /src/Spy/TurboSpy.Lib/Model/AssemblyItem.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using TurboSpy.Core; 3 | 4 | namespace TurboSpy.Model 5 | { 6 | public class AssemblyItem : SpyItem 7 | { 8 | public OneFile One { get; } 9 | 10 | public AssemblyItem(OneFile one) : base(null) 11 | { 12 | One = one; 13 | } 14 | 15 | public override bool CanExpand => true; 16 | 17 | public override IEnumerable GetChildren() 18 | { 19 | yield return new ReferencesItem(this, One.ReferencedModules); 20 | 21 | foreach (var (k, v) in One.TopLevelTypeDefs) 22 | { 23 | yield return new NameSpaceItem(this, k, v); 24 | } 25 | } 26 | 27 | protected override string Text 28 | { 29 | get 30 | { 31 | var name = One.FullAssemblyName; 32 | return $"{name.Name} ({name.Version})"; 33 | } 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /src/Spy/TurboSpy.Lib/Model/EventItem.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using ICSharpCode.Decompiler.TypeSystem; 3 | using TurboSpy.Core; 4 | 5 | namespace TurboSpy.Model 6 | { 7 | public class EventItem : SpyItem 8 | { 9 | public EventItem(SpyItem parent, IEvent @event) : base(parent) 10 | { 11 | Event = @event; 12 | } 13 | 14 | public IEvent Event { get; } 15 | 16 | public override bool CanExpand => false; 17 | 18 | public override IEnumerable GetChildren() 19 | { 20 | yield break; 21 | } 22 | 23 | protected override string Text 24 | => $"{Event.Name} : {Event.ReturnType.ToSimple()}"; 25 | } 26 | } -------------------------------------------------------------------------------- /src/Spy/TurboSpy.Lib/Model/FieldItem.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using ICSharpCode.Decompiler.TypeSystem; 3 | using TurboSpy.Core; 4 | 5 | namespace TurboSpy.Model 6 | { 7 | public class FieldItem : SpyItem 8 | { 9 | public FieldItem(SpyItem parent, IField field) : base(parent) 10 | { 11 | Field = field; 12 | } 13 | 14 | public IField Field { get; } 15 | 16 | public override bool CanExpand => false; 17 | 18 | public override IEnumerable GetChildren() 19 | { 20 | yield break; 21 | } 22 | 23 | protected override string Text 24 | => $"{Field.Name} : {Field.Type.ToSimple()}"; 25 | } 26 | } -------------------------------------------------------------------------------- /src/Spy/TurboSpy.Lib/Model/MethodItem.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using ICSharpCode.Decompiler.TypeSystem; 4 | using TurboSpy.Core; 5 | 6 | namespace TurboSpy.Model 7 | { 8 | public class MethodItem : SpyItem 9 | { 10 | public MethodItem(SpyItem parent, IMethod method) : base(parent) 11 | { 12 | Method = method; 13 | } 14 | 15 | public IMethod Method { get; } 16 | 17 | public override bool CanExpand => false; 18 | 19 | public override IEnumerable GetChildren() 20 | { 21 | yield break; 22 | } 23 | 24 | protected override string Text 25 | { 26 | get 27 | { 28 | var name = Method.Name; 29 | var prm = string.Join(", ", Method.Parameters 30 | .Select(p => p.Type.ToSimple())); 31 | var ret = $" : {Method.ReturnType.ToSimple()}"; 32 | var arg = string.Join(",", Method.TypeArguments 33 | .Select(t => t.ToSimple())); 34 | var args = arg.Length == 0 ? string.Empty : $"<{arg}>"; 35 | if (Method.SymbolKind == SymbolKind.Constructor) 36 | { 37 | name = Method.DeclaringType.Name; 38 | ret = null; 39 | } 40 | return $"{name}{args}({prm}){ret}"; 41 | } 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /src/Spy/TurboSpy.Lib/Model/NameSpaceItem.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using System.Text; 4 | using ICSharpCode.Decompiler.TypeSystem; 5 | using TurboSpy.Core; 6 | 7 | namespace TurboSpy.Model 8 | { 9 | public class NameSpaceItem : SpyItem 10 | { 11 | private readonly string _name; 12 | private readonly ITypeDefinition[] _typeDefs; 13 | 14 | public NameSpaceItem(SpyItem parent, string name, ITypeDefinition[] typeDefs) 15 | : base(parent) 16 | { 17 | _name = name; 18 | _typeDefs = typeDefs; 19 | } 20 | 21 | public override bool CanExpand => _typeDefs.Any(); 22 | 23 | public override IEnumerable GetChildren() 24 | { 25 | foreach (var def in _typeDefs) 26 | { 27 | yield return new TypeDefItem(Parent, def); 28 | } 29 | } 30 | 31 | protected override string Text => _name; 32 | 33 | public string GetListTxt() 34 | { 35 | var bld = new StringBuilder(); 36 | bld.AppendLine(); 37 | var real = _name.Replace(OneFile.RootNamespace, string.Empty); 38 | var full = $"// {real}"; 39 | bld.AppendLine(full); 40 | bld.AppendLine(); 41 | return bld.ToString(); 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /src/Spy/TurboSpy.Lib/Model/PropertyItem.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using ICSharpCode.Decompiler.TypeSystem; 3 | using TurboSpy.Core; 4 | 5 | namespace TurboSpy.Model 6 | { 7 | public class PropertyItem : SpyItem 8 | { 9 | public PropertyItem(SpyItem parent, IProperty property) : base(parent) 10 | { 11 | Property = property; 12 | } 13 | 14 | public IProperty Property { get; } 15 | 16 | public override bool CanExpand => false; 17 | 18 | public override IEnumerable GetChildren() 19 | { 20 | yield break; 21 | } 22 | 23 | protected override string Text 24 | => $"{Property.Name} : {Property.ReturnType.ToSimple()}"; 25 | } 26 | } -------------------------------------------------------------------------------- /src/Spy/TurboSpy.Lib/Model/ReferenceItem.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Reflection; 3 | using System.Text; 4 | 5 | namespace TurboSpy.Model 6 | { 7 | public class ReferenceItem : SpyItem 8 | { 9 | private readonly AssemblyName _module; 10 | 11 | public ReferenceItem(SpyItem parent, AssemblyName module) : base(parent) 12 | { 13 | _module = module; 14 | } 15 | 16 | public override bool CanExpand => false; 17 | 18 | public override IEnumerable GetChildren() 19 | { 20 | yield break; 21 | } 22 | 23 | protected override string Text => _module.Name; 24 | 25 | public string GetListTxt() 26 | { 27 | var bld = new StringBuilder(); 28 | bld.AppendLine(); 29 | var full = $"// {_module.FullName}"; 30 | bld.AppendLine(full); 31 | bld.AppendLine(); 32 | return bld.ToString(); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /src/Spy/TurboSpy.Lib/Model/ReferencesItem.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using System.Reflection; 4 | using System.Text; 5 | using ICSharpCode.Decompiler.Metadata; 6 | 7 | namespace TurboSpy.Model 8 | { 9 | public class ReferencesItem : SpyItem 10 | { 11 | private readonly AssemblyName[] _modules; 12 | private readonly PEFile _file; 13 | 14 | public ReferencesItem(SpyItem parent, IEnumerable modules) : base(parent) 15 | { 16 | _modules = modules.ToArray(); 17 | _file = ((AssemblyItem)parent).One.File; 18 | } 19 | 20 | public override bool CanExpand => _modules.Any(); 21 | 22 | public override IEnumerable GetChildren() 23 | { 24 | foreach (var module in _modules) 25 | { 26 | yield return new ReferenceItem(Parent, module); 27 | } 28 | } 29 | 30 | protected override string Text => "References"; 31 | 32 | public string GetListTxt() 33 | { 34 | var bld = new StringBuilder(); 35 | var meta = _file.Metadata.DetectTargetFrameworkId(); 36 | bld.AppendLine(); 37 | bld.AppendLine($"// Detected Target-Framework-Id: {meta}"); 38 | bld.AppendLine(); 39 | bld.AppendLine("// Referenced assemblies:"); 40 | foreach (var mod in _modules) 41 | { 42 | bld.AppendLine($"// {mod}"); 43 | } 44 | bld.AppendLine(); 45 | return bld.ToString(); 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /src/Spy/TurboSpy.Lib/Model/SpyItem.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace TurboSpy.Model 4 | { 5 | public abstract class SpyItem 6 | { 7 | public SpyItem Parent { get; } 8 | 9 | protected SpyItem(SpyItem parent) 10 | { 11 | Parent = parent; 12 | } 13 | 14 | public abstract bool CanExpand { get; } 15 | public abstract IEnumerable GetChildren(); 16 | protected abstract string Text { get; } 17 | 18 | public override string ToString() => $" {Text}"; 19 | } 20 | } -------------------------------------------------------------------------------- /src/Spy/TurboSpy.Lib/Model/TypeDefItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using ICSharpCode.Decompiler.TypeSystem; 5 | 6 | namespace TurboSpy.Model 7 | { 8 | public class TypeDefItem : SpyItem 9 | { 10 | private readonly ITypeDefinition _def; 11 | 12 | public TypeDefItem(SpyItem parent, ITypeDefinition def) : base(parent) 13 | { 14 | _def = def; 15 | } 16 | 17 | public override bool CanExpand => true; 18 | 19 | public override IEnumerable GetChildren() 20 | { 21 | foreach (var f in _def.Fields.OrderBy(x => x.Name)) 22 | { 23 | if (f.Name.EndsWith("__BackingField")) 24 | continue; 25 | yield return new FieldItem(Parent, f); 26 | } 27 | foreach (var p in _def.Properties.OrderBy(x => x.Name)) 28 | { 29 | yield return new PropertyItem(Parent, p); 30 | } 31 | foreach (var e in _def.Events.OrderBy(x => x.Name)) 32 | { 33 | yield return new EventItem(Parent, e); 34 | } 35 | foreach (var m in _def.Methods.OrderBy(x => x.Name)) 36 | { 37 | if (m.GetType().Name == "FakeMethod" || m.Name.StartsWith("<")) 38 | continue; 39 | yield return new MethodItem(Parent, m); 40 | } 41 | } 42 | 43 | protected override string Text => $"[{Kind}] {_def.Name}{Suffix}"; 44 | 45 | public string Suffix 46 | { 47 | get 48 | { 49 | var prm = string.Join(",", _def.TypeParameters 50 | .Select(t => t.Name)); 51 | return prm.Length == 0 ? string.Empty : $"<{prm}>"; 52 | } 53 | } 54 | 55 | public FullTypeName TypeName => _def.FullTypeName; 56 | 57 | private string Kind 58 | { 59 | get 60 | { 61 | var kind = _def.Kind; 62 | switch (kind) 63 | { 64 | case TypeKind.Class: 65 | return "C"; 66 | case TypeKind.Enum: 67 | return "E"; 68 | case TypeKind.Interface: 69 | return "I"; 70 | case TypeKind.Struct: 71 | return "S"; 72 | case TypeKind.Delegate: 73 | return "D"; 74 | default: 75 | throw new InvalidOperationException($"{kind} ?!"); 76 | } 77 | } 78 | } 79 | } 80 | } -------------------------------------------------------------------------------- /src/Spy/TurboSpy.Lib/SpyCli.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Terminal.Gui; 3 | using TurboBase.UI; 4 | using TurboSpy.View; 5 | 6 | namespace TurboSpy 7 | { 8 | public static class SpyCli 9 | { 10 | public static int Main(string[] args) 11 | { 12 | var boot = new Env 13 | { 14 | Root = Environment.CurrentDirectory, 15 | Args = args 16 | }; 17 | 18 | Application.Init(); 19 | Application.Run(CreateTop(boot)); 20 | Application.Shutdown(); 21 | 22 | return 0; 23 | } 24 | 25 | public static Toplevel CreateTop(Env boot) => new MainTopLevel(boot); 26 | } 27 | } -------------------------------------------------------------------------------- /src/Spy/TurboSpy.Lib/TurboSpy.Lib.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | TurboSpy 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/Spy/TurboSpy.Lib/View/MainTopLevel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using Terminal.Gui; 7 | using Terminal.Gui.Trees; 8 | using TurboBase.IO; 9 | using TurboBase.UI; 10 | using TurboSpy.Core; 11 | using TurboSpy.Model; 12 | 13 | namespace TurboSpy.View 14 | { 15 | internal sealed class MainTopLevel : Toplevel 16 | { 17 | private readonly Env _boot; 18 | private readonly IDictionary _files; 19 | private readonly Decompiler _parent; 20 | private readonly TreeView _treeView; 21 | private readonly TextView _textView; 22 | 23 | public MainTopLevel(Env boot) 24 | { 25 | _boot = boot; 26 | _files = new SortedDictionary(); 27 | _parent = new Decompiler(); 28 | ColorScheme = Visuals.GetBaseColor(); 29 | MenuBar = CreateMenuBar(); 30 | var blue = Visuals.CreateTextColor(); 31 | var (tree, text, winL, winR) = CreateTree(blue, blue); 32 | _treeView = tree; 33 | _textView = text; 34 | var status = CreateStatus(); 35 | Add(MenuBar); 36 | Add(winL); 37 | Add(winR); 38 | Add(status); 39 | 40 | } 41 | 42 | private StatusBar CreateStatus() 43 | { 44 | var statusBar = new StatusBar(Array.Empty()); 45 | return statusBar; 46 | } 47 | 48 | private (TreeView, TextView, Window, Window) CreateTree(ColorScheme wColor, ColorScheme tColor) 49 | { 50 | var winL = new Window("Assemblies") 51 | { 52 | X = 0, 53 | Y = 1, 54 | Width = Dim.Percent(35), 55 | Height = Dim.Fill(), 56 | ColorScheme = wColor 57 | }; 58 | var treeView = new TreeView 59 | { 60 | Width = Dim.Fill(), 61 | Height = Dim.Fill(), 62 | ColorScheme = tColor 63 | }; 64 | treeView.TreeBuilder = new DelegateTreeBuilder(GetChild, CanExpand); 65 | treeView.SelectionChanged += OnTreeSelect; 66 | winL.Add(treeView); 67 | 68 | var winR = new Window("Decompiled") 69 | { 70 | X = Pos.Right(winL), 71 | Y = 1, 72 | Width = Dim.Percent(65), 73 | Height = Dim.Fill(), 74 | ColorScheme = wColor 75 | }; 76 | var textView = new TextView 77 | { 78 | Width = Dim.Fill(), 79 | Height = Dim.Fill(), 80 | BottomOffset = 1, 81 | RightOffset = 1, 82 | ColorScheme = tColor 83 | }; 84 | textView.ClearKeybinding(Key.AltMask | Key.F); 85 | winR.Add(textView); 86 | 87 | return (treeView, textView, winL, winR); 88 | } 89 | 90 | private bool CanExpand(SpyItem arg) => arg.CanExpand; 91 | private IEnumerable GetChild(SpyItem arg) => arg.GetChildren(); 92 | 93 | private void OnTreeSelect(object sender, SelectionChangedEventArgs e) 94 | { 95 | var selected = e.NewValue; 96 | if (selected is AssemblyItem ai) 97 | { 98 | var moduleMeta = ai.One.GetModuleTxt(); 99 | _textView.Text = moduleMeta; 100 | return; 101 | } 102 | if (selected is ReferencesItem ri) 103 | { 104 | var refsMeta = ri.GetListTxt(); 105 | _textView.Text = refsMeta; 106 | return; 107 | } 108 | if (selected is ReferenceItem rfi) 109 | { 110 | var refMeta = rfi.GetListTxt(); 111 | _textView.Text = refMeta; 112 | return; 113 | } 114 | if (selected is NameSpaceItem ni) 115 | { 116 | var nspMeta = ni.GetListTxt(); 117 | _textView.Text = nspMeta; 118 | return; 119 | } 120 | if (selected is TypeDefItem ti) 121 | { 122 | var code = ((AssemblyItem)ti.Parent).One.Decompile(ti); 123 | _textView.Text = code; 124 | return; 125 | } 126 | if (selected is PropertyItem pi) 127 | { 128 | var code = ((AssemblyItem)pi.Parent).One.Decompile(pi.Property); 129 | _textView.Text = code; 130 | return; 131 | } 132 | if (selected is MethodItem mi) 133 | { 134 | var code = ((AssemblyItem)mi.Parent).One.Decompile(mi.Method); 135 | _textView.Text = code; 136 | return; 137 | } 138 | if (selected is FieldItem fi) 139 | { 140 | var code = ((AssemblyItem)fi.Parent).One.Decompile(fi.Field); 141 | _textView.Text = code; 142 | return; 143 | } 144 | if (selected is EventItem ei) 145 | { 146 | var code = ((AssemblyItem)ei.Parent).One.Decompile(ei.Event); 147 | _textView.Text = code; 148 | return; 149 | } 150 | } 151 | 152 | private MenuBar CreateMenuBar() 153 | { 154 | return new MenuBar(new[] 155 | { 156 | new MenuBarItem("_File", new[] 157 | { 158 | new MenuItem("_Open...", null, DoOpen, 159 | null, null, Key.CtrlMask | Key.O), 160 | null, 161 | new MenuItem("E_xit", null, DoExit, 162 | null, null, Key.AltMask | Key.X) 163 | }), 164 | new MenuBarItem("_View", new[] 165 | { 166 | new MenuItem("_Collapse all nodes", null, DoCollapse) 167 | }), 168 | new MenuBarItem("_Help", new[] 169 | { 170 | new MenuItem("_About...", null, DoAbout) 171 | }) 172 | }); 173 | } 174 | 175 | private void DoCollapse() 176 | { 177 | _treeView.CollapseAll(); 178 | } 179 | 180 | private void DoOpen() 181 | { 182 | var allowed = new List { ".dll", ".exe" }; 183 | var dialog = new OpenDialog("Open", "Choose a single file or more.", allowed) 184 | { 185 | AllowsMultipleSelection = false 186 | }; 187 | Application.Run(dialog); 188 | 189 | if (dialog.Canceled || dialog.FilePaths.Count <= 0) 190 | return; 191 | 192 | var currentFile = dialog.FilePaths[0]; 193 | AddFile(currentFile); 194 | } 195 | 196 | private void AddFile(string rawFile) 197 | { 198 | var currentFile = Path.GetFullPath(rawFile); 199 | if (!IoTools.IsValidFile(currentFile)) 200 | { 201 | ShowError(currentFile); 202 | return; 203 | } 204 | var one = LoadFile(currentFile); 205 | _files[currentFile] = one; 206 | RefreshTree(one); 207 | } 208 | 209 | private static void ShowError(string file) 210 | { 211 | MessageBox.ErrorQuery("Load error", file, "_OK"); 212 | } 213 | 214 | private void RefreshTree(OneFile one) 215 | { 216 | var wrap = new AssemblyItem(one); 217 | _treeView.AddObject(wrap); 218 | if (_treeView.Objects.Count() <= 1) 219 | _treeView.GoToFirst(); 220 | _treeView.SetNeedsDisplay(); 221 | _treeView.SetFocus(); 222 | } 223 | 224 | private OneFile LoadFile(string fileName) 225 | { 226 | var decompiler = _parent.GetDecompiler(fileName); 227 | var one = new OneFile(decompiler); 228 | return one; 229 | } 230 | 231 | private void DoExit() 232 | { 233 | RequestStop(); 234 | } 235 | 236 | private static void DoAbout() 237 | { 238 | MessageBox.Query("About", GetAboutMessage(), "_OK"); 239 | } 240 | 241 | private static string GetAboutMessage() 242 | { 243 | var message = new StringBuilder(); 244 | message.AppendLine(@""); 245 | message.AppendLine(@"Turbo Spy"); 246 | message.AppendLine(@""); 247 | message.AppendLine(@"Version 0.1"); 248 | message.AppendLine(@""); 249 | message.AppendLine(@"Copyright (C) 2023 by"); 250 | message.AppendLine(@""); 251 | message.AppendLine(@"Open Inventions, Inc."); 252 | return message.ToString(); 253 | } 254 | } 255 | } -------------------------------------------------------------------------------- /src/Spy/TurboSpy/Program.cs: -------------------------------------------------------------------------------- 1 | namespace TurboSpy 2 | { 3 | internal static class Program 4 | { 5 | private static int Main(string[] args) 6 | { 7 | return SpyCli.Main(args); 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /src/Spy/TurboSpy/TurboSpy.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | spy 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/Spy/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | cd TurboSpy 3 | dotnet publish -r linux-x64 -p:PublishSingleFile=true --self-contained true 4 | dotnet publish -r win-x64 -p:PublishSingleFile=true --self-contained true 5 | -------------------------------------------------------------------------------- /src/Spy/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | sakura -m -d ./TurboSpy -x "dotnet run" 3 | -------------------------------------------------------------------------------- /src/TurboSharp.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.0.31903.59 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Core", "Core", "{CDB19826-CF2C-4A92-B681-026131314C43}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TurboMeta.API", "Core\TurboMeta.API\TurboMeta.API.csproj", "{E72FDB23-45FC-4CBB-916E-6282088C06ED}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TurboMeta.Tests", "Core\TurboMeta.Tests\TurboMeta.Tests.csproj", "{14C8AE3F-AC8B-46D8-AB83-0C74E7412713}" 11 | EndProject 12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Base", "Base", "{810B98FE-FD55-4D48-B163-509C41DBB1AA}" 13 | EndProject 14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TurboBase.IO", "Base\TurboBase.IO\TurboBase.IO.csproj", "{81BDBA4C-A6C7-4AF4-9E4D-9E51972E0063}" 15 | EndProject 16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TurboCompile.API", "Core\TurboCompile.API\TurboCompile.API.csproj", "{32AAAEEE-8A1C-4725-B5A6-0186DA3F2E78}" 17 | EndProject 18 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TurboCompile.Common", "Core\TurboCompile.Common\TurboCompile.Common.csproj", "{AAB09818-9432-44DA-9BC2-37E7E42BB3D8}" 19 | EndProject 20 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TurboCompile.CSharp", "Core\TurboCompile.CSharp\TurboCompile.CSharp.csproj", "{D6A79EDA-9460-4F2A-8310-67F58B73EB98}" 21 | EndProject 22 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TurboCompile.Roslyn", "Core\TurboCompile.Roslyn\TurboCompile.Roslyn.csproj", "{2BAD6465-D7BC-4B26-B908-D302CED65475}" 23 | EndProject 24 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TurboCompile.VBasic", "Core\TurboCompile.VBasic\TurboCompile.VBasic.csproj", "{C0009F34-3A1D-427A-8E74-B4933DFDB4F7}" 25 | EndProject 26 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{778B31F3-D16F-4305-800B-547C14F30885}" 27 | EndProject 28 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TurboDot", "Build\TurboDot\TurboDot.csproj", "{D571B6D1-D597-42DF-BD24-662BEF38682B}" 29 | EndProject 30 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TurboDot.Lib", "Build\TurboDot.Lib\TurboDot.Lib.csproj", "{AD80405F-6976-4899-95D0-7B06C0255617}" 31 | EndProject 32 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Spy", "Spy", "{4E3F9F81-E011-4376-99BE-1ADB92E4D58D}" 33 | EndProject 34 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TurboSpy", "Spy\TurboSpy\TurboSpy.csproj", "{821F219C-D85B-49BC-86BD-2009A9203EBC}" 35 | EndProject 36 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TurboSpy.Lib", "Spy\TurboSpy.Lib\TurboSpy.Lib.csproj", "{7969B215-4E21-4B10-B580-04F9BC74577D}" 37 | EndProject 38 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Run", "Run", "{CD38A618-33A1-447D-B436-58183513C0A1}" 39 | EndProject 40 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TurboRun", "Run\TurboRun\TurboRun.csproj", "{1D3D03EF-9620-4E87-B0B2-A8453AA6A8E6}" 41 | EndProject 42 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TurboRun.Lib", "Run\TurboRun.Lib\TurboRun.Lib.csproj", "{DEBB8FB3-7729-4EDB-82B8-108F378DD367}" 43 | EndProject 44 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "IDE", "IDE", "{10814D7C-EB38-4639-A292-06F040887E80}" 45 | EndProject 46 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TurboSharp", "IDE\TurboSharp\TurboSharp.csproj", "{D920307F-E510-4957-8D95-313670738D3D}" 47 | EndProject 48 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TurboSharp.Lib", "IDE\TurboSharp.Lib\TurboSharp.Lib.csproj", "{429363C3-DB09-4F9E-9432-B3D1205D7C5A}" 49 | EndProject 50 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TurboBase.UI", "Base\TurboBase.UI\TurboBase.UI.csproj", "{4B71CF1B-412D-4AAC-9511-26351612AC83}" 51 | EndProject 52 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TurboMeta.CSharp", "Core\TurboMeta.CSharp\TurboMeta.CSharp.csproj", "{2A9E643B-0115-4C7C-86E8-F61617620F50}" 53 | EndProject 54 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TurboMeta.VBasic", "Core\TurboMeta.VBasic\TurboMeta.VBasic.csproj", "{05963BEF-F30B-4F68-B625-FE3BC5D65A64}" 55 | EndProject 56 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TurboMeta.Common", "Core\TurboMeta.Common\TurboMeta.Common.csproj", "{3339DCBF-6043-47D5-8949-B8054B7B254D}" 57 | EndProject 58 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TurboRepo.API", "Core\TurboRepo.API\TurboRepo.API.csproj", "{CD558CE1-825F-4D5E-AE3A-1235E274DDE5}" 59 | EndProject 60 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TurboRepo.Nuget", "Core\TurboRepo.Nuget\TurboRepo.Nuget.csproj", "{69B1BC9A-BEB0-40BE-8DC9-A35E9055EA50}" 61 | EndProject 62 | Global 63 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 64 | Debug|Any CPU = Debug|Any CPU 65 | Release|Any CPU = Release|Any CPU 66 | EndGlobalSection 67 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 68 | {E72FDB23-45FC-4CBB-916E-6282088C06ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 69 | {E72FDB23-45FC-4CBB-916E-6282088C06ED}.Debug|Any CPU.Build.0 = Debug|Any CPU 70 | {E72FDB23-45FC-4CBB-916E-6282088C06ED}.Release|Any CPU.ActiveCfg = Release|Any CPU 71 | {E72FDB23-45FC-4CBB-916E-6282088C06ED}.Release|Any CPU.Build.0 = Release|Any CPU 72 | {14C8AE3F-AC8B-46D8-AB83-0C74E7412713}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 73 | {14C8AE3F-AC8B-46D8-AB83-0C74E7412713}.Debug|Any CPU.Build.0 = Debug|Any CPU 74 | {14C8AE3F-AC8B-46D8-AB83-0C74E7412713}.Release|Any CPU.ActiveCfg = Release|Any CPU 75 | {14C8AE3F-AC8B-46D8-AB83-0C74E7412713}.Release|Any CPU.Build.0 = Release|Any CPU 76 | {81BDBA4C-A6C7-4AF4-9E4D-9E51972E0063}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 77 | {81BDBA4C-A6C7-4AF4-9E4D-9E51972E0063}.Debug|Any CPU.Build.0 = Debug|Any CPU 78 | {81BDBA4C-A6C7-4AF4-9E4D-9E51972E0063}.Release|Any CPU.ActiveCfg = Release|Any CPU 79 | {81BDBA4C-A6C7-4AF4-9E4D-9E51972E0063}.Release|Any CPU.Build.0 = Release|Any CPU 80 | {32AAAEEE-8A1C-4725-B5A6-0186DA3F2E78}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 81 | {32AAAEEE-8A1C-4725-B5A6-0186DA3F2E78}.Debug|Any CPU.Build.0 = Debug|Any CPU 82 | {32AAAEEE-8A1C-4725-B5A6-0186DA3F2E78}.Release|Any CPU.ActiveCfg = Release|Any CPU 83 | {32AAAEEE-8A1C-4725-B5A6-0186DA3F2E78}.Release|Any CPU.Build.0 = Release|Any CPU 84 | {AAB09818-9432-44DA-9BC2-37E7E42BB3D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 85 | {AAB09818-9432-44DA-9BC2-37E7E42BB3D8}.Debug|Any CPU.Build.0 = Debug|Any CPU 86 | {AAB09818-9432-44DA-9BC2-37E7E42BB3D8}.Release|Any CPU.ActiveCfg = Release|Any CPU 87 | {AAB09818-9432-44DA-9BC2-37E7E42BB3D8}.Release|Any CPU.Build.0 = Release|Any CPU 88 | {D6A79EDA-9460-4F2A-8310-67F58B73EB98}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 89 | {D6A79EDA-9460-4F2A-8310-67F58B73EB98}.Debug|Any CPU.Build.0 = Debug|Any CPU 90 | {D6A79EDA-9460-4F2A-8310-67F58B73EB98}.Release|Any CPU.ActiveCfg = Release|Any CPU 91 | {D6A79EDA-9460-4F2A-8310-67F58B73EB98}.Release|Any CPU.Build.0 = Release|Any CPU 92 | {2BAD6465-D7BC-4B26-B908-D302CED65475}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 93 | {2BAD6465-D7BC-4B26-B908-D302CED65475}.Debug|Any CPU.Build.0 = Debug|Any CPU 94 | {2BAD6465-D7BC-4B26-B908-D302CED65475}.Release|Any CPU.ActiveCfg = Release|Any CPU 95 | {2BAD6465-D7BC-4B26-B908-D302CED65475}.Release|Any CPU.Build.0 = Release|Any CPU 96 | {C0009F34-3A1D-427A-8E74-B4933DFDB4F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 97 | {C0009F34-3A1D-427A-8E74-B4933DFDB4F7}.Debug|Any CPU.Build.0 = Debug|Any CPU 98 | {C0009F34-3A1D-427A-8E74-B4933DFDB4F7}.Release|Any CPU.ActiveCfg = Release|Any CPU 99 | {C0009F34-3A1D-427A-8E74-B4933DFDB4F7}.Release|Any CPU.Build.0 = Release|Any CPU 100 | {D571B6D1-D597-42DF-BD24-662BEF38682B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 101 | {D571B6D1-D597-42DF-BD24-662BEF38682B}.Debug|Any CPU.Build.0 = Debug|Any CPU 102 | {D571B6D1-D597-42DF-BD24-662BEF38682B}.Release|Any CPU.ActiveCfg = Release|Any CPU 103 | {D571B6D1-D597-42DF-BD24-662BEF38682B}.Release|Any CPU.Build.0 = Release|Any CPU 104 | {AD80405F-6976-4899-95D0-7B06C0255617}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 105 | {AD80405F-6976-4899-95D0-7B06C0255617}.Debug|Any CPU.Build.0 = Debug|Any CPU 106 | {AD80405F-6976-4899-95D0-7B06C0255617}.Release|Any CPU.ActiveCfg = Release|Any CPU 107 | {AD80405F-6976-4899-95D0-7B06C0255617}.Release|Any CPU.Build.0 = Release|Any CPU 108 | {821F219C-D85B-49BC-86BD-2009A9203EBC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 109 | {821F219C-D85B-49BC-86BD-2009A9203EBC}.Debug|Any CPU.Build.0 = Debug|Any CPU 110 | {821F219C-D85B-49BC-86BD-2009A9203EBC}.Release|Any CPU.ActiveCfg = Release|Any CPU 111 | {821F219C-D85B-49BC-86BD-2009A9203EBC}.Release|Any CPU.Build.0 = Release|Any CPU 112 | {7969B215-4E21-4B10-B580-04F9BC74577D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 113 | {7969B215-4E21-4B10-B580-04F9BC74577D}.Debug|Any CPU.Build.0 = Debug|Any CPU 114 | {7969B215-4E21-4B10-B580-04F9BC74577D}.Release|Any CPU.ActiveCfg = Release|Any CPU 115 | {7969B215-4E21-4B10-B580-04F9BC74577D}.Release|Any CPU.Build.0 = Release|Any CPU 116 | {1D3D03EF-9620-4E87-B0B2-A8453AA6A8E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 117 | {1D3D03EF-9620-4E87-B0B2-A8453AA6A8E6}.Debug|Any CPU.Build.0 = Debug|Any CPU 118 | {1D3D03EF-9620-4E87-B0B2-A8453AA6A8E6}.Release|Any CPU.ActiveCfg = Release|Any CPU 119 | {1D3D03EF-9620-4E87-B0B2-A8453AA6A8E6}.Release|Any CPU.Build.0 = Release|Any CPU 120 | {DEBB8FB3-7729-4EDB-82B8-108F378DD367}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 121 | {DEBB8FB3-7729-4EDB-82B8-108F378DD367}.Debug|Any CPU.Build.0 = Debug|Any CPU 122 | {DEBB8FB3-7729-4EDB-82B8-108F378DD367}.Release|Any CPU.ActiveCfg = Release|Any CPU 123 | {DEBB8FB3-7729-4EDB-82B8-108F378DD367}.Release|Any CPU.Build.0 = Release|Any CPU 124 | {D920307F-E510-4957-8D95-313670738D3D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 125 | {D920307F-E510-4957-8D95-313670738D3D}.Debug|Any CPU.Build.0 = Debug|Any CPU 126 | {D920307F-E510-4957-8D95-313670738D3D}.Release|Any CPU.ActiveCfg = Release|Any CPU 127 | {D920307F-E510-4957-8D95-313670738D3D}.Release|Any CPU.Build.0 = Release|Any CPU 128 | {429363C3-DB09-4F9E-9432-B3D1205D7C5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 129 | {429363C3-DB09-4F9E-9432-B3D1205D7C5A}.Debug|Any CPU.Build.0 = Debug|Any CPU 130 | {429363C3-DB09-4F9E-9432-B3D1205D7C5A}.Release|Any CPU.ActiveCfg = Release|Any CPU 131 | {429363C3-DB09-4F9E-9432-B3D1205D7C5A}.Release|Any CPU.Build.0 = Release|Any CPU 132 | {4B71CF1B-412D-4AAC-9511-26351612AC83}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 133 | {4B71CF1B-412D-4AAC-9511-26351612AC83}.Debug|Any CPU.Build.0 = Debug|Any CPU 134 | {4B71CF1B-412D-4AAC-9511-26351612AC83}.Release|Any CPU.ActiveCfg = Release|Any CPU 135 | {4B71CF1B-412D-4AAC-9511-26351612AC83}.Release|Any CPU.Build.0 = Release|Any CPU 136 | {2A9E643B-0115-4C7C-86E8-F61617620F50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 137 | {2A9E643B-0115-4C7C-86E8-F61617620F50}.Debug|Any CPU.Build.0 = Debug|Any CPU 138 | {2A9E643B-0115-4C7C-86E8-F61617620F50}.Release|Any CPU.ActiveCfg = Release|Any CPU 139 | {2A9E643B-0115-4C7C-86E8-F61617620F50}.Release|Any CPU.Build.0 = Release|Any CPU 140 | {05963BEF-F30B-4F68-B625-FE3BC5D65A64}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 141 | {05963BEF-F30B-4F68-B625-FE3BC5D65A64}.Debug|Any CPU.Build.0 = Debug|Any CPU 142 | {05963BEF-F30B-4F68-B625-FE3BC5D65A64}.Release|Any CPU.ActiveCfg = Release|Any CPU 143 | {05963BEF-F30B-4F68-B625-FE3BC5D65A64}.Release|Any CPU.Build.0 = Release|Any CPU 144 | {3339DCBF-6043-47D5-8949-B8054B7B254D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 145 | {3339DCBF-6043-47D5-8949-B8054B7B254D}.Debug|Any CPU.Build.0 = Debug|Any CPU 146 | {3339DCBF-6043-47D5-8949-B8054B7B254D}.Release|Any CPU.ActiveCfg = Release|Any CPU 147 | {3339DCBF-6043-47D5-8949-B8054B7B254D}.Release|Any CPU.Build.0 = Release|Any CPU 148 | {CD558CE1-825F-4D5E-AE3A-1235E274DDE5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 149 | {CD558CE1-825F-4D5E-AE3A-1235E274DDE5}.Debug|Any CPU.Build.0 = Debug|Any CPU 150 | {CD558CE1-825F-4D5E-AE3A-1235E274DDE5}.Release|Any CPU.ActiveCfg = Release|Any CPU 151 | {CD558CE1-825F-4D5E-AE3A-1235E274DDE5}.Release|Any CPU.Build.0 = Release|Any CPU 152 | {69B1BC9A-BEB0-40BE-8DC9-A35E9055EA50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 153 | {69B1BC9A-BEB0-40BE-8DC9-A35E9055EA50}.Debug|Any CPU.Build.0 = Debug|Any CPU 154 | {69B1BC9A-BEB0-40BE-8DC9-A35E9055EA50}.Release|Any CPU.ActiveCfg = Release|Any CPU 155 | {69B1BC9A-BEB0-40BE-8DC9-A35E9055EA50}.Release|Any CPU.Build.0 = Release|Any CPU 156 | EndGlobalSection 157 | GlobalSection(SolutionProperties) = preSolution 158 | HideSolutionNode = FALSE 159 | EndGlobalSection 160 | GlobalSection(NestedProjects) = preSolution 161 | {E72FDB23-45FC-4CBB-916E-6282088C06ED} = {CDB19826-CF2C-4A92-B681-026131314C43} 162 | {14C8AE3F-AC8B-46D8-AB83-0C74E7412713} = {CDB19826-CF2C-4A92-B681-026131314C43} 163 | {81BDBA4C-A6C7-4AF4-9E4D-9E51972E0063} = {810B98FE-FD55-4D48-B163-509C41DBB1AA} 164 | {32AAAEEE-8A1C-4725-B5A6-0186DA3F2E78} = {CDB19826-CF2C-4A92-B681-026131314C43} 165 | {AAB09818-9432-44DA-9BC2-37E7E42BB3D8} = {CDB19826-CF2C-4A92-B681-026131314C43} 166 | {D6A79EDA-9460-4F2A-8310-67F58B73EB98} = {CDB19826-CF2C-4A92-B681-026131314C43} 167 | {2BAD6465-D7BC-4B26-B908-D302CED65475} = {CDB19826-CF2C-4A92-B681-026131314C43} 168 | {C0009F34-3A1D-427A-8E74-B4933DFDB4F7} = {CDB19826-CF2C-4A92-B681-026131314C43} 169 | {D571B6D1-D597-42DF-BD24-662BEF38682B} = {778B31F3-D16F-4305-800B-547C14F30885} 170 | {AD80405F-6976-4899-95D0-7B06C0255617} = {778B31F3-D16F-4305-800B-547C14F30885} 171 | {821F219C-D85B-49BC-86BD-2009A9203EBC} = {4E3F9F81-E011-4376-99BE-1ADB92E4D58D} 172 | {7969B215-4E21-4B10-B580-04F9BC74577D} = {4E3F9F81-E011-4376-99BE-1ADB92E4D58D} 173 | {1D3D03EF-9620-4E87-B0B2-A8453AA6A8E6} = {CD38A618-33A1-447D-B436-58183513C0A1} 174 | {DEBB8FB3-7729-4EDB-82B8-108F378DD367} = {CD38A618-33A1-447D-B436-58183513C0A1} 175 | {D920307F-E510-4957-8D95-313670738D3D} = {10814D7C-EB38-4639-A292-06F040887E80} 176 | {429363C3-DB09-4F9E-9432-B3D1205D7C5A} = {10814D7C-EB38-4639-A292-06F040887E80} 177 | {4B71CF1B-412D-4AAC-9511-26351612AC83} = {810B98FE-FD55-4D48-B163-509C41DBB1AA} 178 | {2A9E643B-0115-4C7C-86E8-F61617620F50} = {CDB19826-CF2C-4A92-B681-026131314C43} 179 | {05963BEF-F30B-4F68-B625-FE3BC5D65A64} = {CDB19826-CF2C-4A92-B681-026131314C43} 180 | {3339DCBF-6043-47D5-8949-B8054B7B254D} = {CDB19826-CF2C-4A92-B681-026131314C43} 181 | {CD558CE1-825F-4D5E-AE3A-1235E274DDE5} = {CDB19826-CF2C-4A92-B681-026131314C43} 182 | {69B1BC9A-BEB0-40BE-8DC9-A35E9055EA50} = {CDB19826-CF2C-4A92-B681-026131314C43} 183 | EndGlobalSection 184 | GlobalSection(ExtensibilityGlobals) = postSolution 185 | SolutionGuid = {8A41EE0E-B54F-4045-AF59-6E881C898802} 186 | EndGlobalSection 187 | EndGlobal 188 | --------------------------------------------------------------------------------