ci_exec¶
About¶
A wrapper package designed for running continuous integration (CI) build steps using Python 3.5+.
Managing cross platform build scripts for CI can become tedious at times when you need
to e.g., maintain two nearly identical scripts install_deps.sh
and
install_deps.bat
due to incompatible syntaxes. ci_exec
enables a single file
to manage this using Python.
The ci_exec
package provides a set of wrappers / utility functions designed
specifically for running build steps on CI providers. It is
- Logging by Default
Commands executed, including their full command-line arguments, are logged. This includes any output on
stdout
/stderr
from the commands. The logging resembles whatset -x
would give you in a shell script. For commands that will take a long time, as long as output is being produced, this will additionally prevent timeouts on the build.- Failing by Default
Any command that does not succeed will fail the entire build. An attempt to exit with the same exit code as the command that failed will be performed. Meaning the CI provider will correctly report a failed build.
- Convenient
ci_exec
affords users the ability to write shell-like scripts that will work on any platform that Python can run on. A simple example:from ci_exec import cd, which cmake = which("cmake") ninja = which("ninja") with cd("build", create=True): cmake("..", "-G", "Ninja", "-DCMAKE_BUILD_TYPE=Release") ninja("-j", "2", "test")
Intended Audience¶
Note
ci_exec
can be used for anything related to writing build steps, but it was
originally written to manage C++ projects. The documentation will often have
examples using cmake
and ninja
, users do not need to understand what these
commands are for.
ci_exec
utilizes some “advanced” features of Python that pertain to how the library
itself is consumed. It may not be appropriate for users who do not know any Python at
all. The main features a user should be aware of:
*args
and**kwargs
are used liberally.ci_exec
mostly consists of wrapper classes / functions around the python standard library, and in most cases*args
and**kwargs
are the “pass-through” parameters.Keyword-only arguments. Many library signatures look something like:
def foo(a: str, *, b: int = 2): pass foo("hi") # OK: b = 2 foo("hi", 3) # ERROR: b is keyword only foo("hi", b=3) # OK: b = 3
Anything after the
*,
must be named explicitly.Operator overloading, particularly what
__call__
means and how it works. A quick overview:from ci_exec import Executable # Typically: prefer ci_exec.which instead, which returns a ci_exec.Executable. cmake = Executable("/usr/bin/cmake") # cmake.__call__ invoked with args = [".."], kwargs = {} cmake("..") # cmake.__call__ invoked with args = [".."], kwargs = {"check": False} cmake("..", check=False)
None of these features are altogether that special, but it must be stated clearly and plainly: this library is designed for users who already know Python.
Put differently: if you don’t know why writing script-like Python is useful for CI, while still having access to a full-fledged programming language for when it gets (C++) hard, this package likely has no use for you.
Full Documentation¶
Quick reference:
Wrapper class for defining the escape character and clear sequence. |
|
The core ANSI color codes. |
|
A non-exhaustive list of ANSI style formats. |
|
|
Return |
|
Print a terminal width block with |
|
Represent a reusable executable. |
|
Write a failure message to |
|
Permissive wrapper around |
|
Permissive wrapper around |
|
Restrictive wrapper around |
|
Filter the contents of a file. |
|
Return the |
Check if code is executing on a continuous integration (CI) service. |
|
|
Context manager / decorator that can be used to change directories. |
|
Merge |
|
Context manager / decorator that can be used to set environment variables. |
|
Context manager / decorator that can be used to unset environment variables. |