Skip to content

[CLI-339] Help formatter extension#314

Merged
garydgregory merged 18 commits intoapache:masterfrom
Claudenw:Help_formatter_extension
Oct 14, 2024
Merged

[CLI-339] Help formatter extension#314
garydgregory merged 18 commits intoapache:masterfrom
Claudenw:Help_formatter_extension

Conversation

@Claudenw
Copy link
Contributor

@Claudenw Claudenw commented Sep 28, 2024

Fix for CLI-339

Implementation of a commons client help production system.

Creates a new package containing the classes used by commons-cli to produce the help output.
In general there are 4 classes that users/developers may be interested in.

  • HelpFormatter - the class used to produce the help output for most users.
  • HelpPrinter - Writes the output in a specific output serialization format (e.g. text, XHTML, Markdown, etc.)
  • OptionFormatter - Determines how to format the various data elements in an Option
  • TableDef - Defines a table to be displayed. Useful for developers who want to build custom option displays or use the help system to produce additional information in the help system
  • TextStyle - Defines the style for text in tables and the default style for the TextHelpPrinter.

@Claudenw Claudenw self-assigned this Sep 28, 2024
@Claudenw Claudenw marked this pull request as ready for review October 2, 2024 07:45
@Claudenw
Copy link
Contributor Author

Claudenw commented Oct 2, 2024

Java 24-ea fails due to issues with spotbugs plugin under java-24

Copy link
Member

@garydgregory garydgregory left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @Claudenw

Great start ! :-)

I think that HelpWriter is really an Appendable since you already have 2 out of 3 methods of Appendable's implemented in kind with writeDirect(char|String) where Appendable has append(ch|CharSequence). I made the following change locally and carried it through with a local green build:

/*
  Licensed to the Apache Software Foundation (ASF) under one or more
  contributor license agreements.  See the NOTICE file distributed with
  this work for additional information regarding copyright ownership.
  The ASF licenses this file to You under the Apache License, Version 2.0
  (the "License"); you may not use this file except in compliance with
  the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
 */
package org.apache.commons.cli.help;

import java.io.IOException;
import java.util.Collection;

/**
 * The definition of a semantic scribe.  The semantic scribe write string to output based on the semantic meaning
 * of the type of string.  e.g. a Paragraph -vs- a Heading.
 * <p>
 *     the representation of the semantics is dependant upon the format being output.  For example the plain text
 *     output for a paragraph may print the text followed by two line breaks, while an XHTML output would print the
 *     text surrounded by &lt;p&gt; and &lt;/p&gt;
 * </p>
 */
public interface HelpWriter extends Appendable {

    /**
     * Writes a title.
     *
     * @param title the title to write.
     * @throws IOException on write failure
     */
    void writeTitle(String title) throws IOException;

    /**
     * Writes a paragraph.
     *
     * @param paragraph the paragraph to write.
     * @throws IOException on write failure
     */
    void writePara(String paragraph) throws IOException;

    /**
     * Writes a header.
     *
     * @param level  the level of the header
     * @param text   the text for the header
     * @throws IOException on write failure
     */
    void writeHeader(int level, String text) throws IOException;

    /**
     * Writes a list.
     *
     * @param ordered {@code true} if the list should be ordered.
     * @param list   the list to write.
     * @throws IOException on write failure
     */
    void writeList(boolean ordered, Collection<String> list) throws IOException;

    /**
     * Writes a table.
     *
     * @param table   the table definition to write.
     * @throws IOException on write failure
     */
    void writeTable(TableDef table) throws IOException;
}

and:

public abstract class AbstractHelpWriter implements HelpWriter {
    /**
     * The Appendable instance to write to.
     */
    protected final Appendable output;

    /**
     * Constructs an instance using the provided Appendable instance.
     * @param output the Appendable instance to write to.
     */
    protected AbstractHelpWriter(final Appendable output) {
        this.output = output;
    }

    @Override
    public Appendable append(final CharSequence text) throws IOException {
        output.append(text);
        return this;
    }

    @Override
    public Appendable append(final char ch) throws IOException {
        output.append(ch);
        return this;
    }

    @Override
    public Appendable append(final CharSequence csq, final int start, final int end) throws IOException {
        output.append(csq, start, end);
        return this;
    }
}

WDYT?

* @param options the collection of {@link Option} instances to create the table from.
* @return A {@link TableDef} to display the options.
*/
public TableDef defaultTableBuilder(final Iterable<Option> options) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit odd. If it's the default behavior AND it's overridable from the builder, then it should be the default value. This would also help validate that the class is configurable enough if the default behavior is coded the same way a user would override it. IOW, can I call the Build with the behavior in this method?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a chicken and egg problem.

The builder needs a Function<Iterable, TableDef>.

The HelpFormatter instance class can not pass a reference to a non-static method to the builder.

If the method from the HelpFormatter instance needs to use instance variables it can not be passed.

I need to spend a bit of time to figure out how to untangle this. Perhaps the clarity on the showSince flag will help resolve this.

@Claudenw
Copy link
Contributor Author

Claudenw commented Oct 5, 2024

As far as making HelpWriter extends Appendable I think that is a good idea. However I feel that it moves the class further from the "Writer" concept as delineated by the Javadoc for Writer. I want to rename HelpWriter to Scribe and the implementing calsses to TextScribe, AptScribe, etc.

@garydgregory
Copy link
Member

As far as making HelpWriter extends Appendable I think that is a good idea. However I feel that it moves the class further from the "Writer" concept as delineated by the Javadoc for Writer. I want to rename HelpWriter to Scribe and the implementing calsses to TextScribe, AptScribe, etc.

😄 Since Java's Write implements Appendable, HelpWriter extending Appendable would move the class closer to the "Writer" concept IMO, not further. But, this could be the issue with having named the class "*Writer" in the first place 😄 ❓ Either way, we agree: extend Appendable, whatever the class name is.

Copy link
Member

@garydgregory garydgregory left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @Claudenw
Nice tests! :-)
Please see my assorted comments.
TY.

* The class for help formatters provides the framework to link the {@link HelpWriter} with the {@link OptionFormatter}
* and a default {@link TableDef} so to produce a standard format help page.
*/
public abstract class AbstractHelpFormatter {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's not bake in an odd design for users because its uncomfortable for us developers to put in place a good one ;-) all for one special attribute.

Extensible builders are normal and we do it in several places in Commons (Configuration, Exec, IO), the pattern is [abstract or not] class Builder<T extends Builder<T>> implements Supplier<T> and SubBuilder extends Builder<SubBuilder>.

A simple example for Commons Exec:

Commons IO and Configuration have more advanced and complex examples.

@garydgregory
Copy link
Member

The Javadoc is still off (See Java 23 build output):

[ERROR] C:\Users\ggregory\git\a\commons-cli\src\main\java\org\apache\commons\cli\HelpFormatter.java:597: error: reference not found
[ERROR]      * @deprecated use {@link OptionFormatter#getArgName()} or {@link OptionFormatter.Builder#getArgName()}
[ERROR]                                                                       ^

Copy link
Member

@garydgregory garydgregory left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @Claudenw

Thank you for your updates. I've added to a couple of conversations, resolved a few others, and added some new comments.

TY!

@garydgregory garydgregory merged commit e9a72ea into apache:master Oct 14, 2024
@garydgregory garydgregory changed the title CLI-339: Help formatter extension [CLI-339] Help formatter extension Oct 14, 2024
asfgit pushed a commit that referenced this pull request Oct 14, 2024
- Update changes.xml
- Sort members
- Only use Javadoc @SInCE tags for public and protected elements
- Javadoc: Break before tags
- Javadoc: Write complete sentences.
- Javadoc: Use @code
- Javadoc: Sentences start with a capital letter
- Add missing @OverRide annotation
- Use final
- Rename asArgName to toArgName (it calls another toArgName)
- Whitespace
- Use longer lines
- Normalize test method names
- Name test methods after the methods they test
dongjoon-hyun added a commit to apache/spark that referenced this pull request Aug 4, 2025
### What changes were proposed in this pull request?

This PR aims to upgrade `commons-cli` to 1.10.0 which is the first release tested with **Java 25-ea**.

### Why are the changes needed?

To bring the latest improvements and bug fixes.
- https://commons.apache.org/proper/commons-cli/changes.html#a1.10.0 (2025-07-30)
  - [Run Java 24 and 25-ea](apache/commons-cli@e6a611f)
  - [[CLI-333] org.apache.commons.cli.Option.Builder implements](apache/commons-cli@c9698e6)
  - apache/commons-cli#314
  - apache/commons-cli#334
  - [[CLI-341] HelpFormatter infinite loop with 0 width input](apache/commons-cli@bce0f6a)
  - [[CLI-343] OptionFormatter.getBothOpt() lacks validation for Options](apache/commons-cli@859d5e5)
  - [[CLI-344] Option.processValue() throws NullPointerException when passed](apache/commons-cli@4e0cdd0)
  - [[CLI-347] Options.addOptionGroup(OptionGroup) does not remove required](apache/commons-cli@42be792)
  - [[CLI-349] DefaultParser.parse() throws NullPointerException when options](apache/commons-cli@ff678b0)

### Does this PR introduce _any_ user-facing change?

No behavior change.

### How was this patch tested?

Pass the CIs.

### Was this patch authored or co-authored using generative AI tooling?

No.

Closes #51816 from dongjoon-hyun/SPARK-53102.

Authored-by: Dongjoon Hyun <dongjoon@apache.org>
Signed-off-by: Dongjoon Hyun <dongjoon@apache.org>
dongjoon-hyun added a commit to apache/orc that referenced this pull request Aug 4, 2025
### What changes were proposed in this pull request?

This PR aims to upgrade `commons-cli` to 1.10.0 which is the first release tested with Java 25-ea.

### Why are the changes needed?

To bring the latest improvements and bug fixes.
- https://commons.apache.org/proper/commons-cli/changes.html#a1.10.0 (2025-07-30)
  - [Run Java 24 and 25-ea](apache/commons-cli@e6a611f)
  - [[CLI-333] org.apache.commons.cli.Option.Builder implements](apache/commons-cli@c9698e6)
  - apache/commons-cli#314
  - apache/commons-cli#334
  - [[CLI-341] HelpFormatter infinite loop with 0 width input](apache/commons-cli@bce0f6a)
  - [[CLI-343] OptionFormatter.getBothOpt() lacks validation for Options](apache/commons-cli@859d5e5)
  - [[CLI-344] Option.processValue() throws NullPointerException when passed](apache/commons-cli@4e0cdd0)
  - [[CLI-347] Options.addOptionGroup(OptionGroup) does not remove required](apache/commons-cli@42be792)
  - [[CLI-349] DefaultParser.parse() throws NullPointerException when options](apache/commons-cli@ff678b0)

### How was this patch tested?

Pass the CIs.

### Was this patch authored or co-authored using generative AI tooling?

No.

Closes #2349 from dongjoon-hyun/ORC-1968.

Authored-by: Dongjoon Hyun <dongjoon@apache.org>
Signed-off-by: Dongjoon Hyun <dongjoon@apache.org>
dongjoon-hyun added a commit to apache/orc that referenced this pull request Aug 4, 2025
### What changes were proposed in this pull request?

This PR aims to upgrade `commons-cli` to 1.10.0 which is the first release tested with Java 25-ea.

### Why are the changes needed?

To bring the latest improvements and bug fixes.
- https://commons.apache.org/proper/commons-cli/changes.html#a1.10.0 (2025-07-30)
  - [Run Java 24 and 25-ea](apache/commons-cli@e6a611f)
  - [[CLI-333] org.apache.commons.cli.Option.Builder implements](apache/commons-cli@c9698e6)
  - apache/commons-cli#314
  - apache/commons-cli#334
  - [[CLI-341] HelpFormatter infinite loop with 0 width input](apache/commons-cli@bce0f6a)
  - [[CLI-343] OptionFormatter.getBothOpt() lacks validation for Options](apache/commons-cli@859d5e5)
  - [[CLI-344] Option.processValue() throws NullPointerException when passed](apache/commons-cli@4e0cdd0)
  - [[CLI-347] Options.addOptionGroup(OptionGroup) does not remove required](apache/commons-cli@42be792)
  - [[CLI-349] DefaultParser.parse() throws NullPointerException when options](apache/commons-cli@ff678b0)

### How was this patch tested?

Pass the CIs.

### Was this patch authored or co-authored using generative AI tooling?

No.

Closes #2349 from dongjoon-hyun/ORC-1968.

Authored-by: Dongjoon Hyun <dongjoon@apache.org>
Signed-off-by: Dongjoon Hyun <dongjoon@apache.org>
(cherry picked from commit 7a1a34f)
Signed-off-by: Dongjoon Hyun <dongjoon@apache.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants