This release adds an os-packages file to list all package/srpms in
the build, which can be useful for determining more information on
packages and their corresponding SRPM name.
Signed-off-by: Tudor Marcu <tudor.marcu@intel.com>
This file is intended to be used by validation tooling to identify
orphaned packages and verify there are no file collisions in the build.
Signed-off-by: Matthew Johnson <matthew.johnson@intel.com>
This release fixes the following bugs:
- Resolve /lib to /usr/lib instead of /usr/lib64
- Install DirectPackages to full chroot instead of AllPackages
- DirectPackage is the fully resolved list for the bundle(s)
- Skip continued lines in dnf install output causing missing lines in parsing
- Clear cache before DNF install to full chroot causing dnf tracebacks
Smaller fixes such as adding trailing newline to mixbundles, parsing
versions numbers on init, normalizing bundle name output, and updating
all (currently possible) yum references to dnf were also added.
Signed-off-by: Tudor Marcu <tudor.marcu@intel.com>
Previously mixer wrote the mix bundle list as a newline-separated list,
rather than as a newline-delimited list. This made things like "wc -l"
report one fewer than expected, as the final line contained no newline.
This trailing newline does not affect the existing parsing code.
Signed-off-by: Kevin C. Wells <kevin.c.wells@intel.com>
Keeping the cache around has resulted in interesting errors with invalid
bytes being read from the cache and resulting in DNF tracebacks. As a
fix for this tell DNF not to keepcache and manually clear the cache
before doing the full install. This seems to either be a bug with DNF
itself or maybe with the way Clear Linux is doing its packaging (though
this is just a guess).
The error seen is a UnicodeDecodeError from the DNF source code. It is
trying to decode a non-UTF-8 byte as UTF-8:
Traceback (most recent call last):
File "/usr/bin/dnf", line 58, in <module>
main.user_main(sys.argv[1:], exit_code=True)
File "/usr/lib/python3.6/site-packages/dnf/cli/main.py", line 179, in user_main
errcode = main(args)
File "/usr/lib/python3.6/site-packages/dnf/cli/main.py", line 64, in main
return _main(base, args, cli_class, option_parser_class)
File "/usr/lib/python3.6/site-packages/dnf/cli/main.py", line 99, in _main
return cli_run(cli, base)
File "/usr/lib/python3.6/site-packages/dnf/cli/main.py", line 123, in cli_run
ret = resolving(cli, base)
File "/usr/lib/python3.6/site-packages/dnf/cli/main.py", line 154, in resolving
base.do_transaction(display=displays)
File "/usr/lib/python3.6/site-packages/dnf/cli/cli.py", line 238, in do_transaction
super(BaseCli, self).do_transaction(display)
File "/usr/lib/python3.6/site-packages/dnf/base.py", line 781, in do_transaction
self._run_transaction(cb=cb)
File "/usr/lib/python3.6/site-packages/dnf/base.py", line 925, in _run_transaction
self._verify_transaction(cb.verify_tsi_package)
File "/usr/lib/python3.6/site-packages/dnf/base.py", line 1018, in _verify_transaction
self.history.sync_alldb(po)
File "/usr/lib/python3.6/site-packages/dnf/yum/history.py", line 1399, in sync_alldb
self._save_rpmdb(ipkg) and
File "/usr/lib/python3.6/site-packages/dnf/yum/history.py", line 1360, in _save_rpmdb
val = getattr(ipkg, attr, None)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xa1 in position 0: invalid start byte
Signed-off-by: Matthew Johnson <matthew.johnson@intel.com>
DNF likes to set line-width to a default 80 characters when not running
in a TTY (this was confirmed in the source code) and perform a
complicated 'smart wrap' on the fields after any fields that overflow
their column. This results in wrapped lines that do not have the
information we are looking for. Fortunately these lines are prefixed by
more than one space (' ') character. Since package names are always at
the beginning of the line and only prefixed by one space character, if
there is more than one space we can skip the line when parsing.
Signed-off-by: Matthew Johnson <matthew.johnson@intel.com>
Do not just install the AllPackages list to the full chroot, since this
is just the list of all included packages. The DirectPackages need to be
installed instead since this is the fully resolved list for each bundle.
AllPackages do not need to be installed because all bundles are being
installed to the same place.
Do a check on the length of the DirectPackages list before actually
trying to install them so we don't try to 'dnf install ' (no package
specified) for bundles that don't specify their own packages and only
include other bundles.
Signed-off-by: Matthew Johnson <matthew.johnson@intel.com>
Recently, code was added to ReadVersions to parse the mixversion
and upstreamversion string values as uint32 values. This patch
adds the same logic to init (the only command that does not
result in a call to ReadVersions), so that the parsed versions
will be consistently available.
Signed-off-by: Kevin C. Wells <kevin.c.wells@intel.com>
Recent changes deprecated the use of individual bundle chroots when
building bundle contents and moved away from using yum to using dnf.
Because of this much of our variable and file names and comments were
inconsistent with the implementation.
This includes a change to make 'mixer build chroots' an alias to 'mixer
build bundles' and updates to the bat tests to call the new 'mixer build
bundles' command. This is not a breaking change since 'mixer build
chroots' behaves the way it always has (except internally with the
recent changes mentioned).
Signed-off-by: Matthew Johnson <matthew.johnson@intel.com>
Previously, the names of bundles were output differently from one
command to another. Some would insert the bundle name as-is, some would
surround it with single quotes, and some would use double quotes.
This patch normalizes all output (that I could find in builder.conf) to
use the same output format: all now use the %q formatter, which renders
them with double quotes.
Signed-off-by: Kevin C. Wells <kevin.c.wells@intel.com>
This release includes a significant change to the way chroots are built.
Rather than building individual chroots for each bundle, a single full
chroot is generated, and JSON metadata files are created for each bundle.
This allows us to scale much more easily on machines with limited disk
space. Because chroots are now decoupled from manifest creation, this
also makes it possible in the future to move to bundle builds on
distributed machines.
Additionally, a change was made to allow developers to add extra files
to a bundle in addition to those included by the bundle packages.
A change was included that fails when the manifest cannot be parsed.
Minor bug fixes are also included.
Signed-off-by: Kevin C. Wells <kevin.c.wells@intel.com>
This overhaul leaves several tests using the old method of using chroots
to generate the update to verify we aren't totally deprecating the old
method.
Signed-off-by: Matthew Johnson <matthew.johnson@intel.com>
Deprecate use of chroot-building for each individual bundle. This allows
us to scale much easier on machines with limited disk space. Because
chroots are decoupled from manifest creation this also makes it possible
in the future to move to doing bundle builds on distributed machines and
allows our bundle numbers to scale. The bundle file list is stored in a
JSON file that is read later by the manifest creation step.
This leaves a fallback in swupd/fullchroot.go to allow users to add
content to a chroot in order to extend a typical build.
Signed-off-by: Matthew Johnson <matthew.johnson@intel.com>
This release fixes:
- Travis: add workaround to failing clrtrust
- build-deltas: Do not fail on missing previous versions
- Update 'mixer bundle add' to skip existing bundles
Signed-off-by: Kevin C. Wells <kevin.c.wells@intel.com>
Previously, repeated calls to 'mixer bundle add <bundle>' would yield
the same "Adding bundle <bundle> from <source>" output. Because the
Mix Bundle List is treated as a set, and duplicate bundles are removed,
these redundant additions do not change the resultant list, and are
effectively no-ops.
This patch:
a) Explictly skips the bundles if they already exist.
b) Reports this case to the user
As a result, functionality is equivalent, but the no-op behavior is
more explicit and output is more clear.
Signed-off-by: Kevin C. Wells <kevin.c.wells@intel.com>
A version can be missing if the minversion is newer than the previous
version being checked. This is not an error, but should be printed as a
warning to the user in case this is not expected.
Signed-off-by: Matthew Johnson <matthew.johnson@intel.com>
This release changes basic bundle validation to support previously
non-passing bundles in upstream so mixes with previous versions are not
so strictly filtered. Hardlinking only happens if --keep-chroots is
passed to avoid race conditions and wasting time hardlinking when it
does not need to happen. Issues with bundle list were fixed, offline
mode was added for mixer to skip caching upstream bundle definitions, a
default value for local-bundle directory was added, and other updates to
variables to match the new naming schemes 4.0.* introduced.
Signed-off-by: Tudor Marcu <tudor.marcu@intel.com>
Previously, "basic" bundle validation included checking that the
bundle filename (currently used as the "bundle name") matched the
"Title" field in the bundle header (currently not used), and that
the "Title" field itself was valid. This was a step toward future
usage, where mixer will use the header "Title" itself.
This caused mixer to be incompatible with previous versions of CLR,
for which these filename-to-title missmatches were allowed and thus
present.
This patch moves this checking exclusively to "--strict" validation,
and removes bundle content validation from "basic" altogether. Basic
validation now only checks that the bundle filename is valid and that
the bundle contents syntax can be parsed.
Signed-off-by: Kevin C. Wells <kevin.c.wells@intel.com>
Due to using nosync, hardlinking could start before all of the individual
bundle chroots are actually removed. However, we do not need to hardlink if
--keep-chroots is not passed, because the full chroot implicitly will not
have any duplicate files. In this case, just delete the individual bundle
chroots and don't hardlink.
Signed-off-by: Tudor Marcu <tudor.marcu@intel.com>
Fixes a bug in the location for where the Mix Bundle List
(stored in the 'mixbundles' file) is read/write during 'mixer
bundle add' and 'mixer bundle remove' commands.
Signed-off-by: Kevin C. Wells <kevin.c.wells@intel.com>
This patch adds a persistent "--offline" flag to the top-level mixer
command, which means every command can pass this flag to make mixer
work offline.
When mixer works offline, it skips caching upstream bundle definition
files. This has the implication that every bundle in the user's mix
must be available in local-bundles.
Signed-off-by: Kevin C. Wells <kevin.c.wells@intel.com>
LOCAL_BUNDLE_DIR is a new builder.conf field introduced in mixer 4.0.
It is included in the auto-generated conf from mixer init, and it is
referenced in the updated documentation.
Previously, however, it was marked as a "required" flag in the
ReadBuilderConf function. This meant that existing users, who did not
already have this value, were given an error message saying it was
missing, but no useful information about how to fix this.
This patch provides default fall-back value of the user's PWD +
"/local-bundles" if the field is missing. If this happens, a warning
message is output, informing the user to update their conf.
Signed-off-by: Kevin C. Wells <kevin.c.wells@intel.com>
This release fixes the mixer-completion to install to a given optional prefix
so it can be built in different environments.
Signed-off-by: Tudor Marcu <tudor.marcu@intel.com>
This release introduces a major version update with several new features
and package additions.
The original C swupd-server https://github.com/clearlinux/swupd-server and
bundle-chroot-builder https://github.com/clearlinux/bundle-chroot-builder
are now integrated into mixer itself under the swupd/ and builder/ packages,
and used as libraries instead of standalone binaries. The rewrite closely ties
the swupd-server and chroot-builder functionality directly into mixer, while
providing the benefits of the Go language. The new functionality lives side
by side with the original implementation for the time being, until further
testing is completed to guarantee consistent, stable behaviour. However,
the new features may (and should) be used by providing --new-swupd and
--new-chroots with the appropriate mixer subcommands. They will become the
default as the old standalone build programs are deprecated.
The second major update is a new CLI written using the Cobra framework.
Existing commands are only subtly different:
old new
---- ----
mixer build-chroots mixer build chroots
mixer build-update mixer build update
mixer init-mix mixer init
-flags --flags
In short, the command hierarchy is changed such that things like 'build'
are top level commands, and the things they build are exposed under them,
rather than making many hyphenated commands. Flags are implemented as
regular short and long options, where long options use two hyphens
instead of one.
New commands have been added to make bundle lifecycle management easier,
and to ensure bundles are manipulated correctly without manually copying
things in specific folders. See all new commands by typing "mixer" *enter*.
Miscellaneous fixes to things such as init creating the builder.conf and
doing more upfront work for the user have also been implemented. The
goal of these updates is to streamline the operation of mixer and
improve usability.
Many tests were added for the code base; unit tests for the new
swupd and chroot libraries, BAT tests to cover the interface and
functionality of the Mixer itself, and extensive linting were added to
catch regressions and enforce cleaner code.
Signed-off-by: Tudor Marcu <tudor.marcu@intel.com>
New command checks bundle definition files for validity. Only local bundle files are
checked; upstream bundles are trusted as valid. Valid bundles yield no output.
Any invalid bundles will yield a non-zero return code.
Basic validation includes checking syntax and structure, that the bundle has
a valid name, and that the header 'Title' matches the bundle filename. Commands
like 'mixer bundle edit' run basic validation automatically.
An optional '--strict' flag allows you to additionally check that the other
bundle header flags are parsable and non-empty.
Passing '--all-local' will run validation on all bundles in local-bundles.
This patch also adds tests to check that bundle header parsing is working
and that different types of validation errors are indeed being caught.
Basic validation is added throughout the various 'mixer bundle' commands.
Signed-off-by: Kevin C. Wells <kevin.c.wells@intel.com>
Replace the workflow of manually updating the two files to get a new
version. The 'mixer versions' prints the relevant versions and 'mixer
versions update' provides a way to update those versions.
When updating the command does check the upstream format and do not
cross format bumps. So it helps preventing people generating wrong
content. The commands will provide a point to do more checks in the
future, like if there is a problem with the local bundles after an
update.
Also make the download function previously used to get latest file
reusable for other purposes, and returning error for non-OK status
codes.
To keep commands consistent both 'versions update' and 'init' will
accept --clear-version or --upstream-version (they are equivalent).
Updates #145.
Updates #59.
Signed-off-by: Caio Marcelo de Oliveira Filho <caio.oliveira@intel.com>
Fail early if we can't parse those at ReadVersions time. Also remove
code in the individual functions that were doing these.
Signed-off-by: Caio Marcelo de Oliveira Filho <caio.oliveira@intel.com>
In particular add a "done" message to help with progress indication
during parallelized chroot builds.
Signed-off-by: Matthew Johnson <matthew.johnson@intel.com>
And print the versions being used.
Fixes#123. (in combination with #153 that was already merged)
Signed-off-by: Caio Marcelo de Oliveira Filho <caio.oliveira@intel.com>
Make the number of worker goroutines a parameter in delta creation and
add a flag to set that in Mixer. When zero (default) the flag sets the
number of workers to the number of CPUs.
Having a flag let the users to control better how much resources mixer
can/will take.
Signed-off-by: Caio Marcelo de Oliveira Filho <caio.oliveira@intel.com>
Make the number of worker goroutines a parameter in
swupd.CreateFullfiles and add a flag to set that. When zero (default)
the flag sets the number of workers to the number of CPUs.
Having a flag let the users to control better how much resources mixer
can/will take.
Signed-off-by: Caio Marcelo de Oliveira Filho <caio.oliveira@intel.com>
Use tabwriter to account for the size of all entries
printed (including the "included" ones that where not being accounted
before).
The output will be buffered (so it can calculate the columns) but for
the bundles list this is not an issue.
The code was also simplified to use bundle name directly instead of
taking the route of finding a *bundle and then using its name. They
should be the same.
Before:
bootloader (upstream)
c-basic (upstream)
desktop (upstream)
desktop-apps (upstream) (included)
desktop-assets (upstream) (included)
desktop-gnomelibs (upstream) (included)
desktop-locales (upstream) (included)
kernel-native (upstream)
libX11client (upstream) (included)
os-core (upstream)
os-core-update (upstream)
python3-basic (upstream) (included)
sysadmin-basic (upstream) (included)
After:
bootloader (upstream)
c-basic (upstream)
desktop (upstream)
desktop-apps (upstream) (included)
desktop-assets (upstream) (included)
desktop-gnomelibs (upstream) (included)
desktop-locales (upstream) (included)
kernel-native (upstream)
libX11client (upstream) (included)
os-core (upstream)
os-core-update (upstream)
python3-basic (upstream) (included)
sysadmin-basic (upstream) (included)
Signed-off-by: Caio Marcelo de Oliveira Filho <caio.oliveira@intel.com>
If flag is passed we print the report with all the files in the
manifest and whether they were included or not. The report stays right
above the count of fullfiles and deltas.
The output looks like (modified to fit in the commit message):
Creating delta packs from 10 to 20
Creating delta pack for bundle caio from 10 to 20
Pack report:
/usr/bin/2to3 packed fullfile (from chroot)
/usr/bin/c_hash not packed (already in from manifest)
/usr/bin/clrtrust not packed (already in from manifest)
/usr/bin/corelist not packed (already in from manifest)
/usr/bin/cpan not packed (already in from manifest)
/usr/bin/ebrowse not packed (file deleted)
/usr/bin/emacs not packed (file deleted)
(...)
Creating delta pack for bundle os-core-update-index from 10 to 20
Pack report:
/usr/share/clear/os-core-update-index packed delta (10-20-3a480a802244c61eefd24009b0b24d1ba6d822aa4358ef51bfd4492244589a5e-74fba7851c7bb474588f0321fe4715c8e6f83bba8889cc917f6a0490f3a777b7)
Signed-off-by: Caio Marcelo de Oliveira Filho <caio.oliveira@intel.com>
Fix an old TODO, this gives visibility in every build about the
compression algorithms being used.
Note the accounting "gzip" (and not "external-gzip") because at the
moment it is being used for links and directories. It probably should
just migrate to use the external gzip later.
Output looks like:
=> CREATE FULLFILES
- Already created: 0
- Not compressed: 0
- Compressed
- external-bzip2 40
- gzip 389
- external-xz 2520
- external-gzip 953
Total fullfiles: 3902
Signed-off-by: Caio Marcelo de Oliveira Filho <caio.oliveira@intel.com>
If you update your upstream version number, the tool is supposed to
automatically pull the new definition files for you. There were two
places where it wasn't currently doing that yet, which is now fixed.
Signed-off-by: Kevin C. Wells <kevin.c.wells@intel.com>
Removes bundles from your mix by modifying the Mix Bundle List
(stored in the 'mixbundles' file). The Mix Bundle List is parsed, the bundles
are removed, and the resultant list is written back out in sorted order. If
bundles do not exist in the mix, they are skipped.
Passing '--local' will also remove the corresponding bundle definition file from
local-bundles, if it exists. Please note that this is an irrevocable step.
'--mix' defaults to true. Passing '--mix=false' will prevent the bundle from
being removed from your Mix Bundle List. This is useful when used in conjunction
with '--local' to *only* remove a bundle from local-bundles. If the bundle being
removed is an edited version from upstream, the bundle will remain in your mix
and now reference the original upstream version. If the bundle was custom, and
no upstream alternative exists, a warning will be returned.
Signed-off-by: Kevin C. Wells <kevin.c.wells@intel.com>
Add 'create new bundle' functionality to 'mixer bundle edit'. Now, if a
bundle is not found in local-bundles or upstream-bundles, it is treated
as a new bundle, and a blank bundle definition file template is created
for the user to edit.
Also minor syntax optimization on editing switch.
Adds new command, 'mixer bundle edit', that allows a user to edit local
and upstream bundle definition files. This command will locate the
bundle (looking first in local-bundles, then in upstream-bundles), and launch
an editor to edit it. If the bundle is only found upstream, the bundle file will
first be copied to your local-bundles directory for editing. When the editor
closes, the bundle file is then parsed for validity.
The editor is configured via environment variables. VISUAL takes precedence to
EDITOR. If neither are set, the tool defaults to nano. If nano is not installed,
the tool will skip editing, and act as if '--copy-only' had been passed.
Passing '--copy-only' will suppress launching the editor, and will thus only copy
the bundle file to local-bundles if it is only found upstream. This can be
useful if you want to add a bundle to local-bundles, but wish to edit it at a
later time.
Passing '--add' will also add the bundle(s) to your mix. Please note that
bundles are added after all bunles are edited, and thus will not be added if any
errors are encountered earlier on.
Signed-off-by: Kevin C. Wells <kevin.c.wells@intel.com>
DNF already works in Clear and at the moment Yum is not working, so it
is a good time to stop calling it.
Drop the --packager, if an alternative version of DNF have to be used,
just put it in PATH before the system one.
Fixes#115.
This commit refactors the way you specify what bundles are included
in your mix, as well as how the mix-bundles directory gets
generated.
Major changes in this commit:
- Introduces the Mix Bundles List, a newline-separated file in the
working directory that lists the bundles that must be in the mix.
Other bundles (included by those in the list) will be added
automatically.
- Introduces the local-bundles directory that stores any bundles
that the user created or that have been edited from upstream.
Bundles in the local-bundles directory take precedence over
upstream bundles of the same name.
- Generates the mix-bundles/ directory (used as input to the BCB)
automatically on-the-fly when chroots are built. The Mix Bundles
List is recursed to find all bundles needed for the mix, and the
bundle definition files are copied from either the local or
upstream bundles.
- If '--new-chroots' is passed, the mix-bundles/ directory is
skipped entirely, as the new BCB is capable of reading the
files from anywhere.
- Modifies the 'mixer bundle add' command to now edit the Mix
Bundles List. Bundles are verified to exist in either the local
or upstream bundles. The user is informed whether the added
bundles came from local or upstream.
- Adds a new 'list' command to 'mixer bundle' that prints out
the bundles in the Mix Bundle List (including those
recursively included), all bundles available in local bundles,
or all bundles available in upstream bundles. The mix bundle
list, bundle names are annotated with information about their
origin (local or upstream) and whether they are part of the
Mix Bundle List or just included. For the local and upstream
lists, bundle names are annotated with whether or not they are
currently included in the mix. All three of the above list
types support a '--tree' option that prints them as a formatted
tree view, visually showing the include relationship for bundles
and how the full list is being generated.
Minor changes in this commit:
- As the mix-bundles directory is now created on-the-fly, it is no
longer tracked as a git repository. Instead, the entire mixer
working directory is tracked, with temporary, tool-generated
files ignored. This allows one to track and correlate the Mix
Bundle List, mix version, and upstream version as they are changed.
- The above-mentioned git revision tracking is now optional, and
is only set up if '--git' is passed to 'mixer init'. 'mixer
bundle add' still supports '--git', which mirrors this behavior.
- The '--all' flags for 'mixer init' and 'mixer bundle add' have
been split up into '--all-local' and '--all-upstream'. This
allows a user to add or start with all local or upstream bundles,
or both.
Adds support for the keyword "latest" for `--clear-version` when
running mixer init. This becomes the default value if the flag is
omitted.
'--clear-version latest' will fetch the latest published upstream
version number, according to the value found via 'upstreamurl'
Signed-off-by: Kevin C. Wells <kevin.c.wells@intel.com>
This commit has three main side effects:
1) The .clearversion, .mixversion, and .clearurl files are no longer
hidden files. Deprecation code has been added to work with the old
versions if they exist, but print a deprecation notice.
They were likely originally hidden to declutter the workspace, but
they are (for now) files the user needs to edit directly, and thus
should not be hidden.
2) The clearversion and clearurl files has been renamed
upstreamversion and upstreamurl, as part of a larger goal to
accomodate derivatives-of-derivatives, for whom upstream is not
mainline CLR. (The internal fields on the Builder object have been
renamed as well.) Deprecation code has been added to work with the old
versions if they exist, but print a deprecation notice.
3) Per feedback, the .mixer directory has been removed.
Two of the goals the directory was introduced to solve will instead
be met in different ways:
i) Hiding temporary, sausage-making files. The mix-bundles/
directory will soon cease to exist entirely, once the BCB rewrite
moves out from behind UseNewChrootBuilder. upstream-bundles/ also
contains temporary, tool-generated files, but people have expressed
interest (or at least tolerance) of these not being hidden away.
ii) Organizing/decluttering the workspace. As there are numerous
different configuration files (including the mixversion,
clearversion, clearurl, and forthcoming mix bundle list), having
them in the .mixer directory provided a better form of decluttering
than having the files as hidden dot-files. However, ideally these
files will soon be merged into the builder.conf, when the that
file gets rewritten as a TOML file.
This commit also has minor side effects:
1) General code clean-up (e.g., use of filepath.Join())
2) Change Builder struct field names to match capitalization
conventions
3) Moves the location of InitMix within the file for organizational
purposes.
Signed-off-by: Kevin C. Wells <kevin.c.wells@intel.com>
Refactor bundleSet code to:
1) Loosen definition of bundleSet to simply a set, without
additional constraints. This allows the bundleSet to be built
incrementally, instead of all-at-once, which in turn allows us to
not duplicate bundle parsing that happens elsewhere in the code.
The constraints (completeness and cycle-free), as well as the
computation of the AllPackages field in each bundle, are moved to
a standalone "validateAndFillBundleSet" function.
2) Separate out bundle file parsing into a standalone function,
which allows code reuse elsewhere in the code.
3) Move completeness checking into the sort function, thus
eliminating the need to cycle through the set an additional time.
4) Add additional name validity checking, disallowing bundles with
the reserved names "full" and "MoM"
The above changes do not change the functionality of bundleset,
but improve efficiency and allow code reuse.
All tests have been updated, and additional tests of the bundle
file parsing function have been added.