示例#1
0
        public override async Task <int> Main()
        {
            try
            {
                Environment.CurrentDirectory = PathManager.FindResource();
            }
            catch (FileNotFoundException ex)
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine("Use `nfpm scaffold` to generate a NFive plugin in this directory");

                return(1);
            }

            AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
            {
                if (args.Name.Contains(".resources"))
                {
                    return(null);
                }

                var fileName = args.Name.Substring(0, args.Name.IndexOf(",", StringComparison.InvariantCultureIgnoreCase)) + ".dll";

                if (File.Exists(fileName))
                {
                    return(Assembly.Load(File.ReadAllBytes(fileName)));
                }

                var path = Directory.EnumerateFiles("plugins", "*.dll", SearchOption.AllDirectories).FirstOrDefault(f => Path.GetFileName(f) == fileName);

                if (string.IsNullOrEmpty(path))
                {
                    throw new FileLoadException(args.Name);
                }

                return(Assembly.Load(File.ReadAllBytes(path)));
            };

            DTE dte = null;

            try
            {
                if (!File.Exists(this.Sln))
                {
                    this.Sln = Directory.EnumerateFiles(Environment.CurrentDirectory, "*.sln", SearchOption.TopDirectoryOnly).FirstOrDefault();
                }
                if (this.Sln == null || !File.Exists(this.Sln))
                {
                    this.Sln = Input.String("Visual Studio SLN solution file");
                }

                Console.Write("Searching for existing Visual Studio instance...");

                dte = VisualStudio.GetInstances().FirstOrDefault(env => env.Solution.FileName == this.Sln);

                if (dte != default)
                {
                    Console.WriteLine(" found");
                }
                else
                {
                    Console.WriteLine(" not found");
                    Console.WriteLine("Starting new Visual Studio instance...");

                    dte = (DTE)Activator.CreateInstance(Type.GetTypeFromProgID("VisualStudio.DTE", true), true);

                    this.existingInstance = false;
                }

                Console.WriteLine("Opening solution");

                var solution = Retry.Do(() => dte.Solution);

                if (!Retry.Do(() => solution.IsOpen))
                {
                    Retry.Do(() => solution.Open(this.Sln));
                }

                Console.WriteLine("Building solution");

                solution.SolutionBuild.Build(true);

                Console.WriteLine("Searching for projects");

                var pp = Retry.Do(() => solution.Projects.Cast <Project>().ToList());

                var ppp = Retry.Do(() => pp.Where(p => !string.IsNullOrWhiteSpace(p.FullName)).ToList());

                foreach (var project in ppp)
                {
                    Console.WriteLine($"  Analyzing project {Retry.Do(() => project.Name)}...");

                    var projectPath = Path.GetDirectoryName(Retry.Do(() => project.FullName)) ?? string.Empty;
                    var outputPath  = Path.GetFullPath(Path.Combine(projectPath, Retry.Do(() => project.ConfigurationManager.ActiveConfiguration.Properties.Item("OutputPath").Value.ToString()), Retry.Do(() => project.Properties.Item("OutputFileName").Value.ToString())));

                    var asm = Assembly.Load(File.ReadAllBytes(outputPath));
                    if (!this.Sdk && asm.GetCustomAttribute <ServerPluginAttribute>() == null)
                    {
                        continue;
                    }

                    var contextType = asm.DefinedTypes.FirstOrDefault(t => t.BaseType != null && t.BaseType.IsGenericType && t.BaseType.GetGenericTypeDefinition() == typeof(EFContext <>));
                    if (contextType == default)
                    {
                        continue;
                    }

                    Console.WriteLine($"    Loaded {outputPath}");

                    Console.WriteLine($"    Found DB context: {contextType.Name}");

                    var props = contextType
                                .GetProperties()
                                .Where(p =>
                                       p.CanRead &&
                                       p.CanWrite &&
                                       p.PropertyType.IsGenericType &&
                                       p.PropertyType.GetGenericTypeDefinition() == typeof(DbSet <>) &&
                                       p.PropertyType.GenericTypeArguments.Any(t => !string.IsNullOrEmpty(t.Namespace) && t.Namespace.StartsWith("NFive.SDK."))) // TODO
                                .Select(t => $"dbo.{t.Name}")                                                                                                    // TODO
                                .ToArray();

                    if (!this.Sdk)
                    {
                        Console.WriteLine($"    Excluding tables: {string.Join(", ", props)}");
                    }

                    var migrationsPath = "Migrations";

                    if (!Directory.Exists(Path.Combine(projectPath, migrationsPath)))
                    {
                        migrationsPath = Input.String("Migration source code folder", "Migrations");                                                                                   // TODO: Validate
                    }
                    var @namespace = $"{project.Properties.Item("RootNamespace").Value}.{migrationsPath}";

                    if (asm.DefinedTypes.Any(t => t.BaseType != null && t.BaseType == typeof(DbMigration) && t.Namespace == @namespace && t.Name == this.Name))
                    {
                        throw new Exception($"A migration named \"{this.Name}\" already exists at \"{@namespace}.{this.Name}\", please use another migration name.");
                    }

                    Console.WriteLine("    Generating migration...");

                    var migrationsConfiguration = new DbMigrationsConfiguration
                    {
                        AutomaticMigrationDataLossAllowed = false,
                        AutomaticMigrationsEnabled        = false,
                        CodeGenerator       = new NFiveMigrationCodeGenerator(this.Sdk ? new string[] { } : props),
                        ContextType         = contextType,
                        ContextKey          = $"{@namespace}.Configuration",
                        MigrationsAssembly  = asm,
                        MigrationsDirectory = migrationsPath,
                        MigrationsNamespace = @namespace,
                        TargetDatabase      = new DbConnectionInfo(this.Database, "MySql.Data.MySqlClient")
                    };

                    var ms = new MigrationScaffolder(migrationsConfiguration);

                    if (this.RunMigrations)
                    {
                        var migrator = new DbMigrator(migrationsConfiguration);

                        if (migrator.GetPendingMigrations().Any())
                        {
                            Console.WriteLine("    Running existing migrations...");

                            foreach (var migration in migrator.GetPendingMigrations())
                            {
                                Console.WriteLine($"        Running migration: {migration}");

                                migrator.Update(migration);
                            }
                        }
                    }

                    Console.WriteLine("    Scaffolding migration...");

                    var src = ms.Scaffold(this.Name, false);

                    var file = Path.Combine(projectPath, migrationsPath, $"{src.MigrationId}.{src.Language}");

                    Console.WriteLine($"    Writing migration: {file}");

                    File.WriteAllText(file, src.UserCode);

                    Console.WriteLine("    Updating project...");

                    project.ProjectItems.AddFromFile(file);
                    project.Save();
                }

                Console.WriteLine("Building solution...");

                solution.SolutionBuild.Build(true);

                if (!this.existingInstance)
                {
                    Console.WriteLine("Quitting Visual Studio instance");

                    dte.Quit();
                }

                Console.WriteLine("Done");

                return(await Task.FromResult(0));
            }
            catch (ReflectionTypeLoadException ex)
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine(string.Join(Environment.NewLine, ex.LoaderExceptions.Select(e => e.Message)));

                return(1);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);

                return(1);
            }
            finally
            {
                if (!this.existingInstance)
                {
                    dte.Quit();
                }
            }
        }