<commit_before>// Copyright <NAME> 2017.
// Distributed under the MIT License.
// https://github.com/nuke-build/nuke/blob/master/LICENSE

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using JetBrains.Annotations;
using Nuke.Core.Utilities;
using Nuke.Core.Utilities.Collections;

namespace Nuke.Core.Execution
{
    public static class ParameterService
    {
        private static readonly Func<string[]> s_commandLineArgumentsProvider = () => Environment.GetCommandLineArgs();
        private static readonly Func<IDictionary> s_environmentVariablesProvider = () => Environment.GetEnvironmentVariables();

        [CanBeNull]
        public static T GetParameter<T> (string parameterName, char? separator = null)
        {
            return (T) GetParameter(parameterName, typeof(T), separator);
        }

        [CanBeNull]
        public static T GetCommandLineArgument<T> (string parameterName, char? separator = null)
        {
            return (T) GetCommandLineArgument(parameterName, typeof(T), separator);
        }

        [CanBeNull]
        public static T GetEnvironmentVariable<T> (string parameterName, char? separator = null)
        {
            return (T) GetEnvironmentVariable(parameterName, typeof(T), separator);
        }

        [CanBeNull]
        public static object GetParameter (string parameterName, Type destinationType, char? separator = null)
        {
            return HasCommandLineArgument(parameterName)
                ? GetCommandLineArgument(parameterName, destinationType, separator)
                : GetEnvironmentVariable(parameterName, destinationType, separator);
        }

        [CanBeNull]
        public static object GetCommandLineArgument (string argumentName, Type destinationType, char? separator = null)
        {
            var args = s_commandLineArgumentsProvider.Invoke();
            var index = Array.FindLastIndex(args, x => x.EqualsOrdinalIgnoreCase($"-{argumentName}"));
            if (index == -1)
                return GetDefaultValue(destinationType);

            var values = args.Skip(index + 1).TakeWhile(x => !x.StartsWith("-")).ToArray();
            ControlFlow.Assert(values.Length == 1 || !separator.HasValue || values.All(x => !x.Contains(separator.Value)),
                $"Command-line argument '{argumentName}' with value [ {values.Join(", ")} ] cannot be split with separator '{separator}'.");
            values = separator.HasValue && values.Any(x => x.Contains(separator.Value))
                ? values.SingleOrDefault()?.Split(separator.Value) ?? new string[0]
                : values;

            try
            {
                return ConvertValues(argumentName, values, destinationType);
            }
            catch (Exception ex)
            {
                ControlFlow.Fail(
                    new[] { ex.Message, "Command-line arguments were:" }
                            .Concat(args.Select((x, i) => $"  [{i}] = {x}"))
                            .Join(Environment.NewLine));
                return null;
            }
        }

        private static bool HasCommandLineArgument (string argumentName)
        {
            var args = s_commandLineArgumentsProvider.Invoke();
            return Array.FindLastIndex(args, x => x.EqualsOrdinalIgnoreCase($"-{argumentName}")) != -1;
        }

        [CanBeNull]
        public static object GetEnvironmentVariable (string variableName, Type destinationType, char? separator = null)
        {
            var variables = s_environmentVariablesProvider.Invoke();
            var value = variables.Contains(variableName) ? (string) variables[variableName] : null;
            if (value == null)
                return GetDefaultValue(destinationType);

            try
            {
                return ConvertValues(variableName, separator.HasValue ? value.Split(separator.Value) : new[] { value }, destinationType);
            }
            catch (Exception ex)
            {
                ControlFlow.Fail(new[] { ex.Message, "Environment variable was:", value }.Join(Environment.NewLine));
                return null;
            }
        }

        [CanBeNull]
        private static object GetDefaultValue (Type type)
        {
            if (type.IsArray)
                return Array.CreateInstance(type.GetElementType(), length: 0);

            if (Nullable.GetUnderlyingType(type) == null && type != typeof(string))
                return Activator.CreateInstance(type);

            return null;
        }

        [CanBeNull]
        private static object ConvertValues (string parameterName, IReadOnlyCollection<string> values, Type destinationType)
        {
            try
            {
                return ConvertValues(values, destinationType);
            }
            catch (Exception ex)
            {
                ControlFlow.Fail(new[] { $"Resolving parameter '{parameterName}' failed.", ex.Message }.Join(Environment.NewLine));
                return null;
            }
        }

        [CanBeNull]
        private static object ConvertValues (IReadOnlyCollection<string> values, Type destinationType)
        {
            ControlFlow.Assert(!destinationType.IsArray || destinationType.GetArrayRank() == 1, "Arrays must have a rank of 1.");
            var elementType = destinationType.IsArray ? destinationType.GetElementType() : destinationType;
            ControlFlow.Assert(values.Count < 2 || elementType != null, "values.Count < 2 || elementType != null");

            if (values.Count == 0)
            {
                if (destinationType == typeof(bool) || destinationType == typeof(bool?))
                    return true;
                if (elementType == typeof(string) || Nullable.GetUnderlyingType(elementType) != null)
                    return null;
            }

            var convertedValues = values.Select(x => Convert(x, elementType)).ToList();
            if (!destinationType.IsArray)
            {
                ControlFlow.Assert(convertedValues.Count == 1, $"Value [ {values.Join(", ")} ] cannot be assigned to '{GetName(destinationType)}'.");
                return convertedValues.Single();
            }

            var array = Array.CreateInstance(elementType, convertedValues.Count);
            convertedValues.ForEach((x, i) => array.SetValue(x, i));
            ControlFlow.Assert(destinationType.IsInstanceOfType(array),
                $"Type '{GetName(array.GetType())}' is not an instance of '{GetName(destinationType)}'.");

            return array;
        }

        [CanBeNull]
        private static object Convert (string value, Type destinationType)
        {
            try
            {
                var typeConverter = TypeDescriptor.GetConverter(destinationType);
                return typeConverter.ConvertFromInvariantString(value);
            }
            catch
            {
                ControlFlow.Fail($"Value '{value}' could not be converted to '{GetName(destinationType)}'.");
                return null;
            }
        }

        private static string GetName(Type type)
        {
            if (type.IsArray)
                return $"{type.GetElementType().Name}[]";
            if (Nullable.GetUnderlyingType(type) != null)
                return Nullable.GetUnderlyingType(type).Name + "?";
            return type.Name;
        }
    }
}
<commit_msg>Return null even for arrays.<commit_after>// Copyright <NAME> 2017.
// Distributed under the MIT License.
// https://github.com/nuke-build/nuke/blob/master/LICENSE

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using JetBrains.Annotations;
using Nuke.Core.Utilities;
using Nuke.Core.Utilities.Collections;

namespace Nuke.Core.Execution
{
    public static class ParameterService
    {
        private static readonly Func<string[]> s_commandLineArgumentsProvider = () => Environment.GetCommandLineArgs();
        private static readonly Func<IDictionary> s_environmentVariablesProvider = () => Environment.GetEnvironmentVariables();

        [CanBeNull]
        public static T GetParameter<T> (string parameterName, char? separator = null)
        {
            return (T) GetParameter(parameterName, typeof(T), separator);
        }

        [CanBeNull]
        public static T GetCommandLineArgument<T> (string parameterName, char? separator = null)
        {
            return (T) GetCommandLineArgument(parameterName, typeof(T), separator);
        }

        [CanBeNull]
        public static T GetEnvironmentVariable<T> (string parameterName, char? separator = null)
        {
            return (T) GetEnvironmentVariable(parameterName, typeof(T), separator);
        }

        [CanBeNull]
        public static object GetParameter (string parameterName, Type destinationType, char? separator = null)
        {
            return HasCommandLineArgument(parameterName)
                ? GetCommandLineArgument(parameterName, destinationType, separator)
                : GetEnvironmentVariable(parameterName, destinationType, separator);
        }

        [CanBeNull]
        public static object GetCommandLineArgument (string argumentName, Type destinationType, char? separator = null)
        {
            var args = s_commandLineArgumentsProvider.Invoke();
            var index = Array.FindLastIndex(args, x => x.EqualsOrdinalIgnoreCase($"-{argumentName}"));
            if (index == -1)
                return GetDefaultValue(destinationType);

            var values = args.Skip(index + 1).TakeWhile(x => !x.StartsWith("-")).ToArray();
            ControlFlow.Assert(values.Length == 1 || !separator.HasValue || values.All(x => !x.Contains(separator.Value)),
                $"Command-line argument '{argumentName}' with value [ {values.Join(", ")} ] cannot be split with separator '{separator}'.");
            values = separator.HasValue && values.Any(x => x.Contains(separator.Value))
                ? values.SingleOrDefault()?.Split(separator.Value) ?? new string[0]
                : values;

            try
            {
                return ConvertValues(argumentName, values, destinationType);
            }
            catch (Exception ex)
            {
                ControlFlow.Fail(
                    new[] { ex.Message, "Command-line arguments were:" }
                            .Concat(args.Select((x, i) => $"  [{i}] = {x}"))
                            .Join(Environment.NewLine));
                return null;
            }
        }

        private static bool HasCommandLineArgument (string argumentName)
        {
            var args = s_commandLineArgumentsProvider.Invoke();
            return Array.FindLastIndex(args, x => x.EqualsOrdinalIgnoreCase($"-{argumentName}")) != -1;
        }

        [CanBeNull]
        public static object GetEnvironmentVariable (string variableName, Type destinationType, char? separator = null)
        {
            var variables = s_environmentVariablesProvider.Invoke();
            var value = variables.Contains(variableName) ? (string) variables[variableName] : null;
            if (value == null)
                return GetDefaultValue(destinationType);

            try
            {
                return ConvertValues(variableName, separator.HasValue ? value.Split(separator.Value) : new[] { value }, destinationType);
            }
            catch (Exception ex)
            {
                ControlFlow.Fail(new[] { ex.Message, "Environment variable was:", value }.Join(Environment.NewLine));
                return null;
            }
        }

        [CanBeNull]
        private static object GetDefaultValue (Type type)
        {
            if (Nullable.GetUnderlyingType(type) == null && type != typeof(string) && !type.IsArray)
                return Activator.CreateInstance(type);

            return null;
        }

        [CanBeNull]
        private static object ConvertValues (string parameterName, IReadOnlyCollection<string> values, Type destinationType)
        {
            try
            {
                return ConvertValues(values, destinationType);
            }
            catch (Exception ex)
            {
                ControlFlow.Fail(new[] { $"Resolving parameter '{parameterName}' failed.", ex.Message }.Join(Environment.NewLine));
                return null;
            }
        }

        [CanBeNull]
        private static object ConvertValues (IReadOnlyCollection<string> values, Type destinationType)
        {
            ControlFlow.Assert(!destinationType.IsArray || destinationType.GetArrayRank() == 1, "Arrays must have a rank of 1.");
            var elementType = destinationType.IsArray ? destinationType.GetElementType() : destinationType;
            ControlFlow.Assert(values.Count < 2 || elementType != null, "values.Count < 2 || elementType != null");

            if (values.Count == 0)
            {
                if (destinationType == typeof(bool) || destinationType == typeof(bool?))
                    return true;
                if (elementType == typeof(string) || Nullable.GetUnderlyingType(elementType) != null)
                    return null;
            }

            var convertedValues = values.Select(x => Convert(x, elementType)).ToList();
            if (!destinationType.IsArray)
            {
                ControlFlow.Assert(convertedValues.Count == 1, $"Value [ {values.Join(", ")} ] cannot be assigned to '{GetName(destinationType)}'.");
                return convertedValues.Single();
            }

            var array = Array.CreateInstance(elementType, convertedValues.Count);
            convertedValues.ForEach((x, i) => array.SetValue(x, i));
            ControlFlow.Assert(destinationType.IsInstanceOfType(array),
                $"Type '{GetName(array.GetType())}' is not an instance of '{GetName(destinationType)}'.");

            return array;
        }

        [CanBeNull]
        private static object Convert (string value, Type destinationType)
        {
            try
            {
                var typeConverter = TypeDescriptor.GetConverter(destinationType);
                return typeConverter.ConvertFromInvariantString(value);
            }
            catch
            {
                ControlFlow.Fail($"Value '{value}' could not be converted to '{GetName(destinationType)}'.");
                return null;
            }
        }

        private static string GetName(Type type)
        {
            if (type.IsArray)
                return $"{type.GetElementType().Name}[]";
            if (Nullable.GetUnderlyingType(type) != null)
                return Nullable.GetUnderlyingType(type).Name + "?";
            return type.Name;
        }
    }
}

{'fraction_non_alphanumeric': 0.10568503300552337, 'fraction_numerical': 0.0020881045399434193, 'mean_word_length': 2.1171530547973965, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 39, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6337092', 'n_tokens_mistral': 3702, 'n_tokens_neox': 3552, 'n_words': 851}