JohnSundell / Marathon

[DEPRECATED] Marathon makes it easy to write, run and manage your Swift scripts πŸƒ
MIT License
1.86k stars 78 forks source link

Redefine tasks #182

Closed ghost closed 6 years ago

ghost commented 6 years ago

LOVE YOUR CODE BRO MY EYES BLEED WITH HAPPINESS

I have enjoyed spending time on Marathon and I hope you like this pull request.

I noticed Marathon is using the command pattern so I started reading up about it. Then I started looking at Marathon and I noticed a few potential bugs or risky areas that I might be able to improve.

No hard feelings if you don't want to pull this one in.

Tasks

If the ScriptManager throws during the early setup phase, the error CouldNotPerformSetup is thrown for all tasks. However, the following tasks do not require the ScriptManager.

Further, the following tasks only use a PackageManager.

And the Help task uses neither.

The following do not consume any options or supplementary arguments.

So have fixed these issues in this pull request by reworking tasks so that they are not all treated the same.

A Collection Of Strings

arguments: [String]

The input at the CommandLine includes

  1. a command
  2. one or many options
  3. other supplementary arguments

These appear in marathon as an array of strings and are rarely unpacked into types.

So for instance...

marathon create <name> <content>

Could be represented like this

final class CreateTask {
    let name: String?
    let content: String?

This pull request implements this by digesting the array of command line arguments (strings) where possible (as early as possible).

enum Option: String {
    case noOpen = "--no-open"
    case force = "--force"
    case allScriptData = "--all-script-data"
    case allPackages = "--all-packages"
    case verbose = "--verbose"
    case noXcode = "--no-xcode"
}

enum Command {
    case create(arguments: [String])
    case edit(arguments: [String])
    case remove(arguments: [String])
    case run(arguments: [String])
    case install(arguments: [String])
    case add(arguments: [String])
    case list
    case update
    case help
}

struct Request {

    let command: Command
    let options: [Option]
    let printer: Printer

    init(arguments: [String], printer: Printer) throws {
        self.printer = printer
        var arguments = arguments
        // strip away
        arguments.removeFirst()
        // strip away
        self.options = Option.assemble(from: &arguments)
        if let argument = arguments.first {
            // strip away
            self.command = try Command(command: argument, arguments: Array(arguments.dropFirst()))
        } else {
            self.command = .help
        }
        /// more stripping in individual Tasks where appropriate
    }
}

The RunTask task, which runs a script that may itself require arguments, is represented in the same way i.e. with properties.

class RunTask {
    let name: String?
    let arguments: [String]

The benefit of this approach is that the task is only given the arguments relevant for the task at hand. All other arguments are stripped away.

Building

Arguments no longer passed in as strings here.

#if os(Linux)
    try script.build(for: .release(environment: .linux))
#else
    try script.build(for: .release(environment: .unspecified))
#endif

Printer

I made this change quite early on. I'm not sure why. Would you like me to change it back? πŸ™„

Before

class Printer {
    let output: PrintFunction
    let reportProgress: VerbosePrintFunction
    let verboseOutput: VerbosePrintFunction

After

class Printer {
    let conclusion: PrintFunction
    let progress: VerbosePrintFunction
    let debug: VerbosePrintFunction
JohnSundell commented 6 years ago

Hi @rob-nash, and thanks for your contribution. However, this change is too big to be considered at the moment, since we're not looking to make such big architectural changes. The focus for Marathon right now is to keep up with changes in Xcode and the underlying developer tools, to fix bugs, and to implement missing features that would make using it easier. After that, we can take a look at improving the architecture, but it would have to be done piece by piece, not with such a big change. Thanks anyway πŸ™‚

ghost commented 6 years ago

I understand @JohnSundell no worries πŸ‘