Creating Artifacts

A brief overview of artifact creating using this API.

This is targeted at those who are familiar with how artifacts are modelled and generated in fossil(1).

Primary artifact reference:

In fossil(1), artifacts are generated via the careful crafting of a memory buffer (large string) in the format described in the document above. While it's relatively straightforward to do, there are lots of potential gotchas, and a bug can potentially inject "bad data" into the repo (though the verify-before-commit process will likely catch any problems before the commit is allowed to go through). The libfossil API uses a higher-level (OO) approach, where the user describes a "deck" of cards and then tells the library to save it in the repo (fsl_deck_save()) or output it to some other channel (fsl_deck_output()). The API ensures that the deck's cards get output in the proper order and that any cards which require special treatment get that treatment (e.g. the "fossilize" encoding of certain text fields). The "deck" concept is equivalent to Artifact in fossil(1), but we use the word deck because (A) Artifact is highly ambiguous in this context and (B) deck is arguably the most obvious choice for the name of a type which acts as a "container of cards."

Ideally, client-level code will never have to create an artifact via the fsl_deck API (because doing so requires a fairly good understanding of what the deck is for in the first place, including the individual Cards). The public API strives to hide those levels of details, where feasible, or at least provide simpler/safer alternatives for basic operations. Some operations may require some level of direct work with a fsl_deck instance. Likewise, much read-only functionality directly exposes fsl_deck to clients, so some familiarity with the type and its APIs will be necessary for most clients.

The process of creating an artifact looks a lot like the following code example. We have elided error checking for readability purposes, but in fact this code has undefined behaviour if error codes are not checked and appropriately reacted to.

fsl_deck * d = &deck; // for typing convenience
fsl_deck_init( fslCtx, d, FSL_CATYPE_CONTROL ); // must come first
fsl_deck_U_set( d, "your-fossil-name", -1 );
fsl_deck_T_add( d, FSL_TAGTYPE_ADD, "...uuid being tagged...",
"tag-name", "optional tag value");
// unshuffle is necessary when using multi-cards which may
// need sorting (tags, filenames, etc.):
fsl_deck_unshuffle(d, 0);
// Unshuffling is done by the client because the deck is const
// when we output it:
// note that fsl_deck_save() does the unshuffle itself.

The order the cards are added to the deck is irrelevant - they will be output in the order specified by the Fossil specs regardless of their insertion order. Each setter/adder function knows, based on the deck's type (set via fsl_deck_init()), whether the given card type is legal, and will return an error (probably FSL_RC_TYPE) if an attempt is made to add a card which is illegal for that deck type. Likewise, fsl_deck_output() and fsl_deck_save() confirm that the decks they are given contain (A) only allowed cards and (B) have all required cards. fsl_deck_save() also sorts any "multi-cards" which need it (e.g. T- and F-cards).