[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/kidoz/dotpython/main/src/DotPython.Cli/DotPythonCommand.cs [Back]  [Original]

using DotPython.Hosting.Packaging;
using DotPython.Language.Diagnostics;
using DotPython.Language.Text;
using DotPython.Runtime.Managed;
using DotPython.Runtime.Managed.Execution;

namespace DotPython.Cli;

internal static class DotPythonCommand
{
    public static int Run(
        IReadOnlyList arguments,
        TextReader standardInput,
        TextWriter standardOutput,
        TextWriter standardError,
        CancellationToken cancellationToken = default
    )
    {
        ArgumentNullException.ThrowIfNull(arguments);
        ArgumentNullException.ThrowIfNull(standardInput);
        ArgumentNullException.ThrowIfNull(standardOutput);
        ArgumentNullException.ThrowIfNull(standardError);

        if (arguments.Count == 0)
        {
            standardError.WriteLine(
                "dotpython: interactive mode is not implemented; use -c, -, or a script path"
            );
            return 2;
        }

        if (arguments[0] is "-h" or "--help")
        {
            WriteHelp(standardOutput);
            return 0;
        }

        if (arguments[0] is "-V" or "--version")
        {
            var compatibility = ManagedRuntimeDescriptor.Compatibility;
            standardOutput.WriteLine(
                $"DotPython {compatibility.Implementation} (Python {compatibility.LanguageVersion})"
            );
            return 0;
        }

        if (arguments[0] == "wheel")
        {
            return RunWheelCommand(arguments, standardOutput, standardError);
        }

        if (
            !TryReadSource(
                arguments,
                standardInput,
                standardError,
                out var source,
                out var moduleSearchPath
            )
        )
        {
            return 2;
        }

        try
        {
            var engine = new ManagedPythonEngine(
                new ManagedModuleDiscoveryOptions { SearchPaths = [moduleSearchPath] }
            );
            var result = engine.Execute(
                source,
                standardOutput,
                new ManagedExecutionOptions { StandardInput = standardInput },
                cancellationToken
            );
            if (result.Success)
            {
                return 0;
            }

            foreach (var diagnostic in result.Diagnostics)
            {
                WriteDiagnostic(result.Source, diagnostic, standardError);
            }

            return 1;
        }
        catch (OperationCanceledException)
        {
            standardError.WriteLine("dotpython: execution cancelled");
            return 130;
        }
        catch (Exception exception)
            when (exception
                    is IOException
                        or InvalidDataException
                        or UnauthorizedAccessException
                        or ArgumentException
            )
        {
            standardError.WriteLine($"dotpython: module discovery failed: {exception.Message}");
            return 1;
        }
    }

    private static int RunWheelCommand(
        IReadOnlyList arguments,
        TextWriter standardOutput,
        TextWriter standardError
    )
    {
        if (arguments.Count != 3 || arguments[1] != "inspect")
        {
            standardError.WriteLine("dotpython: usage: dotpython wheel inspect ");
            return 2;
        }

        try
        {
            var inspection = PythonWheelInspector.Inspect(arguments[2]);
            standardOutput.WriteLine(PythonWheelInspectionJson.Serialize(inspection));
            return inspection.IsValid ? 0 : 1;
        }
        catch (IOException exception)
        {
            standardError.WriteLine(
                $"dotpython: cannot inspect '{arguments[2]}': {exception.Message}"
            );
            return 1;
        }
        catch (UnauthorizedAccessException exception)
        {
            standardError.WriteLine(
                $"dotpython: cannot inspect '{arguments[2]}': {exception.Message}"
            );
            return 1;
        }
    }

    private static bool TryReadSource(
        IReadOnlyList arguments,
        TextReader standardInput,
        TextWriter standardError,
        out SourceText source,
        out string moduleSearchPath
    )
    {
        if (arguments[0] == "-c")
        {
            if (arguments.Count < 2)
            {
                standardError.WriteLine("dotpython: argument expected for -c");
                source = new SourceText(string.Empty, "");
                moduleSearchPath = Directory.GetCurrentDirectory();
                return false;
            }

            source = new SourceText(arguments[1], "");
            moduleSearchPath = Directory.GetCurrentDirectory();
            return true;
        }

        if (arguments[0] == "-")
        {
            source = new SourceText(standardInput.ReadToEnd(), "");
            moduleSearchPath = Directory.GetCurrentDirectory();
            return true;
        }

        if (arguments[0].StartsWith('-'))
        {
            standardError.WriteLine($"dotpython: unsupported option '{arguments[0]}'");
            source = new SourceText(string.Empty, "");
            moduleSearchPath = Directory.GetCurrentDirectory();
            return false;
        }

        try
        {
            var fullPath = Path.GetFullPath(arguments[0]);
            source = new SourceText(File.ReadAllText(fullPath), fullPath);
            moduleSearchPath = Path.GetDirectoryName(fullPath) ?? Directory.GetCurrentDirectory();
            return true;
        }
        catch (IOException exception)
        {
            standardError.WriteLine(
                $"dotpython: cannot read '{arguments[0]}': {exception.Message}"
            );
            source = new SourceText(string.Empty, arguments[0]);
            moduleSearchPath = Directory.GetCurrentDirectory();
            return false;
        }
        catch (UnauthorizedAccessException exception)
        {
            standardError.WriteLine(
                $"dotpython: cannot read '{arguments[0]}': {exception.Message}"
            );
            source = new SourceText(string.Empty, arguments[0]);
            moduleSearchPath = Directory.GetCurrentDirectory();
            return false;
        }
    }

    private static void WriteDiagnostic(
        SourceText source,
        Diagnostic diagnostic,
        TextWriter standardError
    )
    {
        var position = source.GetLinePosition(Math.Min(diagnostic.Span.Start, source.Length));
        standardError.WriteLine(
            $"{source.FilePath ?? ""}:{position.Line + 1}:{position.Character + 1}: "
                + $"{diagnostic.Code}: {diagnostic.Message}"
        );
    }

    private static void WriteHelp(TextWriter output)
    {
        output.WriteLine("Usage: dotpython -c command [args]");
        output.WriteLine("       dotpython - [args]");
        output.WriteLine("       dotpython script.py [args]");
        output.WriteLine("       dotpython wheel inspect artifact.whl");
        output.WriteLine();
        output.WriteLine(
            "Current managed subset: literals, names, assignment, arithmetic, and calls."
        );
    }
}

Web Proxy Viewer  |  New URL  |  Original Page