Skip to main content

A python variant of the redo build system, with which You Can (Not) Redo.

Project description

dp-redo

A python variant of the redo build system, with which You Can (Not) Redo.

Example

Let's say we have a build process where we read test.c and generate test.o:

import os, sys
source_tree = os.path.dirname(os.path.abspath(sys.argv[0]))

def test():
    source = os.path.join(source_tree, "test.c")

    # The simplest compiler 😁
    os.system("cat {} > {}".format(source, "test.o"))

if __name__ == "__main__":
    test()

test will be run every time no matter whether test.c gets an update or not, which wastes much time. Now let's add some magic:

from dp_redo import *
import os, sys

source_tree = os.path.dirname(os.path.abspath(sys.argv[0]))

@do("test.o")
def test(target_name, target_base_name, output_path):
    redo_ifchange("test.c")
    source = os.path.join(source_tree, "test.c")
    os.system("cat {} > {}".format(source, output_path))

if __name__ == "__main__":
    redo_ifchange(test)

If you run it multiple times:

PS C:\Users\lishengq\source\repos\dp-redo\build> python ..\test2.py
Redoing target: test
PS C:\Users\lishengq\source\repos\dp-redo\build> python ..\test2.py
Skipping target test: it's up to date.

Fantastic, isn't it? If you changed test.c, modified the test method itself, or deleted test.o, test will be executed again:

PS C:\Users\lishengq\source\repos\dp-redo\build> python ..\test2.py
Redoing target: test. Reason: It's python code has changed
PS C:\Users\lishengq\source\repos\dp-redo\build> python ..\test2.py
Redoing target: test. Reason: The target file doesn't exist
PS C:\Users\lishengq\source\repos\dp-redo\build> python ..\test2.py
Redoing target: test. Reason: test.c has been modified
PS C:\Users\lishengq\source\repos\dp-redo\build> 

A target method can also depend on another method, which is rather simple:

from dp_redo import *
import os, sys

source_tree = os.path.dirname(os.path.abspath(sys.argv[0]))

@do("test2.o")
def test2(target_name, target_base_name, output_path):
    os.system("echo test2 > " + output_path)

@do("test.o")
def test(target_name, target_base_name, output_path):
    redo_ifchange(test2, "test.c")
    source = os.path.join(source_tree, "test.c")
    os.system("cat {} > {}".format(source, output_path))

if __name__ == "__main__":
    redo_ifchange(test)

What makes redo more interesting is that, you can call redo_ifchange to add dependencies at any time, even after your compilation:

from dp_redo import *
import os, sys, re

source_tree = os.path.dirname(os.path.abspath(sys.argv[0]))

@do("test2.o")
def test2(target_name, target_base_name, output_path):
    print("In test2")
    os.system("echo test2 > " + output_path)

@do("test.o")
def test(target_name, target_base_name, output_path):
    redo_ifchange(test2)
    source = os.path.join(source_tree, "test.c")
    os.system("gcc -M -MF test.c.dep -o {} {}".format(output_path, source))

    # Dependent headers given by gcc
    deps = open('test.c.dep', 'r').read().split(": ")[1].strip().split("\\\n")
    redo_ifchange(*deps)

if __name__ == "__main__":
    redo_ifchange(test)

Now when any headers are changed, the build process will be run again.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dp-redo-3.0.2.tar.gz (4.4 kB view hashes)

Uploaded source

Built Distribution

dp_redo-3.0.2-py3-none-any.whl (5.9 kB view hashes)

Uploaded py3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page