private static int Execute(CommonOptions commonOptions,
            string from,
            string to,
            string output,
            bool idempotent,
            string context,
            string environment)
        {
            var sql = new OperationExecutor(commonOptions, environment)
                .ScriptMigration(from, to, idempotent, context);

            if (string.IsNullOrEmpty(output))
            {
                ConsoleCommandLogger.Output(sql);
            }
            else
            {
                ConsoleCommandLogger.Verbose("Writing SQL script to '" + output + "'".Bold().Black());
                File.WriteAllText(output, sql, Encoding.UTF8);

                ConsoleCommandLogger.Output("Done");
            }

            return 0;
        }
        private static async Task<int> ExecuteAsync(CommonOptions commonOptions,
            string connection,
            string provider,
            bool dataAnnotations,
            string context,
            bool force,
            string outputDir,
            IEnumerable<string> schemas,
            IEnumerable<string> tables,
            string environment)
        {
            await new OperationExecutor(commonOptions, environment)
                .ReverseEngineerAsync(
                    provider,
                    connection,
                    outputDir,
                    context,
                    schemas,
                    tables,
                    dataAnnotations,
                    force);

            ConsoleCommandLogger.Output("Done");

            return 0;
        }
        private static int Execute(CommonOptions commonOptions,
            string migration, 
            string context, 
            string environment)
        {
            new OperationExecutor(commonOptions, environment)
                 .UpdateDatabase(migration, context);

            return 0;
        }
        private static int Execute(CommonOptions commonOptions,
            string context, 
            string environment, 
            bool force)
        {
            new OperationExecutor(commonOptions, environment)
                .RemoveMigration(context, force);

            return 0;
        }
        private static int Execute(CommonOptions commonOptions,
            string environment,
            Action<IEnumerable<Type>> reportResultsAction)
        {
            var contextTypes = new OperationExecutor(commonOptions, environment)
                .GetContextTypes();

            reportResultsAction(contextTypes);

            return 0;
        }
        private static int Execute(CommonOptions commonOptions,
            string context,
            string environment,
            Action<IEnumerable<MigrationInfo>> reportResultsAction)
        {
            var migrations = new OperationExecutor(commonOptions, environment)
                .GetMigrations(context);

            reportResultsAction(migrations);

            return 0;
        }
        private static int Execute(CommonOptions commonOptions,
            string name,
            string outputDir,
            string context,
            string environment,
            Action<MigrationFiles> reporter)
        {
            var files = new OperationExecutor(commonOptions, environment)
                .AddMigration(name, outputDir, context);

            reporter?.Invoke(files);

            ConsoleCommandLogger.Output("Done. To undo this action, use 'dotnet ef migrations remove'");

            return 0;
        }
        private static int Execute(CommonOptions commonOptions,
            string context,
            string environment,
            bool isForced)
        {
            new OperationExecutor(commonOptions, environment)
                .DropDatabase(
                    context,
                    (database, dataSource) =>
                    {
                        if (isForced)
                        {
                            return true;
                        }

                        ConsoleCommandLogger.Output(
                            $"Are you sure you want to drop the database '{database}' on server '{dataSource}'? (y/N)");
                        var readedKey = Console.ReadKey().KeyChar;

                        return (readedKey == 'y') || (readedKey == 'Y');
                    });

            return 0;
        }
        public OperationExecutor(
            [NotNull] CommonOptions options,
            [CanBeNull] string environment)
        {
            if (!string.IsNullOrEmpty(options.DataDirectory))
            {
                Environment.SetEnvironmentVariable(DataDirEnvName, options.DataDirectory);
#if NET451
                AppDomain.CurrentDomain.SetData("DataDirectory", options.DataDirectory);
#endif
            }

            if (!File.Exists(options.Assembly))
            {
                throw new OperationException($"Could not find assembly '{options.Assembly}'.");
            }

            var assemblyFileName = Path.GetFileNameWithoutExtension(options.Assembly);

            // TODO add hooks into Assembly.Load to allow loading from other locations
            var assemblyLoader  = new AssemblyLoader(Assembly.Load);
            var projectAssembly = assemblyLoader.Load(assemblyFileName);

            // optional
            var startupAssembly = string.IsNullOrWhiteSpace(options.StartupAssembly)
                ? projectAssembly
                : assemblyLoader.Load(Path.GetFileNameWithoutExtension(options.StartupAssembly));

            var projectDir = string.IsNullOrEmpty(options.ProjectDirectory)
                ? Directory.GetCurrentDirectory()
                : options.ProjectDirectory;

            var contentRootPath = string.IsNullOrEmpty(options.ContentRootPath)
#if NET451
                ? AppDomain.CurrentDomain.GetData("APP_CONTEXT_BASE_DIRECTORY") as string ?? AppDomain.CurrentDomain.BaseDirectory
#else
                ? AppContext.BaseDirectory
#endif
                : options.ContentRootPath;

            var rootNamespace = string.IsNullOrEmpty(options.RootNamespace)
                ? assemblyFileName
                : options.RootNamespace;

            _contextOperations = new LazyRef <DbContextOperations>(
                () => new DbContextOperations(
                    new LoggerProvider(name => new ConsoleCommandLogger(name)),
                    assembly: projectAssembly,
                    startupAssembly: startupAssembly,
                    environment: environment,
                    contentRootPath: contentRootPath));
            _databaseOperations = new LazyRef <DatabaseOperations>(
                () => new DatabaseOperations(
                    new LoggerProvider(name => new ConsoleCommandLogger(name)),
                    startupAssemblyLoader: assemblyLoader,
                    startupAssembly: startupAssembly,
                    environment: environment,
                    projectDir: projectDir,
                    contentRootPath: contentRootPath,
                    rootNamespace: rootNamespace));
            _migrationsOperations = new LazyRef <MigrationsOperations>(
                () => new MigrationsOperations(
                    new LoggerProvider(name => new ConsoleCommandLogger(name)),
                    assembly: projectAssembly,
                    startupAssemblyLoader: assemblyLoader,
                    startupAssembly: startupAssembly,
                    environment: environment,
                    projectDir: projectDir,
                    contentRootPath: contentRootPath,
                    rootNamespace: rootNamespace));
        }