Skip to content

Commit

Permalink
✨ Tool definitions cleanup & new shortcut
Browse files Browse the repository at this point in the history
- Removed problematic environment variable references in default tool definitions
- Removed confusing inline Ruby evaluation from tool handling (its only use)
- Expanded inline Ruby string expansion in tool definitions to run each time a tool is executed
- Added missing exception handling and logging around shelling out to execute a tool command line
  • Loading branch information
mkarlesky committed Aug 28, 2024
1 parent d603776 commit 66fbfa1
Show file tree
Hide file tree
Showing 12 changed files with 272 additions and 194 deletions.
10 changes: 9 additions & 1 deletion docs/BreakingChanges.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ These breaking changes are complemented by two other documents:

---

# [1.0.0 pre-release] — 2024-07-22
# [1.0.0 pre-release] — 2024-08-27

## Explicit `:paths``:include` entries in the project file

Expand Down Expand Up @@ -181,6 +181,14 @@ In addition, a previously undocumented feature for merging a second configuratio

Thorough documentation on Mixins and the new options for loading a project configuration can be found in _[CeedlingPacket](CeedlingPacket.md))_.

## Tool definition inline Ruby evaluation replacement removed (inline Ruby string expansion remains)

Reaching back to the earliest days of Ceedling, tool definitions supported two slightly different string replacement options that executed at different points in a build’s lifetime. Yeah. It was maybe not great.

Support for `{...}` Ruby evaluation in tool definitions has been removed.

Support for `#{...}` Ruby string expansion in tool definitions remains and is now evaluated each time a tool is executed during a build.

## Command Hooks plugin configuration change

In previous versions of Ceedling, the Command Hooks plugin associated tools and hooks by a naming convention within the top-level `:tools` section of your project configuration. This required some semi-ugly tool names and could lead to a rather unwieldy `:tools` list. Further, this convention also limited a hook to an association with only a single tool.
Expand Down
138 changes: 85 additions & 53 deletions docs/CeedlingPacket.md
Original file line number Diff line number Diff line change
Expand Up @@ -261,11 +261,15 @@ built-in plugins come with Ceedling.

## What’s with This Name?

Glad you asked. Ceedling is tailored for unit tested C projects
and is built upon Rake (a Make replacement implemented in the Ruby
scripting language). So, we've got C, our Rake, and the fertile
soil of a build environment in which to grow and tend your project
and its unit tests. Ta da - _Ceedling_.
Glad you asked. Ceedling is tailored for unit tested C projects and is built
upon Rake, a Make replacement implemented in the Ruby scripting language.

So, we've got C, our Rake, and the fertile soil of a build environment in which
to grow and tend your project and its unit tests. Ta da — _Ceedling_.

Incidentally, though Rake was the backbone of the earliest versions of
Ceedling, it is now being phased out incrementally in successive releases
of this tool. The name Ceedling is not going away, however!

## What Do You Mean “Tailored for unit tested C projects”?

Expand Down Expand Up @@ -2403,14 +2407,19 @@ for this. A few highlights from that reference page:
Ceedling is able to execute inline Ruby string substitution code within the
entries of certain project file configuration elements.

This evaluation occurs when the project file is loaded and processed into a
data structure for use by the Ceedling application.
In some cases, this evaluation may occurs when elements of the project
configuration are loaded and processed into a data structure for use by the
Ceedling application (e.g. path handling). In other cases, this evaluation
occurs each time a project configuration element is referenced (e.g. tools).

_Note:_ One good option for validating and troubleshooting inline Ruby string
exapnsion is use of `ceedling dumpconfig` at the command line. This application
command causes your project configuration to be processed and written to a
YAML file with any inline Ruby string expansions, well, expanded along with
defaults set, plugin actions applied, etc.
_Notes:_
* One good option for validating and troubleshooting inline Ruby string
exapnsion is use of `ceedling dumpconfig` at the command line. This application
command causes your project configuration to be processed and written to a
YAML file with any inline Ruby string expansions, well, expanded along with
defaults set, plugin actions applied, etc.
* A commonly needed expansion is that of referencing an environment variable.
Inline Ruby string expansion supports this. See the example below.

#### Ruby string expansion syntax

Expand Down Expand Up @@ -4255,7 +4264,7 @@ A few items before we dive in:
1. Sometimes Ceedling’s built-in tools are _nearly_ what you need but not
quite. If you only need to add some arguments to all uses of tool's command
line, Ceedling offers a shortcut to do so. See the
[final section of the `:tools`][tool-args-shortcut] documentation for
[final section of the `:tools`][tool-definition-shortcuts] documentation for
details.
1. If you need fine-grained control of the arguments Ceedling uses in the build
steps for test executables, see the documentation for [`:flags`][flags].
Expand All @@ -4268,7 +4277,7 @@ A few items before we dive in:
the shortcut in (1) might be the simplest option.

[flags]: #flags-configure-preprocessing-compilation--linking-command-line-flags
[tool-args-shortcut]: #ceedling-tool-arguments-addition-shortcut
[tool-definition-shortcuts]: #ceedling-tool-modification-shortcuts

### Ceedling tools for test suite builds

Expand Down Expand Up @@ -4478,29 +4487,15 @@ require that some number of its arguments or even the executable itself change
for each run. Consequently, every tool’s argument list and executable field
possess two means for substitution at runtime.

Ceedling provides two kinds of inline Ruby execution and a notation for
populating tool elements with dynamically gathered values within the build
environment.

##### Tool element runtime substitution: Inline Ruby execution
Ceedling provides inline Ruby string expansion and a notation for populating
tool elements with dynamically gathered values within the build environment.

Specifically for tool configuration elements, Ceedling provides two types of
inline Ruby execution.
##### Tool element runtime substitution: Inline Ruby string expansion

1. `"#{...}"`: This notation is that of the beloved
[inline Ruby string expansion][inline-ruby-string-expansion] available in
a variety of configuration file sections. This string expansion occurs once
at startup.

1. `{...}`: This notation causes inline Ruby execution similarly to the
preceding except that the substitution occurs each time the tool is executed.

Why might you need this? Say you have a collection of paths on disk and some
of those paths include spaces. Further suppose that a single tool that must
use those paths requires those spaces to be escaped, but all other uses of
those paths requires the paths to remain unchanged. You could use this
Ceedling feature to insert Ruby code that iterates those paths and escapes
those spaces in the array as used by the tool of this example.
`"#{...}"`: This notation is that of the beloved
[inline Ruby string expansion][inline-ruby-string-expansion] available in a
variety of configuration file sections. This string expansion occurs each
time a tool configuration is executed during a build.

##### Tool element runtime substitution: Notational substitution

Expand Down Expand Up @@ -4636,38 +4631,75 @@ Notes on test fixture tooling example:
1. We’re using `$stderr` redirection to allow us to capture simulator error
messages to `$stdout` for display at the run's conclusion.

### Ceedling tool arguments addition shortcut
### Ceedling tool modification shortcuts

Sometimes Ceedling’s default tool defininitions are _this close_ to being just
what you need. But, darn, you need one extra argument on the command line, and
you'd love to not override an entire tool definition to tweak it.
what you need. But, darn, you need one extra argument on the command line, or
you just need to hack the tool executable. You’d love to get away without
overriding an entire tool definition just in order to tweak it.

We got you.

#### Ceedling tool executable replacement

Sometimes you need to do some sneaky stuff. We get it. This feature lets you
replace the executable of a tool definition — including an internal default —
with your own.

To use this shortcut, simply add a configuration section to your project file at
the top-level, `:tools_<tool_to_modify>` ↳ `:executable`. Of course, you can
combine this with the following modification option in a single block for the
tool. Executable replacement can make use of
[inline Ruby string expansion][inline-ruby-string-expansion].

See the list of tool names at the beginning of the `:tools` documentation to
identify the named options. Plugins can also include their own tool definitions
that can be modified with this same option.

This example YAML...

```yaml
:tools_test_compiler:
:executable: foo
```

... will produce the following:

```shell
> foo <Ceedling default command line>
```

#### Ceedling tool arguments addition shortcut

Now, this little feature only allows you to add arguments to the end of a tool
command line. Not the beginning. And, you can’t remove arguments with this
option.

We got you. Now, this little feature only allows you to add arguments to the
end of a tool command line. Not the beginning. And, you can’t remove arguments
with this hack.
Further, this little feature is a blanket application across all uses of a tool.
If you need fine-grained control of command line flags in build steps per test
executable, please see the [`:flags` configuration documentation][flags].

Further, this little feature is a blanket application across all uses of a
tool. If you need fine-grained control of command line flags in build steps per
test executable, please see the [`:flags` configuration documentation][flags].
To use this shortcut, simply add a configuration section to your project file at
the top-level, `:tools_<tool_to_modify>` ↳ `:arguments`. Of course, you can
combine this with the preceding modification option in a single block for the
tool.

To use this shortcut, simply add a configuration section to your project file
at the top-level, `:tools_<tool_to_modify>` ↳ `:arguments`. See the list of
tool names at the beginning of the `:tools` documentation to identify the named
options. Plugins can also include their own tool definitions that can be
modified with this same hack.
See the list of tool names at the beginning of the `:tools` documentation to
identify the named options. Plugins can also include their own tool definitions
that can be modified with this same hack.

This example YAML:
This example YAML...

```yaml
:tools_test_compiler:
:arguments:
- --flag # Add `--flag` to the end of all test C file compilation
- --flag # Add `--flag` to the end of all test C file compilation
```

...will produce this command line:
... will produce the following (for the default executable):

```shell
> gcc <default command line> --flag
> gcc <Ceedling default command line> --flag
```

## `:plugins` Ceedling extensions
Expand Down
29 changes: 27 additions & 2 deletions docs/Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ This changelog is complemented by two other documents:

---

# [1.0.0 pre-release] — 2024-08-12
# [1.0.0 pre-release] — 2024-08-27

## 🌟 Added

Expand Down Expand Up @@ -145,7 +145,19 @@ The application commands `ceedling new` and `ceedling upgrade` at the command li

If the information is unavailable such as in local development, the SHA is omitted.

This source for this string is intended to be generated and captured in the Gem at the time of an automated build in CI.
This source for this string is generated and captured in the Gem at the time of Ceedling’s automated build in CI.

### Tool definition modification shortcuts expanded for `:executable`

A shortcut for adding arguments to an existing tool defition already existed. The handling for this shortcut has been expanded to allow `:executable` to be redefined.

```yaml
:tools_test_compiler:
:executable: foo # Shell out for `foo` instead of `gcc`
:arguments: # Existing functionality
- --flag1 # Add the following at the end of existing list of command line arguments
- --flag2
```
## 💪 Fixed
Expand Down Expand Up @@ -317,6 +329,12 @@ In previous versions of Ceedling, the Command Hooks plugin associated tools and

Hooks are now enabled within a top-level `:command_hooks` section in your project configuration. Each hook key in this configuration block can now support one or more tools organized beneath it. As such, each hook can execute one or more tools.

### Tool definition inline Ruby string expansion now happens at each execution

Reaching back to the earliest days of Ceedling, tool definitions supported two slightly different string replacement options that executed at different points in a build’s lifetime. Yeah. It was maybe not great. This has been simplfied.

Only support for `#{...}` Ruby string expansion in tool definitions remains. Any such expansions are now evaluated each time a tool is executed during a build.

## 👋 Removed

### `verbosity` and `log` command line tasks have been replaced with command line switches
Expand Down Expand Up @@ -396,3 +414,10 @@ The Gcov plugin’s `:abort_on_uncovered` option plus the related `:uncovered_ig
### Undocumented environment variable `CEEDLING_USER_PROJECT_FILE` support removed

A previously undocumented feature for merging a second configuration via environment variable `CEEDLING_USER_PROJECT_FILE` has been removed. This feature has been superseded by the new Mixins functionality.

### Tool definition inline Ruby evaluation replacement removed (inline Ruby string expansion remains)

Reaching back to the earliest days of Ceedling, tool definitions supported two slightly different string replacement options that executed at different points in a build’s lifetime. Yeah. It was maybe not great.

Support for `{...}` Ruby evaluation in tool definitions has been removed. Support for `#{...}` Ruby string expansion in tool definitions remains.

65 changes: 43 additions & 22 deletions lib/ceedling/configurator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,6 @@ def get_cmock_config
# Process our tools
# - :tools entries
# - Insert missing names for
# - Handle inline Ruby string substitution
# - Handle needed defaults
# - Configure test runner from backtrace configuration
def populate_tools_config(config)
Expand All @@ -323,11 +322,6 @@ def populate_tools_config(config)
# Populate name if not given
tool[:name] = name.to_s if (tool[:name].nil?)

# Handle inline Ruby string substitution in executable
if (tool[:executable] =~ RUBY_STRING_REPLACEMENT_PATTERN)
tool[:executable].replace(@system_wrapper.module_eval(tool[:executable]))
end

# Populate $stderr redirect option
tool[:stderr_redirect] = StdErrRedirect::NONE if (tool[:stderr_redirect].nil?)

Expand All @@ -337,29 +331,56 @@ def populate_tools_config(config)
end


# Smoosh in extra arguments specified at top-level of config.
# This is useful for tweaking arguments for tools (where argument order does not matter).
# Arguments are squirted in at *end* of list.
def populate_tools_supplemental_arguments(config)
msg = @reportinator.generate_progress( 'Processing tool definition supplemental arguments' )
# Process any tool definition shortcuts
# - Append extra arguments
# - Redefine executable
#
# :tools_<name>
# :arguments: [...]
# :executable: '...'
def populate_tools_shortcuts(config)
msg = @reportinator.generate_progress( 'Processing tool definition shortcuts' )
@loginator.log( msg, Verbosity::OBNOXIOUS )

prefix = 'tools_'
config[:tools].each do |key, tool|
name = key.to_s()

# Supplemental tool definition
supplemental = config[(prefix + name).to_sym]

if (not supplemental.nil?)
args_to_add = supplemental[:arguments]
config[:tools].each do |name, tool|
# Lookup shortcut tool definition (:tools_<name>)
shortcut = (prefix + name.to_s).to_sym

# Logging message to be built up
msg = ''

# Try to lookup the executable from user config
executable, _ = @config_walkinator.fetch_value(shortcut, :executable,
hash:config
)

# Try to lookup arguments from user config
args_to_add, _ = @config_walkinator.fetch_value(shortcut, :arguments,
hash:config,
default: []
)

# If either tool definition modification is happening, start building the logging message
if !args_to_add.empty? or !executable.nil?
msg += " > #{name}\n"
end

msg = " > #{name}: Arguments " + args_to_add.map{|arg| "\"#{arg}\""}.join( ', ' )
@loginator.log( msg, Verbosity::DEBUG )
# Log the executable and redefine the tool config
if !executable.nil?
msg += " executable: \"#{executable}\"\n"
tool[:executable] = executable
end

# Adding and flattening is not a good idea -- might over-flatten if array nesting in tool args
# Log the arguments and add to the tool config
if !args_to_add.empty?
msg += " arguments: " + args_to_add.map{|arg| "\"#{arg}\""}.join( ', ' ) + "\n"
puts(tool[:arguments])
tool[:arguments].concat( args_to_add )
end

# Log
@loginator.log( msg, Verbosity::DEBUG ) if !msg.empty?
end
end

Expand Down
1 change: 0 additions & 1 deletion lib/ceedling/constants.rb
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,6 @@ class StdErrRedirect
# Match presence of any glob pattern characters
GLOB_PATTERN = /[\*\?\{\}\[\]]/
RUBY_STRING_REPLACEMENT_PATTERN = /#\{.+\}/
RUBY_EVAL_REPLACEMENT_PATTERN = /^\{(.+)\}$/
TOOL_EXECUTOR_ARGUMENT_REPLACEMENT_PATTERN = /(\$\{(\d+)\})/
TEST_STDOUT_STATISTICS_PATTERN = /\n-+\s*(\d+)\s+Tests\s+(\d+)\s+Failures\s+(\d+)\s+Ignored\s+(OK|FAIL)\s*/i

Expand Down
Loading

0 comments on commit 66fbfa1

Please sign in to comment.