File: apply_extension_patches.py

package info (click to toggle)
duckdb 1.5.1-3
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 299,196 kB
  • sloc: cpp: 865,414; ansic: 57,292; python: 18,871; sql: 12,663; lisp: 11,751; yacc: 7,412; lex: 1,682; sh: 747; makefile: 564
file content (100 lines) | stat: -rw-r--r-- 3,332 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#!/usr/bin/env python3
import sys
import glob
import subprocess
import os
import tempfile

# Get the directory and construct the patch file pattern
directory = sys.argv[1]
patch_pattern = f"{directory}*.patch"

# Find patch files matching the pattern
patches = glob.glob(patch_pattern)


def raise_error(error_msg):
    sys.stderr.write(error_msg + '\n')
    sys.exit(1)


patches = sorted(os.listdir(directory))
for patch in patches:
    if not patch.endswith('.patch'):
        raise_error(
            f'Patch file {patch} found in directory {directory} does not end in ".patch" - rename the patch file'
        )


# Exit if no patches are found
if not patches:
    error_message = (
        f"\nERROR: Extension patching enabled, but no patches found in '{directory}'. "
        "Please make sure APPLY_PATCHES is only enabled when there are actually patches present. "
        "See .github/patches/extensions/README.md for more details."
    )
    raise_error(error_message)


current_dir = os.getcwd()
print(f"Applying patches at '{current_dir}'")
print(f"Resetting patches in {directory}\n")

# capture the current diff
diff_proc = subprocess.run(["git", "diff"], capture_output=True, check=True)
prev_diff = diff_proc.stdout

output_proc = subprocess.run(["git", "diff", "--numstat"], capture_output=True, check=True)
prev_output_lines = output_proc.stdout.decode('utf8').split('\n')
prev_output_lines.sort()

subprocess.run(["git", "clean", "-f"], check=True)
subprocess.run(["git", "reset", "--hard", "HEAD"], check=True)


def apply_patch(patch_file):
    ARGUMENTS = ["patch", "-p1", "--forward", "-i"]
    arguments = []
    arguments.extend(ARGUMENTS)
    arguments.append(patch_file)
    try:
        subprocess.run(arguments, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    except subprocess.CalledProcessError as e:
        arguments[1:1] = ['-d', current_dir]
        command = " ".join(arguments)
        print(f"Failed to apply patch, command to reproduce locally:\n{command}")
        print("\nError output:")
        print(e.stderr.decode('utf-8'))
        print("\nStandard output:")
        print(e.stdout.decode('utf-8'))
        print("Exiting")
        exit(1)


# Apply each patch file using patch
for patch in patches:
    print(f"Applying patch: {patch}\n")
    apply_patch(os.path.join(directory, patch))

# all patches have applied - check the current diff
output_proc = subprocess.run(["git", "diff", "--numstat"], capture_output=True, check=True)
output_lines = output_proc.stdout.decode('utf8').split('\n')
output_lines.sort()

if len(output_lines) <= len(prev_output_lines) and prev_output_lines != output_lines:
    print("Detected local changes - rolling back patch application")

    subprocess.run(["git", "clean", "-f"], check=True)
    subprocess.run(["git", "reset", "--hard", "HEAD"], check=True)
    with tempfile.NamedTemporaryFile() as f:
        f.write(prev_diff)
        f.flush()
        apply_patch(f.name)

    print("--------------------------------------------------")
    print("Generate a patch file using the following command:")
    print("--------------------------------------------------")
    print(f"(cd {os.getcwd()} && git diff > {os.path.join(directory, 'fix.patch')})")
    print("--------------------------------------------------")

    exit(1)