You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucenenet.apache.org by ni...@apache.org on 2017/07/11 07:42:29 UTC

[04/22] lucenenet git commit: Added lucene-cli + tests - a wrapper console application so we can run the various utilities and demos in .NET on the command line.

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/9e389540/src/tools/Lucene.Net.Tests.Cli/Properties/AssemblyInfo.cs
----------------------------------------------------------------------
diff --git a/src/tools/Lucene.Net.Tests.Cli/Properties/AssemblyInfo.cs b/src/tools/Lucene.Net.Tests.Cli/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..a5b2792
--- /dev/null
+++ b/src/tools/Lucene.Net.Tests.Cli/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements.  See the NOTICE file distributed with
+* this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You under the Apache License, Version 2.0
+* (the "License"); you may not use this file except in compliance with
+* the License.  You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Lucene.Net.Tests.Cli")]
+[assembly: AssemblyTrademark("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components.  If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("495b65f0-0b01-40fe-9dc8-5a82c49e07ef")]

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/9e389540/src/tools/Lucene.Net.Tests.Cli/SourceCode/SourceCodeParserTest.cs
----------------------------------------------------------------------
diff --git a/src/tools/Lucene.Net.Tests.Cli/SourceCode/SourceCodeParserTest.cs b/src/tools/Lucene.Net.Tests.Cli/SourceCode/SourceCodeParserTest.cs
new file mode 100644
index 0000000..23ae032
--- /dev/null
+++ b/src/tools/Lucene.Net.Tests.Cli/SourceCode/SourceCodeParserTest.cs
@@ -0,0 +1,72 @@
+using Lucene.Net.Support;
+using NUnit.Framework;
+using System.IO;
+using System.Reflection;
+
+namespace Lucene.Net.Cli.SourceCode
+{
+    /*
+     * Licensed to the Apache Software Foundation (ASF) under one or more
+     * contributor license agreements.  See the NOTICE file distributed with
+     * this work for additional information regarding copyright ownership.
+     * The ASF licenses this file to You under the Apache License, Version 2.0
+     * (the "License"); you may not use this file except in compliance with
+     * the License.  You may obtain a copy of the License at
+     *
+     *     http://www.apache.org/licenses/LICENSE-2.0
+     *
+     * Unless required by applicable law or agreed to in writing, software
+     * distributed under the License is distributed on an "AS IS" BASIS,
+     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     * See the License for the specific language governing permissions and
+     * limitations under the License.
+     */
+
+    public class SourceCodeParserTest
+    {
+        [Test]
+        public void TestSourceCodeSectionParser()
+        {
+            var parser = new SourceCodeSectionParser();
+            var thisAssembly = this.GetType().GetTypeInfo().Assembly;
+
+            using (var output = new MemoryStream())
+            {
+                using (var input = thisAssembly.FindAndGetManifestResourceStream(this.GetType(), "TestInputForParser.cs"))
+                {
+                    parser.ParseSourceCodeFiles(input, output);
+                }
+
+                output.Seek(0, SeekOrigin.Begin);
+
+                using (var reader = new StreamReader(output, SourceCodeSectionParser.ENCODING))
+                {
+                    Assert.AreEqual("using System;", reader.ReadLine());
+                    Assert.AreEqual("using System.Collections.Generic;", reader.ReadLine());
+                    Assert.AreEqual("using System.Linq;", reader.ReadLine());
+                    Assert.AreEqual("using System.Threading.Tasks;", reader.ReadLine());
+                    Assert.AreEqual("using System.Reflection;", reader.ReadLine());
+                    Assert.AreEqual("using System.Xml;", reader.ReadLine());
+                    Assert.AreEqual("", reader.ReadLine());
+                    Assert.AreEqual("namespace Lucene.Net.Cli.SourceCode", reader.ReadLine());
+                    Assert.AreEqual("{", reader.ReadLine());
+                    Assert.AreEqual("    public class TestInputForParser", reader.ReadLine());
+                    Assert.AreEqual("    {", reader.ReadLine());
+                    Assert.AreEqual("        public void Foo()", reader.ReadLine());
+                    Assert.AreEqual("        {", reader.ReadLine());
+                    Assert.AreEqual("            Console.WriteLine(\"Foo\");", reader.ReadLine());
+                    Assert.AreEqual("        }", reader.ReadLine());
+                    Assert.AreEqual("", reader.ReadLine());
+                    Assert.AreEqual("        public void Bar()", reader.ReadLine());
+                    Assert.AreEqual("        {", reader.ReadLine());
+                    Assert.AreEqual("            Console.WriteLine(\"Bar2\");", reader.ReadLine());
+                    Assert.AreEqual("        }", reader.ReadLine());
+                    Assert.AreEqual("    }", reader.ReadLine());
+                    Assert.AreEqual("}", reader.ReadLine());
+                    Assert.AreEqual(null, reader.ReadLine());
+                    Assert.AreEqual(null, reader.ReadLine());
+                }
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/9e389540/src/tools/Lucene.Net.Tests.Cli/SourceCode/TestInputForParser.cs
----------------------------------------------------------------------
diff --git a/src/tools/Lucene.Net.Tests.Cli/SourceCode/TestInputForParser.cs b/src/tools/Lucene.Net.Tests.Cli/SourceCode/TestInputForParser.cs
new file mode 100644
index 0000000..280fc1c
--- /dev/null
+++ b/src/tools/Lucene.Net.Tests.Cli/SourceCode/TestInputForParser.cs
@@ -0,0 +1,53 @@
+// <comment>
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// DO NOT ALTER THIS FILE, it is for testing purposes
+
+// </comment>
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+// <include>
+////using System.Reflection;
+////using System.Xml;
+// </include>
+
+namespace Lucene.Net.Cli.SourceCode
+{
+    public class TestInputForParser
+    {
+        public void Foo()
+        {
+            Console.WriteLine("Foo");
+        }
+
+        // <comment>
+        public void Bar()
+        {
+            Console.WriteLine("Bar1");
+        }
+        // </comment>
+        // <include>
+        ////public void Bar()
+        ////{
+        ////    Console.WriteLine("Bar2");
+        ////}
+        // </include>
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/9e389540/src/tools/Lucene.Net.Tests.Cli/StringExtensions.cs
----------------------------------------------------------------------
diff --git a/src/tools/Lucene.Net.Tests.Cli/StringExtensions.cs b/src/tools/Lucene.Net.Tests.Cli/StringExtensions.cs
new file mode 100644
index 0000000..eeb4e80
--- /dev/null
+++ b/src/tools/Lucene.Net.Tests.Cli/StringExtensions.cs
@@ -0,0 +1,68 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.RegularExpressions;
+
+namespace Lucene.Net.Cli
+{
+    /*
+     * Licensed to the Apache Software Foundation (ASF) under one or more
+     * contributor license agreements.  See the NOTICE file distributed with
+     * this work for additional information regarding copyright ownership.
+     * The ASF licenses this file to You under the Apache License, Version 2.0
+     * (the "License"); you may not use this file except in compliance with
+     * the License.  You may obtain a copy of the License at
+     *
+     *     http://www.apache.org/licenses/LICENSE-2.0
+     *
+     * Unless required by applicable law or agreed to in writing, software
+     * distributed under the License is distributed on an "AS IS" BASIS,
+     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     * See the License for the specific language governing permissions and
+     * limitations under the License.
+     */
+
+    public static class StringExtensions
+    {
+        public static string[] ToArgs(this string input)
+        {
+            return Regex.Replace(input.Trim(), @"\s+", " ").Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).ToArray();
+        }
+
+        public static string OptionValue(this IEnumerable<string> args, string option)
+        {
+            return args.SkipWhile(a => a != option).Skip(1).FirstOrDefault();
+        }
+
+        public static IList<string> OptionValues(this IEnumerable<string> args, string option)
+        {
+            var argsList = new List<string>(args);
+            var result = new List<string>();
+            for (int i = 0; i < argsList.Count; i++)
+            {
+                string current = argsList[i];
+                if (current == option)
+                {
+                    if (i == argsList.Count - 1)
+                    {
+                        result.Add(null);
+                    }
+                    else
+                    {
+                        current = argsList[i + 1];
+                        if (current != option)
+                        {
+                            result.Add(current);
+                            i++;
+                        }
+                        else
+                        {
+                            result.Add(null);
+                        }
+                    }
+                }
+            }
+            return result;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/9e389540/src/tools/Lucene.Net.Tests.Cli/project.json
----------------------------------------------------------------------
diff --git a/src/tools/Lucene.Net.Tests.Cli/project.json b/src/tools/Lucene.Net.Tests.Cli/project.json
new file mode 100644
index 0000000..9ff17e3
--- /dev/null
+++ b/src/tools/Lucene.Net.Tests.Cli/project.json
@@ -0,0 +1,35 @@
+{
+  "version": "4.8.0",
+  "title": "Lucene.Net.Tests.Cli",
+  "dependencies": {
+    "dotnet-test-nunit-teamcity": "3.4.0-beta-3",
+    "lucene-cli": "4.8.0",
+    "Lucene.Net": "4.8.0",
+    "Lucene.Net.TestFramework": "4.8.0",
+    "NUnit": "3.5.0"
+  },
+  "testRunner": "nunit-teamcity",
+  "frameworks": {
+    "netcoreapp1.0": {
+      "imports": "dnxcore50",
+      "buildOptions": {
+        "debugType": "portable",
+        "define": [ "NETSTANDARD" ],
+        "compile": {
+          "excludeFiles": [
+            "SourceCode/TestInputForParser.cs"
+          ]
+        },
+        "embed": {
+          "includeFiles": [
+            "SourceCode/TestInputForParser.cs"
+          ]
+        }
+      }
+    }
+  },
+  "runtimes": {
+    "win7-x86": {},
+    "win7-x64": {}
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/9e389540/src/tools/lucene-cli/CommandLine/CommandArgument.cs
----------------------------------------------------------------------
diff --git a/src/tools/lucene-cli/CommandLine/CommandArgument.cs b/src/tools/lucene-cli/CommandLine/CommandArgument.cs
new file mode 100644
index 0000000..b7081e0
--- /dev/null
+++ b/src/tools/lucene-cli/CommandLine/CommandArgument.cs
@@ -0,0 +1,30 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Lucene.Net.Cli.CommandLine
+{
+    public class CommandArgument
+    {
+        public CommandArgument()
+        {
+            Values = new List<string>();
+        }
+
+        //public string Id { get; set; } // used to identify a command in the list
+        public virtual string Name { get; set; }
+        public bool ShowInHelpText { get; set; } = true;
+        public virtual string Description { get; set; }
+        public List<string> Values { get; private set; }
+        public bool MultipleValues { get; set; }
+        public virtual string Value
+        {
+            get
+            {
+                return Values.FirstOrDefault();
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/9e389540/src/tools/lucene-cli/CommandLine/CommandLineApplication.cs
----------------------------------------------------------------------
diff --git a/src/tools/lucene-cli/CommandLine/CommandLineApplication.cs b/src/tools/lucene-cli/CommandLine/CommandLineApplication.cs
new file mode 100644
index 0000000..978edad
--- /dev/null
+++ b/src/tools/lucene-cli/CommandLine/CommandLineApplication.cs
@@ -0,0 +1,563 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Lucene.Net.Cli.CommandLine
+{
+    public class CommandLineApplication
+    {
+        // Indicates whether the parser should throw an exception when it runs into an unexpected argument.
+        // If this field is set to false, the parser will stop parsing when it sees an unexpected argument, and all
+        // remaining arguments, including the first unexpected argument, will be stored in RemainingArguments property.
+        private readonly bool _throwOnUnexpectedArg;
+
+        public CommandLineApplication(bool throwOnUnexpectedArg = true)
+        {
+            _throwOnUnexpectedArg = throwOnUnexpectedArg;
+            Options = new List<CommandOption>();
+            Arguments = new List<CommandArgument>();
+            Commands = new List<CommandLineApplication>();
+            RemainingArguments = new List<string>();
+            Invoke = () => 0;
+        }
+
+        public CommandLineApplication Parent { get; set; }
+        public virtual string Name { get; set; }
+        public string FullName { get; set; }
+        public string Syntax { get; set; }
+        public virtual string Description { get; set; }
+        public bool ShowInHelpText { get; set; } = true;
+        public string ExtendedHelpText { get; set; }
+        public readonly List<CommandOption> Options;
+        public CommandOption OptionHelp { get; private set; }
+        public CommandOption OptionVersion { get; private set; }
+        public readonly List<CommandArgument> Arguments;
+        public readonly List<string> RemainingArguments;
+        public bool IsShowingInformation { get; protected set; }  // Is showing help or version?
+        public Func<int> Invoke { get; set; }
+        public Func<string> LongVersionGetter { get; set; }
+        public Func<string> ShortVersionGetter { get; set; }
+        public readonly List<CommandLineApplication> Commands;
+        public bool AllowArgumentSeparator { get; set; }
+        public TextWriter Out { get; set; } = Console.Out;
+        public TextWriter Error { get; set; } = Console.Error;
+
+        public IEnumerable<CommandOption> GetOptions()
+        {
+            var expr = Options.AsEnumerable();
+            var rootNode = this;
+            while (rootNode.Parent != null)
+            {
+                rootNode = rootNode.Parent;
+                expr = expr.Concat(rootNode.Options.Where(o => o.Inherited));
+            }
+
+            return expr;
+        }
+
+        public virtual CommandLineApplication Command(string name, Action<CommandLineApplication> configuration,
+            bool throwOnUnexpectedArg = true)
+        {
+            var command = new CommandLineApplication(throwOnUnexpectedArg) { Name = name, Parent = this };
+            Commands.Add(command);
+            configuration(command);
+            return command;
+        }
+
+        public virtual CommandOption Option(string template, string description, CommandOptionType optionType)
+            => Option(template, description, optionType, _ => { }, inherited: false);
+
+        public virtual CommandOption Option(string template, string description, CommandOptionType optionType, bool inherited)
+            => Option(template, description, optionType, _ => { }, inherited);
+
+        public virtual CommandOption Option(string template, string description, CommandOptionType optionType, Action<CommandOption> configuration)
+            => Option(template, description, optionType, configuration, inherited: false);
+
+        public virtual CommandOption Option(string template, string description, CommandOptionType optionType, Action<CommandOption> configuration, bool inherited)
+        {
+            var option = new CommandOption(template, optionType)
+            {
+                Description = description,
+                Inherited = inherited
+            };
+            Options.Add(option);
+            configuration(option);
+            return option;
+        }
+
+        public virtual CommandArgument Argument(string name, string description, bool multipleValues = false)
+        {
+            return Argument(name, description, _ => { }, multipleValues);
+        }
+
+        public virtual CommandArgument Argument(string name, string description, Action<CommandArgument> configuration, bool multipleValues = false)
+        {
+            var lastArg = Arguments.LastOrDefault();
+            if (lastArg != null && lastArg.MultipleValues)
+            {
+                var message = string.Format("The last argument '{0}' accepts multiple values. No more argument can be added.",
+                    lastArg.Name);
+                throw new InvalidOperationException(message);
+            }
+
+            var argument = new CommandArgument { Name = name, Description = description, MultipleValues = multipleValues };
+            Arguments.Add(argument);
+            configuration(argument);
+            return argument;
+        }
+
+        public virtual void OnExecute(Func<int> invoke)
+        {
+            Invoke = invoke;
+        }
+
+        public virtual void OnExecute(Func<Task<int>> invoke)
+        {
+            Invoke = () => invoke().Result;
+        }
+        public virtual int Execute(params string[] args)
+        {
+            CommandLineApplication command = this;
+            CommandOption option = null;
+            IEnumerator<CommandArgument> arguments = null;
+
+            for (var index = 0; index < args.Length; index++)
+            {
+                var arg = args[index];
+                var processed = false;
+                if (!processed && option == null)
+                {
+                    string[] longOption = null;
+                    string[] shortOption = null;
+
+                    if (arg.StartsWith("--"))
+                    {
+                        longOption = arg.Substring(2).Split(new[] { ':', '=' }, 2);
+                    }
+                    else if (arg.StartsWith("-"))
+                    {
+                        shortOption = arg.Substring(1).Split(new[] { ':', '=' }, 2);
+                    }
+                    else // Look for symbols (such as help option)
+                    {
+                        var symbolOption = command.GetOptions().SingleOrDefault(opt => string.Equals(opt.SymbolName, arg, StringComparison.Ordinal));
+                        if (symbolOption != null)
+                        {
+                            shortOption = new string[] { symbolOption.SymbolName, "" };
+                        }
+                    }
+                    if (longOption != null)
+                    {
+                        processed = true;
+                        var longOptionName = longOption[0];
+                        option = command.GetOptions().SingleOrDefault(opt => string.Equals(opt.LongName, longOptionName, StringComparison.Ordinal));
+
+                        if (option == null)
+                        {
+                            if (string.IsNullOrEmpty(longOptionName) && !command._throwOnUnexpectedArg && AllowArgumentSeparator)
+                            {
+                                // skip over the '--' argument separator
+                                index++;
+                            }
+
+                            HandleUnexpectedArg(command, args, index, argTypeName: "option");
+                            break;
+                        }
+
+                        // If we find a help/version option, show information and stop parsing
+                        if (command.OptionHelp == option)
+                        {
+                            command.ShowHelp();
+                            return 0;
+                        }
+                        else if (command.OptionVersion == option)
+                        {
+                            command.ShowVersion();
+                            return 0;
+                        }
+
+                        if (longOption.Length == 2)
+                        {
+                            if (!option.TryParse(longOption[1]))
+                            {
+                                command.ShowHint();
+                                throw new CommandParsingException(command, $"Unexpected value '{longOption[1]}' for option '{option.LongName}'");
+                            }
+                            option = null;
+                        }
+                        else if (option.OptionType == CommandOptionType.NoValue)
+                        {
+                            // No value is needed for this option
+                            option.TryParse(null);
+                            option = null;
+                        }
+                    }
+                    if (shortOption != null)
+                    {
+                        processed = true;
+                        option = command.GetOptions().SingleOrDefault(opt => string.Equals(opt.ShortName, shortOption[0], StringComparison.Ordinal));
+
+                        // If not a short option, try symbol option
+                        if (option == null)
+                        {
+                            option = command.GetOptions().SingleOrDefault(opt => string.Equals(opt.SymbolName, shortOption[0], StringComparison.Ordinal));
+                        }
+
+                        if (option == null)
+                        {
+                            HandleUnexpectedArg(command, args, index, argTypeName: "option");
+                            break;
+                        }
+
+                        // If we find a help/version option, show information and stop parsing
+                        if (command.OptionHelp == option)
+                        {
+                            command.ShowHelp();
+                            return 0;
+                        }
+                        else if (command.OptionVersion == option)
+                        {
+                            command.ShowVersion();
+                            return 0;
+                        }
+
+                        if (shortOption.Length == 2)
+                        {
+                            if (!option.TryParse(shortOption[1]))
+                            {
+                                command.ShowHint();
+                                throw new CommandParsingException(command, $"Unexpected value '{shortOption[1]}' for option '{option.LongName}'");
+                            }
+                            option = null;
+                        }
+                        else if (option.OptionType == CommandOptionType.NoValue)
+                        {
+                            // No value is needed for this option
+                            option.TryParse(null);
+                            option = null;
+                        }
+                    }
+                }
+
+                if (!processed && option != null)
+                {
+                    processed = true;
+                    if (!option.TryParse(arg))
+                    {
+                        command.ShowHint();
+                        throw new CommandParsingException(command, $"Unexpected value '{arg}' for option '{option.LongName}'");
+                    }
+                    option = null;
+                }
+
+                if (!processed && arguments == null)
+                {
+                    var currentCommand = command;
+                    foreach (var subcommand in command.Commands)
+                    {
+                        if (string.Equals(subcommand.Name, arg, StringComparison.OrdinalIgnoreCase))
+                        {
+                            processed = true;
+                            command = subcommand;
+                            break;
+                        }
+                    }
+
+                    // If we detect a subcommand
+                    if (command != currentCommand)
+                    {
+                        processed = true;
+                    }
+                }
+                if (!processed)
+                {
+                    if (arguments == null)
+                    {
+                        arguments = new CommandArgumentEnumerator(command.Arguments.GetEnumerator());
+                    }
+                    if (arguments.MoveNext())
+                    {
+                        processed = true;
+                        arguments.Current.Values.Add(arg);
+                    }
+                }
+                if (!processed)
+                {
+                    HandleUnexpectedArg(command, args, index, argTypeName: "command or argument");
+                    break;
+                }
+            }
+
+            if (option != null)
+            {
+                command.ShowHint();
+                throw new CommandParsingException(command, $"Missing value for option '{option.LongName}'");
+            }
+
+            return command.Invoke();
+        }
+
+        // Helper method that adds a help option
+        public virtual CommandOption HelpOption(string template)
+        {
+            // Help option is special because we stop parsing once we see it
+            // So we store it separately for further use
+            OptionHelp = Option(template, "Show help information", CommandOptionType.NoValue);
+
+            return OptionHelp;
+        }
+
+        public virtual CommandOption VersionOption(string template,
+            string shortFormVersion,
+            string longFormVersion = null)
+        {
+            if (longFormVersion == null)
+            {
+                return VersionOption(template, () => shortFormVersion);
+            }
+            else
+            {
+                return VersionOption(template, () => shortFormVersion, () => longFormVersion);
+            }
+        }
+
+        // Helper method that adds a version option
+        public virtual CommandOption VersionOption(string template,
+            Func<string> shortFormVersionGetter,
+            Func<string> longFormVersionGetter = null)
+        {
+            // Version option is special because we stop parsing once we see it
+            // So we store it separately for further use
+            OptionVersion = Option(template, "Show version information", CommandOptionType.NoValue);
+            ShortVersionGetter = shortFormVersionGetter;
+            LongVersionGetter = longFormVersionGetter ?? shortFormVersionGetter;
+
+            return OptionVersion;
+        }
+
+        // Show short hint that reminds users to use help option
+        public virtual void ShowHint()
+        {
+            if (OptionHelp != null)
+            {
+                Out.WriteLine(string.Format("Specify --{0} for a list of available options and commands.", OptionHelp.LongName));
+            }
+        }
+
+        // Show full help
+        public virtual void ShowHelp(string commandName = null)
+        {
+            for (var cmd = this; cmd != null; cmd = cmd.Parent)
+            {
+                cmd.IsShowingInformation = true;
+            }
+
+            Out.WriteLine(GetHelpText(commandName));
+        }
+
+        public virtual string GetHelpText(string commandName = null)
+        {
+            var headerBuilder = new StringBuilder("Usage:");
+            for (var cmd = this; cmd != null; cmd = cmd.Parent)
+            {
+                headerBuilder.Insert(6, string.Format(" {0}", cmd.Name));
+            }
+
+            CommandLineApplication target;
+
+            if (commandName == null || string.Equals(Name, commandName, StringComparison.OrdinalIgnoreCase))
+            {
+                target = this;
+            }
+            else
+            {
+                target = Commands.SingleOrDefault(cmd => string.Equals(cmd.Name, commandName, StringComparison.OrdinalIgnoreCase));
+
+                if (target != null)
+                {
+                    headerBuilder.AppendFormat(" {0}", commandName);
+                }
+                else
+                {
+                    // The command name is invalid so don't try to show help for something that doesn't exist
+                    target = this;
+                }
+
+            }
+
+            var optionsBuilder = new StringBuilder();
+            var commandsBuilder = new StringBuilder();
+            var argumentsBuilder = new StringBuilder();
+
+            var arguments = target.Arguments.Where(a => a.ShowInHelpText).ToList();
+            if (arguments.Any())
+            {
+                headerBuilder.Append(" [arguments]");
+
+                argumentsBuilder.AppendLine();
+                argumentsBuilder.AppendLine("Arguments:");
+                var maxArgLen = arguments.Max(a => a.Name.Length);
+                var outputFormat = string.Format("  {{0, -{0}}}{{1}}", maxArgLen + 2);
+                foreach (var arg in arguments)
+                {
+                    argumentsBuilder.AppendFormat(outputFormat, arg.Name, arg.Description);
+                    argumentsBuilder.AppendLine();
+                }
+            }
+
+            var options = target.GetOptions().Where(o => o.ShowInHelpText).ToList();
+            if (options.Any())
+            {
+                headerBuilder.Append(" [options]");
+
+                optionsBuilder.AppendLine();
+                optionsBuilder.AppendLine("Options:");
+                var maxOptLen = options.Max(o => o.Template.Length);
+                var outputFormat = string.Format("  {{0, -{0}}}{{1}}", maxOptLen + 2);
+                foreach (var opt in options)
+                {
+                    optionsBuilder.AppendFormat(outputFormat, opt.Template, opt.Description);
+                    optionsBuilder.AppendLine();
+                }
+            }
+
+            var commands = target.Commands.Where(c => c.ShowInHelpText).ToList();
+            if (commands.Any())
+            {
+                headerBuilder.Append(" [command]");
+
+                commandsBuilder.AppendLine();
+                commandsBuilder.AppendLine("Commands:");
+                var maxCmdLen = commands.Max(c => c.Name.Length);
+                var outputFormat = string.Format("  {{0, -{0}}}{{1}}", maxCmdLen + 2);
+                foreach (var cmd in commands.OrderBy(c => c.Name))
+                {
+                    commandsBuilder.AppendFormat(outputFormat, cmd.Name, cmd.Description);
+                    commandsBuilder.AppendLine();
+                }
+
+                if (OptionHelp != null)
+                {
+                    commandsBuilder.AppendLine();
+                    commandsBuilder.AppendFormat($"Use \"{target.Name} [command] --{OptionHelp.LongName}\" for more information about a command.");
+                    commandsBuilder.AppendLine();
+                }
+            }
+
+            if (target.AllowArgumentSeparator)
+            {
+                headerBuilder.Append(" [[--] <arg>...]");
+            }
+
+            headerBuilder.AppendLine();
+
+            var nameAndVersion = new StringBuilder();
+            nameAndVersion.AppendLine(GetFullNameAndVersion());
+            nameAndVersion.AppendLine();
+
+            return nameAndVersion.ToString()
+                + headerBuilder.ToString()
+                + argumentsBuilder.ToString()
+                + optionsBuilder.ToString()
+                + commandsBuilder.ToString()
+                + (string.IsNullOrEmpty(target.ExtendedHelpText) ? "" : Environment.NewLine + target.ExtendedHelpText);
+        }
+
+        public virtual void ShowVersion()
+        {
+            for (var cmd = this; cmd != null; cmd = cmd.Parent)
+            {
+                cmd.IsShowingInformation = true;
+            }
+
+            Out.WriteLine(FullName);
+            Out.WriteLine(LongVersionGetter());
+        }
+
+        public virtual string GetFullNameAndVersion()
+        {
+            return ShortVersionGetter == null ? FullName : string.Format("{0} {1}", FullName, ShortVersionGetter());
+        }
+
+        public virtual void ShowRootCommandFullNameAndVersion()
+        {
+            var rootCmd = this;
+            while (rootCmd.Parent != null)
+            {
+                rootCmd = rootCmd.Parent;
+            }
+
+            Out.WriteLine(rootCmd.GetFullNameAndVersion());
+            Out.WriteLine();
+        }
+
+        private void HandleUnexpectedArg(CommandLineApplication command, string[] args, int index, string argTypeName)
+        {
+            if (command._throwOnUnexpectedArg)
+            {
+                command.ShowHint();
+                throw new CommandParsingException(command, $"Unrecognized {argTypeName} '{args[index]}'");
+            }
+            else
+            {
+                // All remaining arguments are stored for further use
+                command.RemainingArguments.AddRange(new ArraySegment<string>(args, index, args.Length - index));
+            }
+        }
+
+        private class CommandArgumentEnumerator : IEnumerator<CommandArgument>
+        {
+            private readonly IEnumerator<CommandArgument> _enumerator;
+
+            public CommandArgumentEnumerator(IEnumerator<CommandArgument> enumerator)
+            {
+                _enumerator = enumerator;
+            }
+
+            public CommandArgument Current
+            {
+                get
+                {
+                    return _enumerator.Current;
+                }
+            }
+
+            object IEnumerator.Current
+            {
+                get
+                {
+                    return Current;
+                }
+            }
+
+            public void Dispose()
+            {
+                _enumerator.Dispose();
+            }
+
+            public bool MoveNext()
+            {
+                if (Current == null || !Current.MultipleValues)
+                {
+                    return _enumerator.MoveNext();
+                }
+
+                // If current argument allows multiple values, we don't move forward and
+                // all later values will be added to current CommandArgument.Values
+                return true;
+            }
+
+            public void Reset()
+            {
+                _enumerator.Reset();
+            }
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/9e389540/src/tools/lucene-cli/CommandLine/CommandOption.cs
----------------------------------------------------------------------
diff --git a/src/tools/lucene-cli/CommandLine/CommandOption.cs b/src/tools/lucene-cli/CommandLine/CommandOption.cs
new file mode 100644
index 0000000..16c1025
--- /dev/null
+++ b/src/tools/lucene-cli/CommandLine/CommandOption.cs
@@ -0,0 +1,112 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Lucene.Net.Cli.CommandLine
+{
+    public class CommandOption
+    {
+        public CommandOption(string template, CommandOptionType optionType)
+        {
+            Template = template;
+            OptionType = optionType;
+            Values = new List<string>();
+
+            foreach (var part in Template.Split(new[] { ' ', '|' }, StringSplitOptions.RemoveEmptyEntries))
+            {
+                if (part.StartsWith("--"))
+                {
+                    LongName = part.Substring(2);
+                }
+                else if (part.StartsWith("-"))
+                {
+                    var optName = part.Substring(1);
+
+                    // If there is only one char and it is not an English letter, it is a symbol option (e.g. "-?")
+                    if (optName.Length == 1 && !IsEnglishLetter(optName[0]))
+                    {
+                        SymbolName = optName;
+                    }
+                    else
+                    {
+                        ShortName = optName;
+                    }
+                }
+                else if (part.StartsWith("<") && part.EndsWith(">"))
+                {
+                    ValueName = part.Substring(1, part.Length - 2);
+                }
+                else
+                {
+                    throw new ArgumentException($"Invalid template pattern '{template}'", nameof(template));
+                }
+            }
+
+            if (string.IsNullOrEmpty(LongName) && string.IsNullOrEmpty(ShortName) && string.IsNullOrEmpty(SymbolName))
+            {
+                throw new ArgumentException($"Invalid template pattern '{template}'", nameof(template));
+            }
+        }
+
+        /// <summary>
+        /// An ID that can be used to locate this option.
+        /// </summary>
+        public string UniqueId { get; set; }
+        public string Template { get; set; }
+        public string ShortName { get; set; }
+        public string LongName { get; set; }
+        public string SymbolName { get; set; }
+        public string ValueName { get; set; }
+        public string Description { get; set; }
+        public List<string> Values { get; private set; }
+        public CommandOptionType OptionType { get; private set; }
+        public bool ShowInHelpText { get; set; } = true;
+        public bool Inherited { get; set; }
+
+        public bool TryParse(string value)
+        {
+            switch (OptionType)
+            {
+                case CommandOptionType.MultipleValue:
+                    Values.Add(value);
+                    break;
+                case CommandOptionType.SingleValue:
+                    if (Values.Any())
+                    {
+                        return false;
+                    }
+                    Values.Add(value);
+                    break;
+                case CommandOptionType.NoValue:
+                    if (value != null)
+                    {
+                        return false;
+                    }
+                    // Add a value to indicate that this option was specified
+                    Values.Add("on");
+                    break;
+                default:
+                    break;
+            }
+            return true;
+        }
+
+        public bool HasValue()
+        {
+            return Values.Any();
+        }
+
+        public string Value()
+        {
+            return HasValue() ? Values[0] : null;
+        }
+
+        private bool IsEnglishLetter(char c)
+        {
+            return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/9e389540/src/tools/lucene-cli/CommandLine/CommandOptionType.cs
----------------------------------------------------------------------
diff --git a/src/tools/lucene-cli/CommandLine/CommandOptionType.cs b/src/tools/lucene-cli/CommandLine/CommandOptionType.cs
new file mode 100644
index 0000000..ef541e4
--- /dev/null
+++ b/src/tools/lucene-cli/CommandLine/CommandOptionType.cs
@@ -0,0 +1,12 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+namespace Lucene.Net.Cli.CommandLine
+{
+    public enum CommandOptionType
+    {
+        MultipleValue,
+        SingleValue,
+        NoValue
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/9e389540/src/tools/lucene-cli/CommandLine/CommandParsingException.cs
----------------------------------------------------------------------
diff --git a/src/tools/lucene-cli/CommandLine/CommandParsingException.cs b/src/tools/lucene-cli/CommandLine/CommandParsingException.cs
new file mode 100644
index 0000000..bd2446a
--- /dev/null
+++ b/src/tools/lucene-cli/CommandLine/CommandParsingException.cs
@@ -0,0 +1,18 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+
+namespace Lucene.Net.Cli.CommandLine
+{
+    public class CommandParsingException : Exception
+    {
+        public CommandParsingException(CommandLineApplication command, string message)
+            : base(message)
+        {
+            Command = command;
+        }
+
+        public CommandLineApplication Command { get; }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/9e389540/src/tools/lucene-cli/CommandLineOptions.cs
----------------------------------------------------------------------
diff --git a/src/tools/lucene-cli/CommandLineOptions.cs b/src/tools/lucene-cli/CommandLineOptions.cs
new file mode 100644
index 0000000..93c7455
--- /dev/null
+++ b/src/tools/lucene-cli/CommandLineOptions.cs
@@ -0,0 +1,74 @@
+using System;
+
+namespace Lucene.Net.Cli
+{
+    /*
+     * Licensed to the Apache Software Foundation (ASF) under one or more
+     * contributor license agreements.  See the NOTICE file distributed with
+     * this work for additional information regarding copyright ownership.
+     * The ASF licenses this file to You under the Apache License, Version 2.0
+     * (the "License"); you may not use this file except in compliance with
+     * the License.  You may obtain a copy of the License at
+     *
+     *     http://www.apache.org/licenses/LICENSE-2.0
+     *
+     * Unless required by applicable law or agreed to in writing, software
+     * distributed under the License is distributed on an "AS IS" BASIS,
+     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     * See the License for the specific language governing permissions and
+     * limitations under the License.
+     */
+
+    public class CommandLineOptions
+    {
+        public static int Parse(string[] args)
+        {
+            var options = new CommandLineOptions();
+
+            var cmd = new RootCommand.Configuration(options);
+
+            try
+            {
+                return cmd.Execute(args);
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine(Resources.Strings.GeneralExceptionMessage + Environment.NewLine + ex.ToString());
+                cmd.ShowHint();
+                return 1;
+            }
+        }
+
+        //public static readonly string VERBOSE_OPTION_VALUE_NAME = "verbose";
+        //public static readonly string DIRECTORY_TYPE_VALUE_NAME = "directoryType";
+        //public static readonly string INDEX_DIRECTORY_ARGUMENT_ID = "indexDirectory";
+
+        //public CommandOption VerboseOption = new CommandOption("-v|--verbose", CommandOptionType.NoValue)
+        //{
+        //    Description = Resources.Strings.VerboseOptionDescription,
+        //    ValueName = VERBOSE_OPTION_VALUE_NAME
+        //};
+        //public CommandArgument IndexDirectoryArgument = new CommandArgument()
+        //{
+        //    Name = "[<INDEX-DIRECTORY>]",
+        //    Description = Resources.Strings.IndexDirectoryArgumentDescription,
+        //    Id = INDEX_DIRECTORY_ARGUMENT_ID
+        //};
+        //public string IndexDirectory
+        //{
+        //    get
+        //    {
+        //        // Return current directory if index directory not supplied.
+        //        return string.IsNullOrWhiteSpace(IndexDirectoryArgument.Value) ?
+        //            System.AppContext.BaseDirectory :
+        //            IndexDirectoryArgument.Value;
+        //    }
+        //}
+
+        //public CommandOption DirectoryTypeOption = new CommandOption("-dir|-dir-impl|--dir-impl|--directory-type", CommandOptionType.SingleValue)
+        //{
+        //    Description = Resources.Strings.DirectoryTypeOptionDescription,
+        //    ValueName = DIRECTORY_TYPE_VALUE_NAME
+        //};
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/9e389540/src/tools/lucene-cli/ConfigurationBase.cs
----------------------------------------------------------------------
diff --git a/src/tools/lucene-cli/ConfigurationBase.cs b/src/tools/lucene-cli/ConfigurationBase.cs
new file mode 100644
index 0000000..28e8de5
--- /dev/null
+++ b/src/tools/lucene-cli/ConfigurationBase.cs
@@ -0,0 +1,130 @@
+using Lucene.Net.Cli.CommandLine;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+
+namespace Lucene.Net.Cli
+{
+    /*
+     * Licensed to the Apache Software Foundation (ASF) under one or more
+     * contributor license agreements.  See the NOTICE file distributed with
+     * this work for additional information regarding copyright ownership.
+     * The ASF licenses this file to You under the Apache License, Version 2.0
+     * (the "License"); you may not use this file except in compliance with
+     * the License.  You may obtain a copy of the License at
+     *
+     *     http://www.apache.org/licenses/LICENSE-2.0
+     *
+     * Unless required by applicable law or agreed to in writing, software
+     * distributed under the License is distributed on an "AS IS" BASIS,
+     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     * See the License for the specific language governing permissions and
+     * limitations under the License.
+     */
+
+    public abstract class ConfigurationBase : CommandLineApplication
+    {
+        private static Assembly thisAssembly = typeof(ConfigurationBase).GetTypeInfo().Assembly;
+        protected static string HELP_VALUE_NAME = "help";
+
+        protected ConfigurationBase()
+            //: base(throwOnUnexpectedArg: false)
+        {
+            var help = this.HelpOption("-?|-h|--help");
+            help.UniqueId = HELP_VALUE_NAME;
+            help.ShowInHelpText = false;
+
+            this.ShortVersionGetter = () => 
+            {
+                return "Lucene.Net Command Line Utility, Version: " + thisAssembly
+                    .GetCustomAttribute<AssemblyInformationalVersionAttribute>()
+                    .InformationalVersion;
+            };
+
+            this.LongVersionGetter = () =>
+            {
+                return ShortVersionGetter();
+            };
+        }
+
+        public override void OnExecute(Func<int> invoke)
+        {
+            base.OnExecute(() =>
+            {
+                if (this.GetOptionByUniqueId(HELP_VALUE_NAME).HasValue())
+                {
+                    this.ShowHelp();
+                    return 1;
+                }
+                try
+                {
+                    return invoke();
+                }
+                catch (ArgumentException e)
+                {
+                    // Rather than writing to console, the
+                    // utilities are now throwing ArgumentException
+                    // if the args cannot be parsed.
+                    this.ShowHint();
+                    this.ShowHelp();
+                    return 1;
+                }
+            });
+        }
+
+        public Action<string[]> Main { get; set; }
+
+        public CommandOption GetOptionByUniqueId(string uniqueId)
+        {
+            return this.Options.FirstOrDefault(o => o.UniqueId == uniqueId);
+        }
+
+        public CommandOption GetOption<T>()
+        {
+            return this.Options.FirstOrDefault(o => typeof(T).IsAssignableFrom(o.GetType()));
+        }
+
+        public CommandArgument GetArgument<T>()
+        {
+            return this.Arguments.FirstOrDefault(o => typeof(T).IsAssignableFrom(o.GetType()));
+        }
+
+        /// <summary>
+        /// Gets the resource with a specific name. It is automatically
+        /// prefixed by the current command name.
+        /// </summary>
+        /// <param name="resourceName"></param>
+        /// <returns></returns>
+        protected string FromResource(string resourceName)
+        {
+            return Resources.Strings.ResourceManager.GetString(this.GetType().DeclaringType.Name + resourceName);
+        }
+
+        public void ShowNotEnoughArguments(int minimum)
+        {
+            Out.WriteLine(Resources.Strings.NotEnoughArguments, minimum);
+        }
+
+        public bool ValidateArguments(int minimum)
+        {
+            var args = GetNonNullArguments();
+
+            if (args.Length < minimum)
+            {
+                this.ShowNotEnoughArguments(minimum);
+                this.ShowHelp();
+                return false;
+            }
+            return true;
+        }
+
+        public string[] GetNonNullArguments()
+        {
+            return this.Arguments
+                .Where(a => !string.IsNullOrWhiteSpace(a.Value))
+                .SelectMany(a => a.MultipleValues ? a.Values : new List<string> { a.Value })
+                .ToArray();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/9e389540/src/tools/lucene-cli/ICommand.cs
----------------------------------------------------------------------
diff --git a/src/tools/lucene-cli/ICommand.cs b/src/tools/lucene-cli/ICommand.cs
new file mode 100644
index 0000000..b84e8d6
--- /dev/null
+++ b/src/tools/lucene-cli/ICommand.cs
@@ -0,0 +1,27 @@
+namespace Lucene.Net.Cli
+{
+    /*
+     * Licensed to the Apache Software Foundation (ASF) under one or more
+     * contributor license agreements.  See the NOTICE file distributed with
+     * this work for additional information regarding copyright ownership.
+     * The ASF licenses this file to You under the Apache License, Version 2.0
+     * (the "License"); you may not use this file except in compliance with
+     * the License.  You may obtain a copy of the License at
+     *
+     *     http://www.apache.org/licenses/LICENSE-2.0
+     *
+     * Unless required by applicable law or agreed to in writing, software
+     * distributed under the License is distributed on an "AS IS" BASIS,
+     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     * See the License for the specific language governing permissions and
+     * limitations under the License.
+     */
+
+    /// <summary>
+    /// A console command.
+    /// </summary>
+    public interface ICommand
+    {
+        int Run(ConfigurationBase cmd);
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/9e389540/src/tools/lucene-cli/Program.cs
----------------------------------------------------------------------
diff --git a/src/tools/lucene-cli/Program.cs b/src/tools/lucene-cli/Program.cs
new file mode 100644
index 0000000..9ef9869
--- /dev/null
+++ b/src/tools/lucene-cli/Program.cs
@@ -0,0 +1,35 @@
+using System;
+
+namespace Lucene.Net.Cli
+{
+    /*
+     * Licensed to the Apache Software Foundation (ASF) under one or more
+     * contributor license agreements.  See the NOTICE file distributed with
+     * this work for additional information regarding copyright ownership.
+     * The ASF licenses this file to You under the Apache License, Version 2.0
+     * (the "License"); you may not use this file except in compliance with
+     * the License.  You may obtain a copy of the License at
+     *
+     *     http://www.apache.org/licenses/LICENSE-2.0
+     *
+     * Unless required by applicable law or agreed to in writing, software
+     * distributed under the License is distributed on an "AS IS" BASIS,
+     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     * See the License for the specific language governing permissions and
+     * limitations under the License.
+     */
+
+    public class Program
+    {
+        public static int Main(string[] args)
+        {
+            int result = CommandLineOptions.Parse(args);
+
+#if DEBUG
+            Console.ReadKey();
+#endif
+
+            return result;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/9e389540/src/tools/lucene-cli/Properties/AssemblyInfo.cs
----------------------------------------------------------------------
diff --git a/src/tools/lucene-cli/Properties/AssemblyInfo.cs b/src/tools/lucene-cli/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..07a71d6
--- /dev/null
+++ b/src/tools/lucene-cli/Properties/AssemblyInfo.cs
@@ -0,0 +1,37 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements.  See the NOTICE file distributed with
+* this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You under the Apache License, Version 2.0
+* (the "License"); you may not use this file except in compliance with
+* the License.  You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("lucene-cli")]
+[assembly: AssemblyDescription(
+    "Lucene.Net maintenance utilities and demos.")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyDefaultAlias("Lucene.Net.Cli")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components.  If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("d5f3414e-e743-4dca-a50a-da3278a2ba2b")]

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/9e389540/src/tools/lucene-cli/Properties/launchSettings.json
----------------------------------------------------------------------
diff --git a/src/tools/lucene-cli/Properties/launchSettings.json b/src/tools/lucene-cli/Properties/launchSettings.json
new file mode 100644
index 0000000..1c0ef57
--- /dev/null
+++ b/src/tools/lucene-cli/Properties/launchSettings.json
@@ -0,0 +1,7 @@
+{
+  "profiles": {
+    "lucene-cli": {
+      "commandName": "Project"
+    }
+  }
+}
\ No newline at end of file