Merge branch 'master' into post

This commit is contained in:
Jonathan Turner 2019-08-31 15:12:03 +12:00
commit 1d77595576
28 changed files with 894 additions and 481 deletions

81
Cargo.lock generated
View File

@ -641,11 +641,6 @@ dependencies = [
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "doc-comment"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "dtoa" name = "dtoa"
version = "0.4.4" version = "0.4.4"
@ -720,6 +715,16 @@ dependencies = [
"synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "fallible-iterator"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "fallible-streaming-iterator"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "fixedbitset" name = "fixedbitset"
version = "0.1.9" version = "0.1.9"
@ -821,6 +826,15 @@ dependencies = [
"futures-core-preview 0.3.0-alpha.18 (registry+https://github.com/rust-lang/crates.io-index)", "futures-core-preview 0.3.0-alpha.18 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "futures-timer"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures-preview 0.3.0-alpha.18 (registry+https://github.com/rust-lang/crates.io-index)",
"pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "futures-util-preview" name = "futures-util-preview"
version = "0.3.0-alpha.18" version = "0.3.0-alpha.18"
@ -1304,6 +1318,16 @@ dependencies = [
"libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "libsqlite3-sys"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"vcpkg 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "libz-sys" name = "libz-sys"
version = "1.0.25" version = "1.0.25"
@ -1354,6 +1378,14 @@ dependencies = [
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "lru-cache"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "lzw" name = "lzw"
version = "0.10.0" version = "0.10.0"
@ -1567,11 +1599,13 @@ dependencies = [
"enum-utils 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "enum-utils 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-async-stream 0.1.0-alpha.5 (registry+https://github.com/rust-lang/crates.io-index)", "futures-async-stream 0.1.0-alpha.5 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-preview 0.3.0-alpha.18 (registry+https://github.com/rust-lang/crates.io-index)", "futures-preview 0.3.0-alpha.18 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-timer 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"futures_codec 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "futures_codec 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"getset 0.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "getset 0.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"git2 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "git2 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
"glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"heim 0.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "heim 0.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"image 0.22.1 (registry+https://github.com/rust-lang/crates.io-index)", "image 0.22.1 (registry+https://github.com/rust-lang/crates.io-index)",
"indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1583,6 +1617,7 @@ dependencies = [
"nom5_locate 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "nom5_locate 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"onig_sys 69.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "onig_sys 69.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ordered-float 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "ordered-float 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)",
"pretty-hex 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "pretty-hex 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
"pretty_env_logger 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "pretty_env_logger 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1591,6 +1626,7 @@ dependencies = [
"rawkey 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "rawkey 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"roxmltree 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "roxmltree 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rusqlite 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rustyline 5.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustyline 5.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1603,7 +1639,6 @@ dependencies = [
"subprocess 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", "subprocess 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
"surf 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "surf 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syntect 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "syntect 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"sysinfo 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
"tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"term 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2240,6 +2275,20 @@ dependencies = [
"xmlparser 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "xmlparser 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "rusqlite"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"fallible-iterator 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"fallible-streaming-iterator 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
"libsqlite3-sys 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lru-cache 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "rust-argon2" name = "rust-argon2"
version = "0.5.0" version = "0.5.0"
@ -2620,18 +2669,6 @@ dependencies = [
"yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "sysinfo"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
"doc-comment 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "tempfile" name = "tempfile"
version = "3.1.0" version = "3.1.0"
@ -3182,7 +3219,6 @@ dependencies = [
"checksum dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901" "checksum dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901"
"checksum dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" "checksum dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3"
"checksum dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" "checksum dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b"
"checksum doc-comment 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "923dea538cea0aa3025e8685b20d6ee21ef99c4f77e954a30febbaac5ec73a97"
"checksum dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ea57b42383d091c85abcc2706240b94ab2a8fa1fc81c10ff23c4de06e2a90b5e" "checksum dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ea57b42383d091c85abcc2706240b94ab2a8fa1fc81c10ff23c4de06e2a90b5e"
"checksum dunce 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0ad6bf6a88548d1126045c413548df1453d9be094a8ab9fd59bf1fdd338da4f" "checksum dunce 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0ad6bf6a88548d1126045c413548df1453d9be094a8ab9fd59bf1fdd338da4f"
"checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b" "checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b"
@ -3192,6 +3228,8 @@ dependencies = [
"checksum env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" "checksum env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3"
"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" "checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2"
"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" "checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1"
"checksum fallible-iterator 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
"checksum fallible-streaming-iterator 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
"checksum fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33" "checksum fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33"
"checksum flate2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "550934ad4808d5d39365e5d61727309bf18b3b02c6c56b729cb92e7dd84bc3d8" "checksum flate2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "550934ad4808d5d39365e5d61727309bf18b3b02c6c56b729cb92e7dd84bc3d8"
"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
@ -3205,6 +3243,7 @@ dependencies = [
"checksum futures-io-preview 0.3.0-alpha.18 (registry+https://github.com/rust-lang/crates.io-index)" = "ee7de0c1c9ed23f9457b0437fec7663ce64d9cc3c906597e714e529377b5ddd1" "checksum futures-io-preview 0.3.0-alpha.18 (registry+https://github.com/rust-lang/crates.io-index)" = "ee7de0c1c9ed23f9457b0437fec7663ce64d9cc3c906597e714e529377b5ddd1"
"checksum futures-preview 0.3.0-alpha.18 (registry+https://github.com/rust-lang/crates.io-index)" = "efa8f90c4fb2328e381f8adfd4255b4a2b696f77d1c63a3dee6700b564c4e4b5" "checksum futures-preview 0.3.0-alpha.18 (registry+https://github.com/rust-lang/crates.io-index)" = "efa8f90c4fb2328e381f8adfd4255b4a2b696f77d1c63a3dee6700b564c4e4b5"
"checksum futures-sink-preview 0.3.0-alpha.18 (registry+https://github.com/rust-lang/crates.io-index)" = "e9b65a2481863d1b78e094a07e9c0eed458cc7dc6e72b22b7138b8a67d924859" "checksum futures-sink-preview 0.3.0-alpha.18 (registry+https://github.com/rust-lang/crates.io-index)" = "e9b65a2481863d1b78e094a07e9c0eed458cc7dc6e72b22b7138b8a67d924859"
"checksum futures-timer 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8f9eb554aa23143abc64ec4d0016f038caf53bb7cbc3d91490835c54edc96550"
"checksum futures-util-preview 0.3.0-alpha.18 (registry+https://github.com/rust-lang/crates.io-index)" = "7df53daff1e98cc024bf2720f3ceb0414d96fbb0a94f3cad3a5c3bf3be1d261c" "checksum futures-util-preview 0.3.0-alpha.18 (registry+https://github.com/rust-lang/crates.io-index)" = "7df53daff1e98cc024bf2720f3ceb0414d96fbb0a94f3cad3a5c3bf3be1d261c"
"checksum futures_codec 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "36552cd31353fd135114510d53b8d120758120c36aa636a9341970f9efb1e4a0" "checksum futures_codec 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "36552cd31353fd135114510d53b8d120758120c36aa636a9341970f9efb1e4a0"
"checksum getrandom 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "34f33de6f0ae7c9cb5e574502a562e2b512799e32abb801cd1e79ad952b62b49" "checksum getrandom 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "34f33de6f0ae7c9cb5e574502a562e2b512799e32abb801cd1e79ad952b62b49"
@ -3250,12 +3289,14 @@ dependencies = [
"checksum libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)" = "d44e80633f007889c7eff624b709ab43c92d708caad982295768a7b13ca3b5eb" "checksum libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)" = "d44e80633f007889c7eff624b709ab43c92d708caad982295768a7b13ca3b5eb"
"checksum libgit2-sys 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4c179ed6d19cd3a051e68c177fbbc214e79ac4724fac3a850ec9f3d3eb8a5578" "checksum libgit2-sys 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4c179ed6d19cd3a051e68c177fbbc214e79ac4724fac3a850ec9f3d3eb8a5578"
"checksum libnghttp2-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02254d44f4435dd79e695f2c2b83cd06a47919adea30216ceaf0c57ca0a72463" "checksum libnghttp2-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02254d44f4435dd79e695f2c2b83cd06a47919adea30216ceaf0c57ca0a72463"
"checksum libsqlite3-sys 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5e5b95e89c330291768dc840238db7f9e204fd208511ab6319b56193a7f2ae25"
"checksum libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "2eb5e43362e38e2bca2fd5f5134c4d4564a23a5c28e9b95411652021a8675ebe" "checksum libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "2eb5e43362e38e2bca2fd5f5134c4d4564a23a5c28e9b95411652021a8675ebe"
"checksum line-wrap 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f30344350a2a51da54c1d53be93fade8a237e545dbcc4bdbe635413f2117cab9" "checksum line-wrap 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f30344350a2a51da54c1d53be93fade8a237e545dbcc4bdbe635413f2117cab9"
"checksum linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d262045c5b87c0861b3f004610afd0e2c851e2908d08b6c870cbb9d5f494ecd" "checksum linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d262045c5b87c0861b3f004610afd0e2c851e2908d08b6c870cbb9d5f494ecd"
"checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83" "checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83"
"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" "checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c"
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
"checksum lru-cache 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c"
"checksum lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d947cbb889ed21c2a84be6ffbaebf5b4e0f4340638cba0444907e38b56be084" "checksum lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d947cbb889ed21c2a84be6ffbaebf5b4e0f4340638cba0444907e38b56be084"
"checksum macaddr 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3ff4752cb15cffb3e68f7dcb22e0818ac871f8c98fb07a634a81f41fb202a09f" "checksum macaddr 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3ff4752cb15cffb3e68f7dcb22e0818ac871f8c98fb07a634a81f41fb202a09f"
"checksum mach 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "86dd2487cdfea56def77b88438a2c915fb45113c5319bfe7e14306ca4cd0b0e1" "checksum mach 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "86dd2487cdfea56def77b88438a2c915fb45113c5319bfe7e14306ca4cd0b0e1"
@ -3350,6 +3391,7 @@ dependencies = [
"checksum render-tree 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "68ed587df09cfb7ce1bc6fe8f77e24db219f222c049326ccbfb948ec67e31664" "checksum render-tree 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "68ed587df09cfb7ce1bc6fe8f77e24db219f222c049326ccbfb948ec67e31664"
"checksum result 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "194d8e591e405d1eecf28819740abed6d719d1a2db87fc0bcdedee9a26d55560" "checksum result 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "194d8e591e405d1eecf28819740abed6d719d1a2db87fc0bcdedee9a26d55560"
"checksum roxmltree 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "153c367ce9fb8ef7afe637ef92bd083ba0f88b03ef3fcf0287d40be05ae0a61c" "checksum roxmltree 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "153c367ce9fb8ef7afe637ef92bd083ba0f88b03ef3fcf0287d40be05ae0a61c"
"checksum rusqlite 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2a194373ef527035645a1bc21b10dc2125f73497e6e155771233eb187aedd051"
"checksum rust-argon2 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "81ed8d04228b44a740c8d46ff872a28e50fff3d659f307ab4da2cc502e019ff3" "checksum rust-argon2 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "81ed8d04228b44a740c8d46ff872a28e50fff3d659f307ab4da2cc502e019ff3"
"checksum rust-ini 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e52c148ef37f8c375d49d5a73aa70713125b7f19095948a923f80afdeb22ec2" "checksum rust-ini 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e52c148ef37f8c375d49d5a73aa70713125b7f19095948a923f80afdeb22ec2"
"checksum rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f4dccf6f4891ebcc0c39f9b6eb1a83b9bf5d747cb439ec6fba4f3b977038af" "checksum rustc-demangle 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f4dccf6f4891ebcc0c39f9b6eb1a83b9bf5d747cb439ec6fba4f3b977038af"
@ -3394,7 +3436,6 @@ dependencies = [
"checksum syn 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c65d951ab12d976b61a41cf9ed4531fc19735c6e6d84a4bb1453711e762ec731" "checksum syn 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c65d951ab12d976b61a41cf9ed4531fc19735c6e6d84a4bb1453711e762ec731"
"checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" "checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f"
"checksum syntect 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e80b8831c5a543192ffc3727f01cf0e57579c6ac15558e3048bfb5708892167b" "checksum syntect 3.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e80b8831c5a543192ffc3727f01cf0e57579c6ac15558e3048bfb5708892167b"
"checksum sysinfo 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a8e841d2045e01c28343a09841a4c2323d0e936dbb813c95d6c76d13a88668d2"
"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
"checksum term 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42" "checksum term 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42"
"checksum term_size 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9e5b9a66db815dcfd2da92db471106457082577c3c278d4138ab3e3b4e189327" "checksum term_size 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9e5b9a66db815dcfd2da92db471106457082577c3c278d4138ab3e3b4e189327"

View File

@ -15,7 +15,6 @@ documentation = "https://book.nushell.sh"
[dependencies] [dependencies]
rustyline = "5.0.2" rustyline = "5.0.2"
sysinfo = "0.9.2"
chrono = { version = "0.4.7", features = ["serde"] } chrono = { version = "0.4.7", features = ["serde"] }
derive-new = "0.5.7" derive-new = "0.5.7"
prettytable-rs = "0.8.0" prettytable-rs = "0.8.0"
@ -64,6 +63,7 @@ mime = "0.3.13"
regex = "1.2.1" regex = "1.2.1"
pretty-hex = "0.1.0" pretty-hex = "0.1.0"
neso = { version = "0.5.0", optional = true } neso = { version = "0.5.0", optional = true }
hex = "0.3.2"
crossterm = "0.10.2" crossterm = "0.10.2"
tempfile = "3.1.0" tempfile = "3.1.0"
image = "0.22.1" image = "0.22.1"
@ -78,10 +78,16 @@ textwrap = {version = "0.11.0", features = ["term_size"]}
rawkey = {version = "0.1.2", optional = true } rawkey = {version = "0.1.2", optional = true }
clipboard = {version = "0.5", optional = true } clipboard = {version = "0.5", optional = true }
shellexpand = "1.0.0" shellexpand = "1.0.0"
futures-timer = "0.3.0"
pin-utils = "0.1.0-alpha.4"
[features] [features]
raw-key = ["rawkey", "neso"] raw-key = ["rawkey", "neso"]
[dependencies.rusqlite]
version = "0.20.0"
features = ["bundled", "blob"]
[dev-dependencies] [dev-dependencies]
pretty_assertions = "0.6.1" pretty_assertions = "0.6.1"

View File

@ -179,6 +179,8 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
whole_stream_command(ToBSON), whole_stream_command(ToBSON),
whole_stream_command(ToCSV), whole_stream_command(ToCSV),
whole_stream_command(ToJSON), whole_stream_command(ToJSON),
whole_stream_command(ToSQLite),
whole_stream_command(ToDB),
whole_stream_command(ToTOML), whole_stream_command(ToTOML),
whole_stream_command(ToTSV), whole_stream_command(ToTSV),
whole_stream_command(ToYAML), whole_stream_command(ToYAML),
@ -193,9 +195,12 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
whole_stream_command(FromINI), whole_stream_command(FromINI),
whole_stream_command(FromBSON), whole_stream_command(FromBSON),
whole_stream_command(FromJSON), whole_stream_command(FromJSON),
whole_stream_command(FromDB),
whole_stream_command(FromSQLite),
whole_stream_command(FromTOML), whole_stream_command(FromTOML),
whole_stream_command(FromXML), whole_stream_command(FromXML),
whole_stream_command(FromYAML), whole_stream_command(FromYAML),
whole_stream_command(FromYML),
whole_stream_command(Pick), whole_stream_command(Pick),
whole_stream_command(Get), whole_stream_command(Get),
per_item_command(Remove), per_item_command(Remove),

View File

@ -19,6 +19,7 @@ pub(crate) mod from_bson;
pub(crate) mod from_csv; pub(crate) mod from_csv;
pub(crate) mod from_ini; pub(crate) mod from_ini;
pub(crate) mod from_json; pub(crate) mod from_json;
pub(crate) mod from_sqlite;
pub(crate) mod from_toml; pub(crate) mod from_toml;
pub(crate) mod from_tsv; pub(crate) mod from_tsv;
pub(crate) mod from_xml; pub(crate) mod from_xml;
@ -53,6 +54,7 @@ pub(crate) mod to_array;
pub(crate) mod to_bson; pub(crate) mod to_bson;
pub(crate) mod to_csv; pub(crate) mod to_csv;
pub(crate) mod to_json; pub(crate) mod to_json;
pub(crate) mod to_sqlite;
pub(crate) mod to_toml; pub(crate) mod to_toml;
pub(crate) mod to_tsv; pub(crate) mod to_tsv;
pub(crate) mod to_yaml; pub(crate) mod to_yaml;
@ -68,6 +70,7 @@ pub(crate) use command::{
per_item_command, whole_stream_command, Command, PerItemCommand, RawCommandArgs, per_item_command, whole_stream_command, Command, PerItemCommand, RawCommandArgs,
UnevaluatedCallInfo, WholeStreamCommand, UnevaluatedCallInfo, WholeStreamCommand,
}; };
pub(crate) use config::Config; pub(crate) use config::Config;
pub(crate) use cp::Cpy; pub(crate) use cp::Cpy;
pub(crate) use date::Date; pub(crate) use date::Date;
@ -80,10 +83,13 @@ pub(crate) use from_bson::FromBSON;
pub(crate) use from_csv::FromCSV; pub(crate) use from_csv::FromCSV;
pub(crate) use from_ini::FromINI; pub(crate) use from_ini::FromINI;
pub(crate) use from_json::FromJSON; pub(crate) use from_json::FromJSON;
pub(crate) use from_sqlite::FromDB;
pub(crate) use from_sqlite::FromSQLite;
pub(crate) use from_toml::FromTOML; pub(crate) use from_toml::FromTOML;
pub(crate) use from_tsv::FromTSV; pub(crate) use from_tsv::FromTSV;
pub(crate) use from_xml::FromXML; pub(crate) use from_xml::FromXML;
pub(crate) use from_yaml::FromYAML; pub(crate) use from_yaml::FromYAML;
pub(crate) use from_yaml::FromYML;
pub(crate) use get::Get; pub(crate) use get::Get;
pub(crate) use last::Last; pub(crate) use last::Last;
pub(crate) use lines::Lines; pub(crate) use lines::Lines;
@ -113,6 +119,8 @@ pub(crate) use to_array::ToArray;
pub(crate) use to_bson::ToBSON; pub(crate) use to_bson::ToBSON;
pub(crate) use to_csv::ToCSV; pub(crate) use to_csv::ToCSV;
pub(crate) use to_json::ToJSON; pub(crate) use to_json::ToJSON;
pub(crate) use to_sqlite::ToDB;
pub(crate) use to_sqlite::ToSQLite;
pub(crate) use to_toml::ToTOML; pub(crate) use to_toml::ToTOML;
pub(crate) use to_tsv::ToTSV; pub(crate) use to_tsv::ToTSV;
pub(crate) use to_yaml::ToYAML; pub(crate) use to_yaml::ToYAML;

View File

@ -146,53 +146,9 @@ impl InternalCommand {
.insert_at_current(Box::new(ValueShell::new(value))); .insert_at_current(Box::new(ValueShell::new(value)));
} }
CommandAction::EnterShell(location) => { CommandAction::EnterShell(location) => {
let path = std::path::Path::new(&location); context.shell_manager.insert_at_current(Box::new(
FilesystemShell::with_location(location, context.registry().clone())?,
if path.is_dir() { ));
// If it's a directory, add a new filesystem shell
context.shell_manager.insert_at_current(Box::new(
FilesystemShell::with_location(
location,
context.registry().clone(),
)?,
));
} else {
// If it's a file, attempt to open the file as a value and enter it
let cwd = context.shell_manager.path();
let full_path = std::path::PathBuf::from(cwd);
let (file_extension, contents, contents_tag, span_source) =
crate::commands::open::fetch(
&full_path,
&location,
Span::unknown(),
)
.await?;
if let Some(uuid) = contents_tag.origin {
// If we have loaded something, track its source
context.add_span_source(uuid, span_source);
}
match contents {
Value::Primitive(Primitive::String(string)) => {
let value = crate::commands::open::parse_string_as_value(
file_extension,
string,
contents_tag,
Span::unknown(),
)?;
context
.shell_manager
.insert_at_current(Box::new(ValueShell::new(value)));
}
value => context.shell_manager.insert_at_current(Box::new(
ValueShell::new(value.tagged(contents_tag)),
)),
}
}
} }
CommandAction::PreviousShell => { CommandAction::PreviousShell => {
context.shell_manager.prev(); context.shell_manager.prev();

View File

@ -512,7 +512,7 @@ pub trait PerItemCommand: Send + Sync {
&self, &self,
call_info: &CallInfo, call_info: &CallInfo,
registry: &CommandRegistry, registry: &CommandRegistry,
shell_manager: &ShellManager, raw_args: &RawCommandArgs,
input: Tagged<Value>, input: Tagged<Value>,
) -> Result<OutputStream, ShellError>; ) -> Result<OutputStream, ShellError>;
@ -579,7 +579,7 @@ impl Command {
.call_info .call_info
.evaluate(&registry, &Scope::it_value(x.clone())) .evaluate(&registry, &Scope::it_value(x.clone()))
.unwrap(); .unwrap();
match command.run(&call_info, &registry, &raw_args.shell_manager, x) { match command.run(&call_info, &registry, &raw_args, x) {
Ok(o) => o, Ok(o) => o,
Err(e) => VecDeque::from(vec![ReturnValue::Err(e)]).to_output_stream(), Err(e) => VecDeque::from(vec![ReturnValue::Err(e)]).to_output_stream(),
} }
@ -596,7 +596,10 @@ impl Command {
.unwrap(); .unwrap();
// We don't have an $it or block, so just execute what we have // We don't have an $it or block, so just execute what we have
match command.run(&call_info, &registry, &raw_args.shell_manager, nothing) { match command
.run(&call_info, &registry, &raw_args, nothing)
.into()
{
Ok(o) => o, Ok(o) => o,
Err(e) => OutputStream::one(Err(e)), Err(e) => OutputStream::one(Err(e)),
} }

View File

@ -19,10 +19,10 @@ impl PerItemCommand for Cpy {
&self, &self,
call_info: &CallInfo, call_info: &CallInfo,
_registry: &CommandRegistry, _registry: &CommandRegistry,
shell_manager: &ShellManager, raw_args: &RawCommandArgs,
_input: Tagged<Value>, _input: Tagged<Value>,
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
call_info.process(shell_manager, cp)?.run() call_info.process(&raw_args.shell_manager, cp)?.run()
} }
fn name(&self) -> &str { fn name(&self) -> &str {

View File

@ -1,8 +1,10 @@
use crate::commands::command::CommandAction; use crate::commands::command::CommandAction;
use crate::commands::PerItemCommand; use crate::commands::PerItemCommand;
use crate::commands::UnevaluatedCallInfo;
use crate::errors::ShellError; use crate::errors::ShellError;
use crate::parser::registry; use crate::parser::registry;
use crate::prelude::*; use crate::prelude::*;
use std::path::PathBuf;
pub struct Enter; pub struct Enter;
@ -18,18 +20,109 @@ impl PerItemCommand for Enter {
fn run( fn run(
&self, &self,
call_info: &CallInfo, call_info: &CallInfo,
_registry: &registry::CommandRegistry, registry: &registry::CommandRegistry,
_shell_manager: &ShellManager, raw_args: &RawCommandArgs,
_input: Tagged<Value>, _input: Tagged<Value>,
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
let registry = registry.clone();
let raw_args = raw_args.clone();
match call_info.args.expect_nth(0)? { match call_info.args.expect_nth(0)? {
Tagged { Tagged {
item: Value::Primitive(Primitive::String(location)), item: Value::Primitive(Primitive::String(location)),
.. ..
} => Ok(vec![Ok(ReturnSuccess::Action(CommandAction::EnterShell( } => {
location.to_string(), let location = location.to_string();
)))] let location_clone = location.to_string();
.into()), if PathBuf::from(location).is_dir() {
Ok(vec![Ok(ReturnSuccess::Action(CommandAction::EnterShell(
location_clone,
)))]
.into())
} else {
let stream = async_stream_block! {
// If it's a file, attempt to open the file as a value and enter it
let cwd = raw_args.shell_manager.path();
let full_path = std::path::PathBuf::from(cwd);
let (file_extension, contents, contents_tag, span_source) =
crate::commands::open::fetch(
&full_path,
&location_clone,
Span::unknown(),
)
.await.unwrap();
if let Some(uuid) = contents_tag.origin {
// If we have loaded something, track its source
yield ReturnSuccess::action(CommandAction::AddSpanSource(
uuid,
span_source,
));
}
match contents {
Value::Primitive(Primitive::String(_)) => {
let tagged_contents = contents.tagged(contents_tag);
if let Some(extension) = file_extension {
let command_name = format!("from-{}", extension);
if let Some(converter) =
registry.get_command(&command_name)
{
let new_args = RawCommandArgs {
host: raw_args.host,
shell_manager: raw_args.shell_manager,
call_info: UnevaluatedCallInfo {
args: crate::parser::hir::Call {
head: raw_args.call_info.args.head,
positional: None,
named: None,
},
source: raw_args.call_info.source,
source_map: raw_args.call_info.source_map,
name_span: raw_args.call_info.name_span,
},
};
let mut result = converter.run(
new_args.with_input(vec![tagged_contents]),
&registry,
);
let result_vec: Vec<Result<ReturnSuccess, ShellError>> =
result.drain_vec().await;
for res in result_vec {
match res {
Ok(ReturnSuccess::Value(Tagged {
item,
..
})) => {
yield Ok(ReturnSuccess::Action(CommandAction::EnterValueShell(
Tagged {
item: item,
tag: contents_tag,
})));
}
x => yield x,
}
}
} else {
yield Ok(ReturnSuccess::Action(CommandAction::EnterValueShell(tagged_contents)));
}
} else {
yield Ok(ReturnSuccess::Action(CommandAction::EnterValueShell(tagged_contents)));
}
}
_ => {
let tagged_contents = contents.tagged(contents_tag);
yield Ok(ReturnSuccess::Action(CommandAction::EnterValueShell(tagged_contents)));
}
}
};
Ok(stream.to_output_stream())
}
}
x => Ok( x => Ok(
vec![Ok(ReturnSuccess::Action(CommandAction::EnterValueShell( vec![Ok(ReturnSuccess::Action(CommandAction::EnterValueShell(
x.clone(), x.clone(),

View File

@ -45,7 +45,7 @@ fn convert_bson_value_to_nu_value(v: &Bson, tag: impl Into<Tag>) -> Tagged<Value
collected.into_tagged_value() collected.into_tagged_value()
} }
Bson::Boolean(b) => Value::Primitive(Primitive::Boolean(*b)).tagged(tag), Bson::Boolean(b) => Value::Primitive(Primitive::Boolean(*b)).tagged(tag),
Bson::Null => Value::Primitive(Primitive::String(String::from(""))).tagged(tag), Bson::Null => Value::Primitive(Primitive::Nothing).tagged(tag),
Bson::RegExp(r, opts) => { Bson::RegExp(r, opts) => {
let mut collected = TaggedDictBuilder::new(tag); let mut collected = TaggedDictBuilder::new(tag);
collected.insert_tagged( collected.insert_tagged(

View File

@ -32,9 +32,7 @@ fn convert_json_value_to_nu_value(v: &serde_hjson::Value, tag: impl Into<Tag>) -
let tag = tag.into(); let tag = tag.into();
match v { match v {
serde_hjson::Value::Null => { serde_hjson::Value::Null => Value::Primitive(Primitive::Nothing).tagged(tag),
Value::Primitive(Primitive::String(String::from(""))).tagged(tag)
}
serde_hjson::Value::Bool(b) => Value::Primitive(Primitive::Boolean(*b)).tagged(tag), serde_hjson::Value::Bool(b) => Value::Primitive(Primitive::Boolean(*b)).tagged(tag),
serde_hjson::Value::F64(n) => { serde_hjson::Value::F64(n) => {
Value::Primitive(Primitive::Float(OF64::from(*n))).tagged(tag) Value::Primitive(Primitive::Float(OF64::from(*n))).tagged(tag)

166
src/commands/from_sqlite.rs Normal file
View File

@ -0,0 +1,166 @@
use crate::commands::WholeStreamCommand;
use crate::errors::ShellError;
use crate::object::base::OF64;
use crate::object::{Primitive, TaggedDictBuilder, Value};
use crate::prelude::*;
use rusqlite::{types::ValueRef, Connection, Row, NO_PARAMS};
use std::io::Write;
use std::path::Path;
pub struct FromSQLite;
impl WholeStreamCommand for FromSQLite {
fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
from_sqlite(args, registry)
}
fn name(&self) -> &str {
"from-sqlite"
}
fn signature(&self) -> Signature {
Signature::build("from-sqlite")
}
}
pub struct FromDB;
impl WholeStreamCommand for FromDB {
fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
from_sqlite(args, registry)
}
fn name(&self) -> &str {
"from-db"
}
fn signature(&self) -> Signature {
Signature::build("from-db")
}
}
pub fn convert_sqlite_file_to_nu_value(
path: &Path,
tag: impl Into<Tag> + Clone,
) -> Result<Tagged<Value>, rusqlite::Error> {
let conn = Connection::open(path)?;
let mut meta_out = Vec::new();
let mut meta_stmt = conn.prepare("select name from sqlite_master where type='table'")?;
let mut meta_rows = meta_stmt.query(NO_PARAMS)?;
while let Some(meta_row) = meta_rows.next()? {
let table_name: String = meta_row.get(0)?;
let mut meta_dict = TaggedDictBuilder::new(tag.clone());
let mut out = Vec::new();
let mut table_stmt = conn.prepare(&format!("select * from [{}]", table_name))?;
let mut table_rows = table_stmt.query(NO_PARAMS)?;
while let Some(table_row) = table_rows.next()? {
out.push(convert_sqlite_row_to_nu_value(table_row, tag.clone())?)
}
meta_dict.insert_tagged(
"table_name".to_string(),
Value::Primitive(Primitive::String(table_name)).tagged(tag.clone()),
);
meta_dict.insert_tagged("table_values", Value::List(out).tagged(tag.clone()));
meta_out.push(meta_dict.into_tagged_value());
}
let tag = tag.into();
Ok(Value::List(meta_out).tagged(tag))
}
fn convert_sqlite_row_to_nu_value(
row: &Row,
tag: impl Into<Tag> + Clone,
) -> Result<Tagged<Value>, rusqlite::Error> {
let mut collected = TaggedDictBuilder::new(tag.clone());
for (i, c) in row.columns().iter().enumerate() {
collected.insert_tagged(
c.name().to_string(),
convert_sqlite_value_to_nu_value(row.get_raw(i), tag.clone()),
);
}
return Ok(collected.into_tagged_value());
}
fn convert_sqlite_value_to_nu_value(value: ValueRef, tag: impl Into<Tag> + Clone) -> Tagged<Value> {
match value {
ValueRef::Null => Value::Primitive(Primitive::String(String::from(""))).tagged(tag),
ValueRef::Integer(i) => Value::Primitive(Primitive::Int(i)).tagged(tag),
ValueRef::Real(f) => Value::Primitive(Primitive::Float(OF64::from(f))).tagged(tag),
t @ ValueRef::Text(_) => {
// this unwrap is safe because we know the ValueRef is Text.
Value::Primitive(Primitive::String(t.as_str().unwrap().to_string())).tagged(tag)
}
ValueRef::Blob(u) => Value::Binary(u.to_owned()).tagged(tag),
}
}
pub fn from_sqlite_bytes_to_value(
mut bytes: Vec<u8>,
tag: impl Into<Tag> + Clone,
) -> Result<Tagged<Value>, std::io::Error> {
// FIXME: should probably write a sqlite virtual filesystem
// that will allow us to use bytes as a file to avoid this
// write out, but this will require C code. Might be
// best done as a PR to rusqlite.
let mut tempfile = tempfile::NamedTempFile::new()?;
tempfile.write_all(bytes.as_mut_slice())?;
match convert_sqlite_file_to_nu_value(tempfile.path(), tag) {
Ok(value) => Ok(value),
Err(e) => Err(std::io::Error::new(std::io::ErrorKind::Other, e)),
}
}
fn from_sqlite(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
let args = args.evaluate_once(registry)?;
let span = args.name_span();
let input = args.input;
let stream = async_stream_block! {
let values: Vec<Tagged<Value>> = input.values.collect().await;
for value in values {
let value_tag = value.tag();
match value.item {
Value::Binary(vb) =>
match from_sqlite_bytes_to_value(vb, span) {
Ok(x) => match x {
Tagged { item: Value::List(list), .. } => {
for l in list {
yield ReturnSuccess::value(l);
}
}
_ => yield ReturnSuccess::value(x),
}
Err(_) => {
yield Err(ShellError::labeled_error_with_secondary(
"Could not parse as SQLite",
"input cannot be parsed as SQLite",
span,
"value originates from here",
value_tag.span,
))
}
}
_ => yield Err(ShellError::labeled_error_with_secondary(
"Expected a string from pipeline",
"requires string input",
span,
"value originates from here",
value_tag.span,
)),
}
}
};
Ok(stream.to_output_stream())
}

View File

@ -23,6 +23,26 @@ impl WholeStreamCommand for FromYAML {
} }
} }
pub struct FromYML;
impl WholeStreamCommand for FromYML {
fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
from_yaml(args, registry)
}
fn name(&self) -> &str {
"from-yml"
}
fn signature(&self) -> Signature {
Signature::build("from-yml")
}
}
fn convert_yaml_value_to_nu_value(v: &serde_yaml::Value, tag: impl Into<Tag>) -> Tagged<Value> { fn convert_yaml_value_to_nu_value(v: &serde_yaml::Value, tag: impl Into<Tag>) -> Tagged<Value> {
let tag = tag.into(); let tag = tag.into();

View File

@ -16,10 +16,10 @@ impl PerItemCommand for Mkdir {
&self, &self,
call_info: &CallInfo, call_info: &CallInfo,
_registry: &CommandRegistry, _registry: &CommandRegistry,
shell_manager: &ShellManager, raw_args: &RawCommandArgs,
_input: Tagged<Value>, _input: Tagged<Value>,
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
call_info.process(shell_manager, mkdir)?.run() call_info.process(&raw_args.shell_manager, mkdir)?.run()
} }
fn name(&self) -> &str { fn name(&self) -> &str {

View File

@ -29,10 +29,10 @@ impl PerItemCommand for Move {
&self, &self,
call_info: &CallInfo, call_info: &CallInfo,
_registry: &CommandRegistry, _registry: &CommandRegistry,
shell_manager: &ShellManager, raw_args: &RawCommandArgs,
_input: Tagged<Value>, _input: Tagged<Value>,
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
call_info.process(shell_manager, mv)?.run() call_info.process(&raw_args.shell_manager, mv)?.run()
} }
} }

View File

@ -1,6 +1,7 @@
use crate::commands::UnevaluatedCallInfo;
use crate::context::SpanSource; use crate::context::SpanSource;
use crate::errors::ShellError; use crate::errors::ShellError;
use crate::object::{Primitive, Value}; use crate::object::Value;
use crate::parser::hir::SyntaxType; use crate::parser::hir::SyntaxType;
use crate::parser::registry::Signature; use crate::parser::registry::Signature;
use crate::prelude::*; use crate::prelude::*;
@ -25,15 +26,20 @@ impl PerItemCommand for Open {
fn run( fn run(
&self, &self,
call_info: &CallInfo, call_info: &CallInfo,
_registry: &CommandRegistry, registry: &CommandRegistry,
shell_manager: &ShellManager, raw_args: &RawCommandArgs,
_input: Tagged<Value>, _input: Tagged<Value>,
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
run(call_info, shell_manager) run(call_info, registry, raw_args)
} }
} }
fn run(call_info: &CallInfo, shell_manager: &ShellManager) -> Result<OutputStream, ShellError> { fn run(
call_info: &CallInfo,
registry: &CommandRegistry,
raw_args: &RawCommandArgs,
) -> Result<OutputStream, ShellError> {
let shell_manager = &raw_args.shell_manager;
let cwd = PathBuf::from(shell_manager.path()); let cwd = PathBuf::from(shell_manager.path());
let full_path = PathBuf::from(cwd); let full_path = PathBuf::from(cwd);
@ -47,8 +53,9 @@ fn run(call_info: &CallInfo, shell_manager: &ShellManager) -> Result<OutputStrea
let path_buf = path.as_path()?; let path_buf = path.as_path()?;
let path_str = path_buf.display().to_string(); let path_str = path_buf.display().to_string();
let path_span = path.span(); let path_span = path.span();
let name_span = call_info.name_span;
let has_raw = call_info.args.has("raw"); let has_raw = call_info.args.has("raw");
let registry = registry.clone();
let raw_args = raw_args.clone();
let stream = async_stream_block! { let stream = async_stream_block! {
@ -65,7 +72,6 @@ fn run(call_info: &CallInfo, shell_manager: &ShellManager) -> Result<OutputStrea
file_extension.or(path_str.split('.').last().map(String::from)) file_extension.or(path_str.split('.').last().map(String::from))
}; };
if let Some(uuid) = contents_tag.origin { if let Some(uuid) = contents_tag.origin {
// If we have loaded something, track its source // If we have loaded something, track its source
yield ReturnSuccess::action(CommandAction::AddSpanSource( yield ReturnSuccess::action(CommandAction::AddSpanSource(
@ -74,39 +80,46 @@ fn run(call_info: &CallInfo, shell_manager: &ShellManager) -> Result<OutputStrea
)); ));
} }
match contents { let tagged_contents = contents.tagged(contents_tag);
Value::Primitive(Primitive::String(string)) => {
let value = parse_string_as_value(file_extension, string, contents_tag, name_span).unwrap();
match value { if let Some(extension) = file_extension {
Tagged { let command_name = format!("from-{}", extension);
item: Value::List(list), if let Some(converter) = registry.get_command(&command_name) {
.. let new_args = RawCommandArgs {
} => { host: raw_args.host,
for elem in list { shell_manager: raw_args.shell_manager,
yield ReturnSuccess::value(elem); call_info: UnevaluatedCallInfo {
} args: crate::parser::hir::Call {
head: raw_args.call_info.args.head,
positional: None,
named: None
},
source: raw_args.call_info.source,
source_map: raw_args.call_info.source_map,
name_span: raw_args.call_info.name_span,
} }
x => yield ReturnSuccess::value(x), };
} let mut result = converter.run(new_args.with_input(vec![tagged_contents]), &registry);
} let result_vec: Vec<Result<ReturnSuccess, ShellError>> = result.drain_vec().await;
Value::Binary(binary) => { for res in result_vec {
let value = parse_binary_as_value(file_extension, binary, contents_tag, name_span).unwrap(); match res {
Ok(ReturnSuccess::Value(Tagged { item: Value::List(list), ..})) => {
match value { for l in list {
Tagged { yield Ok(ReturnSuccess::Value(l));
item: Value::List(list), }
..
} => {
for elem in list {
yield ReturnSuccess::value(elem);
} }
Ok(ReturnSuccess::Value(Tagged { item, .. })) => {
yield Ok(ReturnSuccess::Value(Tagged { item: item, tag: contents_tag }));
}
x => yield x,
} }
x => yield ReturnSuccess::value(x),
} }
} else {
yield ReturnSuccess::value(tagged_contents);
} }
other => yield ReturnSuccess::value(other.tagged(contents_tag)), } else {
}; yield ReturnSuccess::value(tagged_contents);
}
}; };
Ok(stream.to_output_stream()) Ok(stream.to_output_stream())
@ -419,114 +432,3 @@ fn read_be_u16(input: &[u8]) -> Option<Vec<u16>> {
Some(result) Some(result)
} }
} }
pub fn parse_string_as_value(
extension: Option<String>,
contents: String,
contents_tag: Tag,
name_span: Span,
) -> Result<Tagged<Value>, ShellError> {
match extension {
Some(ref x) if x == "csv" => {
crate::commands::from_csv::from_csv_string_to_value(contents, false, contents_tag)
.map_err(move |_| {
ShellError::labeled_error(
"Could not open as CSV",
"could not open as CSV",
name_span,
)
})
}
Some(ref x) if x == "tsv" => {
crate::commands::from_tsv::from_tsv_string_to_value(contents, false, contents_tag)
.map_err(move |_| {
ShellError::labeled_error(
"Could not open as TSV",
"could not open as TSV",
name_span,
)
})
}
Some(ref x) if x == "toml" => {
crate::commands::from_toml::from_toml_string_to_value(contents, contents_tag).map_err(
move |_| {
ShellError::labeled_error(
"Could not open as TOML",
"could not open as TOML",
name_span,
)
},
)
}
Some(ref x) if x == "json" => {
crate::commands::from_json::from_json_string_to_value(contents, contents_tag).map_err(
move |_| {
ShellError::labeled_error(
"Could not open as JSON",
"could not open as JSON",
name_span,
)
},
)
}
Some(ref x) if x == "ini" => crate::commands::from_ini::from_ini_string_to_value(
contents,
contents_tag,
)
.map_err(move |_| {
ShellError::labeled_error("Could not open as INI", "could not open as INI", name_span)
}),
Some(ref x) if x == "xml" => crate::commands::from_xml::from_xml_string_to_value(
contents,
contents_tag,
)
.map_err(move |_| {
ShellError::labeled_error("Could not open as XML", "could not open as XML", name_span)
}),
Some(ref x) if x == "yml" => {
crate::commands::from_yaml::from_yaml_string_to_value(contents, contents_tag).map_err(
move |_| {
ShellError::labeled_error(
"Could not open as YAML",
"could not open as YAML",
name_span,
)
},
)
}
Some(ref x) if x == "yaml" => {
crate::commands::from_yaml::from_yaml_string_to_value(contents, contents_tag).map_err(
move |_| {
ShellError::labeled_error(
"Could not open as YAML",
"could not open as YAML",
name_span,
)
},
)
}
_ => Ok(Value::string(contents).tagged(contents_tag)),
}
}
pub fn parse_binary_as_value(
extension: Option<String>,
contents: Vec<u8>,
contents_tag: Tag,
name_span: Span,
) -> Result<Tagged<Value>, ShellError> {
match extension {
Some(ref x) if x == "bson" => {
crate::commands::from_bson::from_bson_bytes_to_value(contents, contents_tag).map_err(
move |_| {
ShellError::labeled_error(
"Could not open as BSON",
"could not open as BSON",
name_span,
)
},
)
}
_ => Ok(Value::Binary(contents).tagged(contents_tag)),
}
}

View File

@ -1,8 +1,13 @@
use crate::commands::WholeStreamCommand; use crate::commands::WholeStreamCommand;
use crate::errors::ShellError; use crate::errors::ShellError;
use crate::object::process::process_dict; use crate::object::TaggedDictBuilder;
use crate::prelude::*; use crate::prelude::*;
use sysinfo::SystemExt; use std::time::Duration;
use std::usize;
use futures::stream::{StreamExt, TryStreamExt};
use heim::process::{self as process, Process, ProcessResult};
use heim::units::{ratio, Ratio};
pub struct PS; pub struct PS;
@ -24,28 +29,44 @@ impl WholeStreamCommand for PS {
} }
} }
fn ps(args: CommandArgs, _registry: &CommandRegistry) -> Result<OutputStream, ShellError> { async fn usage(process: Process) -> ProcessResult<(process::Process, Ratio)> {
let system; let usage_1 = process.cpu_usage().await?;
futures_timer::Delay::new(Duration::from_millis(100)).await?;
let usage_2 = process.cpu_usage().await?;
#[cfg(target_os = "linux")] Ok((process, usage_2 - usage_1))
{ }
system = sysinfo::System::new();
} fn ps(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
let args = args.evaluate_once(registry)?;
#[cfg(not(target_os = "linux"))] let span = args.name_span();
{
use sysinfo::RefreshKind; let stream = async_stream_block! {
let mut sy = sysinfo::System::new_with_specifics(RefreshKind::new().with_processes()); let processes = process::processes()
sy.refresh_processes(); .map_ok(|process| {
// Note that there is no `.await` here,
system = sy; // as we want to pass the returned future
} // into the `.try_buffer_unordered`.
let list = system.get_process_list(); usage(process)
})
let list = list .try_buffer_unordered(usize::MAX);
.into_iter() pin_utils::pin_mut!(processes);
.map(|(_, process)| process_dict(process, Tag::unknown_origin(args.call_info.name_span)))
.collect::<VecDeque<_>>(); while let Some(res) = processes.next().await {
if let Ok((process, usage)) = res {
Ok(list.from_input_stream()) let mut dict = TaggedDictBuilder::new(Tag::unknown_origin(span));
dict.insert("pid", Value::int(process.pid()));
if let Ok(name) = process.name().await {
dict.insert("name", Value::string(name));
}
if let Ok(status) = process.status().await {
dict.insert("status", Value::string(format!("{:?}", status)));
}
dict.insert("cpu", Value::float(usage.get::<ratio::percent>() as f64));
yield ReturnSuccess::value(dict.into_tagged_value());
}
}
};
Ok(stream.to_output_stream())
} }

View File

@ -28,10 +28,10 @@ impl PerItemCommand for Remove {
&self, &self,
call_info: &CallInfo, call_info: &CallInfo,
_registry: &CommandRegistry, _registry: &CommandRegistry,
shell_manager: &ShellManager, raw_args: &RawCommandArgs,
_input: Tagged<Value>, _input: Tagged<Value>,
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
call_info.process(shell_manager, rm)?.run() call_info.process(&raw_args.shell_manager, rm)?.run()
} }
} }

View File

@ -1,8 +1,4 @@
use crate::commands::to_csv::{to_string as to_csv_to_string, value_to_csv_value}; use crate::commands::UnevaluatedCallInfo;
use crate::commands::to_tsv::{to_string as to_tsv_to_string, value_to_tsv_value};
use crate::commands::to_json::value_to_json_value;
use crate::commands::to_toml::value_to_toml_value;
use crate::commands::to_yaml::value_to_yaml_value;
use crate::commands::WholeStreamCommand; use crate::commands::WholeStreamCommand;
use crate::errors::ShellError; use crate::errors::ShellError;
use crate::object::Value; use crate::object::Value;
@ -33,7 +29,7 @@ impl WholeStreamCommand for Save {
args: CommandArgs, args: CommandArgs,
registry: &CommandRegistry, registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
args.process(registry, save)?.run() Ok(args.process_raw(registry, save)?.run())
} }
} }
@ -47,16 +43,19 @@ fn save(
name, name,
shell_manager, shell_manager,
source_map, source_map,
host,
commands: registry,
.. ..
}: RunnableContext, }: RunnableContext,
raw_args: RawCommandArgs,
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
let mut full_path = PathBuf::from(shell_manager.path()); let mut full_path = PathBuf::from(shell_manager.path());
let name_span = name; let name_span = name;
if path.is_none() { let source_map = source_map.clone();
let source_map = source_map.clone(); let stream = async_stream_block! {
let stream = async_stream_block! { let input: Vec<Tagged<Value>> = input.values.collect().await;
let input: Vec<Tagged<Value>> = input.values.collect().await; if path.is_none() {
// If there is no filename, check the metadata for the origin filename // If there is no filename, check the metadata for the origin filename
if input.len() > 0 { if input.len() > 0 {
let origin = input[0].origin(); let origin = input[0].origin();
@ -88,50 +87,99 @@ fn save(
name_span, name_span,
)); ));
} }
} else {
let content = if !save_raw { if let Some(file) = path {
to_string_for(full_path.extension(), &input) full_path.push(file.item());
} else {
string_from(&input)
};
match content {
Ok(save_data) => match std::fs::write(full_path, save_data) {
Ok(o) => o,
Err(e) => yield Err(ShellError::string(e.to_string())),
},
Err(e) => yield Err(ShellError::string(e.to_string())),
} }
};
Ok(OutputStream::new(stream))
} else {
if let Some(file) = path {
full_path.push(file.item());
} }
let stream = async_stream_block! { let content = if !save_raw {
let input: Vec<Tagged<Value>> = input.values.collect().await; if let Some(extension) = full_path.extension() {
let command_name = format!("to-{}", extension.to_str().unwrap());
let content = if !save_raw { if let Some(converter) = registry.get_command(&command_name) {
to_string_for(full_path.extension(), &input) let new_args = RawCommandArgs {
host: host,
shell_manager: shell_manager,
call_info: UnevaluatedCallInfo {
args: crate::parser::hir::Call {
head: raw_args.call_info.args.head,
positional: None,
named: None
},
source: raw_args.call_info.source,
source_map: raw_args.call_info.source_map,
name_span: raw_args.call_info.name_span,
}
};
let mut result = converter.run(new_args.with_input(input), &registry);
let result_vec: Vec<Result<ReturnSuccess, ShellError>> = result.drain_vec().await;
let mut result_string = String::new();
for res in result_vec {
match res {
Ok(ReturnSuccess::Value(Tagged { item: Value::Primitive(Primitive::String(s)), .. })) => {
result_string.push_str(&s);
}
_ => {
yield Err(ShellError::labeled_error(
"Save could not successfully save",
"unexpected data during saveS",
name_span,
));
},
}
}
Ok(result_string)
} else {
let mut result_string = String::new();
for res in input {
match res {
Tagged { item: Value::Primitive(Primitive::String(s)), .. } => {
result_string.push_str(&s);
}
_ => {
yield Err(ShellError::labeled_error(
"Save could not successfully save",
"unexpected data during saveS",
name_span,
));
},
}
}
Ok(result_string)
}
} else { } else {
string_from(&input) let mut result_string = String::new();
}; for res in input {
match res {
match content { Tagged { item: Value::Primitive(Primitive::String(s)), .. } => {
Ok(save_data) => match std::fs::write(full_path, save_data) { result_string.push_str(&s);
Ok(o) => o, }
Err(e) => yield Err(ShellError::string(e.to_string())), _ => {
}, yield Err(ShellError::labeled_error(
Err(e) => yield Err(ShellError::string(e.to_string())), "Save could not successfully save",
"unexpected data during saveS",
name_span,
));
},
}
}
Ok(result_string)
} }
} else {
string_from(&input)
}; };
Ok(OutputStream::new(stream)) match content {
} Ok(save_data) => match std::fs::write(full_path, save_data) {
Ok(o) => o,
Err(e) => yield Err(ShellError::string(e.to_string())),
},
Err(e) => yield Err(ShellError::string(e.to_string())),
}
};
Ok(OutputStream::new(stream))
} }
fn string_from(input: &Vec<Tagged<Value>>) -> Result<String, ShellError> { fn string_from(input: &Vec<Tagged<Value>>) -> Result<String, ShellError> {
@ -153,66 +201,3 @@ fn string_from(input: &Vec<Tagged<Value>>) -> Result<String, ShellError> {
Ok(save_data) Ok(save_data)
} }
fn to_string_for(
ext: Option<&std::ffi::OsStr>,
input: &Vec<Tagged<Value>>,
) -> Result<String, ShellError> {
let contents = match ext {
Some(x) if x == "csv" => {
if input.len() != 1 {
return Err(ShellError::string(
"saving to csv requires a single object (or use --raw)",
));
}
to_csv_to_string(&value_to_csv_value(&input[0]))?
}
Some(x) if x == "tsv" => {
if input.len() != 1 {
return Err(ShellError::string(
"saving to tsv requires a single object (or use --raw)",
));
}
to_tsv_to_string(&value_to_tsv_value(&input[0]))?
}
Some(x) if x == "toml" => {
if input.len() != 1 {
return Err(ShellError::string(
"saving to toml requires a single object (or use --raw)",
));
}
toml::to_string(&value_to_toml_value(&input[0]))?
}
Some(x) if x == "json" => {
if input.len() != 1 {
return Err(ShellError::string(
"saving to json requires a single object (or use --raw)",
));
}
serde_json::to_string(&value_to_json_value(&input[0]))?
}
Some(x) if x == "yml" => {
if input.len() != 1 {
return Err(ShellError::string(
"saving to yml requires a single object (or use --raw)",
));
}
serde_yaml::to_string(&value_to_yaml_value(&input[0]))?
}
Some(x) if x == "yaml" => {
if input.len() != 1 {
return Err(ShellError::string(
"saving to yaml requires a single object (or use --raw)",
));
}
serde_yaml::to_string(&value_to_yaml_value(&input[0]))?
}
_ => {
return Err(ShellError::string(
"tried saving a single object with an unrecognized format.",
))
}
};
Ok(contents)
}

203
src/commands/to_sqlite.rs Normal file
View File

@ -0,0 +1,203 @@
use crate::commands::WholeStreamCommand;
use crate::object::{Dictionary, Primitive, Value};
use crate::prelude::*;
use hex::encode;
use rusqlite::{Connection, NO_PARAMS};
use std::io::Read;
pub struct ToSQLite;
impl WholeStreamCommand for ToSQLite {
fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
to_sqlite(args, registry)
}
fn name(&self) -> &str {
"to-sqlite"
}
fn signature(&self) -> Signature {
Signature::build("to-sqlite")
}
}
pub struct ToDB;
impl WholeStreamCommand for ToDB {
fn run(
&self,
args: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
to_sqlite(args, registry)
}
fn name(&self) -> &str {
"to-db"
}
fn signature(&self) -> Signature {
Signature::build("to-db")
}
}
fn comma_concat(acc: String, current: String) -> String {
if acc == "" {
current
} else {
format!("{}, {}", acc, current)
}
}
fn get_columns(rows: &Vec<Tagged<Value>>) -> Result<String, std::io::Error> {
match &rows[0].item {
Value::Object(d) => Ok(d
.entries
.iter()
.map(|(k, _v)| k.clone())
.fold("".to_string(), comma_concat)),
_ => Err(std::io::Error::new(
std::io::ErrorKind::Other,
"Could not find table column names",
)),
}
}
fn nu_value_to_sqlite_string(v: Value) -> String {
match v {
Value::Binary(u) => format!("x'{}'", encode(u)),
Value::Primitive(p) => match p {
Primitive::Nothing => "NULL".into(),
Primitive::Int(i) => format!("{}", i),
Primitive::Float(f) => format!("{}", f.into_inner()),
Primitive::Bytes(u) => format!("{}", u),
Primitive::String(s) => format!("'{}'", s.replace("'", "''")),
Primitive::Boolean(true) => "1".into(),
Primitive::Boolean(_) => "0".into(),
Primitive::Date(d) => format!("'{}'", d),
Primitive::Path(p) => format!("'{}'", p.display().to_string().replace("'", "''")),
Primitive::BeginningOfStream => "NULL".into(),
Primitive::EndOfStream => "NULL".into(),
},
_ => "NULL".into(),
}
}
fn get_insert_values(rows: Vec<Tagged<Value>>) -> Result<String, std::io::Error> {
let values: Result<Vec<_>, _> = rows
.into_iter()
.map(|value| match value.item {
Value::Object(d) => Ok(format!(
"({})",
d.entries
.iter()
.map(|(_k, v)| nu_value_to_sqlite_string(v.item.clone()))
.fold("".to_string(), comma_concat)
)),
_ => Err(std::io::Error::new(
std::io::ErrorKind::Other,
"Could not find table column names",
)),
})
.collect();
let values = values?;
Ok(values.into_iter().fold("".to_string(), comma_concat))
}
fn generate_statements(table: Dictionary) -> Result<(String, String), std::io::Error> {
let table_name = match table.entries.get("table_name") {
Some(Tagged {
item: Value::Primitive(Primitive::String(table_name)),
..
}) => table_name,
_ => {
return Err(std::io::Error::new(
std::io::ErrorKind::Other,
"Could not find table name",
))
}
};
let (columns, insert_values) = match table.entries.get("table_values") {
Some(Tagged {
item: Value::List(l),
..
}) => (get_columns(l), get_insert_values(l.to_vec())),
_ => {
return Err(std::io::Error::new(
std::io::ErrorKind::Other,
"Could not find table values",
))
}
};
let create = format!("create table {}({})", table_name, columns?);
let insert = format!("insert into {} values {}", table_name, insert_values?);
Ok((create, insert))
}
fn sqlite_input_stream_to_bytes(
values: Vec<Tagged<Value>>,
) -> Result<Tagged<Value>, std::io::Error> {
// FIXME: should probably write a sqlite virtual filesystem
// that will allow us to use bytes as a file to avoid this
// write out, but this will require C code. Might be
// best done as a PR to rusqlite.
let mut tempfile = tempfile::NamedTempFile::new()?;
let conn = match Connection::open(tempfile.path()) {
Ok(conn) => conn,
Err(e) => return Err(std::io::Error::new(std::io::ErrorKind::Other, e)),
};
let tag = values[0].tag.clone();
for value in values.into_iter() {
match value.item() {
Value::Object(d) => {
let (create, insert) = generate_statements(d.to_owned())?;
match conn
.execute(&create, NO_PARAMS)
.and_then(|_| conn.execute(&insert, NO_PARAMS))
{
Ok(_) => (),
Err(e) => {
println!("{}", create);
println!("{}", insert);
println!("{:?}", e);
return Err(std::io::Error::new(std::io::ErrorKind::Other, e));
}
}
}
other => {
return Err(std::io::Error::new(
std::io::ErrorKind::Other,
format!("Expected object, found {:?}", other),
))
}
}
}
let mut out = Vec::new();
tempfile.read_to_end(&mut out)?;
Ok(Value::Binary(out).tagged(tag))
}
fn to_sqlite(args: CommandArgs, registry: &CommandRegistry) -> Result<OutputStream, ShellError> {
let args = args.evaluate_once(registry)?;
let name_span = args.name_span();
let stream = async_stream_block! {
let values: Vec<_> = args.input.into_vec().await;
match sqlite_input_stream_to_bytes(values) {
Ok(out) => {
yield ReturnSuccess::value(out)
}
Err(_) => {
yield Err(ShellError::labeled_error(
"Expected an object with SQLite-compatible structure from pipeline",
"requires SQLite-compatible input",
name_span,
))
}
};
};
Ok(stream.to_output_stream())
}

View File

@ -19,7 +19,7 @@ impl PerItemCommand for Where {
&self, &self,
call_info: &CallInfo, call_info: &CallInfo,
_registry: &registry::CommandRegistry, _registry: &registry::CommandRegistry,
_shell_manager: &ShellManager, _raw_args: &RawCommandArgs,
input: Tagged<Value>, input: Tagged<Value>,
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
let input_clone = input.clone(); let input_clone = input.clone();

View File

@ -4,7 +4,6 @@ pub(crate) mod dict;
pub(crate) mod files; pub(crate) mod files;
pub(crate) mod into; pub(crate) mod into;
pub(crate) mod meta; pub(crate) mod meta;
pub(crate) mod process;
pub(crate) mod types; pub(crate) mod types;
#[allow(unused)] #[allow(unused)]

View File

@ -1,29 +0,0 @@
use crate::object::{TaggedDictBuilder, Value};
use crate::prelude::*;
use itertools::join;
use sysinfo::ProcessExt;
pub(crate) fn process_dict(proc: &sysinfo::Process, tag: impl Into<Tag>) -> Tagged<Value> {
let mut dict = TaggedDictBuilder::new(tag);
let cmd = proc.cmd();
let cmd_value = if cmd.len() == 0 {
Value::nothing()
} else {
Value::string(join(cmd, ""))
};
dict.insert("pid", Value::int(proc.pid() as i64));
dict.insert("status", Value::string(proc.status().to_string()));
dict.insert("cpu", Value::float(proc.cpu_usage() as f64));
//dict.insert("name", Value::string(proc.name()));
match cmd_value {
Value::Primitive(Primitive::Nothing) => {
dict.insert("name", Value::string(proc.name()));
}
_ => dict.insert("name", cmd_value),
}
dict.into_tagged_value()
}

View File

@ -39,11 +39,11 @@ pub fn path(head: impl Into<Expression>, tail: Vec<Tagged<impl Into<String>>>) -
#[derive(Debug, Clone, Eq, PartialEq, Getters, Serialize, Deserialize, new)] #[derive(Debug, Clone, Eq, PartialEq, Getters, Serialize, Deserialize, new)]
pub struct Call { pub struct Call {
#[get = "crate"] #[get = "crate"]
head: Box<Expression>, pub head: Box<Expression>,
#[get = "crate"] #[get = "crate"]
positional: Option<Vec<Expression>>, pub positional: Option<Vec<Expression>>,
#[get = "crate"] #[get = "crate"]
named: Option<NamedArguments>, pub named: Option<NamedArguments>,
} }
impl Call { impl Call {

View File

@ -52,6 +52,7 @@ pub(crate) use crate::commands::command::{
CallInfo, CommandAction, CommandArgs, ReturnSuccess, ReturnValue, RunnableContext, CallInfo, CommandAction, CommandArgs, ReturnSuccess, ReturnValue, RunnableContext,
}; };
pub(crate) use crate::commands::PerItemCommand; pub(crate) use crate::commands::PerItemCommand;
pub(crate) use crate::commands::RawCommandArgs;
pub(crate) use crate::context::CommandRegistry; pub(crate) use crate::context::CommandRegistry;
pub(crate) use crate::context::{Context, SpanSource}; pub(crate) use crate::context::{Context, SpanSource};
pub(crate) use crate::env::host::handle_unexpected; pub(crate) use crate::env::host::handle_unexpected;

View File

@ -266,6 +266,10 @@ mod tests {
loc: fixtures().join("sample.bson"), loc: fixtures().join("sample.bson"),
at: 0 at: 0
}, },
Res {
loc: fixtures().join("sample.db"),
at: 0
},
Res { Res {
loc: fixtures().join("sample.ini"), loc: fixtures().join("sample.ini"),
at: 0 at: 0

View File

@ -6,23 +6,22 @@ use helpers::{Playground, Stub::*};
#[test] #[test]
fn recognizes_csv() { fn recognizes_csv() {
Playground::setup("open_test_1", |dirs, sandbox| { Playground::setup("open_test_1", |dirs, sandbox| {
sandbox sandbox.with_files(vec![FileWithContentToBeTrimmed(
.with_files(vec![FileWithContentToBeTrimmed( "nu.zion.csv",
"nu.zion.csv", r#"
r#"
author,lang,source author,lang,source
Jonathan Turner,Rust,New Zealand Jonathan Turner,Rust,New Zealand
Andres N. Robalino,Rust,Ecuador Andres N. Robalino,Rust,Ecuador
Yehuda Katz,Rust,Estados Unidos Yehuda Katz,Rust,Estados Unidos
"# "#,
)]); )]);
let actual = nu!( let actual = nu!(
cwd: dirs.test(), h::pipeline( cwd: dirs.test(), h::pipeline(
r#" r#"
open nu.zion.csv open nu.zion.csv
| where author == "Andres N. Robalino" | where author == "Andres N. Robalino"
| get source | get source
| echo $it | echo $it
"# "#
)); ));
@ -46,11 +45,11 @@ fn open_can_parse_bson_2() {
let actual = nu!( let actual = nu!(
cwd: "tests/fixtures/formats", h::pipeline( cwd: "tests/fixtures/formats", h::pipeline(
r#" r#"
open sample.bson open sample.bson
| get root | get root
| nth 6 | nth 6
| get b | get b
| get '$binary_subtype' | get '$binary_subtype'
| echo $it | echo $it
"# "#
)); ));
@ -58,6 +57,21 @@ fn open_can_parse_bson_2() {
assert_eq!(actual, "function"); assert_eq!(actual, "function");
} }
#[test]
fn open_can_parse_sqlite() {
let actual = nu!(
cwd: "tests/fixtures/formats", h::pipeline(
r#"
open sample.db
| get table_values
| nth 2
| get x
| echo $it"#
));
assert_eq!(actual, "hello");
}
#[test] #[test]
fn open_can_parse_toml() { fn open_can_parse_toml() {
let actual = nu!( let actual = nu!(
@ -74,8 +88,8 @@ fn open_can_parse_tsv() {
cwd: "tests/fixtures/formats", h::pipeline( cwd: "tests/fixtures/formats", h::pipeline(
r#" r#"
open caco3_plastics.tsv open caco3_plastics.tsv
| first 1 | first 1
| get origin | get origin
| echo $it | echo $it
"# "#
)); ));
@ -88,8 +102,8 @@ fn open_can_parse_json() {
let actual = nu!( let actual = nu!(
cwd: "tests/fixtures/formats", h::pipeline( cwd: "tests/fixtures/formats", h::pipeline(
r#" r#"
open sgml_description.json open sgml_description.json
| get glossary.GlossDiv.GlossList.GlossEntry.GlossSee | get glossary.GlossDiv.GlossList.GlossEntry.GlossSee
| echo $it | echo $it
"# "#
)); ));

View File

@ -16,14 +16,13 @@ fn can_convert_table_to_csv_text_and_from_csv_text_back_into_table() {
#[test] #[test]
fn converts_structured_table_to_csv_text() { fn converts_structured_table_to_csv_text() {
Playground::setup("filter_to_csv_test_1", |dirs, sandbox| { Playground::setup("filter_to_csv_test_1", |dirs, sandbox| {
sandbox sandbox.with_files(vec![FileWithContentToBeTrimmed(
.with_files(vec![FileWithContentToBeTrimmed( "csv_text_sample.txt",
"csv_text_sample.txt", r#"
r#"
importer,shipper,tariff_item,name,origin importer,shipper,tariff_item,name,origin
Plasticos Rival,Reverte,2509000000,Calcium carbonate,Spain Plasticos Rival,Reverte,2509000000,Calcium carbonate,Spain
Tigre Ecuador,OMYA Andina,3824909999,Calcium carbonate,Colombia Tigre Ecuador,OMYA Andina,3824909999,Calcium carbonate,Colombia
"# "#,
)]); )]);
let actual = nu!( let actual = nu!(
@ -47,14 +46,13 @@ fn converts_structured_table_to_csv_text() {
#[test] #[test]
fn converts_structured_table_to_csv_text_skipping_headers_after_conversion() { fn converts_structured_table_to_csv_text_skipping_headers_after_conversion() {
Playground::setup("filter_to_csv_test_2", |dirs, sandbox| { Playground::setup("filter_to_csv_test_2", |dirs, sandbox| {
sandbox sandbox.with_files(vec![FileWithContentToBeTrimmed(
.with_files(vec![FileWithContentToBeTrimmed( "csv_text_sample.txt",
"csv_text_sample.txt", r#"
r#"
importer,shipper,tariff_item,name,origin importer,shipper,tariff_item,name,origin
Plasticos Rival,Reverte,2509000000,Calcium carbonate,Spain Plasticos Rival,Reverte,2509000000,Calcium carbonate,Spain
Tigre Ecuador,OMYA Andina,3824909999,Calcium carbonate,Colombia Tigre Ecuador,OMYA Andina,3824909999,Calcium carbonate,Colombia
"# "#,
)]); )]);
let actual = nu!( let actual = nu!(
@ -76,10 +74,9 @@ fn converts_structured_table_to_csv_text_skipping_headers_after_conversion() {
#[test] #[test]
fn converts_from_csv_text_to_structured_table() { fn converts_from_csv_text_to_structured_table() {
Playground::setup("filter_from_csv_test_1", |dirs, sandbox| { Playground::setup("filter_from_csv_test_1", |dirs, sandbox| {
sandbox sandbox.with_files(vec![FileWithContentToBeTrimmed(
.with_files(vec![FileWithContentToBeTrimmed( "los_tres_amigos.txt",
"los_tres_amigos.txt", r#"
r#"
first_name,last_name,rusty_luck first_name,last_name,rusty_luck
Andrés,Robalino,1 Andrés,Robalino,1
Jonathan,Turner,1 Jonathan,Turner,1
@ -106,10 +103,9 @@ fn converts_from_csv_text_to_structured_table() {
#[test] #[test]
fn converts_from_csv_text_skipping_headers_to_structured_table() { fn converts_from_csv_text_skipping_headers_to_structured_table() {
Playground::setup("filter_from_csv_test_2", |dirs, sandbox| { Playground::setup("filter_from_csv_test_2", |dirs, sandbox| {
sandbox sandbox.with_files(vec![FileWithContentToBeTrimmed(
.with_files(vec![FileWithContentToBeTrimmed( "los_tres_amigos.txt",
"los_tres_amigos.txt", r#"
r#"
first_name,last_name,rusty_luck first_name,last_name,rusty_luck
Andrés,Robalino,1 Andrés,Robalino,1
Jonathan,Turner,1 Jonathan,Turner,1
@ -152,10 +148,9 @@ fn can_convert_table_to_json_text_and_from_json_text_back_into_table() {
#[test] #[test]
fn converts_from_json_text_to_structured_table() { fn converts_from_json_text_to_structured_table() {
Playground::setup("filter_from_json_test_1", |dirs, sandbox| { Playground::setup("filter_from_json_test_1", |dirs, sandbox| {
sandbox sandbox.with_files(vec![FileWithContentToBeTrimmed(
.with_files(vec![FileWithContentToBeTrimmed( "katz.txt",
"katz.txt", r#"
r#"
{ {
"katz": [ "katz": [
{"name": "Yehuda", "rusty_luck": 1}, {"name": "Yehuda", "rusty_luck": 1},
@ -173,17 +168,15 @@ fn converts_from_json_text_to_structured_table() {
); );
assert_eq!(actual, "4"); assert_eq!(actual, "4");
}) })
} }
#[test] #[test]
fn converts_from_json_text_recognizing_objects_independendtly_to_structured_table() { fn converts_from_json_text_recognizing_objects_independendtly_to_structured_table() {
Playground::setup("filter_from_json_test_2", |dirs, sandbox| { Playground::setup("filter_from_json_test_2", |dirs, sandbox| {
sandbox sandbox.with_files(vec![FileWithContentToBeTrimmed(
.with_files(vec![FileWithContentToBeTrimmed( "katz.txt",
"katz.txt", r#"
r#"
{"name": "Yehuda", "rusty_luck": 1} {"name": "Yehuda", "rusty_luck": 1}
{"name": "Jonathan", "rusty_luck": 1} {"name": "Jonathan", "rusty_luck": 1}
{"name": "Andres", "rusty_luck": 1} {"name": "Andres", "rusty_luck": 1}
@ -209,10 +202,9 @@ fn converts_from_json_text_recognizing_objects_independendtly_to_structured_tabl
#[test] #[test]
fn converts_structured_table_to_json_text() { fn converts_structured_table_to_json_text() {
Playground::setup("filter_to_json_test", |dirs, sandbox| { Playground::setup("filter_to_json_test", |dirs, sandbox| {
sandbox sandbox.with_files(vec![FileWithContentToBeTrimmed(
.with_files(vec![FileWithContentToBeTrimmed( "sample.txt",
"sample.txt", r#"
r#"
JonAndrehudaTZ,3 JonAndrehudaTZ,3
GorbyPuff,100 GorbyPuff,100
"#, "#,
@ -250,14 +242,13 @@ fn can_convert_table_to_tsv_text_and_from_tsv_text_back_into_table() {
#[test] #[test]
fn converts_structured_table_to_tsv_text() { fn converts_structured_table_to_tsv_text() {
Playground::setup("filter_to_tsv_test_1", |dirs, sandbox| { Playground::setup("filter_to_tsv_test_1", |dirs, sandbox| {
sandbox sandbox.with_files(vec![FileWithContentToBeTrimmed(
.with_files(vec![FileWithContentToBeTrimmed( "tsv_text_sample.txt",
"tsv_text_sample.txt", r#"
r#"
importer shipper tariff_item name origin importer shipper tariff_item name origin
Plasticos Rival Reverte 2509000000 Calcium carbonate Spain Plasticos Rival Reverte 2509000000 Calcium carbonate Spain
Tigre Ecuador OMYA Andina 3824909999 Calcium carbonate Colombia Tigre Ecuador OMYA Andina 3824909999 Calcium carbonate Colombia
"# "#,
)]); )]);
let actual = nu!( let actual = nu!(
@ -281,14 +272,13 @@ fn converts_structured_table_to_tsv_text() {
#[test] #[test]
fn converts_structured_table_to_tsv_text_skipping_headers_after_conversion() { fn converts_structured_table_to_tsv_text_skipping_headers_after_conversion() {
Playground::setup("filter_to_tsv_test_2", |dirs, sandbox| { Playground::setup("filter_to_tsv_test_2", |dirs, sandbox| {
sandbox sandbox.with_files(vec![FileWithContentToBeTrimmed(
.with_files(vec![FileWithContentToBeTrimmed( "tsv_text_sample.txt",
"tsv_text_sample.txt", r#"
r#"
importer shipper tariff_item name origin importer shipper tariff_item name origin
Plasticos Rival Reverte 2509000000 Calcium carbonate Spain Plasticos Rival Reverte 2509000000 Calcium carbonate Spain
Tigre Ecuador OMYA Andina 3824909999 Calcium carbonate Colombia Tigre Ecuador OMYA Andina 3824909999 Calcium carbonate Colombia
"# "#,
)]); )]);
let actual = nu!( let actual = nu!(
@ -310,10 +300,9 @@ fn converts_structured_table_to_tsv_text_skipping_headers_after_conversion() {
#[test] #[test]
fn converts_from_tsv_text_to_structured_table() { fn converts_from_tsv_text_to_structured_table() {
Playground::setup("filter_from_tsv_test_1", |dirs, sandbox| { Playground::setup("filter_from_tsv_test_1", |dirs, sandbox| {
sandbox sandbox.with_files(vec![FileWithContentToBeTrimmed(
.with_files(vec![FileWithContentToBeTrimmed( "los_tres_amigos.txt",
"los_tres_amigos.txt", r#"
r#"
first Name Last Name rusty_luck first Name Last Name rusty_luck
Andrés Robalino 1 Andrés Robalino 1
Jonathan Turner 1 Jonathan Turner 1
@ -340,10 +329,9 @@ fn converts_from_tsv_text_to_structured_table() {
#[test] #[test]
fn converts_from_tsv_text_skipping_headers_to_structured_table() { fn converts_from_tsv_text_skipping_headers_to_structured_table() {
Playground::setup("filter_from_tsv_test_2", |dirs, sandbox| { Playground::setup("filter_from_tsv_test_2", |dirs, sandbox| {
sandbox sandbox.with_files(vec![FileWithContentToBeTrimmed(
.with_files(vec![FileWithContentToBeTrimmed( "los_tres_amigos.txt",
"los_tres_amigos.txt", r#"
r#"
first Name Last Name rusty_luck first Name Last Name rusty_luck
Andrés Robalino 1 Andrés Robalino 1
Jonathan Turner 1 Jonathan Turner 1
@ -354,11 +342,11 @@ fn converts_from_tsv_text_skipping_headers_to_structured_table() {
let actual = nu!( let actual = nu!(
cwd: dirs.test(), h::pipeline( cwd: dirs.test(), h::pipeline(
r#" r#"
open los_tres_amigos.txt open los_tres_amigos.txt
| from-tsv --headerless | from-tsv --headerless
| get Column3 | get Column3
| str --to-int | str --to-int
| sum | sum
| echo $it | echo $it
"# "#
)); ));
@ -368,21 +356,50 @@ fn converts_from_tsv_text_skipping_headers_to_structured_table() {
} }
#[test] #[test]
fn can_convert_json_text_to_bson_and_back_into_table() { fn can_convert_table_to_bson_and_back_into_table() {
let actual = nu!( let actual = nu!(
cwd: "tests/fixtures/formats", cwd: "tests/fixtures/formats", h::pipeline(
"open sample.bson | to-bson | from-bson | get root | nth 1 | get b | echo $it" r#"
); open sample.bson
| to-bson
| from-bson
| get root
| nth 1
| get b
| echo $it"#
));
assert_eq!(actual, "whel"); assert_eq!(actual, "whel");
} }
#[test]
fn can_convert_table_to_sqlite_and_back_into_table() {
let actual = nu!(
cwd: "tests/fixtures/formats", h::pipeline(
r#"
open sample.db
| to-sqlite
| from-sqlite
| get table_values
| nth 2
| get x
| echo $it"#
));
assert_eq!(actual, "hello");
}
#[test] #[test]
fn can_convert_table_to_toml_text_and_from_toml_text_back_into_table() { fn can_convert_table_to_toml_text_and_from_toml_text_back_into_table() {
let actual = nu!( let actual = nu!(
cwd: "tests/fixtures/formats", cwd: "tests/fixtures/formats", h::pipeline(
"open cargo_sample.toml | to-toml | from-toml | get package.name | echo $it" r#"
); open cargo_sample.toml
| to-toml
| from-toml
| get package.name
| echo $it"#
));
assert_eq!(actual, "nu"); assert_eq!(actual, "nu");
} }

BIN
tests/fixtures/formats/sample.db vendored Normal file

Binary file not shown.