diff options
l--------- | .direnv/flake-profile | 1 | ||||
-rw-r--r-- | .direnv/flake-profile.rc | 1515 | ||||
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Cargo.lock | 61 | ||||
-rw-r--r-- | Cargo.toml | 10 | ||||
-rw-r--r-- | flake.lock | 91 | ||||
-rw-r--r-- | flake.nix | 54 | ||||
-rw-r--r-- | src/app.rs | 447 | ||||
-rw-r--r-- | src/consts.rs | 6 | ||||
-rw-r--r-- | src/main.rs | 10 | ||||
-rw-r--r-- | src/undo.rs | 133 |
11 files changed, 2329 insertions, 0 deletions
diff --git a/.direnv/flake-profile b/.direnv/flake-profile new file mode 120000 index 0000000..b4c9021 --- /dev/null +++ b/.direnv/flake-profile | |||
@@ -0,0 +1 @@ | |||
/nix/store/9jfvhch5cimq3cp7jkch719r68jjhpld-nix-shell-env \ No newline at end of file | |||
diff --git a/.direnv/flake-profile.rc b/.direnv/flake-profile.rc new file mode 100644 index 0000000..98ce9c2 --- /dev/null +++ b/.direnv/flake-profile.rc | |||
@@ -0,0 +1,1515 @@ | |||
1 | unset shellHook | ||
2 | nix_saved_PATH="$PATH" | ||
3 | AR=ar | ||
4 | export AR | ||
5 | AS=as | ||
6 | export AS | ||
7 | BASH=/nix/store/f7jzmxq9bpbxsg69cszx56mw14n115n5-bash-4.4-p23/bin/bash | ||
8 | CC=gcc | ||
9 | export CC | ||
10 | CONFIG_SHELL=/nix/store/f7jzmxq9bpbxsg69cszx56mw14n115n5-bash-4.4-p23/bin/bash | ||
11 | export CONFIG_SHELL | ||
12 | CXX=g++ | ||
13 | export CXX | ||
14 | DIRSTACK=() | ||
15 | GROUPS=() | ||
16 | HOSTTYPE=x86_64 | ||
17 | HOST_PATH=/nix/store/w21pgi6691202iafl0cnr7hk6wvvdz3n-coreutils-8.32/bin:/nix/store/70qfzyc5hmvssj7d0dqkqhn827xwgmy3-findutils-4.7.0/bin:/nix/store/49gllxpk2f3dcyx4q8cgj0w39p10s209-diffutils-3.7/bin:/nix/store/n0516fv7vwjbl41nl4q58w9si80ab93i-gnused-4.8/bin:/nix/store/3mx947xcmsyk79izqc8ifv31qafp80pc-gnugrep-3.6/bin:/nix/store/xj242al7hq36baipvj2qdfwf7dljq31f-gawk-5.1.0/bin:/nix/store/39qygzkhcb9i684w3fhr2kkz5gmcyycd-gnutar-1.32/bin:/nix/store/bnpadh78k2qf3hshwapl5s51dj87yykp-gzip-1.10/bin:/nix/store/k514dbajcp0wb32rnglvc940gldj549h-bzip2-1.0.6.0.1-bin/bin:/nix/store/a2q8136fwwkvigxq3icyd70zllvw45lc-gnumake-4.3/bin:/nix/store/f7jzmxq9bpbxsg69cszx56mw14n115n5-bash-4.4-p23/bin:/nix/store/kh9l9zpjxsdnx6zi91pk3yich8ivwii4-patch-2.7.6/bin:/nix/store/bap20qjfwfzl49zz11prqdyfdmq7w8ca-xz-5.2.5-bin/bin | ||
18 | export HOST_PATH | ||
19 | IFS=$' \t\n' | ||
20 | IN_NIX_SHELL=impure | ||
21 | export IN_NIX_SHELL | ||
22 | LD=ld | ||
23 | export LD | ||
24 | MACHTYPE=x86_64-unknown-linux-gnu | ||
25 | NIX_BINTOOLS=/nix/store/jlyaypckqlapwqpck7jscs6qcdwg9bk3-binutils-wrapper-2.35.1 | ||
26 | export NIX_BINTOOLS | ||
27 | NIX_BINTOOLS_WRAPPER_TARGET_HOST_x86_64_unknown_linux_gnu=1 | ||
28 | export NIX_BINTOOLS_WRAPPER_TARGET_HOST_x86_64_unknown_linux_gnu | ||
29 | NIX_BUILD_CORES=8 | ||
30 | export NIX_BUILD_CORES | ||
31 | NIX_CC=/nix/store/ca37d3qrydh0wpw40kswsx30j8dyzxh2-gcc-wrapper-10.2.0 | ||
32 | export NIX_CC | ||
33 | NIX_CC_WRAPPER_TARGET_HOST_x86_64_unknown_linux_gnu=1 | ||
34 | export NIX_CC_WRAPPER_TARGET_HOST_x86_64_unknown_linux_gnu | ||
35 | NIX_CFLAGS_COMPILE=' -frandom-seed=9jfvhch5ci -isystem /nix/store/gkqv9ia81dmmjqcn46ih5yirbzjy7s9p-SDL2-2.0.14-dev/include -isystem /nix/store/5sphs39wg8gyy5pcrcml5pyj1wrn9jil-libGL-1.3.2-dev/include -isystem /nix/store/skwk7hmzwpjvhgjf1y633l01p114xc6n-libglvnd-1.3.2-dev/include -isystem /nix/store/3y6j0k82fdp3ifnq655yv1ad1ih7r70j-libX11-1.7.0-dev/include -isystem /nix/store/vjimy2jlifszmmms664373jdw0yiz4ln-xorgproto-2020.1/include -isystem /nix/store/6xg7mhwh2k7i27r44lx679diwd7ahq6d-libxcb-1.14-dev/include -isystem /nix/store/gkqv9ia81dmmjqcn46ih5yirbzjy7s9p-SDL2-2.0.14-dev/include -isystem /nix/store/5sphs39wg8gyy5pcrcml5pyj1wrn9jil-libGL-1.3.2-dev/include -isystem /nix/store/skwk7hmzwpjvhgjf1y633l01p114xc6n-libglvnd-1.3.2-dev/include -isystem /nix/store/3y6j0k82fdp3ifnq655yv1ad1ih7r70j-libX11-1.7.0-dev/include -isystem /nix/store/vjimy2jlifszmmms664373jdw0yiz4ln-xorgproto-2020.1/include -isystem /nix/store/6xg7mhwh2k7i27r44lx679diwd7ahq6d-libxcb-1.14-dev/include' | ||
36 | export NIX_CFLAGS_COMPILE | ||
37 | NIX_ENFORCE_NO_NATIVE=1 | ||
38 | export NIX_ENFORCE_NO_NATIVE | ||
39 | NIX_HARDENING_ENABLE='fortify stackprotector pic strictoverflow format relro bindnow' | ||
40 | export NIX_HARDENING_ENABLE | ||
41 | NIX_INDENT_MAKE=1 | ||
42 | export NIX_INDENT_MAKE | ||
43 | NIX_LDFLAGS='-rpath /home/np/code/rust/sdl-tests/outputs/out/lib64 -rpath /home/np/code/rust/sdl-tests/outputs/out/lib -L/nix/store/21qrj65fsf1glbnw07f6qnkavgi9rmzw-rust-1.50.0-nightly-2020-12-22-bb1fbbf84/lib -L/nix/store/q47zvd16rpppdz4ami7wrx8318fwjpfk-libGL-1.3.2/lib -L/nix/store/sv2xsv21136linyi477ijd00gmihlwbp-libglvnd-1.3.2/lib -L/nix/store/jmpwz53zajcld1xb8zslh8g8p19d8wzl-libxcb-1.14/lib -L/nix/store/80p7f1sw4szy7w1mhqxd268n6i1gmybs-libX11-1.7.0/lib -L/nix/store/k58g6biziz8vpk6zw5n9bym2c6wxjrpd-SDL2-2.0.14/lib -L/nix/store/21qrj65fsf1glbnw07f6qnkavgi9rmzw-rust-1.50.0-nightly-2020-12-22-bb1fbbf84/lib -L/nix/store/q47zvd16rpppdz4ami7wrx8318fwjpfk-libGL-1.3.2/lib -L/nix/store/sv2xsv21136linyi477ijd00gmihlwbp-libglvnd-1.3.2/lib -L/nix/store/jmpwz53zajcld1xb8zslh8g8p19d8wzl-libxcb-1.14/lib -L/nix/store/80p7f1sw4szy7w1mhqxd268n6i1gmybs-libX11-1.7.0/lib -L/nix/store/k58g6biziz8vpk6zw5n9bym2c6wxjrpd-SDL2-2.0.14/lib' | ||
44 | export NIX_LDFLAGS | ||
45 | NIX_LIB64_IN_SELF_RPATH=1 | ||
46 | NIX_NO_SELF_RPATH=1 | ||
47 | NIX_STORE=/nix/store | ||
48 | export NIX_STORE | ||
49 | NM=nm | ||
50 | export NM | ||
51 | OBJCOPY=objcopy | ||
52 | export OBJCOPY | ||
53 | OBJDUMP=objdump | ||
54 | export OBJDUMP | ||
55 | OPTERR=1 | ||
56 | OPTIND=1 | ||
57 | OSTYPE=linux-gnu | ||
58 | PATH=/nix/store/21qrj65fsf1glbnw07f6qnkavgi9rmzw-rust-1.50.0-nightly-2020-12-22-bb1fbbf84/bin:/nix/store/hpkjc41idlbwk82cnx0sw8mmkjjb5lvi-rust-analyzer-unstable-2021-03-01/bin:/nix/store/2h05zs2wbxv3zisz342k6acfm6awcnwl-cargo-1.49.0/bin:/nix/store/gkqv9ia81dmmjqcn46ih5yirbzjy7s9p-SDL2-2.0.14-dev/bin:/nix/store/zrh1cskgv6kc8bh7hzfii14h2nck33qv-patchelf-0.12/bin:/nix/store/ca37d3qrydh0wpw40kswsx30j8dyzxh2-gcc-wrapper-10.2.0/bin:/nix/store/sr0ci8f8pgby77fj4mpcl9bcgxji3676-gcc-10.2.0/bin:/nix/store/mbxi7rhg9pj2mfnzr7dk9cd46xdhnrf9-glibc-2.32-37-bin/bin:/nix/store/w21pgi6691202iafl0cnr7hk6wvvdz3n-coreutils-8.32/bin:/nix/store/jlyaypckqlapwqpck7jscs6qcdwg9bk3-binutils-wrapper-2.35.1/bin:/nix/store/cp1sa3xxvl71cypiinw2c62i5s33chlr-binutils-2.35.1/bin:/nix/store/mbxi7rhg9pj2mfnzr7dk9cd46xdhnrf9-glibc-2.32-37-bin/bin:/nix/store/w21pgi6691202iafl0cnr7hk6wvvdz3n-coreutils-8.32/bin:/nix/store/w21pgi6691202iafl0cnr7hk6wvvdz3n-coreutils-8.32/bin:/nix/store/70qfzyc5hmvssj7d0dqkqhn827xwgmy3-findutils-4.7.0/bin:/nix/store/49gllxpk2f3dcyx4q8cgj0w39p10s209-diffutils-3.7/bin:/nix/store/n0516fv7vwjbl41nl4q58w9si80ab93i-gnused-4.8/bin:/nix/store/3mx947xcmsyk79izqc8ifv31qafp80pc-gnugrep-3.6/bin:/nix/store/xj242al7hq36baipvj2qdfwf7dljq31f-gawk-5.1.0/bin:/nix/store/39qygzkhcb9i684w3fhr2kkz5gmcyycd-gnutar-1.32/bin:/nix/store/bnpadh78k2qf3hshwapl5s51dj87yykp-gzip-1.10/bin:/nix/store/k514dbajcp0wb32rnglvc940gldj549h-bzip2-1.0.6.0.1-bin/bin:/nix/store/a2q8136fwwkvigxq3icyd70zllvw45lc-gnumake-4.3/bin:/nix/store/f7jzmxq9bpbxsg69cszx56mw14n115n5-bash-4.4-p23/bin:/nix/store/kh9l9zpjxsdnx6zi91pk3yich8ivwii4-patch-2.7.6/bin:/nix/store/bap20qjfwfzl49zz11prqdyfdmq7w8ca-xz-5.2.5-bin/bin | ||
59 | export PATH | ||
60 | PIPESTATUS=([0]="0") | ||
61 | PS4='+ ' | ||
62 | RANLIB=ranlib | ||
63 | export RANLIB | ||
64 | READELF=readelf | ||
65 | export READELF | ||
66 | RUST_SRC_PATH=/nix/store/wfv522w143y3yxx8ap3fkpjk9cnh1w3a-rust-lib-src | ||
67 | export RUST_SRC_PATH | ||
68 | SDL2_PATH='/nix/store/gkqv9ia81dmmjqcn46ih5yirbzjy7s9p-SDL2-2.0.14-dev/include/SDL2 /nix/store/gkqv9ia81dmmjqcn46ih5yirbzjy7s9p-SDL2-2.0.14-dev/include/SDL2 /nix/store/gkqv9ia81dmmjqcn46ih5yirbzjy7s9p-SDL2-2.0.14-dev/include/SDL2' | ||
69 | export SDL2_PATH | ||
70 | SHELL=/nix/store/f7jzmxq9bpbxsg69cszx56mw14n115n5-bash-4.4-p23/bin/bash | ||
71 | export SHELL | ||
72 | SIZE=size | ||
73 | export SIZE | ||
74 | SOURCE_DATE_EPOCH=315532800 | ||
75 | export SOURCE_DATE_EPOCH | ||
76 | STRINGS=strings | ||
77 | export STRINGS | ||
78 | STRIP=strip | ||
79 | export STRIP | ||
80 | XDG_DATA_DIRS=/nix/store/21qrj65fsf1glbnw07f6qnkavgi9rmzw-rust-1.50.0-nightly-2020-12-22-bb1fbbf84/share:/nix/store/2h05zs2wbxv3zisz342k6acfm6awcnwl-cargo-1.49.0/share:/nix/store/gkqv9ia81dmmjqcn46ih5yirbzjy7s9p-SDL2-2.0.14-dev/share:/nix/store/vjimy2jlifszmmms664373jdw0yiz4ln-xorgproto-2020.1/share:/nix/store/80p7f1sw4szy7w1mhqxd268n6i1gmybs-libX11-1.7.0/share:/nix/store/zrh1cskgv6kc8bh7hzfii14h2nck33qv-patchelf-0.12/share | ||
81 | export XDG_DATA_DIRS | ||
82 | _=export | ||
83 | buildInputs= | ||
84 | export buildInputs | ||
85 | builder=/nix/store/f7jzmxq9bpbxsg69cszx56mw14n115n5-bash-4.4-p23/bin/bash | ||
86 | export builder | ||
87 | commonStripFlags=--enable-deterministic-archives | ||
88 | configureFlags= | ||
89 | export configureFlags | ||
90 | defaultBuildInputs= | ||
91 | defaultNativeBuildInputs='/nix/store/zrh1cskgv6kc8bh7hzfii14h2nck33qv-patchelf-0.12 /nix/store/mjjy30kxz775bhhi6j9phw81qh6dsbrf-move-docs.sh /nix/store/kxw6q8v6isaqjm702d71n2421cxamq68-make-symlinks-relative.sh /nix/store/cl3qd985p1yxyfkj96v0hqxiy3w69xq5-compress-man-pages.sh /nix/store/h54dzwd7rdh2jlcv91424csl6d0ccgjy-strip.sh /nix/store/bnj8d7mvbkg3vdb07yz74yhl3g107qq5-patch-shebangs.sh /nix/store/cickvswrvann041nqxb0rxilc46svw1n-prune-libtool-files.sh /nix/store/8zxndz5ag0p6s526c2xyllhk1nrn4c3i-audit-tmpdir.sh /nix/store/c8n9kcdddp9np665xz6ri61b383nxvz8-move-systemd-user-units.sh /nix/store/1i5y55x4b4m9qkx5dqbmr1r6bvrqbanw-multiple-outputs.sh /nix/store/kd4xwxjpjxi71jkm6ka0np72if9rm3y0-move-sbin.sh /nix/store/fyaryjvghbkpfnsyw97hb3lyb37s1pd6-move-lib64.sh /nix/store/ngg1cv31c8c7bcm2n8ww4g06nq7s4zhm-set-source-date-epoch-to-latest.sh /nix/store/pr6nzbscdpg94yvr151lrif2kg0csx7b-reproducible-builds.sh /nix/store/ca37d3qrydh0wpw40kswsx30j8dyzxh2-gcc-wrapper-10.2.0' | ||
92 | depsBuildBuild= | ||
93 | export depsBuildBuild | ||
94 | depsBuildBuildPropagated= | ||
95 | export depsBuildBuildPropagated | ||
96 | depsBuildTarget= | ||
97 | export depsBuildTarget | ||
98 | depsBuildTargetPropagated= | ||
99 | export depsBuildTargetPropagated | ||
100 | depsHostHost= | ||
101 | export depsHostHost | ||
102 | depsHostHostPropagated= | ||
103 | export depsHostHostPropagated | ||
104 | depsTargetTarget= | ||
105 | export depsTargetTarget | ||
106 | depsTargetTargetPropagated= | ||
107 | export depsTargetTargetPropagated | ||
108 | doCheck= | ||
109 | export doCheck | ||
110 | doInstallCheck= | ||
111 | export doInstallCheck | ||
112 | dontAddDisableDepTrack=1 | ||
113 | export dontAddDisableDepTrack | ||
114 | envBuildBuildHooks=([0]="addSDL2Path") | ||
115 | envBuildHostHooks=([0]="addSDL2Path") | ||
116 | envBuildTargetHooks=([0]="addSDL2Path") | ||
117 | envHostHostHooks=([0]="ccWrapper_addCVars" [1]="bintoolsWrapper_addLDVars") | ||
118 | envHostTargetHooks=([0]="ccWrapper_addCVars" [1]="bintoolsWrapper_addLDVars") | ||
119 | fixupOutputHooks=([0]="if [ -z \"\${dontPatchELF-}\" ]; then patchELF \"\$prefix\"; fi" [1]="_makeSymlinksRelative" [2]="if [ -z \"\${dontGzipMan-}\" ]; then compressManPages \"\$prefix\"; fi" [3]="_doStrip" [4]="patchShebangsAuto" [5]="_pruneLibtoolFiles" [6]="if [[ -z \"\${noAuditTmpdir-}\" && -e \"\$prefix\" ]]; then auditTmpdir \"\$prefix\"; fi" [7]="_moveSystemdUserUnits" [8]="_moveSbin" [9]="_moveLib64") | ||
120 | initialPath='/nix/store/w21pgi6691202iafl0cnr7hk6wvvdz3n-coreutils-8.32 /nix/store/70qfzyc5hmvssj7d0dqkqhn827xwgmy3-findutils-4.7.0 /nix/store/49gllxpk2f3dcyx4q8cgj0w39p10s209-diffutils-3.7 /nix/store/n0516fv7vwjbl41nl4q58w9si80ab93i-gnused-4.8 /nix/store/3mx947xcmsyk79izqc8ifv31qafp80pc-gnugrep-3.6 /nix/store/xj242al7hq36baipvj2qdfwf7dljq31f-gawk-5.1.0 /nix/store/39qygzkhcb9i684w3fhr2kkz5gmcyycd-gnutar-1.32 /nix/store/bnpadh78k2qf3hshwapl5s51dj87yykp-gzip-1.10 /nix/store/k514dbajcp0wb32rnglvc940gldj549h-bzip2-1.0.6.0.1-bin /nix/store/a2q8136fwwkvigxq3icyd70zllvw45lc-gnumake-4.3 /nix/store/f7jzmxq9bpbxsg69cszx56mw14n115n5-bash-4.4-p23 /nix/store/kh9l9zpjxsdnx6zi91pk3yich8ivwii4-patch-2.7.6 /nix/store/bap20qjfwfzl49zz11prqdyfdmq7w8ca-xz-5.2.5-bin' | ||
121 | name=nix-shell | ||
122 | export name | ||
123 | nativeBuildInputs='/nix/store/21qrj65fsf1glbnw07f6qnkavgi9rmzw-rust-1.50.0-nightly-2020-12-22-bb1fbbf84 /nix/store/nnw3pf7h3grbi82rvaw16b57w2px7wq5-rust-src-1.50.0-nightly-2020-12-22-bb1fbbf84 /nix/store/hpkjc41idlbwk82cnx0sw8mmkjjb5lvi-rust-analyzer-unstable-2021-03-01 /nix/store/2h05zs2wbxv3zisz342k6acfm6awcnwl-cargo-1.49.0 /nix/store/gkqv9ia81dmmjqcn46ih5yirbzjy7s9p-SDL2-2.0.14-dev' | ||
124 | export nativeBuildInputs | ||
125 | nobuildPhase=$'echo\necho "This derivation is not meant to be built, aborting";\necho\nexit 1\n' | ||
126 | export nobuildPhase | ||
127 | out=/home/np/code/rust/sdl-tests/outputs/out | ||
128 | export out | ||
129 | outputBin=out | ||
130 | outputDev=out | ||
131 | outputDevdoc=REMOVE | ||
132 | outputDevman=out | ||
133 | outputDoc=out | ||
134 | outputInclude=out | ||
135 | outputInfo=out | ||
136 | outputLib=out | ||
137 | outputMan=out | ||
138 | outputs=out | ||
139 | export outputs | ||
140 | patches= | ||
141 | export patches | ||
142 | phases=nobuildPhase | ||
143 | export phases | ||
144 | pkg=/nix/store/ca37d3qrydh0wpw40kswsx30j8dyzxh2-gcc-wrapper-10.2.0 | ||
145 | pkgsBuildHost=([0]="/nix/store/21qrj65fsf1glbnw07f6qnkavgi9rmzw-rust-1.50.0-nightly-2020-12-22-bb1fbbf84" [1]="/nix/store/nnw3pf7h3grbi82rvaw16b57w2px7wq5-rust-src-1.50.0-nightly-2020-12-22-bb1fbbf84" [2]="/nix/store/hpkjc41idlbwk82cnx0sw8mmkjjb5lvi-rust-analyzer-unstable-2021-03-01" [3]="/nix/store/2h05zs2wbxv3zisz342k6acfm6awcnwl-cargo-1.49.0" [4]="/nix/store/gkqv9ia81dmmjqcn46ih5yirbzjy7s9p-SDL2-2.0.14-dev" [5]="/nix/store/5sphs39wg8gyy5pcrcml5pyj1wrn9jil-libGL-1.3.2-dev" [6]="/nix/store/q47zvd16rpppdz4ami7wrx8318fwjpfk-libGL-1.3.2" [7]="/nix/store/sv2xsv21136linyi477ijd00gmihlwbp-libglvnd-1.3.2" [8]="/nix/store/skwk7hmzwpjvhgjf1y633l01p114xc6n-libglvnd-1.3.2-dev" [9]="/nix/store/3y6j0k82fdp3ifnq655yv1ad1ih7r70j-libX11-1.7.0-dev" [10]="/nix/store/vjimy2jlifszmmms664373jdw0yiz4ln-xorgproto-2020.1" [11]="/nix/store/6xg7mhwh2k7i27r44lx679diwd7ahq6d-libxcb-1.14-dev" [12]="/nix/store/jmpwz53zajcld1xb8zslh8g8p19d8wzl-libxcb-1.14" [13]="/nix/store/80p7f1sw4szy7w1mhqxd268n6i1gmybs-libX11-1.7.0" [14]="/nix/store/k58g6biziz8vpk6zw5n9bym2c6wxjrpd-SDL2-2.0.14" [15]="/nix/store/zrh1cskgv6kc8bh7hzfii14h2nck33qv-patchelf-0.12" [16]="/nix/store/mjjy30kxz775bhhi6j9phw81qh6dsbrf-move-docs.sh" [17]="/nix/store/kxw6q8v6isaqjm702d71n2421cxamq68-make-symlinks-relative.sh" [18]="/nix/store/cl3qd985p1yxyfkj96v0hqxiy3w69xq5-compress-man-pages.sh" [19]="/nix/store/h54dzwd7rdh2jlcv91424csl6d0ccgjy-strip.sh" [20]="/nix/store/bnj8d7mvbkg3vdb07yz74yhl3g107qq5-patch-shebangs.sh" [21]="/nix/store/cickvswrvann041nqxb0rxilc46svw1n-prune-libtool-files.sh" [22]="/nix/store/8zxndz5ag0p6s526c2xyllhk1nrn4c3i-audit-tmpdir.sh" [23]="/nix/store/c8n9kcdddp9np665xz6ri61b383nxvz8-move-systemd-user-units.sh" [24]="/nix/store/1i5y55x4b4m9qkx5dqbmr1r6bvrqbanw-multiple-outputs.sh" [25]="/nix/store/kd4xwxjpjxi71jkm6ka0np72if9rm3y0-move-sbin.sh" [26]="/nix/store/fyaryjvghbkpfnsyw97hb3lyb37s1pd6-move-lib64.sh" [27]="/nix/store/ngg1cv31c8c7bcm2n8ww4g06nq7s4zhm-set-source-date-epoch-to-latest.sh" [28]="/nix/store/pr6nzbscdpg94yvr151lrif2kg0csx7b-reproducible-builds.sh" [29]="/nix/store/ca37d3qrydh0wpw40kswsx30j8dyzxh2-gcc-wrapper-10.2.0" [30]="/nix/store/jlyaypckqlapwqpck7jscs6qcdwg9bk3-binutils-wrapper-2.35.1") | ||
146 | postFixupHooks=([0]="_multioutPropagateDev") | ||
147 | postUnpackHooks=([0]="_updateSourceDateEpochFromSourceRoot") | ||
148 | preConfigureHooks=([0]="_multioutConfig") | ||
149 | preFixupHooks=([0]="_moveToShare" [1]="_multioutDocs" [2]="_multioutDevs") | ||
150 | prefix=/home/np/code/rust/sdl-tests/outputs/out | ||
151 | propagatedBuildDepFiles=([0]="propagated-build-build-deps" [1]="propagated-native-build-inputs" [2]="propagated-build-target-deps") | ||
152 | propagatedBuildInputs= | ||
153 | export propagatedBuildInputs | ||
154 | propagatedHostDepFiles=([0]="propagated-host-host-deps" [1]="propagated-build-inputs") | ||
155 | propagatedNativeBuildInputs= | ||
156 | export propagatedNativeBuildInputs | ||
157 | propagatedTargetDepFiles=([0]="propagated-target-target-deps") | ||
158 | shell=/nix/store/f7jzmxq9bpbxsg69cszx56mw14n115n5-bash-4.4-p23/bin/bash | ||
159 | export shell | ||
160 | shellHook= | ||
161 | export shellHook | ||
162 | stdenv=/nix/store/6vjmwq0nxsqm4skc8mrwif0zgy2gmn6r-stdenv-linux | ||
163 | export stdenv | ||
164 | strictDeps= | ||
165 | export strictDeps | ||
166 | system=x86_64-linux | ||
167 | export system | ||
168 | unpackCmdHooks=([0]="_defaultUnpack") | ||
169 | PATH="$PATH:$nix_saved_PATH" | ||
170 | _activatePkgs () | ||
171 | { | ||
172 | local -i hostOffset targetOffset; | ||
173 | local pkg; | ||
174 | for hostOffset in "${allPlatOffsets[@]}"; | ||
175 | do | ||
176 | local pkgsVar="${pkgAccumVarVars[$hostOffset + 1]}"; | ||
177 | for targetOffset in "${allPlatOffsets[@]}"; | ||
178 | do | ||
179 | (( "$hostOffset" <= "$targetOffset" )) || continue; | ||
180 | local pkgsRef="${pkgsVar}[$targetOffset - $hostOffset]"; | ||
181 | local pkgsSlice="${!pkgsRef}[@]"; | ||
182 | for pkg in ${!pkgsSlice+"${!pkgsSlice}"}; | ||
183 | do | ||
184 | activatePackage "$pkg" "$hostOffset" "$targetOffset"; | ||
185 | done; | ||
186 | done; | ||
187 | done | ||
188 | } | ||
189 | _addRpathPrefix () | ||
190 | { | ||
191 | if [ "${NIX_NO_SELF_RPATH:-0}" != 1 ]; then | ||
192 | export NIX_LDFLAGS="-rpath $1/lib ${NIX_LDFLAGS-}"; | ||
193 | if [ -n "${NIX_LIB64_IN_SELF_RPATH:-}" ]; then | ||
194 | export NIX_LDFLAGS="-rpath $1/lib64 ${NIX_LDFLAGS-}"; | ||
195 | fi; | ||
196 | if [ -n "${NIX_LIB32_IN_SELF_RPATH:-}" ]; then | ||
197 | export NIX_LDFLAGS="-rpath $1/lib32 ${NIX_LDFLAGS-}"; | ||
198 | fi; | ||
199 | fi | ||
200 | } | ||
201 | _addToEnv () | ||
202 | { | ||
203 | local -i depHostOffset depTargetOffset; | ||
204 | local pkg; | ||
205 | for depHostOffset in "${allPlatOffsets[@]}"; | ||
206 | do | ||
207 | local hookVar="${pkgHookVarVars[$depHostOffset + 1]}"; | ||
208 | local pkgsVar="${pkgAccumVarVars[$depHostOffset + 1]}"; | ||
209 | for depTargetOffset in "${allPlatOffsets[@]}"; | ||
210 | do | ||
211 | (( "$depHostOffset" <= "$depTargetOffset" )) || continue; | ||
212 | local hookRef="${hookVar}[$depTargetOffset - $depHostOffset]"; | ||
213 | if [[ -z "${strictDeps-}" ]]; then | ||
214 | local visitedPkgs=""; | ||
215 | for pkg in ${pkgsBuildBuild+"${pkgsBuildBuild[@]}"} ${pkgsBuildHost+"${pkgsBuildHost[@]}"} ${pkgsBuildTarget+"${pkgsBuildTarget[@]}"} ${pkgsHostHost+"${pkgsHostHost[@]}"} ${pkgsHostTarget+"${pkgsHostTarget[@]}"} ${pkgsTargetTarget+"${pkgsTargetTarget[@]}"}; | ||
216 | do | ||
217 | if [[ "$visitedPkgs" = *"$pkg"* ]]; then | ||
218 | continue; | ||
219 | fi; | ||
220 | runHook "${!hookRef}" "$pkg"; | ||
221 | visitedPkgs+=" $pkg"; | ||
222 | done; | ||
223 | else | ||
224 | local pkgsRef="${pkgsVar}[$depTargetOffset - $depHostOffset]"; | ||
225 | local pkgsSlice="${!pkgsRef}[@]"; | ||
226 | for pkg in ${!pkgsSlice+"${!pkgsSlice}"}; | ||
227 | do | ||
228 | runHook "${!hookRef}" "$pkg"; | ||
229 | done; | ||
230 | fi; | ||
231 | done; | ||
232 | done | ||
233 | } | ||
234 | _allFlags () | ||
235 | { | ||
236 | for varName in $(awk 'BEGIN { for (v in ENVIRON) if (v ~ /^[a-z][a-zA-Z0-9_]*$/) print v }'); | ||
237 | do | ||
238 | if (( "${NIX_DEBUG:-0}" >= 1 )); then | ||
239 | printf "@%s@ -> %q\n" "${varName}" "${!varName}"; | ||
240 | fi; | ||
241 | args+=("--subst-var" "$varName"); | ||
242 | done | ||
243 | } | ||
244 | _assignFirst () | ||
245 | { | ||
246 | local varName="$1"; | ||
247 | local REMOVE=REMOVE; | ||
248 | shift; | ||
249 | while (( $# )); do | ||
250 | if [ -n "${!1-}" ]; then | ||
251 | eval "${varName}"="$1"; | ||
252 | return; | ||
253 | fi; | ||
254 | shift; | ||
255 | done; | ||
256 | echo "Error: _assignFirst found no valid variant!"; | ||
257 | return 1 | ||
258 | } | ||
259 | _callImplicitHook () | ||
260 | { | ||
261 | local def="$1"; | ||
262 | local hookName="$2"; | ||
263 | if declare -F "$hookName" > /dev/null; then | ||
264 | "$hookName"; | ||
265 | else | ||
266 | if type -p "$hookName" > /dev/null; then | ||
267 | source "$hookName"; | ||
268 | else | ||
269 | if [ -n "${!hookName:-}" ]; then | ||
270 | eval "${!hookName}"; | ||
271 | else | ||
272 | return "$def"; | ||
273 | fi; | ||
274 | fi; | ||
275 | fi | ||
276 | } | ||
277 | _defaultUnpack () | ||
278 | { | ||
279 | local fn="$1"; | ||
280 | if [ -d "$fn" ]; then | ||
281 | cp -pr --reflink=auto -- "$fn" "$(stripHash "$fn")"; | ||
282 | else | ||
283 | case "$fn" in | ||
284 | *.tar.xz | *.tar.lzma | *.txz) | ||
285 | xz -d < "$fn" | tar xf - | ||
286 | ;; | ||
287 | *.tar | *.tar.* | *.tgz | *.tbz2 | *.tbz) | ||
288 | tar xf "$fn" | ||
289 | ;; | ||
290 | *) | ||
291 | return 1 | ||
292 | ;; | ||
293 | esac; | ||
294 | fi | ||
295 | } | ||
296 | _doStrip () | ||
297 | { | ||
298 | local -ra flags=(dontStripHost dontStripTarget); | ||
299 | local -ra stripCmds=(STRIP TARGET_STRIP); | ||
300 | if [[ "${STRIP-}" == "${TARGET_STRIP-}" ]]; then | ||
301 | dontStripTarget+=1; | ||
302 | fi; | ||
303 | local i; | ||
304 | for i in ${!stripCmds[@]}; | ||
305 | do | ||
306 | local -n flag="${flags[$i]}"; | ||
307 | local -n stripCmd="${stripCmds[$i]}"; | ||
308 | if [[ -n "${dontStrip-}" || -n "${flag-}" ]] || ! type -f "${stripCmd-}" 2> /dev/null; then | ||
309 | continue; | ||
310 | fi; | ||
311 | stripDebugList=${stripDebugList:-lib lib32 lib64 libexec bin sbin}; | ||
312 | if [ -n "$stripDebugList" ]; then | ||
313 | stripDirs "$stripCmd" "$stripDebugList" "${stripDebugFlags:--S}"; | ||
314 | fi; | ||
315 | stripAllList=${stripAllList:-}; | ||
316 | if [ -n "$stripAllList" ]; then | ||
317 | stripDirs "$stripCmd" "$stripAllList" "${stripAllFlags:--s}"; | ||
318 | fi; | ||
319 | done | ||
320 | } | ||
321 | _eval () | ||
322 | { | ||
323 | if declare -F "$1" > /dev/null 2>&1; then | ||
324 | "$@"; | ||
325 | else | ||
326 | eval "$1"; | ||
327 | fi | ||
328 | } | ||
329 | _makeSymlinksRelative () | ||
330 | { | ||
331 | local symlinkTarget; | ||
332 | if [ -n "${dontRewriteSymlinks-}" ]; then | ||
333 | return 0; | ||
334 | fi; | ||
335 | while IFS= read -r -d '' f; do | ||
336 | symlinkTarget=$(readlink "$f"); | ||
337 | if [[ "$symlinkTarget"/ != "$prefix"/* ]]; then | ||
338 | continue; | ||
339 | fi; | ||
340 | if [ ! -e "$symlinkTarget" ]; then | ||
341 | echo "the symlink $f is broken, it points to $symlinkTarget (which is missing)"; | ||
342 | fi; | ||
343 | echo "rewriting symlink $f to be relative to $prefix"; | ||
344 | ln -snrf "$symlinkTarget" "$f"; | ||
345 | done < <(find $prefix -type l -print0) | ||
346 | } | ||
347 | _moveLib64 () | ||
348 | { | ||
349 | if [ "${dontMoveLib64-}" = 1 ]; then | ||
350 | return; | ||
351 | fi; | ||
352 | if [ ! -e "$prefix/lib64" -o -L "$prefix/lib64" ]; then | ||
353 | return; | ||
354 | fi; | ||
355 | echo "moving $prefix/lib64/* to $prefix/lib"; | ||
356 | mkdir -p $prefix/lib; | ||
357 | shopt -s dotglob; | ||
358 | for i in $prefix/lib64/*; | ||
359 | do | ||
360 | mv --no-clobber "$i" $prefix/lib; | ||
361 | done; | ||
362 | shopt -u dotglob; | ||
363 | rmdir $prefix/lib64; | ||
364 | ln -s lib $prefix/lib64 | ||
365 | } | ||
366 | _moveSbin () | ||
367 | { | ||
368 | if [ "${dontMoveSbin-}" = 1 ]; then | ||
369 | return; | ||
370 | fi; | ||
371 | if [ ! -e "$prefix/sbin" -o -L "$prefix/sbin" ]; then | ||
372 | return; | ||
373 | fi; | ||
374 | echo "moving $prefix/sbin/* to $prefix/bin"; | ||
375 | mkdir -p $prefix/bin; | ||
376 | shopt -s dotglob; | ||
377 | for i in $prefix/sbin/*; | ||
378 | do | ||
379 | mv "$i" $prefix/bin; | ||
380 | done; | ||
381 | shopt -u dotglob; | ||
382 | rmdir $prefix/sbin; | ||
383 | ln -s bin $prefix/sbin | ||
384 | } | ||
385 | _moveSystemdUserUnits () | ||
386 | { | ||
387 | if [ "${dontMoveSystemdUserUnits:-0}" = 1 ]; then | ||
388 | return; | ||
389 | fi; | ||
390 | if [ ! -e "${prefix:?}/lib/systemd/user" ]; then | ||
391 | return; | ||
392 | fi; | ||
393 | local source="$prefix/lib/systemd/user"; | ||
394 | local target="$prefix/share/systemd/user"; | ||
395 | echo "moving $source/* to $target"; | ||
396 | mkdir -p "$target"; | ||
397 | ( shopt -s dotglob; | ||
398 | for i in "$source"/*; | ||
399 | do | ||
400 | mv "$i" "$target"; | ||
401 | done ); | ||
402 | rmdir "$source"; | ||
403 | ln -s "$target" "$source" | ||
404 | } | ||
405 | _moveToShare () | ||
406 | { | ||
407 | forceShare=${forceShare:=man doc info}; | ||
408 | if [ -z "$forceShare" -o -z "$out" ]; then | ||
409 | return; | ||
410 | fi; | ||
411 | for d in $forceShare; | ||
412 | do | ||
413 | if [ -d "$out/$d" ]; then | ||
414 | if [ -d "$out/share/$d" ]; then | ||
415 | echo "both $d/ and share/$d/ exist!"; | ||
416 | else | ||
417 | echo "moving $out/$d to $out/share/$d"; | ||
418 | mkdir -p $out/share; | ||
419 | mv $out/$d $out/share/; | ||
420 | fi; | ||
421 | fi; | ||
422 | done | ||
423 | } | ||
424 | _multioutConfig () | ||
425 | { | ||
426 | if [ "$outputs" = "out" ] || [ -z "${setOutputFlags-1}" ]; then | ||
427 | return; | ||
428 | fi; | ||
429 | if [ -z "$shareDocName" ]; then | ||
430 | local confScript="$configureScript"; | ||
431 | if [ -z "$confScript" ] && [ -x ./configure ]; then | ||
432 | confScript=./configure; | ||
433 | fi; | ||
434 | if [ -f "$confScript" ]; then | ||
435 | local shareDocName="$(sed -n "s/^PACKAGE_TARNAME='\(.*\)'$/\1/p" < "$confScript")"; | ||
436 | fi; | ||
437 | if [ -z "$shareDocName" ] || echo "$shareDocName" | grep -q '[^a-zA-Z0-9_-]'; then | ||
438 | shareDocName="$(echo "$name" | sed 's/-[^a-zA-Z].*//')"; | ||
439 | fi; | ||
440 | fi; | ||
441 | configureFlags=" --bindir=${!outputBin}/bin --sbindir=${!outputBin}/sbin --includedir=${!outputInclude}/include --oldincludedir=${!outputInclude}/include --mandir=${!outputMan}/share/man --infodir=${!outputInfo}/share/info --docdir=${!outputDoc}/share/doc/${shareDocName} --libdir=${!outputLib}/lib --libexecdir=${!outputLib}/libexec --localedir=${!outputLib}/share/locale $configureFlags"; | ||
442 | installFlags=" pkgconfigdir=${!outputDev}/lib/pkgconfig m4datadir=${!outputDev}/share/aclocal aclocaldir=${!outputDev}/share/aclocal $installFlags" | ||
443 | } | ||
444 | _multioutDevs () | ||
445 | { | ||
446 | if [ "$outputs" = "out" ] || [ -z "${moveToDev-1}" ]; then | ||
447 | return; | ||
448 | fi; | ||
449 | moveToOutput include "${!outputInclude}"; | ||
450 | moveToOutput lib/pkgconfig "${!outputDev}"; | ||
451 | moveToOutput share/pkgconfig "${!outputDev}"; | ||
452 | moveToOutput lib/cmake "${!outputDev}"; | ||
453 | moveToOutput share/aclocal "${!outputDev}"; | ||
454 | for f in "${!outputDev}"/{lib,share}/pkgconfig/*.pc; | ||
455 | do | ||
456 | echo "Patching '$f' includedir to output ${!outputInclude}"; | ||
457 | sed -i "/^includedir=/s,=\${prefix},=${!outputInclude}," "$f"; | ||
458 | done | ||
459 | } | ||
460 | _multioutDocs () | ||
461 | { | ||
462 | local REMOVE=REMOVE; | ||
463 | moveToOutput share/info "${!outputInfo}"; | ||
464 | moveToOutput share/doc "${!outputDoc}"; | ||
465 | moveToOutput share/gtk-doc "${!outputDevdoc}"; | ||
466 | moveToOutput share/devhelp/books "${!outputDevdoc}"; | ||
467 | moveToOutput share/man "${!outputMan}"; | ||
468 | moveToOutput share/man/man3 "${!outputDevman}" | ||
469 | } | ||
470 | _multioutPropagateDev () | ||
471 | { | ||
472 | if [ "$outputs" = "out" ]; then | ||
473 | return; | ||
474 | fi; | ||
475 | local outputFirst; | ||
476 | for outputFirst in $outputs; | ||
477 | do | ||
478 | break; | ||
479 | done; | ||
480 | local propagaterOutput="$outputDev"; | ||
481 | if [ -z "$propagaterOutput" ]; then | ||
482 | propagaterOutput="$outputFirst"; | ||
483 | fi; | ||
484 | if [ -z "${propagatedBuildOutputs+1}" ]; then | ||
485 | local po_dirty="$outputBin $outputInclude $outputLib"; | ||
486 | set +o pipefail; | ||
487 | propagatedBuildOutputs=`echo "$po_dirty" | tr -s ' ' '\n' | grep -v -F "$propagaterOutput" | sort -u | tr '\n' ' ' `; | ||
488 | set -o pipefail; | ||
489 | fi; | ||
490 | if [ -z "$propagatedBuildOutputs" ]; then | ||
491 | return; | ||
492 | fi; | ||
493 | mkdir -p "${!propagaterOutput}"/nix-support; | ||
494 | for output in $propagatedBuildOutputs; | ||
495 | do | ||
496 | echo -n " ${!output}" >> "${!propagaterOutput}"/nix-support/propagated-build-inputs; | ||
497 | done | ||
498 | } | ||
499 | _overrideFirst () | ||
500 | { | ||
501 | if [ -z "${!1-}" ]; then | ||
502 | _assignFirst "$@"; | ||
503 | fi | ||
504 | } | ||
505 | _pruneLibtoolFiles () | ||
506 | { | ||
507 | if [ "${dontPruneLibtoolFiles-}" ] || [ ! -e "$prefix" ]; then | ||
508 | return; | ||
509 | fi; | ||
510 | find "$prefix" -type f -name '*.la' -exec grep -q '^# Generated by .*libtool' {} \; -exec grep -q "^old_library=''" {} \; -exec sed -i {} -e "/^dependency_libs='[^']/ c dependency_libs='' #pruned" \; | ||
511 | } | ||
512 | _updateSourceDateEpochFromSourceRoot () | ||
513 | { | ||
514 | if [ -n "$sourceRoot" ]; then | ||
515 | updateSourceDateEpoch "$sourceRoot"; | ||
516 | fi | ||
517 | } | ||
518 | activatePackage () | ||
519 | { | ||
520 | local pkg="$1"; | ||
521 | local -ri hostOffset="$2"; | ||
522 | local -ri targetOffset="$3"; | ||
523 | (( "$hostOffset" <= "$targetOffset" )) || exit -1; | ||
524 | if [ -f "$pkg" ]; then | ||
525 | source "$pkg"; | ||
526 | fi; | ||
527 | if [[ -z "${strictDeps-}" || "$hostOffset" -le -1 ]]; then | ||
528 | addToSearchPath _PATH "$pkg/bin"; | ||
529 | fi; | ||
530 | if [[ "$hostOffset" -le -1 ]]; then | ||
531 | addToSearchPath _XDG_DATA_DIRS "$pkg/share"; | ||
532 | fi; | ||
533 | if [[ "$hostOffset" -eq 0 && -d "$pkg/bin" ]]; then | ||
534 | addToSearchPath _HOST_PATH "$pkg/bin"; | ||
535 | fi; | ||
536 | if [[ -f "$pkg/nix-support/setup-hook" ]]; then | ||
537 | source "$pkg/nix-support/setup-hook"; | ||
538 | fi | ||
539 | } | ||
540 | addEnvHooks () | ||
541 | { | ||
542 | local depHostOffset="$1"; | ||
543 | shift; | ||
544 | local pkgHookVarsSlice="${pkgHookVarVars[$depHostOffset + 1]}[@]"; | ||
545 | local pkgHookVar; | ||
546 | for pkgHookVar in "${!pkgHookVarsSlice}"; | ||
547 | do | ||
548 | eval "${pkgHookVar}s"'+=("$@")'; | ||
549 | done | ||
550 | } | ||
551 | addSDL2Path () | ||
552 | { | ||
553 | if [ -e "$1/include/SDL2" ]; then | ||
554 | export SDL2_PATH="${SDL2_PATH-}${SDL2_PATH:+ }$1/include/SDL2"; | ||
555 | fi | ||
556 | } | ||
557 | addToSearchPath () | ||
558 | { | ||
559 | addToSearchPathWithCustomDelimiter ":" "$@" | ||
560 | } | ||
561 | addToSearchPathWithCustomDelimiter () | ||
562 | { | ||
563 | local delimiter="$1"; | ||
564 | local varName="$2"; | ||
565 | local dir="$3"; | ||
566 | if [ -d "$dir" ]; then | ||
567 | export "${varName}=${!varName:+${!varName}${delimiter}}${dir}"; | ||
568 | fi | ||
569 | } | ||
570 | auditTmpdir () | ||
571 | { | ||
572 | local dir="$1"; | ||
573 | [ -e "$dir" ] || return 0; | ||
574 | header "checking for references to $TMPDIR/ in $dir..."; | ||
575 | local i; | ||
576 | while IFS= read -r -d '' i; do | ||
577 | if [[ "$i" =~ .build-id ]]; then | ||
578 | continue; | ||
579 | fi; | ||
580 | if isELF "$i"; then | ||
581 | if { | ||
582 | printf :; | ||
583 | patchelf --print-rpath "$i" | ||
584 | } | grep -q -F ":$TMPDIR/"; then | ||
585 | echo "RPATH of binary $i contains a forbidden reference to $TMPDIR/"; | ||
586 | exit 1; | ||
587 | fi; | ||
588 | fi; | ||
589 | if isScript "$i"; then | ||
590 | if [ -e "$(dirname "$i")/.$(basename "$i")-wrapped" ]; then | ||
591 | if grep -q -F "$TMPDIR/" "$i"; then | ||
592 | echo "wrapper script $i contains a forbidden reference to $TMPDIR/"; | ||
593 | exit 1; | ||
594 | fi; | ||
595 | fi; | ||
596 | fi; | ||
597 | done < <(find "$dir" -type f -print0); | ||
598 | stopNest | ||
599 | } | ||
600 | bintoolsWrapper_addLDVars () | ||
601 | { | ||
602 | local role_post; | ||
603 | getHostRoleEnvHook; | ||
604 | if [[ -d "$1/lib64" && ! -L "$1/lib64" ]]; then | ||
605 | export NIX_LDFLAGS${role_post}+=" -L$1/lib64"; | ||
606 | fi; | ||
607 | if [[ -d "$1/lib" ]]; then | ||
608 | local -a glob=($1/lib/lib*); | ||
609 | if [ "${#glob[*]}" -gt 0 ]; then | ||
610 | export NIX_LDFLAGS${role_post}+=" -L$1/lib"; | ||
611 | fi; | ||
612 | fi | ||
613 | } | ||
614 | buildPhase () | ||
615 | { | ||
616 | runHook preBuild; | ||
617 | : ${makeFlags=}; | ||
618 | if [[ -z "$makeFlags" && -z "${makefile:-}" && ! ( -e Makefile || -e makefile || -e GNUmakefile ) ]]; then | ||
619 | echo "no Makefile, doing nothing"; | ||
620 | else | ||
621 | foundMakefile=1; | ||
622 | local flagsArray=(${enableParallelBuilding:+-j${NIX_BUILD_CORES} -l${NIX_BUILD_CORES}} SHELL=$SHELL $makeFlags ${makeFlagsArray+"${makeFlagsArray[@]}"} $buildFlags ${buildFlagsArray+"${buildFlagsArray[@]}"}); | ||
623 | echoCmd 'build flags' "${flagsArray[@]}"; | ||
624 | make ${makefile:+-f $makefile} "${flagsArray[@]}"; | ||
625 | unset flagsArray; | ||
626 | fi; | ||
627 | runHook postBuild | ||
628 | } | ||
629 | ccWrapper_addCVars () | ||
630 | { | ||
631 | local role_post; | ||
632 | getHostRoleEnvHook; | ||
633 | if [ -d "$1/include" ]; then | ||
634 | export NIX_CFLAGS_COMPILE${role_post}+=" -isystem $1/include"; | ||
635 | fi; | ||
636 | if [ -d "$1/Library/Frameworks" ]; then | ||
637 | export NIX_CFLAGS_COMPILE${role_post}+=" -iframework $1/Library/Frameworks"; | ||
638 | fi | ||
639 | } | ||
640 | checkPhase () | ||
641 | { | ||
642 | runHook preCheck; | ||
643 | if [[ -z "${foundMakefile:-}" ]]; then | ||
644 | echo "no Makefile or custom checkPhase, doing nothing"; | ||
645 | runHook postCheck; | ||
646 | return; | ||
647 | fi; | ||
648 | if [[ -z "${checkTarget:-}" ]]; then | ||
649 | if make -n ${makefile:+-f $makefile} check > /dev/null 2>&1; then | ||
650 | checkTarget=check; | ||
651 | else | ||
652 | if make -n ${makefile:+-f $makefile} test > /dev/null 2>&1; then | ||
653 | checkTarget=test; | ||
654 | fi; | ||
655 | fi; | ||
656 | fi; | ||
657 | if [[ -z "${checkTarget:-}" ]]; then | ||
658 | echo "no check/test target in ${makefile:-Makefile}, doing nothing"; | ||
659 | else | ||
660 | local flagsArray=(${enableParallelChecking:+-j${NIX_BUILD_CORES} -l${NIX_BUILD_CORES}} SHELL=$SHELL $makeFlags ${makeFlagsArray+"${makeFlagsArray[@]}"} ${checkFlags:-VERBOSE=y} ${checkFlagsArray+"${checkFlagsArray[@]}"} ${checkTarget}); | ||
661 | echoCmd 'check flags' "${flagsArray[@]}"; | ||
662 | make ${makefile:+-f $makefile} "${flagsArray[@]}"; | ||
663 | unset flagsArray; | ||
664 | fi; | ||
665 | runHook postCheck | ||
666 | } | ||
667 | closeNest () | ||
668 | { | ||
669 | true | ||
670 | } | ||
671 | compressManPages () | ||
672 | { | ||
673 | local dir="$1"; | ||
674 | if [ -L "$dir"/share ] || [ -L "$dir"/share/man ] || [ ! -d "$dir/share/man" ]; then | ||
675 | return; | ||
676 | fi; | ||
677 | echo "gzipping man pages under $dir/share/man/"; | ||
678 | find "$dir"/share/man/ -type f -a '!' -regex '.*\.\(bz2\|gz\)$' -print0 | while IFS= read -r -d '' f; do | ||
679 | if gzip -c -n "$f" > "$f".gz; then | ||
680 | rm "$f"; | ||
681 | else | ||
682 | rm "$f".gz; | ||
683 | fi; | ||
684 | done; | ||
685 | find "$dir"/share/man/ -type l -a '!' -regex '.*\.\(bz2\|gz\)$' -print0 | sort -z | while IFS= read -r -d '' f; do | ||
686 | local target; | ||
687 | target="$(readlink -f "$f")"; | ||
688 | if [ -f "$target".gz ]; then | ||
689 | ln -sf "$target".gz "$f".gz && rm "$f"; | ||
690 | fi; | ||
691 | done | ||
692 | } | ||
693 | configurePhase () | ||
694 | { | ||
695 | runHook preConfigure; | ||
696 | : ${configureScript=}; | ||
697 | : ${configureFlags=}; | ||
698 | if [[ -z "$configureScript" && -x ./configure ]]; then | ||
699 | configureScript=./configure; | ||
700 | fi; | ||
701 | if [ -z "${dontFixLibtool:-}" ]; then | ||
702 | local i; | ||
703 | find . -iname "ltmain.sh" -print0 | while IFS='' read -r -d '' i; do | ||
704 | echo "fixing libtool script $i"; | ||
705 | fixLibtool "$i"; | ||
706 | done; | ||
707 | fi; | ||
708 | if [[ -z "${dontAddPrefix:-}" && -n "$prefix" ]]; then | ||
709 | configureFlags="${prefixKey:---prefix=}$prefix $configureFlags"; | ||
710 | fi; | ||
711 | if [ -z "${dontAddDisableDepTrack:-}" ]; then | ||
712 | if [ -f "$configureScript" ] && grep -q dependency-tracking "$configureScript"; then | ||
713 | configureFlags="--disable-dependency-tracking $configureFlags"; | ||
714 | fi; | ||
715 | fi; | ||
716 | if [ -z "${dontDisableStatic:-}" ]; then | ||
717 | if [ -f "$configureScript" ] && grep -q enable-static "$configureScript"; then | ||
718 | configureFlags="--disable-static $configureFlags"; | ||
719 | fi; | ||
720 | fi; | ||
721 | if [ -n "$configureScript" ]; then | ||
722 | local flagsArray=($configureFlags ${configureFlagsArray+"${configureFlagsArray[@]}"}); | ||
723 | echoCmd 'configure flags' "${flagsArray[@]}"; | ||
724 | $configureScript "${flagsArray[@]}"; | ||
725 | unset flagsArray; | ||
726 | else | ||
727 | echo "no configure script, doing nothing"; | ||
728 | fi; | ||
729 | runHook postConfigure | ||
730 | } | ||
731 | consumeEntire () | ||
732 | { | ||
733 | if IFS='' read -r -N 0 $1; then | ||
734 | echo "consumeEntire(): ERROR: Input null bytes, won't process" 1>&2; | ||
735 | return 1; | ||
736 | fi | ||
737 | } | ||
738 | distPhase () | ||
739 | { | ||
740 | runHook preDist; | ||
741 | local flagsArray=($distFlags ${distFlagsArray+"${distFlagsArray[@]}"} ${distTarget:-dist}); | ||
742 | echo 'dist flags: %q' "${flagsArray[@]}"; | ||
743 | make ${makefile:+-f $makefile} "${flagsArray[@]}"; | ||
744 | if [ "${dontCopyDist:-0}" != 1 ]; then | ||
745 | mkdir -p "$out/tarballs"; | ||
746 | cp -pvd ${tarballs:-*.tar.gz} "$out/tarballs"; | ||
747 | fi; | ||
748 | runHook postDist | ||
749 | } | ||
750 | dumpVars () | ||
751 | { | ||
752 | if [ "${noDumpEnvVars:-0}" != 1 ]; then | ||
753 | export 2> /dev/null >| "$NIX_BUILD_TOP/env-vars" || true; | ||
754 | fi | ||
755 | } | ||
756 | echoCmd () | ||
757 | { | ||
758 | printf "%s:" "$1"; | ||
759 | shift; | ||
760 | printf ' %q' "$@"; | ||
761 | echo | ||
762 | } | ||
763 | exitHandler () | ||
764 | { | ||
765 | exitCode="$?"; | ||
766 | set +e; | ||
767 | if [ -n "${showBuildStats:-}" ]; then | ||
768 | times > "$NIX_BUILD_TOP/.times"; | ||
769 | local -a times=($(cat "$NIX_BUILD_TOP/.times")); | ||
770 | echo "build time elapsed: " "${times[@]}"; | ||
771 | fi; | ||
772 | if (( "$exitCode" != 0 )); then | ||
773 | runHook failureHook; | ||
774 | if [ -n "${succeedOnFailure:-}" ]; then | ||
775 | echo "build failed with exit code $exitCode (ignored)"; | ||
776 | mkdir -p "$out/nix-support"; | ||
777 | printf "%s" "$exitCode" > "$out/nix-support/failed"; | ||
778 | exit 0; | ||
779 | fi; | ||
780 | else | ||
781 | runHook exitHook; | ||
782 | fi; | ||
783 | exit "$exitCode" | ||
784 | } | ||
785 | findInputs () | ||
786 | { | ||
787 | local -r pkg="$1"; | ||
788 | local -ri hostOffset="$2"; | ||
789 | local -ri targetOffset="$3"; | ||
790 | (( "$hostOffset" <= "$targetOffset" )) || exit -1; | ||
791 | local varVar="${pkgAccumVarVars[$hostOffset + 1]}"; | ||
792 | local varRef="$varVar[\$targetOffset - \$hostOffset]"; | ||
793 | local var="${!varRef}"; | ||
794 | unset -v varVar varRef; | ||
795 | local varSlice="$var[*]"; | ||
796 | case "${!varSlice-}" in | ||
797 | *" $pkg "*) | ||
798 | return 0 | ||
799 | ;; | ||
800 | esac; | ||
801 | unset -v varSlice; | ||
802 | eval "$var"'+=("$pkg")'; | ||
803 | if ! [ -e "$pkg" ]; then | ||
804 | echo "build input $pkg does not exist" 1>&2; | ||
805 | exit 1; | ||
806 | fi; | ||
807 | local -i mapOffsetResult; | ||
808 | function mapOffset () | ||
809 | { | ||
810 | local -ri inputOffset="$1"; | ||
811 | if (( "$inputOffset" <= 0 )); then | ||
812 | local -ri outputOffset="$inputOffset + $hostOffset"; | ||
813 | else | ||
814 | local -ri outputOffset="$inputOffset - 1 + $targetOffset"; | ||
815 | fi; | ||
816 | mapOffsetResult="$outputOffset" | ||
817 | }; | ||
818 | local -i relHostOffset; | ||
819 | for relHostOffset in "${allPlatOffsets[@]}"; | ||
820 | do | ||
821 | local files="${propagatedDepFilesVars[$relHostOffset + 1]}"; | ||
822 | mapOffset relHostOffset; | ||
823 | local -i hostOffsetNext="$mapOffsetResult"; | ||
824 | [[ "${allPlatOffsets[*]}" = *"$hostOffsetNext"* ]] || continue; | ||
825 | local -i relTargetOffset; | ||
826 | for relTargetOffset in "${allPlatOffsets[@]}"; | ||
827 | do | ||
828 | (( "$relHostOffset" <= "$relTargetOffset" )) || continue; | ||
829 | local fileRef="${files}[$relTargetOffset - $relHostOffset]"; | ||
830 | local file="${!fileRef}"; | ||
831 | unset -v fileRef; | ||
832 | mapOffset relTargetOffset; | ||
833 | local -i targetOffsetNext="$mapOffsetResult"; | ||
834 | [[ "${allPlatOffsets[*]}" = *"$targetOffsetNext"* ]] || continue; | ||
835 | [[ -f "$pkg/nix-support/$file" ]] || continue; | ||
836 | local pkgNext; | ||
837 | read -r -d '' pkgNext < "$pkg/nix-support/$file" || true; | ||
838 | for pkgNext in $pkgNext; | ||
839 | do | ||
840 | findInputs "$pkgNext" "$hostOffsetNext" "$targetOffsetNext"; | ||
841 | done; | ||
842 | done; | ||
843 | done | ||
844 | } | ||
845 | fixLibtool () | ||
846 | { | ||
847 | sed -i -e 's^eval sys_lib_.*search_path=.*^^' "$1" | ||
848 | } | ||
849 | fixupPhase () | ||
850 | { | ||
851 | local output; | ||
852 | for output in $outputs; | ||
853 | do | ||
854 | if [ -e "${!output}" ]; then | ||
855 | chmod -R u+w "${!output}"; | ||
856 | fi; | ||
857 | done; | ||
858 | runHook preFixup; | ||
859 | local output; | ||
860 | for output in $outputs; | ||
861 | do | ||
862 | prefix="${!output}" runHook fixupOutput; | ||
863 | done; | ||
864 | declare -ra flatVars=(depsBuildBuildPropagated propagatedNativeBuildInputs depsBuildTargetPropagated depsHostHostPropagated propagatedBuildInputs depsTargetTargetPropagated); | ||
865 | declare -ra flatFiles=("${propagatedBuildDepFiles[@]}" "${propagatedHostDepFiles[@]}" "${propagatedTargetDepFiles[@]}"); | ||
866 | local propagatedInputsIndex; | ||
867 | for propagatedInputsIndex in "${!flatVars[@]}"; | ||
868 | do | ||
869 | local propagatedInputsSlice="${flatVars[$propagatedInputsIndex]}[@]"; | ||
870 | local propagatedInputsFile="${flatFiles[$propagatedInputsIndex]}"; | ||
871 | [[ -n "${!propagatedInputsSlice}" ]] || continue; | ||
872 | mkdir -p "${!outputDev}/nix-support"; | ||
873 | printWords ${!propagatedInputsSlice} > "${!outputDev}/nix-support/$propagatedInputsFile"; | ||
874 | done; | ||
875 | if [ -n "${setupHook:-}" ]; then | ||
876 | mkdir -p "${!outputDev}/nix-support"; | ||
877 | substituteAll "$setupHook" "${!outputDev}/nix-support/setup-hook"; | ||
878 | fi; | ||
879 | if [ -n "${setupHooks:-}" ]; then | ||
880 | mkdir -p "${!outputDev}/nix-support"; | ||
881 | local hook; | ||
882 | for hook in $setupHooks; | ||
883 | do | ||
884 | local content; | ||
885 | consumeEntire content < "$hook"; | ||
886 | substituteAllStream content "file '$hook'" >> "${!outputDev}/nix-support/setup-hook"; | ||
887 | unset -v content; | ||
888 | done; | ||
889 | unset -v hook; | ||
890 | fi; | ||
891 | if [ -n "${propagatedUserEnvPkgs:-}" ]; then | ||
892 | mkdir -p "${!outputBin}/nix-support"; | ||
893 | printWords $propagatedUserEnvPkgs > "${!outputBin}/nix-support/propagated-user-env-packages"; | ||
894 | fi; | ||
895 | runHook postFixup | ||
896 | } | ||
897 | genericBuild () | ||
898 | { | ||
899 | if [ -f "${buildCommandPath:-}" ]; then | ||
900 | source "$buildCommandPath"; | ||
901 | return; | ||
902 | fi; | ||
903 | if [ -n "${buildCommand:-}" ]; then | ||
904 | eval "$buildCommand"; | ||
905 | return; | ||
906 | fi; | ||
907 | if [ -z "${phases:-}" ]; then | ||
908 | phases="${prePhases:-} unpackPhase patchPhase ${preConfigurePhases:-} configurePhase ${preBuildPhases:-} buildPhase checkPhase ${preInstallPhases:-} installPhase ${preFixupPhases:-} fixupPhase installCheckPhase ${preDistPhases:-} distPhase ${postPhases:-}"; | ||
909 | fi; | ||
910 | for curPhase in $phases; | ||
911 | do | ||
912 | if [[ "$curPhase" = unpackPhase && -n "${dontUnpack:-}" ]]; then | ||
913 | continue; | ||
914 | fi; | ||
915 | if [[ "$curPhase" = patchPhase && -n "${dontPatch:-}" ]]; then | ||
916 | continue; | ||
917 | fi; | ||
918 | if [[ "$curPhase" = configurePhase && -n "${dontConfigure:-}" ]]; then | ||
919 | continue; | ||
920 | fi; | ||
921 | if [[ "$curPhase" = buildPhase && -n "${dontBuild:-}" ]]; then | ||
922 | continue; | ||
923 | fi; | ||
924 | if [[ "$curPhase" = checkPhase && -z "${doCheck:-}" ]]; then | ||
925 | continue; | ||
926 | fi; | ||
927 | if [[ "$curPhase" = installPhase && -n "${dontInstall:-}" ]]; then | ||
928 | continue; | ||
929 | fi; | ||
930 | if [[ "$curPhase" = fixupPhase && -n "${dontFixup:-}" ]]; then | ||
931 | continue; | ||
932 | fi; | ||
933 | if [[ "$curPhase" = installCheckPhase && -z "${doInstallCheck:-}" ]]; then | ||
934 | continue; | ||
935 | fi; | ||
936 | if [[ "$curPhase" = distPhase && -z "${doDist:-}" ]]; then | ||
937 | continue; | ||
938 | fi; | ||
939 | if [[ -n $NIX_LOG_FD ]]; then | ||
940 | echo "@nix { \"action\": \"setPhase\", \"phase\": \"$curPhase\" }" 1>&$NIX_LOG_FD; | ||
941 | fi; | ||
942 | showPhaseHeader "$curPhase"; | ||
943 | dumpVars; | ||
944 | eval "${!curPhase:-$curPhase}"; | ||
945 | if [ "$curPhase" = unpackPhase ]; then | ||
946 | cd "${sourceRoot:-.}"; | ||
947 | fi; | ||
948 | done | ||
949 | } | ||
950 | getHostRole () | ||
951 | { | ||
952 | getRole "$hostOffset" | ||
953 | } | ||
954 | getHostRoleEnvHook () | ||
955 | { | ||
956 | getRole "$depHostOffset" | ||
957 | } | ||
958 | getRole () | ||
959 | { | ||
960 | case $1 in | ||
961 | -1) | ||
962 | role_post='_FOR_BUILD' | ||
963 | ;; | ||
964 | 0) | ||
965 | role_post='' | ||
966 | ;; | ||
967 | 1) | ||
968 | role_post='_FOR_TARGET' | ||
969 | ;; | ||
970 | *) | ||
971 | echo "binutils-wrapper-2.35.1: used as improper sort of dependency" > 2; | ||
972 | return 1 | ||
973 | ;; | ||
974 | esac | ||
975 | } | ||
976 | getTargetRole () | ||
977 | { | ||
978 | getRole "$targetOffset" | ||
979 | } | ||
980 | getTargetRoleEnvHook () | ||
981 | { | ||
982 | getRole "$depTargetOffset" | ||
983 | } | ||
984 | getTargetRoleWrapper () | ||
985 | { | ||
986 | case $targetOffset in | ||
987 | -1) | ||
988 | export NIX_BINTOOLS_WRAPPER_TARGET_BUILD_x86_64_unknown_linux_gnu=1 | ||
989 | ;; | ||
990 | 0) | ||
991 | export NIX_BINTOOLS_WRAPPER_TARGET_HOST_x86_64_unknown_linux_gnu=1 | ||
992 | ;; | ||
993 | 1) | ||
994 | export NIX_BINTOOLS_WRAPPER_TARGET_TARGET_x86_64_unknown_linux_gnu=1 | ||
995 | ;; | ||
996 | *) | ||
997 | echo "binutils-wrapper-2.35.1: used as improper sort of dependency" > 2; | ||
998 | return 1 | ||
999 | ;; | ||
1000 | esac | ||
1001 | } | ||
1002 | header () | ||
1003 | { | ||
1004 | echo "$1" | ||
1005 | } | ||
1006 | installCheckPhase () | ||
1007 | { | ||
1008 | runHook preInstallCheck; | ||
1009 | if [[ -z "${foundMakefile:-}" ]]; then | ||
1010 | echo "no Makefile or custom installCheckPhase, doing nothing"; | ||
1011 | else | ||
1012 | if [[ -z "${installCheckTarget:-}" ]] && ! make -n ${makefile:+-f $makefile} ${installCheckTarget:-installcheck} > /dev/null 2>&1; then | ||
1013 | echo "no installcheck target in ${makefile:-Makefile}, doing nothing"; | ||
1014 | else | ||
1015 | local flagsArray=(${enableParallelChecking:+-j${NIX_BUILD_CORES} -l${NIX_BUILD_CORES}} SHELL=$SHELL $makeFlags ${makeFlagsArray+"${makeFlagsArray[@]}"} $installCheckFlags ${installCheckFlagsArray+"${installCheckFlagsArray[@]}"} ${installCheckTarget:-installcheck}); | ||
1016 | echoCmd 'installcheck flags' "${flagsArray[@]}"; | ||
1017 | make ${makefile:+-f $makefile} "${flagsArray[@]}"; | ||
1018 | unset flagsArray; | ||
1019 | fi; | ||
1020 | fi; | ||
1021 | runHook postInstallCheck | ||
1022 | } | ||
1023 | installPhase () | ||
1024 | { | ||
1025 | runHook preInstall; | ||
1026 | if [ -n "$prefix" ]; then | ||
1027 | mkdir -p "$prefix"; | ||
1028 | fi; | ||
1029 | local flagsArray=(SHELL=$SHELL $makeFlags ${makeFlagsArray+"${makeFlagsArray[@]}"} $installFlags ${installFlagsArray+"${installFlagsArray[@]}"} ${installTargets:-install}); | ||
1030 | echoCmd 'install flags' "${flagsArray[@]}"; | ||
1031 | make ${makefile:+-f $makefile} "${flagsArray[@]}"; | ||
1032 | unset flagsArray; | ||
1033 | runHook postInstall | ||
1034 | } | ||
1035 | isELF () | ||
1036 | { | ||
1037 | local fn="$1"; | ||
1038 | local fd; | ||
1039 | local magic; | ||
1040 | exec {fd}< "$fn"; | ||
1041 | read -r -n 4 -u "$fd" magic; | ||
1042 | exec {fd}>&-; | ||
1043 | if [ "$magic" = 'ELF' ]; then | ||
1044 | return 0; | ||
1045 | else | ||
1046 | return 1; | ||
1047 | fi | ||
1048 | } | ||
1049 | isScript () | ||
1050 | { | ||
1051 | local fn="$1"; | ||
1052 | local fd; | ||
1053 | local magic; | ||
1054 | exec {fd}< "$fn"; | ||
1055 | read -r -n 2 -u "$fd" magic; | ||
1056 | exec {fd}>&-; | ||
1057 | if [[ "$magic" =~ \#! ]]; then | ||
1058 | return 0; | ||
1059 | else | ||
1060 | return 1; | ||
1061 | fi | ||
1062 | } | ||
1063 | mapOffset () | ||
1064 | { | ||
1065 | local -ri inputOffset="$1"; | ||
1066 | if (( "$inputOffset" <= 0 )); then | ||
1067 | local -ri outputOffset="$inputOffset + $hostOffset"; | ||
1068 | else | ||
1069 | local -ri outputOffset="$inputOffset - 1 + $targetOffset"; | ||
1070 | fi; | ||
1071 | mapOffsetResult="$outputOffset" | ||
1072 | } | ||
1073 | moveToOutput () | ||
1074 | { | ||
1075 | local patt="$1"; | ||
1076 | local dstOut="$2"; | ||
1077 | local output; | ||
1078 | for output in $outputs; | ||
1079 | do | ||
1080 | if [ "${!output}" = "$dstOut" ]; then | ||
1081 | continue; | ||
1082 | fi; | ||
1083 | local srcPath; | ||
1084 | for srcPath in "${!output}"/$patt; | ||
1085 | do | ||
1086 | if [ ! -e "$srcPath" ] && [ ! -L "$srcPath" ]; then | ||
1087 | continue; | ||
1088 | fi; | ||
1089 | if [ "$dstOut" = REMOVE ]; then | ||
1090 | echo "Removing $srcPath"; | ||
1091 | rm -r "$srcPath"; | ||
1092 | else | ||
1093 | local dstPath="$dstOut${srcPath#${!output}}"; | ||
1094 | echo "Moving $srcPath to $dstPath"; | ||
1095 | if [ -d "$dstPath" ] && [ -d "$srcPath" ]; then | ||
1096 | rmdir "$srcPath" --ignore-fail-on-non-empty; | ||
1097 | if [ -d "$srcPath" ]; then | ||
1098 | mv -t "$dstPath" "$srcPath"/*; | ||
1099 | rmdir "$srcPath"; | ||
1100 | fi; | ||
1101 | else | ||
1102 | mkdir -p "$(readlink -m "$dstPath/..")"; | ||
1103 | mv "$srcPath" "$dstPath"; | ||
1104 | fi; | ||
1105 | fi; | ||
1106 | local srcParent="$(readlink -m "$srcPath/..")"; | ||
1107 | if rmdir "$srcParent"; then | ||
1108 | echo "Removing empty $srcParent/ and (possibly) its parents"; | ||
1109 | rmdir -p --ignore-fail-on-non-empty "$(readlink -m "$srcParent/..")" 2> /dev/null || true; | ||
1110 | fi; | ||
1111 | done; | ||
1112 | done | ||
1113 | } | ||
1114 | patchELF () | ||
1115 | { | ||
1116 | local dir="$1"; | ||
1117 | [ -e "$dir" ] || return 0; | ||
1118 | header "shrinking RPATHs of ELF executables and libraries in $dir"; | ||
1119 | local i; | ||
1120 | while IFS= read -r -d '' i; do | ||
1121 | if [[ "$i" =~ .build-id ]]; then | ||
1122 | continue; | ||
1123 | fi; | ||
1124 | if ! isELF "$i"; then | ||
1125 | continue; | ||
1126 | fi; | ||
1127 | echo "shrinking $i"; | ||
1128 | patchelf --shrink-rpath "$i" || true; | ||
1129 | done < <(find "$dir" -type f -print0); | ||
1130 | stopNest | ||
1131 | } | ||
1132 | patchPhase () | ||
1133 | { | ||
1134 | runHook prePatch; | ||
1135 | for i in ${patches:-}; | ||
1136 | do | ||
1137 | header "applying patch $i" 3; | ||
1138 | local uncompress=cat; | ||
1139 | case "$i" in | ||
1140 | *.gz) | ||
1141 | uncompress="gzip -d" | ||
1142 | ;; | ||
1143 | *.bz2) | ||
1144 | uncompress="bzip2 -d" | ||
1145 | ;; | ||
1146 | *.xz) | ||
1147 | uncompress="xz -d" | ||
1148 | ;; | ||
1149 | *.lzma) | ||
1150 | uncompress="lzma -d" | ||
1151 | ;; | ||
1152 | esac; | ||
1153 | $uncompress < "$i" 2>&1 | patch ${patchFlags:--p1}; | ||
1154 | done; | ||
1155 | runHook postPatch | ||
1156 | } | ||
1157 | patchShebangs () | ||
1158 | { | ||
1159 | local pathName; | ||
1160 | if [[ "$1" == "--host" ]]; then | ||
1161 | pathName=HOST_PATH; | ||
1162 | shift; | ||
1163 | else | ||
1164 | if [[ "$1" == "--build" ]]; then | ||
1165 | pathName=PATH; | ||
1166 | shift; | ||
1167 | fi; | ||
1168 | fi; | ||
1169 | echo "patching script interpreter paths in $@"; | ||
1170 | local f; | ||
1171 | local oldPath; | ||
1172 | local newPath; | ||
1173 | local arg0; | ||
1174 | local args; | ||
1175 | local oldInterpreterLine; | ||
1176 | local newInterpreterLine; | ||
1177 | if [[ $# -eq 0 ]]; then | ||
1178 | echo "No arguments supplied to patchShebangs" 1>&2; | ||
1179 | return 0; | ||
1180 | fi; | ||
1181 | local f; | ||
1182 | while IFS= read -r -d '' f; do | ||
1183 | isScript "$f" || continue; | ||
1184 | read -r oldInterpreterLine < "$f"; | ||
1185 | read -r oldPath arg0 args <<< "${oldInterpreterLine:2}"; | ||
1186 | if [[ -z "$pathName" ]]; then | ||
1187 | if [[ -n $strictDeps && $f == "$NIX_STORE"* ]]; then | ||
1188 | pathName=HOST_PATH; | ||
1189 | else | ||
1190 | pathName=PATH; | ||
1191 | fi; | ||
1192 | fi; | ||
1193 | if [[ "$oldPath" == *"/bin/env" ]]; then | ||
1194 | if [[ $arg0 == "-"* || $arg0 == *"="* ]]; then | ||
1195 | echo "$f: unsupported interpreter directive \"$oldInterpreterLine\" (set dontPatchShebangs=1 and handle shebang patching yourself)" 1>&2; | ||
1196 | exit 1; | ||
1197 | fi; | ||
1198 | newPath="$(PATH="${!pathName}" command -v "$arg0" || true)"; | ||
1199 | else | ||
1200 | if [[ -z $oldPath ]]; then | ||
1201 | oldPath="/bin/sh"; | ||
1202 | fi; | ||
1203 | newPath="$(PATH="${!pathName}" command -v "$(basename "$oldPath")" || true)"; | ||
1204 | args="$arg0 $args"; | ||
1205 | fi; | ||
1206 | newInterpreterLine="$newPath $args"; | ||
1207 | newInterpreterLine=${newInterpreterLine%${newInterpreterLine##*[![:space:]]}}; | ||
1208 | if [[ -n "$oldPath" && "${oldPath:0:${#NIX_STORE}}" != "$NIX_STORE" ]]; then | ||
1209 | if [[ -n "$newPath" && "$newPath" != "$oldPath" ]]; then | ||
1210 | echo "$f: interpreter directive changed from \"$oldInterpreterLine\" to \"$newInterpreterLine\""; | ||
1211 | escapedInterpreterLine=${newInterpreterLine//\\/\\\\}; | ||
1212 | timestamp=$(stat --printf "%y" "$f"); | ||
1213 | sed -i -e "1 s|.*|#\!$escapedInterpreterLine|" "$f"; | ||
1214 | touch --date "$timestamp" "$f"; | ||
1215 | fi; | ||
1216 | fi; | ||
1217 | done < <(find "$@" -type f -perm -0100 -print0); | ||
1218 | stopNest | ||
1219 | } | ||
1220 | patchShebangsAuto () | ||
1221 | { | ||
1222 | if [[ -z "${dontPatchShebangs-}" && -e "$prefix" ]]; then | ||
1223 | if [[ "$output" != out && "$output" = "$outputDev" ]]; then | ||
1224 | patchShebangs --build "$prefix"; | ||
1225 | else | ||
1226 | patchShebangs --host "$prefix"; | ||
1227 | fi; | ||
1228 | fi | ||
1229 | } | ||
1230 | printLines () | ||
1231 | { | ||
1232 | (( "$#" > 0 )) || return 0; | ||
1233 | printf '%s\n' "$@" | ||
1234 | } | ||
1235 | printWords () | ||
1236 | { | ||
1237 | (( "$#" > 0 )) || return 0; | ||
1238 | printf '%s ' "$@" | ||
1239 | } | ||
1240 | runHook () | ||
1241 | { | ||
1242 | local hookName="$1"; | ||
1243 | shift; | ||
1244 | local hooksSlice="${hookName%Hook}Hooks[@]"; | ||
1245 | local hook; | ||
1246 | for hook in "_callImplicitHook 0 $hookName" ${!hooksSlice+"${!hooksSlice}"}; | ||
1247 | do | ||
1248 | _eval "$hook" "$@"; | ||
1249 | done; | ||
1250 | return 0 | ||
1251 | } | ||
1252 | runOneHook () | ||
1253 | { | ||
1254 | local hookName="$1"; | ||
1255 | shift; | ||
1256 | local hooksSlice="${hookName%Hook}Hooks[@]"; | ||
1257 | local hook ret=1; | ||
1258 | for hook in "_callImplicitHook 1 $hookName" ${!hooksSlice+"${!hooksSlice}"}; | ||
1259 | do | ||
1260 | if _eval "$hook" "$@"; then | ||
1261 | ret=0; | ||
1262 | break; | ||
1263 | fi; | ||
1264 | done; | ||
1265 | return "$ret" | ||
1266 | } | ||
1267 | showPhaseHeader () | ||
1268 | { | ||
1269 | local phase="$1"; | ||
1270 | case "$phase" in | ||
1271 | unpackPhase) | ||
1272 | header "unpacking sources" | ||
1273 | ;; | ||
1274 | patchPhase) | ||
1275 | header "patching sources" | ||
1276 | ;; | ||
1277 | configurePhase) | ||
1278 | header "configuring" | ||
1279 | ;; | ||
1280 | buildPhase) | ||
1281 | header "building" | ||
1282 | ;; | ||
1283 | checkPhase) | ||
1284 | header "running tests" | ||
1285 | ;; | ||
1286 | installPhase) | ||
1287 | header "installing" | ||
1288 | ;; | ||
1289 | fixupPhase) | ||
1290 | header "post-installation fixup" | ||
1291 | ;; | ||
1292 | installCheckPhase) | ||
1293 | header "running install tests" | ||
1294 | ;; | ||
1295 | *) | ||
1296 | header "$phase" | ||
1297 | ;; | ||
1298 | esac | ||
1299 | } | ||
1300 | stopNest () | ||
1301 | { | ||
1302 | true | ||
1303 | } | ||
1304 | stripDirs () | ||
1305 | { | ||
1306 | local cmd="$1"; | ||
1307 | local dirs="$2"; | ||
1308 | local stripFlags="$3"; | ||
1309 | local dirsNew=; | ||
1310 | local d; | ||
1311 | for d in ${dirs}; | ||
1312 | do | ||
1313 | if [ -d "$prefix/$d" ]; then | ||
1314 | dirsNew="${dirsNew} $prefix/$d "; | ||
1315 | fi; | ||
1316 | done; | ||
1317 | dirs=${dirsNew}; | ||
1318 | if [ -n "${dirs}" ]; then | ||
1319 | header "stripping (with command $cmd and flags $stripFlags) in$dirs"; | ||
1320 | find $dirs -type f -exec $cmd $commonStripFlags $stripFlags '{}' \; 2> /dev/null; | ||
1321 | stopNest; | ||
1322 | fi | ||
1323 | } | ||
1324 | stripHash () | ||
1325 | { | ||
1326 | local strippedName casematchOpt=0; | ||
1327 | strippedName="$(basename -- "$1")"; | ||
1328 | shopt -q nocasematch && casematchOpt=1; | ||
1329 | shopt -u nocasematch; | ||
1330 | if [[ "$strippedName" =~ ^[a-z0-9]{32}- ]]; then | ||
1331 | echo "${strippedName:33}"; | ||
1332 | else | ||
1333 | echo "$strippedName"; | ||
1334 | fi; | ||
1335 | if (( casematchOpt )); then | ||
1336 | shopt -s nocasematch; | ||
1337 | fi | ||
1338 | } | ||
1339 | substitute () | ||
1340 | { | ||
1341 | local input="$1"; | ||
1342 | local output="$2"; | ||
1343 | shift 2; | ||
1344 | if [ ! -f "$input" ]; then | ||
1345 | echo "substitute(): ERROR: file '$input' does not exist" 1>&2; | ||
1346 | return 1; | ||
1347 | fi; | ||
1348 | local content; | ||
1349 | consumeEntire content < "$input"; | ||
1350 | if [ -e "$output" ]; then | ||
1351 | chmod +w "$output"; | ||
1352 | fi; | ||
1353 | substituteStream content "file '$input'" "$@" > "$output" | ||
1354 | } | ||
1355 | substituteAll () | ||
1356 | { | ||
1357 | local input="$1"; | ||
1358 | local output="$2"; | ||
1359 | local -a args=(); | ||
1360 | _allFlags; | ||
1361 | substitute "$input" "$output" "${args[@]}" | ||
1362 | } | ||
1363 | substituteAllInPlace () | ||
1364 | { | ||
1365 | local fileName="$1"; | ||
1366 | shift; | ||
1367 | substituteAll "$fileName" "$fileName" "$@" | ||
1368 | } | ||
1369 | substituteAllStream () | ||
1370 | { | ||
1371 | local -a args=(); | ||
1372 | _allFlags; | ||
1373 | substituteStream "$1" "$2" "${args[@]}" | ||
1374 | } | ||
1375 | substituteInPlace () | ||
1376 | { | ||
1377 | local fileName="$1"; | ||
1378 | shift; | ||
1379 | substitute "$fileName" "$fileName" "$@" | ||
1380 | } | ||
1381 | substituteStream () | ||
1382 | { | ||
1383 | local var=$1; | ||
1384 | local description=$2; | ||
1385 | shift 2; | ||
1386 | while (( "$#" )); do | ||
1387 | case "$1" in | ||
1388 | --replace) | ||
1389 | pattern="$2"; | ||
1390 | replacement="$3"; | ||
1391 | shift 3; | ||
1392 | local savedvar; | ||
1393 | savedvar="${!var}"; | ||
1394 | eval "$var"'=${'"$var"'//"$pattern"/"$replacement"}'; | ||
1395 | if [ "$pattern" != "$replacement" ]; then | ||
1396 | if [ "${!var}" == "$savedvar" ]; then | ||
1397 | echo "substituteStream(): WARNING: pattern '$pattern' doesn't match anything in $description" 1>&2; | ||
1398 | fi; | ||
1399 | fi | ||
1400 | ;; | ||
1401 | --subst-var) | ||
1402 | local varName="$2"; | ||
1403 | shift 2; | ||
1404 | if ! [[ "$varName" =~ ^[a-zA-Z_][a-zA-Z0-9_]*$ ]]; then | ||
1405 | echo "substituteStream(): ERROR: substitution variables must be valid Bash names, \"$varName\" isn't." 1>&2; | ||
1406 | return 1; | ||
1407 | fi; | ||
1408 | if [ -z ${!varName+x} ]; then | ||
1409 | echo "substituteStream(): ERROR: variable \$$varName is unset" 1>&2; | ||
1410 | return 1; | ||
1411 | fi; | ||
1412 | pattern="@$varName@"; | ||
1413 | replacement="${!varName}"; | ||
1414 | eval "$var"'=${'"$var"'//"$pattern"/"$replacement"}' | ||
1415 | ;; | ||
1416 | --subst-var-by) | ||
1417 | pattern="@$2@"; | ||
1418 | replacement="$3"; | ||
1419 | eval "$var"'=${'"$var"'//"$pattern"/"$replacement"}'; | ||
1420 | shift 3 | ||
1421 | ;; | ||
1422 | *) | ||
1423 | echo "substituteStream(): ERROR: Invalid command line argument: $1" 1>&2; | ||
1424 | return 1 | ||
1425 | ;; | ||
1426 | esac; | ||
1427 | done; | ||
1428 | printf "%s" "${!var}" | ||
1429 | } | ||
1430 | unpackFile () | ||
1431 | { | ||
1432 | curSrc="$1"; | ||
1433 | header "unpacking source archive $curSrc" 3; | ||
1434 | if ! runOneHook unpackCmd "$curSrc"; then | ||
1435 | echo "do not know how to unpack source archive $curSrc"; | ||
1436 | exit 1; | ||
1437 | fi | ||
1438 | } | ||
1439 | unpackPhase () | ||
1440 | { | ||
1441 | runHook preUnpack; | ||
1442 | if [ -z "${srcs:-}" ]; then | ||
1443 | if [ -z "${src:-}" ]; then | ||
1444 | echo 'variable $src or $srcs should point to the source'; | ||
1445 | exit 1; | ||
1446 | fi; | ||
1447 | srcs="$src"; | ||
1448 | fi; | ||
1449 | local dirsBefore=""; | ||
1450 | for i in *; | ||
1451 | do | ||
1452 | if [ -d "$i" ]; then | ||
1453 | dirsBefore="$dirsBefore $i "; | ||
1454 | fi; | ||
1455 | done; | ||
1456 | for i in $srcs; | ||
1457 | do | ||
1458 | unpackFile "$i"; | ||
1459 | done; | ||
1460 | : ${sourceRoot=}; | ||
1461 | if [ -n "${setSourceRoot:-}" ]; then | ||
1462 | runOneHook setSourceRoot; | ||
1463 | else | ||
1464 | if [ -z "$sourceRoot" ]; then | ||
1465 | for i in *; | ||
1466 | do | ||
1467 | if [ -d "$i" ]; then | ||
1468 | case $dirsBefore in | ||
1469 | *\ $i\ *) | ||
1470 | |||
1471 | ;; | ||
1472 | *) | ||
1473 | if [ -n "$sourceRoot" ]; then | ||
1474 | echo "unpacker produced multiple directories"; | ||
1475 | exit 1; | ||
1476 | fi; | ||
1477 | sourceRoot="$i" | ||
1478 | ;; | ||
1479 | esac; | ||
1480 | fi; | ||
1481 | done; | ||
1482 | fi; | ||
1483 | fi; | ||
1484 | if [ -z "$sourceRoot" ]; then | ||
1485 | echo "unpacker appears to have produced no directories"; | ||
1486 | exit 1; | ||
1487 | fi; | ||
1488 | echo "source root is $sourceRoot"; | ||
1489 | if [ "${dontMakeSourcesWritable:-0}" != 1 ]; then | ||
1490 | chmod -R u+w -- "$sourceRoot"; | ||
1491 | fi; | ||
1492 | runHook postUnpack | ||
1493 | } | ||
1494 | updateSourceDateEpoch () | ||
1495 | { | ||
1496 | local path="$1"; | ||
1497 | local -a res=($(find "$path" -type f -not -newer "$NIX_BUILD_TOP/.." -printf '%T@ %p\0' | sort -n --zero-terminated | tail -n1 --zero-terminated | head -c -1)); | ||
1498 | local time="${res[0]//\.[0-9]*/}"; | ||
1499 | local newestFile="${res[1]}"; | ||
1500 | if [ "${time:-0}" -gt "$SOURCE_DATE_EPOCH" ]; then | ||
1501 | echo "setting SOURCE_DATE_EPOCH to timestamp $time of file $newestFile"; | ||
1502 | export SOURCE_DATE_EPOCH="$time"; | ||
1503 | local now="$(date +%s)"; | ||
1504 | if [ "$time" -gt $((now - 60)) ]; then | ||
1505 | echo "warning: file $newestFile may be generated; SOURCE_DATE_EPOCH may be non-deterministic"; | ||
1506 | fi; | ||
1507 | fi | ||
1508 | } | ||
1509 | |||
1510 | export NIX_BUILD_TOP="$(mktemp -d --tmpdir nix-shell.XXXXXX)" | ||
1511 | export TMP="$NIX_BUILD_TOP" | ||
1512 | export TMPDIR="$NIX_BUILD_TOP" | ||
1513 | export TEMP="$NIX_BUILD_TOP" | ||
1514 | export TEMPDIR="$NIX_BUILD_TOP" | ||
1515 | eval "$shellHook" | ||
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore | |||
@@ -0,0 +1 @@ | |||
/target | |||
diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..4ab04ea --- /dev/null +++ b/Cargo.lock | |||
@@ -0,0 +1,61 @@ | |||
1 | # This file is automatically @generated by Cargo. | ||
2 | # It is not intended for manual editing. | ||
3 | [[package]] | ||
4 | name = "bitflags" | ||
5 | version = "1.2.1" | ||
6 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
7 | checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" | ||
8 | |||
9 | [[package]] | ||
10 | name = "cfg-if" | ||
11 | version = "0.1.10" | ||
12 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
13 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" | ||
14 | |||
15 | [[package]] | ||
16 | name = "lazy_static" | ||
17 | version = "1.4.0" | ||
18 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
19 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" | ||
20 | |||
21 | [[package]] | ||
22 | name = "libc" | ||
23 | version = "0.2.88" | ||
24 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
25 | checksum = "03b07a082330a35e43f63177cc01689da34fbffa0105e1246cf0311472cac73a" | ||
26 | |||
27 | [[package]] | ||
28 | name = "sdl-tests" | ||
29 | version = "0.1.0" | ||
30 | dependencies = [ | ||
31 | "sdl2", | ||
32 | ] | ||
33 | |||
34 | [[package]] | ||
35 | name = "sdl2" | ||
36 | version = "0.34.3" | ||
37 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
38 | checksum = "fcbb85f4211627a7291c83434d6bbfa723e28dcaa53c7606087e3c61929e4b9c" | ||
39 | dependencies = [ | ||
40 | "bitflags", | ||
41 | "lazy_static", | ||
42 | "libc", | ||
43 | "sdl2-sys", | ||
44 | ] | ||
45 | |||
46 | [[package]] | ||
47 | name = "sdl2-sys" | ||
48 | version = "0.34.3" | ||
49 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
50 | checksum = "28d81feded049b9c14eceb4a4f6d596a98cebbd59abdba949c5552a015466d33" | ||
51 | dependencies = [ | ||
52 | "cfg-if", | ||
53 | "libc", | ||
54 | "version-compare", | ||
55 | ] | ||
56 | |||
57 | [[package]] | ||
58 | name = "version-compare" | ||
59 | version = "0.0.10" | ||
60 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
61 | checksum = "d63556a25bae6ea31b52e640d7c41d1ab27faba4ccb600013837a3d0b3994ca1" | ||
diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..df04cd4 --- /dev/null +++ b/Cargo.toml | |||
@@ -0,0 +1,10 @@ | |||
1 | [package] | ||
2 | name = "sdl-tests" | ||
3 | version = "0.1.0" | ||
4 | authors = ["Akshay <[email protected]>"] | ||
5 | edition = "2018" | ||
6 | |||
7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
8 | |||
9 | [dependencies] | ||
10 | sdl2 = "0.34" | ||
diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..3bb4565 --- /dev/null +++ b/flake.lock | |||
@@ -0,0 +1,91 @@ | |||
1 | { | ||
2 | "nodes": { | ||
3 | "mozillapkgs": { | ||
4 | "flake": false, | ||
5 | "locked": { | ||
6 | "lastModified": 1603906276, | ||
7 | "narHash": "sha256-RsNPnEKd7BcogwkqhaV5kI/HuNC4flH/OQCC/4W5y/8=", | ||
8 | "owner": "mozilla", | ||
9 | "repo": "nixpkgs-mozilla", | ||
10 | "rev": "8c007b60731c07dd7a052cce508de3bb1ae849b4", | ||
11 | "type": "github" | ||
12 | }, | ||
13 | "original": { | ||
14 | "owner": "mozilla", | ||
15 | "repo": "nixpkgs-mozilla", | ||
16 | "type": "github" | ||
17 | } | ||
18 | }, | ||
19 | "naersk": { | ||
20 | "inputs": { | ||
21 | "nixpkgs": "nixpkgs" | ||
22 | }, | ||
23 | "locked": { | ||
24 | "lastModified": 1614785451, | ||
25 | "narHash": "sha256-TPw8kQvr2UNCuvndtY+EjyXp6Q5GEW2l9UafXXh1XmI=", | ||
26 | "owner": "nmattia", | ||
27 | "repo": "naersk", | ||
28 | "rev": "e0fe990b478a66178a58c69cf53daec0478ca6f9", | ||
29 | "type": "github" | ||
30 | }, | ||
31 | "original": { | ||
32 | "owner": "nmattia", | ||
33 | "repo": "naersk", | ||
34 | "type": "github" | ||
35 | } | ||
36 | }, | ||
37 | "nixpkgs": { | ||
38 | "locked": { | ||
39 | "lastModified": 1615043955, | ||
40 | "narHash": "sha256-foTwGGoArFbXdI9Pgq75is7WAqGM821dMsBuEqmSCtw=", | ||
41 | "owner": "NixOS", | ||
42 | "repo": "nixpkgs", | ||
43 | "rev": "d80850806d60e62c2a8189bc62e373a3facae442", | ||
44 | "type": "github" | ||
45 | }, | ||
46 | "original": { | ||
47 | "id": "nixpkgs", | ||
48 | "type": "indirect" | ||
49 | } | ||
50 | }, | ||
51 | "nixpkgs_2": { | ||
52 | "locked": { | ||
53 | "lastModified": 1615043955, | ||
54 | "narHash": "sha256-foTwGGoArFbXdI9Pgq75is7WAqGM821dMsBuEqmSCtw=", | ||
55 | "owner": "NixOS", | ||
56 | "repo": "nixpkgs", | ||
57 | "rev": "d80850806d60e62c2a8189bc62e373a3facae442", | ||
58 | "type": "github" | ||
59 | }, | ||
60 | "original": { | ||
61 | "id": "nixpkgs", | ||
62 | "type": "indirect" | ||
63 | } | ||
64 | }, | ||
65 | "root": { | ||
66 | "inputs": { | ||
67 | "mozillapkgs": "mozillapkgs", | ||
68 | "naersk": "naersk", | ||
69 | "nixpkgs": "nixpkgs_2", | ||
70 | "utils": "utils" | ||
71 | } | ||
72 | }, | ||
73 | "utils": { | ||
74 | "locked": { | ||
75 | "lastModified": 1614513358, | ||
76 | "narHash": "sha256-LakhOx3S1dRjnh0b5Dg3mbZyH0ToC9I8Y2wKSkBaTzU=", | ||
77 | "owner": "numtide", | ||
78 | "repo": "flake-utils", | ||
79 | "rev": "5466c5bbece17adaab2d82fae80b46e807611bf3", | ||
80 | "type": "github" | ||
81 | }, | ||
82 | "original": { | ||
83 | "owner": "numtide", | ||
84 | "repo": "flake-utils", | ||
85 | "type": "github" | ||
86 | } | ||
87 | } | ||
88 | }, | ||
89 | "root": "root", | ||
90 | "version": 7 | ||
91 | } | ||
diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..19aa50a --- /dev/null +++ b/flake.nix | |||
@@ -0,0 +1,54 @@ | |||
1 | { | ||
2 | inputs = { | ||
3 | utils.url = "github:numtide/flake-utils"; | ||
4 | naersk.url = "github:nmattia/naersk"; | ||
5 | mozillapkgs = { | ||
6 | url = "github:mozilla/nixpkgs-mozilla"; | ||
7 | flake = false; | ||
8 | }; | ||
9 | }; | ||
10 | |||
11 | outputs = { self, nixpkgs, utils, naersk, mozillapkgs }: | ||
12 | utils.lib.eachDefaultSystem (system: let | ||
13 | pkgs = nixpkgs.legacyPackages."${system}"; | ||
14 | |||
15 | # Get a specific rust version | ||
16 | mozilla = pkgs.callPackage (mozillapkgs + "/package-set.nix") {}; | ||
17 | rust = (mozilla.rustChannelOf { | ||
18 | date = "2020-12-23"; | ||
19 | channel = "nightly"; | ||
20 | sha256 = "LbKHsCOFXWpg/SEyACfzZuWjKbkXdH6EJKOPSGoO01E="; # set zeros after modifying channel or date | ||
21 | }).rust; | ||
22 | rust-src = (mozilla.rustChannelOf { | ||
23 | date = "2020-12-23"; | ||
24 | channel = "nightly"; | ||
25 | sha256 = "LbKHsCOFXWpg/SEyACfzZuWjKbkXdH6EJKOPSGoO01E="; # set zeros after modifying channel or date | ||
26 | }).rust-src; | ||
27 | |||
28 | naersk-lib = naersk.lib."${system}".override { | ||
29 | cargo = rust; | ||
30 | rustc = rust; | ||
31 | }; | ||
32 | in rec { | ||
33 | packages.my-project = naersk-lib.buildPackage { | ||
34 | pname = "sdl-tests"; | ||
35 | version = "0.1.0"; | ||
36 | root = ./.; | ||
37 | }; | ||
38 | defaultPackage = packages.my-project; | ||
39 | apps.my-project = utils.lib.mkApp { | ||
40 | drv = packages.my-project; | ||
41 | }; | ||
42 | defaultApp = apps.my-project; | ||
43 | devShell = pkgs.mkShell { | ||
44 | nativeBuildInputs = [ | ||
45 | rust | ||
46 | rust-src | ||
47 | pkgs.rust-analyzer | ||
48 | pkgs.cargo | ||
49 | pkgs.SDL2 | ||
50 | ]; | ||
51 | RUST_SRC_PATH = "${pkgs.rust.packages.stable.rustPlatform.rustLibSrc}"; | ||
52 | }; | ||
53 | }); | ||
54 | } | ||
diff --git a/src/app.rs b/src/app.rs new file mode 100644 index 0000000..84d884f --- /dev/null +++ b/src/app.rs | |||
@@ -0,0 +1,447 @@ | |||
1 | use crate::undo::{ModifyRecord, OpKind, Operation, UndoStack}; | ||
2 | |||
3 | use sdl2::{ | ||
4 | event::Event, | ||
5 | keyboard::Keycode, | ||
6 | mouse::MouseButton, | ||
7 | pixels::Color, | ||
8 | rect::{Point, Rect}, | ||
9 | render::Canvas, | ||
10 | video::Window, | ||
11 | Sdl, | ||
12 | }; | ||
13 | |||
14 | use crate::consts::{BLACK, GRID_COLOR, WHITE}; | ||
15 | |||
16 | pub struct AppState<'ctx> { | ||
17 | start: Point, | ||
18 | width: u32, | ||
19 | height: u32, | ||
20 | data: Vec<bool>, | ||
21 | zoom: u8, | ||
22 | brush_size: u8, | ||
23 | grid: Grid, | ||
24 | context: &'ctx Sdl, | ||
25 | canvas: Canvas<Window>, | ||
26 | last_point: Option<Point>, | ||
27 | active_color: bool, | ||
28 | undo_stack: UndoStack<Operation>, | ||
29 | current_operation: Operation, | ||
30 | } | ||
31 | |||
32 | struct Grid { | ||
33 | enabled: bool, | ||
34 | color: Color, | ||
35 | } | ||
36 | |||
37 | impl Grid { | ||
38 | fn new() -> Self { | ||
39 | Self { | ||
40 | enabled: true, | ||
41 | color: GRID_COLOR, | ||
42 | } | ||
43 | } | ||
44 | } | ||
45 | |||
46 | // private actions on appstate | ||
47 | impl<'ctx> AppState<'ctx> { | ||
48 | fn pan<P: Into<Point>>(&mut self, direction: P) { | ||
49 | self.start += direction.into(); | ||
50 | } | ||
51 | |||
52 | fn bounds(&self) -> (Point, Point) { | ||
53 | let x_min = self.start.x(); | ||
54 | let y_min = self.start.y(); | ||
55 | let x_max = self.start.x() + (self.width * self.zoom as u32) as i32; | ||
56 | let y_max = self.start.y() + (self.height * self.zoom as u32) as i32; | ||
57 | return ( | ||
58 | Point::new(x_min, y_min), | ||
59 | Point::new(x_max as i32, y_max as i32), | ||
60 | ); | ||
61 | } | ||
62 | |||
63 | fn change_active_color(&mut self) { | ||
64 | self.active_color = !self.active_color; | ||
65 | } | ||
66 | |||
67 | fn idx_at_coord<P: Into<Point>>(&self, p: P) -> Option<(u32, u32)> { | ||
68 | let p: Point = p.into(); | ||
69 | if self.within_canvas(p) { | ||
70 | // convert p relative to start of drawing area | ||
71 | let rel_p = p - self.start; | ||
72 | // reduce p based on zoom and cell size | ||
73 | let (sx, sy) = (rel_p.x() / self.zoom as i32, rel_p.y() / self.zoom as i32); | ||
74 | return Some((sx as u32, sy as u32)); | ||
75 | } else { | ||
76 | None | ||
77 | } | ||
78 | } | ||
79 | |||
80 | fn within_canvas<P: Into<Point>>(&self, p: P) -> bool { | ||
81 | let p: Point = p.into(); | ||
82 | let (mini, maxi) = self.bounds(); | ||
83 | p.x() < maxi.x() && p.y() < maxi.y() && p.x() >= mini.x() && p.y() >= mini.y() | ||
84 | } | ||
85 | |||
86 | fn within_grid<P: Into<Point>>(&self, p: P) -> bool { | ||
87 | let p = p.into(); | ||
88 | let (x, y) = (p.x(), p.y()); | ||
89 | x >= 0 && x < self.width as i32 && y >= 0 && y < self.height as i32 | ||
90 | } | ||
91 | |||
92 | fn set_at<P: Into<Point>>(&mut self, p: P, val: bool) -> Result<ModifyRecord, ()> { | ||
93 | let p: Point = p.into(); | ||
94 | if let Some((x, y)) = self.idx_at_coord(p) { | ||
95 | let old_val = self.data[(y * self.width + x) as usize]; | ||
96 | self.data[(y * self.width + x) as usize] = val; | ||
97 | return Ok(ModifyRecord::new((x as i32, y as i32), old_val, val)); | ||
98 | } | ||
99 | return Err(()); | ||
100 | } | ||
101 | |||
102 | fn set_with_absolute<P: Into<Point>>(&mut self, p: P, val: bool) -> Result<ModifyRecord, ()> { | ||
103 | let p: Point = p.into(); | ||
104 | let (x, y) = (p.x(), p.y()); | ||
105 | if self.within_grid(p) { | ||
106 | let idx = y as u32 * self.width + x as u32; | ||
107 | let old_val = self.data[idx as usize]; | ||
108 | self.data[idx as usize] = val; | ||
109 | return Ok(ModifyRecord::new((x as i32, y as i32), old_val, val)); | ||
110 | } | ||
111 | return Err(()); | ||
112 | } | ||
113 | |||
114 | fn toggle_grid(&mut self) { | ||
115 | self.grid.enabled = !self.grid.enabled; | ||
116 | } | ||
117 | |||
118 | fn paint_point<P: Into<Point>>( | ||
119 | &mut self, | ||
120 | center: P, | ||
121 | val: bool, | ||
122 | ) -> Result<Vec<ModifyRecord>, ()> { | ||
123 | let radius = self.brush_size; | ||
124 | if radius == 1 { | ||
125 | return Ok(self.set_at(center, val).map(|x| vec![x])?); | ||
126 | } else { | ||
127 | if let Some(center_on_grid) = self.idx_at_coord(center) { | ||
128 | // center_on_grid is now a coordinate on the drawing grid | ||
129 | let (x0, y0) = (center_on_grid.0 as i64, center_on_grid.1 as i64); | ||
130 | let (mut dx, mut dy, mut err) = (radius as i64, 0i64, 1 - radius as i64); | ||
131 | let mut circle = vec![]; | ||
132 | let mut old_vals = vec![]; | ||
133 | while dx >= dy { | ||
134 | circle.push((x0 + dx, y0 + dy)); | ||
135 | circle.push((x0 - dx, y0 + dy)); | ||
136 | circle.push((x0 + dx, y0 - dy)); | ||
137 | circle.push((x0 - dx, y0 - dy)); | ||
138 | circle.push((x0 + dy, y0 + dx)); | ||
139 | circle.push((x0 - dy, y0 + dx)); | ||
140 | circle.push((x0 + dy, y0 - dx)); | ||
141 | circle.push((x0 - dy, y0 - dx)); | ||
142 | dy = dy + 1; | ||
143 | if err < 0 { | ||
144 | err = err + 2 * dy + 1; | ||
145 | } else { | ||
146 | dx -= 1; | ||
147 | err += 2 * (dy - dx) + 1; | ||
148 | } | ||
149 | } | ||
150 | // circle's insides | ||
151 | for x in 0..radius as i64 { | ||
152 | for y in 0..radius as i64 { | ||
153 | if x.pow(2) + y.pow(2) < (radius as i64).pow(2) { | ||
154 | circle.push((x0 + x, y0 + y)); | ||
155 | circle.push((x0 - x, y0 + y)); | ||
156 | circle.push((x0 + x, y0 - y)); | ||
157 | circle.push((x0 - x, y0 - y)); | ||
158 | } | ||
159 | } | ||
160 | } | ||
161 | dbg!(&circle); | ||
162 | for (x, y) in circle { | ||
163 | if self.within_grid((x as i32, y as i32)) { | ||
164 | let idx = y as u32 * self.width + x as u32; | ||
165 | old_vals.push(ModifyRecord::new( | ||
166 | (x as i32, y as i32), | ||
167 | self.data[idx as usize], | ||
168 | val, | ||
169 | )); | ||
170 | self.data[idx as usize] = val; | ||
171 | } | ||
172 | } | ||
173 | return Ok(old_vals); | ||
174 | } | ||
175 | } | ||
176 | return Err(()); | ||
177 | } | ||
178 | |||
179 | fn draw_line<P: Into<Point>>(&mut self, to: P) { | ||
180 | let to = to.into(); | ||
181 | let from = self.last_point.unwrap_or(to.into()); | ||
182 | } | ||
183 | |||
184 | fn apply_operation(&mut self, op: Operation, op_kind: OpKind) -> Result<(), ()> { | ||
185 | for ModifyRecord { | ||
186 | point, | ||
187 | old_val, | ||
188 | val, | ||
189 | } in op.into_iter() | ||
190 | { | ||
191 | self.set_with_absolute( | ||
192 | point, | ||
193 | match op_kind { | ||
194 | OpKind::Undo => old_val, | ||
195 | OpKind::Redo => val, | ||
196 | }, | ||
197 | )?; | ||
198 | } | ||
199 | Ok(()) | ||
200 | } | ||
201 | |||
202 | fn zoom_in(&mut self, p: (i32, i32)) { | ||
203 | // attempt to center around cursor | ||
204 | if let Some(p) = self.idx_at_coord(p) { | ||
205 | let (x1, y1) = (p.0 * (self.zoom as u32), p.1 * (self.zoom as u32)); | ||
206 | let (x2, y2) = (p.0 * (1 + self.zoom as u32), p.1 * (1 + self.zoom as u32)); | ||
207 | let diffx = x2 as i32 - x1 as i32; | ||
208 | let diffy = y2 as i32 - y1 as i32; | ||
209 | self.start = self.start - Point::from((diffx, diffy)); | ||
210 | } | ||
211 | self.zoom += 1; | ||
212 | } | ||
213 | |||
214 | fn increase_brush_size(&mut self) { | ||
215 | self.brush_size += 1; | ||
216 | } | ||
217 | |||
218 | fn descrease_brush_size(&mut self) { | ||
219 | if self.brush_size > 1 { | ||
220 | self.brush_size -= 1; | ||
221 | } | ||
222 | } | ||
223 | |||
224 | fn zoom_out(&mut self, p: (i32, i32)) { | ||
225 | if self.zoom > 1 { | ||
226 | // attempt to center around cursor | ||
227 | if let Some(p) = self.idx_at_coord(p) { | ||
228 | let (x1, y1) = (p.0 * (self.zoom as u32), p.1 * (self.zoom as u32)); | ||
229 | let (x2, y2) = (p.0 * (self.zoom as u32 - 1), p.1 * (self.zoom as u32 - 1)); | ||
230 | let diffx = x2 as i32 - x1 as i32; | ||
231 | let diffy = y2 as i32 - y1 as i32; | ||
232 | self.start = self.start - Point::from((diffx, diffy)); | ||
233 | } | ||
234 | self.zoom -= 1; | ||
235 | } | ||
236 | } | ||
237 | |||
238 | fn draw_grid(&mut self) { | ||
239 | let cs = self.zoom as u32; | ||
240 | let canvas = &mut self.canvas; | ||
241 | canvas.set_draw_color(self.grid.color); | ||
242 | for i in 0..=self.width { | ||
243 | let x = (i * cs) as i32; | ||
244 | let y = (self.height * cs) as i32; | ||
245 | let start = self.start + Point::new(x, 0); | ||
246 | let end = self.start + Point::new(x, y); | ||
247 | canvas.draw_line(start, end).unwrap(); | ||
248 | } | ||
249 | for j in 0..=self.height { | ||
250 | let x = (self.width * cs) as i32; | ||
251 | let y = (j * cs) as i32; | ||
252 | let start = self.start + Point::new(0, y); | ||
253 | let end = self.start + Point::new(x, y); | ||
254 | canvas.draw_line(start, end).unwrap(); | ||
255 | } | ||
256 | } | ||
257 | |||
258 | fn draw(&mut self) { | ||
259 | let cs = self.zoom as u32; | ||
260 | if self.grid.enabled { | ||
261 | self.draw_grid(); | ||
262 | } | ||
263 | let canvas = &mut self.canvas; | ||
264 | for (idx, val) in self.data.iter().enumerate() { | ||
265 | if *val { | ||
266 | let idx = idx as i32; | ||
267 | let (x, y) = (idx % self.width as i32, idx / self.height as i32); | ||
268 | canvas.set_draw_color(WHITE); | ||
269 | canvas | ||
270 | .fill_rect(Rect::new( | ||
271 | // start drawing 1 pixel after the grid line | ||
272 | x * cs as i32 + self.start.x() + 1, | ||
273 | y * cs as i32 + self.start.y() + 1, | ||
274 | // stop drawing 1 pixel before the grid line | ||
275 | cs - 1, | ||
276 | cs - 1, | ||
277 | )) | ||
278 | .unwrap(); | ||
279 | } | ||
280 | } | ||
281 | } | ||
282 | |||
283 | fn modify<F>(&mut self, func: F) | ||
284 | where | ||
285 | F: FnOnce(&mut Self), | ||
286 | { | ||
287 | func(self); | ||
288 | self.canvas.set_draw_color(Color::RGB(0, 0, 0)); | ||
289 | self.canvas.clear(); | ||
290 | self.canvas.set_draw_color(Color::RGB(64, 64, 64)); | ||
291 | self.draw(); | ||
292 | self.canvas.present(); | ||
293 | } | ||
294 | } | ||
295 | |||
296 | // publicly available functions on appstate | ||
297 | impl<'ctx> AppState<'ctx> { | ||
298 | pub fn init(width: u32, height: u32, context: &'ctx Sdl) -> Self { | ||
299 | let video_subsystem = context.video().unwrap(); | ||
300 | |||
301 | let window = video_subsystem | ||
302 | .window("Pixel editor", 200, 200) | ||
303 | .position_centered() | ||
304 | .opengl() | ||
305 | .build() | ||
306 | .map_err(|e| e.to_string()) | ||
307 | .unwrap(); | ||
308 | |||
309 | let canvas = window | ||
310 | .into_canvas() | ||
311 | .build() | ||
312 | .map_err(|e| e.to_string()) | ||
313 | .unwrap(); | ||
314 | |||
315 | let data = vec![false; (width * height) as usize]; | ||
316 | Self { | ||
317 | start: Point::new(60, 60), | ||
318 | width, | ||
319 | height, | ||
320 | data, | ||
321 | zoom: 5, | ||
322 | brush_size: 1, | ||
323 | grid: Grid::new(), | ||
324 | canvas, | ||
325 | context, | ||
326 | last_point: None, | ||
327 | active_color: true, | ||
328 | undo_stack: UndoStack::new(), | ||
329 | current_operation: Vec::new(), | ||
330 | } | ||
331 | } | ||
332 | |||
333 | pub fn run(&mut self) { | ||
334 | self.canvas.set_draw_color(BLACK); | ||
335 | self.canvas.clear(); | ||
336 | self.draw(); | ||
337 | self.canvas.present(); | ||
338 | |||
339 | let mut event_pump = self.context.event_pump().unwrap(); | ||
340 | |||
341 | 'running: loop { | ||
342 | let mouse = event_pump.mouse_state(); | ||
343 | for event in event_pump.poll_iter() { | ||
344 | match event { | ||
345 | Event::KeyDown { | ||
346 | keycode: Some(k), .. | ||
347 | } => { | ||
348 | match k { | ||
349 | // pan | ||
350 | Keycode::W => self.modify(|e| e.pan((0, 10))), | ||
351 | Keycode::A => self.modify(|e| e.pan((10, 0))), | ||
352 | Keycode::S => self.modify(|e| e.pan((0, -10))), | ||
353 | Keycode::D => self.modify(|e| e.pan((-10, 0))), | ||
354 | // zoom | ||
355 | Keycode::C => { | ||
356 | let cursor = (mouse.x(), mouse.y()); | ||
357 | self.modify(|e| e.zoom_in(cursor)); | ||
358 | } | ||
359 | Keycode::Z => { | ||
360 | let cursor = (mouse.x(), mouse.y()); | ||
361 | self.modify(|e| e.zoom_out(cursor)); | ||
362 | } | ||
363 | // brush ops | ||
364 | Keycode::Q => self.modify(|e| e.descrease_brush_size()), | ||
365 | Keycode::E => self.modify(|e| e.increase_brush_size()), | ||
366 | // flip color | ||
367 | Keycode::X => self.modify(|e| e.change_active_color()), | ||
368 | // toggle grid | ||
369 | Keycode::Tab => self.modify(|e| e.toggle_grid()), | ||
370 | // exit | ||
371 | Keycode::Escape => break 'running, | ||
372 | // undo & redo | ||
373 | Keycode::U => self.modify(|e| { | ||
374 | if let Some(op) = e.undo_stack.undo() { | ||
375 | e.apply_operation(op, OpKind::Undo); | ||
376 | } | ||
377 | }), | ||
378 | Keycode::R => self.modify(|e| { | ||
379 | if let Some(op) = e.undo_stack.redo() { | ||
380 | e.apply_operation(op, OpKind::Redo); | ||
381 | } | ||
382 | }), | ||
383 | _ => (), | ||
384 | } | ||
385 | } | ||
386 | // start of operation | ||
387 | Event::MouseButtonDown { | ||
388 | x, y, mouse_btn, .. | ||
389 | } => { | ||
390 | self.modify(|e| { | ||
391 | let pt = (x, y); | ||
392 | e.last_point = Some(pt.into()); | ||
393 | let val = match mouse_btn { | ||
394 | MouseButton::Right => !e.active_color, | ||
395 | _ => e.active_color, | ||
396 | }; | ||
397 | if let Ok(o) = e.paint_point(pt, val) { | ||
398 | e.current_operation.extend(o); | ||
399 | } | ||
400 | }); | ||
401 | } | ||
402 | // click and drag | ||
403 | Event::MouseMotion { | ||
404 | x, y, mousestate, .. | ||
405 | } => { | ||
406 | let is_left = mousestate.is_mouse_button_pressed(MouseButton::Left); | ||
407 | let is_right = mousestate.is_mouse_button_pressed(MouseButton::Right); | ||
408 | if is_left { | ||
409 | self.modify(|e| { | ||
410 | let pt = (x, y); | ||
411 | let val = e.active_color; | ||
412 | if let Ok(o) = e.paint_point(pt, val) { | ||
413 | e.current_operation.extend(o); | ||
414 | } | ||
415 | }); | ||
416 | } else if is_right { | ||
417 | self.modify(|e| { | ||
418 | let pt = (x, y); | ||
419 | let val = !e.active_color; | ||
420 | if let Ok(o) = e.paint_point(pt, val) { | ||
421 | e.current_operation.extend(o); | ||
422 | } | ||
423 | }); | ||
424 | } | ||
425 | } | ||
426 | // end of operation | ||
427 | Event::MouseButtonUp { .. } => self.modify(|e| { | ||
428 | dbg!(&e.current_operation.len()); | ||
429 | let op = e | ||
430 | .current_operation | ||
431 | .drain(..) | ||
432 | .filter(|v| !v.old_val == v.val) | ||
433 | .collect::<Vec<_>>(); | ||
434 | e.undo_stack.push(op); | ||
435 | dbg!(&e.undo_stack); | ||
436 | }), | ||
437 | Event::Quit { .. } => { | ||
438 | break 'running; | ||
439 | } | ||
440 | _ => { | ||
441 | self.modify(|_| ()); | ||
442 | } | ||
443 | } | ||
444 | } | ||
445 | } | ||
446 | } | ||
447 | } | ||
diff --git a/src/consts.rs b/src/consts.rs new file mode 100644 index 0000000..b5cea43 --- /dev/null +++ b/src/consts.rs | |||
@@ -0,0 +1,6 @@ | |||
1 | use sdl2::pixels::Color; | ||
2 | |||
3 | pub const GRID_COLOR: Color = Color::RGB(64, 64, 64); | ||
4 | pub const WHITE: Color = Color::RGB(255, 255, 255); | ||
5 | pub const BLACK: Color = Color::RGB(0, 0, 0); | ||
6 | |||
diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..bf89508 --- /dev/null +++ b/src/main.rs | |||
@@ -0,0 +1,10 @@ | |||
1 | mod app; | ||
2 | mod consts; | ||
3 | mod undo; | ||
4 | |||
5 | use app::AppState; | ||
6 | |||
7 | pub fn main() { | ||
8 | let sdl_context = sdl2::init().unwrap(); | ||
9 | AppState::init(100, 100, &sdl_context).run(); | ||
10 | } | ||
diff --git a/src/undo.rs b/src/undo.rs new file mode 100644 index 0000000..2249fe7 --- /dev/null +++ b/src/undo.rs | |||
@@ -0,0 +1,133 @@ | |||
1 | #[derive(Copy, Clone, Debug)] | ||
2 | pub struct ModifyRecord { | ||
3 | pub point: (i32, i32), | ||
4 | pub old_val: bool, | ||
5 | pub val: bool, | ||
6 | } | ||
7 | |||
8 | impl ModifyRecord { | ||
9 | pub fn new(point: (i32, i32), old_val: bool, val: bool) -> Self { | ||
10 | ModifyRecord { | ||
11 | point, | ||
12 | old_val, | ||
13 | val, | ||
14 | } | ||
15 | } | ||
16 | } | ||
17 | |||
18 | pub enum OpKind { | ||
19 | Undo, | ||
20 | Redo, | ||
21 | } | ||
22 | |||
23 | pub type Operation = Vec<ModifyRecord>; | ||
24 | |||
25 | #[derive(Debug)] | ||
26 | pub struct UndoStack<T> { | ||
27 | operations: Vec<T>, | ||
28 | position: Option<u32>, | ||
29 | } | ||
30 | |||
31 | impl<T> UndoStack<T> | ||
32 | where | ||
33 | T: Clone, | ||
34 | { | ||
35 | pub fn new() -> Self { | ||
36 | Self { | ||
37 | operations: Vec::with_capacity(64), | ||
38 | position: None, | ||
39 | } | ||
40 | } | ||
41 | |||
42 | pub fn push(&mut self, op: T) { | ||
43 | if let Some(p) = self.position { | ||
44 | // remove all operations past the newly pushed operation | ||
45 | for _ in 1 + (p as usize)..self.operations.len() { | ||
46 | self.operations.pop(); | ||
47 | } | ||
48 | // advance position | ||
49 | self.position = Some(p + 1); | ||
50 | // add new operation | ||
51 | self.operations.push(op); | ||
52 | } else { | ||
53 | // empty ops list or undone till start of stack | ||
54 | // remove all operations past the newly pushed operation | ||
55 | self.operations.clear(); | ||
56 | // advance position | ||
57 | self.position = Some(0); | ||
58 | // add new operation | ||
59 | self.operations.push(op); | ||
60 | } | ||
61 | } | ||
62 | |||
63 | pub fn undo(&mut self) -> Option<T> { | ||
64 | if let Some(p) = self.position { | ||
65 | self.position = p.checked_sub(1); | ||
66 | // we want to return a clone and not a reference because push deletes the item | ||
67 | return Some(self.operations[p as usize].clone()); | ||
68 | } | ||
69 | return None; | ||
70 | } | ||
71 | |||
72 | pub fn redo(&mut self) -> Option<T> { | ||
73 | if let Some(p) = self.position { | ||
74 | if p < self.operations.len() as u32 - 1 { | ||
75 | self.position = Some(p + 1); | ||
76 | return Some(self.operations[1 + p as usize].clone()); | ||
77 | } | ||
78 | } else if !self.operations.is_empty() { | ||
79 | self.position = Some(0); | ||
80 | return Some(self.operations[0].clone()); | ||
81 | } | ||
82 | return None; | ||
83 | } | ||
84 | } | ||
85 | |||
86 | #[cfg(test)] | ||
87 | mod tests { | ||
88 | use super::*; | ||
89 | |||
90 | fn setup() -> UndoStack<u32> { | ||
91 | let mut stack = UndoStack::new(); | ||
92 | stack.push(10); | ||
93 | stack.push(5); | ||
94 | stack.push(2); | ||
95 | stack | ||
96 | } | ||
97 | |||
98 | #[test] | ||
99 | fn undo_works() { | ||
100 | let mut stack = setup(); | ||
101 | assert_eq!(stack.undo(), Some(2)); | ||
102 | assert_eq!(stack.undo(), Some(5)); | ||
103 | assert_eq!(stack.undo(), Some(10)); | ||
104 | } | ||
105 | #[test] | ||
106 | fn redo_works() { | ||
107 | let mut stack = setup(); | ||
108 | stack.undo(); | ||
109 | stack.undo(); | ||
110 | stack.undo(); | ||
111 | assert_eq!(stack.redo(), Some(10)); | ||
112 | assert_eq!(stack.redo(), Some(5)); | ||
113 | assert_eq!(stack.redo(), Some(2)); | ||
114 | } | ||
115 | |||
116 | #[test] | ||
117 | fn undo_push_redo() { | ||
118 | let mut stack = setup(); | ||
119 | stack.undo(); | ||
120 | stack.push(16); | ||
121 | assert_eq!(stack.redo(), None); | ||
122 | assert_eq!(stack.undo(), Some(16)); | ||
123 | } | ||
124 | |||
125 | #[test] | ||
126 | fn stack_identity() { | ||
127 | let mut stack = setup(); | ||
128 | stack.undo(); | ||
129 | stack.redo(); | ||
130 | stack.undo(); | ||
131 | assert_eq!(stack.operations, setup().operations); | ||
132 | } | ||
133 | } | ||