It's the removed section from the get_config() function, but with an
extra Vec<_> creation. This is necessary here because the strings from
the environment variable don't live long enough for lazy evaluation.
Now I can actually test the function!
The previous search locations are still what I'll want for normal
operation, though, so I'll be putting in a new util function to generate
them.
"Now finish drawing the Owl."
I started assembling everything before realizing that I've been thinking
about the program backwards. The `WholeFile` struct is completely
unnecessary, as are several of the functions that help to create it.
I forgot that I don't need to collect all the project tables, only the
"[all]" table, and what ever the user is currently using. I want the
structure of a Map, not a list. I don't want this wrapper, I want the
toml::Value directly.
The implementation is dead simple, and pretty dumb. I'm not going to
figure out all the different IO errors I might see. Instead, the
function will report that it couldn't read the file and call it good.
This function almost writes itself. I need a thin layer to handle the
file IO errors and report them appropriately, and then all the magic is
a pass-through of the existing read_conf_str.
I've made basic unit tests for the most obvious scenarios. The test for
missing-file behavior is incomplete because I need to create a new error
variant.
I'm beginning work on the file reading functions, so I need some files
to read in my tests. I'll also need the WholeFile struct to compare
against.
The input string has been moved out into a file and put back into the
test fixture with `include_str!()`. The WholeFile construction has been
moved to a util function so I can reuse it in another test.
The empty configuration string is some kind of an error, but I'm not
sure where and how to handle it. It should be treated as a soft error,
where I fall back to some hardcoded defaults.
There's a logic hole at the moment: The error I'm actually getting right
now is "NoSuchTable" because the "[all]" table doesn't exist. For a
totally empty config file, the above response should be used. But what
about a non-empty conf file? Is a missing "[all]" valid or not? For now,
assert the loader returns *an* error and leave behind a TODO for later.
I like being able to chain methods instead of using a temporary variable
in between, so I've made one single function like I'm doing the builder
pattern.
But not really because there's nothing to build or finalize and such.
Don't repeat yourself. These property reading routines are actually
methods on the PartialConfig struct, so make them *actually* methods.
Because the table doesn't know it's own name, the path-specific config
needs to be updated with that external knowledge.
The `lconf()` function will eventually load the whole file, but for now
it reads in only the "[all]" table.
That "[all]" table will be used as the global fallback when per-project
settings are left unspecified.
The unit test "passes" but only because I've discarded those per-project
configs from the expected result. This is just so I can see clearly that
the all-table is loading properly.
The get_property function needs to say that there is no property so that
the caller can respond appropriately. I'm going to need to frequently
respond to the "no such property" path by treating it as *not* an error.
If the config file doesn't specify a property, that's not an error, it's
just not specified and the default should be used instead. This util fn
makes that a bit more ergonomic.
I don't want to remember to construct a `String` every single time I
want to call this function with a string literal. So I won't.
Make the functions generic over anything that implements the ToString
trait.
I don't know for sure if the string-ified version of a Release struct is
being printed to the terminal. As such, I don't know if the user wants,
does not want, or has mixed intentions for the stringification of this
thing.
No Display impl, instead just a `colorized()` method.
Itertools already has an intersperse method for me. Why would I build my
own when I can do this? There's even a `fold()` over the units that come
out of the print routine.
The result list has the newest item first, but I want to print them the
other way around. This way the newest (and presumably most interesting)
release is always the visible item, regardless of how many others have
printed and scrolled off screen.
I'm not certain what info I want to present when listing the Releases.
The idea is that the release version is the most important, and that it
matches the git-tag associated with the release. I'll print that first.
Next, the name of the release followed by the body text. The list of
releases will become quite large for some projects, and the body text
may include a changelog. Both of these will cause the output to become
quite large. I will need to create a size limiter, but I'm ignoring that
for now.
Who created the release and when may be useful when searching for a
release, so I've included that as the final section.
I think I got the names from the Go source code, but the API emits JSON
that has these names instead. The api/swagger guide even says as much.
This caused the super fun quirk that the upload actually succeedes, but
the program reports an error condition because of the deserialization
failure. Time to bump a minor revision!