All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.yin.flags.GflagsParser Maven / Gradle / Ivy

Go to download

Easy to use command-line parser, which enables you to define cmdline flags directly the class they are used in.

There is a newer version: 0.3.0-beta2
Show newest version
package com.github.yin.flags;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * Parses command-line arguments under rules defined by:
 * https://gflags.github.io/gflags/
 */
class GflagsParser implements Parser {
    private static final Logger log = LoggerFactory.getLogger(GflagsParser.class);
    private final List arguments = new ArrayList();
    private final FlagIndex flags;
    private AcceptorState state;
    private FlagMetadata lastMeta;

    enum AcceptorState {KEY_EXPECTED, VALUE_EXPECTED}

    public GflagsParser(@Nonnull FlagIndex flags) {
        this.flags = flags;
    }

    @Override
    public List parse(String[] args) {
        start();
        for (String arg : args) {
            next(arg);
        }
        return end();
    }

    protected void start() {
        state = AcceptorState.KEY_EXPECTED;
    }

    protected void next(String arg) {
        if (arg.startsWith("--")) {
            flag(arg.substring(2), arg);
        } else if (arg.startsWith("-")) {
            flag(arg.substring(1), arg);
        } else {
            handleValue(arg);
        }
    }

    protected void flag(String flag, String orig) {
        int i = flag.indexOf('=');
        if (i == -1) {
            key(flag, orig);
        } else {
            String key = flag.substring(0, i);
            String value = flag.substring(i + 1, flag.length() - i - 1);
            keyAndValue(key, value, orig);
        }
    }

    protected void key(String key, String original) {
        if (state != AcceptorState.KEY_EXPECTED) {
            errorFlagHasNoValue();
        }
        Collection flagsByName = flags.byName().get(key);
        if (flagsByName.isEmpty() && key.startsWith("no")) {
            flagsByName = flags.byName().get(key.substring(2));
            if (flagsByName.size() == 1) {
                handleFalseFlag(flagsByName.iterator().next(), original);
            } else if (flagsByName.isEmpty()) {
                errorUnknownFlag(original);
            } else {
                errorAmbigousFlag(original, flagsByName);
            }
        }
        if (flagsByName.size() == 1) {
            handleFlag(flagsByName.iterator().next());
        } else if (flagsByName.isEmpty()) {
            errorUnknownFlag(original);
        } else {
            errorAmbigousFlag(original, flagsByName);
        }
    }

    protected void keyAndValue(String key, String value, String original) {
        if (state != AcceptorState.KEY_EXPECTED) {
            errorFlagHasNoValue();
        }
        Collection flagsByName = flags.byName().get(key);
        if (flagsByName.size() == 1) {
            handleFlag(flagsByName.iterator().next());
            handleValue(value);
        } else if (flagsByName.isEmpty()) {
            errorUnknownFlag(original);
        } else {
            errorAmbigousFlag(original, flagsByName);
        }
    }

    protected void handleFlag(FlagMetadata meta) {
        Class flagtype = meta.getClass();
        if (BasicFlag.BooleanFlag.class.isAssignableFrom(flagtype)) {
            meta.flag().parse("true");
        } else {
            this.lastMeta = meta;
            state = AcceptorState.VALUE_EXPECTED;
        }
    }

    protected void handleFalseFlag(FlagMetadata meta, String orig) {
        Class flagtype = meta.getClass();
        if (BasicFlag.BooleanFlag.class.isAssignableFrom(flagtype)) {
            meta.flag().parse("false");
        } else {
            errorUnknownFlag(orig);
        }
    }

    protected void handleValue(String value) {
        //TODO yin: Add support for collections
        if (state == AcceptorState.VALUE_EXPECTED) {
            lastMeta.flag().parse(value);
            state = AcceptorState.KEY_EXPECTED;
        } else {
            arguments.add(value);
        }
    }

    protected List end() {
        if (state != AcceptorState.KEY_EXPECTED) {
            errorFlagHasNoValue();
        }
        return arguments;
    }

    protected void errorUnknownFlag(String flag) {
        log.error("Unknown flag: {}", flag);
    }

    protected void errorAmbigousFlag(String flag, Collection flagsByName) {
        log.error("Flag {} resolves in multiple classes: {}", flag,
                flagsByName.stream().map(meta -> meta.flagID()).toArray());
    }

    protected void errorFlagHasNoValue() {
        log.error("Option {} has no value", lastMeta);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy