mirror of
https://codeberg.org/andyscott/ziglings.git
synced 2024-12-22 14:03:10 -05:00
commit
2ed24ab3cf
27 changed files with 290 additions and 101 deletions
25
.github/workflows/ci.yml
vendored
Normal file
25
.github/workflows/ci.yml
vendored
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
name: CI
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches: [ main ]
|
||||||
|
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
compat:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
zig: [ 0.6.0, 0.7.0, 0.8.0, 0.9.0, 0.10.0 ]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Setup Zig
|
||||||
|
uses: goto-bus-stop/setup-zig@v2
|
||||||
|
with:
|
||||||
|
version: ${{ matrix.zig }}
|
||||||
|
|
||||||
|
- name: Check compatibility with old Zig compilers
|
||||||
|
run: ci/compat.sh
|
25
ci/compat.sh
Executable file
25
ci/compat.sh
Executable file
|
@ -0,0 +1,25 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# This script checks that `zig build` will return an useful error message when
|
||||||
|
# the Zig compiler is not compatible, instead of failing due to a syntax error.
|
||||||
|
#
|
||||||
|
# This script should be run on an UNIX system.
|
||||||
|
|
||||||
|
zig_version=$(zig version)
|
||||||
|
|
||||||
|
zig build -Dn=1 -Dhealed &> /dev/null 2>&1
|
||||||
|
zig_ret=$?
|
||||||
|
|
||||||
|
if [ "$zig_ret" -eq 0 ]; then
|
||||||
|
printf "zig %s unexpectedly succeeded\n" "$zig_version"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
zig_error=$(zig build -Dn=1 -Dhealed 2>&1)
|
||||||
|
|
||||||
|
echo "$zig_error" | grep -q "it looks like your version of zig is too old"
|
||||||
|
zig_ret=$?
|
||||||
|
|
||||||
|
if [ "$zig_ret" -ne 0 ]; then
|
||||||
|
printf "zig %s is not compatible\n" "$zig_version"
|
||||||
|
exit 1
|
||||||
|
fi
|
|
@ -107,7 +107,7 @@ const Path = struct {
|
||||||
const a_paths = [_]Path{
|
const a_paths = [_]Path{
|
||||||
Path{
|
Path{
|
||||||
.from = &a, // from: Archer's Point
|
.from = &a, // from: Archer's Point
|
||||||
.to = &b, // to: Bridge
|
.to = &b, // to: Bridge
|
||||||
.dist = 2,
|
.dist = 2,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -115,12 +115,12 @@ const a_paths = [_]Path{
|
||||||
const b_paths = [_]Path{
|
const b_paths = [_]Path{
|
||||||
Path{
|
Path{
|
||||||
.from = &b, // from: Bridge
|
.from = &b, // from: Bridge
|
||||||
.to = &a, // to: Archer's Point
|
.to = &a, // to: Archer's Point
|
||||||
.dist = 2,
|
.dist = 2,
|
||||||
},
|
},
|
||||||
Path{
|
Path{
|
||||||
.from = &b, // from: Bridge
|
.from = &b, // from: Bridge
|
||||||
.to = &d, // to: Dogwood Grove
|
.to = &d, // to: Dogwood Grove
|
||||||
.dist = 1,
|
.dist = 1,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -128,12 +128,12 @@ const b_paths = [_]Path{
|
||||||
const c_paths = [_]Path{
|
const c_paths = [_]Path{
|
||||||
Path{
|
Path{
|
||||||
.from = &c, // from: Cottage
|
.from = &c, // from: Cottage
|
||||||
.to = &d, // to: Dogwood Grove
|
.to = &d, // to: Dogwood Grove
|
||||||
.dist = 3,
|
.dist = 3,
|
||||||
},
|
},
|
||||||
Path{
|
Path{
|
||||||
.from = &c, // from: Cottage
|
.from = &c, // from: Cottage
|
||||||
.to = &e, // to: East Pond
|
.to = &e, // to: East Pond
|
||||||
.dist = 2,
|
.dist = 2,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -141,17 +141,17 @@ const c_paths = [_]Path{
|
||||||
const d_paths = [_]Path{
|
const d_paths = [_]Path{
|
||||||
Path{
|
Path{
|
||||||
.from = &d, // from: Dogwood Grove
|
.from = &d, // from: Dogwood Grove
|
||||||
.to = &b, // to: Bridge
|
.to = &b, // to: Bridge
|
||||||
.dist = 1,
|
.dist = 1,
|
||||||
},
|
},
|
||||||
Path{
|
Path{
|
||||||
.from = &d, // from: Dogwood Grove
|
.from = &d, // from: Dogwood Grove
|
||||||
.to = &c, // to: Cottage
|
.to = &c, // to: Cottage
|
||||||
.dist = 3,
|
.dist = 3,
|
||||||
},
|
},
|
||||||
Path{
|
Path{
|
||||||
.from = &d, // from: Dogwood Grove
|
.from = &d, // from: Dogwood Grove
|
||||||
.to = &f, // to: Fox Pond
|
.to = &f, // to: Fox Pond
|
||||||
.dist = 7,
|
.dist = 7,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -159,20 +159,20 @@ const d_paths = [_]Path{
|
||||||
const e_paths = [_]Path{
|
const e_paths = [_]Path{
|
||||||
Path{
|
Path{
|
||||||
.from = &e, // from: East Pond
|
.from = &e, // from: East Pond
|
||||||
.to = &c, // to: Cottage
|
.to = &c, // to: Cottage
|
||||||
.dist = 2,
|
.dist = 2,
|
||||||
},
|
},
|
||||||
Path{
|
Path{
|
||||||
.from = &e, // from: East Pond
|
.from = &e, // from: East Pond
|
||||||
.to = &f, // to: Fox Pond
|
.to = &f, // to: Fox Pond
|
||||||
.dist = 1, // (one-way down a short waterfall!)
|
.dist = 1, // (one-way down a short waterfall!)
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const f_paths = [_]Path{
|
const f_paths = [_]Path{
|
||||||
Path{
|
Path{
|
||||||
.from = &f, // from: Fox Pond
|
.from = &f, // from: Fox Pond
|
||||||
.to = &d, // to: Dogwood Grove
|
.to = &d, // to: Dogwood Grove
|
||||||
.dist = 7,
|
.dist = 7,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -355,8 +355,8 @@ pub fn main() void {
|
||||||
// Here's where the hermit decides where he would like to go. Once
|
// Here's where the hermit decides where he would like to go. Once
|
||||||
// you get the program working, try some different Places on the
|
// you get the program working, try some different Places on the
|
||||||
// map!
|
// map!
|
||||||
const start = &a; // Archer's Point
|
const start = &a; // Archer's Point
|
||||||
const destination = &f; // Fox Pond
|
const destination = &f; // Fox Pond
|
||||||
|
|
||||||
// Store each Path array as a slice in each Place. As mentioned
|
// Store each Path array as a slice in each Place. As mentioned
|
||||||
// above, we needed to delay making these references to avoid
|
// above, we needed to delay making these references to avoid
|
||||||
|
|
|
@ -18,10 +18,10 @@
|
||||||
const print = @import("std").debug.print;
|
const print = @import("std").debug.print;
|
||||||
|
|
||||||
pub fn main() void {
|
pub fn main() void {
|
||||||
var zig = [_]u8 {
|
var zig = [_]u8{
|
||||||
0o131, // octal
|
0o131, // octal
|
||||||
0b1101000, // binary
|
0b1101000, // binary
|
||||||
0x66, // hex
|
0x66, // hex
|
||||||
};
|
};
|
||||||
|
|
||||||
print("{s} is cool.\n", .{zig});
|
print("{s} is cool.\n", .{zig});
|
||||||
|
|
|
@ -16,7 +16,7 @@ const print = @import("std").debug.print;
|
||||||
pub fn main() void {
|
pub fn main() void {
|
||||||
// Here we declare arrays of three different types and sizes
|
// Here we declare arrays of three different types and sizes
|
||||||
// at compile time from a function call. Neat!
|
// at compile time from a function call. Neat!
|
||||||
const s1 = makeSequence(u8, 3); // creates a [3]u8
|
const s1 = makeSequence(u8, 3); // creates a [3]u8
|
||||||
const s2 = makeSequence(u32, 5); // creates a [5]u32
|
const s2 = makeSequence(u32, 5); // creates a [5]u32
|
||||||
const s3 = makeSequence(i64, 7); // creates a [7]i64
|
const s3 = makeSequence(i64, 7); // creates a [7]i64
|
||||||
|
|
||||||
|
|
|
@ -151,8 +151,8 @@ const HermitsNotebook = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn main() void {
|
pub fn main() void {
|
||||||
const start = &a; // Archer's Point
|
const start = &a; // Archer's Point
|
||||||
const destination = &f; // Fox Pond
|
const destination = &f; // Fox Pond
|
||||||
|
|
||||||
// We could either have this:
|
// We could either have this:
|
||||||
//
|
//
|
||||||
|
|
|
@ -18,8 +18,8 @@ pub fn main() void {
|
||||||
//
|
//
|
||||||
// Don't change this part:
|
// Don't change this part:
|
||||||
//
|
//
|
||||||
// = .{'h', 'e', 'l', 'l', 'o'};
|
// = .{ 'h', 'e', 'l', 'l', 'o' };
|
||||||
//
|
//
|
||||||
const hello = .{'h', 'e', 'l', 'l', 'o'};
|
const hello = .{ 'h', 'e', 'l', 'l', 'o' };
|
||||||
print("I say {s}!\n", .{hello});
|
print("I say {s}!\n", .{hello});
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,7 +99,7 @@ pub fn main() !void {
|
||||||
var my_insects = [_]Insect{
|
var my_insects = [_]Insect{
|
||||||
Insect{ .ant = Ant{ .still_alive = true } },
|
Insect{ .ant = Ant{ .still_alive = true } },
|
||||||
Insect{ .bee = Bee{ .flowers_visited = 17 } },
|
Insect{ .bee = Bee{ .flowers_visited = 17 } },
|
||||||
Insect{ .grasshopper = Grasshopper{ .distance_hopped = 32 }, },
|
Insect{ .grasshopper = Grasshopper{ .distance_hopped = 32 } },
|
||||||
};
|
};
|
||||||
|
|
||||||
std.debug.print("Daily Insect Report:\n", .{});
|
std.debug.print("Daily Insect Report:\n", .{});
|
||||||
|
|
|
@ -42,5 +42,8 @@ do
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# Check the healed exercises formatting.
|
||||||
|
zig fmt --check patches/healed
|
||||||
|
|
||||||
# Test the healed exercises. May the compiler have mercy upon us.
|
# Test the healed exercises. May the compiler have mercy upon us.
|
||||||
zig build -Dhealed
|
zig build -Dhealed
|
||||||
|
|
|
@ -5,6 +5,6 @@
|
||||||
> if (err == MyNumberError.TooSmall) {
|
> if (err == MyNumberError.TooSmall) {
|
||||||
> return 10;
|
> return 10;
|
||||||
> }
|
> }
|
||||||
>
|
>
|
||||||
> return err;
|
> return err;
|
||||||
> };
|
> };
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
22c22
|
26c26
|
||||||
< stdout.print("Hello world!\n", .{});
|
< stdout.print("Hello world!\n", .{});
|
||||||
---
|
---
|
||||||
> try stdout.print("Hello world!\n", .{});
|
> try stdout.print("Hello world!\n", .{});
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
35c34
|
35c35
|
||||||
< std.debug.print("failed!\n", .{});
|
< std.debug.print("failed!\n", .{});
|
||||||
---
|
---
|
||||||
> errdefer std.debug.print("failed!\n", .{});
|
> errdefer std.debug.print("failed!\n", .{});
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
24c24
|
26c26
|
||||||
< const b: *u8 = &a; // fix this!
|
< const b: *u8 = &a; // fix this!
|
||||||
---
|
---
|
||||||
> const b: *const u8 = &a; // fix this!
|
> const b: *const u8 = &a; // fix this!
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
24c12
|
24c24
|
||||||
< tail: *Elephant = null, // Hmm... tail needs something...
|
< tail: *Elephant = null, // Hmm... tail needs something...
|
||||||
---
|
---
|
||||||
> tail: ?*Elephant = null, // <---- make this optional!
|
> tail: ?*Elephant = null, // <---- make this optional!
|
||||||
54c42
|
54c54
|
||||||
< if (e.tail == null) ???;
|
< if (e.tail == null) ???;
|
||||||
---
|
---
|
||||||
> if (e.tail == null) break;
|
> if (e.tail == null) break;
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
< var first_line2: Err!*const [21]u8 = ???;
|
< var first_line2: Err!*const [21]u8 = ???;
|
||||||
---
|
---
|
||||||
> var first_line2: Err!*const [21]u8 = Err.Cthulhu;
|
> var first_line2: Err!*const [21]u8 = Err.Cthulhu;
|
||||||
79,80c79,80
|
80,81c80,81
|
||||||
< fn printSecondLine() ??? {
|
< fn printSecondLine() ??? {
|
||||||
< var second_line2: ?*const [18]u8 = ???;
|
< var second_line2: ?*const [18]u8 = ???;
|
||||||
---
|
---
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
22,24c22,24
|
22,24c22,24
|
||||||
< 0o131, // octal
|
< 0o131, // octal
|
||||||
< 0b1101000, // binary
|
< 0b1101000, // binary
|
||||||
< 0x66, // hex
|
< 0x66, // hex
|
||||||
---
|
---
|
||||||
> 0o132, // octal
|
> 0o132, // octal
|
||||||
> 0b1101001, // binary
|
> 0b1101001, // binary
|
||||||
> 0x67, // hex
|
> 0x67, // hex
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
72c72
|
67c67
|
||||||
< const expected_result: u8 = ???;
|
< const expected_result: u8 = ???;
|
||||||
---
|
---
|
||||||
> const expected_result: u8 = 0b00010010;
|
> const expected_result: u8 = 0b00010010;
|
||||||
88c88
|
82c82
|
||||||
< const tupni: u8 = @bitReverse(input, tupni);
|
< const tupni: u8 = @bitReverse(input, tupni);
|
||||||
---
|
---
|
||||||
> const tupni: u8 = @bitReverse(input);
|
> const tupni: u8 = @bitReverse(input);
|
||||||
|
|
|
@ -1,39 +1,20 @@
|
||||||
--- exercises/065_builtins2.zig
|
61c61
|
||||||
+++ answers/065_builtins2.zig
|
< narcissus.??? = ???;
|
||||||
@@ -58,7 +58,7 @@
|
---
|
||||||
// Oops! We cannot leave the 'me' and 'myself' fields
|
> narcissus.myself = &narcissus;
|
||||||
// undefined. Please set them here:
|
73c73
|
||||||
narcissus.me = &narcissus;
|
< const Type2 = narcissus.fetchTheMostBeautifulType();
|
||||||
- narcissus.??? = ???;
|
---
|
||||||
+ narcissus.myself = &narcissus;
|
> const Type2 = Narcissus.fetchTheMostBeautifulType();
|
||||||
|
112c112
|
||||||
// This determines a "peer type" from three separate
|
< if (fields[0].??? != void) {
|
||||||
// references (they just happen to all be the same object).
|
---
|
||||||
@@ -70,7 +70,7 @@
|
> if (fields[0].type != void) {
|
||||||
//
|
116c116
|
||||||
// The fix for this is very subtle, but it makes a big
|
< if (fields[1].??? != void) {
|
||||||
// difference!
|
---
|
||||||
- const Type2 = narcissus.fetchTheMostBeautifulType();
|
> if (fields[1].type != void) {
|
||||||
+ const Type2 = Narcissus.fetchTheMostBeautifulType();
|
120c120
|
||||||
|
< if (fields[2].??? != void) {
|
||||||
// Now we print a pithy statement about Narcissus.
|
---
|
||||||
print("A {s} loves all {s}es. ", .{
|
> if (fields[2].type != void) {
|
||||||
@@ -109,15 +109,15 @@
|
|
||||||
// Please complete these 'if' statements so that the field
|
|
||||||
// name will not be printed if the field is of type 'void'
|
|
||||||
// (which is a zero-bit type that takes up no space at all!):
|
|
||||||
- if (fields[0].??? != void) {
|
|
||||||
+ if (fields[0].type != void) {
|
|
||||||
print(" {s}", .{@typeInfo(Narcissus).Struct.fields[0].name});
|
|
||||||
}
|
|
||||||
|
|
||||||
- if (fields[1].??? != void) {
|
|
||||||
+ if (fields[1].type != void) {
|
|
||||||
print(" {s}", .{@typeInfo(Narcissus).Struct.fields[1].name});
|
|
||||||
}
|
|
||||||
|
|
||||||
- if (fields[2].??? != void) {
|
|
||||||
+ if (fields[2].type != void) {
|
|
||||||
print(" {s}", .{@typeInfo(Narcissus).Struct.fields[2].name});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
64,65c64,65
|
65,66c65,66
|
||||||
< var var_int = 12345;
|
< var var_int = 12345;
|
||||||
< var var_float = 987.654;
|
< var var_float = 987.654;
|
||||||
---
|
---
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
85c84
|
85c85
|
||||||
< for (???) |s| {
|
< for (???) |s| {
|
||||||
---
|
---
|
||||||
> for (my_seq) |s| {
|
> for (my_seq) |s| {
|
||||||
97c96
|
97c97
|
||||||
< while (??? != my_sentinel) {
|
< while (??? != my_sentinel) {
|
||||||
---
|
---
|
||||||
> while (my_seq[i] != my_sentinel) {
|
> while (my_seq[i] != my_sentinel) {
|
||||||
|
|
|
@ -1,18 +1,8 @@
|
||||||
--- exercises/080_anonymous_structs.zig
|
51c51
|
||||||
+++ answers/080_anonymous_structs.zig
|
< var circle1 = ??? {
|
||||||
@@ -48,13 +48,13 @@
|
---
|
||||||
// * circle1 should hold i32 integers
|
> var circle1 = Circle(i32){
|
||||||
// * circle2 should hold f32 floats
|
57c57
|
||||||
//
|
< var circle2 = ??? {
|
||||||
- var circle1 = ??? {
|
---
|
||||||
+ var circle1 = Circle(i32){
|
> var circle2 = Circle(f32){
|
||||||
.center_x = 25,
|
|
||||||
.center_y = 70,
|
|
||||||
.radius = 15,
|
|
||||||
};
|
|
||||||
|
|
||||||
- var circle2 = ??? {
|
|
||||||
+ var circle2 = Circle(f32){
|
|
||||||
.center_x = 25.234,
|
|
||||||
.center_y = 70.999,
|
|
||||||
.radius = 15.714,
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
23c23
|
23c23
|
||||||
< const hello = .{'h', 'e', 'l', 'l', 'o'};
|
< const hello = .{ 'h', 'e', 'l', 'l', 'o' };
|
||||||
---
|
---
|
||||||
> const hello: [5]u8 = .{'h', 'e', 'l', 'l', 'o'};
|
> const hello: [5]u8 = .{ 'h', 'e', 'l', 'l', 'o' };
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
65c65
|
66c66
|
||||||
< var avg: []f64 = ???;
|
< var avg: []f64 = ???;
|
||||||
---
|
---
|
||||||
> var avg: []f64 = try allocator.alloc(f64, arr.len);
|
> var avg: []f64 = try allocator.alloc(f64, arr.len);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
82c82
|
83c83
|
||||||
< ???;
|
< ???;
|
||||||
---
|
---
|
||||||
> x ^= y;
|
> x ^= y;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
62c62
|
63c63
|
||||||
< return bits == 0x..???;
|
< return bits == 0x..???;
|
||||||
---
|
---
|
||||||
> return bits == 0x3ffffff;
|
> return bits == 0x3ffffff;
|
||||||
|
|
97
tools/check-exercises.py
Executable file
97
tools/check-exercises.py
Executable file
|
@ -0,0 +1,97 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import difflib
|
||||||
|
import io
|
||||||
|
import os
|
||||||
|
import os.path
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
IGNORE = subprocess.DEVNULL
|
||||||
|
PIPE = subprocess.PIPE
|
||||||
|
|
||||||
|
EXERCISES_PATH = "exercises"
|
||||||
|
HEALED_PATH = "patches/healed"
|
||||||
|
PATCHES_PATH = "patches/patches"
|
||||||
|
|
||||||
|
|
||||||
|
# Heals all the exercises.
|
||||||
|
def heal():
|
||||||
|
maketree(HEALED_PATH)
|
||||||
|
|
||||||
|
with os.scandir(EXERCISES_PATH) as it:
|
||||||
|
for entry in it:
|
||||||
|
name = entry.name
|
||||||
|
|
||||||
|
original_path = entry.path
|
||||||
|
patch_path = os.path.join(PATCHES_PATH, patch_name(name))
|
||||||
|
output_path = os.path.join(HEALED_PATH, name)
|
||||||
|
|
||||||
|
patch(original_path, patch_path, output_path)
|
||||||
|
|
||||||
|
|
||||||
|
# Yields all the healed exercises that are not correctly formatted.
|
||||||
|
def check_healed():
|
||||||
|
term = subprocess.run(
|
||||||
|
["zig", "fmt", "--check", HEALED_PATH], stdout=PIPE, text=True
|
||||||
|
)
|
||||||
|
if term.stdout == "" and term.returncode != 0:
|
||||||
|
term.check_returncode()
|
||||||
|
|
||||||
|
stream = io.StringIO(term.stdout)
|
||||||
|
for line in stream:
|
||||||
|
yield line.strip()
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
heal()
|
||||||
|
|
||||||
|
# Show the unified diff between the original example and the correctly
|
||||||
|
# formatted one.
|
||||||
|
for i, original in enumerate(check_healed()):
|
||||||
|
if i > 0:
|
||||||
|
print()
|
||||||
|
|
||||||
|
name = os.path.basename(original)
|
||||||
|
print(f"checking exercise {name}...\n")
|
||||||
|
|
||||||
|
from_file = open(original)
|
||||||
|
to_file = zig_fmt_file(original)
|
||||||
|
|
||||||
|
diff = difflib.unified_diff(
|
||||||
|
from_file.readlines(), to_file.readlines(), name, name + "-fmt"
|
||||||
|
)
|
||||||
|
sys.stderr.writelines(diff)
|
||||||
|
|
||||||
|
|
||||||
|
def maketree(path):
|
||||||
|
return os.makedirs(path, exist_ok=True)
|
||||||
|
|
||||||
|
|
||||||
|
# Returns path with the patch extension.
|
||||||
|
def patch_name(path):
|
||||||
|
name, _ = os.path.splitext(path)
|
||||||
|
|
||||||
|
return name + ".patch"
|
||||||
|
|
||||||
|
|
||||||
|
# Applies patch to original, and write the file to output.
|
||||||
|
def patch(original, patch, output):
|
||||||
|
subprocess.run(
|
||||||
|
["patch", "-i", patch, "-o", output, original], stdout=IGNORE, check=True
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Formats the Zig file at path, and returns the possibly reformatted file as a
|
||||||
|
# file object.
|
||||||
|
def zig_fmt_file(path):
|
||||||
|
with open(path) as stdin:
|
||||||
|
term = subprocess.run(
|
||||||
|
["zig", "fmt", "--stdin"], stdin=stdin, stdout=PIPE, check=True, text=True
|
||||||
|
)
|
||||||
|
|
||||||
|
return io.StringIO(term.stdout)
|
||||||
|
|
||||||
|
|
||||||
|
main()
|
68
tools/update-patches.py
Executable file
68
tools/update-patches.py
Executable file
|
@ -0,0 +1,68 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import os
|
||||||
|
import os.path
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
|
||||||
|
IGNORE = subprocess.DEVNULL
|
||||||
|
|
||||||
|
EXERCISES_PATH = "exercises"
|
||||||
|
ANSWERS_PATH = "answers"
|
||||||
|
PATCHES_PATH = "patches/patches"
|
||||||
|
|
||||||
|
|
||||||
|
# Heals all the exercises.
|
||||||
|
def heal():
|
||||||
|
maketree(ANSWERS_PATH)
|
||||||
|
|
||||||
|
with os.scandir(EXERCISES_PATH) as it:
|
||||||
|
for entry in it:
|
||||||
|
name = entry.name
|
||||||
|
|
||||||
|
original_path = entry.path
|
||||||
|
patch_path = os.path.join(PATCHES_PATH, patch_name(name))
|
||||||
|
output_path = os.path.join(ANSWERS_PATH, name)
|
||||||
|
|
||||||
|
patch(original_path, patch_path, output_path)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
heal()
|
||||||
|
|
||||||
|
with os.scandir(EXERCISES_PATH) as it:
|
||||||
|
for entry in it:
|
||||||
|
name = entry.name
|
||||||
|
|
||||||
|
broken_path = entry.path
|
||||||
|
healed_path = os.path.join(ANSWERS_PATH, name)
|
||||||
|
patch_path = os.path.join(PATCHES_PATH, patch_name(name))
|
||||||
|
|
||||||
|
with open(patch_path, "w") as file:
|
||||||
|
term = subprocess.run(
|
||||||
|
["diff", broken_path, healed_path],
|
||||||
|
stdout=file,
|
||||||
|
text=True,
|
||||||
|
)
|
||||||
|
assert term.returncode == 1
|
||||||
|
|
||||||
|
|
||||||
|
def maketree(path):
|
||||||
|
return os.makedirs(path, exist_ok=True)
|
||||||
|
|
||||||
|
|
||||||
|
# Returns path with the patch extension.
|
||||||
|
def patch_name(path):
|
||||||
|
name, _ = os.path.splitext(path)
|
||||||
|
|
||||||
|
return name + ".patch"
|
||||||
|
|
||||||
|
|
||||||
|
# Applies patch to original, and write the file to output.
|
||||||
|
def patch(original, patch, output):
|
||||||
|
subprocess.run(
|
||||||
|
["patch", "-i", patch, "-o", output, original], stdout=IGNORE, check=True
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
main()
|
Loading…
Reference in a new issue