DEV Community

Kyle Homen
Kyle Homen

Posted on

OSD600 Lab 4

For this lab, we're practicing using git remotes and merges to collaborate with our peers. The feature I worked on was adding support for a TOML "dotfile" configuration file that could be used to specify all of the available CLI arguments.

This week I wanted to try something different and work on a C++ repository. So far I have played it safe and have just worked with python, even when contributing to other students' projects.

The Code

I found that this repository had no pull request yet so I contacted the owner to get permission to work on it after filing an issue, then I got to work researching how to approach this using C++. My C++ is rusty, so it took me some time to work my way through the code. Finally, with a little research, I worked out that I could use the existing CMake file in this project to set up the tomlplusplus implementation which would allow me to parse a config.toml file and load default options into the tool. I added a new function, loadFromConfig, that reads the TOML file and populates the CLI options struct with values like output, include, exclude, and recent. This way, users can define their preferences once and avoid repeating long command-line arguments.

Example from loadFromConfig

            auto tbl = toml::parse_file(path); // Parse TOML file into table

            // Loading of each argument value from table
            if (auto out = tbl["output"].value<std::string>()) // Checks if key exists and assigns string
                opts.outputFile = *out; // Dereferences and stores the string in Options struct

            if (auto inc = tbl["include"].value<std::string>()) {
                opts.includePattern = *inc;
                std::string pattern = *inc; // Copy for use in lambda
                // Takes in variable pattern and argument for file path and passes into filter function
                opts.onIncludeFilter = [pattern](const std::filesystem::path &p) {
                    return onlyIncludedExtensions(p.string(), pattern); 
                };
            }
Enter fullscreen mode Exit fullscreen mode

I had some trouble at first getting the TOML logic to work, because I wasn't running the built in filter functions (such as onlyIncludedExtensions) that were used on certain CLI arguments. For example, output was working fine when using the TOML file, but include wasn't because I wasn't putting the arguments through the helper function.

Moving on, in main.cpp, I added the configuration loader alongside the cli parser, then checked if each cli argument existed. If the cli argument was left empty, the config argument would be used, and if there was no TOML argument, the built in default from the Options struct would be used.

Example from main

        // Parse config.toml options
        cfgOpt = config::loadFromConfig("config.toml");
        // Parse cli options
        cliOpt = cli::parse(argc, argv);
        // Merge options, overiding any config options with cli options
        opt = cfgOpt;

        if (!cliOpt.outputFile.empty())
            opt.outputFile = cliOpt.outputFile;
        if (!cliOpt.includePattern.empty()) {
            opt.includePattern = cliOpt.includePattern;
            opt.onIncludeFilter = cliOpt.onIncludeFilter;
        }
Enter fullscreen mode Exit fullscreen mode

Here I had a moment where none of my changes seemed to go through, and I struggled for almost an hour before realizing I wasn't making a new build for each change.. turns out I did have it right at some point and just kept testing an older version. It's been a while..

After finally making the correct build, I tested the tool with a sample config.toml like this:

output = "report.md"
include = ""
exclude = "LICENSE"
recent = true
Enter fullscreen mode Exit fullscreen mode

Now, running repoctx . automatically picks up these defaults — and if you want to override them, you can still pass flags like --output custom.md or --exclude README.

In the pull request I made, I documented the changes I had made and gave some usage examples. The author of the project asked me to remove some unnecessary file I had accidentally uploaded, add some comments, and fix a minor issue with bracket formatting (my IDE had auto formatting on which I hadn't noticed). After making those changes, the changes were merged.

Working with Git

I didn't have too much trouble with git this week either. Although, I did get ahead of myself and merged a PR through the git UI and not with the command line. It's hard not to use the built in git features in VSCode and Github sometimes, that's something I need to practice more.

One thing I did do manually was test the work done in my project using remotes. I was able to make a branch and mess around a bit without the fear of overriding any of the work the other student had done, or any of my own work. For example, I found that the TOML file the student had created was not in the same directory as my repo-scan.py, and therefore nothing was happening. But once I moved the file over I could test it appropriately (and address and issue with my file structure).

The issue made in my project was explained well, and the PR request had no issues I could find while testing, and explained the changes well.

Top comments (0)