kareman / Moderator

A simple, modular command line argument parser in Swift.
MIT License
21 stars 2 forks source link

Arguments with spaces in the value? #2

Closed jeffctown closed 7 years ago

jeffctown commented 7 years ago

Is there a way to create an argument that allows spaces in it?

I am trying to use Moderator for a swift script to post a message to the Slack API. How can i pass in a "message" argument that may have spaces in it? Wrapping my message argument value in quotes does not seem to work.

I imagine I could write my messages to a file, and pass in the filename, but I was curious if there is any other way with the current Moderator implementation.

import Foundation
import Moderator
import SwiftShell

let arguments = Moderator(description: "Post a message to Slack.")

let messageArg = arguments.add(Argument<String?>.optionWithValue("m", name: "message", description: "The message to post."))
let botNameArg = arguments.add(Argument<String?>.optionWithValue("n", name: "name", description: "The name of the bot."))
let urlSlugArg = arguments.add(Argument<String>.optionWithValue("p", name: "path", description: "The url path (the part after https://hooks.slack.com/services/)."))

do {
    try arguments.parse()

    guard let message = messageArg.value else {
        throw ArgumentError(errormessage: "Slack message not found.", usagetext: "use -m Message")
    }

    guard let urlSlug = urlSlugArg.value else {
        throw ArgumentError(errormessage: "Slack URL path not found.", usagetext: "use -p T000000/B000000/XXXXXXX")
    }

    guard let botName = botNameArg.value else {
        throw ArgumentError(errormessage: "Bot name not found.", usagetext: "use -n BotName")
    }

    } catch {
        print("*** FAILURE!")
        print(error)
        exit(Int32(error._code))
    }

Here is what happens with my current script. I am trying to get the "m" argument to contain spaces:

$ marathon run post-to-slack.swift -m Message! -p T00000000/B00000000/XXXXXXXXXXXX -n Bot

$ marathon run post-to-slack.swift -m Longer Message! -p T0000000/B0000000/XXXXXXXXXXXX -n Bot
*** FAILURE!
Unknown arguments: Message!
Post a message to Slack.

Usage: post-to-slack
  -m <message>:
      The message to post.
  -n <name>:
      The name of the bot.
  -p <path>:
      The url path (the part after https://hooks.slack.com/services/).

$ marathon run post-to-slack.swift -m "Longer Message!" -p T00000000/B00000000/XXXXXXXXXXXXXX -n Bot
-bash: !": event not found

Thanks you for any guidance you can help provide. Loving your tools.

kareman commented 7 years ago

This seems to be an issue with marathon. If you go to the project directory of post-to-slack.swift (by default in ~/.marathon/Scripts/Cache/`) and run:

swift build
./.build/debug/post-to-slack -m "Longer Message" -p T0000000/B0000000/XXXXXXXXXXXX -n Bot

it should work. But only without the !, otherwise bash will complain about "event not found".

kareman commented 7 years ago

Apparently you can include ! if you use single quotes instead: https://unix.stackexchange.com/questions/33339/cant-use-exclamation-mark-in-bash

jeffctown commented 7 years ago

I'm seeing the exact behavior you are describing. Seems like an issue with Marathon. Thanks for the fast response. 👍

kareman commented 7 years ago

@jeffctown BTW your example above reminded me that the automatically generated error message Moderator gives when a required argument is missing is pretty useless. I tried to improve on that in this release: https://github.com/kareman/Moderator/releases/tag/0.4.2 . Now you can do this:

let messageArg = arguments.add(Argument<String?>.optionWithValue("m", name: "message", description: "The message to post.").required())
let botNameArg = arguments.add(Argument<String?>.optionWithValue("n", name: "name", description: "The name of the bot.").required())
let urlSlugArg = arguments.add(Argument<String>.optionWithValue("p", name: "path", description: "The url path (the part after https://hooks.slack.com/services/).").required(errormessage: "Slack URL path not found. Use -p T000000/B000000/XXXXXXX"))

do {
    try arguments.parse()

    let message = messageArg.value
    let urlSlug = urlSlugArg.value
    let botName = botNameArg.value

and still (hopefully) get useful error messages. I'd love to hear any feedback you have, you can comment on the commit itself (https://github.com/kareman/Moderator/commit/19660ff89e5dd6ed17ab70505d9147ddca1ab482) or create a new issue if you want.

jeffctown commented 7 years ago

@kareman great man. I will be picking this up again tonight, so I will update and let you know how the new error messages are looking.

FYI - the marathon team was able to provide a crazy fast turn around to get this fixed within 24 hours - https://github.com/JohnSundell/Marathon/issues/114.

jeffctown commented 7 years ago

@kareman love it man. I think you've helped convince me to rewrite all of my automation scripts in swift. 👍

kareman commented 7 years ago

Glad to hear it :) . Automation feels much safer when you can catch many errors at compile time.