summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.cargo/config.toml2
-rw-r--r--Cargo.lock368
-rw-r--r--xtask/Cargo.toml10
-rw-r--r--xtask/src/lib.rs20
-rw-r--r--xtask/src/main.rs3
-rw-r--r--xtask/src/release.rs174
-rw-r--r--xtask/src/release/version.rs302
7 files changed, 862 insertions, 17 deletions
diff --git a/.cargo/config.toml b/.cargo/config.toml
index 35049cb..8c7aa77 100644
--- a/.cargo/config.toml
+++ b/.cargo/config.toml
@@ -1,2 +1,2 @@
[alias]
-xtask = "run --package xtask --"
+xtask = "run --config profile.dev.debug=false --package xtask --"
diff --git a/Cargo.lock b/Cargo.lock
index 2bdcb0a..150534b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -27,6 +27,21 @@ dependencies = [
]
[[package]]
+name = "android-tzdata"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
+
+[[package]]
+name = "android_system_properties"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
+dependencies = [
+ "libc",
+]
+
+[[package]]
name = "anstream"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -62,7 +77,7 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
dependencies = [
- "windows-sys",
+ "windows-sys 0.48.0",
]
[[package]]
@@ -72,7 +87,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188"
dependencies = [
"anstyle",
- "windows-sys",
+ "windows-sys 0.48.0",
]
[[package]]
@@ -82,6 +97,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
[[package]]
+name = "autocfg"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
+
+[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -89,6 +110,17 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bstr"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"
+dependencies = [
+ "lazy_static",
+ "memchr",
+ "regex-automata",
+]
+
+[[package]]
+name = "bstr"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3d4260bcc2e8fc9df1eac4919a720effeb63a3f0952f5bf4944adfa18897f09"
@@ -98,6 +130,12 @@ dependencies = [
]
[[package]]
+name = "bumpalo"
+version = "3.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
+
+[[package]]
name = "cc"
version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -113,6 +151,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
+name = "chrono"
+version = "0.4.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5"
+dependencies = [
+ "android-tzdata",
+ "iana-time-zone",
+ "num-traits",
+ "winapi",
+]
+
+[[package]]
name = "clap"
version = "4.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -180,6 +230,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
+name = "console"
+version = "0.15.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8"
+dependencies = [
+ "encode_unicode",
+ "lazy_static",
+ "libc",
+ "windows-sys 0.45.0",
+]
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
+
+[[package]]
name = "crc32fast"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -189,6 +257,12 @@ dependencies = [
]
[[package]]
+name = "encode_unicode"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
+
+[[package]]
name = "errno"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -196,7 +270,7 @@ checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
dependencies = [
"errno-dragonfly",
"libc",
- "windows-sys",
+ "windows-sys 0.48.0",
]
[[package]]
@@ -218,7 +292,7 @@ dependencies = [
"cfg-if",
"libc",
"redox_syscall",
- "windows-sys",
+ "windows-sys 0.48.0",
]
[[package]]
@@ -266,13 +340,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc"
dependencies = [
"aho-corasick 0.7.20",
- "bstr",
+ "bstr 1.4.0",
"fnv",
"log",
"regex",
]
[[package]]
+name = "hashbrown"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
+
+[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -285,6 +365,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
[[package]]
+name = "iana-time-zone"
+version = "0.1.56"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c"
+dependencies = [
+ "android_system_properties",
+ "core-foundation-sys",
+ "iana-time-zone-haiku",
+ "js-sys",
+ "wasm-bindgen",
+ "windows",
+]
+
+[[package]]
+name = "iana-time-zone-haiku"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
+dependencies = [
+ "cc",
+]
+
+[[package]]
name = "idna"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -312,6 +415,16 @@ dependencies = [
]
[[package]]
+name = "indexmap"
+version = "1.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
+dependencies = [
+ "autocfg",
+ "hashbrown",
+]
+
+[[package]]
name = "io-lifetimes"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -319,7 +432,7 @@ checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220"
dependencies = [
"hermit-abi",
"libc",
- "windows-sys",
+ "windows-sys 0.48.0",
]
[[package]]
@@ -331,7 +444,7 @@ dependencies = [
"hermit-abi",
"io-lifetimes",
"rustix",
- "windows-sys",
+ "windows-sys 0.48.0",
]
[[package]]
@@ -344,6 +457,15 @@ dependencies = [
]
[[package]]
+name = "js-sys"
+version = "0.3.63"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790"
+dependencies = [
+ "wasm-bindgen",
+]
+
+[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -429,6 +551,15 @@ dependencies = [
]
[[package]]
+name = "num-traits"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
name = "once_cell"
version = "1.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -548,7 +679,7 @@ dependencies = [
"io-lifetimes",
"libc",
"linux-raw-sys",
- "windows-sys",
+ "windows-sys 0.48.0",
]
[[package]]
@@ -561,12 +692,27 @@ dependencies = [
]
[[package]]
+name = "semver"
+version = "1.0.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
+
+[[package]]
name = "serde"
version = "1.0.163"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2"
[[package]]
+name = "serde_spanned"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93107647184f6027e3b7dcb2e11034cf95ffa1e3a682c67951963ac69c1c007d"
+dependencies = [
+ "serde",
+]
+
+[[package]]
name = "sharded-slab"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -576,6 +722,26 @@ dependencies = [
]
[[package]]
+name = "similar"
+version = "2.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "420acb44afdae038210c99e69aae24109f32f15500aa708e81d46c9f29d55fcf"
+dependencies = [
+ "bstr 0.2.17",
+ "unicode-segmentation",
+]
+
+[[package]]
+name = "similar-asserts"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbf644ad016b75129f01a34a355dcb8d66a5bc803e417c7a77cc5d5ee9fa0f18"
+dependencies = [
+ "console",
+ "similar",
+]
+
+[[package]]
name = "smallvec"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -635,6 +801,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
+name = "toml_datetime"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "toml_edit"
+version = "0.19.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2380d56e8670370eee6566b0bfd4265f65b3f432e8c6d85623f728d4fa31f739"
+dependencies = [
+ "indexmap",
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "winnow",
+]
+
+[[package]]
name = "tracing"
version = "0.1.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -718,6 +906,12 @@ dependencies = [
]
[[package]]
+name = "unicode-segmentation"
+version = "1.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
+
+[[package]]
name = "url"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -757,6 +951,60 @@ dependencies = [
]
[[package]]
+name = "wasm-bindgen"
+version = "0.2.86"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73"
+dependencies = [
+ "cfg-if",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.86"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb"
+dependencies = [
+ "bumpalo",
+ "log",
+ "once_cell",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.86"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.86"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.86"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93"
+
+[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -788,12 +1036,45 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
+name = "windows"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
+dependencies = [
+ "windows-targets 0.48.0",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.45.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
+dependencies = [
+ "windows-targets 0.42.2",
+]
+
+[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
- "windows-targets",
+ "windows-targets 0.48.0",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
+dependencies = [
+ "windows_aarch64_gnullvm 0.42.2",
+ "windows_aarch64_msvc 0.42.2",
+ "windows_i686_gnu 0.42.2",
+ "windows_i686_msvc 0.42.2",
+ "windows_x86_64_gnu 0.42.2",
+ "windows_x86_64_gnullvm 0.42.2",
+ "windows_x86_64_msvc 0.42.2",
]
[[package]]
@@ -802,58 +1083,109 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
dependencies = [
- "windows_aarch64_gnullvm",
- "windows_aarch64_msvc",
- "windows_i686_gnu",
- "windows_i686_msvc",
- "windows_x86_64_gnu",
- "windows_x86_64_gnullvm",
- "windows_x86_64_msvc",
+ "windows_aarch64_gnullvm 0.48.0",
+ "windows_aarch64_msvc 0.48.0",
+ "windows_i686_gnu 0.48.0",
+ "windows_i686_msvc 0.48.0",
+ "windows_x86_64_gnu 0.48.0",
+ "windows_x86_64_gnullvm 0.48.0",
+ "windows_x86_64_msvc 0.48.0",
]
[[package]]
name = "windows_aarch64_gnullvm"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
+
+[[package]]
+name = "windows_aarch64_gnullvm"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
[[package]]
name = "windows_aarch64_msvc"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
+
+[[package]]
+name = "windows_aarch64_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
[[package]]
name = "windows_i686_gnu"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
+
+[[package]]
+name = "windows_i686_gnu"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
[[package]]
name = "windows_i686_msvc"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
+
+[[package]]
+name = "windows_i686_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
[[package]]
name = "windows_x86_64_gnu"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
+
+[[package]]
+name = "windows_x86_64_gnu"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
[[package]]
name = "windows_x86_64_gnullvm"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
[[package]]
name = "windows_x86_64_msvc"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
+
+[[package]]
+name = "windows_x86_64_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
[[package]]
+name = "winnow"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61de7bac303dc551fe038e2b3cef0f571087a47571ea6e79a87692ac99b99699"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
name = "xattr"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -867,7 +1199,11 @@ name = "xtask"
version = "0.3.2"
dependencies = [
"anyhow",
+ "chrono",
"clap",
"flate2",
+ "semver",
+ "similar-asserts",
"tar",
+ "toml_edit",
]
diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml
index 5040f0a..1694407 100644
--- a/xtask/Cargo.toml
+++ b/xtask/Cargo.toml
@@ -13,3 +13,13 @@ anyhow = { workspace = true }
clap = { workspace = true }
tar = "0.4.38"
flate2 = "1.0.26"
+semver = "1.0.17"
+toml_edit = { version = "0.19.10", features = ["serde"] }
+
+[dependencies.chrono]
+version = "0.4.26"
+default-features = false
+features = ["std", "clock"]
+
+[dev-dependencies]
+similar-asserts = "1.4.2"
diff --git a/xtask/src/lib.rs b/xtask/src/lib.rs
index f01fe7b..26dcbd1 100644
--- a/xtask/src/lib.rs
+++ b/xtask/src/lib.rs
@@ -8,3 +8,23 @@ const PKG_INCLUDE: &[&str] = &[
];
pub mod dist;
+pub mod release;
+
+/// Parse version from git describe output.
+pub fn git_version() -> anyhow::Result<semver::Version> {
+ let stdout = std::process::Command::new("git")
+ .arg("describe")
+ .arg("--long")
+ .arg("--abbrev=7")
+ .output()?
+ .stdout;
+
+ std::str::from_utf8(&stdout)?
+ .trim()
+ .trim_start_matches('v')
+ .replacen("-g", ".g", 1)
+ .replacen('-', "-r", 1)
+ .parse()
+ .map_err(Into::into)
+}
+
diff --git a/xtask/src/main.rs b/xtask/src/main.rs
index 51d5491..7454bf0 100644
--- a/xtask/src/main.rs
+++ b/xtask/src/main.rs
@@ -26,6 +26,7 @@ fn main() -> Result<()> {
let out_dir = dist::find_out_dir(&cli.profile)?;
println!("{}", out_dir.display());
}
+ Commands::Release(release) => release.run()?,
};
Ok(())
@@ -57,6 +58,8 @@ enum Commands {
#[arg(short, long)]
tag: Option<String>,
},
+
+ Release(release::Release),
}
fn get_package_dir() -> PathBuf {
diff --git a/xtask/src/release.rs b/xtask/src/release.rs
new file mode 100644
index 0000000..8bf4444
--- /dev/null
+++ b/xtask/src/release.rs
@@ -0,0 +1,174 @@
+use std::process::{Command, Stdio};
+
+use anyhow::Result;
+use clap::{Args, Subcommand};
+use semver::Version;
+
+use self::version::{Bump, Level, Replacement};
+
+mod version;
+
+#[derive(Debug, Clone, Args)]
+pub struct Release {
+ #[command(subcommand)]
+ step: Option<Step>,
+
+ /// Level of version bump version.
+ #[arg(global = true, required = false)]
+ level: version::Level,
+
+ /// Options passed to git commit.
+ #[arg(global = true, last = true)]
+ git_commit_args: Vec<String>,
+}
+
+impl Release {
+ pub fn run(self) -> Result<()> {
+ match self.step {
+ Some(step) => step.run(),
+ None => {
+ let bump = Step::bump(self.level)?;
+
+ println!("Bumped version: {bump}");
+
+ Ok(())
+ }
+ }
+ }
+}
+
+#[derive(Debug, Clone, Subcommand)]
+pub enum Step {
+ /// Bump version in package files and commit changes.
+ Bump {
+ #[arg(from_global)]
+ level: version::Level,
+ },
+
+ /// Make a release commit.
+ Commit {
+ #[arg(from_global)]
+ git_commit_args: Vec<String>,
+ },
+
+ /// Create git tag for release.
+ Tag {
+ #[arg(from_global)]
+ level: version::Level,
+ },
+}
+
+impl Step {
+ pub fn run(self) -> Result<()> {
+ match self {
+ Step::Bump { level } => {
+ let bump = Self::bump(level)?;
+ println!("Bumped version: {bump}");
+ }
+ Step::Commit { git_commit_args } => Self::commit(git_commit_args)?,
+ Step::Tag { level } => {
+ let stdout = Command::new("git")
+ .arg("describe")
+ .arg("--abbrev=0")
+ .output()?
+ .stdout;
+
+ let prev = std::str::from_utf8(&stdout)?.parse()?;
+ let next = level.bump(&prev);
+ Self::tag(prev, next)?;
+ }
+ };
+
+ Ok(())
+ }
+
+ pub fn bump(level: Level) -> Result<Bump> {
+ let mut bump = Bump::from(level);
+
+ bump.bump_file("README.md", &[Replacement::Version])?;
+ bump.bump_file("pkg/archlinux/projectr/PKGBUILD", &[Replacement::Version])?;
+ bump.bump_file(
+ "pkg/archlinux/projectr-bin/PKGBUILD",
+ &[Replacement::Version],
+ )?;
+
+ let stdout = std::process::Command::new("git")
+ .arg("describe")
+ .arg("--long")
+ .arg("--abbrev=7")
+ .output()?
+ .stdout;
+ let pkgver = std::str::from_utf8(&stdout)?
+ .trim()
+ .trim_start_matches('v')
+ .replacen("-g", ".g", 1)
+ .replacen('-', "-r", 1)
+ .replace('-', ".");
+
+ bump.bump_file(
+ "pkg/archlinux/projectr-git/PKGBUILD",
+ &[Replacement::FindLine(
+ |l| l.starts_with("pkgver="),
+ format!("pkgver={pkgver}"),
+ )],
+ )?;
+
+ bump.bump_file(
+ "CHANGELOG.md",
+ &[
+ Replacement::Append(
+ "## [Unreleased]".to_string(),
+ format!(
+ "\n## [{}] - {}",
+ bump.next,
+ chrono::Utc::now().format("%Y-%m-%d")
+ ),
+ ),
+ Replacement::Append(
+ "[Unreleased]: https://git.sr.ht/~tobyvin/projectr/log/HEAD".to_string(),
+ format!(
+ "[{0}]: https://git.sr.ht/~tobyvin/projectr/log/v{0}",
+ bump.next
+ ),
+ ),
+ ],
+ )?;
+
+ Ok(bump)
+ }
+
+ pub fn commit(git_commit_args: Vec<String>) -> Result<()> {
+ let git_commit = Command::new("git")
+ .arg("commit")
+ .args(git_commit_args)
+ .status()?;
+
+ anyhow::ensure!(git_commit.success(), "Failed to commit changes");
+
+ Ok(())
+ }
+
+ pub fn tag(from: Version, to: Version) -> Result<String> {
+ let tag_name = format!("v{}", to);
+
+ let shortlog_child = Command::new("git")
+ .arg("shortlog")
+ .arg(format!("v{}..HEAD", from))
+ .arg("--abbrev=7")
+ .stdout(Stdio::piped())
+ .spawn()?;
+
+ let git_commit = Command::new("git")
+ .arg("tag")
+ .arg("-s")
+ .arg(&tag_name)
+ .arg("--file")
+ .arg("-")
+ .stdin(Stdio::from(shortlog_child.stdout.unwrap())) // Pipe through.
+ .status()?;
+
+ anyhow::ensure!(git_commit.success(), "Failed to commit changes");
+
+ Ok(tag_name)
+ }
+}
diff --git a/xtask/src/release/version.rs b/xtask/src/release/version.rs
new file mode 100644
index 0000000..0c8cffd
--- /dev/null
+++ b/xtask/src/release/version.rs
@@ -0,0 +1,302 @@
+use std::{
+ fmt::Display,
+ fs::File,
+ io::{Read, Write},
+ path::Path,
+ process::Command,
+ str::FromStr,
+};
+
+use anyhow::Result;
+use semver::Version;
+
+use crate::PKG_VER;
+
+#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord)]
+pub enum Level {
+ Major,
+ Minor,
+ #[default]
+ Patch,
+}
+
+impl Level {
+ pub fn bump(&self, version: &Version) -> Version {
+ match self {
+ Self::Major => Version::new(version.major + 1, 0, 0),
+ Self::Minor => Version::new(version.major, version.minor + 1, 0),
+ Self::Patch => Version::new(version.major, version.minor, version.patch + 1),
+ }
+ }
+}
+
+impl FromStr for Level {
+ type Err = anyhow::Error;
+
+ fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
+ match s.to_lowercase().as_str() {
+ "major" => Ok(Level::Major),
+ "minor" => Ok(Level::Minor),
+ "patch" => Ok(Level::Patch),
+ s => Err(anyhow::anyhow!("Invalid bump level: {s}")),
+ }
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
+pub struct Bump {
+ pub version: Version,
+ pub next: Version,
+}
+
+impl Bump {
+ pub fn new(major: u64, minor: u64, patch: u64, level: Level) -> Self {
+ let version = Version::new(major, minor, patch);
+ let next = level.bump(&version);
+ Self { version, next }
+ }
+
+ fn check_modified<P>(path: P) -> Result<bool>
+ where
+ P: AsRef<Path>,
+ {
+ Ok(Command::new("git")
+ .arg("diff-index")
+ .arg("--quiet")
+ .arg("HEAD")
+ .arg(path.as_ref())
+ .output()?
+ .status
+ .success())
+ }
+
+ pub fn bump_file<P>(&mut self, path: P, replacements: &[Replacement]) -> Result<()>
+ where
+ P: AsRef<Path>,
+ {
+ let path = path.as_ref();
+
+ anyhow::ensure!(
+ Self::check_modified(path)?,
+ "{} has uncommited changes. Aborting.",
+ path.display()
+ );
+
+ let file = File::open(path)?;
+
+ self.bump(&file, &file, replacements)?;
+
+ let git_added = Command::new("git").arg("add").arg(path).status()?;
+
+ anyhow::ensure!(git_added.success(), "Failed to add bumped files to git");
+
+ Ok(())
+ }
+
+ fn bump<R, W>(&self, mut reader: R, mut writer: W, replacements: &[Replacement]) -> Result<()>
+ where
+ R: Read,
+ W: Write,
+ {
+ let mut buf = String::new();
+ reader.read_to_string(&mut buf)?;
+
+ let buf = replacements
+ .iter()
+ .try_fold(buf, |acc, r| r.replace(self, acc))?;
+
+ writer.write_all(buf.as_bytes()).map_err(Into::into)
+ }
+}
+
+impl Display for Bump {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{} -> {}", self.version, self.next)
+ }
+}
+
+impl Default for Bump {
+ fn default() -> Self {
+ let version = PKG_VER.parse().unwrap_or_else(|_| Version::new(0, 1, 0));
+ Self {
+ next: Level::default().bump(&version),
+ version,
+ }
+ }
+}
+
+impl From<Level> for Bump {
+ fn from(level: Level) -> Self {
+ let mut v = Self::default();
+ v.next = level.bump(&v.version);
+ v
+ }
+}
+
+#[derive(Default)]
+pub enum Replacement {
+ #[default]
+ Version,
+ CargoVersion,
+ FindLine(fn(&&str) -> bool, String),
+ Replace(String, String),
+ Append(String, String),
+}
+
+impl Replacement {
+ pub fn replace(&self, bump: &Bump, buf: String) -> Result<String> {
+ let buf = match self {
+ Replacement::Version => buf.replace(&bump.version.to_string(), &bump.next.to_string()),
+ Replacement::Replace(from, to) => buf.replace(from, to),
+ Replacement::Append(line, append) => buf.replace(line, &format!("{line}\n{append}")),
+ Replacement::FindLine(find, replace) => match buf.lines().find(find) {
+ Some(line) => buf.replace(line, replace),
+ None => buf,
+ },
+ Replacement::CargoVersion => {
+ let mut cargo_toml: toml_edit::Document = buf.parse()?;
+ cargo_toml["workspace"]["package"]["version"] =
+ toml_edit::value(bump.next.to_string());
+ cargo_toml.to_string()
+ }
+ };
+
+ Ok(buf)
+ }
+}
+
+#[cfg(test)]
+mod test {
+
+ use similar_asserts::SimpleDiff;
+
+ use super::*;
+
+ fn setup_test() -> Result<(), std::io::Error> {
+ let project_root = std::path::Path::new(&env!("CARGO_MANIFEST_DIR"))
+ .parent()
+ .expect("Failed to get parent directory.")
+ .to_path_buf();
+
+ std::env::set_current_dir(project_root)
+ }
+
+ fn print_diff(reader: &[u8], writer: &[u8]) {
+ let left = std::str::from_utf8(reader).unwrap();
+ let right = std::str::from_utf8(writer).unwrap();
+ let diff = SimpleDiff::from_str(left, right, "old", "new");
+
+ println!("{diff}")
+ }
+
+ #[test]
+ fn test_bump_cargo() {
+ setup_test().unwrap();
+
+ let bump = Bump::default();
+ let file = "Cargo.toml";
+
+ let content = std::fs::read_to_string(file).unwrap();
+ let reader = content.as_bytes();
+ let mut writer = Vec::new();
+
+ let replacements = &[Replacement::CargoVersion];
+
+ bump.bump(reader, &mut writer, replacements).unwrap();
+
+ println!("{file}: {bump}");
+ print_diff(reader, &writer)
+ }
+
+ #[test]
+ fn test_bump_changelog() {
+ setup_test().unwrap();
+
+ let bump = Bump::default();
+ let file = "CHANGELOG.md";
+
+ let content = std::fs::read_to_string(file).unwrap();
+ let reader = content.as_bytes();
+ let mut writer = Vec::new();
+
+ let replacements = &[
+ Replacement::Append(
+ "## [Unreleased]".to_string(),
+ format!(
+ "\n## [{}] - {}",
+ bump.next,
+ chrono::Utc::now().format("%Y-%m-%d")
+ ),
+ ),
+ Replacement::Append(
+ "[Unreleased]: https://git.sr.ht/~tobyvin/projectr/log/HEAD".to_string(),
+ format!(
+ "[{0}]: https://git.sr.ht/~tobyvin/projectr/log/v{0}",
+ bump.next
+ ),
+ ),
+ ];
+
+ bump.bump(reader, &mut writer, replacements).unwrap();
+
+ println!("{file}: {bump}");
+ print_diff(reader, &writer)
+ }
+
+ #[test]
+ fn test_bump_readme() {
+ setup_test().unwrap();
+
+ let bump = Bump::default();
+ let file = "README.md";
+
+ let content = std::fs::read_to_string(file);
+ let reader = content.as_deref().unwrap().as_bytes();
+ let mut writer = Vec::new();
+
+ let replacements = &[Replacement::Version];
+
+ bump.bump(reader, &mut writer, replacements).unwrap();
+
+ println!("{file}: {bump}");
+ print_diff(reader, &writer)
+ }
+
+ #[test]
+ fn test_bump_vsc_pkgbuild() {
+ setup_test().unwrap();
+
+ let bump = Bump::default();
+ let file = "pkg/archlinux/projectr-git/PKGBUILD";
+
+ let content = std::fs::read_to_string(file).unwrap();
+ let reader = content.as_bytes();
+ let mut writer = Vec::new();
+
+ let stdout = std::process::Command::new("git")
+ .arg("describe")
+ .arg("--long")
+ .arg("--abbrev=7")
+ .output()
+ .unwrap()
+ .stdout;
+
+ let pkgver = std::str::from_utf8(&stdout)
+ .unwrap()
+ .trim()
+ .trim_start_matches('v')
+ .replacen("-g", ".g", 1)
+ .replacen('-', "-r", 1)
+ .replace('-', ".");
+
+ let replacements = &[Replacement::FindLine(
+ |l| l.starts_with("pkgver="),
+ format!("pkgver={pkgver}"),
+ )];
+
+ bump.bump(reader, &mut writer, replacements).unwrap();
+
+ println!("{file}: {bump}");
+ print_diff(reader, &writer)
+ }
+}