Fossil Forum

Command exit codes
Login

Command exit codes

Command exit codes

(1) By Busslina (busslina) on 2024-03-18 20:31:07 [link] [source]

Is there documentation about the exit codes meaning for every sub/command?

(2) By Stephan Beal (stephan) on 2024-03-18 20:49:55 in reply to 1 [link] [source]

Is there documentation about the exit codes meaning for every sub/command?

No, and there are no such codes. Contrary to popular belief, C only specifies two portable exit codes: EXIT_SUCCESS and EXIT_FAILURE. Fossil also does not consistently use more than two result codes: success and failure.

(3) By Busslina (busslina) on 2024-03-18 21:19:38 in reply to 2 [link] [source]

Thanks, but it is possible to give a more detailed information using extra codes. E.G. Systemd.

I understand that in your way of work maybe doesn't need it, but to create a well defined specific exit codes:

  1. Is not too much
  2. In my opinion will give more value to Fossil moving it to the next level, making it viable to create and manage new repositories in a automated way. This opens a wide set of possibilities.

(5.1) By Stephan Beal (stephan) on 2024-03-18 21:33:06 edited from 5.0 in reply to 3 [link] [source]

... but it is possible to give a more detailed information using extra codes. E.G. Systemd.

Sure it's possible but it's not (contrary to popular belief) portable.

Is not too much

Patches will be thoughtfully considered. Edit: fossil currently has 110 distinct commands, by the way (and 258 if we count the test commands).

This opens a wide set of possibilities.

Sharing concrete use cases often goes a long way towards convincing those who might volunteer to take on such work.

Just used to Discord where you can correct the messages.

You can edit your messages here, but not while they're pending moderation.

(6) By Busslina (busslina) on 2024-03-18 21:45:49 in reply to 5.1 [link] [source]

Thanks

(7.2) By Busslina (busslina) on 2024-03-18 22:02:18 edited from 7.1 in reply to 5.1 [link] [source]

What do you think about this solution?

All commands have an optional --status-code argument and when present, the first line of the output will be a number between 0 and 255

(8) By Stephan Beal (stephan) on 2024-03-18 22:29:52 in reply to 7.2 [source]

What do you think about this solution?

Patches will be thoughtfully considered :).

You'll quickly find that fossil's internals call exit() for very nearly any error and can do so from any given command, so defining a very specific list of result codes will pose a significant challenge.

the first line of the output will be a number between 0 and 255

The status code is not known until after all work is done or some error has been encountered, possibly after having generated an arbitrary amount of output, so it would be effectively impossible to guaranty that the first line of output could be reserved for a status code.

Technical challenges aside: given the scope of the proposed changes (110 commands and countless subcommands, plus commitment from developers to adhere to those result codes for the rest of fossil's life), getting such a change approved for integration into the trunk would require compelling justifications beyond "it would be cool to have" (which certainly nobody is doubting, but that's not enough justification for a change of this scope).

(9.6) By Busslina (busslina) on 2024-03-19 03:19:41 edited from 9.5 in reply to 8 [link] [source]

I have just coded in C for the first time in years. Having my will to keep digging on this issue until I see that there is no way, I will try to propose a better solution and if you or the team, at some point, think that it is feasible I would try to implement it.

So lets put the idea of having this status code from the first line to the last line of the output. That seems way easier to achieve.

I did a simple implementation in C.

So, it's mandatory to call exitWWrapper instead of exit everywhere when an error occurs (and wants to exit immediately).

Also, on success, if a function wants to specify a status code it must call exitWrapper too.

It's some restrictive, but I don't know if it is too much for you.

So, it could be refactored command by command and it isn't mandatory to have a status code defined for every command. (Also it could fire an error when used --status-code on an unsupported sub/command)



#define STATUS_CODE_SUCCESS 0
#define STATUS_CODE_BAD_USAGE 10
#define STATUS_CODE_SUCCESS_CUSTOM_1 21

void exitWWrapper(int exitCode, int statusCode, char* statusCodeDescription);

int commandOne();

int commandTwo();
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>

#include "main.h"

// Links
//
// - https://cplusplus.com/reference/cstdlib/exit/

// ----------------------------------------------------
// Subcommand arguments
// ----------------------------------------------------
// one                  --  Command one
// two                  --  Command two
// ----------------------------------------------------
// Optional arguments
// ----------------------------------------------------
// --status-code        -- Show status code
// ----------------------------------------------------


int subcommandCount = 0;
bool oneSubcommand = false;
bool twoSubcommand = false;
bool statusCodeMode = false;

int main(int argc, char** argv) {

    // Bad usage I
    if (argc < 2) {
        printf("Bad usage: must specify a subcommand\n", argc);
        exitWWrapper(EXIT_FAILURE, STATUS_CODE_BAD_USAGE, "");
    }

    // Processing arguments
    for (int i = 1; i < argc; i++) {
        if (strcmp(argv[i], "one") == 0) {
            oneSubcommand = true;
            subcommandCount++;
        } else if (strcmp(argv[i], "two") == 0) {
            twoSubcommand = true;
            subcommandCount++;
        } else if (strcmp(argv[i], "--status-code") == 0) {
            statusCodeMode = true;
        } else {
            printf("Bad usage: unknown argument %s\n", argv[i]);
            exitWWrapper(EXIT_FAILURE, STATUS_CODE_BAD_USAGE, "");
        }
    }

    // Bad usage II
    if (subcommandCount != 1) {
        if (subcommandCount == 0) {
            printf("Bad usage: must specify a subcommand\n");
        } else {
            printf("Bad usage: must specify only one subcommand\n");
        }


        exitWWrapper(EXIT_FAILURE, STATUS_CODE_BAD_USAGE, "");
    }

    if (oneSubcommand) {

        // commandOne Will never return 
        return commandOne();
    }

    if (twoSubcommand) {
        return commandTwo();
    }

    exitWWrapper(EXIT_FAILURE, STATUS_CODE_BAD_USAGE, "Fatal error: must be unreachable");
}

void exitWWrapper(int exitCode, int statusCode, char* statusCodeDescription) {

    if (statusCodeMode) {
        printf("$status-code:%d$status-code-description:%s$\n", statusCode, statusCodeDescription);
    }

    exit(exitCode);
}

int commandOne() {
    printf("Hey, I'm command one\n");

    exitWWrapper(EXIT_SUCCESS, STATUS_CODE_SUCCESS_CUSTOM_1, "");
}

int commandTwo() {
    printf("Hey, I'm command two\n");

    return EXIT_SUCCESS;
}

(4.2) By Busslina (busslina) on 2024-03-18 21:46:13 edited from 4.1 in reply to 2 [link] [source]

Deleted

(10) By Larry Brasfield (larrybr) on 2024-03-19 03:43:38 in reply to 1 [link] [source]

I'm chiming in here because I do not see significant value in adding complexity to the exit codes returned by fossil.

Certainly, for general programming, it is good to have components upon which one relies producing useful diagnostic information. This is particularly true for those errors which can be anticipated as common and subject to some sort of remedy, even an automated remedy in many cases.

But the fossil program is, fundamentally, a tool for human interaction with one or more Fossil repositories. For that purpose, the mere fact of failure and an error message to stderr suffices. In that usage, splitting the general "failed" return into a set of distinct failures has no utility, and and neither would structuring the auxiliary error details ensconced within the error messages.

If somebody intends to build a higher level UI incorporating Fossil repo know-how into its implementation, there is a better tool for the job, one which Stephen has created for just that purpose. (I will let him speak to its current state of readiness for the task you envision, as that becomes apparent.)

It would be nice, from a purely aesthetic perspective, to see the fossil program implemented using a more general purpose library such as Stephen has defined, designed, and substantially implemented. Then, alternative user interfaces or more automated clients could incorporate that library. I would see such an effort as a better investment of software development effort and enthusiasm than revising the existing fossil code to suit a purpose for which it has not been designed.

(11) By Stephan Beal (stephan) on 2024-03-19 07:52:43 in reply to 10 [link] [source]

It would be nice, from a purely aesthetic perspective, to see the fossil program implemented using a more general purpose library ...

Indeed: https://fossil.wanderinghorse.net/r/libfossil

As far as its readiness goes: it's my daily driver for all CLI features except sync (for which it currently shells out to the fossil binary). Conversely, none of the UI-related features, including parsing of wiki/doc pages, are implemented and there are currently no plans to do so.

Sidebar: my first question to Richard when meeting him for the first time was why fossil had not been written as a library/app combination like he'd done with sqlite. His answer: "because I wanted it running tomorrow instead of next month." i.e. it was a matter of practicality, and keeping it that way remains to be one. Its monolithic structure lets it do many things in far less code than a library can. e.g. where as library has to check for every single little error code and bubble those up to the caller, the app can simply die on error with an informative message directly at the failure point. That truly does save tons of development time. The lack of checks for malloc() failures alone saves tremendous amounts of code and effort.

@Busslina:

I have just coded in C for the first time in years. Having my will to keep digging on this issue until I see that there is no way,

The fossil internals are significantly more intricate than your example, so your proposal is nowhere near as straightforward to implement in fossil. Though i encourage you to dig around in the code and become familiar with it, i unequivocally agree with Larry that fossil is an interactive application and that this particular capability provides too little benefit for interactive fossil use to justify the code upheaval it would require.