Skip to content

Commit

Permalink
Fixes CLI parser
Browse files Browse the repository at this point in the history
This work continues on from 38c8987

It Closes #145 and Closes #126

It adds several important features (like support for custom value parsers) and our own help text generator.

Note we are dependent on a custom build hosted by @atruskie until natemcmaster/CommandLineUtils#51 is resolved
  • Loading branch information
atruskie committed Feb 17, 2018
1 parent 513bbc7 commit 19b246a
Show file tree
Hide file tree
Showing 61 changed files with 1,051 additions and 707 deletions.
9 changes: 5 additions & 4 deletions src/Acoustics.Shared/Extensions/EnumerableExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,17 @@
// ReSharper disable once CheckNamespace
namespace System
{
using System;
using Acoustics.Shared;
using Acoustics.Shared.Contracts;
using Collections.Generic;
using JetBrains.Annotations;
using Linq;
using Threading.Tasks;
using Acoustics.Shared;
using Acoustics.Shared.Contracts;

public static class EnumerableExtensions
{

[ContractAnnotation("items:null => true; items:notnull => false")]
public static bool IsNullOrEmpty<T>(this IEnumerable<T> items)
{
return items == null || !items.Any();
Expand Down Expand Up @@ -311,4 +312,4 @@ public static IEnumerable<T> Append<T>(this IEnumerable<T> items, T newItem)
yield return newItem;
}
}
}
}
7 changes: 6 additions & 1 deletion src/Acoustics.Shared/Extensions/FileInfoExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ public static bool TryCreate(this DirectoryInfo file)
public static FileInfo Touch(this FileInfo info)
{
using (File.OpenWrite(info.FullName))
{
{
}

info.Refresh();
Expand All @@ -163,6 +163,11 @@ public static T RefreshInfo<T>(this T info)
info.Refresh();
return info;
}

public static string BaseName(this FileInfo file)
{
return Path.GetFileNameWithoutExtension(file.Name);
}
}

public class FileInfoNameComparer : IComparer<FileInfo>, IEqualityComparer<FileInfo>
Expand Down
6 changes: 6 additions & 0 deletions src/Acoustics.Shared/Logging/LoggedConsole.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,11 @@ public static void WriteFatalLine(string str, Exception exception)
Log.Fatal(str, exception);
}

public static void WriteFatalLine(string str)
{
Log.Fatal(str);
}

public static void WriteWaitingLine<T>(Task<T> task, string message = null)
{
WriteLine(message ?? "Waiting...");
Expand All @@ -121,6 +126,7 @@ public static string Prompt(string prompt, bool forPassword = false, TimeSpan? t
{
return ReadHiddenLine();
}

var line = System.Console.ReadLine();
return line;
});
Expand Down
2 changes: 1 addition & 1 deletion src/Acoustics.Shared/Meta.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace Acoustics.Shared

public static class Meta
{
public const string Description = "QUT Aacoustics Analysis Program - version ";
public const string Description = "QUT Ecoacoustics Analysis Programs";

public const string Name = "AnalysisPrograms.exe";

Expand Down
4 changes: 2 additions & 2 deletions src/Acoustics.Shared/Yaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,9 @@ public static void Serialize<T>(FileInfo file, T obj)
}
}

internal static (object, T) LoadAndDeserialize<T>(FileInfo file)
internal static (object, T) LoadAndDeserialize<T>(string path)
{
using (var stream = file.OpenText())
using (var stream = File.OpenText(path))
{
// allow merging in yaml back references
var parser = new MergingParser(new Parser(stream));
Expand Down
15 changes: 11 additions & 4 deletions src/Acoustics.Tools/AudioUtilityRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -166,14 +166,21 @@ private bool DoValidation(bool throwExceptions)
return false;
}

if (this.Channels.NotNull() && (this.Channels.Length == 0 || this.Channels.Any(c => c < 1)))
if (this.Channels.NotNull())
{
if (throwExceptions)
if (this.Channels.Length == 0)
{
throw new ChannelNotAvailableException("Channel number should be greater than 0.");
this.Channels = null;
}
else if (this.Channels.Any(c => c < 1))
{
if (throwExceptions)
{
throw new ChannelNotAvailableException("Channel number should be greater than 0.");
}

return false;
return false;
}
}

/*if (this.Channel.HasValue && this.MixDownToMono.HasValue && this.MixDownToMono.Value)
Expand Down
4 changes: 2 additions & 2 deletions src/AnalysisPrograms/AED.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public class Aed : AbstractStrongAnalyser
/// </summary>
[Command(
CommandName,
Description = "Acosutic event detection, for short files (~ 1min)")]
Description = "Acoustic event detection, for short files (~ 1min)")]
public class Arguments : SourceConfigOutputDirArguments
{
public override Task<int> Execute(CommandLineApplication app)
Expand Down Expand Up @@ -270,7 +270,7 @@ public static void Execute(Arguments arguments)
LoggedConsole.WriteLine(date);

FileInfo recodingFile = arguments.Source;
var recodingBaseName = Path.GetFileNameWithoutExtension(arguments.Source.Name);
var recodingBaseName = recodingFile.BaseName();
DirectoryInfo outputDir = arguments.Output.Combine(EcosoundsAedIdentifier);
outputDir.Create();

Expand Down
20 changes: 8 additions & 12 deletions src/AnalysisPrograms/AnalyseLongRecordings/AnalyseLongRecording.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ namespace AnalysisPrograms.AnalyseLongRecordings
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.Drawing;
using System.IO;
Expand Down Expand Up @@ -61,15 +62,15 @@ public static void Execute(Arguments arguments)

// 1. set up the necessary files
var sourceAudio = arguments.Source;
var configFile = arguments.Config;
var configFile = arguments.Config.ToFileInfo();
var outputDirectory = arguments.Output;
var tempFilesDirectory = arguments.TempDir;

// if a temp dir is not given, use output dir as temp dir
if (tempFilesDirectory == null)
{
Log.Warn("No temporary directory provided, using output directory");
tempFilesDirectory = arguments.Output;
tempFilesDirectory = outputDirectory;
}

// try an automatically find the config file
Expand Down Expand Up @@ -137,7 +138,7 @@ public static void Execute(Arguments arguments)
}

// AT 2018-02: changed logic so default index properties loaded if not provided
FileInfo indicesPropertiesConfig = IndexProperties.Find(configuration, arguments.Config);
FileInfo indicesPropertiesConfig = IndexProperties.Find(configuration, configFile);
if (indicesPropertiesConfig == null || !indicesPropertiesConfig.Exists)
{
Log.Warn("IndexProperties config can not be found! Loading a default");
Expand Down Expand Up @@ -391,17 +392,12 @@ public static T FindAndCheckAnalyser<T>(string analysisIdentifier, string partia
T analyser = analysers.FirstOrDefault(a => a.Identifier == searchName);
if (analyser == null)
{
var error = $@"###
We can not determine what analysis you want to run. We tried to search for ""{searchName}""
###
";
var error = $"We can not determine what analysis you want to run. We tried to search for \"{searchName}\"";
LoggedConsole.WriteError(error);
var knownAnalyzers = analysers.Aggregate(string.Empty, (a, i) => a + $"\t {i.Identifier}\n");
var knownAnalyzers = analysers.Aggregate(string.Empty, (a, i) => a + $" {i.Identifier}\n");
LoggedConsole.WriteLine("Available analysers are:\n" + knownAnalyzers);

throw new CommandLineArgumentException("Cannot find a valid IAnalyser2");
throw new ValidationException($"Cannot find an IAnalyser2 with the name `{searchName}`");
}

return analyser;
Expand All @@ -414,7 +410,7 @@ private static void Cleanup(Arguments args, FileInfo configFile)
{
if (args.WhenExitCopyConfig)
{
configFile.CopyTo(Path.Combine(args.Output.FullName, args.Config.Name), true);
configFile.CopyTo(Path.Combine(args.Output.FullName, Path.GetFileName(args.Config)), true);
}

if (args.WhenExitCopyLog)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,44 +44,54 @@ public Arguments()
#endif
}

[Option("Sets the name of the analysis to run. If not set, analysis identifer is parsed from the config file name.")]
[Option(Description = "Sets the name of the analysis to run. If not set, analysis identifer is parsed from the config file name.")]
public string AnalysisIdentifier { get; set; }

[Option(
"A TEMP directory where cut files will be stored. Use this option for efficiency (e.g. write to a RAM Disk).",
ShortName = "t"
)]
Description = "A TEMP directory where cut files will be stored. Use this option for efficiency (e.g. write to a RAM Disk).",
ShortName = "t")]
[DirectoryExistsOrCreate(createIfNotExists: true)]
[LegalFilePath]
public DirectoryInfo TempDir { get; set; }

[Option("The start offset to start analyzing from (in seconds)")]
[Option(
CommandOptionType.SingleValue,
Description = "The start offset to start analyzing from (in seconds)")]
[InRange(min: 0)]
public double? StartOffset { get; set; }

[Option("The end offset to stop analyzing (in seconds)")]
[Option(
CommandOptionType.SingleValue,
Description = "The end offset to stop analyzing (in seconds)")]
[InRange(min: 0)]
public double? EndOffset { get; set; }

[Option("Allow advancing the start of the analysis to the nearest minute. A valid datetime must be available in the file name. Seed additional notes for options.")]
[Option(
Description = "Allow advancing the start of the analysis to the nearest minute. A valid datetime must be available in the file name. Seed additional notes for options.",
ShortName = "")]
public TimeAlignment AlignToMinute { get; set; } = TimeAlignment.None;

[Option("An array of channels to select. Default is all channels.")]
[Option(Description = "An array of channels to select. Default is all channels.")]
public int[] Channels { get; set; } = null;

[Option(
"Mix all selected input channels down into one mono channel. Default is to mixdown.",
CommandOptionType.SingleValue)]
CommandOptionType.SingleValue,
Description = "Mix all selected input channels down into one mono channel. Default is to mixdown.")]
public bool MixDownToMono { get; set; } = true;

[Option("Whether or not run this analysis in parallel - multiple segments can be analyzed at the same time")]
[Option(
Description = "Whether or not run this analysis in parallel - multiple segments can be analyzed at the same time",
ShortName = "p")]
public bool Parallel { get; set; } = false;

[Option(
"If true, attempts to copy the executable's log file to output directory. If it can't determine an output directory, it copies to the working directory.")]
Description = "If true, attempts to copy the executable's log file to output directory. If it can't determine an output directory, it copies to the working directory.",
ShortName = "")]
public bool WhenExitCopyLog { get; set; }

[Option(
"If true, attempts to copy the executable's config file to output directory. If it can't determine an output directory, it copies to the working directory. If it can't find a config file, nothing is copied")]
Description = "If true, attempts to copy the executable's config file to output directory. If it can't determine an output directory, it copies to the working directory. If it can't find a config file, nothing is copied",
ShortName = "")]
public bool WhenExitCopyConfig { get; set; }

public override Task<int> Execute(CommandLineApplication app)
Expand Down
4 changes: 3 additions & 1 deletion src/AnalysisPrograms/AnalysesAvailable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ namespace AnalysisPrograms
using Recognizers.Base;
using TowseyLibrary;

[Command("List available IAnalyzers available for use with audio2csv or eventRecognizer")]
[Command(
"AnalysesAvailable",
Description = "List available IAnalyzers available for use with audio2csv or eventRecognizer")]
public class AnalysesAvailable
: SubCommandBase
{
Expand Down
8 changes: 7 additions & 1 deletion src/AnalysisPrograms/AnalysisPrograms.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@
<HintPath>..\..\packages\MathNet.Numerics.3.20.2\lib\net40\MathNet.Numerics.dll</HintPath>
</Reference>
<Reference Include="McMaster.Extensions.CommandLineUtils, Version=2.2.0.0, Culture=neutral, PublicKeyToken=6f71cb76b82f055d, processorArchitecture=MSIL">
<HintPath>..\..\packages\McMaster.Extensions.CommandLineUtils.2.2.0-alpha.162\lib\net45\McMaster.Extensions.CommandLineUtils.dll</HintPath>
<HintPath>..\..\packages\McMaster.Extensions.CommandLineUtils.1.0.0-CI00005\lib\net45\McMaster.Extensions.CommandLineUtils.dll</HintPath>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="Microsoft.Data.Sqlite, Version=2.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
Expand Down Expand Up @@ -281,7 +281,13 @@
<Compile Include="Production\Arguments\SourceArguments.cs" />
<Compile Include="Production\Arguments\SourceConfigOutputDirArguments.cs" />
<Compile Include="Production\Arguments\SubCommandBase.cs" />
<Compile Include="Production\CommandLineApplicationExtensions.cs" />
<Compile Include="Production\CustomHelpTextGenerator.cs" />
<Compile Include="Production\FileSystemProvider.cs" />
<Compile Include="Production\Parsers\FileInfoParser.cs" />
<Compile Include="Production\Parsers\DirectoryInfoParser.cs" />
<Compile Include="Production\Parsers\TimeSpanParser.cs" />
<Compile Include="Production\Parsers\DateTimeOffsetParser.cs" />
<Compile Include="Production\PhysicalConsoleLogger.cs" />
<Compile Include="Production\Validation\DirectoryExistsOrCreateAttribute.cs" />
<Compile Include="Production\Validation\ExistingFileAttribute.cs" />
Expand Down
24 changes: 12 additions & 12 deletions src/AnalysisPrograms/Audio2InputForConvCNN.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ private static Arguments Dev()
//Source = @"C:\SensorNetworks\WavFiles\ConvDNNData\ConvDNN_annotation_export_commonNameOnly_withPadding_20140829.processed.csv".ToFileInfo(),
Source = @"Y:\Results\2014Aug29-000000 - Mangalam Data Export\Output\ConvDNN_annotation_export_commonNameOnly_withPadding_20140829.processed.csv".ToFileInfo(),

Config = @"C:\Work\GitHub\audio-analysis\AudioAnalysis\AnalysisConfigFiles\Mangalam.Sonogram.yml".ToFileInfo(),
Config = @"C:\Work\GitHub\audio-analysis\AudioAnalysis\AnalysisConfigFiles\Mangalam.Sonogram.yml",

Output = (@"C:\SensorNetworks\Output\ConvDNN\" + datestamp).ToDirectoryInfo(),
};
Expand All @@ -100,9 +100,9 @@ public static void Execute(Arguments arguments)
}

LoggedConsole.WriteLine("Generate ConvDNN images for single recording");
LoggedConsole.WriteLine("# Input Audio file: " + arguments.Source.Name);
LoggedConsole.WriteLine("# Configuration file: " + arguments.Config.Name);
LoggedConsole.WriteLine("# Output directry: " + arguments.Output.Name);
LoggedConsole.WriteLine("# Input Audio file: " + arguments.Source);
LoggedConsole.WriteLine("# Configuration file: " + arguments.Config);
LoggedConsole.WriteLine("# Output directry: " + arguments.Output);

// Verify target event information
if (string.IsNullOrWhiteSpace(arguments.TargetEventBounds))
Expand All @@ -128,7 +128,7 @@ public static void Execute(Arguments arguments)
}

// Grab configuration
var configDict = GetConfigurationForConvCnn(arguments.Config);
var configDict = GetConfigurationForConvCnn(arguments.Config.ToFileInfo());

var result = AnalyseOneRecording(arguments.Source, configDict, localEventStart, localEventEnd, (int)minHz, (int)mazHz, arguments.Output);
Log.InfoFormat("SpectrogramPath:" + result.SpectrogramFile);
Expand All @@ -149,21 +149,21 @@ public static void Main(Arguments arguments)
arguments = Dev();
}

if (!arguments.Output.Exists)
var output = arguments.Output;
if (!output.Exists)
{
arguments.Output.Create();
output.Create();
}

Log.InfoFormat("# PRE-PROCESS SHORT AUDIO RECORDINGS FOR Convolutional DNN");
Log.InfoFormat("# DATE AND TIME: " + DateTime.Now);
Log.InfoFormat("# Input .csv file: " + arguments.Source.Name);
Log.InfoFormat("# Configure file: " + arguments.Config.Name);
Log.InfoFormat("# Output directry: " + arguments.Output.Name);
Log.InfoFormat("# Input .csv file: " + arguments.Source);
Log.InfoFormat("# Configure file: " + arguments.Config);
Log.InfoFormat("# Output directry: " + arguments.Output);

// 1. set up the necessary files
FileInfo csvFileInfo = arguments.Source;
FileInfo configFile = arguments.Config;
DirectoryInfo output = arguments.Output;
FileInfo configFile = arguments.Config.ToFileInfo();

// 2. get the config dictionary
var configDict = GetConfigurationForConvCnn(configFile);
Expand Down
Loading

0 comments on commit 19b246a

Please sign in to comment.