Compare commits

...

10 Commits

Author SHA1 Message Date
Greg Shuflin
b81d106c91 Parse module 2024-07-09 09:39:53 -07:00
Casey Rodarmor
458805e283
Allow mod path to be directory containing module source (#2238) 2024-07-08 22:38:25 +00:00
Casey Rodarmor
d6669e0b97
Allow enabling unstable features with set unstable (#2237) 2024-07-08 03:45:03 +00:00
Casey Rodarmor
564814208f
Lexiclean search directory so .. does not check the current directory (#2236)
If the search directory was `..`, for example in the invocation
`just ../foo`, we would wind up checking the justfile in the current
directory since we did `INVOCATION_DIRECTORY/..`.ancestors(), which
would first return `INVOCATION_DIRECTORY`.

Instead, lexiclean the result of joining th invocation directory with
the search directory, so `..` is removed, and `ancestors()` doesn't
return the invocation directory.
2024-07-08 02:12:07 +00:00
Casey Rodarmor
f1020b4e6a
Allow abbreviating functions ending in _directory to _dir (#2235) 2024-07-07 22:47:18 +00:00
Casey Rodarmor
5e9f46e855
Release 1.30.1 (#2232)
- Bump version: 1.30.0 → 1.30.1
- Update changelog
- Update changelog contributor credits
2024-07-07 04:24:32 +00:00
Casey Rodarmor
241e7b46a5
Fix function argument count mismatch error message (#2231) 2024-07-07 04:19:36 +00:00
Casey Rodarmor
0c9b159aa4
Bump version to 1.30.0 (#2229) 2024-07-06 23:15:18 +00:00
Casey Rodarmor
d2f66815da
Release 1.30.0 (#2228)
- Bump version: 1.29.1 → 1.30.0
- Update changelog
- Update changelog contributor credits
- Update dependencies
- Update version references in readme
2024-07-06 23:11:25 +00:00
Casey Rodarmor
50e8874e0e
Tweak readme (#2227) 2024-07-06 23:03:08 +00:00
31 changed files with 611 additions and 224 deletions

View File

@ -1,6 +1,56 @@
Changelog
=========
[1.30.1](https://github.com/casey/just/releases/tag/1.30.1) - 2024-07-06
------------------------------------------------------------------------
### Fixed
- Fix function argument count mismatch error message ([#2231](https://github.com/casey/just/pull/2231) by [casey](https://github.com/casey))
[1.30.0](https://github.com/casey/just/releases/tag/1.30.0) - 2024-07-06
------------------------------------------------------------------------
### Fixed
- Allow comments after `mod` statements ([#2201](https://github.com/casey/just/pull/2201) by [casey](https://github.com/casey))
### Changed
- Allow unstable features with `--summary` ([#2210](https://github.com/casey/just/pull/2210) by [casey](https://github.com/casey))
- Don't analyze comments when `ignore-comments` is set ([#2180](https://github.com/casey/just/pull/2180) by [casey](https://github.com/casey))
- List recipes by group in group justfile order with `just --list --unsorted` ([#2164](https://github.com/casey/just/pull/2164) by [casey](https://github.com/casey))
- List groups in source order with `just --groups --unsorted` ([#2160](https://github.com/casey/just/pull/2160) by [casey](https://github.com/casey))
### Added
- Avoid `install` and add 32-bit arm targets to `install.sh` ([#2214](https://github.com/casey/just/pull/2214) by [CramBL](https://github.com/CramBL))
- Give modules doc comments for `--list` ([#2199](https://github.com/casey/just/pull/2199) by [Spatenheinz](https://github.com/Spatenheinz))
- Add `datetime()` and `datetime_utc()` functions ([#2167](https://github.com/casey/just/pull/2167) by [casey](https://github.com/casey))
- Allow setting more command-line options with environment variables ([#2161](https://github.com/casey/just/pull/2161) by [casey](https://github.com/casey))
### Library
- Don't exit process in `run()` on argument parse error ([#2176](https://github.com/casey/just/pull/2176) by [casey](https://github.com/casey))
- Allow passing command-line arguments into `run()` ([#2173](https://github.com/casey/just/pull/2173) by [casey](https://github.com/casey))
- Ignore env_logger initialization errors ([#2170](https://github.com/casey/just/pull/2170) by [EnigmaCurry](https://github.com/EnigmaCurry))
### Misc
- Tweak readme ([#2227](https://github.com/casey/just/pull/2227) by [casey](https://github.com/casey))
- Add development guide to readme ([#2226](https://github.com/casey/just/pull/2226) by [casey](https://github.com/casey))
- Add shell-expanded string syntax to grammar ([#2223](https://github.com/casey/just/pull/2223) by [casey](https://github.com/casey))
- Add recipe for testing bash completion script ([#2221](https://github.com/casey/just/pull/2221) by [casey](https://github.com/casey))
- Fix use of `justfile_directory()` in readme ([#2219](https://github.com/casey/just/pull/2219) by [casey](https://github.com/casey))
- Use default values for `--list-heading` and `--list-prefix` ([#2213](https://github.com/casey/just/pull/2213) by [casey](https://github.com/casey))
- Use `clap::ValueParser` ([#2211](https://github.com/casey/just/pull/2211) by [neunenak](https://github.com/neunenak))
- Document module doc comments in readme ([#2208](https://github.com/casey/just/pull/2208) by [casey](https://github.com/casey))
- Use `-and` instead of `&&` in PowerShell completion script ([#2204](https://github.com/casey/just/pull/2204) by [casey](https://github.com/casey))
- Fix readme formatting ([#2203](https://github.com/casey/just/pull/2203) by [casey](https://github.com/casey))
- Link to justfiles on GitHub in readme ([#2198](https://github.com/casey/just/pull/2198) by [bukowa](https://github.com/bukowa))
- Link to modules when first introduced in readme ([#2193](https://github.com/casey/just/pull/2193) by [casey](https://github.com/casey))
- Update `softprops/action-gh-release` ([#2183](https://github.com/casey/just/pull/2183) by [app/dependabot](https://github.com/app/dependabot))
- Document remote justfile workaround ([#2175](https://github.com/casey/just/pull/2175) by [casey](https://github.com/casey))
- Document library interface ([#2174](https://github.com/casey/just/pull/2174) by [casey](https://github.com/casey))
- Remove dependency on cradle ([#2169](https://github.com/casey/just/pull/2169) by [nc7s](https://github.com/nc7s))
- Add note to readme about quoting paths on Windows ([#2166](https://github.com/casey/just/pull/2166) by [casey](https://github.com/casey))
- Add missing changelog credits ([#2163](https://github.com/casey/just/pull/2163) by [casey](https://github.com/casey))
- Credit myself in changelog ([#2162](https://github.com/casey/just/pull/2162) by [casey](https://github.com/casey))
[1.29.1](https://github.com/casey/just/releases/tag/1.29.1) - 2024-06-14
------------------------------------------------------------------------

158
Cargo.lock generated
View File

@ -121,9 +121,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.5.0"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
[[package]]
name = "blake3"
@ -174,9 +174,9 @@ checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239"
[[package]]
name = "cc"
version = "1.0.99"
version = "1.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695"
checksum = "74b6a57f98764a267ff415d50a25e6e166f3831a5071af4995296ea97d210490"
[[package]]
name = "cfg-if"
@ -201,7 +201,7 @@ dependencies = [
"js-sys",
"num-traits",
"wasm-bindgen",
"windows-targets 0.52.5",
"windows-targets 0.52.6",
]
[[package]]
@ -221,9 +221,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.5.7"
version = "4.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f"
checksum = "84b3edb18336f4df585bc9aa31dd99c036dfa5dc5e9a2939a722a188f3a8970d"
dependencies = [
"clap_builder",
"clap_derive",
@ -231,9 +231,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.5.7"
version = "4.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7e204572485eb3fbf28f871612191521df159bc3e15a9f5064c66dba3a8c05f"
checksum = "c1c09dd5ada6c6c78075d6fd0da3f90d8080651e2d6cc8eb2f1aaa4034ced708"
dependencies = [
"anstream",
"anstyle",
@ -244,23 +244,23 @@ dependencies = [
[[package]]
name = "clap_complete"
version = "4.5.5"
version = "4.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2020fa13af48afc65a9a87335bda648309ab3d154cd03c7ff95b378c7ed39c4"
checksum = "1d598e88f6874d4b888ed40c71efbcbf4076f1dfbae128a08a8c9e45f710605d"
dependencies = [
"clap 4.5.7",
"clap 4.5.8",
]
[[package]]
name = "clap_derive"
version = "4.5.5"
version = "4.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6"
checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085"
dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
"syn 2.0.66",
"syn 2.0.69",
]
[[package]]
@ -271,11 +271,11 @@ checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70"
[[package]]
name = "clap_mangen"
version = "0.2.21"
version = "0.2.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74b70fc13e60c0e1d490dc50eb73a749be6d81f4ef03783df1d9b7b0c62bc937"
checksum = "f50dde5bc0c853d6248de457e5eb6e5a674a54b93810a34ded88d882ca1fe2de"
dependencies = [
"clap 4.5.7",
"clap 4.5.8",
"roff",
]
@ -407,15 +407,15 @@ checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b"
[[package]]
name = "edit-distance"
version = "2.1.0"
version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbbaaaf38131deb9ca518a274a45bfdb8771f139517b073b16c2d3d32ae5037b"
checksum = "853fc7035888bd1c9320f3a05bfe7f344f49b8766a4bb4209b1ac5f0503d9577"
[[package]]
name = "either"
version = "1.12.0"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
name = "env_filter"
@ -591,13 +591,13 @@ dependencies = [
[[package]]
name = "just"
version = "1.29.1"
version = "1.30.1"
dependencies = [
"ansi_term",
"blake3",
"camino",
"chrono",
"clap 4.5.7",
"clap 4.5.8",
"clap_complete",
"clap_mangen",
"ctrlc",
@ -635,9 +635,9 @@ dependencies = [
[[package]]
name = "lazy_static"
version = "1.4.0"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "lexiclean"
@ -657,7 +657,7 @@ version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
dependencies = [
"bitflags 2.5.0",
"bitflags 2.6.0",
"libc",
]
@ -669,9 +669,9 @@ checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
[[package]]
name = "log"
version = "0.4.21"
version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]]
name = "memchr"
@ -694,7 +694,7 @@ version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4"
dependencies = [
"bitflags 2.5.0",
"bitflags 2.6.0",
"cfg-if",
"cfg_aliases",
"libc",
@ -779,9 +779,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.85"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23"
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
dependencies = [
"unicode-ident",
]
@ -792,7 +792,7 @@ version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b"
dependencies = [
"bitflags 2.5.0",
"bitflags 2.6.0",
"getopts",
"memchr",
"unicase",
@ -933,7 +933,7 @@ version = "0.38.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
dependencies = [
"bitflags 2.5.0",
"bitflags 2.6.0",
"errno",
"libc",
"linux-raw-sys",
@ -960,29 +960,29 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
[[package]]
name = "serde"
version = "1.0.203"
version = "1.0.204"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094"
checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.203"
version = "1.0.204"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba"
checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.66",
"syn 2.0.69",
]
[[package]]
name = "serde_json"
version = "1.0.117"
version = "1.0.120"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5"
dependencies = [
"itoa",
"ryu",
@ -1037,7 +1037,7 @@ dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
"syn 2.0.66",
"syn 2.0.69",
]
[[package]]
@ -1078,9 +1078,9 @@ dependencies = [
[[package]]
name = "strum"
version = "0.26.2"
version = "0.26.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29"
checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
dependencies = [
"strum_macros",
]
@ -1095,7 +1095,7 @@ dependencies = [
"proc-macro2",
"quote",
"rustversion",
"syn 2.0.66",
"syn 2.0.69",
]
[[package]]
@ -1111,9 +1111,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.66"
version = "2.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
checksum = "201fcda3845c23e8212cd466bfebf0bd20694490fc0356ae8e428e0824a915a6"
dependencies = [
"proc-macro2",
"quote",
@ -1183,7 +1183,7 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.66",
"syn 2.0.69",
]
[[package]]
@ -1240,9 +1240,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "uuid"
version = "1.8.0"
version = "1.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0"
checksum = "5de17fd2f7da591098415cff336e12965a28061ddace43b59cb3c430179c9439"
dependencies = [
"getrandom",
]
@ -1286,7 +1286,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.66",
"syn 2.0.69",
"wasm-bindgen-shared",
]
@ -1308,7 +1308,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.66",
"syn 2.0.69",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@ -1359,7 +1359,7 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
dependencies = [
"windows-targets 0.52.5",
"windows-targets 0.52.6",
]
[[package]]
@ -1377,7 +1377,7 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets 0.52.5",
"windows-targets 0.52.6",
]
[[package]]
@ -1397,18 +1397,18 @@ dependencies = [
[[package]]
name = "windows-targets"
version = "0.52.5"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm 0.52.5",
"windows_aarch64_msvc 0.52.5",
"windows_i686_gnu 0.52.5",
"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.5",
"windows_x86_64_gnu 0.52.5",
"windows_x86_64_gnullvm 0.52.5",
"windows_x86_64_msvc 0.52.5",
"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]]
@ -1419,9 +1419,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.5"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
@ -1431,9 +1431,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.5"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
@ -1443,15 +1443,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_gnu"
version = "0.52.5"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.5"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
@ -1461,9 +1461,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_i686_msvc"
version = "0.52.5"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
@ -1473,9 +1473,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.5"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
@ -1485,9 +1485,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.5"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
@ -1497,9 +1497,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.5"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "winsafe"

View File

@ -1,6 +1,6 @@
[package]
name = "just"
version = "1.29.1"
version = "1.30.1"
authors = ["Casey Rodarmor <casey@rodarmor.com>"]
autotests = false
categories = ["command-line-utilities", "development-tools"]

View File

@ -379,11 +379,11 @@ There will never be a `just` 2.0. Any desirable backwards-incompatible changes
will be opt-in on a per-`justfile` basis, so users may migrate at their
leisure.
Features that aren't yet ready for stabilization are gated behind the
`--unstable` flag. Features enabled by `--unstable` may change in backwards
incompatible ways at any time. Unstable features can also be enabled by setting
the environment variable `JUST_UNSTABLE` to any value other than `false`, `0`,
or the empty string.
Features that aren't yet ready for stabilization are marked as unstable and may
be changed or removed at any time. Using unstable features produces an error by
default, which can be suppressed with by passing the `--unstable` flag,
`set unstable`, or setting the environment variable `JUST_UNSTABLE`, to any
value other than `false`, `0`, or the empty string.
Editor Support
--------------
@ -820,6 +820,7 @@ foo:
| `positional-arguments` | boolean | `false` | Pass positional arguments. |
| `shell` | `[COMMAND, ARGS…]` | - | Set the command used to invoke recipes and evaluate backticks. |
| `tempdir` | string | - | Create temporary directories in `tempdir` instead of the system default temporary directory. |
| `unstable`<sup>master</sup> | boolean | `false` | Enable unstable features. |
| `windows-powershell` | boolean | `false` | Use PowerShell on Windows as default shell. (Deprecated. Use `windows-shell` instead. |
| `windows-shell` | `[COMMAND, ARGS…]` | - | Set the command used to invoke recipes and evaluate backticks. |
@ -1349,6 +1350,11 @@ Done!
`just` provides a few built-in functions that might be useful when writing
recipes.
All functions ending in `_directory` can be abbreviated to `_dir`. So
`home_directory()` can also be written as `home_dir()`. In addition,
`invocation_directory_native()` can be abbreviated to
`invocation_dir_native()`.
#### System Information
- `arch()` — Instruction set architecture. Possible values are: `"aarch64"`,
@ -1645,8 +1651,8 @@ which will halt execution.
#### Datetime
- `datetime(format)`<sup>master</sup> - Return local time with `format`.
- `datetime_utc(format)`<sup>master</sup> - Return UTC time with `format`.
- `datetime(format)`<sup>1.30.0</sup> - Return local time with `format`.
- `datetime_utc(format)`<sup>1.30.0</sup> - Return UTC time with `format`.
The arguments to `datetime` and `datetime_utc` are `strftime`-style format
strings, see the
@ -3149,8 +3155,8 @@ Missing source files for optional imports do not produce an error.
### Modules<sup>1.19.0</sup>
A `justfile` can declare modules using `mod` statements. `mod` statements are
currently unstable, so you'll need to use the `--unstable` flag, or set the
`JUST_UNSTABLE` environment variable to use them.
currently unstable, so you'll need to use the `--unstable` flag,
`set unstable`, or set the `JUST_UNSTABLE` environment variable to use them.
If you have the following `justfile`:
@ -3198,7 +3204,10 @@ mod foo 'PATH'
Which loads the module's source file from `PATH`, instead of from the usual
locations. A leading `~/` in `PATH` is replaced with the current user's home
directory.
directory. `PATH` may point to the module source file itself, or to a directory
containing the module source file with the name `mod.just`, `justfile`, or
`.justfile`. In the latter two cases, the module file may have any
capitalization.
Environment files are only loaded for the root justfile, and loaded environment
variables are available in submodules. Settings in submodules that affect
@ -3229,7 +3238,7 @@ mod? foo 'baz.just'
```
Modules may be given doc comments which appear in `--list`
output<sup>master</sup>:
output<sup>1.30.0</sup>:
```mf
# foo is a great module!
@ -3751,9 +3760,9 @@ binary from the outside by invoking `just` on a given `justfile` and set of
command-line arguments, and checking the output.
You should write whichever type of tests are easiest to write for your feature
while still providing test good coverage.
while still providing good test coverage.
Unit tests are useful for testing new Rust functions that are used internally,
Unit tests are useful for testing new Rust functions that are used internally
and as an aid for development. A good example are the unit tests which cover
the
[`unindent()` function](https://github.com/casey/just/blob/master/src/unindent.rs),
@ -3765,7 +3774,7 @@ Integration tests are useful for making sure that the final behavior of the
`just` binary is correct. `unindent()` is also covered by integration tests
which make sure that evaluating a triple-quoted string produces the correct
unindented value. However, there are not integration tests for all possible
cases, since these are covered by faster, more concise unit tests that call
cases. These are covered by faster, more concise unit tests that call
`unindent()` directly.
Existing integration tests are in two forms, those that use the `test!` macro
@ -3817,8 +3826,7 @@ checking the program's stdout, stderr, and exit code .
9. Enjoy the sweet feeling of your PR getting merged!
Feel free at any time to open a draft PR with your changes for discussion and
feedback.
Feel free to open a draft PR at any time for discussion and feedback.
### Hints

View File

@ -37,6 +37,8 @@ impl<'src> Analyzer<'src> {
let mut warnings = Vec::new();
let mut unstable = BTreeSet::new();
let mut modules: Table<Justfile> = Table::new();
let mut unexports: HashSet<String> = HashSet::new();
@ -92,6 +94,8 @@ impl<'src> Analyzer<'src> {
doc,
..
} => {
unstable.insert(Unstable::Modules);
if let Some(absolute) = absolute {
define(*name, "module", false)?;
modules.insert(Self::analyze(
@ -194,6 +198,7 @@ impl<'src> Analyzer<'src> {
settings,
source: root.into(),
unexports,
unstable,
warnings,
})
}

View File

@ -252,7 +252,7 @@ mod tests {
fs::write(&path, "mod foo").unwrap();
fs::create_dir(tempdir.path().join("foo")).unwrap();
fs::write(tempdir.path().join("foo/mod.just"), "bar:").unwrap();
let compilation = Compiler::compile(true, &loader, &path).unwrap();
let compilation = Compiler::compile(&loader, &path).unwrap();
assert_eq!(
ArgumentParser::parse_arguments(&compilation.justfile, &["foo", "bar"]).unwrap(),
@ -271,7 +271,7 @@ mod tests {
fs::write(&path, "mod foo").unwrap();
fs::create_dir(tempdir.path().join("foo")).unwrap();
fs::write(tempdir.path().join("foo/mod.just"), "bar:").unwrap();
let compilation = Compiler::compile(true, &loader, &path).unwrap();
let compilation = Compiler::compile(&loader, &path).unwrap();
assert_matches!(
ArgumentParser::parse_arguments(&compilation.justfile, &["foo", "zzz"]).unwrap_err(),
@ -289,7 +289,7 @@ mod tests {
tempdir.write("foo.just", "bar:");
let loader = Loader::new();
let compilation = Compiler::compile(true, &loader, &tempdir.path().join("justfile")).unwrap();
let compilation = Compiler::compile(&loader, &tempdir.path().join("justfile")).unwrap();
assert_matches!(
ArgumentParser::parse_arguments(&compilation.justfile, &["foo::zzz"]).unwrap_err(),
@ -307,7 +307,7 @@ mod tests {
tempdir.write("foo.just", "bar:");
let loader = Loader::new();
let compilation = Compiler::compile(true, &loader, &tempdir.path().join("justfile")).unwrap();
let compilation = Compiler::compile(&loader, &tempdir.path().join("justfile")).unwrap();
assert_matches!(
ArgumentParser::parse_arguments(&compilation.justfile, &["foo::bar::baz"]).unwrap_err(),
@ -323,7 +323,7 @@ mod tests {
tempdir.write("justfile", "");
let loader = Loader::new();
let compilation = Compiler::compile(true, &loader, &tempdir.path().join("justfile")).unwrap();
let compilation = Compiler::compile(&loader, &tempdir.path().join("justfile")).unwrap();
assert_matches!(
ArgumentParser::parse_arguments(&compilation.justfile, &[]).unwrap_err(),
@ -337,7 +337,7 @@ mod tests {
tempdir.write("justfile", "foo bar:");
let loader = Loader::new();
let compilation = Compiler::compile(true, &loader, &tempdir.path().join("justfile")).unwrap();
let compilation = Compiler::compile(&loader, &tempdir.path().join("justfile")).unwrap();
assert_matches!(
ArgumentParser::parse_arguments(&compilation.justfile, &[]).unwrap_err(),
@ -355,7 +355,7 @@ mod tests {
tempdir.write("foo.just", "bar:");
let loader = Loader::new();
let compilation = Compiler::compile(true, &loader, &tempdir.path().join("justfile")).unwrap();
let compilation = Compiler::compile(&loader, &tempdir.path().join("justfile")).unwrap();
assert_matches!(
ArgumentParser::parse_arguments(&compilation.justfile, &[]).unwrap_err(),

View File

@ -66,7 +66,7 @@ pub(crate) enum CompileErrorKind<'src> {
FunctionArgumentCountMismatch {
function: &'src str,
found: usize,
expected: Range<usize>,
expected: RangeInclusive<usize>,
},
Include,
InconsistentLeadingWhitespace {

View File

@ -4,14 +4,13 @@ pub(crate) struct Compiler;
impl Compiler {
pub(crate) fn compile<'src>(
unstable: bool,
loader: &'src Loader,
root: &Path,
) -> RunResult<'src, Compilation<'src>> {
let mut asts = HashMap::<PathBuf, Ast>::new();
let mut loaded = Vec::new();
let mut paths = HashMap::<PathBuf, PathBuf>::new();
let mut srcs = HashMap::<PathBuf, &str>::new();
let mut loaded = Vec::new();
let mut stack = Vec::new();
stack.push(Source::root(root));
@ -42,25 +41,14 @@ impl Compiler {
relative,
..
} => {
if !unstable {
return Err(Error::Unstable {
message: "Modules are currently unstable.".into(),
});
}
let parent = current.path.parent().unwrap();
let import = if let Some(relative) = relative {
let path = parent.join(Self::expand_tilde(&relative.cooked)?);
let relative = relative
.as_ref()
.map(|relative| Self::expand_tilde(&relative.cooked))
.transpose()?;
if path.is_file() {
Some(path)
} else {
None
}
} else {
Self::find_module_file(parent, *name)?
};
let import = Self::find_module_file(parent, *name, relative.as_deref())?;
if let Some(import) = import {
if current.file_path.contains(&import) {
@ -112,25 +100,69 @@ impl Compiler {
Ok(Compilation {
asts,
srcs,
justfile,
root: root.into(),
srcs,
})
}
fn find_module_file<'src>(parent: &Path, module: Name<'src>) -> RunResult<'src, Option<PathBuf>> {
let mut candidates = vec![format!("{module}.just"), format!("{module}/mod.just")]
.into_iter()
.filter(|path| parent.join(path).is_file())
.collect::<Vec<String>>();
fn find_module_file<'src>(
parent: &Path,
module: Name<'src>,
path: Option<&Path>,
) -> RunResult<'src, Option<PathBuf>> {
let mut candidates = Vec::new();
let directory = parent.join(module.lexeme());
if let Some(path) = path {
let full = parent.join(path);
if directory.exists() {
let entries = fs::read_dir(&directory).map_err(|io_error| SearchError::Io {
io_error,
directory: directory.clone(),
})?;
if full.is_file() {
return Ok(Some(full));
}
candidates.push((path.join("mod.just"), true));
for name in search::JUSTFILE_NAMES {
candidates.push((path.join(name), false));
}
} else {
candidates.push((format!("{module}.just").into(), true));
candidates.push((format!("{module}/mod.just").into(), true));
for name in search::JUSTFILE_NAMES {
candidates.push((format!("{module}/{name}").into(), false));
}
}
let mut grouped = BTreeMap::<PathBuf, Vec<(PathBuf, bool)>>::new();
for (candidate, case_sensitive) in candidates {
let candidate = parent.join(candidate).lexiclean();
grouped
.entry(candidate.parent().unwrap().into())
.or_default()
.push((candidate, case_sensitive));
}
let mut found = Vec::new();
for (directory, candidates) in grouped {
let entries = match fs::read_dir(&directory) {
Ok(entries) => entries,
Err(io_error) => {
if io_error.kind() == io::ErrorKind::NotFound {
continue;
}
return Err(
SearchError::Io {
io_error,
directory,
}
.into(),
);
}
};
for entry in entries {
let entry = entry.map_err(|io_error| SearchError::Io {
@ -139,22 +171,34 @@ impl Compiler {
})?;
if let Some(name) = entry.file_name().to_str() {
for justfile_name in search::JUSTFILE_NAMES {
if name.eq_ignore_ascii_case(justfile_name) {
candidates.push(format!("{module}/{name}"));
for (candidate, case_sensitive) in &candidates {
let candidate_name = candidate.file_name().unwrap().to_str().unwrap();
let eq = if *case_sensitive {
name == candidate_name
} else {
name.eq_ignore_ascii_case(candidate_name)
};
if eq {
found.push(candidate.parent().unwrap().join(name));
}
}
}
}
}
match candidates.as_slice() {
[] => Ok(None),
[file] => Ok(Some(parent.join(file).lexiclean())),
found => Err(Error::AmbiguousModuleFile {
found: found.into(),
if found.len() > 1 {
found.sort();
Err(Error::AmbiguousModuleFile {
found: found
.into_iter()
.map(|found| found.strip_prefix(parent).unwrap().into())
.collect(),
module,
}),
})
} else {
Ok(found.into_iter().next())
}
}
@ -225,7 +269,7 @@ recipe_b: recipe_c
let loader = Loader::new();
let justfile_a_path = tmp.path().join("justfile");
let compilation = Compiler::compile(false, &loader, &justfile_a_path).unwrap();
let compilation = Compiler::compile(&loader, &justfile_a_path).unwrap();
assert_eq!(compilation.root_src(), justfile_a);
}
@ -242,11 +286,91 @@ recipe_b: recipe_c
let loader = Loader::new();
let justfile_a_path = tmp.path().join("justfile");
let loader_output = Compiler::compile(false, &loader, &justfile_a_path).unwrap_err();
let loader_output = Compiler::compile(&loader, &justfile_a_path).unwrap_err();
assert_matches!(loader_output, Error::CircularImport { current, import }
if current == tmp.path().join("subdir").join("b").lexiclean() &&
import == tmp.path().join("justfile").lexiclean()
);
}
#[test]
fn find_module_file() {
#[track_caller]
fn case(path: Option<&str>, files: &[&str], expected: Result<Option<&str>, &[&str]>) {
let module = Name {
token: Token {
column: 0,
kind: TokenKind::Identifier,
length: 3,
line: 0,
offset: 0,
path: Path::new(""),
src: "foo",
},
};
let tempdir = tempfile::tempdir().unwrap();
for file in files {
if let Some(parent) = Path::new(file).parent() {
fs::create_dir_all(tempdir.path().join(parent)).unwrap();
}
fs::write(tempdir.path().join(file), "").unwrap();
}
let actual = Compiler::find_module_file(tempdir.path(), module, path.map(Path::new));
match expected {
Err(expected) => match actual.unwrap_err() {
Error::AmbiguousModuleFile { found, .. } => {
assert_eq!(
found,
expected
.iter()
.map(|expected| expected.replace('/', std::path::MAIN_SEPARATOR_STR).into())
.collect::<Vec<PathBuf>>()
);
}
_ => panic!("unexpected error"),
},
Ok(Some(expected)) => assert_eq!(
actual.unwrap().unwrap(),
tempdir
.path()
.join(expected.replace('/', std::path::MAIN_SEPARATOR_STR))
),
Ok(None) => assert_eq!(actual.unwrap(), None),
}
}
case(None, &["foo.just"], Ok(Some("foo.just")));
case(None, &["FOO.just"], Ok(None));
case(None, &["foo/mod.just"], Ok(Some("foo/mod.just")));
case(None, &["foo/MOD.just"], Ok(None));
case(None, &["foo/justfile"], Ok(Some("foo/justfile")));
case(None, &["foo/JUSTFILE"], Ok(Some("foo/JUSTFILE")));
case(None, &["foo/.justfile"], Ok(Some("foo/.justfile")));
case(None, &["foo/.JUSTFILE"], Ok(Some("foo/.JUSTFILE")));
case(
None,
&["foo/.justfile", "foo/justfile"],
Err(&["foo/.justfile", "foo/justfile"]),
);
case(None, &["foo/JUSTFILE"], Ok(Some("foo/JUSTFILE")));
case(Some("bar"), &["bar"], Ok(Some("bar")));
case(Some("bar"), &["bar/mod.just"], Ok(Some("bar/mod.just")));
case(Some("bar"), &["bar/justfile"], Ok(Some("bar/justfile")));
case(Some("bar"), &["bar/JUSTFILE"], Ok(Some("bar/JUSTFILE")));
case(Some("bar"), &["bar/.justfile"], Ok(Some("bar/.justfile")));
case(Some("bar"), &["bar/.JUSTFILE"], Ok(Some("bar/.JUSTFILE")));
case(
Some("bar"),
&["bar/justfile", "bar/mod.just"],
Err(&["bar/justfile", "bar/mod.just"]),
);
}
}

View File

@ -4,7 +4,7 @@ use super::*;
pub(crate) enum Error<'src> {
AmbiguousModuleFile {
module: Name<'src>,
found: Vec<String>,
found: Vec<PathBuf>,
},
ArgumentCountMismatch {
recipe: &'src str,
@ -262,7 +262,7 @@ impl<'src> ColorDisplay for Error<'src> {
AmbiguousModuleFile { module, found } =>
write!(f,
"Found multiple source files for module `{module}`: {}",
List::and_ticked(found),
List::and_ticked(found.iter().map(|path| path.display())),
)?,
ArgumentCountMismatch { recipe, found, min, max, .. } => {
let count = Count("argument", *found);
@ -460,7 +460,7 @@ impl<'src> ColorDisplay for Error<'src> {
}
}
Unstable { message } => {
write!(f, "{message} Invoke `just` with the `--unstable` flag to enable unstable features.")?;
write!(f, "{message} Invoke `just` with `--unstable`, set the `JUST_UNSTABLE` environment variable, or add `set unstable` to your `justfile` to enable unstable features.")?;
}
WriteJustfile { justfile, io_error } => {
let justfile = justfile.display();

View File

@ -32,7 +32,15 @@ impl<'src: 'run, 'run> Context<'src, 'run> {
}
pub(crate) fn get(name: &str) -> Option<Function> {
let function = match name {
let name = if let Some(prefix) = name.strip_suffix("_dir") {
format!("{prefix}_directory")
} else if let Some(prefix) = name.strip_suffix("_dir_native") {
format!("{prefix}_directory_native")
} else {
name.into()
};
let function = match name.as_str() {
"absolute_path" => Unary(absolute_path),
"append" => Binary(append),
"arch" => Nullary(arch),
@ -108,15 +116,15 @@ pub(crate) fn get(name: &str) -> Option<Function> {
}
impl Function {
pub(crate) fn argc(&self) -> Range<usize> {
pub(crate) fn argc(&self) -> RangeInclusive<usize> {
match *self {
Nullary(_) => 0..0,
Unary(_) => 1..1,
UnaryOpt(_) => 1..2,
UnaryPlus(_) => 1..usize::MAX,
Binary(_) => 2..2,
BinaryPlus(_) => 2..usize::MAX,
Ternary(_) => 3..3,
Nullary(_) => 0..=0,
Unary(_) => 1..=1,
UnaryOpt(_) => 1..=2,
UnaryPlus(_) => 1..=usize::MAX,
Binary(_) => 2..=2,
BinaryPlus(_) => 2..=usize::MAX,
Ternary(_) => 3..=3,
}
}
}

View File

@ -13,6 +13,7 @@ pub(crate) enum Item<'src> {
relative: StringLiteral<'src>,
},
Module {
attributes: BTreeSet<Attribute<'src>>,
absolute: Option<PathBuf>,
doc: Option<&'src str>,
name: Name<'src>,

View File

@ -27,6 +27,8 @@ pub(crate) struct Justfile<'src> {
pub(crate) source: PathBuf,
pub(crate) unexports: HashSet<String>,
pub(crate) warnings: Vec<Warning>,
#[serde(skip)]
pub(crate) unstable: BTreeSet<Unstable>,
}
impl<'src> Justfile<'src> {
@ -225,6 +227,22 @@ impl<'src> Justfile<'src> {
Ok(())
}
pub(crate) fn check_unstable(&self, config: &Config) -> RunResult<'src> {
if !config.unstable && !self.settings.unstable {
if let Some(unstable) = self.unstable.iter().next() {
return Err(Error::Unstable {
message: unstable.message(),
});
}
}
for module in self.modules.values() {
module.check_unstable(config)?;
}
Ok(())
}
pub(crate) fn get_alias(&self, name: &str) -> Option<&Alias<'src>> {
self.aliases.get(name)
}

View File

@ -26,6 +26,7 @@ pub(crate) enum Keyword {
Tempdir,
True,
Unexport,
Unstable,
WindowsPowershell,
WindowsShell,
X,

View File

@ -42,8 +42,8 @@ pub(crate) use {
shell::Shell, show_whitespace::ShowWhitespace, source::Source, string_kind::StringKind,
string_literal::StringLiteral, subcommand::Subcommand, suggestion::Suggestion, table::Table,
thunk::Thunk, token::Token, token_kind::TokenKind, unresolved_dependency::UnresolvedDependency,
unresolved_recipe::UnresolvedRecipe, use_color::UseColor, variables::Variables,
verbosity::Verbosity, warning::Warning,
unresolved_recipe::UnresolvedRecipe, unstable::Unstable, use_color::UseColor,
variables::Variables, verbosity::Verbosity, warning::Warning,
},
camino::Utf8Path,
clap::ValueEnum,
@ -204,6 +204,7 @@ mod token_kind;
mod unindent;
mod unresolved_dependency;
mod unresolved_recipe;
mod unstable;
mod use_color;
mod variables;
mod verbosity;

View File

@ -294,6 +294,7 @@ impl<'src> Node<'src> for Set<'src> {
| Setting::Fallback(value)
| Setting::PositionalArguments(value)
| Setting::Quiet(value)
| Setting::Unstable(value)
| Setting::WindowsPowerShell(value)
| Setting::IgnoreComments(value) => {
set.push_mut(value.to_string());

View File

@ -373,27 +373,7 @@ impl<'run, 'src> Parser<'run, 'src> {
|| self.next_are(&[Identifier, QuestionMark]) =>
{
let doc = pop_doc_comment(&mut items, eol_since_last_comment);
self.presume_keyword(Keyword::Mod)?;
let optional = self.accepted(QuestionMark)?;
let name = self.parse_name()?;
let relative = if self.next_is(StringToken) || self.next_are(&[Identifier, StringToken])
{
Some(self.parse_string_literal()?)
} else {
None
};
items.push(Item::Module {
absolute: None,
doc,
name,
optional,
relative,
});
items.push(self.parse_module(BTreeSet::new(), doc)?);
}
Some(Keyword::Set)
if self.next_are(&[Identifier, Identifier, ColonEquals])
@ -430,6 +410,17 @@ impl<'run, 'src> Parser<'run, 'src> {
Some(Keyword::Alias) if self.next_are(&[Identifier, Identifier, ColonEquals]) => {
items.push(Item::Alias(self.parse_alias(attributes)?));
}
Some(Keyword::Mod)
if self.next_are(&[Identifier, Identifier, Comment])
|| self.next_are(&[Identifier, Identifier, Eof])
|| self.next_are(&[Identifier, Identifier, Eol])
|| self.next_are(&[Identifier, Identifier, Identifier, StringToken])
|| self.next_are(&[Identifier, Identifier, StringToken])
|| self.next_are(&[Identifier, QuestionMark]) =>
{
let doc = pop_doc_comment(&mut items, eol_since_last_comment);
items.push(self.parse_module(attributes, doc)?);
}
_ => {
let quiet = self.accepted(At)?;
let doc = pop_doc_comment(&mut items, eol_since_last_comment);
@ -454,6 +445,33 @@ impl<'run, 'src> Parser<'run, 'src> {
}
}
fn parse_module(
&mut self,
attributes: BTreeSet<Attribute<'src>>,
doc: Option<&'src str>,
) -> CompileResult<'src, Item<'src>> {
self.presume_keyword(Keyword::Mod)?;
let optional = self.accepted(QuestionMark)?;
let name = self.parse_name()?;
let relative = if self.next_is(StringToken) || self.next_are(&[Identifier, StringToken]) {
Some(self.parse_string_literal()?)
} else {
None
};
Ok(Item::Module {
attributes,
absolute: None,
doc,
name,
optional,
relative,
})
}
/// Parse an alias, e.g `alias name := target`
fn parse_alias(
&mut self,
@ -936,6 +954,7 @@ impl<'run, 'src> Parser<'run, 'src> {
Keyword::IgnoreComments => Some(Setting::IgnoreComments(self.parse_set_bool()?)),
Keyword::PositionalArguments => Some(Setting::PositionalArguments(self.parse_set_bool()?)),
Keyword::Quiet => Some(Setting::Quiet(self.parse_set_bool()?)),
Keyword::Unstable => Some(Setting::Unstable(self.parse_set_bool()?)),
Keyword::WindowsPowershell => Some(Setting::WindowsPowerShell(self.parse_set_bool()?)),
_ => None,
};
@ -2568,7 +2587,7 @@ mod tests {
kind: FunctionArgumentCountMismatch {
function: "arch",
found: 1,
expected: 0..0,
expected: 0..=0,
},
}
@ -2582,7 +2601,7 @@ mod tests {
kind: FunctionArgumentCountMismatch {
function: "env_var",
found: 0,
expected: 1..1,
expected: 1..=1,
},
}
@ -2596,7 +2615,7 @@ mod tests {
kind: FunctionArgumentCountMismatch {
function: "env",
found: 3,
expected: 1..2,
expected: 1..=2,
},
}
@ -2610,7 +2629,7 @@ mod tests {
kind: FunctionArgumentCountMismatch {
function: "env",
found: 0,
expected: 1..2,
expected: 1..=2,
},
}
@ -2624,7 +2643,7 @@ mod tests {
kind: FunctionArgumentCountMismatch {
function: "env_var_or_default",
found: 1,
expected: 2..2,
expected: 2..=2,
},
}
@ -2638,7 +2657,7 @@ mod tests {
kind: FunctionArgumentCountMismatch {
function: "join",
found: 1,
expected: 2..usize::MAX,
expected: 2..=usize::MAX,
},
}
@ -2652,7 +2671,7 @@ mod tests {
kind: FunctionArgumentCountMismatch {
function: "replace",
found: 1,
expected: 3..3,
expected: 3..=3,
},
}
}

View File

@ -10,16 +10,14 @@ pub(crate) trait RangeExt<T> {
pub(crate) struct DisplayRange<T>(T);
impl Display for DisplayRange<&Range<usize>> {
impl Display for DisplayRange<&RangeInclusive<usize>> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
if self.0.start == self.0.end {
write!(f, "0")?;
} else if self.0.start == self.0.end - 1 {
write!(f, "{}", self.0.start)?;
} else if self.0.end == usize::MAX {
write!(f, "{} or more", self.0.start)?;
if self.0.start() == self.0.end() {
write!(f, "{}", self.0.start())?;
} else if *self.0.end() == usize::MAX {
write!(f, "{} or more", self.0.start())?;
} else {
write!(f, "{} to {}", self.0.start, self.0.end - 1)?;
write!(f, "{} to {}", self.0.start(), self.0.end())?;
}
Ok(())
}
@ -76,10 +74,10 @@ mod tests {
assert!(!(1..1).contains(&1));
assert!((1..1).is_empty());
assert!((5..5).is_empty());
assert_eq!((1..1).display().to_string(), "0");
assert_eq!((1..2).display().to_string(), "1");
assert_eq!((5..6).display().to_string(), "5");
assert_eq!((5..10).display().to_string(), "5 to 9");
assert_eq!((1..usize::MAX).display().to_string(), "1 or more");
assert_eq!((0..=0).display().to_string(), "0");
assert_eq!((1..=1).display().to_string(), "1");
assert_eq!((5..=5).display().to_string(), "5");
assert_eq!((5..=9).display().to_string(), "5 to 9");
assert_eq!((1..=usize::MAX).display().to_string(), "1 or more");
}
}

View File

@ -4,6 +4,7 @@ const DEFAULT_JUSTFILE_NAME: &str = JUSTFILE_NAMES[0];
pub(crate) const JUSTFILE_NAMES: [&str; 2] = ["justfile", ".justfile"];
const PROJECT_ROOT_CHILDREN: &[&str] = &[".bzr", ".git", ".hg", ".svn", "_darcs"];
#[derive(Debug)]
pub(crate) struct Search {
pub(crate) justfile: PathBuf,
pub(crate) working_directory: PathBuf,

View File

@ -15,6 +15,7 @@ pub(crate) enum Setting<'src> {
Quiet(bool),
Shell(Shell<'src>),
Tempdir(String),
Unstable(bool),
WindowsPowerShell(bool),
WindowsShell(Shell<'src>),
}
@ -31,6 +32,7 @@ impl<'src> Display for Setting<'src> {
| Self::IgnoreComments(value)
| Self::PositionalArguments(value)
| Self::Quiet(value)
| Self::Unstable(value)
| Self::WindowsPowerShell(value) => write!(f, "{value}"),
Self::Shell(shell) | Self::WindowsShell(shell) => write!(f, "{shell}"),
Self::DotenvFilename(value) | Self::DotenvPath(value) | Self::Tempdir(value) => {

View File

@ -20,6 +20,7 @@ pub(crate) struct Settings<'src> {
pub(crate) quiet: bool,
pub(crate) shell: Option<Shell<'src>>,
pub(crate) tempdir: Option<String>,
pub(crate) unstable: bool,
pub(crate) windows_powershell: bool,
pub(crate) windows_shell: Option<Shell<'src>>,
}
@ -66,6 +67,9 @@ impl<'src> Settings<'src> {
Setting::Shell(shell) => {
settings.shell = Some(shell);
}
Setting::Unstable(unstable) => {
settings.unstable = unstable;
}
Setting::WindowsPowerShell(windows_powershell) => {
settings.windows_powershell = windows_powershell;
}

View File

@ -110,9 +110,10 @@ impl Subcommand {
) {
let starting_path = match &config.search_config {
SearchConfig::FromInvocationDirectory => config.invocation_directory.clone(),
SearchConfig::FromSearchDirectory { search_directory } => {
env::current_dir().unwrap().join(search_directory)
}
SearchConfig::FromSearchDirectory { search_directory } => config
.invocation_directory
.join(search_directory)
.lexiclean(),
_ => unreachable!(),
};
@ -189,7 +190,9 @@ impl Subcommand {
loader: &'src Loader,
search: &Search,
) -> RunResult<'src, Compilation<'src>> {
let compilation = Compiler::compile(config.unstable, loader, &search.justfile)?;
let compilation = Compiler::compile(loader, &search.justfile)?;
compilation.justfile.check_unstable(config)?;
if config.verbosity.loud() {
for warning in &compilation.justfile.warnings {

View File

@ -28,7 +28,7 @@ mod full {
pub fn summary(path: &Path) -> io::Result<Result<Summary, String>> {
let loader = Loader::new();
match Compiler::compile(false, &loader, path) {
match Compiler::compile(&loader, path) {
Ok(compilation) => Ok(Ok(Summary::new(&compilation.justfile))),
Err(error) => Ok(Err(if let Error::Compile { compile_error } = error {
compile_error.to_string()

12
src/unstable.rs Normal file
View File

@ -0,0 +1,12 @@
#[derive(Copy, Clone, Debug, PartialEq, Ord, Eq, PartialOrd)]
pub(crate) enum Unstable {
Modules,
}
impl Unstable {
pub(crate) fn message(self) -> String {
match self {
Self::Modules => "Modules are currently unstable.".into(),
}
}
}

View File

@ -4,10 +4,7 @@ test! {
name: unstable_not_passed,
justfile: "",
args: ("--fmt"),
stderr: "
error: The `--fmt` command is currently unstable. \
Invoke `just` with the `--unstable` flag to enable unstable features.
",
stderr_regex: "error: The `--fmt` command is currently unstable..*",
status: EXIT_FAILURE,
}

View File

@ -1050,3 +1050,51 @@ fn is_dependency() {
.stdout("beta false\ngamma true\n")
.run();
}
#[test]
fn unary_argument_count_mismamatch_error_message() {
Test::new()
.justfile("x := datetime()")
.args(["--evaluate"])
.stderr(
"
error: Function `datetime` called with 0 arguments but takes 1
justfile:1:6
1 x := datetime()
^^^^^^^^
",
)
.status(EXIT_FAILURE)
.run();
}
#[test]
fn dir_abbreviations_are_accepted() {
Test::new()
.justfile(
"
abbreviated := justfile_dir()
unabbreviated := justfile_directory()
@foo:
# {{ assert(abbreviated == unabbreviated, 'fail') }}
",
)
.run();
}
#[test]
fn invocation_dir_native_abbreviation_is_accepted() {
Test::new()
.justfile(
"
abbreviated := invocation_directory_native()
unabbreviated := invocation_dir_native()
@foo:
# {{ assert(abbreviated == unabbreviated, 'fail') }}
",
)
.run();
}

View File

@ -56,7 +56,9 @@ fn alias() {
"quiet": false,
"shell": null,
"tempdir" : null,
"unstable": false,
"ignore_comments": false,
"unstable": false,
"windows_powershell": false,
"windows_shell": null,
},
@ -98,6 +100,7 @@ fn assignment() {
"quiet": false,
"shell": null,
"tempdir" : null,
"unstable": false,
"windows_powershell": false,
"windows_shell": null,
},
@ -153,6 +156,7 @@ fn body() {
"quiet": false,
"shell": null,
"tempdir" : null,
"unstable": false,
"windows_powershell": false,
"windows_shell": null,
},
@ -220,6 +224,7 @@ fn dependencies() {
"quiet": false,
"shell": null,
"tempdir" : null,
"unstable": false,
"windows_powershell": false,
"windows_shell": null,
},
@ -325,6 +330,7 @@ fn dependency_argument() {
"quiet": false,
"shell": null,
"tempdir" : null,
"unstable": false,
"windows_powershell": false,
"windows_shell": null,
},
@ -392,6 +398,7 @@ fn duplicate_recipes() {
"quiet": false,
"shell": null,
"tempdir" : null,
"unstable": false,
"windows_powershell": false,
"windows_shell": null,
},
@ -437,6 +444,7 @@ fn duplicate_variables() {
"quiet": false,
"shell": null,
"tempdir" : null,
"unstable": false,
"windows_powershell": false,
"windows_shell": null,
},
@ -485,6 +493,7 @@ fn doc_comment() {
"quiet": false,
"shell": null,
"tempdir" : null,
"unstable": false,
"windows_powershell": false,
"windows_shell": null,
},
@ -519,6 +528,7 @@ fn empty_justfile() {
"quiet": false,
"shell": null,
"tempdir" : null,
"unstable": false,
"windows_powershell": false,
"windows_shell": null,
},
@ -674,6 +684,7 @@ fn parameters() {
"quiet": false,
"shell": null,
"tempdir" : null,
"unstable": false,
"windows_powershell": false,
"windows_shell": null,
},
@ -762,6 +773,7 @@ fn priors() {
"quiet": false,
"shell": null,
"tempdir" : null,
"unstable": false,
"windows_powershell": false,
"windows_shell": null,
},
@ -810,6 +822,7 @@ fn private() {
"quiet": false,
"shell": null,
"tempdir" : null,
"unstable": false,
"windows_powershell": false,
"windows_shell": null,
},
@ -858,6 +871,7 @@ fn quiet() {
"quiet": false,
"shell": null,
"tempdir" : null,
"unstable": false,
"windows_powershell": false,
"windows_shell": null,
},
@ -921,6 +935,7 @@ fn settings() {
"command": "a",
},
"tempdir": null,
"unstable": false,
"windows_powershell": false,
"windows_shell": null,
},
@ -972,6 +987,7 @@ fn shebang() {
"quiet": false,
"shell": null,
"tempdir": null,
"unstable": false,
"windows_powershell": false,
"windows_shell": null,
},
@ -1020,6 +1036,7 @@ fn simple() {
"quiet": false,
"shell": null,
"tempdir": null,
"unstable": false,
"windows_powershell": false,
"windows_shell": null,
},
@ -1070,6 +1087,7 @@ fn attribute() {
"quiet": false,
"shell": null,
"tempdir" : null,
"unstable": false,
"ignore_comments": false,
"windows_powershell": false,
"windows_shell": null,
@ -1136,6 +1154,7 @@ fn module() {
"quiet": false,
"shell": null,
"tempdir" : null,
"unstable": false,
"ignore_comments": false,
"windows_powershell": false,
"windows_shell": null,
@ -1158,6 +1177,7 @@ fn module() {
"quiet": false,
"shell": null,
"tempdir" : null,
"unstable": false,
"ignore_comments": false,
"windows_powershell": false,
"windows_shell": null,

View File

@ -19,7 +19,7 @@ pub(crate) use {
fs,
io::Write,
iter,
path::{Path, PathBuf, MAIN_SEPARATOR},
path::{Path, PathBuf, MAIN_SEPARATOR, MAIN_SEPARATOR_STR},
process::{Command, Stdio},
str,
},

View File

@ -8,10 +8,8 @@ fn modules_are_unstable() {
mod foo
",
)
.stderr(
"error: Modules are currently unstable. \
Invoke `just` with the `--unstable` flag to enable unstable features.\n",
)
.write("foo.just", "")
.stderr_regex("error: Modules are currently unstable..*")
.status(EXIT_FAILURE)
.run();
}
@ -441,12 +439,13 @@ fn modules_require_unambiguous_file() {
.status(EXIT_FAILURE)
.stderr(
"
error: Found multiple source files for module `foo`: `foo.just` and `foo/justfile`
error: Found multiple source files for module `foo`: `foo/justfile` and `foo.just`
justfile:1:5
1 mod foo
^^^
",
"
.replace('/', MAIN_SEPARATOR_STR),
)
.run();
}
@ -566,6 +565,23 @@ fn modules_may_specify_path() {
.run();
}
#[test]
fn modules_may_specify_path_to_directory() {
Test::new()
.write("commands/bar/mod.just", "foo:\n @echo FOO")
.justfile(
"
mod foo 'commands/bar'
",
)
.test_round_trip(false)
.arg("--unstable")
.arg("foo")
.arg("foo")
.stdout("FOO\n")
.run();
}
#[test]
fn modules_with_paths_are_dumped_correctly() {
Test::new()

View File

@ -143,6 +143,22 @@ fn single_upwards() {
search_test(path, &["../"]);
}
#[test]
fn double_upwards() {
let tmp = temptree! {
justfile: "default:\n\techo ok",
foo: {
bar: {
justfile: "default:\n\techo foo",
},
},
};
let path = tmp.path().join("foo/bar");
search_test(path, &["../default"]);
}
#[test]
fn find_dot_justfile() {
Test::new()

View File

@ -150,7 +150,7 @@ impl Test {
}
pub(crate) fn stderr_regex(mut self, stderr_regex: impl AsRef<str>) -> Self {
self.stderr_regex = Some(Regex::new(&format!("^{}$", stderr_regex.as_ref())).unwrap());
self.stderr_regex = Some(Regex::new(&format!("^(?s){}$", stderr_regex.as_ref())).unwrap());
self
}

View File

@ -26,12 +26,12 @@ default:
"#;
for val in ["0", "", "false"] {
Test::new()
.justfile(justfile)
.args(["--fmt"])
.env("JUST_UNSTABLE", val)
.status(EXIT_FAILURE)
.stderr("error: The `--fmt` command is currently unstable. Invoke `just` with the `--unstable` flag to enable unstable features.\n")
.run();
.justfile(justfile)
.args(["--fmt"])
.env("JUST_UNSTABLE", val)
.status(EXIT_FAILURE)
.stderr_regex("error: The `--fmt` command is currently unstable.*")
.run();
}
}
@ -45,6 +45,40 @@ default:
.justfile(justfile)
.args(["--fmt"])
.status(EXIT_FAILURE)
.stderr("error: The `--fmt` command is currently unstable. Invoke `just` with the `--unstable` flag to enable unstable features.\n")
.stderr_regex("error: The `--fmt` command is currently unstable.*")
.run();
}
#[test]
fn set_unstable_with_setting() {
Test::new()
.justfile(
"
set unstable
mod foo
",
)
.write("foo.just", "@bar:\n echo BAR")
.args(["foo", "bar"])
.stdout("BAR\n")
.run();
}
#[test]
fn unstable_setting_does_not_affect_submodules() {
Test::new()
.justfile(
"
set unstable
mod foo
",
)
.write("foo.just", "mod bar")
.write("bar.just", "baz:\n echo hello")
.args(["foo", "bar"])
.stderr_regex("error: Modules are currently unstable.*")
.status(EXIT_FAILURE)
.run();
}