示例#1
0
        static void Main()
        {
            var sourcesPath = Path.Combine(Environment.CurrentDirectory, "Sources");

            Console.WriteLine($"Running from: {Environment.CurrentDirectory}");
            Console.WriteLine($"Sources from: {sourcesPath}");
            Console.WriteLine("Modify the sources to compile and run it!");

            var compiler = new Compiler();
            var runner   = new Runner();

            using (var watcher = new ObservableFileSystemWatcher(c => { c.Path = @".\Sources"; }))
            {
                var changes = watcher.Changed.Throttle(TimeSpan.FromSeconds(.5)).Where(c => c.FullPath.EndsWith(@"DynamicProgram.cs")).Select(c => c.FullPath);

                changes.Subscribe(filepath => runner.Execute(compiler.Compile(filepath), new[] { "France" }));

                watcher.Start();

                Console.WriteLine("Press any key to exit!");
                Console.ReadLine();
            }
        }
示例#2
0
        public static async Task Live(LiveConfiguration configuration = null)
        {
            //Extract LiveBlazor.zip to a temporary folter
            //var stream = typeof(LiveBlazor).Assembly.GetManifestResourceStream("LivingThing.LiveBlazor.LiveBlazor.zip");
            //var workingDirectory = Path.GetDirectoryName(Path.Combine(Environment.CurrentDirectory, "..", "LiveBlazor"));
            //if (!Directory.Exists(workingDirectory))
            //{
            //    Directory.CreateDirectory(workingDirectory);
            //}
            //var zipPath = Path.Combine(workingDirectory, "LiveBlazor.zip");
            //FileStream fs = new FileStream(zipPath, FileMode.Create);
            //stream.CopyTo(fs);
            //fs.Close();
            //stream.Close();
            //ZipFile.ExtractToDirectory(zipPath, workingDirectory, true);
            ////prebuild project enabling restore, so we dont have to restor anymore, which is faster
            //$"cd {workingDirectory} & dotnet build".Bash();

            harmony = new Harmony("com.liveblazor.livingthing");
            var compiler = new Compiler();

            var invokeAsync     = typeof(ComponentBase).GetMethod("InvokeAsync", bindingAttr: BindingFlags.NonPublic | BindingFlags.Instance, types: new Type[] { typeof(Action) }, binder: null, modifiers: null);
            var stateHasChanged = typeof(ComponentBase).GetMethod("StateHasChanged", BindingFlags.NonPublic | BindingFlags.Instance);

            //find all components in all assemblies
            var componentTypes = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes()).Where(t => !t.IsAbstract && t.MemberType == MemberTypes.TypeInfo && typeof(ComponentBase).IsAssignableFrom(t)).ToArray();
            var prefix         = typeof(Blazor).GetMethod(nameof(Prefix));

            foreach (var _type in componentTypes)
            {
                var types = configuration?.Filter?.Invoke(_type) ?? new Type[] { _type };
                foreach (var type in types)
                {
                    if (!typeof(ComponentBase).IsAssignableFrom(type))
                    {
                        throw new InvalidOperationException($"Type {type} is not a Component");
                    }
                    if (!type.ContainsGenericParameters)
                    {
                        var renderTree = type.GetMethod("BuildRenderTree", BindingFlags.NonPublic | BindingFlags.Instance);
                        if (renderTree.DeclaringType == type)
                        {
                            if (type.Name == "DeviceListItem")
                            {
                            }
                            var context = new LiveComponentContext()
                            {
                                OriginalMethod        = type.GetMethod("BuildRenderTree", BindingFlags.NonPublic | BindingFlags.Instance),
                                OriginalTypeInference = type.Assembly.GetType("__Blazor." + type.FullName + ".TypeInference"),
                            };
                            liveContexts[type] = context;
                            harmony.Patch(renderTree, new HarmonyMethod(prefix));
                        }
                    }
                }
            }

            string watchPath = configuration?.WatchDirectory ?? Environment.CurrentDirectory;

            if (configuration?.WatchDirectory == null)
            {
                var solutionPath = Path.GetFullPath(Path.Combine(watchPath, "../"));
                if (Directory.EnumerateFiles(solutionPath).Any(f => f.EndsWith(".sln")))
                {
                    watchPath = solutionPath;
                }
            }

            watcher = new ObservableFileSystemWatcher(c =>
            {
                c.Path = watchPath;
                c.IncludeSubdirectories = true;
                c.Filter       = "*.razor";
                c.NotifyFilter = NotifyFilters.Attributes |
                                 NotifyFilters.CreationTime |
                                 NotifyFilters.FileName |
                                 NotifyFilters.LastAccess |
                                 NotifyFilters.LastWrite |
                                 NotifyFilters.Size |
                                 NotifyFilters.Security;
                //c.Filters.Add("*.razor");
            });

            var changes = watcher.Changed.Throttle(TimeSpan.FromSeconds(.5));

            string dotnetPath    = (await "where dotnet".CLI()).StdOut.Trim();
            string dotnetVersion = (await "dotnet --version".CLI()).StdOut.Trim();
            var    dotnetFolder  = Path.GetDirectoryName(dotnetPath) + "\\";

            var buildRenderTreeMethodPatcher = typeof(Blazor).GetMethod(nameof(ReplaceBuildRenderTree));
            var typeInferenceMethodsPatcher  = typeof(Blazor).GetMethod(nameof(ReplaceTypeInference));

            changes.Subscribe(async filepath =>
            {
                string razorGeneratePath = configuration?.RazoGeneratorPath ?? @$ "{dotnetFolder}sdk\{dotnetVersion}\Sdks\Microsoft.NET.Sdk.Razor\tools\netcoreapp3.0\rzc.dll";
                var project              = GetProjectPath(Path.GetDirectoryName(filepath.FullPath));
                string projectName       = Path.GetFileNameWithoutExtension(project.FileName);
                var workspace            = $"obj\\Debug\\{project.Type}\\";
                var workingDirectory     = $"{project.Path}{workspace}";
                var outputPath           = $"{workingDirectory}{Path.GetFileName(filepath.FullPath)}.g.cs";
                string filePathInProject = filepath.FullPath.Replace(project.Path, "");
                var @namespace           = projectName;
                string compile           = $"dotnet exec \"{razorGeneratePath}\" generate -s \"{filepath.FullPath}\" -r \"{filePathInProject}\" -o \"{outputPath}\" -k component -p {project.Path} -v 3.0 -c {configuration?.ProjectConfiguration??"Default"} --root-namespace {@namespace} -t \"{workspace}{projectName}.TagHelpers.output.cache\"";
                await $"cd {project.Path} & {compile}".CLI();

                var file = File.ReadAllText(outputPath);
                List <string> sourceCodes = new List <string>()
                {
                    file
                };
                var csFile = Path.ChangeExtension(filepath.FullPath, ".razor.cs");
                if (File.Exists(csFile))
                {
                    var csFileContent = File.ReadAllText(csFile);
                    sourceCodes.Add(csFileContent);
                }


                var code = compiler.Compile(sourceCodes.ToArray());

                using (var asm = new MemoryStream(code))
                {
                    var assemblyLoadContext = new UnloadableAssemblyLoadContext();

                    var assembly = assemblyLoadContext.LoadFromStream(asm);
                    // var assembly = Assembly.Load(code);//.LoadFromStream(asm);
                    Type newType = assembly.ExportedTypes.First(t => t.Name == Path.GetFileNameWithoutExtension(filepath.Name));
                    //Type newType = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes()).First(t => t.Name == Path.GetFileNameWithoutExtension(filepath.Name));

                    assemblyLoadContext.Unload();

                    Type originalType = componentTypes.FirstOrDefault(t => t.FullName == newType.FullName);
                    if (originalType != null)
                    {
                        LiveComponentContext context = null;
                        liveContexts.TryGetValue(originalType, out context);
                        if (context != null)
                        {
                            context.NewType = newType;
                            currentType     = originalType;
                            try
                            {
                                harmony.Patch(context.OriginalMethod, transpiler: new HarmonyMethod(buildRenderTreeMethodPatcher));
                                //patch all anonymous method of this type
                                //var anonymousMethods =
                                //pathch typeInference class
                                Type inferenceType = assembly.DefinedTypes.FirstOrDefault(t => t.Name == "TypeInference");
                                if (inferenceType != null && context.OriginalTypeInference != null)
                                {
                                    currentTypeInference = inferenceType;
                                    var methods          = inferenceType.GetMethods();
                                    foreach (var method in methods)
                                    {
                                        var originalMethod = context.OriginalTypeInference.GetMethod(method.Name);
                                        harmony.Patch(originalMethod, transpiler: new HarmonyMethod(typeInferenceMethodsPatcher));
                                    }
                                }
                            }
                            catch (Exception e)
                            {
                                Console.WriteLine(e.Message);
                                Console.WriteLine(e.StackTrace);
                                return;
                            }
                            context.Components.ForEach(c =>
                            {
                                Action rerender = () => stateHasChanged.Invoke(c, new object[] { });
                                invokeAsync.Invoke(c, new object[] { rerender });
                            });
                        }
                    }
                }
            });
示例#3
0
 public FilesystemInjectorClient()
 {
     WatchMask          = "*.dll, *.exe";
     _fileSystemWatcher = new ObservableFileSystemWatcher(fsw => fsw.IncludeSubdirectories = true);
 }