diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..6cb6e38 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,7 @@ +* +!Cargo.toml +!Cargo.lock +!core/ +!server/ +!sqlite/ +!docker-entrypoint.sh diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index efe9a0d..0000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,58 +0,0 @@ -name: Build - -on: [push, pull_request] - -jobs: - build: - strategy: - fail-fast: false - matrix: - target: - - tag: amd64-musl - target: x86_64-unknown-linux-musl - - tag: amd64-glibc - target: x86_64-unknown-linux-gnu - name: Build TaskChampion Sync-Server ${{ matrix.target.tag }} - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Load .env file - uses: xom9ikk/dotenv@v2 - - name: Setup Rust toolchain - uses: dtolnay/rust-toolchain@stable - with: - toolchain: ${{ env.RUST_VERSION }} - targets: ${{ matrix.target.target }} - - name: Build - run: | - [ "${{ matrix.target.target }}" == "x86_64-unknown-linux-musl" ] && sudo apt update && sudo apt -y install musl-tools - cargo build --target ${{ matrix.target.target }} --release --locked - - name: Package current compilation - id: package-current - run: | - install -Dm755 "target/${{ matrix.target.target }}/release/taskchampion-sync-server" "taskchampion-sync-server-${{ matrix.target.tag }}-${GITHUB_REF##*/}-${GITHUB_SHA}/taskchampion-sync-server" - install -Dm644 "README.md" "taskchampion-sync-server-${{ matrix.target.tag }}-${GITHUB_REF##*/}-${GITHUB_SHA}/README.md" - install -Dm644 "LICENSE" "taskchampion-sync-server-${{ matrix.target.tag }}-${GITHUB_REF##*/}-${GITHUB_SHA}/LICENSE" - echo "version=${GITHUB_REF##*/}-${GITHUB_SHA}" >> $GITHUB_OUTPUT - - name: Archive current compilation - uses: actions/upload-artifact@v4 - with: - name: "taskchampion-sync-server-${{ matrix.target.tag }}-${{ steps.package-current.outputs.version }}" - path: "taskchampion-sync-server-${{ matrix.target.tag }}-${{ steps.package-current.outputs.version }}/" - - name: Package tagged compilation - id: package - if: startsWith(github.ref, 'refs/tags/') && github.event_name != 'pull_request' - run: | - install -Dm755 "target/${{ matrix.target.target }}/release/taskchampion-sync-server" "taskchampion-sync-server-${{ matrix.target.tag }}-${GITHUB_REF##*/}/taskchampion-sync-server" - install -Dm644 "README.md" "taskchampion-sync-server-${{ matrix.target.tag }}-${GITHUB_REF##*/}/README.md" - install -Dm644 "LICENSE" "taskchampion-sync-server-${{ matrix.target.tag }}-${GITHUB_REF##*/}/LICENSE" - tar cvJf "taskchampion-sync-server-${{ matrix.target.tag }}-${GITHUB_REF##*/}.tar.xz" "taskchampion-sync-server-${{ matrix.target.tag }}-${GITHUB_REF##*/}" - echo "version=${GITHUB_REF##*/}" >> $GITHUB_OUTPUT - - name: Release - uses: softprops/action-gh-release@v2 - if: startsWith(github.ref, 'refs/tags/') && github.event_name != 'pull_request' - with: - files: "taskchampion-sync-server-${{ matrix.target.tag }}-${{ steps.package.outputs.version }}.tar.xz" - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 1738f24..6840527 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -2,8 +2,6 @@ name: Build Docker on: push: - branches: - - '*' tags: - '*' diff --git a/.github/workflows/rust-tests.yml b/.github/workflows/rust-tests.yml index 0b7c18f..d5b357d 100644 --- a/.github/workflows/rust-tests.yml +++ b/.github/workflows/rust-tests.yml @@ -13,6 +13,8 @@ jobs: # A simple matrix for now, but if we introduce an MSRV it can be added here. matrix: rust: + # MSRV + - "1.81.0" - "stable" runs-on: ubuntu-latest diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 2dbb528..f1d3a32 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -2,7 +2,7 @@ name: security on: schedule: - - cron: '0 0 * * *' + - cron: '33 0 * * THU' push: paths: - '**/Cargo.toml' diff --git a/Cargo.lock b/Cargo.lock index bed1a41..acbbf54 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21,15 +21,14 @@ dependencies = [ [[package]] name = "actix-http" -version = "3.9.0" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d48f96fc3003717aeb9856ca3d02a8c7de502667ad76eeacd830b48d2e91fac4" +checksum = "44dfe5c9e0004c623edc65391dfd51daa201e7e30ebd9c9bedf873048ec32bc2" dependencies = [ "actix-codec", "actix-rt", "actix-service", "actix-utils", - "ahash", "base64", "bitflags", "brotli", @@ -38,6 +37,7 @@ dependencies = [ "derive_more", "encoding_rs", "flate2", + "foldhash", "futures-core", "h2", "http", @@ -96,9 +96,9 @@ dependencies = [ [[package]] name = "actix-server" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ca2549781d8dd6d75c40cf6b6051260a2cc2f3c62343d761a969a0640646894" +checksum = "a65064ea4a457eaf07f2fba30b4c695bf43b721790e9530d26cb6f9019ff7502" dependencies = [ "actix-rt", "actix-service", @@ -113,12 +113,11 @@ dependencies = [ [[package]] name = "actix-service" -version = "2.0.2" +version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b894941f818cfdc7ccc4b9e60fa7e53b5042a2e8567270f9147d5591893373a" +checksum = "9e46f36bf0e5af44bdc4bdb36fbbd421aa98c79a9bce724e1edeb3894e10dc7f" dependencies = [ "futures-core", - "paste", "pin-project-lite", ] @@ -134,9 +133,9 @@ dependencies = [ [[package]] name = "actix-web" -version = "4.9.0" +version = "4.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9180d76e5cc7ccbc4d60a506f2c727730b154010262df5b910eb17dbe4b8cb38" +checksum = "a597b77b5c6d6a1e1097fddde329a83665e25c5437c696a3a9a4aa514a614dea" dependencies = [ "actix-codec", "actix-http", @@ -147,13 +146,13 @@ dependencies = [ "actix-service", "actix-utils", "actix-web-codegen", - "ahash", "bytes", "bytestring", "cfg-if", "cookie", "derive_more", "encoding_rs", + "foldhash", "futures-core", "futures-util", "impl-more", @@ -171,6 +170,7 @@ dependencies = [ "smallvec", "socket2", "time", + "tracing", "url", ] @@ -188,9 +188,9 @@ dependencies = [ [[package]] name = "addr2line" -version = "0.24.1" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] @@ -208,10 +208,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", - "getrandom", "once_cell", "version_check", - "zerocopy", + "zerocopy 0.7.35", ] [[package]] @@ -255,9 +254,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.15" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", @@ -270,43 +269,44 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.4" +version = "3.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "once_cell", + "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.89" +version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" +checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" [[package]] name = "autocfg" @@ -337,9 +337,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bitflags" -version = "2.6.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" [[package]] name = "block-buffer" @@ -352,9 +352,9 @@ dependencies = [ [[package]] name = "brotli" -version = "6.0.0" +version = "8.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74f7971dbd9326d58187408ab83117d8ac1bb9c17b085fdacd1cf2f598719b6b" +checksum = "9991eea70ea4f293524138648e41ee89b0b2b12ddef3b255effa43c8056e0e0d" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -363,9 +363,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "4.0.1" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362" +checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -373,36 +373,30 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "bytes" -version = "1.7.2" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "bytestring" -version = "1.3.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d80203ea6b29df88012294f62733de21cfeab47f17b41af3a38bc30a03ee72" +checksum = "e465647ae23b2823b0753f50decb2d5a86d2bb2cac04788fafd1f80e45378e5f" dependencies = [ "bytes", ] [[package]] name = "cc" -version = "1.1.24" +version = "1.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812acba72f0a070b003d3697490d2b55b837230ae7c6c6497f05cc2ddbb8d938" +checksum = "525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c" dependencies = [ "jobserver", "libc", @@ -417,9 +411,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.38" +version = "0.4.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" dependencies = [ "android-tzdata", "iana-time-zone", @@ -427,23 +421,23 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets", + "windows-link", ] [[package]] name = "clap" -version = "4.5.19" +version = "4.5.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7be5744db7978a28d9df86a214130d106a89ce49644cbc4e3f0c22c3fba30615" +checksum = "d8aa86934b44c19c50f87cc2790e19f54f7a67aedb64101c2e1a2e5ecfb73944" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.19" +version = "4.5.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5fbc17d3ef8278f55b282b2a2e75ae6f6c7d4bb70ed3d0382375104bfafdb4b" +checksum = "2414dbb2dd0695280da6ea9261e327479e9d37b0630f6b53ba2a11c60c679fd9" dependencies = [ "anstream", "anstyle", @@ -453,21 +447,15 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "colorchoice" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" - -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "cookie" @@ -488,9 +476,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.14" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" dependencies = [ "libc", ] @@ -516,24 +504,32 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.11" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" dependencies = [ "powerfmt", ] [[package]] name = "derive_more" -version = "0.99.18" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" +checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" dependencies = [ - "convert_case", "proc-macro2", "quote", - "rustc_version", "syn", + "unicode-xid", ] [[package]] @@ -565,18 +561,18 @@ dependencies = [ [[package]] name = "encoding_rs" -version = "0.8.34" +version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ "cfg-if", ] [[package]] name = "env_filter" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" +checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" dependencies = [ "log", "regex", @@ -584,31 +580,31 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.11.5" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" +checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" dependencies = [ "anstream", "anstyle", "env_filter", - "humantime", + "jiff", "log", ] [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -625,15 +621,15 @@ checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" [[package]] name = "fastrand" -version = "2.1.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "flate2" -version = "1.0.34" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" +checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" dependencies = [ "crc32fast", "miniz_oxide", @@ -645,6 +641,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -656,9 +658,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -671,9 +673,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -681,15 +683,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -704,9 +706,9 @@ checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", @@ -715,21 +717,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -755,20 +757,21 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" dependencies = [ "cfg-if", "libc", - "wasi", + "r-efi", + "wasi 0.14.2+wasi-0.2.4", ] [[package]] name = "gimli" -version = "0.31.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "h2" @@ -813,12 +816,6 @@ dependencies = [ "hashbrown 0.14.5", ] -[[package]] -name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - [[package]] name = "http" version = "0.2.12" @@ -832,9 +829,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.9.5" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "httpdate" @@ -842,22 +839,17 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - [[package]] name = "iana-time-zone" -version = "0.1.61" +version = "0.1.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", + "log", "wasm-bindgen", "windows-core", ] @@ -912,9 +904,9 @@ dependencies = [ [[package]] name = "icu_locid_transform_data" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" +checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" [[package]] name = "icu_normalizer" @@ -936,9 +928,9 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" +checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" [[package]] name = "icu_properties" @@ -957,9 +949,9 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" +checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" [[package]] name = "icu_provider" @@ -1012,15 +1004,15 @@ dependencies = [ [[package]] name = "impl-more" -version = "0.1.6" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "206ca75c9c03ba3d4ace2460e57b189f39f43de612c2f85836e65c929701bb2d" +checksum = "e8a5a9a0ff0086c7a148acb942baaabeadf9504d10400b5a05645853729b9cd2" [[package]] name = "indexmap" -version = "2.6.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "equivalent", "hashbrown 0.15.2", @@ -1034,25 +1026,51 @@ checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "jiff" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f33145a5cbea837164362c7bd596106eb7c5198f97d1ba6f6ebb3223952e488" +dependencies = [ + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde", +] + +[[package]] +name = "jiff-static" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43ce13c40ec6956157a3635d97a1ee2df323b263f09ea14165131289cb0f5c19" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "jobserver" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" dependencies = [ + "getrandom", "libc", ] [[package]] name = "js-sys" -version = "0.3.70" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -1064,9 +1082,9 @@ checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" [[package]] name = "libc" -version = "0.2.162" +version = "0.2.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" +checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" [[package]] name = "libsqlite3-sys" @@ -1081,15 +1099,15 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.4.14" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413" [[package]] name = "litemap" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" +checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" [[package]] name = "local-channel" @@ -1120,9 +1138,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.22" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "memchr" @@ -1138,23 +1156,22 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "miniz_oxide" -version = "0.8.0" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430" dependencies = [ "adler2", ] [[package]] name = "mio" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ - "hermit-abi", "libc", "log", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.52.0", ] @@ -1175,21 +1192,18 @@ dependencies = [ [[package]] name = "object" -version = "0.36.4" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.20.1" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82881c4be219ab5faaf2ad5e5e5ecdff8c66bd7402ca3160975c93b24961afd1" -dependencies = [ - "portable-atomic", -] +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "parking_lot" @@ -1214,12 +1228,6 @@ dependencies = [ "windows-targets", ] -[[package]] -name = "paste" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" - [[package]] name = "percent-encoding" version = "2.3.1" @@ -1228,9 +1236,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -1240,15 +1248,24 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "portable-atomic" -version = "1.9.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" +checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" + +[[package]] +name = "portable-atomic-util" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +dependencies = [ + "portable-atomic", +] [[package]] name = "powerfmt" @@ -1258,11 +1275,11 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ - "zerocopy", + "zerocopy 0.8.24", ] [[package]] @@ -1277,38 +1294,44 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.37" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] [[package]] -name = "rand" -version = "0.8.5" +name = "r-efi" +version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + +[[package]] +name = "rand" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" dependencies = [ - "libc", "rand_chacha", "rand_core", + "zerocopy 0.8.24", ] [[package]] name = "rand_chacha" -version = "0.3.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", "rand_core", @@ -1316,27 +1339,27 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.4" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ "getrandom", ] [[package]] name = "redox_syscall" -version = "0.5.7" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3" dependencies = [ "bitflags", ] [[package]] name = "regex" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", @@ -1346,9 +1369,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -1387,33 +1410,30 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" -[[package]] -name = "rustc_version" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver", -] - [[package]] name = "rustix" -version = "0.38.39" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "375116bee2be9ed569afe2154ea6a99dfdffd257f533f187498c2a8f5feaf4ee" +checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] -name = "ryu" -version = "1.0.18" +name = "rustversion" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "scopeguard" @@ -1421,26 +1441,20 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "semver" -version = "1.0.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" - [[package]] name = "serde" -version = "1.0.210" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.210" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", @@ -1449,9 +1463,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.128" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ "itoa", "memchr", @@ -1508,15 +1522,15 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.2" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" [[package]] name = "socket2" -version = "0.5.7" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" dependencies = [ "libc", "windows-sys 0.52.0", @@ -1536,9 +1550,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.87" +version = "2.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" dependencies = [ "proc-macro2", "quote", @@ -1558,7 +1572,7 @@ dependencies = [ [[package]] name = "taskchampion-sync-server" -version = "0.4.1" +version = "0.6.2-pre" dependencies = [ "actix-rt", "actix-web", @@ -1573,6 +1587,7 @@ dependencies = [ "serde_json", "taskchampion-sync-server-core", "taskchampion-sync-server-storage-sqlite", + "temp-env", "tempfile", "thiserror", "uuid", @@ -1580,7 +1595,7 @@ dependencies = [ [[package]] name = "taskchampion-sync-server-core" -version = "0.5.0-pre" +version = "0.6.2-pre" dependencies = [ "anyhow", "chrono", @@ -1593,7 +1608,7 @@ dependencies = [ [[package]] name = "taskchampion-sync-server-storage-sqlite" -version = "0.5.0-pre" +version = "0.6.2-pre" dependencies = [ "anyhow", "chrono", @@ -1606,13 +1621,22 @@ dependencies = [ ] [[package]] -name = "tempfile" -version = "3.14.0" +name = "temp-env" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" +checksum = "96374855068f47402c3121c6eed88d29cb1de8f3ab27090e273e420bdabcf050" +dependencies = [ + "parking_lot", +] + +[[package]] +name = "tempfile" +version = "3.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" dependencies = [ - "cfg-if", "fastrand", + "getrandom", "once_cell", "rustix", "windows-sys 0.59.0", @@ -1620,18 +1644,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.3" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.3" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", @@ -1640,9 +1664,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.36" +version = "0.3.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" dependencies = [ "deranged", "itoa", @@ -1655,15 +1679,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" +checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" [[package]] name = "time-macros" -version = "0.2.18" +version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" dependencies = [ "num-conv", "time-core", @@ -1681,9 +1705,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.40.0" +version = "1.44.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" +checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48" dependencies = [ "backtrace", "bytes", @@ -1698,9 +1722,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.12" +version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" +checksum = "6b9590b93e6fcc1739458317cccd391ad3955e2bde8913edf6f95f9e65a8f034" dependencies = [ "bytes", "futures-core", @@ -1711,35 +1735,53 @@ dependencies = [ [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "log", "pin-project-lite", + "tracing-attributes", "tracing-core", ] [[package]] -name = "tracing-core" -version = "0.1.32" +name = "tracing-attributes" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", ] [[package]] name = "typenum" -version = "1.17.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "url" @@ -1772,12 +1814,14 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.11.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" +checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" dependencies = [ "getrandom", + "js-sys", "serde", + "wasm-bindgen", ] [[package]] @@ -1799,25 +1843,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] -name = "wasm-bindgen" -version = "0.2.93" +name = "wasi" +version = "0.14.2+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", "once_cell", + "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.93" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", "syn", @@ -1826,9 +1879,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.93" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1836,9 +1889,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.93" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", @@ -1849,17 +1902,70 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.93" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] [[package]] name = "windows-core" -version = "0.52.0" +version = "0.61.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" dependencies = [ - "windows-targets", + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" + +[[package]] +name = "windows-result" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" +dependencies = [ + "windows-link", ] [[package]] @@ -1944,6 +2050,15 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags", +] + [[package]] name = "write16" version = "1.0.0" @@ -1992,8 +2107,16 @@ version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ - "byteorder", - "zerocopy-derive", + "zerocopy-derive 0.7.35", +] + +[[package]] +name = "zerocopy" +version = "0.8.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" +dependencies = [ + "zerocopy-derive 0.8.24", ] [[package]] @@ -2008,19 +2131,30 @@ dependencies = [ ] [[package]] -name = "zerofrom" -version = "0.1.5" +name = "zerocopy-derive" +version = "0.8.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", @@ -2052,27 +2186,27 @@ dependencies = [ [[package]] name = "zstd" -version = "0.13.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "7.2.1" +version = "7.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" dependencies = [ "zstd-sys", ] [[package]] name = "zstd-sys" -version = "2.0.13+zstd.1.5.6" +version = "2.0.15+zstd.1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" +checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237" dependencies = [ "cc", "pkg-config", diff --git a/Cargo.toml b/Cargo.toml index ef67faf..ba0140c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,20 +5,22 @@ members = [ "server", "sqlite", ] +rust-version = "1.81.0" # MSRV [workspace.dependencies] -uuid = { version = "^1.11.0", features = ["serde", "v4"] } -actix-web = "^4.9.0" +uuid = { version = "^1.17.0", features = ["serde", "v4"] } +actix-web = "^4.11.0" anyhow = "1.0" thiserror = "2.0" futures = "^0.3.25" serde_json = "^1.0" serde = { version = "^1.0.147", features = ["derive"] } -clap = { version = "^4.5.6", features = ["string"] } +clap = { version = "^4.5.6", features = ["string", "env"] } log = "^0.4.17" -env_logger = "^0.11.5" +env_logger = "^0.11.7" rusqlite = { version = "0.32", features = ["bundled"] } chrono = { version = "^0.4.38", features = ["serde"] } actix-rt = "2" tempfile = "3" pretty_assertions = "1" +temp-env = "0.3" diff --git a/Dockerfile b/Dockerfile index f9542af..630deb7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,19 +1,25 @@ # Versions must be major.minor -ARG RUST_VERSION -ARG ALPINE_VERSION +# Default versions are as below +ARG RUST_VERSION=1.78 +ARG ALPINE_VERSION=3.19 FROM docker.io/rust:${RUST_VERSION}-alpine${ALPINE_VERSION} AS builder -COPY . /data +COPY Cargo.lock Cargo.toml /data/ +COPY core /data/core/ +COPY server /data/server/ +COPY sqlite /data/sqlite/ RUN apk -U add libc-dev && \ cd /data && \ cargo build --release FROM docker.io/alpine:${ALPINE_VERSION} COPY --from=builder /data/target/release/taskchampion-sync-server /bin -RUN adduser -S -D -H -h /var/lib/taskchampion-sync-server -s /sbin/nologin -G users \ +RUN apk add --no-cache su-exec && \ + adduser -u 1092 -S -D -H -h /var/lib/taskchampion-sync-server -s /sbin/nologin -G users \ -g taskchampion taskchampion && \ - install -d -m755 -o100 -g100 "/var/lib/taskchampion-sync-server" + install -d -m1755 -o1092 -g1092 "/var/lib/taskchampion-sync-server" EXPOSE 8080 -VOLUME "/var/lib/taskchampion-sync-server" -USER taskchampion -ENTRYPOINT [ "taskchampion-sync-server" ] +VOLUME /var/lib/taskchampion-sync-server/data +COPY docker-entrypoint.sh /bin +ENTRYPOINT [ "/bin/docker-entrypoint.sh" ] +CMD [ "/bin/taskchampion-sync-server" ] diff --git a/README.md b/README.md index 3be02cd..0c4d0bc 100644 --- a/README.md +++ b/README.md @@ -27,31 +27,42 @@ use a reverse proxy such as Nginx, haproxy, or Apache httpd. ### Using Docker-Compose -The [`docker-compose.yml`](./docker-compose.yml) file in this repository is -sufficient to run taskchampion-sync-server, including setting up TLS -certificates using Lets Encrypt, thanks to [Caddy](https://caddyserver.com/). +Every release of the server generates a Docker image in +`ghcr.io/gothenburgbitfactory/taskchampion-sync-server`. The tags include +`latest` for the latest release, and both minor and patch versions, e.g., `0.5` +and `0.5.1`. + +The +[`docker-compose.yml`](https://raw.githubusercontent.com/GothenburgBitFactory/taskchampion-sync-server/refs/tags/v0.6.1/docker-compose.yml) +file in this repository is sufficient to run taskchampion-sync-server, +including setting up TLS certificates using Lets Encrypt, thanks to +[Caddy](https://caddyserver.com/). You will need a server with ports 80 and 443 open to the Internet and with a fixed, publicly-resolvable hostname. These ports must be available both to your Taskwarrior clients and to the Lets Encrypt servers. -On that server, clone this repository (or just download `docker-compose.yml` to -the current directory -- the rest of the contents of this repository are not -required) and run +On that server, download `docker-compose.yml` from the link above (it is pinned +to the latest release) into the current directory. Then run ```sh -TASKCHAMPION_SYNC_SERVER_HOSTNAME=taskwarrior.example.com docker compose up +TASKCHAMPION_SYNC_SERVER_HOSTNAME=taskwarrior.example.com \ +TASKCHAMPION_SYNC_SERVER_CLIENT_ID=your-client-id \ +docker compose up ``` +The `TASKCHAMPION_SYNC_SERVER_CLIENT_ID` limits the server to the given client +ID; omit it to allow all client IDs. + It can take a few minutes to obtain the certificate; the caddy container will -log a msg "certificate obtained successfully" when this is complete, or error -messages if the process fails. Once this process is complete, configure your -`.taskrc`'s to point to the server: +log a message "certificate obtained successfully" when this is complete, or +error messages if the process fails. Once this process is complete, configure +your `.taskrc`'s to point to the server: ``` sync.server.url=https://taskwarrior.example.com -sync.server.client_id=[your client-id] -sync.encryption_secret=[your encryption secret] +sync.server.client_id=your-client-id +sync.encryption_secret=your-encryption-secret ``` The docker-compose images store data in a docker volume named @@ -65,11 +76,20 @@ system startup. See the docker-compose documentation for more information. The server is configured with command-line options. See `taskchampion-sync-server --help` for full details. -The `--data-dir` option specifies where the server should store its data, and -`--port` gives the port on which the HTTP server runs. +The `--listen` option specifies the interface and port the server listens on. +It must contain an IP-Address or a DNS name and a port number. This option is +mandatory, but can be repeated to specify multiple interfaces or ports. This +value can be specified in environment variable `LISTEN`, as a comma-separated +list of values. + +The `--data-dir` option specifies where the server should store its data. This +value can be specified in the environment variable `DATA_DIR`. By default, the server allows all client IDs. To limit the accepted client IDs, -such as when running a personal server, use `--allow-client-id `. +specify them in the environment variable `CLIENT_ID`, as a comma-separated list +of UUIDs. Client IDs can be specified with `--allow-client-id`, but this should +not be used on shared systems, as command line arguments are visible to all +users on the system. The server only logs errors by default. To add additional logging output, set environment variable `RUST_LOG` to `info` to get a log message for every @@ -88,7 +108,11 @@ release version. You can install Rust from your distribution package or use rustup default stable ``` -If you prefer, you can use the stable version only for install TaskChampion +The minimum supported Rust version (MSRV) is given in +[`Cargo.toml`](./Cargo.toml). Note that package repositories typically do not +have sufficiently new versions of Rust. + +If you prefer, you can use the stable version only for installing TaskChampion Sync-Server (you must clone the repository first). ```sh rustup override set stable @@ -108,6 +132,7 @@ cargo build --release After build the binary is located in `target/release/taskchampion-sync-server`. + ### Building the Container To build the container execute the following commands. @@ -129,4 +154,12 @@ docker run -t -d \ This start TaskChampion Sync-Server and publish the port to host. Please note that this is a basic run, all data will be destroyed after stop and -delete container. +delete container. You may also set `DATA_DIR`, `CLIENT_ID`, or `LISTEN` with `-e`, e.g., + +```sh +docker run -t -d \ + --name=taskchampion \ + -e LISTEN=0.0.0.0:9000 \ + -p 9000:9000 \ + taskchampion-sync-server +``` diff --git a/RELEASING.md b/RELEASING.md new file mode 100644 index 0000000..6671ddf --- /dev/null +++ b/RELEASING.md @@ -0,0 +1,21 @@ +# Release process + +1. Run `git pull upstream main` +1. Run `cargo test` +1. Run `cargo clean && cargo clippy` +1. Remove the `-pre` from `version` in all `*/Cargo.toml`, and from the `version = ..` in any references between packages. +1. Update the link to `docker-compose.yml` in `README.md` to refer to the new version. +1. Update the docker image in `docker-compose.yml` to refer to the new version. +1. Run `cargo semver-checks` (https://crates.io/crates/cargo-semver-checks) +1. Run `cargo build --release` +1. Commit the changes (Cargo.lock will change too) with comment `vX.Y.Z`. +1. Run `git tag vX.Y.Z` +1. Run `git push upstream` +1. Run `git push upstream --tag vX.Y.Z` +1. Run `cargo publish -p taskchampion-sync-server-core` +1. Run `cargo publish -p taskchampion-sync-server-storage-sqlite` (and add any other new published packages here) +1. Bump the patch version in `*/Cargo.toml` and add the `-pre` suffix. This allows `cargo-semver-checks` to check for changes not accounted for in the version delta. +1. Run `cargo build --release` again to update `Cargo.lock` +1. Commit that change with comment "Bump to -pre version". +1. Run `git push upstream` +1. Navigate to the tag in the GitHub releases UI and create a release with general comments about the changes in the release diff --git a/core/Cargo.toml b/core/Cargo.toml index 0944bdd..ee6f890 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -1,9 +1,11 @@ [package] name = "taskchampion-sync-server-core" -version = "0.5.0-pre" +version = "0.6.2-pre" authors = ["Dustin J. Mitchell "] edition = "2021" description = "Core of sync protocol for TaskChampion" +homepage = "https://github.com/GothenburgBitFactory/taskchampion" +repository = "https://github.com/GothenburgBitFactory/taskchampion-sync-server" license = "MIT" [dependencies] diff --git a/core/src/inmemory.rs b/core/src/inmemory.rs index 9c7ac48..a6ace2f 100644 --- a/core/src/inmemory.rs +++ b/core/src/inmemory.rs @@ -130,7 +130,6 @@ impl StorageTxn for InnerTxn<'_> { parent_version_id: Uuid, history_segment: Vec, ) -> anyhow::Result<()> { - // TODO: verify it doesn't exist (`.entry`?) let version = Version { version_id, parent_version_id, @@ -143,15 +142,33 @@ impl StorageTxn for InnerTxn<'_> { snap.versions_since += 1; } } else { - return Err(anyhow::anyhow!("Client {} does not exist", self.client_id)); + anyhow::bail!("Client {} does not exist", self.client_id); } - self.guard + if self + .guard .children - .insert((self.client_id, parent_version_id), version_id); - self.guard + .insert((self.client_id, parent_version_id), version_id) + .is_some() + { + anyhow::bail!( + "Client {} already has a child for {}", + self.client_id, + parent_version_id + ); + } + if self + .guard .versions - .insert((self.client_id, version_id), version); + .insert((self.client_id, version_id), version) + .is_some() + { + anyhow::bail!( + "Client {} already has a version {}", + self.client_id, + version_id + ); + } self.written = true; Ok(()) @@ -259,6 +276,25 @@ mod test { Ok(()) } + #[test] + fn test_add_version_exists() -> anyhow::Result<()> { + let storage = InMemoryStorage::new(); + let client_id = Uuid::new_v4(); + let mut txn = storage.txn(client_id)?; + + let version_id = Uuid::new_v4(); + let parent_version_id = Uuid::new_v4(); + let history_segment = b"abc".to_vec(); + + txn.new_client(parent_version_id)?; + txn.add_version(version_id, parent_version_id, history_segment.clone())?; + assert!(txn + .add_version(version_id, parent_version_id, history_segment.clone()) + .is_err()); + txn.commit()?; + Ok(()) + } + #[test] fn test_snapshots() -> anyhow::Result<()> { let storage = InMemoryStorage::new(); diff --git a/docker-compose.yml b/docker-compose.yml index 7d6255d..5b45098 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,16 +1,13 @@ volumes: data: + services: - # Make the necessary subdirectories of the `data` volume, and set ownership of the - # `tss/taskchampion-sync-server` directory, as the server runs as user 100. mkdir: image: caddy:2-alpine command: | /bin/sh -c " - mkdir -p /data/caddy/data /data/caddy/config /data/tss/taskchampion-sync-server && - chown -R 100:100 /data/tss/taskchampion-sync-server - " + mkdir -p /data/caddy/data /data/caddy/config /data/tss/taskchampion-sync-server" volumes: - type: volume source: data @@ -46,19 +43,21 @@ services: condition: service_completed_successfully tss: - image: ghcr.io/gothenburgbitfactory/taskchampion-sync-server:main + image: ghcr.io/gothenburgbitfactory/taskchampion-sync-server:0.6.1 restart: unless-stopped + environment: + - "RUST_LOG=info" + - "DATA_DIR=/var/lib/taskchampion-sync-server/data" + - "LISTEN=0.0.0.0:8080" + - "CLIENT_ID=${TASKCHAMPION_SYNC_SERVER_CLIENT_ID}" volumes: - type: volume source: data - target: /tss + target: /var/lib/taskchampion-sync-server/data read_only: false volume: nocopy: true - subpath: tss - command: --data-dir /tss/taskchampion-sync-server --port 8080 - environment: - - RUST_LOG=info + subpath: tss/taskchampion-sync-server depends_on: mkdir: condition: service_completed_successfully diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh new file mode 100755 index 0000000..4004966 --- /dev/null +++ b/docker-entrypoint.sh @@ -0,0 +1,29 @@ +#!/bin/sh +set -e +echo "starting entrypoint script..." +if [ "$1" = "/bin/taskchampion-sync-server" ]; then + : ${DATA_DIR:=/var/lib/taskchampion-sync-server} + export DATA_DIR + echo "setting up data directory ${DATA_DIR}" + mkdir -p "${DATA_DIR}" + chown -R taskchampion:users "${DATA_DIR}" + chmod -R 700 "${DATA_DIR}" + + : ${LISTEN:=0.0.0.0:8080} + export LISTEN + echo "Listen set to ${LISTEN}" + + if [ -n "${CLIENT_ID}" ]; then + export CLIENT_ID + echo "Limiting to client ID ${CLIENT_ID}" + else + unset CLIENT_ID + fi + + if [ "$(id -u)" = "0" ]; then + echo "Running server as user 'taskchampion'" + exec su-exec taskchampion "$@" + fi +else + eval "${@}" +fi diff --git a/server/Cargo.toml b/server/Cargo.toml index f631ac5..9aea205 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "taskchampion-sync-server" -version = "0.4.1" +version = "0.6.2-pre" authors = ["Dustin J. Mitchell "] edition = "2021" publish = false @@ -24,3 +24,4 @@ chrono.workspace = true actix-rt.workspace = true tempfile.workspace = true pretty_assertions.workspace = true +temp-env.workspace = true diff --git a/server/src/bin/taskchampion-sync-server.rs b/server/src/bin/taskchampion-sync-server.rs index 15fd9c3..d75ecda 100644 --- a/server/src/bin/taskchampion-sync-server.rs +++ b/server/src/bin/taskchampion-sync-server.rs @@ -21,30 +21,38 @@ fn command() -> Command { .version(env!("CARGO_PKG_VERSION")) .about("Server for TaskChampion") .arg( - arg!(-p --port "Port on which to serve") - .help("Port on which to serve") - .value_parser(value_parser!(usize)) - .default_value("8080"), + arg!(-l --listen
) + .help("Address and Port on which to listen on. Can be an IP Address or a DNS name followed by a colon and a port e.g. localhost:8080") + .value_delimiter(',') + .value_parser(ValueParser::string()) + .env("LISTEN") + .action(ArgAction::Append) + .required(true), ) .arg( arg!(-d --"data-dir" "Directory in which to store data") .value_parser(ValueParser::os_string()) + .env("DATA_DIR") .default_value("/var/lib/taskchampion-sync-server"), ) .arg( arg!(-C --"allow-client-id" "Client IDs to allow (can be repeated; if not specified, all clients are allowed)") + .value_delimiter(',') .value_parser(value_parser!(Uuid)) + .env("CLIENT_ID") .action(ArgAction::Append) .required(false), ) .arg( arg!(--"snapshot-versions" "Target number of versions between snapshots") .value_parser(value_parser!(u32)) + .env("SNAPSHOT_VERSIONS") .default_value(default_snapshot_versions), ) .arg( arg!(--"snapshot-days" "Target number of days between snapshots") .value_parser(value_parser!(i64)) + .env("SNAPSHOT_DAYS") .default_value(default_snapshot_days), ) } @@ -56,35 +64,59 @@ fn print_error(res: ServiceResponse) -> actix_web::Result>, + listen_addresses: Vec, +} + +impl ServerArgs { + fn new(matches: clap::ArgMatches) -> Self { + Self { + data_dir: matches.get_one::("data-dir").unwrap().clone(), + snapshot_versions: *matches.get_one("snapshot-versions").unwrap(), + snapshot_days: *matches.get_one("snapshot-days").unwrap(), + client_id_allowlist: matches + .get_many("allow-client-id") + .map(|ids| ids.copied().collect()), + listen_addresses: matches + .get_many::("listen") + .unwrap() + .cloned() + .collect(), + } + } +} + #[actix_web::main] async fn main() -> anyhow::Result<()> { env_logger::init(); let matches = command().get_matches(); - let data_dir: &OsString = matches.get_one("data-dir").unwrap(); - let port: usize = *matches.get_one("port").unwrap(); - let snapshot_versions: u32 = *matches.get_one("snapshot-versions").unwrap(); - let snapshot_days: i64 = *matches.get_one("snapshot-days").unwrap(); - let client_id_allowlist: Option> = matches - .get_many("allow-client-id") - .map(|ids| ids.copied().collect()); - + let server_args = ServerArgs::new(matches); let config = ServerConfig { - snapshot_days, - snapshot_versions, + snapshot_days: server_args.snapshot_days, + snapshot_versions: server_args.snapshot_versions, }; - let server = WebServer::new(config, client_id_allowlist, SqliteStorage::new(data_dir)?); + let server = WebServer::new( + config, + server_args.client_id_allowlist, + SqliteStorage::new(server_args.data_dir)?, + ); - log::info!("Serving on port {}", port); - HttpServer::new(move || { + let mut http_server = HttpServer::new(move || { App::new() .wrap(ErrorHandlers::new().handler(StatusCode::INTERNAL_SERVER_ERROR, print_error)) .wrap(Logger::default()) .configure(|cfg| server.config(cfg)) - }) - .bind(format!("0.0.0.0:{}", port))? - .run() - .await?; + }); + for listen_address in server_args.listen_addresses { + log::info!("Serving on {}", listen_address); + http_server = http_server.bind(listen_address)? + } + http_server.run().await?; Ok(()) } @@ -94,55 +126,187 @@ mod test { use actix_web::{self, App}; use clap::ArgMatches; use taskchampion_sync_server_core::InMemoryStorage; + use temp_env::{with_var, with_var_unset, with_vars, with_vars_unset}; - /// Get the list of allowed client IDs - fn allowed(matches: &ArgMatches) -> Option> { - matches - .get_many::("allow-client-id") - .map(|ids| ids.copied().collect::>()) + /// Get the list of allowed client IDs, sorted. + fn allowed(matches: ArgMatches) -> Option> { + ServerArgs::new(matches) + .client_id_allowlist + .map(|ids| ids.into_iter().collect::>()) + .map(|mut ids| { + ids.sort(); + ids + }) + } + + #[test] + fn command_listen_two() { + with_var_unset("LISTEN", || { + let matches = command().get_matches_from([ + "tss", + "--listen", + "localhost:8080", + "--listen", + "otherhost:9090", + ]); + assert_eq!( + ServerArgs::new(matches).listen_addresses, + vec!["localhost:8080".to_string(), "otherhost:9090".to_string()] + ); + }); + } + + #[test] + fn command_listen_two_env() { + with_var("LISTEN", Some("localhost:8080,otherhost:9090"), || { + let matches = command().get_matches_from(["tss"]); + assert_eq!( + ServerArgs::new(matches).listen_addresses, + vec!["localhost:8080".to_string(), "otherhost:9090".to_string()] + ); + }); } #[test] fn command_allowed_client_ids_none() { - let matches = command().get_matches_from(["tss"]); - assert_eq!(allowed(&matches), None); + with_var_unset("CLIENT_ID", || { + let matches = command().get_matches_from(["tss", "--listen", "localhost:8080"]); + assert_eq!(allowed(matches), None); + }); } #[test] fn command_allowed_client_ids_one() { - let matches = - command().get_matches_from(["tss", "-C", "711d5cf3-0cf0-4eb8-9eca-6f7f220638c0"]); - assert_eq!( - allowed(&matches), - Some(vec![Uuid::parse_str( - "711d5cf3-0cf0-4eb8-9eca-6f7f220638c0" - ) - .unwrap()]) + with_var_unset("CLIENT_ID", || { + let matches = command().get_matches_from([ + "tss", + "--listen", + "localhost:8080", + "-C", + "711d5cf3-0cf0-4eb8-9eca-6f7f220638c0", + ]); + assert_eq!( + allowed(matches), + Some(vec![Uuid::parse_str( + "711d5cf3-0cf0-4eb8-9eca-6f7f220638c0" + ) + .unwrap()]) + ); + }); + } + + #[test] + fn command_allowed_client_ids_one_env() { + with_var( + "CLIENT_ID", + Some("711d5cf3-0cf0-4eb8-9eca-6f7f220638c0"), + || { + let matches = command().get_matches_from(["tss", "--listen", "localhost:8080"]); + assert_eq!( + allowed(matches), + Some(vec![Uuid::parse_str( + "711d5cf3-0cf0-4eb8-9eca-6f7f220638c0" + ) + .unwrap()]) + ); + }, ); } #[test] fn command_allowed_client_ids_two() { - let matches = command().get_matches_from([ - "tss", - "-C", - "711d5cf3-0cf0-4eb8-9eca-6f7f220638c0", - "-C", - "bbaf4b61-344a-4a39-a19e-8caa0669b353", - ]); - assert_eq!( - allowed(&matches), - Some(vec![ - Uuid::parse_str("711d5cf3-0cf0-4eb8-9eca-6f7f220638c0").unwrap(), - Uuid::parse_str("bbaf4b61-344a-4a39-a19e-8caa0669b353").unwrap() - ]) + with_var_unset("CLIENT_ID", || { + let matches = command().get_matches_from([ + "tss", + "--listen", + "localhost:8080", + "-C", + "711d5cf3-0cf0-4eb8-9eca-6f7f220638c0", + "-C", + "bbaf4b61-344a-4a39-a19e-8caa0669b353", + ]); + assert_eq!( + allowed(matches), + Some(vec![ + Uuid::parse_str("711d5cf3-0cf0-4eb8-9eca-6f7f220638c0").unwrap(), + Uuid::parse_str("bbaf4b61-344a-4a39-a19e-8caa0669b353").unwrap() + ]) + ); + }); + } + + #[test] + fn command_allowed_client_ids_two_env() { + with_var( + "CLIENT_ID", + Some("711d5cf3-0cf0-4eb8-9eca-6f7f220638c0,bbaf4b61-344a-4a39-a19e-8caa0669b353"), + || { + let matches = command().get_matches_from(["tss", "--listen", "localhost:8080"]); + assert_eq!( + allowed(matches), + Some(vec![ + Uuid::parse_str("711d5cf3-0cf0-4eb8-9eca-6f7f220638c0").unwrap(), + Uuid::parse_str("bbaf4b61-344a-4a39-a19e-8caa0669b353").unwrap() + ]) + ); + }, ); } #[test] fn command_data_dir() { - let matches = command().get_matches_from(["tss", "--data-dir", "/foo/bar"]); - assert_eq!(matches.get_one::("data-dir").unwrap(), "/foo/bar"); + with_var_unset("DATA_DIR", || { + let matches = command().get_matches_from([ + "tss", + "--data-dir", + "/foo/bar", + "--listen", + "localhost:8080", + ]); + assert_eq!(ServerArgs::new(matches).data_dir, "/foo/bar"); + }); + } + + #[test] + fn command_data_dir_env() { + with_var("DATA_DIR", Some("/foo/bar"), || { + let matches = command().get_matches_from(["tss", "--listen", "localhost:8080"]); + assert_eq!(ServerArgs::new(matches).data_dir, "/foo/bar"); + }); + } + + #[test] + fn command_snapshot() { + with_vars_unset(["SNAPSHOT_DAYS", "SNAPSHOT_VERSIONS"], || { + let matches = command().get_matches_from([ + "tss", + "--listen", + "localhost:8080", + "--snapshot-days", + "13", + "--snapshot-versions", + "20", + ]); + let server_args = ServerArgs::new(matches); + assert_eq!(server_args.snapshot_days, 13i64); + assert_eq!(server_args.snapshot_versions, 20u32); + }); + } + + #[test] + fn command_snapshot_env() { + with_vars( + [ + ("SNAPSHOT_DAYS", Some("13")), + ("SNAPSHOT_VERSIONS", Some("20")), + ], + || { + let matches = command().get_matches_from(["tss", "--listen", "localhost:8080"]); + let server_args = ServerArgs::new(matches); + assert_eq!(server_args.snapshot_days, 13i64); + assert_eq!(server_args.snapshot_versions, 20u32); + }, + ); } #[actix_rt::test] diff --git a/sqlite/Cargo.toml b/sqlite/Cargo.toml index 7187891..6718f19 100644 --- a/sqlite/Cargo.toml +++ b/sqlite/Cargo.toml @@ -1,13 +1,15 @@ [package] name = "taskchampion-sync-server-storage-sqlite" -version = "0.5.0-pre" +version = "0.6.2-pre" authors = ["Dustin J. Mitchell "] edition = "2021" description = "SQLite backend for TaskChampion-sync-server" +homepage = "https://github.com/GothenburgBitFactory/taskchampion" +repository = "https://github.com/GothenburgBitFactory/taskchampion-sync-server" license = "MIT" [dependencies] -taskchampion-sync-server-core = { path = "../core", version = "0.5.0-pre" } +taskchampion-sync-server-core = { path = "../core", version = "0.6.2-pre" } uuid.workspace = true anyhow.workspace = true thiserror.workspace = true diff --git a/sqlite/src/lib.rs b/sqlite/src/lib.rs index 7441b17..bd9f93f 100644 --- a/sqlite/src/lib.rs +++ b/sqlite/src/lib.rs @@ -385,6 +385,23 @@ mod test { Ok(()) } + #[test] + fn test_add_version_exists() -> anyhow::Result<()> { + let tmp_dir = TempDir::new()?; + let storage = SqliteStorage::new(tmp_dir.path())?; + let client_id = Uuid::new_v4(); + let mut txn = storage.txn(client_id)?; + + let version_id = Uuid::new_v4(); + let parent_version_id = Uuid::new_v4(); + let history_segment = b"abc".to_vec(); + txn.add_version(version_id, parent_version_id, history_segment.clone())?; + assert!(txn + .add_version(version_id, parent_version_id, history_segment.clone()) + .is_err()); + Ok(()) + } + #[test] fn test_snapshots() -> anyhow::Result<()> { let tmp_dir = TempDir::new()?;