Skip to content

Commit

Permalink
Merge pull request #16 from datalust/dev
Browse files Browse the repository at this point in the history
Release
  • Loading branch information
nblumhardt authored Aug 2, 2017
2 parents 913a90e + c6bcb0f commit d4b2557
Show file tree
Hide file tree
Showing 23 changed files with 302 additions and 80 deletions.
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,23 @@ piggy up ... -v schema=myapp -v admin=myuser
### Change log

The change log is stored in the target database in `piggy.changes`. The `piggy log` command is used to view applied change scripts.

### Help

Run `piggy help` to see all available commands, and `piggy help <command>` for detailed command help.

```
> piggy help
Usage: piggy <command> [<args>]
Available commands are:
baseline Add scripts to the change log without running them
help Show information about available commands
log List change scripts that have been applied to a database
pending Determine which scripts will be run in an update
up Bring a database up to date
--version Print the current executable version
Type `piggy help <command>` for detailed help
```

16 changes: 8 additions & 8 deletions piggy.sln
Original file line number Diff line number Diff line change
Expand Up @@ -43,20 +43,20 @@ Global
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{8250E09A-7479-4322-A251-DABFD9F129B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8250E09A-7479-4322-A251-DABFD9F129B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8250E09A-7479-4322-A251-DABFD9F129B6}.Debug|x64.ActiveCfg = Debug|x64
{8250E09A-7479-4322-A251-DABFD9F129B6}.Debug|x64.Build.0 = Debug|x64
{8250E09A-7479-4322-A251-DABFD9F129B6}.Debug|x64.ActiveCfg = Debug|Any CPU
{8250E09A-7479-4322-A251-DABFD9F129B6}.Debug|x64.Build.0 = Debug|Any CPU
{8250E09A-7479-4322-A251-DABFD9F129B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8250E09A-7479-4322-A251-DABFD9F129B6}.Release|Any CPU.Build.0 = Release|Any CPU
{8250E09A-7479-4322-A251-DABFD9F129B6}.Release|x64.ActiveCfg = Release|x64
{8250E09A-7479-4322-A251-DABFD9F129B6}.Release|x64.Build.0 = Release|x64
{8250E09A-7479-4322-A251-DABFD9F129B6}.Release|x64.ActiveCfg = Release|Any CPU
{8250E09A-7479-4322-A251-DABFD9F129B6}.Release|x64.Build.0 = Release|Any CPU
{E3291CB6-F4A9-4A01-9E65-B70E2A32B0D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E3291CB6-F4A9-4A01-9E65-B70E2A32B0D5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E3291CB6-F4A9-4A01-9E65-B70E2A32B0D5}.Debug|x64.ActiveCfg = Debug|x64
{E3291CB6-F4A9-4A01-9E65-B70E2A32B0D5}.Debug|x64.Build.0 = Debug|x64
{E3291CB6-F4A9-4A01-9E65-B70E2A32B0D5}.Debug|x64.ActiveCfg = Debug|Any CPU
{E3291CB6-F4A9-4A01-9E65-B70E2A32B0D5}.Debug|x64.Build.0 = Debug|Any CPU
{E3291CB6-F4A9-4A01-9E65-B70E2A32B0D5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E3291CB6-F4A9-4A01-9E65-B70E2A32B0D5}.Release|Any CPU.Build.0 = Release|Any CPU
{E3291CB6-F4A9-4A01-9E65-B70E2A32B0D5}.Release|x64.ActiveCfg = Release|x64
{E3291CB6-F4A9-4A01-9E65-B70E2A32B0D5}.Release|x64.Build.0 = Release|x64
{E3291CB6-F4A9-4A01-9E65-B70E2A32B0D5}.Release|x64.ActiveCfg = Release|Any CPU
{E3291CB6-F4A9-4A01-9E65-B70E2A32B0D5}.Release|x64.Build.0 = Release|Any CPU
{5E28D963-3523-49DE-B03B-E76684258415}.Debug|Any CPU.ActiveCfg = Debug|x64
{5E28D963-3523-49DE-B03B-E76684258415}.Debug|x64.ActiveCfg = Debug|x64
{5E28D963-3523-49DE-B03B-E76684258415}.Release|Any CPU.ActiveCfg = Release|x64
Expand Down
45 changes: 45 additions & 0 deletions src/Datalust.Piggy/Baseline/BaselineSession.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using System.Text;
using Datalust.Piggy.Database;
using Datalust.Piggy.History;
using Datalust.Piggy.Status;
using Npgsql;
using Serilog;

namespace Datalust.Piggy.Baseline
{
class BaselineSession
{
public static void BaselineDatabase(string host, string database, string username, string password, string scriptRoot)
{
using (var connection = DatabaseConnector.Connect(host, database, username, password, false))
{
var scripts = DatabaseStatus.GetPendingScripts(connection, scriptRoot);

Log.Information("Found {Count} script files without change log records", scripts.Length);

if (scripts.Length != 0)
{
var commandText = new StringBuilder();
commandText.AppendLine("START TRANSACTION ISOLATION LEVEL REPEATABLE READ;");
commandText.AppendLine(AppliedChangeScriptLog.ChangesTableCreateScript);

foreach (var script in scripts)
{
Log.Information("Recording {FullPath} as {ScriptFile}", script.FullPath, script.RelativeName);
commandText.AppendLine(AppliedChangeScriptLog.CreateApplyLogScriptFor(script));
}

commandText.AppendLine("COMMIT TRANSACTION;");

Log.Information("Writing change log");
using (var command = new NpgsqlCommand(commandText.ToString(), connection))
{
command.ExecuteNonQuery();
}
}

Log.Information("Done");
}
}
}
}
16 changes: 7 additions & 9 deletions src/Datalust.Piggy/Cli/Command.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

namespace Datalust.Piggy.Cli
{
public abstract class Command
abstract class Command
{
private readonly IList<CommandFeature> _features = new List<CommandFeature>();
readonly IList<CommandFeature> _features = new List<CommandFeature>();

protected Command()
{
Expand Down Expand Up @@ -48,7 +48,7 @@ public int Invoke(string[] args)
{
var unrecognised = Options.Parse(args).ToArray();

var errs = _features.SelectMany(f => f.Errors).ToList();
var errs = _features.SelectMany(f => f.GetUsageErrors()).ToList();

if (errs.Any())
{
Expand All @@ -67,11 +67,9 @@ public int Invoke(string[] args)

protected virtual int Run(string[] unrecognised)
{
// All commands used to accept --nologo
var notIgnored = unrecognised.Where(o => o.IndexOf("nologo", StringComparison.OrdinalIgnoreCase) == -1);
if (notIgnored.Any())
if (unrecognised.Any())
{
ShowUsageErrors(new [] { "Unrecognized options: " + string.Join(", ", notIgnored) });
ShowUsageErrors(new [] { "Unrecognized options: " + string.Join(", ", unrecognised) });
return -1;
}

Expand All @@ -92,9 +90,9 @@ protected virtual void ShowUsageErrors(IEnumerable<string> errors)

protected bool Require(string value, string name)
{
if (string.IsNullOrWhiteSpace(value))
if (!Requirement.IsNonEmpty(value))
{
ShowUsageErrors(new [] { $"Please specify a {name}." });
ShowUsageErrors(new [] { Requirement.NonEmptyDescription(name) });
return false;
}
return true;
Expand Down
12 changes: 4 additions & 8 deletions src/Datalust.Piggy/Cli/CommandFeature.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;

namespace Datalust.Piggy.Cli
{
public abstract class CommandFeature
abstract class CommandFeature
{
protected CommandFeature()
{
Errors = new List<string>();
}

public abstract void Enable(OptionSet options);

public IList<string> Errors { get; private set; }
public virtual IEnumerable<string> GetUsageErrors() => Array.Empty<string>();
}
}
4 changes: 2 additions & 2 deletions src/Datalust.Piggy/Cli/CommandLineHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace Datalust.Piggy.Cli
{
public class CommandLineHost
class CommandLineHost
{
readonly List<Meta<Lazy<Command>, CommandMetadata>> _availableCommands;

Expand All @@ -31,7 +31,7 @@ public int Run(string[] args)
}

Console.WriteLine($"Usage: {name} <command> [<args>]");
Console.WriteLine($"Type '{name} help' for available commands.");
Console.WriteLine($"Type `{name} help` for available commands");
return -1;
}
}
Expand Down
45 changes: 45 additions & 0 deletions src/Datalust.Piggy/Cli/Commands/BaselineCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using System;
using Datalust.Piggy.Baseline;
using Datalust.Piggy.Cli.Features;
using Datalust.Piggy.Update;
using Npgsql;
using Serilog;

namespace Datalust.Piggy.Cli.Commands
{
[Command("baseline", "Add scripts to the change log without running them")]
class BaselineCommand : Command
{
readonly UsernamePasswordFeature _usernamePasswordFeature;
readonly DatabaseFeature _databaseFeature;
readonly LoggingFeature _loggingFeature;
readonly ScriptRootFeature _scriptRootFeature;

public BaselineCommand()
{
_databaseFeature = Enable<DatabaseFeature>();
_usernamePasswordFeature = Enable<UsernamePasswordFeature>();
_scriptRootFeature = Enable<ScriptRootFeature>();
_loggingFeature = Enable<LoggingFeature>();
}

protected override int Run()
{
_loggingFeature.Configure();

try
{
BaselineSession.BaselineDatabase(
_databaseFeature.Host, _databaseFeature.Database, _usernamePasswordFeature.Username, _usernamePasswordFeature.Password,
_scriptRootFeature.ScriptRoot);

return 0;
}
catch (Exception ex)
{
Log.Fatal(ex, "Could not baseline the database");
return -1;
}
}
}
}
4 changes: 2 additions & 2 deletions src/Datalust.Piggy/Cli/Commands/HelpCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
namespace Datalust.Piggy.Cli.Commands
{
[Command("help", "Show information about available commands")]
public class HelpCommand : Command
class HelpCommand : Command
{
readonly List<Meta<Lazy<Command>, CommandMetadata>> _availableCommands;

Expand Down Expand Up @@ -54,7 +54,7 @@ protected override int Run(string[] unrecognised)
}

Console.WriteLine();
Console.WriteLine($"Type '{name} help <command>' for detailed help.");
Console.WriteLine($"Type `{name} help <command>` for detailed help");

return 0;
}
Expand Down
6 changes: 1 addition & 5 deletions src/Datalust.Piggy/Cli/Commands/LogCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,6 @@ protected override int Run()
{
_loggingFeature.Configure();

if (!(Require(_databaseFeature.Host, "host") && Require(_databaseFeature.Database, "database") &&
Require("username", _usernamePasswordFeature.Username) && Require("password", _usernamePasswordFeature.Password)))
return -1;

try
{
using (var connection = DatabaseConnector.Connect(_databaseFeature.Host, _databaseFeature.Database,
Expand All @@ -43,7 +39,7 @@ protected override int Run()
}
catch (Exception ex)
{
Log.Fatal(ex, "Could not apply change scripts");
Log.Fatal(ex, "Could not list change scripts");
return -1;
}
}
Expand Down
49 changes: 49 additions & 0 deletions src/Datalust.Piggy/Cli/Commands/PendingCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using System;
using Datalust.Piggy.Cli.Features;
using Datalust.Piggy.Database;
using Datalust.Piggy.Status;
using Serilog;

namespace Datalust.Piggy.Cli.Commands
{
[Command("pending", "Determine which scripts will be run in an update")]
class PendingCommand : Command
{
readonly UsernamePasswordFeature _usernamePasswordFeature;
readonly DatabaseFeature _databaseFeature;
readonly LoggingFeature _loggingFeature;
readonly ScriptRootFeature _scriptRootFeature;

public PendingCommand()
{
_databaseFeature = Enable<DatabaseFeature>();
_usernamePasswordFeature = Enable<UsernamePasswordFeature>();
_scriptRootFeature = Enable<ScriptRootFeature>();
_loggingFeature = Enable<LoggingFeature>();
}

protected override int Run()
{
_loggingFeature.Configure();

try
{
using (var connection = DatabaseConnector.Connect(_databaseFeature.Host, _databaseFeature.Database,
_usernamePasswordFeature.Username, _usernamePasswordFeature.Password, false))
{
foreach (var pending in DatabaseStatus.GetPendingScripts(connection, _scriptRootFeature.ScriptRoot))
{
Console.WriteLine($"{pending.RelativeName}");
}
}

return 0;
}
catch (Exception ex)
{
Log.Fatal(ex, "Could not determine pending change scripts");
return -1;
}
}
}
}
16 changes: 3 additions & 13 deletions src/Datalust.Piggy/Cli/Commands/UpdateCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,15 @@ class UpdateCommand : Command
readonly UsernamePasswordFeature _usernamePasswordFeature;
readonly DatabaseFeature _databaseFeature;
readonly LoggingFeature _loggingFeature;
readonly ScriptRootFeature _scriptRootFeature;

string _scriptRoot;
bool _createIfMissing = true;

public UpdateCommand()
{
_databaseFeature = Enable<DatabaseFeature>();
_usernamePasswordFeature = Enable<UsernamePasswordFeature>();

Options.Add(
"s=|script-root=",
"The root directory to search for scripts",
v => _scriptRoot = v);

_scriptRootFeature = Enable<ScriptRootFeature>();
_defineVariablesFeature = Enable<DefineVariablesFeature>();

Options.Add("no-create", "If the database does not already exist, do not attempt to create it", v => _createIfMissing = false);
Expand All @@ -38,16 +33,11 @@ protected override int Run()
{
_loggingFeature.Configure();

if (!(Require(_databaseFeature.Host, "host") && Require(_databaseFeature.Database, "database") &&
Require("username", _usernamePasswordFeature.Username) && Require("password", _usernamePasswordFeature.Password) &&
Require(_scriptRoot, "script root directory")))
return -1;

try
{
UpdateSession.ApplyChangeScripts(
_databaseFeature.Host, _databaseFeature.Database, _usernamePasswordFeature.Username, _usernamePasswordFeature.Password,
_createIfMissing, _scriptRoot, _defineVariablesFeature.Variables);
_createIfMissing, _scriptRootFeature.ScriptRoot, _defineVariablesFeature.Variables);

return 0;
}
Expand Down
10 changes: 9 additions & 1 deletion src/Datalust.Piggy/Cli/Features/DatabaseFeature.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace Datalust.Piggy.Cli.Features
using System.Collections.Generic;

namespace Datalust.Piggy.Cli.Features
{
class DatabaseFeature : CommandFeature
{
Expand All @@ -17,5 +19,11 @@ public override void Enable(OptionSet options)
"The database to apply changes to",
v => Database = v);
}

public override IEnumerable<string> GetUsageErrors()
{
if (!Requirement.IsNonEmpty(Host)) yield return Requirement.NonEmptyDescription("host");
if (!Requirement.IsNonEmpty(Database)) yield return Requirement.NonEmptyDescription("database");
}
}
}
Loading

0 comments on commit d4b2557

Please sign in to comment.