Connect applications to schemes, filetypes, and more on macOS (more to come)
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

brought back the justfile

+439
+439
justfile
··· 1 + #!/usr/bin/env just 2 + 3 + # --- Settings --- # 4 + set shell := ["nu", "-c"] 5 + set positional-arguments := true 6 + set allow-duplicate-variables := true 7 + set windows-shell := ["nu", "-c"] 8 + set dotenv-load := true 9 + 10 + # --- Variables --- # 11 + project_root := justfile_directory() 12 + output_directory := project_root + "/dist" 13 + build_directory := `cargo metadata --format-version 1 | jq -r .target_directory` 14 + 15 + system := `rustc --version --verbose | grep '^host:' | awk '{print $2}'` 16 + main_package := "infat" 17 + 18 + # ▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰ # 19 + # Recipes # 20 + # ▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰▰ # 21 + 22 + [doc('List all available recipes')] 23 + default: 24 + @just --list 25 + 26 + # --- Build & Check --- # 27 + [doc('Check workspace for compilation errors')] 28 + [group('build')] 29 + check: 30 + @echo "🔎 Checking workspace..." 31 + cargo check --workspace 32 + 33 + [doc('Build workspace in debug mode')] 34 + [group('build')] 35 + build target="aarch64-apple-darwin" package=(main_package): 36 + @echo "🔨 Building workspace (debug)..." 37 + cargo build --workspace --bin '{{main_package}}' --target '{{target}}' 38 + 39 + [doc('Build workspace in release mode')] 40 + [group('build')] 41 + build-release target=(system) package=(main_package): 42 + @echo "🚀 Building workspace (release) for {{target}}…" 43 + cargo build --workspace --release --bin '{{main_package}}' --target '{{target}}' 44 + 45 + # --- Packaging --- # 46 + [doc('Package release binary with completions for distribution')] 47 + [group('packaging')] 48 + package target=(system): 49 + #!/usr/bin/env nu 50 + def build_error [msg: string, error?: record] { 51 + if ($error != null) { 52 + let annotated_error = ($error | upsert msg $'($msg): ($error.msg)') 53 + $annotated_error.rendered | print --stderr 54 + } else { 55 + (error make --unspanned { msg: $msg }) | print --stderr 56 + } 57 + exit 1 58 + } 59 + 60 + print "📦 Packaging release binary…" 61 + 62 + 63 + let target = '{{target}}' 64 + let prime = '{{main_package}}' 65 + let out = "{{output_directory}}" 66 + let artifact_dir = $'{{build_directory}}/($target)/release' 67 + 68 + try { 69 + just build-release $target 70 + 71 + print $'🛬 Destination is ($out)' 72 + 73 + # Windows the only one that has an executable extension 74 + let ext = if ($target | str contains 'windows-msvc') { '.exe' } else { '' } 75 + 76 + # Example: package-triplet 77 + let qualified_name = $"($prime)-($target)" 78 + 79 + let bin_path = $'($artifact_dir)/($prime)($ext)' # Where rust puts the binary artifact 80 + let out_path = $'($out)/($qualified_name)($ext)' 81 + 82 + # Create output directory structure 83 + try { 84 + mkdir $out 85 + } catch {|e| 86 + build_error $"Failed to create directory: ($out)" $e 87 + } 88 + 89 + # Copy completion scripts 90 + let completions = [$'($prime).bash', $'($prime).elv', $'($prime).fish', $'_($prime).ps1', $'_($prime)'] 91 + 92 + for completion in $completions { 93 + let src = $'($artifact_dir)/($completion)' 94 + let dst = $'($out)/($completion)' 95 + 96 + if ($src | path exists) { 97 + try { 98 + cp --force $src $dst # Using force here because default nu copy only works with existing files otherwise 99 + print $"('Successfully copied completion to destination:' | ansi gradient --fgstart '0x00ff00' --fgend '0xff0080' --bgstart '0x1a1a1a' --bgend '0x0d0d0d') (basename $src)" 100 + } catch {|e| 101 + build_error $"Failed to copy completion script ($src)" $e 102 + } 103 + } else { 104 + print --stderr $"Warning: completion script missing: ($src)" 105 + } 106 + } 107 + 108 + # Copy main binary 109 + try { 110 + cp --force $bin_path $out_path 111 + print $"('Successfully copied binary to destination:' | ansi gradient --fgstart '0x00ff00' --fgend '0xff0080' --bgstart '0x1a1a1a' --bgend '0x0d0d0d') (basename $bin_path)" 112 + } catch { |e| 113 + build_error $"Failed to copy binary ($bin_path)" $e 114 + } 115 + 116 + } catch { |e| 117 + build_error "Packaging failed" $e 118 + } 119 + 120 + [doc('Generate checksums for distribution files')] 121 + [group('packaging')] 122 + checksum directory=(output_directory): 123 + #!/usr/bin/env nu 124 + def build_error [msg: string, error?: record] { 125 + if ($error != null) { 126 + let annotated_error = ($error | upsert msg $'($msg): ($error.msg)') 127 + $annotated_error.rendered | print --stderr 128 + exit 1 129 + } else { 130 + (error make --unspanned { msg: $msg }) | print --stderr 131 + exit 1 132 + } 133 + } 134 + 135 + let dir = '{{directory}}' 136 + print $"🔒 Generating checksums in '($dir)'…" 137 + 138 + # Validate directory exists 139 + if not ($dir | path exists) { 140 + build_error $"'($dir)' is not a directory." 141 + } 142 + 143 + try { 144 + cd $dir 145 + 146 + # Remove existing checksum files 147 + try { 148 + glob '*.sum' | each { |file| rm $file } 149 + } catch { 150 + # Ignore errors if no .sum files exist 151 + } 152 + 153 + # Get all files except checksum files 154 + let files = ls | where type == file | where name !~ '\.sum$' | get name 155 + 156 + if (($files | length) == 0) { 157 + print --stderr "Warning: No files found to checksum" 158 + return 159 + } 160 + 161 + # Generate SHA256 checksums 162 + try { 163 + let sha256_results = $files | each { |file| 164 + let hash = (open --raw $file | hash sha256) 165 + $"($hash) ./($file | path basename)" 166 + } 167 + $sha256_results | str join (char newline) | save SHA256.sum 168 + } catch {|e| 169 + build_error $"Failed to generate SHA256 checksums" $e 170 + } 171 + 172 + # Generate MD5 checksums 173 + try { 174 + let md5_results = $files | each { |file| 175 + let hash = (open --raw $file | hash md5) 176 + $"($hash) ./($file | path basename)" 177 + } 178 + $md5_results | str join (char newline) | save MD5.sum 179 + } catch {|e| 180 + build_error $"Failed to generate MD5 checksums" $e 181 + } 182 + 183 + # Generate BLAKE3 checksums (using b3sum command) 184 + try { 185 + let b3_results = $files | each { |file| 186 + let result = (run-external 'b3sum' $file | complete) 187 + if $result.exit_code != 0 { 188 + build_error $"b3sum failed for ($file): ($result.stderr)" 189 + } 190 + let hash = ($result.stdout | str trim | split row ' ' | get 0) 191 + $"($hash) ./($file | path basename)" 192 + } 193 + $b3_results | str join (char newline) | save BLAKE3.sum 194 + } catch {|e| 195 + build_error $"Failed to generate BLAKE3 checksums" $e 196 + } 197 + 198 + print $"✅ Checksums created in '($dir)'" 199 + 200 + } catch {|e| 201 + build_error $"Checksum generation failed" $e 202 + } 203 + 204 + [doc('Compress all release packages into tar.gz archives')] 205 + [group('packaging')] 206 + compress directory=(output_directory): 207 + #!/usr/bin/env nu 208 + def build_error [msg: string, error?: record] { 209 + if ($error != null) { 210 + let annotated_error = ($error | upsert msg $'($msg): ($error.msg)') 211 + $annotated_error.rendered | print --stderr 212 + exit 1 213 + } else { 214 + (error make --unspanned { msg: $msg }) | print --stderr 215 + exit 1 216 + } 217 + } 218 + 219 + print "🗜️ Compressing release packages..." 220 + 221 + let dir = '{{directory}}' 222 + if not ($dir | path exists) { 223 + build_error $"Directory '($dir)' does not exist" 224 + } 225 + 226 + try { 227 + # Find all package directories 228 + mut package_dirs = ls $dir | where type == dir | get name 229 + 230 + if (($package_dirs | length) == 0) { 231 + # Just one package found to compress 232 + $package_dirs = ($package_dirs | append $dir) 233 + } 234 + 235 + for pkg_dir in $package_dirs { 236 + let pkg_name = ($pkg_dir | path basename) 237 + print $"🎁 Compressing package: ($pkg_name)" 238 + 239 + try { 240 + let parent_dir = ($pkg_dir | path dirname) 241 + let archive_name = $'($pkg_dir).tar.gz' 242 + 243 + # Use tar command to create compressed archive 244 + let result = (run-external 'tar' '-czf' $archive_name '-C' $parent_dir $pkg_name | complete) 245 + 246 + if $result.exit_code != 0 { 247 + build_error $"Failed to create archive for ($pkg_name): ($result.stderr)" 248 + } 249 + 250 + print $"✅ Successfully compressed ($pkg_name)" 251 + 252 + } catch { |e| 253 + build_error $"Compression failed for ($pkg_name)" $e 254 + } 255 + } 256 + 257 + print "🎉 All packages compressed successfully!" 258 + 259 + } catch { |e| 260 + build_error $"Compression process failed" $e 261 + } 262 + 263 + [doc('Complete release pipeline: build, checksum, and compress')] 264 + [group('packaging')] 265 + release: build-release 266 + just checksum 267 + 268 + # --- Execution --- # 269 + [doc('Run application in debug mode')] 270 + [group('execution')] 271 + run package=(main_package) +args="": 272 + @echo "▶️ Running {{package}} (debug)..." 273 + cargo run --bin '{{package}}' -- '$@' 274 + 275 + [doc('Run application in release mode')] 276 + [group('execution')] 277 + run-release package=(main_package) +args="": 278 + @echo "▶️ Running '{{package}}' (release)..." 279 + cargo run --bin '{{package}}' --release -- '$@' 280 + 281 + # --- Testing --- # 282 + [doc('Run all workspace tests')] 283 + [group('testing')] 284 + test: 285 + @echo "🧪 Running workspace tests..." 286 + cargo test --workspace 287 + 288 + [doc('Run workspace tests with additional arguments')] 289 + [group('testing')] 290 + test-with +args: 291 + @echo "🧪 Running workspace tests with args: '$@'" 292 + cargo test --workspace -- '$@' 293 + 294 + # --- Code Quality --- # 295 + [doc('Format all Rust code in the workspace')] 296 + [group('quality')] 297 + fmt: 298 + @echo "💅 Formatting Rust code..." 299 + cargo fmt 300 + 301 + 302 + [doc('Check if Rust code is properly formatted')] 303 + [group('quality')] 304 + fmt-check: 305 + @echo "💅 Checking Rust code formatting..." 306 + cargo fmt 307 + 308 + 309 + [doc('Lint code with Clippy in debug mode')] 310 + [group('quality')] 311 + lint: 312 + @echo "🧹 Linting with Clippy (debug)..." 313 + cargo clippy --workspace -- -D warnings 314 + 315 + [doc('Automatically fix Clippy lints where possible')] 316 + [group('quality')] 317 + lint-fix: 318 + @echo "🩹 Fixing Clippy lints..." 319 + cargo clippy --workspace --fix --allow-dirty --allow-staged 320 + 321 + # --- Documentation --- # 322 + [doc('Generate project documentation')] 323 + [group('common')] 324 + doc: 325 + @echo "📚 Generating documentation..." 326 + cargo doc --workspace --no-deps 327 + 328 + [doc('Generate and open project documentation in browser')] 329 + [group('common')] 330 + doc-open: doc 331 + @echo "📚 Opening documentation in browser..." 332 + cargo doc --workspace --no-deps --open 333 + 334 + # --- Maintenance --- # 335 + [doc('Extract release notes from changelog for specified tag')] 336 + [group('common')] 337 + create-notes raw_tag outfile changelog: 338 + #!/usr/bin/env nu 339 + def build_error [msg: string, error?: record] { 340 + if ($error != null) { 341 + let annotated_error = ($error | upsert msg $'($msg): ($error.msg)') 342 + $annotated_error.rendered | print --stderr 343 + exit 1 344 + } else { 345 + (error make --unspanned { msg: $msg }) | print --stderr 346 + exit 1 347 + } 348 + } 349 + 350 + let tag_v = '{{raw_tag}}' 351 + let tag = ($tag_v | str replace --regex '^v' '') # Remove prefix v 352 + let outfile = '{{outfile}}' 353 + let changelog_file = '{{changelog}}' 354 + 355 + try { 356 + # Verify changelog exists 357 + if not ($changelog_file | path exists) { 358 + build_error $"($changelog_file) not found." 359 + } 360 + 361 + print $"Extracting notes for tag: ($tag_v) \(searching for section [($tag)]\)" 362 + 363 + # Write header to output file 364 + "# What's new\n" | save $outfile 365 + 366 + # Read and process changelog 367 + let content = (open $changelog_file | lines) 368 + let section_header = $"## [($tag)]" 369 + 370 + # Find the start of the target section 371 + let start_idx = ($content | enumerate | where item == $section_header | get index | first) 372 + 373 + if ($start_idx | is-empty) { 374 + build_error $"Could not find section header ($section_header) in ($changelog_file)" 375 + } 376 + 377 + # Find the end of the target section (next ## [ header) 378 + let remaining_lines = ($content | skip ($start_idx + 1)) 379 + let next_section_idx = ($remaining_lines | enumerate | where item =~ '^## \[' | get index | first) 380 + 381 + let section_lines = if ($next_section_idx | is-empty) { 382 + $remaining_lines 383 + } else { 384 + $remaining_lines | take $next_section_idx 385 + } 386 + 387 + # Append section content to output file 388 + $section_lines | str join (char newline) | save --append $outfile 389 + 390 + # Check if output file has meaningful content 391 + let output_size = (open $outfile | str length) 392 + if $output_size > 20 { # More than just the header 393 + print $"Successfully extracted release notes to '($outfile)'." 394 + } else { 395 + print --stderr $"Warning: '($outfile)' appears empty. Is '($section_header)' present in '($changelog_file)'?" 396 + } 397 + 398 + } catch { |e| 399 + build_error $"Failed to extract release notes:" $e 400 + } 401 + 402 + [doc('Update Cargo dependencies')] 403 + [group('maintenance')] 404 + update: 405 + @echo "🔄 Updating dependencies..." 406 + cargo update 407 + 408 + [doc('Clean build artifacts')] 409 + [group('maintenance')] 410 + clean: 411 + @echo "🧹 Cleaning build artifacts..." 412 + cargo clean 413 + 414 + # --- Installation --- # 415 + [doc('Build and install binary to system')] 416 + [group('installation')] 417 + install package=(main_package): build-release 418 + @echo "💾 Installing {{main_package}} binary..." 419 + cargo install --bin '{{package}}' 420 + 421 + [doc('Force install binary')] 422 + [group('installation')] 423 + install-force package=(main_package): build-release 424 + @echo "💾 Force installing {{main_package}} binary..." 425 + cargo install --bin '{{package}}' --force 426 + 427 + # --- Aliases --- # 428 + alias b := build 429 + alias br := build-release 430 + alias c := check 431 + alias t := test 432 + alias f := fmt 433 + alias l := lint 434 + alias lf := lint-fix 435 + alias cl := clean 436 + alias up := update 437 + alias i := install 438 + alias ifo := install-force 439 + alias rr := run-release