From 894f1348938114afa8c9cc2beec8ecd39e03f856 Mon Sep 17 00:00:00 2001 From: Marc 'risson' Schmitt Date: Thu, 19 Mar 2026 14:12:00 +0000 Subject: [PATCH] root: init rust workspace (#20983) --- .config/deny.toml | 35 ++ .config/rustfmt.toml | 16 + .github/actions/setup/action.yml | 16 +- .github/actions/test-results/action.yml | 4 + .github/workflows/ci-main.yml | 32 ++ .gitignore | 18 + CODEOWNERS | 5 + Cargo.lock | 271 ++++++++++ Cargo.toml | 133 +++++ Makefile | 22 +- cspell.config.jsonc | 73 +-- locale/en/dictionaries/rust.txt | 13 + rust-toolchain.toml | 2 +- .../setup/full-dev-environment.mdx | 1 + website/scripts/docsmg/Cargo.lock | 474 ------------------ website/scripts/docsmg/Cargo.toml | 26 +- website/scripts/docsmg/install.sh | 4 +- website/scripts/docsmg/src/generate.rs | 19 +- website/scripts/docsmg/src/hackyfixes.rs | 26 +- website/scripts/docsmg/src/links.rs | 18 +- website/scripts/docsmg/src/main.rs | 51 +- website/scripts/docsmg/src/migrate.rs | 338 ++++++------- website/scripts/docsmg/src/migratefile.rs | 19 +- website/scripts/docsmg/src/move.rs | 12 +- 24 files changed, 859 insertions(+), 769 deletions(-) create mode 100644 .config/deny.toml create mode 100644 .config/rustfmt.toml create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 locale/en/dictionaries/rust.txt delete mode 100644 website/scripts/docsmg/Cargo.lock diff --git a/.config/deny.toml b/.config/deny.toml new file mode 100644 index 0000000000..26a61084e8 --- /dev/null +++ b/.config/deny.toml @@ -0,0 +1,35 @@ +[licenses] +allow = ["Apache-2.0", "MIT", "MPL-2.0", "Unicode-3.0"] + +[licenses.private] +ignore = true + +[bans] +multiple-versions = "allow" +wildcards = "deny" +[bans.workspace-dependencies] +duplicates = "deny" +include-path-dependencies = true +unused = "deny" + +# No non-FIPS compliant dependencies +[[bans.deny]] +name = "native-tls" +[[bans.deny]] +name = "openssl" +[[bans.deny]] +name = "openssl-sys" +[[bans.deny]] +name = "ring" +[[bans.features]] +allow = [ + "alloc", + "aws-lc-sys", + "default", + "fips", + "prebuilt-nasm", + "ring-io", + "ring-sig-verify", +] +name = "aws-lc-rs" +exact = true diff --git a/.config/rustfmt.toml b/.config/rustfmt.toml new file mode 100644 index 0000000000..85ee115daf --- /dev/null +++ b/.config/rustfmt.toml @@ -0,0 +1,16 @@ +comment_width = 100 +format_code_in_doc_comments = true +format_strings = true +group_imports = "StdExternalCrate" +hex_literal_case = "Lower" +imports_granularity = "Crate" +max_width = 100 +newline_style = "Unix" +normalize_comments = true +normalize_doc_attributes = true +reorder_impl_items = true +style_edition = "2024" +use_field_init_shorthand = true +use_try_shorthand = true +where_single_line = true +wrap_comments = true diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index 42a3bcb47f..09fb27c87b 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -4,7 +4,7 @@ description: "Setup authentik testing environment" inputs: dependencies: description: "List of dependencies to setup" - default: "system,python,node,go,runtime" + default: "system,python,rust,node,go,runtime" postgresql_version: description: "Optional postgresql image tag" default: "16" @@ -34,6 +34,20 @@ runs: if: ${{ contains(inputs.dependencies, 'python') }} shell: bash run: uv sync --all-extras --dev --frozen + - name: Setup rust (stable) + if: ${{ contains(inputs.dependencies, 'rust') && !contains(inputs.dependencies, 'rust-nightly') }} + uses: actions-rust-lang/setup-rust-toolchain@a0b538fa0b742a6aa35d6e2c169b4bd06d225a98 # v1 + - name: Setup rust (nightly) + if: ${{ contains(inputs.dependencies, 'rust-nightly') }} + uses: actions-rust-lang/setup-rust-toolchain@a0b538fa0b742a6aa35d6e2c169b4bd06d225a98 # v1 + with: + toolchain: nightly + components: rustfmt + - name: Setup rust dependencies + if: ${{ contains(inputs.dependencies, 'rust') }} + uses: taiki-e/install-action@64c5c20c872907b6f7cd50994ac189e7274160f2 # v2 + with: + tool: cargo-deny cargo-machete cargo-llvm-cov nextest - name: Setup node (web) if: ${{ contains(inputs.dependencies, 'node') }} uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v4 diff --git a/.github/actions/test-results/action.yml b/.github/actions/test-results/action.yml index d2dc472891..253624b6e0 100644 --- a/.github/actions/test-results/action.yml +++ b/.github/actions/test-results/action.yml @@ -2,6 +2,8 @@ name: "Process test results" description: Convert test results to JUnit, add them to GitHub Actions and codecov inputs: + files: + description: Comma-separated explicit list of files to upload flags: description: Codecov flags @@ -10,10 +12,12 @@ runs: steps: - uses: codecov/codecov-action@1af58845a975a7985b0beb0cbe6fbbb71a41dbad # v5 with: + files: ${{ inputs.files }} flags: ${{ inputs.flags }} use_oidc: true - uses: codecov/codecov-action@1af58845a975a7985b0beb0cbe6fbbb71a41dbad # v5 with: + files: ${{ inputs.files }} flags: ${{ inputs.flags }} use_oidc: true report_type: test_results diff --git a/.github/workflows/ci-main.yml b/.github/workflows/ci-main.yml index 6d57cacb84..5bb0c264c8 100644 --- a/.github/workflows/ci-main.yml +++ b/.github/workflows/ci-main.yml @@ -16,6 +16,7 @@ env: POSTGRES_DB: authentik POSTGRES_USER: authentik POSTGRES_PASSWORD: "EK-5jnKfjrGRm<77" + RUSTFLAGS: "-Dwarnings" permissions: # Needed for checkout @@ -41,6 +42,14 @@ jobs: deps: python - job: mypy deps: python + - job: cargo-deny + deps: rust + - job: cargo-machete + deps: rust + - job: clippy + deps: rust + - job: rustfmt + deps: rust-nightly runs-on: ubuntu-latest steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5 @@ -291,6 +300,29 @@ jobs: with: name: conformance-certification-${{ matrix.job.name }} path: tests/openid_conformance/exports/ + test-rust: + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v5 + - name: Setup authentik env + uses: ./.github/actions/setup + with: + dependencies: rust + - name: run tests + run: | + cargo llvm-cov --no-report nextest --workspace + cargo llvm-cov report --codecov --output-path target/llvm-cov-target/rust.json + - uses: ./.github/actions/test-results + if: ${{ always() }} + with: + files: target/llvm-cov-target/rust.json + flags: rust + - if: ${{ !cancelled() }} + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + with: + name: test-rust + path: target/llvm-cov-target/rust.json ci-core-mark: if: always() needs: diff --git a/.gitignore b/.gitignore index 4734c1d09c..01c20f85f1 100644 --- a/.gitignore +++ b/.gitignore @@ -195,6 +195,24 @@ pyvenv.cfg pip-selfcheck.json # End of https://www.gitignore.io/api/python,django + +# Created by https://www.toptal.com/developers/gitignore/api/rust +# Edit at https://www.toptal.com/developers/gitignore?templates=rust + +### Rust ### +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb + +# End of https://www.toptal.com/developers/gitignore/api/rust + /static/ local.env.yml diff --git a/CODEOWNERS b/CODEOWNERS index fa3f25dc7b..ffb2bffde4 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -3,6 +3,7 @@ # Backend authentik/ @goauthentik/backend blueprints/ @goauthentik/backend +src/ @goauthentik/backend cmd/ @goauthentik/backend internal/ @goauthentik/backend lifecycle/ @goauthentik/backend @@ -11,8 +12,12 @@ scripts/ @goauthentik/backend tests/ @goauthentik/backend pyproject.toml @goauthentik/backend uv.lock @goauthentik/backend +Cargo.toml @goauthentik/backend +Cargo.lock @goauthentik/backend go.mod @goauthentik/backend go.sum @goauthentik/backend +.config/ @goauthentik/backend +rust-toolchain.toml @goauthentik/backend # Infrastructure .github/ @goauthentik/infrastructure lifecycle/aws/ @goauthentik/infrastructure diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000000..7e04eb34d8 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,271 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "anstream" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" + +[[package]] +name = "anstyle-parse" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys", +] + +[[package]] +name = "clap" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1110bd8a634a1ab8cb04345d8d878267d57c3cf1b38d91b71af6686408bbca6a" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" + +[[package]] +name = "colorchoice" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" + +[[package]] +name = "colored" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "docsmg" +version = "0.0.0" +dependencies = [ + "clap", + "colored", + "dotenvy", + "eyre", + "regex", +] + +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + +[[package]] +name = "eyre" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" +dependencies = [ + "indenter", + "once_cell", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "indenter" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "964de6e86d545b246d84badc0fef527924ace5134f30641c203ef52ba83f58d5" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000000..47987f7b26 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,133 @@ +[workspace] +members = ["website/scripts/docsmg"] +resolver = "3" + +[workspace.package] +authors = ["authentik Team "] +edition = "2024" +readme = "README.md" +homepage = "https://goauthentik.io" +repository = "https://github.com/goauthentik/authentik.git" +license-file = "LICENSE" +publish = false + +[workspace.dependencies] +clap = { version = "4.5.59", features = ["derive", "env"] } +colored = "3.1.1" +dotenvy = "0.15.7" +eyre = "0.6.12" +regex = "1.12.3" + +[profile.dev.package.backtrace] +opt-level = 3 + +[profile.release] +lto = true +debug = 2 + +[workspace.lints.rust] +ambiguous_negative_literals = "warn" +closure_returning_async_block = "warn" +macro_use_extern_crate = "deny" +# must_not_suspend = "deny", unstable see https://github.com/rust-lang/rust/issues/83310 +non_ascii_idents = "deny" +redundant_imports = "warn" +semicolon_in_expressions_from_macros = "warn" +trivial_casts = "warn" +trivial_numeric_casts = "warn" +unit_bindings = "warn" +unreachable_pub = "warn" +unsafe_code = "deny" +unused_extern_crates = "warn" +unused_import_braces = "warn" +unused_lifetimes = "warn" +unused_macro_rules = "warn" +unused_qualifications = "warn" + +[workspace.lints.rustdoc] +unescaped_backticks = "warn" + +[workspace.lints.clippy] +### enable all lints +cargo = { priority = -1, level = "warn" } +complexity = { priority = -1, level = "warn" } +correctness = { priority = -1, level = "warn" } +nursery = { priority = -1, level = "warn" } +pedantic = { priority = -1, level = "warn" } +perf = { priority = -1, level = "warn" } +# Those are too restrictive and disabled by default, however we enable some below +# restriction = { priority = -1, level = "warn" } +style = { priority = -1, level = "warn" } +suspicious = { priority = -1, level = "warn" } +### and disable the ones we don't want +### pedantic group +redundant_closure_for_method_calls = "allow" +too_many_lines = "allow" +### nursery +redundant_pub_crate = "allow" +option_if_let_else = "allow" +### restriction group +allow_attributes = "warn" +allow_attributes_without_reason = "warn" +as_conversions = "warn" +as_pointer_underscore = "warn" +as_underscore = "warn" +assertions_on_result_states = "warn" +clone_on_ref_ptr = "warn" +create_dir = "warn" +dbg_macro = "warn" +default_numeric_fallback = "warn" +disallowed_script_idents = "warn" +doc_paragraphs_missing_punctuation = "warn" +empty_drop = "warn" +empty_enum_variants_with_brackets = "warn" +empty_structs_with_brackets = "warn" +error_impl_error = "warn" +exit = "warn" +filetype_is_file = "warn" +float_cmp_const = "warn" +fn_to_numeric_cast_any = "warn" +get_unwrap = "warn" +if_then_some_else_none = "warn" +impl_trait_in_params = "warn" +infinite_loop = "warn" +lossy_float_literal = "warn" +map_with_unused_argument_over_ranges = "warn" +mem_forget = "warn" +missing_asserts_for_indexing = "warn" +missing_trait_methods = "warn" +mixed_read_write_in_expression = "warn" +mutex_atomic = "warn" +mutex_integer = "warn" +needless_raw_strings = "warn" +non_zero_suggestions = "warn" +panic_in_result_fn = "warn" +pathbuf_init_then_push = "warn" +print_stdout = "warn" +rc_buffer = "warn" +redundant_test_prefix = "warn" +redundant_type_annotations = "warn" +ref_patterns = "warn" +renamed_function_params = "warn" +rest_pat_in_fully_bound_structs = "warn" +return_and_then = "warn" +same_name_method = "warn" +semicolon_inside_block = "warn" +str_to_string = "warn" +string_add = "warn" +suspicious_xor_used_as_pow = "warn" +tests_outside_test_module = "warn" +todo = "warn" +try_err = "warn" +undocumented_unsafe_blocks = "warn" +unimplemented = "warn" +unnecessary_safety_comment = "warn" +unnecessary_safety_doc = "warn" +unnecessary_self_imports = "warn" +unneeded_field_pattern = "warn" +unseparated_literal_suffix = "warn" +unused_result_ok = "warn" +unused_trait_names = "warn" +unwrap_in_result = "warn" +unwrap_used = "warn" +verbose_file_reads = "warn" diff --git a/Makefile b/Makefile index 4e5d2a28b2..769bfc7226 100644 --- a/Makefile +++ b/Makefile @@ -23,6 +23,7 @@ BREW_LDFLAGS := BREW_CPPFLAGS := BREW_PKG_CONFIG_PATH := +CARGO := cargo UV := uv # For macOS users, add the libxml2 installed from brew libxmlsec1 to the build path @@ -69,9 +70,12 @@ help: ## Show this help sort @echo "" -go-test: +go-test: ## Run the golang tests go test -timeout 0 -v -race -cover ./... +rust-test: ## Run the Rust tests + $(CARGO) nextest run --workspace + test: ## Run the server tests and produce a coverage report (locally) $(UV) run coverage run manage.py test --keepdb $(or $(filter-out $@,$(MAKECMDGOALS)),authentik) $(UV) run coverage html @@ -80,11 +84,12 @@ test: ## Run the server tests and produce a coverage report (locally) lint-fix: ## Lint and automatically fix errors in the python source code. Reports spelling errors. $(UV) run black $(PY_SOURCES) $(UV) run ruff check --fix $(PY_SOURCES) + $(CARGO) +nightly fmt --all -- --config-path .config/rustfmt.toml lint-spellcheck: ## Reports spelling errors. npm run lint:spellcheck -lint: ci-lint-bandit ci-lint-mypy ## Lint the python and golang sources +lint: ci-lint-bandit ci-lint-mypy ci-lint-cargo-deny ci-lint-cargo-machete ## Lint the python and golang sources golangci-lint run -v core-install: @@ -332,6 +337,7 @@ test-docker: ci--meta-debug: $(UV) run python -V || echo "No python installed" + $(CARGO) --version || echo "No rust installed" node --version || echo "No node installed" ci-lint-mypy: ci--meta-debug @@ -352,6 +358,18 @@ ci-lint-bandit: ci--meta-debug ci-lint-pending-migrations: ci--meta-debug $(UV) run ak makemigrations --check +ci-lint-cargo-deny: ci--meta-debug + $(CARGO) deny --locked --workspace check --config .config/deny.toml + +ci-lint-cargo-machete: ci--meta-debug + $(CARGO) machete + +ci-lint-rustfmt: ci--meta-debug + $(CARGO) +nightly fmt --all --check -- --config-path .config/rustfmt.toml + +ci-lint-clippy: ci--meta-debug + $(CARGO) clippy -- -D warnings + ci-test: ci--meta-debug $(UV) run coverage run manage.py test --keepdb authentik $(UV) run coverage report diff --git a/cspell.config.jsonc b/cspell.config.jsonc index b9f5a8cf3b..f71c0cd906 100644 --- a/cspell.config.jsonc +++ b/cspell.config.jsonc @@ -12,7 +12,12 @@ }, "reporters": [ "default", - ["@cspell/cspell-json-reporter", { "outFile": "./cspell-report.json" }] + [ + "@cspell/cspell-json-reporter", + { + "outFile": "./cspell-report.json" + } + ] ], "dictionaryDefinitions": [ { @@ -32,12 +37,16 @@ "path": "./locale/en/dictionaries/python.txt", "addWords": true }, + { + "name": "en-x-authentik-rust", + "path": "./locale/en/dictionaries/rust.txt", + "addWords": true + }, { "name": "en-x-authentik-golang", "path": "./locale/en/dictionaries/golang.txt", "addWords": true }, - { "name": "en-x-authentik-people", "path": "./locale/en/dictionaries/people.txt", @@ -81,7 +90,10 @@ { "name": "ConfSuffix", "description": "Variables with `conf` or `config` suffix", - "pattern": ["\\w+(conf|config)\\b", "\\b(conf|config)\\w+"] + "pattern": [ + "\\w+(conf|config)\\b", + "\\b(conf|config)\\w+" + ] } ], "ignoreRegExpList": [ @@ -119,7 +131,6 @@ "\\w+l?ified\\b", // "ifying" suffix, e.g. "stringifying", "classifying". "\\w+l?ifying\\b", - "SpellCheckerIgnoreInDocSetting", "EncodedURI", "Urls", @@ -135,7 +146,11 @@ "languageSettings": [ { "languageId": "markdown,mdx", - "dictionaries": ["en-x-authentik-python", "en-x-authentik-golang"], + "dictionaries": [ + "en-x-authentik-python", + "en-x-authentik-rust", + "en-x-authentik-golang" + ], "ignoreRegExpList": [ // Fenced code blocks "/^\\s*```[\\s\\S]*?^\\s*```/gm", @@ -146,7 +161,6 @@ }, { "languageId": "typescript,javascript,typescriptreact,javascriptreact,mdx,astro", - "ignoreRegExpList": [ // Event handlers e.g. onClick, onmouseover "\\bon\\w+\\b", @@ -166,18 +180,33 @@ }, { "languageId": "python", - "dictionaries": ["en-x-authentik-python"], - "includeRegExpList": ["comments"] + "dictionaries": [ + "en-x-authentik-python" + ], + "includeRegExpList": [ + "comments" + ] + }, + { + "languageId": "rust", + "dictionaries": [ + "en-x-authentik-rust" + ] }, { "languageId": "go", - "dictionaries": ["en-x-authentik-golang"] + "dictionaries": [ + "en-x-authentik-golang" + ] }, { - "languageId": "makefile", - "dictionaries": ["en-x-authentik-python", "en-x-authentik-golang"] + "languageId": "makefile,toml,yaml", + "dictionaries": [ + "en-x-authentik-python", + "en-x-authentik-rust", + "en-x-authentik-golang" + ] }, - { "languageId": "css,scss", "ignoreRegExpList": [ @@ -188,20 +217,15 @@ ], "ignorePaths": [ //#region i18n - "{cspell.*,cSpell.*,.cspell.*,cspell.config.*}", // CSpell configuration files "cspell-report.{json,html,txt}", // CSpell report files "dictionaries", // Custom dictionary files "ignore.txt", // Custom ignore list files - "./locale", // Locale files (Django, CSpell) "web/xliff", // XLIFF translation files "web/src/locales", // Generated TypeScript locale - //#endregion - //#region Monorepo - "CODEOWNERS", // GitHub code owners file "LICENSE", // License file ".gitignore", // Git ignore file @@ -224,9 +248,7 @@ "fixtures", // Test fixtures "tests/e2e/**/*.php", // PHP fixtures "compose.yml", // Docker Compose files - //#region JavaScript/TypeScript - ".eslintignore", // ESLint ignore file ".prettierignore", // Prettier ignore file ".yarn", // Yarn cache and configuration @@ -239,7 +261,6 @@ "*.min.{js,css}", // Minified JS and CSS files "*.min.{js,css}.map", // Source maps for minified files //#region Python - "pyproject.toml", "unittest.xml", // Pytest output ".venv", // Python virtual environment @@ -248,37 +269,25 @@ "blueprints", "mds", //#endregion - //#region Rust - "./target", // Rust compilation artifacts - //#endregion - //#region Docusaurus - "*.api.mdx", // Generated API docs ".docusaurus/**", // Cache "./{docs,website}/build", // Topic docs build output "./{docs,website}/**/build", // Workspaces output - //#endregion - //#region Golang - "go.mod", // Go module file "go.sum", // Go module file "htmlcov", // Coverage HTML output "coverage.txt", // Coverage text output - //#endregion - //#region Media - "./data", // Media files "./media", // Legacy media files "*.{png,jpg,pdf,svg}" // Binary files - //#endregion ], "useGitignore": true, diff --git a/locale/en/dictionaries/rust.txt b/locale/en/dictionaries/rust.txt new file mode 100644 index 0000000000..7c4b914bb2 --- /dev/null +++ b/locale/en/dictionaries/rust.txt @@ -0,0 +1,13 @@ +allinone +argh +clippy +nasm +netns +pointee +rcgen +serde +sqlx +tcpv +tungstenite +unseparated +zstd diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 16ad9a6d2d..7e00284a46 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] channel = "1.94.0" -profile = "minimal" +components = ["clippy", "rust-analyzer", "llvm-tools-preview"] diff --git a/website/docs/developer-docs/setup/full-dev-environment.mdx b/website/docs/developer-docs/setup/full-dev-environment.mdx index 0d75b3cc08..55770c2a5f 100644 --- a/website/docs/developer-docs/setup/full-dev-environment.mdx +++ b/website/docs/developer-docs/setup/full-dev-environment.mdx @@ -18,6 +18,7 @@ Before you begin, ensure you have the following tools installed. You can run the - [Python](https://www.python.org/) (3.14) - [uv](https://docs.astral.sh/uv/getting-started/installation/) (Latest stable release) +- [Rust](https://rust-lang.org/learn/get-started/) (We provide a `rust-toolchain.toml` file for the correct version, and we use the nightly toolchain to run formatting with rustfmt.) - [Go](https://go.dev/) (1.26 or later) - [Node.js](https://nodejs.org/en) (24 or later) - [PostgreSQL](https://www.postgresql.org/) (16 or later) diff --git a/website/scripts/docsmg/Cargo.lock b/website/scripts/docsmg/Cargo.lock deleted file mode 100644 index 0ea7aef5e9..0000000000 --- a/website/scripts/docsmg/Cargo.lock +++ /dev/null @@ -1,474 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "addr2line" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "anstream" -version = "0.6.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" - -[[package]] -name = "anstyle-parse" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" -dependencies = [ - "anstyle", - "windows-sys 0.52.0", -] - -[[package]] -name = "anyhow" -version = "1.0.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" - -[[package]] -name = "backtrace" -version = "0.3.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "cc" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaff6f8ce506b9773fa786672d63fc7a191ffea1be33f72bbd4aeacefca9ffc8" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "clap" -version = "4.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64acc1846d54c1fe936a78dc189c34e28d3f5afc348403f28ecf53660b9b8462" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb8393d67ba2e7bfaf28a23458e4e2b543cc73a99595511eb207fdb8aede942" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_derive" -version = "4.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "clap_lex" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" - -[[package]] -name = "colorchoice" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" - -[[package]] -name = "colored" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" -dependencies = [ - "lazy_static", - "windows-sys 0.48.0", -] - -[[package]] -name = "docsmg" -version = "0.1.0" -dependencies = [ - "anyhow", - "clap", - "colored", - "dotenv", - "regex", - "tokio", -] - -[[package]] -name = "dotenv" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" - -[[package]] -name = "gimli" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "is_terminal_polyfill" -version = "1.70.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "libc" -version = "0.2.155" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "miniz_oxide" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" -dependencies = [ - "adler", -] - -[[package]] -name = "object" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce" -dependencies = [ - "memchr", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" - -[[package]] -name = "proc-macro2" -version = "1.0.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "regex" -version = "1.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" - -[[package]] -name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" - -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - -[[package]] -name = "syn" -version = "2.0.70" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0209b68b3613b093e0ec905354eccaedcfe83b8cb37cbdeae64026c3064c16" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tokio" -version = "1.38.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" -dependencies = [ - "backtrace", - "pin-project-lite", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "utf8parse" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/website/scripts/docsmg/Cargo.toml b/website/scripts/docsmg/Cargo.toml index 9a7e18c861..0c12214ae2 100644 --- a/website/scripts/docsmg/Cargo.toml +++ b/website/scripts/docsmg/Cargo.toml @@ -1,14 +1,20 @@ [package] name = "docsmg" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +version = "0.0.0" +authors.workspace = true +edition.workspace = true +readme.workspace = true +homepage.workspace = true +repository.workspace = true +license-file.workspace = true +publish = false [dependencies] -anyhow = "1.0.86" -clap = { version = "4.5.9", features = ["derive", "env"] } -colored = "2.1.0" -dotenv = "0.15.0" -regex = "1.10.6" -tokio = "1.38.0" +eyre.workspace = true +clap.workspace = true +colored.workspace = true +dotenvy.workspace = true +regex.workspace = true + +[lints] +workspace = true diff --git a/website/scripts/docsmg/install.sh b/website/scripts/docsmg/install.sh index b00126dbec..d2fbe26d67 100755 --- a/website/scripts/docsmg/install.sh +++ b/website/scripts/docsmg/install.sh @@ -1,5 +1,5 @@ -cargo install --git https://github.com/goauthentik/authentik +cargo install --git https://github.com/goauthentik/authentik docsmg sudo wget https://raw.githubusercontent.com/goauthentik/authentik/main/website/scripts/docsmg/m.bash -O /bin/map sudo wget https://raw.githubusercontent.com/goauthentik/authentik/main/website/scripts/docsmg/mcomplete.bash -O /bin/mapcomplete sudo chmod 755 /bin/map -echo "source mapcomplete" >> ~/.zshrc +echo "source mapcomplete" >>~/.zshrc diff --git a/website/scripts/docsmg/src/generate.rs b/website/scripts/docsmg/src/generate.rs index bda5dd017c..55cf8d6052 100644 --- a/website/scripts/docsmg/src/generate.rs +++ b/website/scripts/docsmg/src/generate.rs @@ -1,31 +1,24 @@ -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use crate::{migratefile::read_migrate_file_left_side, recurse_directory}; -pub fn generate(migratefile: Option, migrate_path: PathBuf) { +pub(crate) fn generate(migratefile: Option<&Path>, migrate_path: &Path) { // if there is a migrate file, read it and get the paths from the left side let paths: Vec = match migratefile { - Some(i) => { - let contents = read_migrate_file_left_side(i); - if let Ok(contents) = contents { - contents - } else { - vec![] - } - } + Some(i) => read_migrate_file_left_side(i).unwrap_or_default(), None => { vec![] } }; // get rid of paths already in the specified migrate file - let paths: Vec = recurse_directory(migrate_path.clone()) + let paths: Vec = recurse_directory(migrate_path) .iter() - .filter_map(|x| x.strip_prefix(migrate_path.clone()).ok()) + .filter_map(|x| x.strip_prefix(migrate_path).ok()) .filter(|x| !paths.contains(&x.to_path_buf())) .map(|x| x.to_path_buf()) .collect(); for path in paths { - println!("{} ->", path.display()); + eprintln!("{} ->", path.display()); } } diff --git a/website/scripts/docsmg/src/hackyfixes.rs b/website/scripts/docsmg/src/hackyfixes.rs index f7c3ab0204..5fd4c6dbcb 100644 --- a/website/scripts/docsmg/src/hackyfixes.rs +++ b/website/scripts/docsmg/src/hackyfixes.rs @@ -1,24 +1,30 @@ -use std::{ffi::OsStr, fs::{read_to_string, write}, path::PathBuf}; +use std::{ + fs::{read_to_string, write}, + path::Path, +}; use crate::recurse_directory; -pub fn add_extra_dot_dot_to_expression_mdx(migrate_path: PathBuf) { +pub(crate) fn add_extra_dot_dot_to_expression_mdx(migrate_path: &Path) { let binding = recurse_directory(migrate_path); - let files = binding.iter().filter(|x| if let Some(i) = x.file_name() { - if Some("expression.mdx") == i.to_str() || Some("expressions.md") == i.to_str() { - true + let files = binding.iter().filter(|x| { + if let Some(i) = x.file_name() { + Some("expression.mdx") == i.to_str() || Some("expressions.md") == i.to_str() } else { false } - } else { - false }); for file in files { - let content = match read_to_string(file) { - Ok(i) => i, - _ => continue, + let Ok(content) = read_to_string(file) else { + continue; }; let _ = write(file, content.replace("../expressions", "../../expressions")); } } + +#[cfg(test)] +mod tests { + #[test] + fn noop() {} +} diff --git a/website/scripts/docsmg/src/links.rs b/website/scripts/docsmg/src/links.rs index 26d61d9468..ee86c588aa 100644 --- a/website/scripts/docsmg/src/links.rs +++ b/website/scripts/docsmg/src/links.rs @@ -1,20 +1,22 @@ -use std::{fs::read_to_string, path::PathBuf}; +use std::{ + fs::read_to_string, + path::{Path, PathBuf}, +}; use regex::{Captures, Regex}; use crate::recurse_directory; -pub fn shorten_all_external_links(migrate_path: PathBuf) { - let files = recurse_directory(migrate_path.clone()); +#[expect(unused)] +pub(crate) fn shorten_all_external_links(migrate_path: &Path) { + let files = recurse_directory(migrate_path); + let re = Regex::new(r"\[(?.*)\]\((?.*)\)").unwrap(); for file in files { let file = migrate_path.join(file); let absolute_file = file.clone().canonicalize().unwrap(); - let contents = if let Ok(x) = read_to_string(file) { - x - } else { + let Ok(contents) = read_to_string(file) else { continue; }; - let re = Regex::new(r"\[(?.*)\]\((?.*)\)").unwrap(); let captures: Vec = re.captures_iter(&contents).collect(); for capture in captures { let link = &capture["link"]; @@ -31,4 +33,4 @@ pub fn shorten_all_external_links(migrate_path: PathBuf) { } } -fn shorten_link_relative_to(link_to_shorten: PathBuf, relative_to: PathBuf) {} +fn shorten_link_relative_to(_link_to_shorten: PathBuf, _relative_to: PathBuf) {} diff --git a/website/scripts/docsmg/src/main.rs b/website/scripts/docsmg/src/main.rs index b6ce1fedf1..c2a62a66f2 100644 --- a/website/scripts/docsmg/src/main.rs +++ b/website/scripts/docsmg/src/main.rs @@ -1,13 +1,19 @@ -use std::{fs, path::PathBuf}; +#![expect(clippy::allow_attributes_without_reason)] +#![expect(clippy::unwrap_used)] + +use std::{ + fs, + path::{Path, PathBuf}, +}; use clap::{Parser, Subcommand}; mod generate; +mod hackyfixes; mod links; mod migrate; mod migratefile; mod r#move; -mod hackyfixes; #[derive(Parser)] struct Cli { @@ -45,41 +51,38 @@ enum Commands { } fn main() { - let _ = dotenv::from_filename("./docsmg.env"); + let _ = dotenvy::from_filename("./docsmg.env"); let cli = Cli::parse(); match cli.command { - Commands::Move { old_path, new_path } => r#move::r#move(old_path, new_path), + Commands::Move { old_path, new_path } => r#move::r#move(&old_path, &new_path), Commands::Migrate { migratefile, quiet } => { - migrate::migrate(quiet, migratefile, cli.migrate_path) + migrate::migrate(quiet, &migratefile, &cli.migrate_path); } Commands::Unmigrate { migratefile, quiet } => { - migrate::unmigrate(quiet, migratefile, cli.migrate_path) + migrate::unmigrate(quiet, &migratefile, &cli.migrate_path); + } + Commands::Generate { migratefile } => { + generate::generate(migratefile.as_deref(), &cli.migrate_path); } - Commands::Generate { migratefile } => generate::generate(migratefile, cli.migrate_path), } } -fn recurse_directory(path: PathBuf) -> Vec { +fn recurse_directory(path: &Path) -> Vec { let paths = fs::read_dir(path).expect("path to exist"); let mut final_paths = vec![]; - for path in paths { - match path { - Ok(path) => { - if !path.path().is_file() && !path.path().is_dir() { - continue; - } // dont go any further if not a file or directory - let is_dir = path.path().is_dir(); - let path = path.path(); + for path in paths.flatten() { + if !path.path().is_file() && !path.path().is_dir() { + continue; + } // dont go any further if not a file or directory + let is_dir = path.path().is_dir(); + let path = path.path(); - if is_dir { - let mut paths = recurse_directory(path); - final_paths.append(&mut paths); - } else { - final_paths.push(path); - } - } - _ => {} + if is_dir { + let mut paths = recurse_directory(&path); + final_paths.append(&mut paths); + } else { + final_paths.push(path); } } final_paths diff --git a/website/scripts/docsmg/src/migrate.rs b/website/scripts/docsmg/src/migrate.rs index 459c0d66e5..5355aa38c8 100644 --- a/website/scripts/docsmg/src/migrate.rs +++ b/website/scripts/docsmg/src/migrate.rs @@ -1,36 +1,41 @@ use std::{ - collections::{HashMap, HashSet, VecDeque}, env::consts::OS, ffi::OsStr, fs::{create_dir_all, read_to_string, remove_file, write, File}, path::{Component, PathBuf}, process::Command + collections::{HashMap, VecDeque}, + ffi::OsStr, + fmt::Write as _, + fs::{self, File}, + iter::repeat_with, + path::{Component, Path, PathBuf}, + process::Command, }; -use colored::Colorize; +use colored::Colorize as _; +use eyre::Result; use regex::{Captures, Regex}; -use crate::{hackyfixes::add_extra_dot_dot_to_expression_mdx, migratefile::read_migrate_file, recurse_directory, Cli}; +use crate::{ + hackyfixes::add_extra_dot_dot_to_expression_mdx, migratefile::read_migrate_file, + recurse_directory, +}; -pub fn migrate(quiet: bool, migratefile: PathBuf, migrate_path: PathBuf) { +pub(crate) fn migrate(quiet: bool, migratefile: &Path, migrate_path: &Path) { if !quiet { - println!("Reading migrate file"); + eprintln!("Reading migrate file"); } - let files = read_migrate_file(migratefile); - - let files = match files { - Ok(i) => { - if !quiet { - println!("{}", "Success".green()); - } - i - } - Err(_) => { - println!("{}: Could not read migrate file", "Error".red()); - return; + let files = if let Ok(files) = read_migrate_file(migratefile) { + if !quiet { + eprintln!("{}", "Success".green()); } + files + } else { + eprintln!("{}: Could not read migrate file", "Error".red()); + return; }; - replace_links(migrate_path.clone(), files.clone()); - let successful_moves = move_files(quiet, migrate_path.clone(), files); - add_redirects(successful_moves.clone(), migrate_path.clone()); - //shorten_all_external_links(migrate_path); - add_extra_dot_dot_to_expression_mdx(migrate_path.clone()); + replace_links(migrate_path, &files); + let successful_moves = move_files(quiet, migrate_path, &files); + add_redirects(&successful_moves, migrate_path); + // shorten_all_external_links(migrate_path); + add_extra_dot_dot_to_expression_mdx(migrate_path); let _ = Command::new("sh") .arg("-c") .arg("find . -empty -type d -delete") @@ -38,76 +43,71 @@ pub fn migrate(quiet: bool, migratefile: PathBuf, migrate_path: PathBuf) { .output(); } -pub fn unmigrate(quiet: bool, migratefile: PathBuf, migrate_path: PathBuf) { +pub(crate) fn unmigrate(quiet: bool, migratefile: &Path, migrate_path: &Path) { if !quiet { - println!("Reading migrate file"); + eprintln!("Reading migrate file"); } - let files = read_migrate_file(migratefile); - let files = match files { - Ok(i) => { - if !quiet { - println!("{}", "Success".green()); - } - i - } - Err(_) => { - println!("{}: Could not read migrate file", "Error".red()); - return; + let files = if let Ok(files) = read_migrate_file(migratefile) { + if !quiet { + eprintln!("{}", "Success".green()); } + files + } else { + eprintln!("{}: Could not read migrate file", "Error".red()); + return; }; let files: Vec<(PathBuf, PathBuf)> = files.iter().map(|x| (x.1.clone(), x.0.clone())).collect(); //switch files to reverse a migration - replace_links(migrate_path.clone(), files.clone()); - let successful_moves = move_files(quiet, migrate_path.clone(), files); + replace_links(migrate_path, &files); + let successful_moves = move_files(quiet, migrate_path, &files); let successful_moves: Vec<(PathBuf, PathBuf)> = successful_moves .iter() .map(|x| (x.1.clone(), x.0.clone())) .collect(); //switch files to reverse a migration - remove_redirects(successful_moves, migrate_path.clone()); - //shorten_all_external_links(migrate_path); + remove_redirects(&successful_moves, migrate_path); + // shorten_all_external_links(migrate_path); } fn move_files( quiet: bool, - migrate_path: PathBuf, - files: Vec<(PathBuf, PathBuf)>, + migrate_path: &Path, + files: &[(PathBuf, PathBuf)], ) -> Vec<(PathBuf, PathBuf)> { let mut successful_moves = vec![]; for file in files { if !quiet { - print!("{} -> {} : ", file.0.display(), file.1.display()); + eprint!("{} -> {} : ", file.0.display(), file.1.display()); } - let rename: anyhow::Result<()> = (|| { + let rename: Result<()> = (|| { let old_file = migrate_path.join(&file.0); let new_file = migrate_path.join(&file.1); - std::fs::create_dir_all(&new_file.parent().expect("files to have a parent"))?; - std::fs::rename(&old_file, &new_file)?; + fs::create_dir_all(new_file.parent().expect("files to have a parent"))?; + fs::rename(&old_file, &new_file)?; Ok(()) })(); match rename { - Ok(_) => { + Ok(()) => { if !quiet { - println!("{}", "Success".green()); + eprintln!("{}", "Success".green()); } - successful_moves.push(file); + successful_moves.push(file.to_owned()); } - Err(_) => println!( + Err(_) => eprintln!( "{}: Could not move file {}", "Error".red(), file.0.display() ), - }; + } } successful_moves } -fn replace_links(migrate_path: PathBuf, moves: Vec<(PathBuf, PathBuf)>) { - let files = recurse_directory(migrate_path.clone()); - let mut moved = HashSet::new(); +fn replace_links(migrate_path: &Path, moves: &[(PathBuf, PathBuf)]) { + let files = recurse_directory(migrate_path); let mut absolute_moves = vec![]; - for r#move in &moves { + for r#move in moves { let r#move = ( migrate_path.join(r#move.0.clone()), migrate_path.join(r#move.1.clone()), @@ -115,59 +115,55 @@ fn replace_links(migrate_path: PathBuf, moves: Vec<(PathBuf, PathBuf)>) { let absolute_move_0 = r#move .0 .canonicalize() - .expect(&format!("{}", r#move.0.display())); + .unwrap_or_else(|_| panic!("{}", r#move.0.display())); - let _ = create_dir_all(r#move.1.parent().unwrap()); + let _ = fs::create_dir_all(r#move.1.parent().unwrap()); let tmp_file = File::create_new(&r#move.1); - let absolute_move_1 = r#move.1.clone().canonicalize().expect(&format!( - "{} {:?}", - r#move.1.display(), - tmp_file - )); + let absolute_move_1 = r#move + .1 + .clone() + .canonicalize() + .unwrap_or_else(|_| panic!("{} {:?}", r#move.1.display(), tmp_file)); // delete file if it didn't already exist - if let Ok(_) = tmp_file { - let _ = remove_file(&r#move.1); - }; + if tmp_file.is_ok() { + let _ = fs::remove_file(&r#move.1); + } absolute_moves.push((absolute_move_0, absolute_move_1)); } let absolute_moves = absolute_moves .iter() - .map(|x| x.clone()) + .cloned() .collect::>(); + let re = Regex::new(r"\[(?[\w \-\*'`]*)\]\((?[\w\-\\/\\.#]*)\)").unwrap(); for file in files { let absolute_file = file.canonicalize().unwrap(); - println!("{}", absolute_file.display()); - let mut contents = match read_to_string(file.clone()) { - Ok(i) => i, - Err(_) => continue, + eprintln!("{}", absolute_file.display()); + let Ok(mut contents) = fs::read_to_string(file.clone()) else { + continue; }; // replace old absolute file with the new absolute file let old_absolute_file = absolute_file.clone(); let absolute_file = match absolute_moves.get(&absolute_file) { Some(file) => { - println!(" new file: {}", file.display()); - moved.insert(absolute_file); + eprintln!(" new file: {}", file.display()); file.clone() } None => absolute_file.clone(), }; // get all links in file and remove web links and link to self - let re = Regex::new(r"\[(?[\w \-\*'`]*)\]\((?[\w\-\\/\\.#]*)\)").unwrap(); let tmp_contents = contents.clone(); let captures: Vec = re .captures_iter(&tmp_contents) .filter(|x| { let link = &x["link"]; - !["http", "#", "/"] - .iter() - .fold(false, |acc, x| acc || link.starts_with(x)) + !["http", "#", "/"].iter().any(|x| link.starts_with(x)) }) .collect(); - println!(" captures: {}\n", captures.len()); + eprintln!(" captures: {}\n", captures.len()); for capture in captures { let mut capture_log = String::new(); @@ -176,37 +172,31 @@ fn replace_links(migrate_path: PathBuf, moves: Vec<(PathBuf, PathBuf)>) { let link_postfix_index = link.find('#'); - let link_postfix = match link_postfix_index { - Some(i) => { - let link_postfix = link[i..].to_owned(); - link_path = link[..i].to_owned(); - Some(link_postfix) - } - None => { - link_path = link.clone(); - None - }, + let link_postfix = if let Some(i) = link_postfix_index { + let link_postfix = link[i..].to_owned(); + link_path = link[..i].to_owned(); + Some(link_postfix) + } else { + link_path = link.clone(); + None }; let absolute_link = old_absolute_file.parent().unwrap().join(link_path.clone()); - //let _ = create_dir_all(absolute_link.parent().unwrap()); - //let tmp_file = File::create_new(&absolute_link); + // let _ = fs::create_dir_all(absolute_link.parent().unwrap()); + // let tmp_file = File::create_new(&absolute_link); - let absolute_link = match absolute_link + let Ok(absolute_link) = absolute_link .canonicalize() - .or(absolute_link.with_extension("md").canonicalize()) - .or(absolute_link.with_extension("mdx").canonicalize()) - { - Ok(link) => link, - _ => { - println!( - " {}: {} -> {}", - "failed".red(), - absolute_file.to_string_lossy().to_string().red(), - absolute_link.to_string_lossy().to_string().red() - ); - continue; - } + .or_else(|_| absolute_link.with_extension("md").canonicalize()) + .or_else(|_| absolute_link.with_extension("mdx").canonicalize()) + else { + eprintln!( + " {}: {} -> {}", + "failed".red(), + absolute_file.to_string_lossy().to_string().red(), + absolute_link.to_string_lossy().to_string().red() + ); + continue; }; let absolute_link = if absolute_link.is_file() { absolute_link @@ -215,7 +205,7 @@ fn replace_links(migrate_path: PathBuf, moves: Vec<(PathBuf, PathBuf)>) { } else if absolute_link.join("index.mdx").is_file() { absolute_link.join("index.mdx") } else { - println!( + eprintln!( " {}: {} -> {}", "failed".red(), absolute_file.to_string_lossy().to_string().red(), @@ -224,10 +214,10 @@ fn replace_links(migrate_path: PathBuf, moves: Vec<(PathBuf, PathBuf)>) { continue; }; // delete file if it didn't already exist - //if let Ok(_) = tmp_file { - // let _ = remove_file(&absolute_link); + // if tmp_file.is_ok() { + // let _ = fs::remove_file(&absolute_link); //}; - capture_log.push_str(&format!(" oldalink: {}\n", absolute_link.display())); + let _ = writeln!(capture_log, " oldalink: {}", absolute_link.display()); // replace old absolute link with the new absolute link let absolute_link = match absolute_moves.get(&absolute_link) { @@ -235,7 +225,7 @@ fn replace_links(migrate_path: PathBuf, moves: Vec<(PathBuf, PathBuf)>) { None => absolute_link.clone(), }; - capture_log.push_str(&format!(" newalink: {}\n", absolute_link.display())); + let _ = writeln!(capture_log, " newalink: {}", absolute_link.display()); // create tmp absolutes and make them into components let tmp_absolute_file = absolute_file.clone(); @@ -245,24 +235,26 @@ fn replace_links(migrate_path: PathBuf, moves: Vec<(PathBuf, PathBuf)>) { // remove the shared path components loop { if tmp_absolute_file.front() != tmp_absolute_link.front() - || tmp_absolute_file.front() == None + || tmp_absolute_file.front().is_none() { break; } tmp_absolute_file.pop_front(); tmp_absolute_link.pop_front(); } - capture_log.push_str(&format!( - " shrtfile: {}\n", + let _ = writeln!( + capture_log, + " shrtfile: {}", tmp_absolute_file.iter().collect::().display() - )); - capture_log.push_str(&format!( - " shrtlink: {}\n", + ); + let _ = writeln!( + capture_log, + " shrtlink: {}", tmp_absolute_link.iter().collect::().display() - )); + ); - if tmp_absolute_file.len() <= 0 { - println!( + if tmp_absolute_file.is_empty() { + eprintln!( " {}: {} -> {}", "failed".red(), absolute_file.to_string_lossy().to_string().red(), @@ -270,8 +262,8 @@ fn replace_links(migrate_path: PathBuf, moves: Vec<(PathBuf, PathBuf)>) { ); continue; } - let escapes = (0..tmp_absolute_file.len() - 1) - .map(|_| Component::Normal("..".as_ref())) + let escapes = repeat_with(|| Component::Normal("..".as_ref())) + .take(tmp_absolute_file.len() - 1) .collect::(); let new_link = escapes.join(tmp_absolute_link.iter().collect::()); @@ -284,69 +276,66 @@ fn replace_links(migrate_path: PathBuf, moves: Vec<(PathBuf, PathBuf)>) { .collect::() .to_str() { - Some(".") => new_link, - Some("..") => new_link, + Some("." | "..") => new_link, _ => PathBuf::from(".").join(new_link), }; let mut new_link = new_link.to_string_lossy().to_string(); - match link_postfix { - Some(i) => new_link.push_str(&i), - None => {} + if let Some(i) = link_postfix { + new_link.push_str(&i); } - capture_log.push_str(&format!(" old link: {}\n", link)); - capture_log.push_str(&format!(" new link: {}\n", new_link)); - print!("{}", capture_log); - //println!("{} {} {}", absolute_file.display(), absolute_link.display(), new_link.display()); - let tmp_contents = contents.replace(&format!("({})", link), &format!("({})", new_link)); + let _ = writeln!(capture_log, " old link: {link}"); + let _ = writeln!(capture_log, " new link: {new_link}"); + eprint!("{capture_log}"); + // eprintln!("{} {} {}", absolute_file.display(), absolute_link.display(), + // new_link.display()); + let tmp_contents = contents.replace(&format!("({link})"), &format!("({new_link})")); if tmp_contents == contents { - println!("{}", " nothing replaced".yellow()); + eprintln!("{}", " nothing replaced".yellow()); } else { contents = tmp_contents; - }; - println!(""); + } + eprintln!(); } - write(file, contents).unwrap(); + fs::write(file, contents).unwrap(); } } -fn fix_internal_links_in_file(migrate_path: PathBuf, move_from: PathBuf, move_to: PathBuf) { +#[expect(unused)] +fn fix_internal_links_in_file(migrate_path: &Path, move_from: &Path, move_to: &Path) { let move_from = migrate_path.join(move_from); let move_to = migrate_path.join(move_to); - let contents = read_to_string(&move_from); - let mut contents = match contents { - Ok(ok) => ok, - Err(_) => return, + let Ok(mut contents) = fs::read_to_string(&move_from) else { + return; }; let re = Regex::new(r"\[(?.*)\]\((?.*)\)").unwrap(); let captures: Vec = re.captures_iter(&contents).collect(); let mut changes = vec![]; for capture in captures { - //let name = &capture["name"]; + // let name = &capture["name"]; let link = &capture["link"]; if link.starts_with('#') || link.starts_with("http") { continue; } let link = PathBuf::from(link); - //println!("{} {}", move_from.display(), link.display()); + // println!("{} {}", move_from.display(), link.display()); let absolute_link = move_from .parent() .unwrap() .canonicalize() .unwrap() .join(&link); - if move_to.components().collect::>().len() > 1 { - let _ = create_dir_all(move_to.parent().unwrap()); + if move_to.components().count() > 1 { + let _ = fs::create_dir_all(move_to.parent().unwrap()); } let tmp_file = File::create_new(move_to.clone()); - //println!("{} {} {} {}", name, link.display(), absolute_link.display(), make_path_relative(absolute_link.clone(), move_to.canonicalize().unwrap().clone()).display()); - let new_link = make_path_relative( - absolute_link.clone(), - move_to.canonicalize().unwrap().clone(), - ); - if let Ok(_) = tmp_file { - remove_file(move_to.clone()).unwrap() - }; + // println!("{} {} {} {}", name, link.display(), absolute_link.display(), + // make_path_relative(absolute_link.clone(), + // move_to.canonicalize().unwrap().clone()).display()); + let new_link = make_path_relative(&absolute_link, &move_to.canonicalize().unwrap()); + if tmp_file.is_ok() { + fs::remove_file(move_to.clone()).unwrap(); + } changes.push((link.clone(), new_link.clone())); } for i in changes { @@ -355,73 +344,64 @@ fn fix_internal_links_in_file(migrate_path: PathBuf, move_from: PathBuf, move_to &format!("({})", i.1.display()), ); } - write(move_from, contents).unwrap(); + fs::write(move_from, contents).unwrap(); } -fn make_path_relative(path: PathBuf, relative_to: PathBuf) -> PathBuf { +fn make_path_relative(path: &Path, relative_to: &Path) -> PathBuf { let mut subdirs = 0; let path_components = path.components().collect::>(); let relative_to_components = relative_to.components().collect::>(); loop { - if path_components.len() <= subdirs { - break; - } else if path_components[subdirs] != relative_to_components[subdirs] { + if path_components.len() <= subdirs + || path_components[subdirs] != relative_to_components[subdirs] + { break; } subdirs += 1; } let new_path = &path_components[subdirs..].iter().collect::(); - let backouts = (0..relative_to_components.len() - subdirs - 1) - .map(|_| PathBuf::from("..")) + let backouts = repeat_with(|| PathBuf::from("..")) + .take(relative_to_components.len() - subdirs - 1) .reduce(|acc, e| acc.join(e)) - .unwrap_or(PathBuf::from("")); - //println!("{}, {}", relative_to_components.len() - subdirs - 1, backouts.display()); + .unwrap_or_else(|| PathBuf::from("")); + // println!("{}, {}", relative_to_components.len() - subdirs - 1, backouts.display()); let new_path = backouts.join(new_path); - let new_path = if new_path - .to_string_lossy() - .to_string() - .chars() - .next() - .unwrap() - != '.' - { - PathBuf::from(".").join(new_path) - } else { + let new_path = if new_path.to_string_lossy().to_string().starts_with('.') { new_path + } else { + PathBuf::from(".").join(new_path) }; - let new_path = if new_path.file_name() == Some(OsStr::new("index.md")) + if new_path.file_name() == Some(OsStr::new("index.md")) || new_path.file_name() == Some(OsStr::new("index.mdx")) { new_path.parent().unwrap().to_path_buf() } else { new_path - }; - - new_path + } } -fn add_redirects(successful_moves: Vec<(PathBuf, PathBuf)>, migrate_path: PathBuf) { +fn add_redirects(successful_moves: &[(PathBuf, PathBuf)], migrate_path: &Path) { let redirects = generate_redirects(successful_moves); let netlify_path = migrate_path.parent().unwrap().join("netlify.toml"); - let mut netlify_contents = read_to_string(netlify_path.clone()).unwrap(); + let mut netlify_contents = fs::read_to_string(netlify_path.clone()).unwrap(); for redirect in redirects { netlify_contents.push_str(&redirect); } - std::fs::write(netlify_path, netlify_contents).unwrap(); + fs::write(netlify_path, netlify_contents).unwrap(); } -fn remove_redirects(successful_moves: Vec<(PathBuf, PathBuf)>, migrate_path: PathBuf) { +fn remove_redirects(successful_moves: &[(PathBuf, PathBuf)], migrate_path: &Path) { let redirects = generate_redirects(successful_moves); let netlify_path = migrate_path.parent().unwrap().join("netlify.toml"); - let mut netlify_contents = read_to_string(netlify_path.clone()).unwrap(); + let mut netlify_contents = fs::read_to_string(netlify_path.clone()).unwrap(); for redirect in redirects { netlify_contents = netlify_contents.replace(&redirect, ""); } - std::fs::write(netlify_path, netlify_contents).unwrap(); + fs::write(netlify_path, netlify_contents).unwrap(); } -fn generate_redirects(successful_moves: Vec<(PathBuf, PathBuf)>) -> Vec { +fn generate_redirects(successful_moves: &[(PathBuf, PathBuf)]) -> Vec { successful_moves .iter() .map(|x| { diff --git a/website/scripts/docsmg/src/migratefile.rs b/website/scripts/docsmg/src/migratefile.rs index e7b24d6502..de653934fb 100644 --- a/website/scripts/docsmg/src/migratefile.rs +++ b/website/scripts/docsmg/src/migratefile.rs @@ -1,16 +1,21 @@ -use std::{fs::read_to_string, path::PathBuf}; +use std::{ + fs::read_to_string, + path::{Path, PathBuf}, +}; -pub fn read_migrate_file(file: PathBuf) -> anyhow::Result> { +use eyre::Result; + +pub(crate) fn read_migrate_file(file: &Path) -> Result> { let contents = read_to_string(file)?; let lines: Vec = contents .split('\n') .map(|x| x.to_owned()) - .filter(|x| x != "") + .filter(|x| !x.is_empty()) .collect(); let migrations = lines .iter() .filter_map(|x| x.split_once(" -> ")) - .filter(|x| !(x.0 == x.1)) + .filter(|x| x.0 != x.1) .map(|x| { ( x.0.parse().expect("a valid path"), @@ -21,16 +26,16 @@ pub fn read_migrate_file(file: PathBuf) -> anyhow::Result anyhow::Result> { +pub(crate) fn read_migrate_file_left_side(file: &Path) -> Result> { let contents = read_to_string(file)?; let lines: Vec = contents .split('\n') .map(|x| x.to_owned()) - .filter(|x| x != "") + .filter(|x| !x.is_empty()) .collect(); let migrations = lines .iter() - .map(|x| x.split(" -> ").collect::>()[0].into()) + .map(|x| x.split(" -> ").next().unwrap().into()) .collect::>(); Ok(migrations) } diff --git a/website/scripts/docsmg/src/move.rs b/website/scripts/docsmg/src/move.rs index 64f4e87185..3e493dde7c 100644 --- a/website/scripts/docsmg/src/move.rs +++ b/website/scripts/docsmg/src/move.rs @@ -1,20 +1,20 @@ -use std::path::PathBuf; +use std::path::Path; use crate::recurse_directory; -pub fn r#move(old_path: PathBuf, new_path: PathBuf) { +pub(crate) fn r#move(old_path: &Path, new_path: &Path) { let is_dir = old_path.is_dir(); if is_dir { - let paths = recurse_directory(old_path.clone()); + let paths = recurse_directory(old_path); for path in paths { let raw_path = path - .strip_prefix(old_path.clone()) + .strip_prefix(old_path) .expect("path to be within old path"); let new_path = new_path.join(raw_path); - println!("{} -> {}", path.display(), new_path.display()); + eprintln!("{} -> {}", path.display(), new_path.display()); } } else { - println!( + eprintln!( "{} -> {}", old_path.to_string_lossy(), new_path.to_string_lossy()