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]]
|
[[package]]
|
||||||
name = "async-signal"
|
name = "async-signal"
|
||||||
version = "0.2.8"
|
version = "0.2.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "794f185324c2f00e771cd9f1ae8b5ac68be2ca7abb129a87afd6e86d228bc54d"
|
checksum = "dfb3634b73397aa844481f814fad23bbf07fdb0eabec10f2eb95e58944b1ec32"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-io",
|
"async-io",
|
||||||
"async-lock",
|
"async-lock",
|
||||||
|
@ -370,9 +370,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytes"
|
name = "bytes"
|
||||||
version = "1.6.0"
|
version = "1.6.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9"
|
checksum = "a12916984aab3fa6e39d655a33e09c0071eb36d6ab3aea5c2d78551f1df6d952"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bzip2"
|
name = "bzip2"
|
||||||
|
@ -406,13 +406,12 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.1.1"
|
version = "1.1.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "907d8581360765417f8f2e0e7d602733bbed60156b4465b7617243689ef9b83d"
|
checksum = "2aba8f4e9906c7ce3c73463f62a7f0c65183ada1a2d47e397cc8810827f9694f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"jobserver",
|
"jobserver",
|
||||||
"libc",
|
"libc",
|
||||||
"once_cell",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -597,25 +596,6 @@ dependencies = [
|
||||||
"cfg-if",
|
"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]]
|
[[package]]
|
||||||
name = "crossbeam-utils"
|
name = "crossbeam-utils"
|
||||||
version = "0.8.20"
|
version = "0.8.20"
|
||||||
|
@ -723,9 +703,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deflate64"
|
name = "deflate64"
|
||||||
version = "0.1.8"
|
version = "0.1.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "83ace6c86376be0b6cdcf3fb41882e81d94b31587573d1cfa9d01cd06bba210d"
|
checksum = "da692b8d1080ea3045efaab14434d40468c3d8657e42abddfffca87b428f4c1b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deranged"
|
name = "deranged"
|
||||||
|
@ -1152,6 +1132,7 @@ dependencies = [
|
||||||
"gix-utils",
|
"gix-utils",
|
||||||
"gix-validate",
|
"gix-validate",
|
||||||
"gix-worktree",
|
"gix-worktree",
|
||||||
|
"gix-worktree-state",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"regex",
|
"regex",
|
||||||
|
@ -1172,7 +1153,7 @@ dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"serde",
|
"serde",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"winnow 0.6.13",
|
"winnow 0.6.14",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1256,7 +1237,7 @@ dependencies = [
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"unicode-bom",
|
"unicode-bom",
|
||||||
"winnow 0.6.13",
|
"winnow 0.6.14",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1529,7 +1510,7 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"winnow 0.6.13",
|
"winnow 0.6.14",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1600,9 +1581,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gix-path"
|
name = "gix-path"
|
||||||
version = "0.10.8"
|
version = "0.10.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ca987128ffb056d732bd545db5db3d8b103d252fbf083c2567bb0796876619a4"
|
checksum = "8d23d5bbda31344d8abc8de7c075b3cf26e5873feba7c4a15d916bce67382bd9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bstr",
|
"bstr",
|
||||||
"gix-trace",
|
"gix-trace",
|
||||||
|
@ -1655,7 +1636,7 @@ dependencies = [
|
||||||
"maybe-async",
|
"maybe-async",
|
||||||
"serde",
|
"serde",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"winnow 0.6.13",
|
"winnow 0.6.14",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1689,7 +1670,7 @@ dependencies = [
|
||||||
"memmap2",
|
"memmap2",
|
||||||
"serde",
|
"serde",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"winnow 0.6.13",
|
"winnow 0.6.14",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1878,16 +1859,23 @@ dependencies = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "globset"
|
name = "gix-worktree-state"
|
||||||
version = "0.4.14"
|
version = "0.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1"
|
checksum = "e64b2835892ce553b15aef7f6f7bb1e39e146fdf71eb99609b86710a7786cf34"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
|
||||||
"bstr",
|
"bstr",
|
||||||
"log",
|
"gix-features",
|
||||||
"regex-automata",
|
"gix-filter",
|
||||||
"regex-syntax",
|
"gix-fs",
|
||||||
|
"gix-glob",
|
||||||
|
"gix-hash",
|
||||||
|
"gix-index",
|
||||||
|
"gix-object",
|
||||||
|
"gix-path",
|
||||||
|
"gix-worktree",
|
||||||
|
"io-close",
|
||||||
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2119,22 +2107,6 @@ dependencies = [
|
||||||
"unicode-normalization",
|
"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]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "1.9.3"
|
version = "1.9.3"
|
||||||
|
@ -2216,6 +2188,16 @@ dependencies = [
|
||||||
"cfg-if",
|
"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]]
|
[[package]]
|
||||||
name = "ipnet"
|
name = "ipnet"
|
||||||
version = "2.9.0"
|
version = "2.9.0"
|
||||||
|
@ -2284,9 +2266,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "keyring"
|
name = "keyring"
|
||||||
version = "3.0.1"
|
version = "3.0.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f32930aef50aff920e88e6cf66b70a6d587a6f2bae6aeade5c1e583661a40f8e"
|
checksum = "9961b98f55dc0b2737000132505bdafa249abab147ee9de43c50ae04a054aa6c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"dbus-secret-service",
|
"dbus-secret-service",
|
||||||
|
@ -2728,7 +2710,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
"redox_syscall 0.5.2",
|
"redox_syscall 0.5.3",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"windows-targets 0.52.6",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
@ -2774,7 +2756,6 @@ dependencies = [
|
||||||
"flate2",
|
"flate2",
|
||||||
"full_moon",
|
"full_moon",
|
||||||
"gix",
|
"gix",
|
||||||
"ignore",
|
|
||||||
"indicatif",
|
"indicatif",
|
||||||
"indicatif-log-bridge",
|
"indicatif-log-bridge",
|
||||||
"inquire",
|
"inquire",
|
||||||
|
@ -2787,7 +2768,6 @@ dependencies = [
|
||||||
"pretty_env_logger",
|
"pretty_env_logger",
|
||||||
"relative-path",
|
"relative-path",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"secrecy",
|
|
||||||
"semver",
|
"semver",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
@ -2867,9 +2847,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "portable-atomic"
|
name = "portable-atomic"
|
||||||
version = "1.6.0"
|
version = "1.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0"
|
checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "powerfmt"
|
name = "powerfmt"
|
||||||
|
@ -3014,9 +2994,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.5.2"
|
version = "0.5.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd"
|
checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
]
|
]
|
||||||
|
@ -3228,15 +3208,6 @@ version = "1.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "secrecy"
|
|
||||||
version = "0.8.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e"
|
|
||||||
dependencies = [
|
|
||||||
"zeroize",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "secret-service"
|
name = "secret-service"
|
||||||
version = "4.0.0"
|
version = "4.0.0"
|
||||||
|
@ -3258,9 +3229,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "security-framework"
|
name = "security-framework"
|
||||||
version = "2.11.0"
|
version = "2.11.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0"
|
checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
"core-foundation",
|
"core-foundation",
|
||||||
|
@ -3271,9 +3242,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "security-framework-sys"
|
name = "security-framework-sys"
|
||||||
version = "2.11.0"
|
version = "2.11.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7"
|
checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"core-foundation-sys",
|
"core-foundation-sys",
|
||||||
"libc",
|
"libc",
|
||||||
|
@ -3353,9 +3324,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_with"
|
name = "serde_with"
|
||||||
version = "3.8.3"
|
version = "3.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e73139bc5ec2d45e6c5fd85be5a46949c1c39a4c18e56915f5eb4c12f975e377"
|
checksum = "69cecfa94848272156ea67b2b1a53f20fc7bc638c4a46d2f8abde08f05f4b857"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
@ -3371,9 +3342,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_with_macros"
|
name = "serde_with_macros"
|
||||||
version = "3.8.3"
|
version = "3.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b80d3d6b56b64335c0180e5ffde23b3c5e08c14c585b51a15bd0e95393f46703"
|
checksum = "a8fee4991ef4f274617a51ad4af30519438dacb2f56ac773b08a1922ff743350"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"darling",
|
"darling",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
|
@ -3407,9 +3378,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sha1_smol"
|
name = "sha1_smol"
|
||||||
version = "1.0.0"
|
version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012"
|
checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sha2"
|
name = "sha2"
|
||||||
|
@ -3608,18 +3579,18 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.62"
|
version = "1.0.63"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f2675633b1499176c2dff06b0856a27976a8f9d436737b4cf4f312d4d91d8bbb"
|
checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror-impl",
|
"thiserror-impl",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror-impl"
|
name = "thiserror-impl"
|
||||||
version = "1.0.62"
|
version = "1.0.63"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d20468752b09f49e909e55a5d338caa8bedf615594e9d80bc4c565d30faf798c"
|
checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -3695,9 +3666,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.38.0"
|
version = "1.38.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a"
|
checksum = "eb2caba9f80616f438e09748d5acda951967e1ea58508ef53d9c6402485a46df"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"backtrace",
|
"backtrace",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
@ -3734,14 +3705,14 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml"
|
name = "toml"
|
||||||
version = "0.8.14"
|
version = "0.8.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335"
|
checksum = "ac2caab0bf757388c6c0ae23b3293fdb463fee59434529014f85e3263b995c28"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_spanned",
|
"serde_spanned",
|
||||||
"toml_datetime",
|
"toml_datetime",
|
||||||
"toml_edit 0.22.15",
|
"toml_edit 0.22.16",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -3766,15 +3737,15 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_edit"
|
name = "toml_edit"
|
||||||
version = "0.22.15"
|
version = "0.22.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d59a3a72298453f564e2b111fa896f8d07fabb36f51f06d7e875fc5e0b5a3ef1"
|
checksum = "278f3d518e152219c994ce877758516bca5e118eaed6996192a774fb9fbf0788"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap 2.2.6",
|
"indexmap 2.2.6",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_spanned",
|
"serde_spanned",
|
||||||
"toml_datetime",
|
"toml_datetime",
|
||||||
"winnow 0.6.13",
|
"winnow 0.6.14",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -4253,9 +4224,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winnow"
|
name = "winnow"
|
||||||
version = "0.6.13"
|
version = "0.6.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1"
|
checksum = "374ec40a2d767a3c1b4972d9475ecd557356637be906f2cb3f7fe17a6eb5e22f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
@ -4389,9 +4360,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zip"
|
name = "zip"
|
||||||
version = "2.1.3"
|
version = "2.1.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "775a2b471036342aa69bc5a602bc889cb0a06cda00477d0c69566757d5553d39"
|
checksum = "b895748a3ebcb69b9d38dcfdf21760859a4b0d0b0015277640c2ef4c69640e6f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aes",
|
"aes",
|
||||||
"arbitrary",
|
"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"]
|
include = ["src/**/*", "Cargo.toml", "Cargo.lock", "README.md", "LICENSE", "CHANGELOG.md"]
|
||||||
|
|
||||||
[features]
|
[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"]
|
wally-compat = ["toml", "zip"]
|
||||||
roblox = []
|
roblox = []
|
||||||
lune = []
|
lune = []
|
||||||
|
@ -21,11 +21,14 @@ name = "pesde"
|
||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
required-features = ["bin"]
|
required-features = ["bin"]
|
||||||
|
|
||||||
|
[lints.clippy]
|
||||||
|
uninlined_format_args = "warn"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
serde = { version = "1.0.204", features = ["derive"] }
|
serde = { version = "1.0.204", features = ["derive"] }
|
||||||
serde_yaml = "0.9.34"
|
serde_yaml = "0.9.34"
|
||||||
serde_json = "1.0.120"
|
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"] }
|
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"] }
|
semver = { version = "1.0.23", features = ["serde"] }
|
||||||
reqwest = { version = "0.12.5", default-features = false, features = ["rustls-tls", "blocking"] }
|
reqwest = { version = "0.12.5", default-features = false, features = ["rustls-tls", "blocking"] }
|
||||||
|
@ -34,26 +37,26 @@ flate2 = "1.0.30"
|
||||||
pathdiff = "0.2.1"
|
pathdiff = "0.2.1"
|
||||||
relative-path = { version = "1.9.3", features = ["serde"] }
|
relative-path = { version = "1.9.3", features = ["serde"] }
|
||||||
log = "0.4.22"
|
log = "0.4.22"
|
||||||
thiserror = "1.0.62"
|
thiserror = "1.0.63"
|
||||||
threadpool = "1.8.1"
|
threadpool = "1.8.1"
|
||||||
full_moon = { version = "1.0.0-rc.5", features = ["luau"] }
|
full_moon = { version = "1.0.0-rc.5", features = ["luau"] }
|
||||||
url = { version = "2.5.2", features = ["serde"] }
|
url = { version = "2.5.2", features = ["serde"] }
|
||||||
cfg-if = "1.0.0"
|
cfg-if = "1.0.0"
|
||||||
once_cell = "1.19.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"] }
|
chrono = { version = "0.4.38", features = ["serde"] }
|
||||||
|
|
||||||
toml = { version = "0.8.14", optional = true }
|
toml = { version = "0.8.15", optional = true }
|
||||||
zip = { version = "2.1.3", optional = true }
|
zip = { version = "2.1.5", optional = true }
|
||||||
|
|
||||||
anyhow = { version = "1.0.86", optional = true }
|
anyhow = { version = "1.0.86", optional = true }
|
||||||
open = { version = "5.3.0", 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 }
|
colored = { version = "2.1.0", optional = true }
|
||||||
nondestructive = { version = "0.0.25", optional = true }
|
nondestructive = { version = "0.0.25", optional = true }
|
||||||
clap = { version = "4.5.9", features = ["derive"], optional = true }
|
clap = { version = "4.5.9", features = ["derive"], optional = true }
|
||||||
directories = { version = "5.0.1", 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 }
|
pretty_env_logger = { version = "0.5.0", optional = true }
|
||||||
indicatif = { version = "0.17.8", optional = true }
|
indicatif = { version = "0.17.8", optional = true }
|
||||||
indicatif-log-bridge = { version = "0.2.2", 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
|
/// The index to use. Defaults to `default`, or the configured default index if current directory doesn't have a manifest
|
||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
index: Option<String>,
|
index: Option<String>,
|
||||||
|
|
||||||
|
/// The token to use for authentication, skipping login
|
||||||
|
#[arg(short, long, conflicts_with = "index")]
|
||||||
|
token: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
|
@ -44,7 +48,11 @@ enum AccessTokenResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LoginCommand {
|
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() {
|
let manifest = match project.deser_manifest() {
|
||||||
Ok(manifest) => Some(manifest),
|
Ok(manifest) => Some(manifest),
|
||||||
Err(e) => match e {
|
Err(e) => match e {
|
||||||
|
@ -82,18 +90,13 @@ impl LoginCommand {
|
||||||
.try_into()
|
.try_into()
|
||||||
.context("cannot parse URL to git URL")?,
|
.context("cannot parse URL to git URL")?,
|
||||||
);
|
);
|
||||||
source
|
source.refresh(project).context("failed to refresh index")?;
|
||||||
.refresh(&project)
|
|
||||||
.context("failed to refresh index")?;
|
|
||||||
|
|
||||||
dbg!(source.all_packages(&project).unwrap());
|
|
||||||
|
|
||||||
let config = source
|
let config = source
|
||||||
.config(&project)
|
.config(project)
|
||||||
.context("failed to read index config")?;
|
.context("failed to read index config")?;
|
||||||
let client_id = config.github_oauth_client_id;
|
let client_id = config.github_oauth_client_id;
|
||||||
|
|
||||||
let reqwest = reqwest_client(project.data_dir())?;
|
|
||||||
let response = reqwest
|
let response = reqwest
|
||||||
.post(Url::parse_with_params(
|
.post(Url::parse_with_params(
|
||||||
"https://github.com/login/device/code",
|
"https://github.com/login/device/code",
|
||||||
|
@ -150,13 +153,7 @@ impl LoginCommand {
|
||||||
|
|
||||||
match response {
|
match response {
|
||||||
AccessTokenResponse::Success { access_token } => {
|
AccessTokenResponse::Success { access_token } => {
|
||||||
set_token(project.data_dir(), Some(&access_token))?;
|
return Ok(access_token);
|
||||||
|
|
||||||
println!(
|
|
||||||
"logged in as {}",
|
|
||||||
get_token_login(&reqwest, &access_token)?.bold()
|
|
||||||
);
|
|
||||||
return Ok(());
|
|
||||||
}
|
}
|
||||||
AccessTokenResponse::Error(e) => match e {
|
AccessTokenResponse::Error(e) => match e {
|
||||||
AccessTokenError::AuthorizationPending => continue,
|
AccessTokenError::AuthorizationPending => continue,
|
||||||
|
@ -178,4 +175,19 @@ impl LoginCommand {
|
||||||
|
|
||||||
anyhow::bail!("code expired, please re-run the login command");
|
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) => {
|
Some(index) => {
|
||||||
config.default_index = index.clone();
|
config.default_index = index.clone();
|
||||||
write_config(project.data_dir(), &config)?;
|
write_config(project.data_dir(), &config)?;
|
||||||
println!("default index set to: {}", index);
|
println!("default index set to: {index}");
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
println!("current default index: {}", config.default_index);
|
println!("current default index: {}", config.default_index);
|
||||||
|
|
|
@ -2,17 +2,22 @@ use clap::Subcommand;
|
||||||
use pesde::Project;
|
use pesde::Project;
|
||||||
|
|
||||||
mod default_index;
|
mod default_index;
|
||||||
|
mod scripts_repo;
|
||||||
|
|
||||||
#[derive(Debug, Subcommand)]
|
#[derive(Debug, Subcommand)]
|
||||||
pub enum ConfigCommands {
|
pub enum ConfigCommands {
|
||||||
/// Configuration for the default index
|
/// Configuration for the default index
|
||||||
DefaultIndex(default_index::DefaultIndexCommand),
|
DefaultIndex(default_index::DefaultIndexCommand),
|
||||||
|
|
||||||
|
/// Configuration for the scripts repository
|
||||||
|
ScriptsRepo(scripts_repo::ScriptsRepoCommand),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConfigCommands {
|
impl ConfigCommands {
|
||||||
pub fn run(self, project: Project) -> anyhow::Result<()> {
|
pub fn run(self, project: Project) -> anyhow::Result<()> {
|
||||||
match self {
|
match self {
|
||||||
ConfigCommands::DefaultIndex(default_index) => default_index.run(project),
|
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 crate::cli::read_config;
|
||||||
|
use anyhow::Context;
|
||||||
use clap::Args;
|
use clap::Args;
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
use inquire::validator::Validation;
|
use inquire::validator::Validation;
|
||||||
use pesde::{errors::ManifestReadError, names::PackageName, Project, DEFAULT_INDEX_NAME};
|
use pesde::{
|
||||||
use std::str::FromStr;
|
errors::ManifestReadError, manifest::ScriptName, names::PackageName, Project,
|
||||||
|
DEFAULT_INDEX_NAME,
|
||||||
|
};
|
||||||
|
use std::{path::Path, str::FromStr};
|
||||||
|
|
||||||
#[derive(Debug, Args)]
|
#[derive(Debug, Args)]
|
||||||
pub struct InitCommand {}
|
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 {
|
impl InitCommand {
|
||||||
pub fn run(self, project: Project) -> anyhow::Result<()> {
|
pub fn run(self, project: Project) -> anyhow::Result<()> {
|
||||||
match project.read_manifest() {
|
match project.read_manifest() {
|
||||||
|
@ -94,6 +113,57 @@ impl InitCommand {
|
||||||
mapping.insert_str("license", license);
|
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
|
let mut indices = mapping
|
||||||
.insert("indices", nondestructive::yaml::Separator::Auto)
|
.insert("indices", nondestructive::yaml::Separator::Auto)
|
||||||
.make_mapping();
|
.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 anyhow::Context;
|
||||||
|
use gix::remote::Direction;
|
||||||
use keyring::Entry;
|
use keyring::Entry;
|
||||||
use pesde::Project;
|
use pesde::Project;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::path::Path;
|
use std::{collections::HashSet, path::Path};
|
||||||
|
|
||||||
mod auth;
|
mod auth;
|
||||||
mod config;
|
mod config;
|
||||||
mod init;
|
mod init;
|
||||||
mod install;
|
mod install;
|
||||||
|
mod publish;
|
||||||
mod run;
|
mod run;
|
||||||
|
mod self_install;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct CliConfig {
|
pub struct CliConfig {
|
||||||
pub default_index: url::Url,
|
pub default_index: url::Url,
|
||||||
|
pub scripts_repo: url::Url,
|
||||||
pub token: Option<String>,
|
pub token: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +25,9 @@ impl Default for CliConfig {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
default_index: "https://github.com/daimond113/pesde-index".parse().unwrap(),
|
default_index: "https://github.com/daimond113/pesde-index".parse().unwrap(),
|
||||||
|
scripts_repo: "https://github.com/daimond113/pesde-scripts"
|
||||||
|
.parse()
|
||||||
|
.unwrap(),
|
||||||
token: None,
|
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)? {
|
if let Some(token) = get_token(data_dir)? {
|
||||||
headers.insert(
|
headers.insert(
|
||||||
reqwest::header::AUTHORIZATION,
|
reqwest::header::AUTHORIZATION,
|
||||||
format!("Bearer {}", token)
|
format!("Bearer {token}")
|
||||||
.parse()
|
.parse()
|
||||||
.context("failed to create auth header")?,
|
.context("failed to create auth header")?,
|
||||||
);
|
);
|
||||||
|
@ -125,6 +133,139 @@ pub fn reqwest_client(data_dir: &Path) -> anyhow::Result<reqwest::blocking::Clie
|
||||||
.build()?)
|
.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)]
|
#[derive(Debug, clap::Subcommand)]
|
||||||
pub enum Subcommand {
|
pub enum Subcommand {
|
||||||
/// Authentication-related commands
|
/// Authentication-related commands
|
||||||
|
@ -143,6 +284,12 @@ pub enum Subcommand {
|
||||||
|
|
||||||
/// Installs all dependencies for the project
|
/// Installs all dependencies for the project
|
||||||
Install(install::InstallCommand),
|
Install(install::InstallCommand),
|
||||||
|
|
||||||
|
/// Publishes the project to the registry
|
||||||
|
Publish(publish::PublishCommand),
|
||||||
|
|
||||||
|
/// Installs the pesde binary and scripts
|
||||||
|
SelfInstall(self_install::SelfInstallCommand),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Subcommand {
|
impl Subcommand {
|
||||||
|
@ -153,6 +300,8 @@ impl Subcommand {
|
||||||
Subcommand::Init(init) => init.run(project),
|
Subcommand::Init(init) => init.run(project),
|
||||||
Subcommand::Run(run) => run.run(project),
|
Subcommand::Run(run) => run.run(project),
|
||||||
Subcommand::Install(install) => install.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 anyhow::Context;
|
||||||
use clap::Args;
|
use clap::Args;
|
||||||
use pesde::{
|
use pesde::{
|
||||||
names::PackageName,
|
names::{PackageName, PackageNames},
|
||||||
scripts::{execute_lune_script, execute_script},
|
scripts::execute_script,
|
||||||
Project,
|
Project, PACKAGES_CONTAINER_NAME,
|
||||||
};
|
};
|
||||||
use relative_path::RelativePathBuf;
|
use relative_path::RelativePathBuf;
|
||||||
|
|
||||||
|
@ -20,13 +21,58 @@ pub struct RunCommand {
|
||||||
|
|
||||||
impl RunCommand {
|
impl RunCommand {
|
||||||
pub fn run(self, project: Project) -> anyhow::Result<()> {
|
pub fn run(self, project: Project) -> anyhow::Result<()> {
|
||||||
if let Ok(_pkg_name) = self.package_or_script.parse::<PackageName>() {
|
if let Ok(pkg_name) = self.package_or_script.parse::<PackageName>() {
|
||||||
todo!("implement binary package execution")
|
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 let Ok(manifest) = project.deser_manifest() {
|
||||||
if manifest.scripts.contains_key(&self.package_or_script) {
|
if let Some(script_path) = manifest.scripts.get(&self.package_or_script) {
|
||||||
execute_script(&manifest, &self.package_or_script, &self.args)
|
execute_script(
|
||||||
|
Some(&self.package_or_script),
|
||||||
|
&script_path.to_path(project.path()),
|
||||||
|
&self.args,
|
||||||
|
project.path(),
|
||||||
|
false,
|
||||||
|
)
|
||||||
.context("failed to execute script")?;
|
.context("failed to execute script")?;
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
@ -40,7 +86,7 @@ impl RunCommand {
|
||||||
anyhow::bail!("path does not exist: {}", path.display());
|
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")?;
|
.context("failed to execute script")?;
|
||||||
|
|
||||||
Ok(())
|
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 {
|
impl Project {
|
||||||
|
// TODO: use threadpool for concurrent downloads
|
||||||
pub fn download_graph(
|
pub fn download_graph(
|
||||||
&self,
|
&self,
|
||||||
graph: &DependencyGraph,
|
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};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
pub mod download;
|
pub mod download;
|
||||||
|
mod git;
|
||||||
pub mod linking;
|
pub mod linking;
|
||||||
pub mod lockfile;
|
pub mod lockfile;
|
||||||
pub mod manifest;
|
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 LOCKFILE_FILE_NAME: &str = "pesde.lock";
|
||||||
pub const DEFAULT_INDEX_NAME: &str = "default";
|
pub const DEFAULT_INDEX_NAME: &str = "default";
|
||||||
pub const PACKAGES_CONTAINER_NAME: &str = ".pesde";
|
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(|| {
|
pub(crate) static REQWEST_CLIENT: Lazy<reqwest::blocking::Client> = Lazy::new(|| {
|
||||||
reqwest::blocking::Client::builder()
|
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")
|
.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)]
|
#[derive(Debug, Default, Clone)]
|
||||||
pub struct AuthConfig {
|
pub struct AuthConfig {
|
||||||
pesde_token: Option<secrecy::SecretString>,
|
pesde_token: Option<String>,
|
||||||
git_credentials: Option<GitAccount>,
|
git_credentials: Option<gix::sec::identity::Account>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AuthConfig {
|
impl AuthConfig {
|
||||||
|
@ -76,39 +45,28 @@ impl AuthConfig {
|
||||||
AuthConfig::default()
|
AuthConfig::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_pesde_token<S: Into<secrecy::SecretString>>(mut self, token: Option<S>) -> Self {
|
pub fn pesde_token(&self) -> Option<&str> {
|
||||||
self.pesde_token = token.map(Into::into);
|
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
|
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.git_credentials = git_credentials;
|
||||||
self
|
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)]
|
#[derive(Debug)]
|
||||||
pub struct Project {
|
pub struct Project {
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
|
@ -137,6 +95,10 @@ impl Project {
|
||||||
&self.data_dir
|
&self.data_dir
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn auth_config(&self) -> &AuthConfig {
|
||||||
|
&self.auth_config
|
||||||
|
}
|
||||||
|
|
||||||
pub fn read_manifest(&self) -> Result<Vec<u8>, errors::ManifestReadError> {
|
pub fn read_manifest(&self) -> Result<Vec<u8>, errors::ManifestReadError> {
|
||||||
let bytes = std::fs::read(self.path.join(MANIFEST_FILE_NAME))?;
|
let bytes = std::fs::read(self.path.join(MANIFEST_FILE_NAME))?;
|
||||||
Ok(bytes)
|
Ok(bytes)
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
linking::generator::get_file_types, lockfile::DownloadedGraph, manifest::Manifest,
|
linking::generator::get_file_types,
|
||||||
names::PackageNames, source::PackageRef, Project, MANIFEST_FILE_NAME, PACKAGES_CONTAINER_NAME,
|
lockfile::DownloadedGraph,
|
||||||
|
manifest::{Manifest, ScriptName, Target},
|
||||||
|
names::PackageNames,
|
||||||
|
scripts::execute_script,
|
||||||
|
source::PackageRef,
|
||||||
|
Project, MANIFEST_FILE_NAME, PACKAGES_CONTAINER_NAME,
|
||||||
};
|
};
|
||||||
use semver::Version;
|
use semver::Version;
|
||||||
use std::{collections::BTreeMap, fs::create_dir_all};
|
use std::{collections::BTreeMap, fs::create_dir_all};
|
||||||
|
@ -34,7 +39,7 @@ impl Project {
|
||||||
version,
|
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) {
|
let contents = match std::fs::read_to_string(&lib_file) {
|
||||||
Ok(contents) => contents,
|
Ok(contents) => contents,
|
||||||
|
@ -60,6 +65,30 @@ impl Project {
|
||||||
.entry(name)
|
.entry(name)
|
||||||
.or_default()
|
.or_default()
|
||||||
.insert(version, types);
|
.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")]
|
#[error("error generating require path")]
|
||||||
GetRequirePath(#[from] crate::linking::generator::errors::GetRequirePathError),
|
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 version: Version,
|
||||||
pub overrides: BTreeMap<OverrideKey, DependencySpecifiers>,
|
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;
|
use std::fs::create_dir_all;
|
||||||
|
|
||||||
mod cli;
|
mod cli;
|
||||||
|
pub mod git;
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
#[clap(version, about = "pesde is a feature-rich package manager for Luau")]
|
#[clap(version, about = "pesde is a feature-rich package manager for Luau")]
|
||||||
|
|
139
src/manifest.rs
139
src/manifest.rs
|
@ -1,15 +1,14 @@
|
||||||
|
use crate::{names::PackageName, source::DependencySpecifiers};
|
||||||
use relative_path::RelativePathBuf;
|
use relative_path::RelativePathBuf;
|
||||||
use semver::Version;
|
use semver::Version;
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_with::{DeserializeFromStr, SerializeDisplay};
|
use serde_with::{DeserializeFromStr, SerializeDisplay};
|
||||||
use std::{
|
use std::{
|
||||||
collections::BTreeMap,
|
collections::{BTreeMap, BTreeSet},
|
||||||
fmt::{Display, Formatter},
|
fmt::{Display, Formatter},
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{names::PackageName, source::DependencySpecifiers};
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
#[serde(rename_all = "snake_case", deny_unknown_fields)]
|
#[serde(rename_all = "snake_case", deny_unknown_fields)]
|
||||||
pub enum TargetKind {
|
pub enum TargetKind {
|
||||||
|
@ -54,23 +53,32 @@ impl TargetKind {
|
||||||
return "packages".to_string();
|
return "packages".to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
format!("{}_packages", dependency)
|
format!("{dependency}_packages")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
#[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 {
|
pub enum Target {
|
||||||
#[cfg(feature = "roblox")]
|
#[cfg(feature = "roblox")]
|
||||||
Roblox { lib: RelativePathBuf },
|
Roblox {
|
||||||
|
#[serde(default)]
|
||||||
|
lib: Option<RelativePathBuf>,
|
||||||
|
#[serde(default)]
|
||||||
|
build_files: BTreeSet<String>,
|
||||||
|
},
|
||||||
#[cfg(feature = "lune")]
|
#[cfg(feature = "lune")]
|
||||||
Lune {
|
Lune {
|
||||||
|
#[serde(default)]
|
||||||
lib: Option<RelativePathBuf>,
|
lib: Option<RelativePathBuf>,
|
||||||
|
#[serde(default)]
|
||||||
bin: Option<RelativePathBuf>,
|
bin: Option<RelativePathBuf>,
|
||||||
},
|
},
|
||||||
#[cfg(feature = "luau")]
|
#[cfg(feature = "luau")]
|
||||||
Luau {
|
Luau {
|
||||||
|
#[serde(default)]
|
||||||
lib: Option<RelativePathBuf>,
|
lib: Option<RelativePathBuf>,
|
||||||
|
#[serde(default)]
|
||||||
bin: Option<RelativePathBuf>,
|
bin: Option<RelativePathBuf>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -90,55 +98,47 @@ impl Target {
|
||||||
pub fn lib_path(&self) -> Option<&RelativePathBuf> {
|
pub fn lib_path(&self) -> Option<&RelativePathBuf> {
|
||||||
match self {
|
match self {
|
||||||
#[cfg(feature = "roblox")]
|
#[cfg(feature = "roblox")]
|
||||||
Target::Roblox { lib } => Some(lib),
|
Target::Roblox { lib, .. } => lib.as_ref(),
|
||||||
#[cfg(feature = "lune")]
|
#[cfg(feature = "lune")]
|
||||||
Target::Lune { lib, .. } => lib.as_ref(),
|
Target::Lune { lib, .. } => lib.as_ref(),
|
||||||
#[cfg(feature = "luau")]
|
#[cfg(feature = "luau")]
|
||||||
Target::Luau { lib, .. } => lib.as_ref(),
|
Target::Luau { lib, .. } => lib.as_ref(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Serialize for Target {
|
pub fn bin_path(&self) -> Option<&RelativePathBuf> {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
match self {
|
||||||
where
|
#[cfg(feature = "roblox")]
|
||||||
S: Serializer,
|
Target::Roblox { .. } => None,
|
||||||
{
|
|
||||||
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 {
|
|
||||||
#[cfg(feature = "lune")]
|
#[cfg(feature = "lune")]
|
||||||
Target::Lune { lib, bin } => {
|
Target::Lune { bin, .. } => bin.as_ref(),
|
||||||
if lib.is_none() && bin.is_none() {
|
|
||||||
return Err(serde::de::Error::custom(
|
|
||||||
"one of `lib` or `bin` exports must be defined",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "luau")]
|
#[cfg(feature = "luau")]
|
||||||
Target::Luau { lib, bin } => {
|
Target::Luau { bin, .. } => bin.as_ref(),
|
||||||
if lib.is_none() && bin.is_none() {
|
|
||||||
return Err(serde::de::Error::custom(
|
|
||||||
"one of `lib` or `bin` exports must be defined",
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[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 struct Manifest {
|
||||||
pub name: PackageName,
|
pub name: PackageName,
|
||||||
pub version: Version,
|
pub version: Version,
|
||||||
#[serde(default)]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
#[serde(default)]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
pub license: Option<String>,
|
pub license: Option<String>,
|
||||||
#[serde(default)]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
pub authors: Option<Vec<String>>,
|
pub authors: Option<Vec<String>>,
|
||||||
#[serde(default)]
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||||
pub repository: Option<String>,
|
pub repository: Option<String>,
|
||||||
pub target: Target,
|
pub target: Target,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub private: bool,
|
pub private: bool,
|
||||||
#[serde(default)]
|
#[serde(default, skip_serializing)]
|
||||||
pub scripts: BTreeMap<String, RelativePathBuf>,
|
pub scripts: BTreeMap<String, RelativePathBuf>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub indices: BTreeMap<String, url::Url>,
|
pub indices: BTreeMap<String, url::Url>,
|
||||||
#[cfg(feature = "wally-compat")]
|
#[cfg(feature = "wally-compat")]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub wally_indices: BTreeMap<String, url::Url>,
|
pub wally_indices: BTreeMap<String, url::Url>,
|
||||||
#[cfg(all(feature = "wally-compat", feature = "roblox"))]
|
#[serde(default, skip_serializing)]
|
||||||
#[serde(default)]
|
|
||||||
pub sourcemap_generator: Option<String>,
|
|
||||||
#[serde(default)]
|
|
||||||
pub overrides: BTreeMap<OverrideKey, DependencySpecifiers>,
|
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>,
|
pub dependencies: BTreeMap<String, DependencySpecifiers>,
|
||||||
#[serde(default)]
|
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
|
||||||
pub peer_dependencies: BTreeMap<String, DependencySpecifiers>,
|
pub peer_dependencies: BTreeMap<String, DependencySpecifiers>,
|
||||||
#[serde(default)]
|
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
|
||||||
pub dev_dependencies: BTreeMap<String, DependencySpecifiers>,
|
pub dev_dependencies: BTreeMap<String, DependencySpecifiers>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,4 +293,15 @@ pub mod errors {
|
||||||
#[error("another specifier is already using the alias {0}")]
|
#[error("another specifier is already using the alias {0}")]
|
||||||
AliasConflict(String),
|
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 {
|
impl Display for PackageNames {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
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::{
|
use std::{
|
||||||
ffi::OsStr,
|
ffi::OsStr,
|
||||||
io::{BufRead, BufReader},
|
io::{BufRead, BufReader},
|
||||||
|
path::Path,
|
||||||
process::{Command, Stdio},
|
process::{Command, Stdio},
|
||||||
thread::spawn,
|
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_name: Option<&str>,
|
||||||
script_path: &RelativePathBuf,
|
script_path: &Path,
|
||||||
args: A,
|
args: A,
|
||||||
) -> Result<(), std::io::Error> {
|
cwd: P,
|
||||||
|
return_stdout: bool,
|
||||||
|
) -> Result<Option<String>, std::io::Error> {
|
||||||
match Command::new("lune")
|
match Command::new("lune")
|
||||||
.arg("run")
|
.arg("run")
|
||||||
.arg(script_path.as_str())
|
.arg(script_path.as_os_str())
|
||||||
.args(args)
|
.args(args)
|
||||||
|
.current_dir(cwd)
|
||||||
.stdin(Stdio::null())
|
.stdin(Stdio::null())
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.stderr(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 {
|
let script = match script_name {
|
||||||
Some(script) => script.to_string(),
|
Some(script) => script.to_string(),
|
||||||
None => script_path.to_string(),
|
None => script_path.to_string_lossy().to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let script_2 = script.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() {
|
for line in stdout.lines() {
|
||||||
match line {
|
match line {
|
||||||
Ok(line) => {
|
Ok(line) => {
|
||||||
log::info!("[{script_2}]: {line}");
|
log::info!("[{script_2}]: {line}");
|
||||||
|
|
||||||
|
if return_stdout {
|
||||||
|
stdout_str.push_str(&line);
|
||||||
|
stdout_str.push('\n');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::error!("ERROR IN READING STDOUT OF {script_2}: {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 => {
|
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),
|
Err(e) => 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ impl DependencySpecifier for DependencySpecifiers {}
|
||||||
impl Display for DependencySpecifiers {
|
impl Display for DependencySpecifiers {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
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 specifier::PesdeDependencySpecifier;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
authenticate_conn,
|
git::authenticate_conn,
|
||||||
manifest::{DependencyType, Target},
|
manifest::{DependencyType, Target},
|
||||||
names::{PackageName, PackageNames},
|
names::{PackageName, PackageNames},
|
||||||
source::{hash, DependencySpecifiers, PackageSource, ResolveResult},
|
source::{hash, DependencySpecifiers, PackageSource, ResolveResult},
|
||||||
|
@ -264,7 +264,7 @@ impl PackageSource for PesdePackageSource {
|
||||||
.connect(Direction::Fetch)
|
.connect(Direction::Fetch)
|
||||||
.map_err(|e| Self::RefreshError::Connect(self.repo_url.clone(), e))?;
|
.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
|
connection
|
||||||
.prepare_fetch(gix::progress::Discard, Default::default())
|
.prepare_fetch(gix::progress::Discard, Default::default())
|
||||||
|
@ -276,12 +276,13 @@ impl PackageSource for PesdePackageSource {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::fs::create_dir_all(&path)?;
|
std::fs::create_dir_all(&path)?;
|
||||||
|
|
||||||
let auth_config = project.auth_config.clone();
|
let auth_config = project.auth_config.clone();
|
||||||
|
|
||||||
gix::prepare_clone_bare(self.repo_url.clone(), &path)
|
gix::prepare_clone_bare(self.repo_url.clone(), &path)
|
||||||
.map_err(|e| Self::RefreshError::Clone(self.repo_url.clone(), e))?
|
.map_err(|e| Self::RefreshError::Clone(self.repo_url.clone(), e))?
|
||||||
.configure_connection(move |c| {
|
.configure_connection(move |c| {
|
||||||
authenticate_conn(c, auth_config.clone());
|
authenticate_conn(c, &auth_config);
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
.fetch_only(gix::progress::Discard, &false.into())
|
.fetch_only(gix::progress::Discard, &false.into())
|
||||||
|
@ -344,9 +345,7 @@ impl PackageSource for PesdePackageSource {
|
||||||
let mut response = REQWEST_CLIENT.get(url);
|
let mut response = REQWEST_CLIENT.get(url);
|
||||||
|
|
||||||
if let Some(token) = &project.auth_config.pesde_token {
|
if let Some(token) = &project.auth_config.pesde_token {
|
||||||
use secrecy::ExposeSecret;
|
response = response.header("Authorization", format!("Bearer {token}"));
|
||||||
response =
|
|
||||||
response.header("Authorization", format!("Bearer {}", token.expose_secret()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let response = response.send()?;
|
let response = response.send()?;
|
||||||
|
|
Loading…
Reference in a new issue