mirror of
https://github.com/pesde-pkg/pesde.git
synced 2024-12-12 11:00:36 +00:00
feat: roblox sync config script
This commit is contained in:
parent
10ca24a0cc
commit
d81f2350df
22 changed files with 940 additions and 291 deletions
175
Cargo.lock
generated
175
Cargo.lock
generated
|
@ -227,9 +227,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "async-signal"
|
||||
version = "0.2.8"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "794f185324c2f00e771cd9f1ae8b5ac68be2ca7abb129a87afd6e86d228bc54d"
|
||||
checksum = "dfb3634b73397aa844481f814fad23bbf07fdb0eabec10f2eb95e58944b1ec32"
|
||||
dependencies = [
|
||||
"async-io",
|
||||
"async-lock",
|
||||
|
@ -370,9 +370,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
|||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.6.0"
|
||||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9"
|
||||
checksum = "a12916984aab3fa6e39d655a33e09c0071eb36d6ab3aea5c2d78551f1df6d952"
|
||||
|
||||
[[package]]
|
||||
name = "bzip2"
|
||||
|
@ -406,13 +406,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.1.1"
|
||||
version = "1.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "907d8581360765417f8f2e0e7d602733bbed60156b4465b7617243689ef9b83d"
|
||||
checksum = "2aba8f4e9906c7ce3c73463f62a7f0c65183ada1a2d47e397cc8810827f9694f"
|
||||
dependencies = [
|
||||
"jobserver",
|
||||
"libc",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -597,25 +596,6 @@ dependencies = [
|
|||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
|
||||
dependencies = [
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.20"
|
||||
|
@ -723,9 +703,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deflate64"
|
||||
version = "0.1.8"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83ace6c86376be0b6cdcf3fb41882e81d94b31587573d1cfa9d01cd06bba210d"
|
||||
checksum = "da692b8d1080ea3045efaab14434d40468c3d8657e42abddfffca87b428f4c1b"
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
|
@ -1152,6 +1132,7 @@ dependencies = [
|
|||
"gix-utils",
|
||||
"gix-validate",
|
||||
"gix-worktree",
|
||||
"gix-worktree-state",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"regex",
|
||||
|
@ -1172,7 +1153,7 @@ dependencies = [
|
|||
"itoa",
|
||||
"serde",
|
||||
"thiserror",
|
||||
"winnow 0.6.13",
|
||||
"winnow 0.6.14",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1256,7 +1237,7 @@ dependencies = [
|
|||
"smallvec",
|
||||
"thiserror",
|
||||
"unicode-bom",
|
||||
"winnow 0.6.13",
|
||||
"winnow 0.6.14",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1529,7 +1510,7 @@ dependencies = [
|
|||
"serde",
|
||||
"smallvec",
|
||||
"thiserror",
|
||||
"winnow 0.6.13",
|
||||
"winnow 0.6.14",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1600,9 +1581,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "gix-path"
|
||||
version = "0.10.8"
|
||||
version = "0.10.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca987128ffb056d732bd545db5db3d8b103d252fbf083c2567bb0796876619a4"
|
||||
checksum = "8d23d5bbda31344d8abc8de7c075b3cf26e5873feba7c4a15d916bce67382bd9"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"gix-trace",
|
||||
|
@ -1655,7 +1636,7 @@ dependencies = [
|
|||
"maybe-async",
|
||||
"serde",
|
||||
"thiserror",
|
||||
"winnow 0.6.13",
|
||||
"winnow 0.6.14",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1689,7 +1670,7 @@ dependencies = [
|
|||
"memmap2",
|
||||
"serde",
|
||||
"thiserror",
|
||||
"winnow 0.6.13",
|
||||
"winnow 0.6.14",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1878,16 +1859,23 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "globset"
|
||||
version = "0.4.14"
|
||||
name = "gix-worktree-state"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1"
|
||||
checksum = "e64b2835892ce553b15aef7f6f7bb1e39e146fdf71eb99609b86710a7786cf34"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"bstr",
|
||||
"log",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
"gix-features",
|
||||
"gix-filter",
|
||||
"gix-fs",
|
||||
"gix-glob",
|
||||
"gix-hash",
|
||||
"gix-index",
|
||||
"gix-object",
|
||||
"gix-path",
|
||||
"gix-worktree",
|
||||
"io-close",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2119,22 +2107,6 @@ dependencies = [
|
|||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ignore"
|
||||
version = "0.4.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b46810df39e66e925525d6e38ce1e7f6e1d208f72dc39757880fcb66e2c58af1"
|
||||
dependencies = [
|
||||
"crossbeam-deque",
|
||||
"globset",
|
||||
"log",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"same-file",
|
||||
"walkdir",
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.9.3"
|
||||
|
@ -2216,6 +2188,16 @@ dependencies = [
|
|||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "io-close"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9cadcf447f06744f8ce713d2d6239bb5bde2c357a452397a9ed90c625da390bc"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ipnet"
|
||||
version = "2.9.0"
|
||||
|
@ -2284,9 +2266,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "keyring"
|
||||
version = "3.0.1"
|
||||
version = "3.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f32930aef50aff920e88e6cf66b70a6d587a6f2bae6aeade5c1e583661a40f8e"
|
||||
checksum = "9961b98f55dc0b2737000132505bdafa249abab147ee9de43c50ae04a054aa6c"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"dbus-secret-service",
|
||||
|
@ -2728,7 +2710,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
|
|||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall 0.5.2",
|
||||
"redox_syscall 0.5.3",
|
||||
"smallvec",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
@ -2774,7 +2756,6 @@ dependencies = [
|
|||
"flate2",
|
||||
"full_moon",
|
||||
"gix",
|
||||
"ignore",
|
||||
"indicatif",
|
||||
"indicatif-log-bridge",
|
||||
"inquire",
|
||||
|
@ -2787,7 +2768,6 @@ dependencies = [
|
|||
"pretty_env_logger",
|
||||
"relative-path",
|
||||
"reqwest",
|
||||
"secrecy",
|
||||
"semver",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
@ -2867,9 +2847,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.6.0"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0"
|
||||
checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265"
|
||||
|
||||
[[package]]
|
||||
name = "powerfmt"
|
||||
|
@ -3014,9 +2994,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.2"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd"
|
||||
checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
]
|
||||
|
@ -3228,15 +3208,6 @@ version = "1.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "secrecy"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e"
|
||||
dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "secret-service"
|
||||
version = "4.0.0"
|
||||
|
@ -3258,9 +3229,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "security-framework"
|
||||
version = "2.11.0"
|
||||
version = "2.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0"
|
||||
checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"core-foundation",
|
||||
|
@ -3271,9 +3242,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "security-framework-sys"
|
||||
version = "2.11.0"
|
||||
version = "2.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7"
|
||||
checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
|
@ -3353,9 +3324,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_with"
|
||||
version = "3.8.3"
|
||||
version = "3.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e73139bc5ec2d45e6c5fd85be5a46949c1c39a4c18e56915f5eb4c12f975e377"
|
||||
checksum = "69cecfa94848272156ea67b2b1a53f20fc7bc638c4a46d2f8abde08f05f4b857"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"chrono",
|
||||
|
@ -3371,9 +3342,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_with_macros"
|
||||
version = "3.8.3"
|
||||
version = "3.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b80d3d6b56b64335c0180e5ffde23b3c5e08c14c585b51a15bd0e95393f46703"
|
||||
checksum = "a8fee4991ef4f274617a51ad4af30519438dacb2f56ac773b08a1922ff743350"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
|
@ -3407,9 +3378,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "sha1_smol"
|
||||
version = "1.0.0"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012"
|
||||
checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d"
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
|
@ -3608,18 +3579,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.62"
|
||||
version = "1.0.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2675633b1499176c2dff06b0856a27976a8f9d436737b4cf4f312d4d91d8bbb"
|
||||
checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.62"
|
||||
version = "1.0.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d20468752b09f49e909e55a5d338caa8bedf615594e9d80bc4c565d30faf798c"
|
||||
checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -3695,9 +3666,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
|||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.38.0"
|
||||
version = "1.38.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a"
|
||||
checksum = "eb2caba9f80616f438e09748d5acda951967e1ea58508ef53d9c6402485a46df"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bytes",
|
||||
|
@ -3734,14 +3705,14 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.8.14"
|
||||
version = "0.8.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335"
|
||||
checksum = "ac2caab0bf757388c6c0ae23b3293fdb463fee59434529014f85e3263b995c28"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_edit 0.22.15",
|
||||
"toml_edit 0.22.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3766,15 +3737,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.22.15"
|
||||
version = "0.22.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d59a3a72298453f564e2b111fa896f8d07fabb36f51f06d7e875fc5e0b5a3ef1"
|
||||
checksum = "278f3d518e152219c994ce877758516bca5e118eaed6996192a774fb9fbf0788"
|
||||
dependencies = [
|
||||
"indexmap 2.2.6",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"winnow 0.6.13",
|
||||
"winnow 0.6.14",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -4253,9 +4224,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.6.13"
|
||||
version = "0.6.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1"
|
||||
checksum = "374ec40a2d767a3c1b4972d9475ecd557356637be906f2cb3f7fe17a6eb5e22f"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
@ -4389,9 +4360,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "zip"
|
||||
version = "2.1.3"
|
||||
version = "2.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "775a2b471036342aa69bc5a602bc889cb0a06cda00477d0c69566757d5553d39"
|
||||
checksum = "b895748a3ebcb69b9d38dcfdf21760859a4b0d0b0015277640c2ef4c69640e6f"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"arbitrary",
|
||||
|
|
19
Cargo.toml
19
Cargo.toml
|
@ -10,7 +10,7 @@ repository = "https://github.com/daimond113/pesde"
|
|||
include = ["src/**/*", "Cargo.toml", "Cargo.lock", "README.md", "LICENSE", "CHANGELOG.md"]
|
||||
|
||||
[features]
|
||||
bin = ["clap", "directories", "ignore", "pretty_env_logger", "reqwest/json", "reqwest/multipart", "indicatif", "indicatif-log-bridge", "inquire", "nondestructive", "colored", "anyhow", "keyring", "open"]
|
||||
bin = ["clap", "directories", "pretty_env_logger", "reqwest/json", "reqwest/multipart", "indicatif", "indicatif-log-bridge", "inquire", "nondestructive", "colored", "anyhow", "keyring", "open", "gix/worktree-mutation"]
|
||||
wally-compat = ["toml", "zip"]
|
||||
roblox = []
|
||||
lune = []
|
||||
|
@ -21,11 +21,14 @@ name = "pesde"
|
|||
path = "src/main.rs"
|
||||
required-features = ["bin"]
|
||||
|
||||
[lints.clippy]
|
||||
uninlined_format_args = "warn"
|
||||
|
||||
[dependencies]
|
||||
serde = { version = "1.0.204", features = ["derive"] }
|
||||
serde_yaml = "0.9.34"
|
||||
serde_json = "1.0.120"
|
||||
serde_with = "3.8.3"
|
||||
serde_with = "3.9.0"
|
||||
gix = { version = "0.63.0", default-features = false, features = ["blocking-http-transport-reqwest-rust-tls", "revparse-regex", "credentials", "serde"] }
|
||||
semver = { version = "1.0.23", features = ["serde"] }
|
||||
reqwest = { version = "0.12.5", default-features = false, features = ["rustls-tls", "blocking"] }
|
||||
|
@ -34,26 +37,26 @@ flate2 = "1.0.30"
|
|||
pathdiff = "0.2.1"
|
||||
relative-path = { version = "1.9.3", features = ["serde"] }
|
||||
log = "0.4.22"
|
||||
thiserror = "1.0.62"
|
||||
thiserror = "1.0.63"
|
||||
threadpool = "1.8.1"
|
||||
full_moon = { version = "1.0.0-rc.5", features = ["luau"] }
|
||||
url = { version = "2.5.2", features = ["serde"] }
|
||||
cfg-if = "1.0.0"
|
||||
once_cell = "1.19.0"
|
||||
secrecy = "0.8.0"
|
||||
# TODO: reevaluate whether to use this
|
||||
# secrecy = "0.8.0"
|
||||
chrono = { version = "0.4.38", features = ["serde"] }
|
||||
|
||||
toml = { version = "0.8.14", optional = true }
|
||||
zip = { version = "2.1.3", optional = true }
|
||||
toml = { version = "0.8.15", optional = true }
|
||||
zip = { version = "2.1.5", optional = true }
|
||||
|
||||
anyhow = { version = "1.0.86", optional = true }
|
||||
open = { version = "5.3.0", optional = true }
|
||||
keyring = { version = "3.0.1", features = ["crypto-rust", "windows-native", "apple-native", "linux-native"], optional = true }
|
||||
keyring = { version = "3.0.3", features = ["crypto-rust", "windows-native", "apple-native", "linux-native"], optional = true }
|
||||
colored = { version = "2.1.0", optional = true }
|
||||
nondestructive = { version = "0.0.25", optional = true }
|
||||
clap = { version = "4.5.9", features = ["derive"], optional = true }
|
||||
directories = { version = "5.0.1", optional = true }
|
||||
ignore = { version = "0.4.22", optional = true }
|
||||
pretty_env_logger = { version = "0.5.0", optional = true }
|
||||
indicatif = { version = "0.17.8", optional = true }
|
||||
indicatif-log-bridge = { version = "0.2.2", optional = true }
|
||||
|
|
|
@ -15,6 +15,10 @@ pub struct LoginCommand {
|
|||
/// The index to use. Defaults to `default`, or the configured default index if current directory doesn't have a manifest
|
||||
#[arg(short, long)]
|
||||
index: Option<String>,
|
||||
|
||||
/// The token to use for authentication, skipping login
|
||||
#[arg(short, long, conflicts_with = "index")]
|
||||
token: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
|
@ -44,7 +48,11 @@ enum AccessTokenResponse {
|
|||
}
|
||||
|
||||
impl LoginCommand {
|
||||
pub fn run(self, project: Project) -> anyhow::Result<()> {
|
||||
pub fn authenticate_device_flow(
|
||||
&self,
|
||||
project: &Project,
|
||||
reqwest: &reqwest::blocking::Client,
|
||||
) -> anyhow::Result<String> {
|
||||
let manifest = match project.deser_manifest() {
|
||||
Ok(manifest) => Some(manifest),
|
||||
Err(e) => match e {
|
||||
|
@ -82,18 +90,13 @@ impl LoginCommand {
|
|||
.try_into()
|
||||
.context("cannot parse URL to git URL")?,
|
||||
);
|
||||
source
|
||||
.refresh(&project)
|
||||
.context("failed to refresh index")?;
|
||||
|
||||
dbg!(source.all_packages(&project).unwrap());
|
||||
source.refresh(project).context("failed to refresh index")?;
|
||||
|
||||
let config = source
|
||||
.config(&project)
|
||||
.config(project)
|
||||
.context("failed to read index config")?;
|
||||
let client_id = config.github_oauth_client_id;
|
||||
|
||||
let reqwest = reqwest_client(project.data_dir())?;
|
||||
let response = reqwest
|
||||
.post(Url::parse_with_params(
|
||||
"https://github.com/login/device/code",
|
||||
|
@ -150,13 +153,7 @@ impl LoginCommand {
|
|||
|
||||
match response {
|
||||
AccessTokenResponse::Success { access_token } => {
|
||||
set_token(project.data_dir(), Some(&access_token))?;
|
||||
|
||||
println!(
|
||||
"logged in as {}",
|
||||
get_token_login(&reqwest, &access_token)?.bold()
|
||||
);
|
||||
return Ok(());
|
||||
return Ok(access_token);
|
||||
}
|
||||
AccessTokenResponse::Error(e) => match e {
|
||||
AccessTokenError::AuthorizationPending => continue,
|
||||
|
@ -178,4 +175,19 @@ impl LoginCommand {
|
|||
|
||||
anyhow::bail!("code expired, please re-run the login command");
|
||||
}
|
||||
|
||||
pub fn run(self, project: Project) -> anyhow::Result<()> {
|
||||
let reqwest = reqwest_client(project.data_dir())?;
|
||||
|
||||
let token = match self.token {
|
||||
Some(token) => token,
|
||||
None => self.authenticate_device_flow(&project, &reqwest)?,
|
||||
};
|
||||
|
||||
println!("logged in as {}", get_token_login(&reqwest, &token)?.bold());
|
||||
|
||||
set_token(project.data_dir(), Some(&token))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ impl DefaultIndexCommand {
|
|||
Some(index) => {
|
||||
config.default_index = index.clone();
|
||||
write_config(project.data_dir(), &config)?;
|
||||
println!("default index set to: {}", index);
|
||||
println!("default index set to: {index}");
|
||||
}
|
||||
None => {
|
||||
println!("current default index: {}", config.default_index);
|
||||
|
|
|
@ -2,17 +2,22 @@ use clap::Subcommand;
|
|||
use pesde::Project;
|
||||
|
||||
mod default_index;
|
||||
mod scripts_repo;
|
||||
|
||||
#[derive(Debug, Subcommand)]
|
||||
pub enum ConfigCommands {
|
||||
/// Configuration for the default index
|
||||
DefaultIndex(default_index::DefaultIndexCommand),
|
||||
|
||||
/// Configuration for the scripts repository
|
||||
ScriptsRepo(scripts_repo::ScriptsRepoCommand),
|
||||
}
|
||||
|
||||
impl ConfigCommands {
|
||||
pub fn run(self, project: Project) -> anyhow::Result<()> {
|
||||
match self {
|
||||
ConfigCommands::DefaultIndex(default_index) => default_index.run(project),
|
||||
ConfigCommands::ScriptsRepo(scripts_repo) => scripts_repo.run(project),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
39
src/cli/config/scripts_repo.rs
Normal file
39
src/cli/config/scripts_repo.rs
Normal file
|
@ -0,0 +1,39 @@
|
|||
use crate::cli::{read_config, write_config, CliConfig};
|
||||
use clap::Args;
|
||||
use pesde::Project;
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
pub struct ScriptsRepoCommand {
|
||||
/// The new repo URL to set as default, don't pass any value to check the current default repo
|
||||
#[arg(index = 1)]
|
||||
repo: Option<url::Url>,
|
||||
|
||||
/// Resets the default repo to the default value
|
||||
#[arg(short, long, conflicts_with = "repo")]
|
||||
reset: bool,
|
||||
}
|
||||
|
||||
impl ScriptsRepoCommand {
|
||||
pub fn run(self, project: Project) -> anyhow::Result<()> {
|
||||
let mut config = read_config(project.data_dir())?;
|
||||
|
||||
let repo = if self.reset {
|
||||
Some(CliConfig::default().scripts_repo)
|
||||
} else {
|
||||
self.repo
|
||||
};
|
||||
|
||||
match repo {
|
||||
Some(repo) => {
|
||||
config.scripts_repo = repo.clone();
|
||||
write_config(project.data_dir(), &config)?;
|
||||
println!("scripts repo set to: {repo}");
|
||||
}
|
||||
None => {
|
||||
println!("current scripts repo: {}", config.scripts_repo);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -1,13 +1,32 @@
|
|||
use crate::cli::read_config;
|
||||
use anyhow::Context;
|
||||
use clap::Args;
|
||||
use colored::Colorize;
|
||||
use inquire::validator::Validation;
|
||||
use pesde::{errors::ManifestReadError, names::PackageName, Project, DEFAULT_INDEX_NAME};
|
||||
use std::str::FromStr;
|
||||
use pesde::{
|
||||
errors::ManifestReadError, manifest::ScriptName, names::PackageName, Project,
|
||||
DEFAULT_INDEX_NAME,
|
||||
};
|
||||
use std::{path::Path, str::FromStr};
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
pub struct InitCommand {}
|
||||
|
||||
fn script_contents(path: &Path) -> String {
|
||||
format!(
|
||||
concat!(
|
||||
r#"local process = require("@lune/process")
|
||||
local home_dir = if process.os == "windows" then process.env.userprofile else process.env.HOME
|
||||
|
||||
require(home_dir .. ""#,
|
||||
"/.",
|
||||
env!("CARGO_PKG_NAME"),
|
||||
r#"/scripts/{}")"#,
|
||||
),
|
||||
path.display()
|
||||
)
|
||||
}
|
||||
|
||||
impl InitCommand {
|
||||
pub fn run(self, project: Project) -> anyhow::Result<()> {
|
||||
match project.read_manifest() {
|
||||
|
@ -94,6 +113,57 @@ impl InitCommand {
|
|||
mapping.insert_str("license", license);
|
||||
}
|
||||
|
||||
let target_env = inquire::Select::new(
|
||||
"What environment are you targeting for your package?",
|
||||
vec![
|
||||
#[cfg(feature = "roblox")]
|
||||
"roblox",
|
||||
#[cfg(feature = "lune")]
|
||||
"lune",
|
||||
#[cfg(feature = "luau")]
|
||||
"luau",
|
||||
],
|
||||
)
|
||||
.prompt()
|
||||
.unwrap();
|
||||
|
||||
let mut target = mapping
|
||||
.insert("target", nondestructive::yaml::Separator::Auto)
|
||||
.make_mapping();
|
||||
target.insert_str("environment", target_env);
|
||||
|
||||
if target_env == "roblox"
|
||||
|| inquire::Confirm::new(&format!(
|
||||
"Would you like to setup a default {} script?",
|
||||
ScriptName::RobloxSyncConfigGenerator
|
||||
))
|
||||
.prompt()
|
||||
.unwrap()
|
||||
{
|
||||
let folder = project.path().join(concat!(".", env!("CARGO_PKG_NAME")));
|
||||
std::fs::create_dir_all(&folder).context("failed to create scripts folder")?;
|
||||
|
||||
std::fs::write(
|
||||
folder.join(format!("{}.luau", ScriptName::RobloxSyncConfigGenerator)),
|
||||
script_contents(Path::new(&format!(
|
||||
"lune/rojo/{}.luau",
|
||||
ScriptName::RobloxSyncConfigGenerator
|
||||
))),
|
||||
)
|
||||
.context("failed to write script file")?;
|
||||
|
||||
mapping
|
||||
.insert("scripts", nondestructive::yaml::Separator::Auto)
|
||||
.make_mapping()
|
||||
.insert_str(
|
||||
ScriptName::RobloxSyncConfigGenerator.to_string(),
|
||||
format!(
|
||||
concat!(concat!(".", env!("CARGO_PKG_NAME")), "/{}.luau"),
|
||||
ScriptName::RobloxSyncConfigGenerator
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
let mut indices = mapping
|
||||
.insert("indices", nondestructive::yaml::Separator::Auto)
|
||||
.make_mapping();
|
||||
|
|
153
src/cli/mod.rs
153
src/cli/mod.rs
|
@ -1,18 +1,23 @@
|
|||
use crate::git::authenticate_conn;
|
||||
use anyhow::Context;
|
||||
use gix::remote::Direction;
|
||||
use keyring::Entry;
|
||||
use pesde::Project;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::Path;
|
||||
use std::{collections::HashSet, path::Path};
|
||||
|
||||
mod auth;
|
||||
mod config;
|
||||
mod init;
|
||||
mod install;
|
||||
mod publish;
|
||||
mod run;
|
||||
mod self_install;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct CliConfig {
|
||||
pub default_index: url::Url,
|
||||
pub scripts_repo: url::Url,
|
||||
pub token: Option<String>,
|
||||
}
|
||||
|
||||
|
@ -20,6 +25,9 @@ impl Default for CliConfig {
|
|||
fn default() -> Self {
|
||||
Self {
|
||||
default_index: "https://github.com/daimond113/pesde-index".parse().unwrap(),
|
||||
scripts_repo: "https://github.com/daimond113/pesde-scripts"
|
||||
.parse()
|
||||
.unwrap(),
|
||||
token: None,
|
||||
}
|
||||
}
|
||||
|
@ -102,7 +110,7 @@ pub fn reqwest_client(data_dir: &Path) -> anyhow::Result<reqwest::blocking::Clie
|
|||
if let Some(token) = get_token(data_dir)? {
|
||||
headers.insert(
|
||||
reqwest::header::AUTHORIZATION,
|
||||
format!("Bearer {}", token)
|
||||
format!("Bearer {token}")
|
||||
.parse()
|
||||
.context("failed to create auth header")?,
|
||||
);
|
||||
|
@ -125,6 +133,139 @@ pub fn reqwest_client(data_dir: &Path) -> anyhow::Result<reqwest::blocking::Clie
|
|||
.build()?)
|
||||
}
|
||||
|
||||
pub fn update_scripts_folder(project: &Project) -> anyhow::Result<()> {
|
||||
let home_dir = directories::UserDirs::new()
|
||||
.context("failed to get home directory")?
|
||||
.home_dir()
|
||||
.to_owned();
|
||||
|
||||
let scripts_dir = home_dir
|
||||
.join(concat!(".", env!("CARGO_PKG_NAME")))
|
||||
.join("scripts");
|
||||
|
||||
if scripts_dir.exists() {
|
||||
let repo = gix::open(&scripts_dir).context("failed to open scripts repository")?;
|
||||
|
||||
let remote = repo
|
||||
.find_default_remote(Direction::Fetch)
|
||||
.context("missing default remote of scripts repository")?
|
||||
.context("failed to find default remote of scripts repository")?;
|
||||
|
||||
let mut connection = remote
|
||||
.connect(Direction::Fetch)
|
||||
.context("failed to connect to default remote of scripts repository")?;
|
||||
|
||||
authenticate_conn(&mut connection, project.auth_config());
|
||||
|
||||
let results = connection
|
||||
.prepare_fetch(gix::progress::Discard, Default::default())
|
||||
.context("failed to prepare scripts repository fetch")?
|
||||
.receive(gix::progress::Discard, &false.into())
|
||||
.context("failed to receive new scripts repository contents")?;
|
||||
|
||||
let remote_ref = results
|
||||
.ref_map
|
||||
.remote_refs
|
||||
.first()
|
||||
.context("failed to get remote refs of scripts repository")?;
|
||||
|
||||
let unpacked = remote_ref.unpack();
|
||||
let oid = unpacked
|
||||
.1
|
||||
.or(unpacked.2)
|
||||
.context("couldn't find oid in remote ref")?;
|
||||
|
||||
let tree = repo
|
||||
.find_object(oid)
|
||||
.context("failed to find scripts repository tree")?
|
||||
.peel_to_tree()
|
||||
.context("failed to peel scripts repository object to tree")?;
|
||||
|
||||
let mut index = gix::index::File::from_state(
|
||||
gix::index::State::from_tree(&tree.id, &repo.objects, Default::default())
|
||||
.context("failed to create index state from scripts repository tree")?,
|
||||
repo.index_path(),
|
||||
);
|
||||
|
||||
let opts = gix::worktree::state::checkout::Options {
|
||||
overwrite_existing: true,
|
||||
destination_is_initially_empty: false,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
gix::worktree::state::checkout(
|
||||
&mut index,
|
||||
repo.work_dir().context("scripts repo is bare")?,
|
||||
repo.objects
|
||||
.clone()
|
||||
.into_arc()
|
||||
.context("failed to clone objects")?,
|
||||
&gix::progress::Discard,
|
||||
&gix::progress::Discard,
|
||||
&false.into(),
|
||||
opts,
|
||||
)
|
||||
.context("failed to checkout scripts repository")?;
|
||||
|
||||
index
|
||||
.write(gix::index::write::Options::default())
|
||||
.context("failed to write index")?;
|
||||
} else {
|
||||
std::fs::create_dir_all(&scripts_dir).context("failed to create scripts directory")?;
|
||||
|
||||
let cli_config = read_config(project.data_dir())?;
|
||||
|
||||
gix::prepare_clone(cli_config.scripts_repo.as_str(), &scripts_dir)
|
||||
.context("failed to prepare scripts repository clone")?
|
||||
.fetch_then_checkout(gix::progress::Discard, &false.into())
|
||||
.context("failed to fetch and checkout scripts repository")?
|
||||
.0
|
||||
.main_worktree(gix::progress::Discard, &false.into())
|
||||
.context("failed to set scripts repository as main worktree")?;
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub trait IsUpToDate {
|
||||
fn is_up_to_date(&self) -> anyhow::Result<bool>;
|
||||
}
|
||||
|
||||
impl IsUpToDate for Project {
|
||||
fn is_up_to_date(&self) -> anyhow::Result<bool> {
|
||||
let manifest = self.deser_manifest()?;
|
||||
let lockfile = match self.deser_lockfile() {
|
||||
Ok(lockfile) => lockfile,
|
||||
Err(pesde::errors::LockfileReadError::Io(e))
|
||||
if e.kind() == std::io::ErrorKind::NotFound =>
|
||||
{
|
||||
return Ok(false);
|
||||
}
|
||||
Err(e) => return Err(e.into()),
|
||||
};
|
||||
|
||||
if manifest.name != lockfile.name || manifest.version != lockfile.version {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
let specs = lockfile
|
||||
.graph
|
||||
.into_iter()
|
||||
.flat_map(|(_, versions)| versions)
|
||||
.filter_map(|(_, node)| match node.node.direct {
|
||||
Some((_, spec)) => Some((spec, node.node.ty)),
|
||||
None => None,
|
||||
})
|
||||
.collect::<HashSet<_>>();
|
||||
|
||||
Ok(!manifest
|
||||
.all_dependencies()
|
||||
.context("failed to get all dependencies")?
|
||||
.iter()
|
||||
.all(|(_, (spec, ty))| specs.contains(&(spec.clone(), *ty))))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, clap::Subcommand)]
|
||||
pub enum Subcommand {
|
||||
/// Authentication-related commands
|
||||
|
@ -143,6 +284,12 @@ pub enum Subcommand {
|
|||
|
||||
/// Installs all dependencies for the project
|
||||
Install(install::InstallCommand),
|
||||
|
||||
/// Publishes the project to the registry
|
||||
Publish(publish::PublishCommand),
|
||||
|
||||
/// Installs the pesde binary and scripts
|
||||
SelfInstall(self_install::SelfInstallCommand),
|
||||
}
|
||||
|
||||
impl Subcommand {
|
||||
|
@ -153,6 +300,8 @@ impl Subcommand {
|
|||
Subcommand::Init(init) => init.run(project),
|
||||
Subcommand::Run(run) => run.run(project),
|
||||
Subcommand::Install(install) => install.run(project),
|
||||
Subcommand::Publish(publish) => publish.run(project),
|
||||
Subcommand::SelfInstall(self_install) => self_install.run(project),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
289
src/cli/publish.rs
Normal file
289
src/cli/publish.rs
Normal file
|
@ -0,0 +1,289 @@
|
|||
use anyhow::Context;
|
||||
use clap::Args;
|
||||
use colored::Colorize;
|
||||
use pesde::{manifest::Target, Project, MANIFEST_FILE_NAME, MAX_ARCHIVE_SIZE};
|
||||
use std::{io::Seek, path::Component};
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
pub struct PublishCommand {
|
||||
/// Whether to output a tarball instead of publishing
|
||||
#[arg(short, long)]
|
||||
dry_run: bool,
|
||||
}
|
||||
|
||||
impl PublishCommand {
|
||||
pub fn run(self, project: Project) -> anyhow::Result<()> {
|
||||
let mut manifest = project
|
||||
.deser_manifest()
|
||||
.context("failed to read manifest")?;
|
||||
|
||||
if manifest.private {
|
||||
println!("{}", "package is private, cannot publish".red().bold());
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
manifest
|
||||
.target
|
||||
.validate_publish()
|
||||
.context("manifest not fit for publishing")?;
|
||||
|
||||
let mut archive = tar::Builder::new(flate2::write::GzEncoder::new(
|
||||
vec![],
|
||||
flate2::Compression::best(),
|
||||
));
|
||||
|
||||
let mut display_includes: Vec<String> = vec![MANIFEST_FILE_NAME.to_string()];
|
||||
#[cfg(feature = "roblox")]
|
||||
let mut display_build_files: Vec<String> = vec![];
|
||||
|
||||
let (lib_path, bin_path) = (
|
||||
manifest.target.lib_path().cloned(),
|
||||
manifest.target.bin_path().cloned(),
|
||||
);
|
||||
|
||||
#[cfg(feature = "roblox")]
|
||||
let mut roblox_target = match &mut manifest.target {
|
||||
Target::Roblox { build_files, .. } => Some(build_files),
|
||||
_ => None,
|
||||
};
|
||||
#[cfg(not(feature = "roblox"))]
|
||||
let roblox_target = None::<()>;
|
||||
|
||||
if !manifest.includes.insert(MANIFEST_FILE_NAME.to_string()) {
|
||||
display_includes.push(MANIFEST_FILE_NAME.to_string());
|
||||
|
||||
println!(
|
||||
"{}: {MANIFEST_FILE_NAME} was not in includes, adding it",
|
||||
"warn".yellow().bold()
|
||||
);
|
||||
}
|
||||
|
||||
for (name, path) in [("lib path", lib_path), ("bin path", bin_path)] {
|
||||
let Some(export_path) = path else { continue };
|
||||
|
||||
let export_path = export_path.to_path(project.path());
|
||||
if !export_path.exists() {
|
||||
anyhow::bail!("{name} points to non-existent file");
|
||||
}
|
||||
|
||||
if !export_path.is_file() {
|
||||
anyhow::bail!("{name} must point to a file");
|
||||
}
|
||||
|
||||
let contents =
|
||||
std::fs::read_to_string(&export_path).context(format!("failed to read {name}"))?;
|
||||
|
||||
if let Err(err) = full_moon::parse(&contents).map_err(|errs| {
|
||||
errs.into_iter()
|
||||
.map(|err| err.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
}) {
|
||||
anyhow::bail!("{name} is not a valid Luau file: {err}");
|
||||
}
|
||||
|
||||
let first_part = export_path
|
||||
.strip_prefix(project.path())
|
||||
.context(format!("{name} not within project directory"))?
|
||||
.components()
|
||||
.next()
|
||||
.context(format!("{name} must contain at least one part"))?;
|
||||
|
||||
let first_part = match first_part {
|
||||
Component::Normal(part) => part,
|
||||
_ => anyhow::bail!("{name} must be within project directory"),
|
||||
};
|
||||
|
||||
let first_part_str = first_part.to_string_lossy();
|
||||
|
||||
if manifest.includes.insert(first_part_str.to_string()) {
|
||||
println!(
|
||||
"{}: {name} was not in includes, adding {first_part_str}",
|
||||
"warn".yellow().bold()
|
||||
);
|
||||
}
|
||||
|
||||
if roblox_target.as_mut().map_or(false, |build_files| {
|
||||
build_files.insert(first_part_str.to_string())
|
||||
}) {
|
||||
println!(
|
||||
"{}: {name} was not in build files, adding {first_part_str}",
|
||||
"warn".yellow().bold()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for included_name in &manifest.includes {
|
||||
let included_path = project.path().join(included_name);
|
||||
|
||||
if !included_path.exists() {
|
||||
anyhow::bail!("included file {included_name} does not exist");
|
||||
}
|
||||
|
||||
// it'll be included later, with our mut modifications
|
||||
if included_name.eq_ignore_ascii_case(MANIFEST_FILE_NAME) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if included_path.is_file() {
|
||||
display_includes.push(included_name.clone());
|
||||
|
||||
archive.append_file(
|
||||
included_name,
|
||||
&mut std::fs::File::open(&included_path)
|
||||
.context(format!("failed to read {included_name}"))?,
|
||||
)?;
|
||||
} else {
|
||||
display_includes.push(format!("{included_name}/*"));
|
||||
|
||||
archive
|
||||
.append_dir_all(included_name, &included_path)
|
||||
.context(format!("failed to include directory {included_name}"))?;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(build_files) = &roblox_target {
|
||||
for build_file in build_files.iter() {
|
||||
if build_file.eq_ignore_ascii_case(MANIFEST_FILE_NAME) {
|
||||
println!(
|
||||
"{}: {MANIFEST_FILE_NAME} is in build files, please remove it",
|
||||
"warn".yellow().bold()
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
let build_file_path = project.path().join(build_file);
|
||||
|
||||
if !build_file_path.exists() {
|
||||
anyhow::bail!("build file {build_file} does not exist");
|
||||
}
|
||||
|
||||
if !manifest.includes.contains(build_file) {
|
||||
anyhow::bail!("build file {build_file} is not in includes, please add it");
|
||||
}
|
||||
|
||||
if build_file_path.is_file() {
|
||||
display_build_files.push(build_file.clone());
|
||||
} else {
|
||||
display_build_files.push(format!("{build_file}/*"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
println!("\n{}", "please confirm the following information:".bold());
|
||||
println!("name: {}", manifest.name);
|
||||
println!("version: {}", manifest.version);
|
||||
println!(
|
||||
"description: {}",
|
||||
manifest.description.as_deref().unwrap_or("(none)")
|
||||
);
|
||||
println!(
|
||||
"license: {}",
|
||||
manifest.license.as_deref().unwrap_or("(none)")
|
||||
);
|
||||
println!(
|
||||
"authors: {}",
|
||||
manifest
|
||||
.authors
|
||||
.as_ref()
|
||||
.map_or("(none)".to_string(), |a| a.join(", "))
|
||||
);
|
||||
println!(
|
||||
"repository: {}",
|
||||
manifest.repository.as_deref().unwrap_or("(none)")
|
||||
);
|
||||
|
||||
let roblox_target = roblox_target.is_some_and(|_| true);
|
||||
|
||||
println!("target: {}", manifest.target);
|
||||
println!(
|
||||
"\tlib path: {}",
|
||||
manifest
|
||||
.target
|
||||
.lib_path()
|
||||
.map_or("(none)".to_string(), |p| p.to_string())
|
||||
);
|
||||
|
||||
match roblox_target {
|
||||
#[cfg(feature = "roblox")]
|
||||
true => {
|
||||
println!("\tbuild files: {}", display_build_files.join(", "));
|
||||
}
|
||||
_ => {
|
||||
println!(
|
||||
"\tbin path: {}",
|
||||
manifest
|
||||
.target
|
||||
.bin_path()
|
||||
.map_or("(none)".to_string(), |p| p.to_string())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
println!(
|
||||
"includes: {}",
|
||||
display_includes.into_iter().collect::<Vec<_>>().join(", ")
|
||||
);
|
||||
|
||||
if !self.dry_run && !inquire::Confirm::new("is this information correct?").prompt()? {
|
||||
println!("{}", "publish aborted".red().bold());
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
let temp_manifest_path = project
|
||||
.data_dir()
|
||||
.join(format!("temp_manifest_{}", chrono::Utc::now().timestamp()));
|
||||
|
||||
let mut temp_manifest = std::fs::File::options()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.create(true)
|
||||
.truncate(true)
|
||||
.open(&temp_manifest_path)
|
||||
.context("failed to create temp manifest file")?;
|
||||
|
||||
serde_yaml::to_writer(&mut temp_manifest, &manifest)
|
||||
.context("failed to write temp manifest file")?;
|
||||
temp_manifest
|
||||
.rewind()
|
||||
.context("failed to rewind temp manifest file")?;
|
||||
|
||||
archive.append_file(MANIFEST_FILE_NAME, &mut temp_manifest)?;
|
||||
|
||||
drop(temp_manifest);
|
||||
|
||||
std::fs::remove_file(temp_manifest_path)?;
|
||||
|
||||
let archive = archive
|
||||
.into_inner()
|
||||
.context("failed to encode archive")?
|
||||
.finish()
|
||||
.context("failed to get archive bytes")?;
|
||||
|
||||
if archive.len() > MAX_ARCHIVE_SIZE {
|
||||
anyhow::bail!(
|
||||
"archive size exceeds maximum size of {} bytes by {} bytes",
|
||||
MAX_ARCHIVE_SIZE,
|
||||
archive.len() - MAX_ARCHIVE_SIZE
|
||||
);
|
||||
}
|
||||
|
||||
if self.dry_run {
|
||||
std::fs::write("package.tar.gz", archive)?;
|
||||
|
||||
println!(
|
||||
"{}",
|
||||
"(dry run) package written to package.tar.gz".green().bold()
|
||||
);
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
todo!("publishing to registry");
|
||||
}
|
||||
}
|
|
@ -1,9 +1,10 @@
|
|||
use crate::cli::IsUpToDate;
|
||||
use anyhow::Context;
|
||||
use clap::Args;
|
||||
use pesde::{
|
||||
names::PackageName,
|
||||
scripts::{execute_lune_script, execute_script},
|
||||
Project,
|
||||
names::{PackageName, PackageNames},
|
||||
scripts::execute_script,
|
||||
Project, PACKAGES_CONTAINER_NAME,
|
||||
};
|
||||
use relative_path::RelativePathBuf;
|
||||
|
||||
|
@ -20,14 +21,59 @@ pub struct RunCommand {
|
|||
|
||||
impl RunCommand {
|
||||
pub fn run(self, project: Project) -> anyhow::Result<()> {
|
||||
if let Ok(_pkg_name) = self.package_or_script.parse::<PackageName>() {
|
||||
todo!("implement binary package execution")
|
||||
if let Ok(pkg_name) = self.package_or_script.parse::<PackageName>() {
|
||||
let graph = if project.is_up_to_date()? {
|
||||
project.deser_lockfile()?.graph
|
||||
} else {
|
||||
anyhow::bail!("outdated lockfile, please run the install command first")
|
||||
};
|
||||
|
||||
let pkg_name = PackageNames::Pesde(pkg_name);
|
||||
|
||||
for (version, node) in graph.get(&pkg_name).context("package not found in graph")? {
|
||||
if node.node.direct.is_none() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let Some(bin_path) = node.target.bin_path() else {
|
||||
anyhow::bail!("package has no bin path");
|
||||
};
|
||||
|
||||
let base_folder = node
|
||||
.node
|
||||
.base_folder(project.deser_manifest()?.target.kind(), true);
|
||||
let container_folder = node.node.container_folder(
|
||||
&project
|
||||
.path()
|
||||
.join(base_folder)
|
||||
.join(PACKAGES_CONTAINER_NAME),
|
||||
&pkg_name,
|
||||
version,
|
||||
);
|
||||
|
||||
let path = bin_path.to_path(&container_folder);
|
||||
|
||||
execute_script(
|
||||
Some(pkg_name.as_str().1),
|
||||
&path,
|
||||
&self.args,
|
||||
project.path(),
|
||||
false,
|
||||
)
|
||||
.context("failed to execute script")?;
|
||||
}
|
||||
}
|
||||
|
||||
if let Ok(manifest) = project.deser_manifest() {
|
||||
if manifest.scripts.contains_key(&self.package_or_script) {
|
||||
execute_script(&manifest, &self.package_or_script, &self.args)
|
||||
.context("failed to execute script")?;
|
||||
if let Some(script_path) = manifest.scripts.get(&self.package_or_script) {
|
||||
execute_script(
|
||||
Some(&self.package_or_script),
|
||||
&script_path.to_path(project.path()),
|
||||
&self.args,
|
||||
project.path(),
|
||||
false,
|
||||
)
|
||||
.context("failed to execute script")?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -40,7 +86,7 @@ impl RunCommand {
|
|||
anyhow::bail!("path does not exist: {}", path.display());
|
||||
}
|
||||
|
||||
execute_lune_script(None, &relative_path, &self.args)
|
||||
execute_script(None, &path, &self.args, project.path(), false)
|
||||
.context("failed to execute script")?;
|
||||
|
||||
Ok(())
|
||||
|
|
14
src/cli/self_install.rs
Normal file
14
src/cli/self_install.rs
Normal file
|
@ -0,0 +1,14 @@
|
|||
use crate::cli::update_scripts_folder;
|
||||
use clap::Args;
|
||||
use pesde::Project;
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
pub struct SelfInstallCommand {}
|
||||
|
||||
impl SelfInstallCommand {
|
||||
pub fn run(self, project: Project) -> anyhow::Result<()> {
|
||||
update_scripts_folder(&project)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ use crate::{
|
|||
};
|
||||
|
||||
impl Project {
|
||||
// TODO: use threadpool for concurrent downloads
|
||||
pub fn download_graph(
|
||||
&self,
|
||||
graph: &DependencyGraph,
|
||||
|
|
23
src/git.rs
Normal file
23
src/git.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
use crate::AuthConfig;
|
||||
|
||||
pub fn authenticate_conn(
|
||||
conn: &mut gix::remote::Connection<
|
||||
'_,
|
||||
'_,
|
||||
Box<dyn gix::protocol::transport::client::Transport + Send>,
|
||||
>,
|
||||
auth_config: &AuthConfig,
|
||||
) {
|
||||
if let Some(iden) = auth_config.git_credentials().cloned() {
|
||||
conn.set_credentials(move |action| match action {
|
||||
gix::credentials::helper::Action::Get(ctx) => {
|
||||
Ok(Some(gix::credentials::protocol::Outcome {
|
||||
identity: iden.clone(),
|
||||
next: gix::credentials::helper::NextAction::from(ctx),
|
||||
}))
|
||||
}
|
||||
gix::credentials::helper::Action::Store(_) => Ok(None),
|
||||
gix::credentials::helper::Action::Erase(_) => Ok(None),
|
||||
});
|
||||
}
|
||||
}
|
82
src/lib.rs
82
src/lib.rs
|
@ -8,6 +8,7 @@ use once_cell::sync::Lazy;
|
|||
use std::path::{Path, PathBuf};
|
||||
|
||||
pub mod download;
|
||||
mod git;
|
||||
pub mod linking;
|
||||
pub mod lockfile;
|
||||
pub mod manifest;
|
||||
|
@ -20,6 +21,7 @@ pub const MANIFEST_FILE_NAME: &str = "pesde.yaml";
|
|||
pub const LOCKFILE_FILE_NAME: &str = "pesde.lock";
|
||||
pub const DEFAULT_INDEX_NAME: &str = "default";
|
||||
pub const PACKAGES_CONTAINER_NAME: &str = ".pesde";
|
||||
pub const MAX_ARCHIVE_SIZE: usize = 4 * 1024 * 1024;
|
||||
|
||||
pub(crate) static REQWEST_CLIENT: Lazy<reqwest::blocking::Client> = Lazy::new(|| {
|
||||
reqwest::blocking::Client::builder()
|
||||
|
@ -32,43 +34,10 @@ pub(crate) static REQWEST_CLIENT: Lazy<reqwest::blocking::Client> = Lazy::new(||
|
|||
.expect("failed to create reqwest client")
|
||||
});
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct GitAccount {
|
||||
username: String,
|
||||
password: secrecy::SecretString,
|
||||
}
|
||||
|
||||
impl GitAccount {
|
||||
pub fn new<S: Into<secrecy::SecretString>>(username: String, password: S) -> Self {
|
||||
GitAccount {
|
||||
username,
|
||||
password: password.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_account(&self) -> gix::sec::identity::Account {
|
||||
use secrecy::ExposeSecret;
|
||||
|
||||
gix::sec::identity::Account {
|
||||
username: self.username.clone(),
|
||||
password: self.password.expose_secret().to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<gix::sec::identity::Account> for GitAccount {
|
||||
fn from(account: gix::sec::identity::Account) -> Self {
|
||||
GitAccount {
|
||||
username: account.username,
|
||||
password: account.password.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct AuthConfig {
|
||||
pesde_token: Option<secrecy::SecretString>,
|
||||
git_credentials: Option<GitAccount>,
|
||||
pesde_token: Option<String>,
|
||||
git_credentials: Option<gix::sec::identity::Account>,
|
||||
}
|
||||
|
||||
impl AuthConfig {
|
||||
|
@ -76,39 +45,28 @@ impl AuthConfig {
|
|||
AuthConfig::default()
|
||||
}
|
||||
|
||||
pub fn with_pesde_token<S: Into<secrecy::SecretString>>(mut self, token: Option<S>) -> Self {
|
||||
self.pesde_token = token.map(Into::into);
|
||||
pub fn pesde_token(&self) -> Option<&str> {
|
||||
self.pesde_token.as_deref()
|
||||
}
|
||||
|
||||
pub fn git_credentials(&self) -> Option<&gix::sec::identity::Account> {
|
||||
self.git_credentials.as_ref()
|
||||
}
|
||||
|
||||
pub fn with_pesde_token<S: AsRef<str>>(mut self, token: Option<S>) -> Self {
|
||||
self.pesde_token = token.map(|s| s.as_ref().to_string());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_git_credentials(mut self, git_credentials: Option<GitAccount>) -> Self {
|
||||
pub fn with_git_credentials(
|
||||
mut self,
|
||||
git_credentials: Option<gix::sec::identity::Account>,
|
||||
) -> Self {
|
||||
self.git_credentials = git_credentials;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn authenticate_conn(
|
||||
conn: &mut gix::remote::Connection<
|
||||
'_,
|
||||
'_,
|
||||
Box<dyn gix::protocol::transport::client::Transport + Send>,
|
||||
>,
|
||||
auth_config: AuthConfig,
|
||||
) {
|
||||
if let Some(iden) = auth_config.git_credentials {
|
||||
conn.set_credentials(move |action| match action {
|
||||
gix::credentials::helper::Action::Get(ctx) => {
|
||||
Ok(Some(gix::credentials::protocol::Outcome {
|
||||
identity: iden.as_account(),
|
||||
next: gix::credentials::helper::NextAction::from(ctx),
|
||||
}))
|
||||
}
|
||||
gix::credentials::helper::Action::Store(_) => Ok(None),
|
||||
gix::credentials::helper::Action::Erase(_) => Ok(None),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Project {
|
||||
path: PathBuf,
|
||||
|
@ -137,6 +95,10 @@ impl Project {
|
|||
&self.data_dir
|
||||
}
|
||||
|
||||
pub fn auth_config(&self) -> &AuthConfig {
|
||||
&self.auth_config
|
||||
}
|
||||
|
||||
pub fn read_manifest(&self) -> Result<Vec<u8>, errors::ManifestReadError> {
|
||||
let bytes = std::fs::read(self.path.join(MANIFEST_FILE_NAME))?;
|
||||
Ok(bytes)
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
use crate::{
|
||||
linking::generator::get_file_types, lockfile::DownloadedGraph, manifest::Manifest,
|
||||
names::PackageNames, source::PackageRef, Project, MANIFEST_FILE_NAME, PACKAGES_CONTAINER_NAME,
|
||||
linking::generator::get_file_types,
|
||||
lockfile::DownloadedGraph,
|
||||
manifest::{Manifest, ScriptName, Target},
|
||||
names::PackageNames,
|
||||
scripts::execute_script,
|
||||
source::PackageRef,
|
||||
Project, MANIFEST_FILE_NAME, PACKAGES_CONTAINER_NAME,
|
||||
};
|
||||
use semver::Version;
|
||||
use std::{collections::BTreeMap, fs::create_dir_all};
|
||||
|
@ -34,7 +39,7 @@ impl Project {
|
|||
version,
|
||||
);
|
||||
|
||||
let lib_file = lib_file.to_path(container_folder);
|
||||
let lib_file = lib_file.to_path(&container_folder);
|
||||
|
||||
let contents = match std::fs::read_to_string(&lib_file) {
|
||||
Ok(contents) => contents,
|
||||
|
@ -60,6 +65,30 @@ impl Project {
|
|||
.entry(name)
|
||||
.or_default()
|
||||
.insert(version, types);
|
||||
|
||||
#[cfg(feature = "roblox")]
|
||||
if let Target::Roblox { build_files, .. } = &node.target {
|
||||
let script_name = ScriptName::RobloxSyncConfigGenerator.to_string();
|
||||
|
||||
let Some(script_path) = manifest.scripts.get(&script_name) else {
|
||||
log::warn!("not having a `{script_name}` script in the manifest might cause issues with Roblox linking");
|
||||
continue;
|
||||
};
|
||||
|
||||
execute_script(
|
||||
Some(&script_name),
|
||||
&script_path.to_path(self.path()),
|
||||
build_files,
|
||||
&container_folder,
|
||||
false,
|
||||
)
|
||||
.map_err(|e| {
|
||||
errors::LinkingError::GenerateRobloxSyncConfig(
|
||||
container_folder.display().to_string(),
|
||||
e,
|
||||
)
|
||||
})?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -173,5 +202,9 @@ pub mod errors {
|
|||
|
||||
#[error("error generating require path")]
|
||||
GetRequirePath(#[from] crate::linking::generator::errors::GetRequirePathError),
|
||||
|
||||
#[cfg(feature = "roblox")]
|
||||
#[error("error generating roblox sync config for {0}")]
|
||||
GenerateRobloxSyncConfig(String, #[source] std::io::Error),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,5 +91,5 @@ pub struct Lockfile {
|
|||
pub version: Version,
|
||||
pub overrides: BTreeMap<OverrideKey, DependencySpecifiers>,
|
||||
|
||||
pub graph: DependencyGraph,
|
||||
pub graph: DownloadedGraph,
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ use pesde::{AuthConfig, Project};
|
|||
use std::fs::create_dir_all;
|
||||
|
||||
mod cli;
|
||||
pub mod git;
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[clap(version, about = "pesde is a feature-rich package manager for Luau")]
|
||||
|
|
143
src/manifest.rs
143
src/manifest.rs
|
@ -1,15 +1,14 @@
|
|||
use crate::{names::PackageName, source::DependencySpecifiers};
|
||||
use relative_path::RelativePathBuf;
|
||||
use semver::Version;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_with::{DeserializeFromStr, SerializeDisplay};
|
||||
use std::{
|
||||
collections::BTreeMap,
|
||||
collections::{BTreeMap, BTreeSet},
|
||||
fmt::{Display, Formatter},
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
use crate::{names::PackageName, source::DependencySpecifiers};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
#[serde(rename_all = "snake_case", deny_unknown_fields)]
|
||||
pub enum TargetKind {
|
||||
|
@ -54,23 +53,32 @@ impl TargetKind {
|
|||
return "packages".to_string();
|
||||
}
|
||||
|
||||
format!("{}_packages", dependency)
|
||||
format!("{dependency}_packages")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
#[serde(rename_all = "snake_case", tag = "environment", remote = "Self")]
|
||||
#[serde(rename_all = "snake_case", tag = "environment")]
|
||||
pub enum Target {
|
||||
#[cfg(feature = "roblox")]
|
||||
Roblox { lib: RelativePathBuf },
|
||||
Roblox {
|
||||
#[serde(default)]
|
||||
lib: Option<RelativePathBuf>,
|
||||
#[serde(default)]
|
||||
build_files: BTreeSet<String>,
|
||||
},
|
||||
#[cfg(feature = "lune")]
|
||||
Lune {
|
||||
#[serde(default)]
|
||||
lib: Option<RelativePathBuf>,
|
||||
#[serde(default)]
|
||||
bin: Option<RelativePathBuf>,
|
||||
},
|
||||
#[cfg(feature = "luau")]
|
||||
Luau {
|
||||
#[serde(default)]
|
||||
lib: Option<RelativePathBuf>,
|
||||
#[serde(default)]
|
||||
bin: Option<RelativePathBuf>,
|
||||
},
|
||||
}
|
||||
|
@ -90,55 +98,47 @@ impl Target {
|
|||
pub fn lib_path(&self) -> Option<&RelativePathBuf> {
|
||||
match self {
|
||||
#[cfg(feature = "roblox")]
|
||||
Target::Roblox { lib } => Some(lib),
|
||||
Target::Roblox { lib, .. } => lib.as_ref(),
|
||||
#[cfg(feature = "lune")]
|
||||
Target::Lune { lib, .. } => lib.as_ref(),
|
||||
#[cfg(feature = "luau")]
|
||||
Target::Luau { lib, .. } => lib.as_ref(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for Target {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
Self::serialize(self, serializer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for Target {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let target = Self::deserialize(deserializer)?;
|
||||
|
||||
match &target {
|
||||
pub fn bin_path(&self) -> Option<&RelativePathBuf> {
|
||||
match self {
|
||||
#[cfg(feature = "roblox")]
|
||||
Target::Roblox { .. } => None,
|
||||
#[cfg(feature = "lune")]
|
||||
Target::Lune { lib, bin } => {
|
||||
if lib.is_none() && bin.is_none() {
|
||||
return Err(serde::de::Error::custom(
|
||||
"one of `lib` or `bin` exports must be defined",
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Target::Lune { bin, .. } => bin.as_ref(),
|
||||
#[cfg(feature = "luau")]
|
||||
Target::Luau { lib, bin } => {
|
||||
if lib.is_none() && bin.is_none() {
|
||||
return Err(serde::de::Error::custom(
|
||||
"one of `lib` or `bin` exports must be defined",
|
||||
));
|
||||
}
|
||||
}
|
||||
Target::Luau { bin, .. } => bin.as_ref(),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => {}
|
||||
pub fn validate_publish(&self) -> Result<(), errors::TargetValidatePublishError> {
|
||||
let has_exports = match self {
|
||||
#[cfg(feature = "roblox")]
|
||||
Target::Roblox { lib, .. } => lib.is_some(),
|
||||
#[cfg(feature = "lune")]
|
||||
Target::Lune { lib, bin } => lib.is_some() || bin.is_some(),
|
||||
#[cfg(feature = "luau")]
|
||||
Target::Luau { lib, bin } => lib.is_some() || bin.is_some(),
|
||||
};
|
||||
|
||||
Ok(target)
|
||||
if !has_exports {
|
||||
return Err(errors::TargetValidatePublishError::NoExportedFiles);
|
||||
}
|
||||
|
||||
match self {
|
||||
#[cfg(feature = "roblox")]
|
||||
Target::Roblox { build_files, .. } if build_files.is_empty() => {
|
||||
Err(errors::TargetValidatePublishError::NoBuildFiles)
|
||||
}
|
||||
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -190,39 +190,57 @@ impl Display for OverrideKey {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug, Clone)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
pub enum ScriptName {
|
||||
#[cfg(feature = "roblox")]
|
||||
RobloxSyncConfigGenerator,
|
||||
#[cfg(all(feature = "wally-compat", feature = "roblox"))]
|
||||
SourcemapGenerator,
|
||||
}
|
||||
|
||||
impl Display for ScriptName {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
#[cfg(feature = "roblox")]
|
||||
ScriptName::RobloxSyncConfigGenerator => write!(f, "roblox_sync_config_generator"),
|
||||
#[cfg(all(feature = "wally-compat", feature = "roblox"))]
|
||||
ScriptName::SourcemapGenerator => write!(f, "sourcemap_generator"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct Manifest {
|
||||
pub name: PackageName,
|
||||
pub version: Version,
|
||||
#[serde(default)]
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub description: Option<String>,
|
||||
#[serde(default)]
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub license: Option<String>,
|
||||
#[serde(default)]
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub authors: Option<Vec<String>>,
|
||||
#[serde(default)]
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub repository: Option<String>,
|
||||
pub target: Target,
|
||||
#[serde(default)]
|
||||
pub private: bool,
|
||||
#[serde(default)]
|
||||
#[serde(default, skip_serializing)]
|
||||
pub scripts: BTreeMap<String, RelativePathBuf>,
|
||||
#[serde(default)]
|
||||
pub indices: BTreeMap<String, url::Url>,
|
||||
#[cfg(feature = "wally-compat")]
|
||||
#[serde(default)]
|
||||
pub wally_indices: BTreeMap<String, url::Url>,
|
||||
#[cfg(all(feature = "wally-compat", feature = "roblox"))]
|
||||
#[serde(default)]
|
||||
pub sourcemap_generator: Option<String>,
|
||||
#[serde(default)]
|
||||
#[serde(default, skip_serializing)]
|
||||
pub overrides: BTreeMap<OverrideKey, DependencySpecifiers>,
|
||||
#[serde(default)]
|
||||
pub includes: BTreeSet<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
|
||||
pub dependencies: BTreeMap<String, DependencySpecifiers>,
|
||||
#[serde(default)]
|
||||
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
|
||||
pub peer_dependencies: BTreeMap<String, DependencySpecifiers>,
|
||||
#[serde(default)]
|
||||
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
|
||||
pub dev_dependencies: BTreeMap<String, DependencySpecifiers>,
|
||||
}
|
||||
|
||||
|
@ -275,4 +293,15 @@ pub mod errors {
|
|||
#[error("another specifier is already using the alias {0}")]
|
||||
AliasConflict(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
#[non_exhaustive]
|
||||
pub enum TargetValidatePublishError {
|
||||
#[error("no exported files specified")]
|
||||
NoExportedFiles,
|
||||
|
||||
#[cfg(feature = "roblox")]
|
||||
#[error("roblox target must have at least one build file")]
|
||||
NoBuildFiles,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,7 +91,7 @@ impl PackageNames {
|
|||
impl Display for PackageNames {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
PackageNames::Pesde(name) => write!(f, "{}", name),
|
||||
PackageNames::Pesde(name) => write!(f, "{name}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,21 +1,23 @@
|
|||
use crate::manifest::Manifest;
|
||||
use relative_path::RelativePathBuf;
|
||||
use std::{
|
||||
ffi::OsStr,
|
||||
io::{BufRead, BufReader},
|
||||
path::Path,
|
||||
process::{Command, Stdio},
|
||||
thread::spawn,
|
||||
};
|
||||
|
||||
pub fn execute_lune_script<A: IntoIterator<Item = S>, S: AsRef<OsStr>>(
|
||||
pub fn execute_script<A: IntoIterator<Item = S>, S: AsRef<OsStr>, P: AsRef<Path>>(
|
||||
script_name: Option<&str>,
|
||||
script_path: &RelativePathBuf,
|
||||
script_path: &Path,
|
||||
args: A,
|
||||
) -> Result<(), std::io::Error> {
|
||||
cwd: P,
|
||||
return_stdout: bool,
|
||||
) -> Result<Option<String>, std::io::Error> {
|
||||
match Command::new("lune")
|
||||
.arg("run")
|
||||
.arg(script_path.as_str())
|
||||
.arg(script_path.as_os_str())
|
||||
.args(args)
|
||||
.current_dir(cwd)
|
||||
.stdin(Stdio::null())
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
|
@ -27,7 +29,7 @@ pub fn execute_lune_script<A: IntoIterator<Item = S>, S: AsRef<OsStr>>(
|
|||
|
||||
let script = match script_name {
|
||||
Some(script) => script.to_string(),
|
||||
None => script_path.to_string(),
|
||||
None => script_path.to_string_lossy().to_string(),
|
||||
};
|
||||
|
||||
let script_2 = script.to_string();
|
||||
|
@ -46,10 +48,17 @@ pub fn execute_lune_script<A: IntoIterator<Item = S>, S: AsRef<OsStr>>(
|
|||
}
|
||||
});
|
||||
|
||||
let mut stdout_str = String::new();
|
||||
|
||||
for line in stdout.lines() {
|
||||
match line {
|
||||
Ok(line) => {
|
||||
log::info!("[{script_2}]: {line}");
|
||||
|
||||
if return_stdout {
|
||||
stdout_str.push_str(&line);
|
||||
stdout_str.push('\n');
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("ERROR IN READING STDOUT OF {script_2}: {e}");
|
||||
|
@ -57,24 +66,18 @@ pub fn execute_lune_script<A: IntoIterator<Item = S>, S: AsRef<OsStr>>(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if return_stdout {
|
||||
Ok(Some(stdout_str))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
|
||||
log::warn!("Lune could not be found in PATH: {e}")
|
||||
log::warn!("Lune could not be found in PATH: {e}");
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
Err(e) => return Err(e),
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn execute_script<A: IntoIterator<Item = S>, S: AsRef<OsStr>>(
|
||||
manifest: &Manifest,
|
||||
script: &str,
|
||||
args: A,
|
||||
) -> Result<(), std::io::Error> {
|
||||
if let Some(script_path) = manifest.scripts.get(script) {
|
||||
return execute_lune_script(Some(script), script_path, args);
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ impl DependencySpecifier for DependencySpecifiers {}
|
|||
impl Display for DependencySpecifiers {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
DependencySpecifiers::Pesde(specifier) => write!(f, "{}", specifier),
|
||||
DependencySpecifiers::Pesde(specifier) => write!(f, "{specifier}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ use pkg_ref::PesdePackageRef;
|
|||
use specifier::PesdeDependencySpecifier;
|
||||
|
||||
use crate::{
|
||||
authenticate_conn,
|
||||
git::authenticate_conn,
|
||||
manifest::{DependencyType, Target},
|
||||
names::{PackageName, PackageNames},
|
||||
source::{hash, DependencySpecifiers, PackageSource, ResolveResult},
|
||||
|
@ -264,7 +264,7 @@ impl PackageSource for PesdePackageSource {
|
|||
.connect(Direction::Fetch)
|
||||
.map_err(|e| Self::RefreshError::Connect(self.repo_url.clone(), e))?;
|
||||
|
||||
authenticate_conn(&mut connection, project.auth_config.clone());
|
||||
authenticate_conn(&mut connection, &project.auth_config);
|
||||
|
||||
connection
|
||||
.prepare_fetch(gix::progress::Discard, Default::default())
|
||||
|
@ -276,12 +276,13 @@ impl PackageSource for PesdePackageSource {
|
|||
}
|
||||
|
||||
std::fs::create_dir_all(&path)?;
|
||||
|
||||
let auth_config = project.auth_config.clone();
|
||||
|
||||
gix::prepare_clone_bare(self.repo_url.clone(), &path)
|
||||
.map_err(|e| Self::RefreshError::Clone(self.repo_url.clone(), e))?
|
||||
.configure_connection(move |c| {
|
||||
authenticate_conn(c, auth_config.clone());
|
||||
authenticate_conn(c, &auth_config);
|
||||
Ok(())
|
||||
})
|
||||
.fetch_only(gix::progress::Discard, &false.into())
|
||||
|
@ -344,9 +345,7 @@ impl PackageSource for PesdePackageSource {
|
|||
let mut response = REQWEST_CLIENT.get(url);
|
||||
|
||||
if let Some(token) = &project.auth_config.pesde_token {
|
||||
use secrecy::ExposeSecret;
|
||||
response =
|
||||
response.header("Authorization", format!("Bearer {}", token.expose_secret()));
|
||||
response = response.header("Authorization", format!("Bearer {token}"));
|
||||
}
|
||||
|
||||
let response = response.send()?;
|
||||
|
|
Loading…
Reference in a new issue