├── .gitignore ├── .travis.yml ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── appveyor.yml ├── bors.toml ├── ergo ├── Cargo.toml └── src │ ├── deep_copy.rs │ └── lib.rs ├── ergo_config ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── appveyor.yml ├── bors.toml └── src │ └── lib.rs ├── ergo_fs ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── appveyor.yml ├── bors.toml ├── notes.md └── src │ ├── glob_wrapper.rs │ ├── lib.rs │ └── tmp.rs ├── ergo_std ├── .gitignore ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── appveyor.yml ├── bors.toml └── src │ └── lib.rs ├── ergo_sync ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── appveyor.yml ├── bors.toml └── src │ ├── ch.rs │ ├── lib.rs │ └── scoped.rs └── ergo_sys ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── appveyor.yml ├── bors.toml └── src └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /target/ 3 | **/*.rs.bk 4 | Cargo.lock 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | 3 | branches: 4 | only: 5 | - master 6 | # This is where pull requests from "bors r+" are built. 7 | - staging 8 | # This is where pull requests from "bors try" are built. 9 | - trying 10 | 11 | rust: 12 | - stable 13 | - beta 14 | - nightly 15 | 16 | matrix: 17 | allow_failures: 18 | - rust: nightly 19 | 20 | cache: cargo 21 | 22 | notifications: 23 | email: 24 | on_success: never 25 | 26 | script: 27 | - RUST_BACKTRACE=1 cargo test --verbose --all -- --nocapture 28 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | 3 | members = [ 4 | "ergo", 5 | "ergo_config", 6 | "ergo_fs", 7 | "ergo_std", 8 | "ergo_sync", 9 | "ergo_sys", 10 | ] 11 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Copyright 2018 Garrett Berg, vitiral@gmail.com 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Garrett Berg, vitiral@gmail.com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ergo: making rust's ecosystem more ergonomic, therefore more fun. 2 | 3 | [![Build Status](https://travis-ci.org/rust-crates/ergo.svg?branch=master)](https://travis-ci.org/rust-crates/ergo) 4 | [![Build status](https://ci.appveyor.com/api/projects/status/iet58b7gj9jh19mt?svg=true)](https://ci.appveyor.com/project/vitiral/ergo-5l7h9) 5 | [![Docs](https://docs.rs/ergo/badge.svg)](https://docs.rs/ergo) 6 | 7 | 8 | _The Ergo Ecosystem_ is an effort to unify the rust ecosystem at critical 9 | sections. It is currently focused on improving Command Line Interface (CLI) 10 | ergonomics. To accomplish this it will create _multiple targeted 11 | conglomeration_ crates. These crates do much more than simply exporting the 12 | API of their sub-crates. They implement wrapper types to unify them, as well 13 | as have tested documentation to ensure they interopate together reliably. 14 | 15 | @autron said it best in the 16 | [rust 2018 roadmap](https://github.com/aturon/rfcs/blob/roadmap-2018/text/0000-roadmap-2018.md#cli-apps) 17 | 18 | > ### CLI apps 19 | > > Rust is a fantastic language for writing a Command Line Application (CLI). 20 | > > For the ergonomics of hacking, it has one of the best argument parsers 21 | > > ever, has seriously the best serialization library ever and it compiles to 22 | > > almost any target and goes fast when it runs. (@vitiral) 23 | > 24 | > Rust has also seem some production update in the CLI space, for which it is 25 | > very well-suited. This is a space where Rust’s portability, reliability, and 26 | > ability to produce static binaries make it extremely attractive. We also have a 27 | > number of excellent libraries already. This year, we will improve this 28 | > ecosystem and pull it together into a polished, coherent package for people 29 | > checking out Rust. Read @vitiral’s post and @killercup’s crate for some 30 | > inspiration! 31 | 32 | 33 | # Vision 34 | Ergo's current goal is to be a full featured CLI SDK, built from composable 35 | and distinct sub components. You should be able to depend on the `ergo` library 36 | itself or each of its sub components individually. 37 | 38 | Ergo aims to provide the following benefits: 39 | - A standardized API for disparate types/approaches, allowing library authors 40 | to develop simple libraries of high quality, which can then be combined into 41 | an ecosystem with a unified API and excellent ergonomics. 42 | - A starting point for CLI and application developers for documentation and 43 | *How To* guides. We hope to release an **Ergo Cookbook** once the libraries 44 | are more stable. 45 | - Encourage interopability, quality, and ergonomic errors among the major CLI 46 | crates in the rust ecosystem and act as a driver towards higher quality and 47 | uniformity. 48 | 49 | 50 | # Sub Crates 51 | The ergo ecosystem is split into multiple crates, each with the prefix `ergo_` 52 | 53 | The `ergo` crate itself is _currently in alpha status_. The primary author is 54 | rewriting his CLI application using it to get the rough edges ironed out and 55 | we are looking for feedback, contributors and leaders from the community 56 | during this time 57 | 58 | For now, consuder using [quicli](https://github.com/killercup/quicli) which 59 | will [integrate cleanly with the ergo 60 | ecosystem](https://github.com/killercup/quicli/issues/43) in the future. 61 | If you _do_ use this crate expect frequenty changes that are not semver 62 | compliant. 63 | 64 | 65 | ## Implemented Sub Crates 66 | - [x] [**ergo_fs**](https://github.com/vitiral/ergo_fs): ergonomic filesystem 67 | operations. (_beta status_) 68 | - [x] [**ergo_sync**](https://github.com/rust-crates/ergo_sync): provides an 69 | ultra-simple API for using `Sync` types, i.e. running threads and sending 70 | messages. (_beta status_) 71 | - [x] [**ergo_std**](https://github.com/rust-crates/ergo_std): "generally 72 | needed stuff" -- `regex`, `lazy_static`, `maplit`, `itertools`, `ordermap`. 73 | This will be _very few crates_. It is mostly composed of things which could 74 | practically be in the std library. (_beta status_) 75 | - [x] [**ergo_config**](https://github.com/rust-crates/ergo_config): 76 | deserialization and config files and ENV variables: `ron`, `toml`, 77 | `serde_json`, `serde_yaml`, `configure` (_alpha status_) 78 | - [x] [**ergo_sys**](https://github.com/rust-crates/ergo_sys): deal with 79 | interfacing with the OS. Examples currently only include signal handling 80 | (`ctrlc`) and randomness (`rand`) but we are looking for other important 81 | crates. (_alpha status_) 82 | 83 | 84 | ## Future Sub Crates 85 | - [ ] **ergo_client**: methods/types to be an HTTP client. Sub crates probably 86 | include `reqwest`, `h2` and some kinds of json-rpc+soap protocol helpers. 87 | - [ ] **ergo_term**: simple and ergonomic terminal rendering. 88 | - [ ] **ergo_test**: one-stop-shop for core testing functionality, mocking, 89 | etc. 90 | 91 | 92 | # LICENSE 93 | The source code in this repository is Licensed under either of 94 | - Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or 95 | http://www.apache.org/licenses/LICENSE-2.0) 96 | - MIT license ([LICENSE-MIT](LICENSE-MIT) or 97 | http://opensource.org/licenses/MIT) 98 | 99 | at your option. 100 | 101 | Unless you explicitly state otherwise, any contribution intentionally submitted 102 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall 103 | be dual licensed as above, without any additional terms or conditions. 104 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # Appveyor configuration template for Rust using rustup for Rust installation 2 | # https://github.com/starkat99/appveyor-rust 3 | 4 | ## Operating System (VM environment) ## 5 | 6 | # Rust needs at least Visual Studio 2013 Appveyor OS for MSVC targets. 7 | os: Visual Studio 2015 8 | 9 | # Bors configuration 10 | branches: 11 | only: 12 | # This is where pull requests from "bors r+" are built. 13 | - staging 14 | # This is where pull requests from "bors try" are built. 15 | - trying 16 | 17 | ## Build Matrix ## 18 | 19 | # This configuration will setup a build for each channel & target combination (12 windows 20 | # combinations in all). 21 | # 22 | # There are 3 channels: stable, beta, and nightly. 23 | # 24 | # Alternatively, the full version may be specified for the channel to build using that specific 25 | # version (e.g. channel: 1.5.0) 26 | # 27 | # The values for target are the set of windows Rust build targets. Each value is of the form 28 | # 29 | # ARCH-pc-windows-TOOLCHAIN 30 | # 31 | # Where ARCH is the target architecture, either x86_64 or i686, and TOOLCHAIN is the linker 32 | # toolchain to use, either msvc or gnu. See https://www.rust-lang.org/downloads.html#win-foot for 33 | # a description of the toolchain differences. 34 | # See https://github.com/rust-lang-nursery/rustup.rs/#toolchain-specification for description of 35 | # toolchains and host triples. 36 | # 37 | # Comment out channel/target combos you do not wish to build in CI. 38 | # 39 | # You may use the `cargoflags` and `RUSTFLAGS` variables to set additional flags for cargo commands 40 | # and rustc, respectively. For instance, you can uncomment the cargoflags lines in the nightly 41 | # channels to enable unstable features when building for nightly. Or you could add additional 42 | # matrix entries to test different combinations of features. 43 | environment: 44 | matrix: 45 | 46 | ### MSVC Toolchains ### 47 | 48 | # Stable 64-bit MSVC 49 | - channel: stable 50 | target: x86_64-pc-windows-msvc 51 | # Stable 32-bit MSVC 52 | - channel: stable 53 | target: i686-pc-windows-msvc 54 | # # Beta 64-bit MSVC 55 | # - channel: beta 56 | # target: x86_64-pc-windows-msvc 57 | # # Beta 32-bit MSVC 58 | # - channel: beta 59 | # target: i686-pc-windows-msvc 60 | # # Nightly 64-bit MSVC 61 | # - channel: nightly 62 | # target: x86_64-pc-windows-msvc 63 | # #cargoflags: --features "unstable" 64 | # # Nightly 32-bit MSVC 65 | # - channel: nightly 66 | # target: i686-pc-windows-msvc 67 | # #cargoflags: --features "unstable" 68 | 69 | ### GNU Toolchains ### 70 | 71 | # Stable 64-bit GNU 72 | - channel: stable 73 | target: x86_64-pc-windows-gnu 74 | # Stable 32-bit GNU 75 | - channel: stable 76 | target: i686-pc-windows-gnu 77 | # # Beta 64-bit GNU 78 | # - channel: beta 79 | # target: x86_64-pc-windows-gnu 80 | # # Beta 32-bit GNU 81 | # - channel: beta 82 | # target: i686-pc-windows-gnu 83 | # # Nightly 64-bit GNU 84 | # - channel: nightly 85 | # target: x86_64-pc-windows-gnu 86 | # #cargoflags: --features "unstable" 87 | # # Nightly 32-bit GNU 88 | # - channel: nightly 89 | # target: i686-pc-windows-gnu 90 | # #cargoflags: --features "unstable" 91 | 92 | ### Allowed failures ### 93 | 94 | # See Appveyor documentation for specific details. In short, place any channel or targets you wish 95 | # to allow build failures on (usually nightly at least is a wise choice). This will prevent a build 96 | # or test failure in the matching channels/targets from failing the entire build. 97 | matrix: 98 | allow_failures: 99 | - channel: nightly 100 | 101 | # If you only care about stable channel build failures, uncomment the following line: 102 | #- channel: beta 103 | 104 | ## Install Script ## 105 | 106 | # This is the most important part of the Appveyor configuration. This installs the version of Rust 107 | # specified by the 'channel' and 'target' environment variables from the build matrix. This uses 108 | # rustup to install Rust. 109 | # 110 | # For simple configurations, instead of using the build matrix, you can simply set the 111 | # default-toolchain and default-host manually here. 112 | install: 113 | - appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe 114 | - rustup-init -yv --default-toolchain %channel% --default-host %target% 115 | - set PATH=%PATH%;%USERPROFILE%\.cargo\bin 116 | - rustc -vV 117 | - cargo -vV 118 | 119 | ## Build Script ## 120 | 121 | # 'cargo test' takes care of building for us, so disable Appveyor's build stage. This prevents 122 | # the "directory does not contain a project or solution file" error. 123 | build: false 124 | 125 | # Uses 'cargo test' to run tests and build. Alternatively, the project may call compiled programs 126 | #directly or perform other testing commands. Rust will automatically be placed in the PATH 127 | # environment variable. 128 | test_script: 129 | - cargo test --verbose --all %cargoflags% -- --nocapture 130 | -------------------------------------------------------------------------------- /bors.toml: -------------------------------------------------------------------------------- 1 | status = [ 2 | "continuous-integration/travis-ci/push", 3 | "continuous-integration/appveyor/branch" 4 | ] 5 | 6 | # Uncomment this to use a two hour timeout. 7 | # The default is one hour. 8 | # timeout_sec = 7200 9 | -------------------------------------------------------------------------------- /ergo/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Garrett Berg "] 3 | description = " making rust's ecosystem more ergonomic, therefore more fun." 4 | documentation = "https://docs.rs/ergo" 5 | keywords = ["ergonomics", "cli", "application"] 6 | license = "MIT OR Apache-2.0" 7 | name = "ergo" 8 | readme = "README.md" 9 | repository = "https://github.com/rust-crates/ergo" 10 | version = "0.0.6" 11 | 12 | [dependencies] 13 | ergo_config = {path="../ergo_config", version="0.0.1"} 14 | ergo_fs = {path="../ergo_fs", version="0.2.0"} 15 | ergo_std = {path="../ergo_std", version="0.0.4"} 16 | ergo_sync = {path="../ergo_sync", version="0.1.0"} 17 | ergo_sys = {path="../ergo_sys", version="0.0.1"} 18 | -------------------------------------------------------------------------------- /ergo/src/deep_copy.rs: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2018 Garrett Berg, vitiral@gmail.com 2 | * 3 | * Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | * copied, modified, or distributed except according to those terms. 7 | */ 8 | //! Define the deepcopy function 9 | use super::*; 10 | use std::fs; 11 | use std::io; 12 | 13 | /// Do a deep copy of a directory from one location to another. 14 | /// 15 | /// This will follow symlinks and copy the _contents_. Recursive paths will cause an 16 | /// error to be raised. 17 | /// 18 | /// Errors are sent over the `send_err` channel. 19 | pub fn deep_copy>(send_err: Sender, from: PathDir, to: P) { 20 | let to = ch_try!( 21 | send_err, 22 | create_dir_maybe(to).map_err(|err| err.into()), 23 | return 24 | ); 25 | 26 | let (send_file, recv_file) = ch::bounded(128); 27 | 28 | // First thread walks and creates directories, and sends files to copy 29 | take!(=send_err as errs, =to as to_walk); 30 | spawn(move || { 31 | walk_and_create_dirs(from, to_walk, errs, send_file); 32 | }); 33 | 34 | // Threadpool copy files into directories that are pre-created. 35 | for _ in 0..num_cpus::get() { 36 | take!(=send_err, =recv_file, =to); 37 | spawn(move || { 38 | for (from, to_postfix) in recv_file { 39 | ch_try!( 40 | send_err, 41 | from.copy(to.join(to_postfix)).map_err(|err| err.into()), 42 | continue 43 | ); 44 | } 45 | }); 46 | } 47 | } 48 | 49 | /// Do a contents-first yeild and follow any symlinks -- we are doing an _actual_ copy 50 | fn walk_and_create_dirs( 51 | from: PathDir, 52 | to: PathDir, 53 | send_err: Sender, 54 | send_file: Sender<(PathFile, PathBuf)>, 55 | ) { 56 | let mut it = from.walk().follow_links(true).into_iter(); 57 | loop { 58 | let entry = match it.next() { 59 | Some(entry) => entry, 60 | None => break, 61 | }; 62 | macro_rules! handle_err { 63 | ($entry:expr) => { 64 | match $entry { 65 | Ok(e) => e, 66 | Err(err) => { 67 | ch!(send_err <- err.into()); 68 | continue; 69 | } 70 | } 71 | }; 72 | } 73 | let entry = handle_err!(entry); 74 | let to_postfix = entry 75 | .path() 76 | .strip_prefix(&from) 77 | .map_err(|e| io::Error::new(io::ErrorKind::Other, e)); 78 | let to_postfix = handle_err!(to_postfix); 79 | 80 | match handle_err!(PathType::new(entry.path())) { 81 | PathType::Dir(_) => { 82 | // Create it immediately 83 | if let Err(err) = PathDir::create(to.join(to_postfix)) { 84 | ch!(send_err <- err.into()); 85 | // We couldn't create the directory so it needs to be skipped. 86 | it.skip_current_dir(); 87 | } 88 | } 89 | PathType::File(from_file) => { 90 | ch!(send_file <- (from_file, to_postfix.to_path_buf())); 91 | } 92 | } 93 | } 94 | } 95 | 96 | fn create_dir_maybe>(path: P) -> path_abs::Result { 97 | let arc = PathArc::new(path); 98 | fs::create_dir(&arc).map_err(|err| path_abs::Error::new(err, "creating dir", arc.clone()))?; 99 | PathDir::new(arc) 100 | } 101 | -------------------------------------------------------------------------------- /ergo/src/lib.rs: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2018 Garrett Berg, vitiral@gmail.com 2 | * 3 | * Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | * copied, modified, or distributed except according to those terms. 7 | */ 8 | //! **Make rust's ecosystem more ergonomic, therefore more fun!** 9 | //! 10 | //! _This crate is in alpha status, please see the github project for 11 | //! more details_ 12 | //! 13 | //! https://github.com/rust-crates/ergo 14 | #![allow(unused_imports)] 15 | 16 | #[macro_use] 17 | pub extern crate ergo_config; 18 | #[macro_use] 19 | pub extern crate ergo_fs; 20 | #[macro_use] 21 | pub extern crate ergo_std; 22 | #[macro_use] 23 | pub extern crate ergo_sync; 24 | #[macro_use] 25 | pub extern crate ergo_sys; 26 | 27 | pub use ergo_config::*; 28 | pub use ergo_fs::*; 29 | pub use ergo_std::*; 30 | pub use ergo_sync::*; 31 | pub use ergo_sys::*; 32 | 33 | mod deep_copy; 34 | pub use deep_copy::deep_copy; 35 | -------------------------------------------------------------------------------- /ergo_config/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Garrett Berg "] 3 | description = "Make loading configuration more ergonomic, therefore fun!" 4 | documentation = "https://docs.rs/ergo_config" 5 | keywords = [ 6 | "ergo", 7 | "configuration", 8 | ] 9 | license = "MIT OR Apache-2.0" 10 | name = "ergo_config" 11 | readme = "README.md" 12 | repository = "https://github.com/rust-crates/ergo_config" 13 | version = "0.0.1" 14 | 15 | [dependencies] 16 | configure = "0.1.1" 17 | ron = "0.1.7" 18 | serde_json = "1.0.9" 19 | serde_yaml = "0.7.3" 20 | toml = "0.4.5" 21 | -------------------------------------------------------------------------------- /ergo_config/LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Copyright 2018 Garrett Berg, vitiral@gmail.com 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /ergo_config/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Garrett Berg, vitiral@gmail.com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /ergo_config/README.md: -------------------------------------------------------------------------------- 1 | # ergo_config: loading configuration more ergonomic, therefore fun! 2 | 3 | [![Build Status](https://travis-ci.org/rust-crates/ergo_config.svg?branch=master)](https://travis-ci.org/rust-crates/ergo_config) 4 | [![Build status](https://ci.appveyor.com/api/projects/status/vgis54solhygre0n?svg=true)](https://ci.appveyor.com/project/rust-crates/path-abs) 5 | [![Docs](https://docs.rs/ergo_config/badge.svg)](https://docs.rs/ergo_config) 6 | 7 | **See the [library docs](https://docs.rs/ergo_config) for more information** 8 | 9 | 10 | # LICENSE 11 | The source code in this repository is Licensed under either of 12 | - Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or 13 | http://www.apache.org/licenses/LICENSE-2.0) 14 | - MIT license ([LICENSE-MIT](LICENSE-MIT) or 15 | http://opensource.org/licenses/MIT) 16 | 17 | at your option. 18 | 19 | Unless you explicitly state otherwise, any contribution intentionally submitted 20 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall 21 | be dual licensed as above, without any additional terms or conditions. 22 | -------------------------------------------------------------------------------- /ergo_config/appveyor.yml: -------------------------------------------------------------------------------- 1 | # Appveyor configuration template for Rust using rustup for Rust installation 2 | # https://github.com/starkat99/appveyor-rust 3 | 4 | ## Operating System (VM environment) ## 5 | 6 | # Rust needs at least Visual Studio 2013 Appveyor OS for MSVC targets. 7 | os: Visual Studio 2015 8 | 9 | # Bors configuration 10 | branches: 11 | only: 12 | # This is where pull requests from "bors r+" are built. 13 | - staging 14 | # This is where pull requests from "bors try" are built. 15 | - trying 16 | 17 | ## Build Matrix ## 18 | 19 | # This configuration will setup a build for each channel & target combination (12 windows 20 | # combinations in all). 21 | # 22 | # There are 3 channels: stable, beta, and nightly. 23 | # 24 | # Alternatively, the full version may be specified for the channel to build using that specific 25 | # version (e.g. channel: 1.5.0) 26 | # 27 | # The values for target are the set of windows Rust build targets. Each value is of the form 28 | # 29 | # ARCH-pc-windows-TOOLCHAIN 30 | # 31 | # Where ARCH is the target architecture, either x86_64 or i686, and TOOLCHAIN is the linker 32 | # toolchain to use, either msvc or gnu. See https://www.rust-lang.org/downloads.html#win-foot for 33 | # a description of the toolchain differences. 34 | # See https://github.com/rust-lang-nursery/rustup.rs/#toolchain-specification for description of 35 | # toolchains and host triples. 36 | # 37 | # Comment out channel/target combos you do not wish to build in CI. 38 | # 39 | # You may use the `cargoflags` and `RUSTFLAGS` variables to set additional flags for cargo commands 40 | # and rustc, respectively. For instance, you can uncomment the cargoflags lines in the nightly 41 | # channels to enable unstable features when building for nightly. Or you could add additional 42 | # matrix entries to test different combinations of features. 43 | environment: 44 | matrix: 45 | 46 | ### MSVC Toolchains ### 47 | 48 | # Stable 64-bit MSVC 49 | - channel: stable 50 | target: x86_64-pc-windows-msvc 51 | # Stable 32-bit MSVC 52 | - channel: stable 53 | target: i686-pc-windows-msvc 54 | # # Beta 64-bit MSVC 55 | # - channel: beta 56 | # target: x86_64-pc-windows-msvc 57 | # # Beta 32-bit MSVC 58 | # - channel: beta 59 | # target: i686-pc-windows-msvc 60 | # # Nightly 64-bit MSVC 61 | # - channel: nightly 62 | # target: x86_64-pc-windows-msvc 63 | # #cargoflags: --features "unstable" 64 | # # Nightly 32-bit MSVC 65 | # - channel: nightly 66 | # target: i686-pc-windows-msvc 67 | # #cargoflags: --features "unstable" 68 | 69 | ### GNU Toolchains ### 70 | 71 | # Stable 64-bit GNU 72 | - channel: stable 73 | target: x86_64-pc-windows-gnu 74 | # Stable 32-bit GNU 75 | - channel: stable 76 | target: i686-pc-windows-gnu 77 | # # Beta 64-bit GNU 78 | # - channel: beta 79 | # target: x86_64-pc-windows-gnu 80 | # # Beta 32-bit GNU 81 | # - channel: beta 82 | # target: i686-pc-windows-gnu 83 | # # Nightly 64-bit GNU 84 | # - channel: nightly 85 | # target: x86_64-pc-windows-gnu 86 | # #cargoflags: --features "unstable" 87 | # # Nightly 32-bit GNU 88 | # - channel: nightly 89 | # target: i686-pc-windows-gnu 90 | # #cargoflags: --features "unstable" 91 | 92 | ### Allowed failures ### 93 | 94 | # See Appveyor documentation for specific details. In short, place any channel or targets you wish 95 | # to allow build failures on (usually nightly at least is a wise choice). This will prevent a build 96 | # or test failure in the matching channels/targets from failing the entire build. 97 | matrix: 98 | allow_failures: 99 | - channel: nightly 100 | 101 | # If you only care about stable channel build failures, uncomment the following line: 102 | #- channel: beta 103 | 104 | ## Install Script ## 105 | 106 | # This is the most important part of the Appveyor configuration. This installs the version of Rust 107 | # specified by the 'channel' and 'target' environment variables from the build matrix. This uses 108 | # rustup to install Rust. 109 | # 110 | # For simple configurations, instead of using the build matrix, you can simply set the 111 | # default-toolchain and default-host manually here. 112 | install: 113 | - appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe 114 | - rustup-init -yv --default-toolchain %channel% --default-host %target% 115 | - set PATH=%PATH%;%USERPROFILE%\.cargo\bin 116 | - rustc -vV 117 | - cargo -vV 118 | 119 | ## Build Script ## 120 | 121 | # 'cargo test' takes care of building for us, so disable Appveyor's build stage. This prevents 122 | # the "directory does not contain a project or solution file" error. 123 | build: false 124 | 125 | # Uses 'cargo test' to run tests and build. Alternatively, the project may call compiled programs 126 | #directly or perform other testing commands. Rust will automatically be placed in the PATH 127 | # environment variable. 128 | test_script: 129 | - cargo test --verbose --all %cargoflags% -- --nocapture 130 | -------------------------------------------------------------------------------- /ergo_config/bors.toml: -------------------------------------------------------------------------------- 1 | status = [ 2 | "continuous-integration/travis-ci/push", 3 | "continuous-integration/appveyor/branch" 4 | ] 5 | 6 | # Uncomment this to use a two hour timeout. 7 | # The default is one hour. 8 | # timeout_sec = 7200 9 | -------------------------------------------------------------------------------- /ergo_config/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! **Make loading configuration more ergonomic, therefore fun!** 2 | //! 3 | //! This is the configuration loading libray as part of the [`ergo`] crate ecosystem. 4 | //! 5 | //! > This library should rarely be used on its own. Refer to the [`ergo`] crate ecosystem 6 | //! > for how to use its exported features. For one thing it depends on `serde` to actually 7 | //! > be used in most cases. 8 | //! 9 | //! ### Special thanks 10 | //! 11 | //! The crates that are exported are: 12 | //! 13 | //! - [**configure**](https://github.com/withoutboats/configure): pull in configuration from the 14 | //! environment. 15 | //! - [**ron**](https://github.com/ron-rs/ron): Rusty Object Notation. 16 | //! - [**serde_json**](https://github.com/serde-rs/json): Strongly typed JSON library for Rust. 17 | //! - [**serde_yaml**](https://github.com/dtolnay/serde-yaml): Strongly typed YAML library for 18 | //! Rust. 19 | //! - [**toml**](https://github.com/alexcrichton/toml-rs): A TOML encoding/decoding library for 20 | //! Rust. 21 | //! 22 | //! Consider supporting their development individually and starring them on github. 23 | //! 24 | //! [`ergo`]: https://github.com/rust-crates/ergo 25 | #![allow(unused_imports)] 26 | 27 | #[macro_use] 28 | pub extern crate configure; 29 | pub extern crate serde_json as json; 30 | pub extern crate serde_yaml as yaml; 31 | pub extern crate toml; 32 | 33 | pub use configure::*; 34 | -------------------------------------------------------------------------------- /ergo_fs/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Garrett Berg "] 3 | description = "Types for making working with the filesystem ergonomic, therefore fun." 4 | documentation = "https://docs.rs/ergo_fs" 5 | keywords = [ 6 | "filesystem", 7 | "path", 8 | "file", 9 | "types", 10 | "ergonomic", 11 | ] 12 | license = "MIT OR Apache-2.0" 13 | name = "ergo_fs" 14 | readme = "README.md" 15 | repository = "https://github.com/rust-crates/ergo_fs" 16 | version = "0.2.0" 17 | 18 | [dependencies] 19 | glob = "0.2.11" 20 | path_abs = "^0.4.0" 21 | shellexpand = "1.0.0" 22 | std_prelude = "^0.2.9" 23 | tar = "^0.4.14" 24 | tempdir = "^0.3.5" 25 | walkdir = "^2.0.1" 26 | -------------------------------------------------------------------------------- /ergo_fs/LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Copyright 2018 Garrett Berg, vitiral@gmail.com 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /ergo_fs/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Garrett Berg, vitiral@gmail.com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /ergo_fs/README.md: -------------------------------------------------------------------------------- 1 | # Methods and types for making working with the filesystem ergonomic, therefore fun. 2 | 3 | [![Build Status](https://travis-ci.org/rust-crates/ergo_fs.svg?branch=master)](https://travis-ci.org/rust-crates/ergo_fs) 4 | [![Build status](https://ci.appveyor.com/api/projects/status/vgis54solhygre0n?svg=true)](https://ci.appveyor.com/project/rust-crates/path-abs) 5 | [![Docs](https://docs.rs/ergo_fs/badge.svg)](https://docs.rs/ergo_fs) 6 | 7 | **See the [library docs](https://docs.rs/ergo_fs) for more information** 8 | 9 | ## Future Items 10 | 11 | - [ ] Clean up TODOs, mostly around error messages in external crates. 12 | - [ ] Have an API review done by the rust community. 13 | - [ ] Support `ramfs` as `PathRam`, see [this issue][ramfs] 14 | 15 | [ramfs]: https://github.com/rust-lang-nursery/tempdir/issues/42 16 | 17 | # LICENSE 18 | The source code in this repository is Licensed under either of 19 | - Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or 20 | http://www.apache.org/licenses/LICENSE-2.0) 21 | - MIT license ([LICENSE-MIT](LICENSE-MIT) or 22 | http://opensource.org/licenses/MIT) 23 | 24 | at your option. 25 | 26 | Unless you explicitly state otherwise, any contribution intentionally submitted 27 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall 28 | be dual licensed as above, without any additional terms or conditions. 29 | -------------------------------------------------------------------------------- /ergo_fs/appveyor.yml: -------------------------------------------------------------------------------- 1 | # Appveyor configuration template for Rust using rustup for Rust installation 2 | # https://github.com/starkat99/appveyor-rust 3 | 4 | ## Operating System (VM environment) ## 5 | 6 | # Rust needs at least Visual Studio 2013 Appveyor OS for MSVC targets. 7 | os: Visual Studio 2015 8 | 9 | # Bors configuration 10 | branches: 11 | only: 12 | # This is where pull requests from "bors r+" are built. 13 | - staging 14 | # This is where pull requests from "bors try" are built. 15 | - trying 16 | 17 | ## Build Matrix ## 18 | 19 | # This configuration will setup a build for each channel & target combination (12 windows 20 | # combinations in all). 21 | # 22 | # There are 3 channels: stable, beta, and nightly. 23 | # 24 | # Alternatively, the full version may be specified for the channel to build using that specific 25 | # version (e.g. channel: 1.5.0) 26 | # 27 | # The values for target are the set of windows Rust build targets. Each value is of the form 28 | # 29 | # ARCH-pc-windows-TOOLCHAIN 30 | # 31 | # Where ARCH is the target architecture, either x86_64 or i686, and TOOLCHAIN is the linker 32 | # toolchain to use, either msvc or gnu. See https://www.rust-lang.org/downloads.html#win-foot for 33 | # a description of the toolchain differences. 34 | # See https://github.com/rust-lang-nursery/rustup.rs/#toolchain-specification for description of 35 | # toolchains and host triples. 36 | # 37 | # Comment out channel/target combos you do not wish to build in CI. 38 | # 39 | # You may use the `cargoflags` and `RUSTFLAGS` variables to set additional flags for cargo commands 40 | # and rustc, respectively. For instance, you can uncomment the cargoflags lines in the nightly 41 | # channels to enable unstable features when building for nightly. Or you could add additional 42 | # matrix entries to test different combinations of features. 43 | environment: 44 | matrix: 45 | 46 | ### MSVC Toolchains ### 47 | 48 | # Stable 64-bit MSVC 49 | - channel: stable 50 | target: x86_64-pc-windows-msvc 51 | # Stable 32-bit MSVC 52 | - channel: stable 53 | target: i686-pc-windows-msvc 54 | # # Beta 64-bit MSVC 55 | # - channel: beta 56 | # target: x86_64-pc-windows-msvc 57 | # # Beta 32-bit MSVC 58 | # - channel: beta 59 | # target: i686-pc-windows-msvc 60 | # # Nightly 64-bit MSVC 61 | # - channel: nightly 62 | # target: x86_64-pc-windows-msvc 63 | # #cargoflags: --features "unstable" 64 | # # Nightly 32-bit MSVC 65 | # - channel: nightly 66 | # target: i686-pc-windows-msvc 67 | # #cargoflags: --features "unstable" 68 | 69 | ### GNU Toolchains ### 70 | 71 | # Stable 64-bit GNU 72 | - channel: stable 73 | target: x86_64-pc-windows-gnu 74 | # Stable 32-bit GNU 75 | - channel: stable 76 | target: i686-pc-windows-gnu 77 | # # Beta 64-bit GNU 78 | # - channel: beta 79 | # target: x86_64-pc-windows-gnu 80 | # # Beta 32-bit GNU 81 | # - channel: beta 82 | # target: i686-pc-windows-gnu 83 | # # Nightly 64-bit GNU 84 | # - channel: nightly 85 | # target: x86_64-pc-windows-gnu 86 | # #cargoflags: --features "unstable" 87 | # # Nightly 32-bit GNU 88 | # - channel: nightly 89 | # target: i686-pc-windows-gnu 90 | # #cargoflags: --features "unstable" 91 | 92 | ### Allowed failures ### 93 | 94 | # See Appveyor documentation for specific details. In short, place any channel or targets you wish 95 | # to allow build failures on (usually nightly at least is a wise choice). This will prevent a build 96 | # or test failure in the matching channels/targets from failing the entire build. 97 | matrix: 98 | allow_failures: 99 | - channel: nightly 100 | 101 | # If you only care about stable channel build failures, uncomment the following line: 102 | #- channel: beta 103 | 104 | ## Install Script ## 105 | 106 | # This is the most important part of the Appveyor configuration. This installs the version of Rust 107 | # specified by the 'channel' and 'target' environment variables from the build matrix. This uses 108 | # rustup to install Rust. 109 | # 110 | # For simple configurations, instead of using the build matrix, you can simply set the 111 | # default-toolchain and default-host manually here. 112 | install: 113 | - appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe 114 | - rustup-init -yv --default-toolchain %channel% --default-host %target% 115 | - set PATH=%PATH%;%USERPROFILE%\.cargo\bin 116 | - rustc -vV 117 | - cargo -vV 118 | 119 | ## Build Script ## 120 | 121 | # 'cargo test' takes care of building for us, so disable Appveyor's build stage. This prevents 122 | # the "directory does not contain a project or solution file" error. 123 | build: false 124 | 125 | # Uses 'cargo test' to run tests and build. Alternatively, the project may call compiled programs 126 | #directly or perform other testing commands. Rust will automatically be placed in the PATH 127 | # environment variable. 128 | test_script: 129 | - cargo test --verbose --all %cargoflags% -- --nocapture 130 | -------------------------------------------------------------------------------- /ergo_fs/bors.toml: -------------------------------------------------------------------------------- 1 | status = [ 2 | "continuous-integration/travis-ci/push", 3 | "continuous-integration/appveyor/branch" 4 | ] 5 | 6 | # Uncomment this to use a two hour timeout. 7 | # The default is one hour. 8 | # timeout_sec = 7200 9 | -------------------------------------------------------------------------------- /ergo_fs/notes.md: -------------------------------------------------------------------------------- 1 | - Open a ticket to WalkDir to pretify their `From for io::Error` implementation. 2 | -------------------------------------------------------------------------------- /ergo_fs/src/glob_wrapper.rs: -------------------------------------------------------------------------------- 1 | /* Much of the documentation in this file was taken from the `glob` crate. 2 | * 3 | * Copyright (c) 2018 Garrett Berg, vitiral@gmail.com 4 | * Copyright (c) 2014 The Rust Project Developers. 5 | * 6 | * Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 9 | * copied, modified, or distributed except according to those terms. 10 | */ 11 | //! Wrapper around the `glob` crate. 12 | 13 | use std::io; 14 | use std_prelude::*; 15 | use path_abs::{PathDir, PathFile, PathType}; 16 | use glob_crate; 17 | 18 | /// Renamed [`glob::MatchOptions`](../glob/struct.MatchOptions.html) 19 | pub type GlobOptions = glob_crate::MatchOptions; 20 | 21 | /// Renamed [`glob::PatternError`](../glob/struct.PatternError.html) 22 | pub type GlobPatternError = glob_crate::PatternError; 23 | 24 | #[inline(always)] 25 | /// Return an iterator that produces all the `PathType`s that match the given pattern, which may be 26 | /// absolute or relative to the current working directory. 27 | /// 28 | /// This may return an error if the pattern is invalid. 29 | /// 30 | /// This method uses the default match options and is equivalent to calling 31 | /// `glob_with(pattern, GlobOptions::new())`. Use [`glob_with`](fn.glob_with.html) directly if you 32 | /// want to use non-default match options. 33 | /// 34 | /// When iterating, each result is a `io::Result` which expresses the possibility that there was an 35 | /// `io::Error` when attempting to read the contents of the matched path. 36 | /// 37 | /// # Example 38 | /// 39 | /// ```rust 40 | /// # extern crate ergo_fs; 41 | /// use ergo_fs::*; 42 | /// 43 | /// # fn try_main() -> ::std::io::Result<()> { 44 | /// let mut count = 0; 45 | /// for entry in glob("src/glob_*.rs").unwrap() { 46 | /// # count += 1; assert!(entry.is_ok()); 47 | /// match entry? { 48 | /// PathType::File(file) => println!("file: {}", file.display()), 49 | /// PathType::Dir(dir) => println!("dir: {}", dir.display()), 50 | /// } 51 | /// } 52 | /// # assert_eq!(count, 1); 53 | /// # Ok(()) } fn main() { try_main().unwrap() } 54 | /// ``` 55 | /// 56 | /// The above code will print: 57 | /// 58 | /// ```ignore 59 | /// /path/to/crate/src/glob_wrapper.rs 60 | /// ``` 61 | /// 62 | /// If there were more files with the prefix `glob_` it would print more. 63 | pub fn glob(pattern: &str) -> Result { 64 | GlobPathTypes::new(pattern) 65 | } 66 | 67 | #[inline(always)] 68 | /// The same as [`glob`](fn.glob.html) but with additional options. 69 | pub fn glob_with(pattern: &str, options: &GlobOptions) -> Result { 70 | GlobPathTypes::with(pattern, options) 71 | } 72 | 73 | /// An iterator that yields `PathType`s from the filesystem that match a particular pattern. 74 | /// 75 | /// Note that it yields `Result` in order to report any IoErrors that 76 | /// may arise during iteration. If a directory matches but is unreadable, thereby preventing its 77 | /// contents from being checked for matches, a `path_abs::Error` is returned to express this. 78 | /// 79 | /// See the [`glob`](fn.glob.html) function for more details. 80 | pub struct GlobPathTypes { 81 | paths: glob_crate::Paths, 82 | } 83 | 84 | /// Returns an iterator of only `PathFile`s, any directories that matched the glob are ignored. 85 | /// 86 | /// See [`GlobPathTypes::files`](struct.GlobPathTypes.html#method=files) 87 | pub struct GlobPathFiles { 88 | types: GlobPathTypes, 89 | } 90 | 91 | /// Returns an iterator of only `PathDirs`s, any files that matched the glob are ignored. 92 | /// 93 | /// See [`GlobPathTypes::dirs`](struct.GlobPathTypes.html#method=dirs) 94 | pub struct GlobPathDirs { 95 | types: GlobPathTypes, 96 | } 97 | 98 | impl GlobPathTypes { 99 | #[inline(always)] 100 | fn new(pattern: &str) -> Result { 101 | Ok(GlobPathTypes { 102 | paths: glob_crate::glob(pattern)?, 103 | }) 104 | } 105 | 106 | #[inline(always)] 107 | fn with( 108 | pattern: &str, 109 | options: &GlobOptions, 110 | ) -> Result { 111 | Ok(GlobPathTypes { 112 | paths: glob_crate::glob_with(pattern, options)?, 113 | }) 114 | } 115 | 116 | #[inline(always)] 117 | /// Consume self and return an iterator over only the files, ignoring any directories. 118 | /// 119 | /// # Example 120 | /// ```rust 121 | /// # extern crate ergo_fs; 122 | /// use ergo_fs::*; 123 | /// 124 | /// # fn try_main() -> ::std::io::Result<()> { 125 | /// # let mut count = 0; 126 | /// // unwrap since we know we are inputing a good pattern 127 | /// for file in glob("src/glob*.rs").unwrap().files() { 128 | /// println!("file: {}", file?.display()); 129 | /// # count += 1; 130 | /// } 131 | /// # assert_eq!(count, 1); 132 | /// # Ok(()) } fn main() { try_main().unwrap() } 133 | /// ``` 134 | pub fn files(self) -> GlobPathFiles { 135 | GlobPathFiles { types: self } 136 | } 137 | 138 | #[inline(always)] 139 | /// Consume self and return an iterator over only the directories, ignoring any files. 140 | /// 141 | /// # Example 142 | /// ```rust 143 | /// # extern crate ergo_fs; 144 | /// use ergo_fs::*; 145 | /// 146 | /// # fn try_main() -> ::std::io::Result<()> { 147 | /// # let mut count = 0; 148 | /// // unwrap since we know we are inputing a good pattern 149 | /// for dir in glob("src/*").unwrap().dirs() { 150 | /// println!("dir: {}", dir?.display()); 151 | /// # count += 1; 152 | /// } 153 | /// # assert_eq!(count, 0); 154 | /// # Ok(()) } fn main() { try_main().unwrap() } 155 | /// ``` 156 | pub fn dirs(self) -> GlobPathDirs { 157 | GlobPathDirs { types: self } 158 | } 159 | } 160 | 161 | impl Iterator for GlobPathTypes { 162 | type Item = io::Result; 163 | // FIXME: if we can get an owned value of the io::Error then we can 164 | // make this return path_abs::Error 165 | fn next(&mut self) -> Option> { 166 | if let Some(result) = self.paths.next() { 167 | match result { 168 | Ok(path) => Some(PathType::new(path).map_err(|err| err.into())), 169 | Err(err) => Some(Err(io::Error::new(err.error().kind(), err))), 170 | } 171 | } else { 172 | None 173 | } 174 | } 175 | } 176 | 177 | impl Iterator for GlobPathFiles { 178 | // FIXME: make path_abs::Error 179 | type Item = io::Result; 180 | fn next(&mut self) -> Option> { 181 | loop { 182 | match self.types.next() { 183 | Some(Ok(ty)) => match ty { 184 | PathType::File(file) => return Some(Ok(file)), 185 | // ignore directories 186 | PathType::Dir(_) => {} 187 | }, 188 | Some(Err(err)) => return Some(Err(err)), 189 | // iterator exahusted 190 | None => return None, 191 | } 192 | } 193 | } 194 | } 195 | 196 | impl Iterator for GlobPathDirs { 197 | // FIXME: make path_abs::Error 198 | type Item = io::Result; 199 | fn next(&mut self) -> Option> { 200 | loop { 201 | match self.types.next() { 202 | Some(Ok(ty)) => match ty { 203 | PathType::Dir(dir) => return Some(Ok(dir)), 204 | // ignore files 205 | PathType::File(_) => {} 206 | }, 207 | Some(Err(err)) => return Some(Err(err)), 208 | None => return None, // iterator exahusted 209 | } 210 | } 211 | } 212 | } 213 | -------------------------------------------------------------------------------- /ergo_fs/src/lib.rs: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2018 Garrett Berg, vitiral@gmail.com 2 | * 3 | * Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be 6 | * copied, modified, or distributed except according to those terms. 7 | */ 8 | //! Methods and types for making working with the filesystem ergonomic, therefore fun. 9 | //! 10 | //! ## Purpose 11 | //! 12 | //! This crate provides a minimal set of common types and methods for working with the filesystem. 13 | //! These types aim to provide: 14 | //! 15 | //! - Descriptive error messages 16 | //! - Good performance, but not necessarily at _all_ costs. 17 | //! - As much type safety as is possible when dealing with the filesystem 18 | //! 19 | //! The crates it wraps/rexports are: 20 | //! 21 | //! - [`glob`](https://github.com/rust-lang-nursery/glob): Support for matching file paths against 22 | //! Unix shell style patterns. 23 | //! - [`path_abs`](https://github.com/vitiral/path_abs): Ergonomic paths and files in rust. 24 | //! - [`shellexpand`](https://github.com/netvl/shellexpand): A library for shell-like expansions of 25 | //! variables in strings. 26 | //! - [`tar-rs`](https://github.com/alexcrichton/tar-rs): A library for reading and writing TAR 27 | //! archives. 28 | //! - [`tempdir`](https://github.com/rust-lang-nursery/tempdir): Temporary directories 29 | //! of files. 30 | //! - [`walkdir`](https://github.com/BurntSushi/walkdir): Provides an efficient and cross platform 31 | //! implementation of recursive directory traversal. 32 | //! 33 | //! Consider supporting their development individually and starring them on github. 34 | //! 35 | //! ## How to Use 36 | //! ergo_fs is intended to be a "standard library" of filesystem types. Therefore you should 37 | //! use like so: 38 | //! 39 | //! ``` 40 | //! extern crate ergo_fs; 41 | //! use ergo_fs::*; 42 | //! # fn try_main() -> ::std::io::Result<()> { 43 | //! # Ok(()) } fn main() { try_main().unwrap() } 44 | //! ``` 45 | //! 46 | //! # Types 47 | //! This library provides several kinds of types which improve and expand on `std::fs` and 48 | //! `std::path`, as well as provide new functionality like temporary files and tar archives. 49 | //! 50 | //! ## Path, Dir and File Types 51 | //! These types provide improved error messages and type safety when working with paths and files. 52 | //! 53 | //! - [`PathArc`](struct.PathArc.html): a reference counted `PathBuf` with methods reimplemented 54 | //! with better error messages. Use this for a generic serializable path that may or may 55 | //! not exist. 56 | //! - [`PathAbs`](struct.PathAbs.html): a reference counted absolute (canonicalized) path that is 57 | //! guaranteed (on initialization) to exist. 58 | //! - [`PathFile`](struct.PathFile.html): a `PathAbs` that is guaranteed to be a file, with 59 | //! associated methods. 60 | //! - [`PathDir`](struct.PathDir.html): a `PathAbs` that is guaranteed to be a directory, with 61 | //! associated methods. 62 | //! - [`PathType`](struct.PathType.html): an enum containing either a PathFile or a PathDir. 63 | //! Returned by [`PathDir::list`][dir_list] 64 | //! - [`PathTmp`](struct.PathTmp.html): a `PathDir` that is deleted when it goes out of scope. 65 | //! This is a wrapper around the crate `tempdir::TempDir` with methods that mimick the `Path` 66 | //! types in this crate. 67 | //! - [`FileRead`](struct.FileRead.html): a read-only file handle with `path()` attached and 68 | //! improved error messages. Contains only the methods and trait implementations which are 69 | //! allowed by a read-only file. 70 | //! - [`FileWrite`](struct.FileWrite.html): a write-only file handle with `path()` attached and 71 | //! improved error messages. Contains only the methods and trait implementations which are 72 | //! allowed by a write-only file. 73 | //! - [`FileEdit`](struct.FileEdit.html): a read/write file handle with `path()` attached and 74 | //! improved error messages. Contains methods and trait implements for both readable _and_ 75 | //! writeable files. 76 | //! - [`WalkDir`](struct.WalkDir.html): used for recursively walking directories _quickly_. 77 | //! See the **Walkdir** section below. 78 | //! 79 | //! In addition, it exports the following from [`std_prelude`](../std_prelude/index.html) 80 | //! 81 | //! - traits: `Read, IoWrite` 82 | //! - types: `Path, PathBuf` 83 | //! 84 | //! 85 | //! # Methods 86 | //! The following methods are exported. 87 | //! 88 | //! - [`expand`](fn.expand.html): does shell expansion on both tilde (`~` = home dir) and 89 | //! environment variables with the user's home directory + env variables. Also see the 90 | //! exported [`shellexpand`](shellexpand/index.html) crate itself. Consider using with 91 | //! `glob` (see below). 92 | //! - [`glob`](fn.glob.html): a lightweight wrapper around [`glob::glob`](../glob/fn.glob.html) that 93 | //! returns `PathType` objects. 94 | //! - [`glob_with`](fn.glob_with.html): a lightweight wrapper around 95 | //! [`glob::glob_with`](../glob/fn.glob_with.html) that returns `PathType` objects. 96 | //! 97 | //! # Details 98 | //! Bellow are some additional details about imported types. 99 | //! 100 | //! ## Walkdir 101 | //! 102 | //! Use `PathDir::walk` to walk a directory. This returns the [`Walkdir`](struct.WalkDir.html) 103 | //! iterator, which is a direct export from the [`walkdir`](../walkdir/index.html) crate. The 104 | //! crate already has excellent error messages, and although it returns the regular 105 | //! `std::path::PathBuf` type, you can convert to a `PathType` using `PathType::from_entry`. 106 | //! 107 | //! > TODO: although the WalkDir error can be auto-converted to std::io::Error, it 108 | //! > does not preserve the pretty output. See 109 | //! > [this ticket](https://github.com/BurntSushi/walkdir/pull/92) 110 | //! 111 | //! ### Examples 112 | //! ```rust 113 | //! # extern crate ergo_fs; 114 | //! use ergo_fs::*; 115 | //! 116 | //! # fn try_main() -> ::std::io::Result<()> { 117 | //! let dir = PathDir::new("src")?; 118 | //! for entry in dir.walk().max_depth(1) { 119 | //! match PathType::from_entry(entry?)? { 120 | //! PathType::File(file) => println!("got file {}", file.display()), 121 | //! PathType::Dir(dir) => println!("got dir {}", dir.display()), 122 | //! } 123 | //! } 124 | //! # Ok(()) } fn main() { try_main().unwrap() } 125 | //! ``` 126 | //! 127 | //! ## Tar Files 128 | //! Similarly to walkdir, this is a direct export of the `tar` crate. It is recommended that you 129 | //! use the `FileWrite` and `FileRead` types when interacting with this crate so that 130 | //! reading/writing have context. This library already has pretty errors for every other operation. 131 | //! 132 | //! ```rust 133 | //! # extern crate ergo_fs; 134 | //! use ergo_fs::*; 135 | //! use ergo_fs::tar::Builder; 136 | //! 137 | //! # fn try_main() -> ::std::io::Result<()> { 138 | //! // We are going to tar the source code of this library 139 | //! 140 | //! let tmp = PathTmp::create("tmp")?; 141 | //! let mut tarfile = FileWrite::create(tmp.join("src.tar"))?; 142 | //! 143 | //! // tar the source directory 144 | //! let mut tar = Builder::new(tarfile); 145 | //! tar.append_dir_all("src", ".")?; 146 | //! tar.finish(); 147 | //! let tarfile = tar.into_inner()?; 148 | //! 149 | //! // A tarfile now exists, do whatever you would like with it. 150 | //! # Ok(()) } fn main() { try_main().unwrap() } 151 | //! ``` 152 | 153 | pub extern crate glob as glob_crate; 154 | pub extern crate path_abs; 155 | pub extern crate shellexpand; 156 | pub extern crate std_prelude; 157 | pub extern crate tar; 158 | pub extern crate tempdir; 159 | pub extern crate walkdir; 160 | 161 | // ------------------------------- 162 | // External Crate Exports 163 | 164 | use std::borrow::Cow; // FIXME: remove this 165 | use std_prelude::*; 166 | pub use path_abs::{FileEdit, FileRead, FileWrite, PathAbs, PathArc, PathDir, PathFile, PathType}; 167 | pub use walkdir::{Error as WalkError, WalkDir}; 168 | pub use std_prelude::{Read, IoWrite, Path, PathBuf}; 169 | 170 | // ------------------------------- 171 | // Local Modules and Exports 172 | 173 | mod tmp; 174 | mod glob_wrapper; 175 | 176 | pub use glob_wrapper::{ 177 | // functions 178 | glob, glob_with, 179 | // renamed types 180 | GlobOptions, GlobPatternError, 181 | // new iterators 182 | GlobPathDirs, GlobPathFiles, GlobPathTypes, 183 | }; 184 | pub use tmp::PathTmp; 185 | 186 | /// Extension method on the `Path` type. 187 | pub trait PathDirExt 188 | where 189 | Self: AsRef, 190 | { 191 | /// Walk the `PathDir`, returning the `WalkDir` builder. 192 | /// 193 | /// # Examples 194 | /// ```rust 195 | /// # extern crate ergo_fs; 196 | /// use ergo_fs::*; 197 | /// 198 | /// # fn try_main() -> ::std::io::Result<()> { 199 | /// let dir = PathDir::new("src")?; 200 | /// for entry in dir.walk().max_depth(1) { 201 | /// match PathType::from_entry(entry?)? { 202 | /// PathType::File(file) => println!("got file {}", file.display()), 203 | /// PathType::Dir(dir) => println!("got dir {}", dir.display()), 204 | /// } 205 | /// } 206 | /// # Ok(()) } fn main() { try_main().unwrap() } 207 | /// ``` 208 | fn walk(&self) -> walkdir::WalkDir { 209 | walkdir::WalkDir::new(&self) 210 | } 211 | } 212 | 213 | /// Extended methods for `PathType` 214 | pub trait PathTypeExt { 215 | /// Create a `PathType` from a `walkdir::DirEntry` using fewer syscalls. 216 | /// 217 | /// See [`PathDir::walk`] 218 | /// 219 | /// [`PathDir::walk`]: trait.PathDirExt.html#method.walk 220 | fn from_entry(entry: walkdir::DirEntry) -> path_abs::Result { 221 | let abs = PathAbs::new(entry.path())?; 222 | let ty = entry.file_type(); 223 | if ty.is_file() { 224 | Ok(PathType::File(PathFile::from_abs_unchecked(abs))) 225 | } else if ty.is_dir() { 226 | Ok(PathType::Dir(PathDir::from_abs_unchecked(abs))) 227 | } else { 228 | // it is a symlink and we _must_ use a syscall to resolve the type. 229 | PathType::from_abs(abs) 230 | } 231 | } 232 | } 233 | 234 | impl PathDirExt for PathDir {} 235 | impl PathTypeExt for PathType {} 236 | 237 | // --------------------------------------- 238 | // ----------- SHELL EXPANSION ----------- 239 | 240 | /// Renamed [`shellexpand::LookupError`](../shellexpand/struct.LookupError.html) for better 241 | /// ergonomics. 242 | pub type ExpandError = shellexpand::LookupError<::std::env::VarError>; 243 | 244 | /// Performs both tilde and environment shell expansions in the default system context. This is 245 | /// the same as [`shellexpand::full`](../shellexpand/fn.full.html) and is the "typical use case" 246 | /// for expanding strings. 247 | /// 248 | /// Note that non-existant variables will result in an `Err` (in `sh` they are silently replaced 249 | /// with an empty string). Also, environment lookup is only done _as needed_ so this function is 250 | /// performant on strings that do not expand. 251 | /// 252 | /// For more options and information, see the exported [`shellexpand`](../shellexpand/index.html). 253 | /// 254 | /// # Examples 255 | /// ``` 256 | /// # extern crate ergo_fs; 257 | /// use std::env; 258 | /// use ergo_fs::*; 259 | /// 260 | /// # fn try_main() -> Result<(), ExpandError> { 261 | /// env::set_var("A", "a value"); 262 | /// env::set_var("B", "b value"); 263 | /// 264 | /// let home_dir = env::home_dir() 265 | /// .map(|p| p.display().to_string()) 266 | /// .unwrap_or_else(|| "~".to_owned()); 267 | /// 268 | /// // Performs both tilde and environment expansions using the system contexts 269 | /// assert_eq!( 270 | /// expand("~/$A/${B}s")?, 271 | /// format!("{}/a value/b values", home_dir) 272 | /// ); 273 | /// 274 | /// // Unknown variables cause expansion errors 275 | /// assert_eq!( 276 | /// expand("~/$UNKNOWN/$B"), 277 | /// Err(ExpandError { 278 | /// var_name: "UNKNOWN".into(), 279 | /// cause: env::VarError::NotPresent 280 | /// }) 281 | /// ); 282 | /// # Ok(()) } fn main() { try_main().unwrap() } 283 | /// ``` 284 | pub fn expand(input: &SI) -> Result, ExpandError> 285 | where 286 | SI: AsRef, 287 | { 288 | shellexpand::full(input) 289 | } 290 | -------------------------------------------------------------------------------- /ergo_fs/src/tmp.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Garrett Berg, vitiral@gmail.com 2 | // 3 | // Almost all of the docs in this module are copy/pasted from the tempdir crate. 4 | // Copyright (c) 2015 The Rust Project Developers. See the COPYRIGHT 5 | // file at the top-level directory of this distribution and at 6 | // http://rust-lang.org/COPYRIGHT. 7 | // 8 | // Licensed under the Apache License, Version 2.0 or the MIT license 10 | // , at your 11 | // option. This file may not be copied, modified, or distributed 12 | // except according to those terms. 13 | 14 | use std::env; 15 | use std::fmt; 16 | 17 | use std_prelude::*; 18 | use tempdir; 19 | use path_abs::{Error, PathAbs, PathArc, PathDir, Result}; 20 | 21 | /// A `PathDir` that is automatically deleted when it goes out of scope. 22 | /// 23 | /// > **Unlike the other `Path` types, this type is not cloneable.** 24 | /// 25 | /// The [`PathTmp`] type creates a directory on the file system that is deleted once it goes out of 26 | /// scope. At construction, the `PathTmp` creates a new directory with a randomly generated name, 27 | /// and with a prefix of your choosing. 28 | /// 29 | /// The default constructor, [`PathTmp::create`], creates directories in the location returned by 30 | /// [`std::env::temp_dir()`], but `PathTmp` can be configured to manage a temporary directory in 31 | /// any location by constructing with [`PathTmp::create_in`]. 32 | /// 33 | /// After creating a `PathTmp`, work with the file system by doing standard [`std::fs`] file system 34 | /// operations on its [`Path`], which can be retrieved with [`PathTmp::path`]. Once the `PathTmp` 35 | /// value is dropped, the directory at the path will be deleted, along with any files and 36 | /// directories it contains. It is your responsibility to ensure that no further file system 37 | /// operations are attempted inside the temporary directory once it has been deleted. 38 | /// 39 | /// Various platform-specific conditions may cause `PathTmp` to fail to delete the underlying 40 | /// directory. It's important to ensure that handles (like [`File`] and [`ReadDir`]) to files 41 | /// inside the directory are dropped before the `PathTmp` goes out of scope. The `PathTmp` 42 | /// destructor will silently ignore any errors in deleting the directory; to instead handle errors 43 | /// call [`PathTmp::close`]. 44 | /// 45 | /// Note that if the program exits before the `PathTmp` destructor is run, such as via 46 | /// [`std::process::exit`], by segfaulting, or by receiving a signal like `SIGINT`, then the 47 | /// temporary directory will not be deleted. 48 | /// 49 | /// [`File`]: http://doc.rust-lang.org/std/fs/struct.File.html 50 | /// [`Path`]: http://doc.rust-lang.org/std/path/struct.Path.html 51 | /// [`ReadDir`]: http://doc.rust-lang.org/std/fs/struct.ReadDir.html 52 | /// [`PathTmp::close`]: struct.PathTmp.html#method.close 53 | /// [`PathTmp::create`]: struct.PathTmp.html#method.new 54 | /// [`PathTmp::create_in`]: struct.PathTmp.html#method.new_in 55 | /// [`PathTmp::path`]: struct.PathTmp.html#method.path 56 | /// [`PathTmp`]: struct.PathTmp.html 57 | /// [`std::env::temp_dir()`]: https://doc.rust-lang.org/std/env/fn.temp_dir.html 58 | /// [`std::fs`]: http://doc.rust-lang.org/std/fs/index.html 59 | /// [`std::process::exit`]: http://doc.rust-lang.org/std/process/fn.exit.html 60 | pub struct PathTmp { 61 | /// The reference to the absolute path 62 | dir: PathDir, 63 | /// The reference to the temporary file 64 | tmp: tempdir::TempDir, 65 | } 66 | 67 | impl PathTmp { 68 | /// Attempts to make a temporary directory inside of `env::temp_dir()` whose name will have the 69 | /// prefix, `prefix`. The directory and everything inside it will be automatically deleted once 70 | /// the returned `PathTmp` is destroyed. 71 | /// 72 | /// # Errors 73 | /// 74 | /// If the directory can not be created, `Err` is returned. 75 | /// 76 | /// # Examples 77 | /// ``` 78 | /// use ergo_fs::{PathFile, PathTmp}; 79 | /// 80 | /// let tmp_dir = PathTmp::create("example").unwrap(); 81 | /// let file = PathFile::create(tmp_dir.join("temporary-note.txt")).unwrap(); 82 | /// let message = "This file existed, but only for a moment."; 83 | /// file.write_str(message).unwrap(); 84 | /// assert_eq!(file.read_string().unwrap(), message); 85 | /// 86 | /// // Close the tmp_dir manually (would automatically happen when dropped). 87 | /// // All contents are automatically deleted. 88 | /// tmp_dir.close().unwrap(); 89 | /// assert!(!file.exists()); 90 | /// ``` 91 | pub fn create(prefix: &str) -> Result { 92 | PathTmp::create_in(&env::temp_dir(), prefix) 93 | } 94 | 95 | /// Attempts to create a temporary directory inside of `base` whose name will have the prefix 96 | /// `prefix`. The created directory and everything inside it will be automatically deleted once 97 | /// the returned `PathTmp` is destroyed. 98 | /// 99 | /// # Errors 100 | /// 101 | /// If the directory can not be created, `Err` is returned. 102 | /// 103 | /// # Examples 104 | /// 105 | /// ``` 106 | /// use ergo_fs::{PathFile, PathTmp}; 107 | /// 108 | /// let tmp_dir = PathTmp::create_in(".", "example").unwrap(); 109 | /// let file = PathFile::create(tmp_dir.join("temporary-note.txt")).unwrap(); 110 | /// let message = "This file existed, but only for a moment."; 111 | /// file.write_str(message).unwrap(); 112 | /// assert_eq!(file.read_string().unwrap(), message); 113 | /// 114 | /// // Close the tmp_dir manually (would automatically happen when dropped). 115 | /// // All contents are automatically deleted. 116 | /// tmp_dir.close().unwrap(); 117 | /// assert!(!file.exists()); 118 | /// ``` 119 | pub fn create_in>(base: P, prefix: &str) -> Result { 120 | let tmp = tempdir::TempDir::new_in(&base, prefix) 121 | .map_err(|err| Error::new(err, "creating tmpdir", PathArc::new(&base)))?; 122 | 123 | Ok(PathTmp { 124 | dir: PathDir::new(tmp.path())?, 125 | tmp: tmp, 126 | }) 127 | } 128 | 129 | /// Persist the temporary directory on the file system. 130 | /// 131 | /// This method consumes `self`, returning the location of the temporary directory as a regular 132 | /// `PathDir`. The directory will no longer be automatically deleted. 133 | /// 134 | /// # Examples 135 | /// 136 | /// ``` 137 | /// use ergo_fs::PathTmp; 138 | /// 139 | /// let tmp_dir = PathTmp::create_in(".", "persist").unwrap(); 140 | /// let dir = tmp_dir.persist(); 141 | /// 142 | /// // The directory is now persisted to disk 143 | /// assert!(dir.exists()); 144 | /// 145 | /// // It can still be manually removed though. 146 | /// dir.remove().unwrap(); 147 | /// ``` 148 | pub fn persist(self) -> PathDir { 149 | self.tmp.into_path(); 150 | self.dir 151 | } 152 | 153 | /// Closes and removes the temporary directory, returing a `Result`. 154 | /// 155 | /// Although `PathTmp` removes the directory on drop, in the destructor 156 | /// any errors are ignored. To detect errors cleaning up the temporary 157 | /// directory, call `close` instead. 158 | /// 159 | /// # Errors 160 | /// 161 | /// This function may return a variety of [`std::io::Error`]s that result from deleting 162 | /// the files and directories contained with the temporary directory, 163 | /// as well as from deleting the temporary directory itself. These errors 164 | /// may be platform specific. 165 | /// 166 | /// [`std::io::Error`]: http://doc.rust-lang.org/std/io/struct.Error.html 167 | pub fn close(self) -> Result<()> { 168 | let dir = self.dir; 169 | self.tmp 170 | .close() 171 | .map_err(|err| Error::new(err, "removing", dir.into())) 172 | } 173 | 174 | /// Return a reference to a basic `std::path::Path` 175 | pub fn as_path(&self) -> &Path { 176 | self.as_ref() 177 | } 178 | } 179 | 180 | impl fmt::Debug for PathTmp { 181 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 182 | self.dir.fmt(f) 183 | } 184 | } 185 | 186 | impl Hash for PathTmp { 187 | fn hash(&self, state: &mut H) { 188 | self.dir.hash(state); 189 | } 190 | } 191 | 192 | impl AsRef for PathTmp { 193 | fn as_ref(&self) -> &PathDir { 194 | &self.dir 195 | } 196 | } 197 | 198 | impl AsRef for PathTmp { 199 | fn as_ref(&self) -> &PathAbs { 200 | self.dir.as_ref() 201 | } 202 | } 203 | 204 | impl AsRef for PathTmp { 205 | fn as_ref(&self) -> &Path { 206 | self.dir.as_ref() 207 | } 208 | } 209 | 210 | impl AsRef for PathTmp { 211 | fn as_ref(&self) -> &PathBuf { 212 | self.dir.as_ref() 213 | } 214 | } 215 | 216 | impl Deref for PathTmp { 217 | type Target = PathAbs; 218 | 219 | fn deref(&self) -> &PathAbs { 220 | &self.dir 221 | } 222 | } 223 | 224 | impl Into for PathTmp { 225 | /// Downgrades the `PathTmp` into a `PathAbs` 226 | fn into(self) -> PathAbs { 227 | self.dir.into() 228 | } 229 | } 230 | 231 | impl Into for PathTmp { 232 | /// Downgrades the `PathTmp` into a `PathArc` 233 | fn into(self) -> PathArc { 234 | self.dir.into() 235 | } 236 | } 237 | 238 | impl Into for PathTmp { 239 | /// Downgrades the `PathTmp` into a `PathBuf`. Avoids a clone if this is the only reference. 240 | fn into(self) -> PathBuf { 241 | self.dir.into() 242 | } 243 | } 244 | -------------------------------------------------------------------------------- /ergo_std/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | /target/ 3 | **/*.rs.bk 4 | Cargo.lock 5 | -------------------------------------------------------------------------------- /ergo_std/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Garrett Berg "] 3 | description = "items that could be in the standard library, part of the ergo ecosystem" 4 | documentation = "https://docs.rs/ergo_std" 5 | keywords = [ 6 | "ergo", 7 | "std", 8 | ] 9 | license = "MIT OR Apache-2.0" 10 | name = "ergo_std" 11 | readme = "README.md" 12 | repository = "https://github.com/rust-crates/ergo_std" 13 | version = "0.0.4" 14 | 15 | [dependencies] 16 | itertools = "0.7" 17 | lazy_static = "1.0" 18 | maplit = "1.0" 19 | regex = "0.2.5" 20 | serde = "1.0" 21 | serde_derive = "1.0" 22 | std_prelude = "0.2" 23 | indexmap = "1.0.1" 24 | -------------------------------------------------------------------------------- /ergo_std/LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Copyright 2018 Garrett Berg, vitiral@gmail.com 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /ergo_std/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Garrett Berg, vitiral@gmail.com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /ergo_std/README.md: -------------------------------------------------------------------------------- 1 | # ergo_std: items that could be in the standard library. 2 | 3 | [![Build Status](https://travis-ci.org/rust-crates/ergo_std.svg?branch=master)](https://travis-ci.org/rust-crates/ergo_std) 4 | [![Build status](https://ci.appveyor.com/api/projects/status/vgis54solhygre0n?svg=true)](https://ci.appveyor.com/project/rust-crates/path-abs) 5 | [![Docs](https://docs.rs/ergo_std/badge.svg)](https://docs.rs/ergo_std) 6 | 7 | **See the [library docs](https://docs.rs/ergo_std) for more information** 8 | 9 | 10 | # LICENSE 11 | The source code in this repository is Licensed under either of 12 | - Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or 13 | http://www.apache.org/licenses/LICENSE-2.0) 14 | - MIT license ([LICENSE-MIT](LICENSE-MIT) or 15 | http://opensource.org/licenses/MIT) 16 | 17 | at your option. 18 | 19 | Unless you explicitly state otherwise, any contribution intentionally submitted 20 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall 21 | be dual licensed as above, without any additional terms or conditions. 22 | -------------------------------------------------------------------------------- /ergo_std/appveyor.yml: -------------------------------------------------------------------------------- 1 | # Appveyor configuration template for Rust using rustup for Rust installation 2 | # https://github.com/starkat99/appveyor-rust 3 | 4 | ## Operating System (VM environment) ## 5 | 6 | # Rust needs at least Visual Studio 2013 Appveyor OS for MSVC targets. 7 | os: Visual Studio 2015 8 | 9 | # Bors configuration 10 | branches: 11 | only: 12 | # This is where pull requests from "bors r+" are built. 13 | - staging 14 | # This is where pull requests from "bors try" are built. 15 | - trying 16 | 17 | ## Build Matrix ## 18 | 19 | # This configuration will setup a build for each channel & target combination (12 windows 20 | # combinations in all). 21 | # 22 | # There are 3 channels: stable, beta, and nightly. 23 | # 24 | # Alternatively, the full version may be specified for the channel to build using that specific 25 | # version (e.g. channel: 1.5.0) 26 | # 27 | # The values for target are the set of windows Rust build targets. Each value is of the form 28 | # 29 | # ARCH-pc-windows-TOOLCHAIN 30 | # 31 | # Where ARCH is the target architecture, either x86_64 or i686, and TOOLCHAIN is the linker 32 | # toolchain to use, either msvc or gnu. See https://www.rust-lang.org/downloads.html#win-foot for 33 | # a description of the toolchain differences. 34 | # See https://github.com/rust-lang-nursery/rustup.rs/#toolchain-specification for description of 35 | # toolchains and host triples. 36 | # 37 | # Comment out channel/target combos you do not wish to build in CI. 38 | # 39 | # You may use the `cargoflags` and `RUSTFLAGS` variables to set additional flags for cargo commands 40 | # and rustc, respectively. For instance, you can uncomment the cargoflags lines in the nightly 41 | # channels to enable unstable features when building for nightly. Or you could add additional 42 | # matrix entries to test different combinations of features. 43 | environment: 44 | matrix: 45 | 46 | ### MSVC Toolchains ### 47 | 48 | # Stable 64-bit MSVC 49 | - channel: stable 50 | target: x86_64-pc-windows-msvc 51 | # Stable 32-bit MSVC 52 | - channel: stable 53 | target: i686-pc-windows-msvc 54 | # # Beta 64-bit MSVC 55 | # - channel: beta 56 | # target: x86_64-pc-windows-msvc 57 | # # Beta 32-bit MSVC 58 | # - channel: beta 59 | # target: i686-pc-windows-msvc 60 | # # Nightly 64-bit MSVC 61 | # - channel: nightly 62 | # target: x86_64-pc-windows-msvc 63 | # #cargoflags: --features "unstable" 64 | # # Nightly 32-bit MSVC 65 | # - channel: nightly 66 | # target: i686-pc-windows-msvc 67 | # #cargoflags: --features "unstable" 68 | 69 | ### GNU Toolchains ### 70 | 71 | # Stable 64-bit GNU 72 | - channel: stable 73 | target: x86_64-pc-windows-gnu 74 | # Stable 32-bit GNU 75 | - channel: stable 76 | target: i686-pc-windows-gnu 77 | # # Beta 64-bit GNU 78 | # - channel: beta 79 | # target: x86_64-pc-windows-gnu 80 | # # Beta 32-bit GNU 81 | # - channel: beta 82 | # target: i686-pc-windows-gnu 83 | # # Nightly 64-bit GNU 84 | # - channel: nightly 85 | # target: x86_64-pc-windows-gnu 86 | # #cargoflags: --features "unstable" 87 | # # Nightly 32-bit GNU 88 | # - channel: nightly 89 | # target: i686-pc-windows-gnu 90 | # #cargoflags: --features "unstable" 91 | 92 | ### Allowed failures ### 93 | 94 | # See Appveyor documentation for specific details. In short, place any channel or targets you wish 95 | # to allow build failures on (usually nightly at least is a wise choice). This will prevent a build 96 | # or test failure in the matching channels/targets from failing the entire build. 97 | matrix: 98 | allow_failures: 99 | - channel: nightly 100 | 101 | # If you only care about stable channel build failures, uncomment the following line: 102 | #- channel: beta 103 | 104 | ## Install Script ## 105 | 106 | # This is the most important part of the Appveyor configuration. This installs the version of Rust 107 | # specified by the 'channel' and 'target' environment variables from the build matrix. This uses 108 | # rustup to install Rust. 109 | # 110 | # For simple configurations, instead of using the build matrix, you can simply set the 111 | # default-toolchain and default-host manually here. 112 | install: 113 | - appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe 114 | - rustup-init -yv --default-toolchain %channel% --default-host %target% 115 | - set PATH=%PATH%;%USERPROFILE%\.cargo\bin 116 | - rustc -vV 117 | - cargo -vV 118 | 119 | ## Build Script ## 120 | 121 | # 'cargo test' takes care of building for us, so disable Appveyor's build stage. This prevents 122 | # the "directory does not contain a project or solution file" error. 123 | build: false 124 | 125 | # Uses 'cargo test' to run tests and build. Alternatively, the project may call compiled programs 126 | #directly or perform other testing commands. Rust will automatically be placed in the PATH 127 | # environment variable. 128 | test_script: 129 | - cargo test --verbose --all %cargoflags% -- --nocapture 130 | -------------------------------------------------------------------------------- /ergo_std/bors.toml: -------------------------------------------------------------------------------- 1 | status = [ 2 | "continuous-integration/travis-ci/push", 3 | "continuous-integration/appveyor/branch" 4 | ] 5 | 6 | # Uncomment this to use a two hour timeout. 7 | # The default is one hour. 8 | # timeout_sec = 7200 9 | -------------------------------------------------------------------------------- /ergo_std/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! **ergo_std**: items that could be in the standard library. 2 | //! 3 | //! This is the "core types" library as part of the [`ergo`] crates ecosystem. It contains useful 4 | //! types, traits and functions for general purpose programming projects which do not fall 5 | //! into the other [`ergo`] crates but which are boons to ergonomics and productivity. 6 | //! 7 | //! # How to Use 8 | //! 9 | //! In your `Cargo.toml` 10 | //! 11 | //! ```toml,no_compile 12 | //! [dependencies] 13 | //! ergo_std = "0.1" 14 | //! serde = "1.0" 15 | //! serde_derive = "1.0" 16 | //! ``` 17 | //! 18 | //! > You have to put the other crates in your `Cargo.toml` in order for `#[derive(...)]` to work 19 | //! > correctly. 20 | //! 21 | //! ```rust 22 | //! #[macro_use] extern crate ergo_std; 23 | //! use ergo_std::*; 24 | //! fn main() { 25 | //! /* Your code goes here */ 26 | //! } 27 | //! ``` 28 | //! 29 | //! # Exported Items 30 | //! 31 | //! The following crates and types are exported. See their docs for how to use them. 32 | //! 33 | //! - **[`std_prelude`]**: extends rust's `std::prelude` with commonly used types. The 34 | //! crate is well documented with justification and usecases for each type. 35 | //! - **[`serde`]**: the defacto serialization library of rust. Also imports `serde_derive` 36 | //! so you can use `#[derive(Serialize, Deserialize)]`. 37 | //! - **[`lazy_static!`]**: the `lazy_static!` macro is the current standard way to create 38 | //! global variables and constants. Warning that they are created lazily (at run time)! 39 | //! - **[`itertools`]**: the itertools prelude provides traits that extends rust's already 40 | //! extensive iterator API. 41 | //! - **[`indexmap`]**: indexable and sortable map and set types with similar performance 42 | //! to `std` types and beter performance when iterating. 43 | //! - **[`maplit`]**: provides `hashmap!`, `hashset!`, `btreemap!` and `btreeset!` macros to 44 | //! compliment rust's existing `vec!` macro. These 45 | //! - **[`Regex`]**: the regular expression type from the `regex` crate. 46 | //! 47 | //! [`ergo`]: https://github.com/rust-crates/ergo 48 | //! [`std_prelude`]: ../std_prelude/index.html 49 | //! [`itertools`]: ../itertools/index.html 50 | //! [`indexmap`]: ../indexmap/index.html 51 | //! [`lazy_static!`]: ../lazy_static/index.html 52 | //! [`maplit`]: ../maplit/index.html 53 | //! [`Regex`]: struct.Regex.html 54 | //! 55 | //! ### Special thanks 56 | //! 57 | //! The crates that are exported are: 58 | //! 59 | //! - [**serde**](https://github.com/serde-rs/serde): Serialization framework for Rust 60 | //! - [**std_prelude**](https://github.com/vitiral/std_prelude): prelude that the rust stdlib 61 | //! should have always had 62 | //! - [**lazy_static**](https://github.com/rust-lang-nursery/lazy-static.rs): A small macro for 63 | //! defining lazy evaluated static variables in Rust. 64 | //! - [**itertools**](https://github.com/bluss/rust-itertools): Extra iterator adaptors, iterator 65 | //! methods, free functions, and macros. 66 | //! - [**indexmap**](https://github.com/bluss/indexmap): A hash table with consistent order and 67 | //! fast iteration (previously named `ordermap`) 68 | //! - [**maplit**](https://github.com/bluss/maplit): Rust container / collection literal macros for 69 | //! HashMap, HashSet, BTreeMap, BTreeSet. 70 | //! - [**regex**](https://github.com/rust-lang/regex): An implementation of regular expressions for 71 | //! Rust. This implementation uses finite automata and guarantees linear time matching on all 72 | //! inputs. 73 | //! 74 | //! Consider supporting their development individually and starring them on github. 75 | #![allow(unused_imports)] 76 | 77 | #[macro_use] 78 | pub extern crate itertools; 79 | #[macro_use] 80 | pub extern crate indexmap; 81 | #[macro_use] 82 | pub extern crate lazy_static; 83 | #[macro_use] 84 | pub extern crate maplit; 85 | pub extern crate std_prelude; 86 | pub extern crate regex; 87 | pub extern crate serde; 88 | #[macro_use] 89 | pub extern crate serde_derive; 90 | 91 | pub use std_prelude::*; 92 | pub use lazy_static::*; 93 | pub use itertools::Itertools; 94 | pub use indexmap::*; 95 | pub use maplit::*; 96 | pub use regex::Regex; 97 | pub use serde::*; 98 | pub use serde_derive::*; 99 | 100 | -------------------------------------------------------------------------------- /ergo_sync/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Garrett Berg "] 3 | description = "Methods and types for making working with the filesystem ergonomic, therefore fun." 4 | documentation = "https://docs.rs/ergo_sync" 5 | keywords = [ 6 | "thread", 7 | "channel", 8 | "sync", 9 | ] 10 | license = "MIT OR Apache-2.0" 11 | name = "ergo_sync" 12 | readme = "README.md" 13 | repository = "https://github.com/rust-crates/ergo_sync" 14 | version = "0.1.0" 15 | 16 | [dependencies] 17 | crossbeam-channel = "0.1.2" 18 | num_cpus = "1.8.0" 19 | std_prelude = "0.2.11" 20 | taken = "0.1.0" 21 | 22 | [dev-dependencies] 23 | rayon = "0.9.0" 24 | crossbeam-utils = "0.2.2" 25 | -------------------------------------------------------------------------------- /ergo_sync/LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Copyright 2018 Garrett Berg, vitiral@gmail.com 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /ergo_sync/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Garrett Berg, vitiral@gmail.com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /ergo_sync/README.md: -------------------------------------------------------------------------------- 1 | # ergo_sync: making creating and synchronizing threads ergonomic, therefore fun! 2 | 3 | [![Build Status](https://travis-ci.org/rust-crates/ergo_sync.svg?branch=master)](https://travis-ci.org/rust-crates/ergo_sync) 4 | [![Build status](https://ci.appveyor.com/api/projects/status/vgis54solhygre0n?svg=true)](https://ci.appveyor.com/project/rust-crates/path-abs) 5 | [![Docs](https://docs.rs/ergo_sync/badge.svg)](https://docs.rs/ergo_sync) 6 | 7 | **See the [library docs](https://docs.rs/ergo_sync) for more information** 8 | 9 | 10 | # LICENSE 11 | The source code in this repository is Licensed under either of 12 | - Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or 13 | http://www.apache.org/licenses/LICENSE-2.0) 14 | - MIT license ([LICENSE-MIT](LICENSE-MIT) or 15 | http://opensource.org/licenses/MIT) 16 | 17 | at your option. 18 | 19 | Unless you explicitly state otherwise, any contribution intentionally submitted 20 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall 21 | be dual licensed as above, without any additional terms or conditions. 22 | -------------------------------------------------------------------------------- /ergo_sync/appveyor.yml: -------------------------------------------------------------------------------- 1 | # Appveyor configuration template for Rust using rustup for Rust installation 2 | # https://github.com/starkat99/appveyor-rust 3 | 4 | ## Operating System (VM environment) ## 5 | 6 | # Rust needs at least Visual Studio 2013 Appveyor OS for MSVC targets. 7 | os: Visual Studio 2015 8 | 9 | # Bors configuration 10 | branches: 11 | only: 12 | # This is where pull requests from "bors r+" are built. 13 | - staging 14 | # This is where pull requests from "bors try" are built. 15 | - trying 16 | 17 | ## Build Matrix ## 18 | 19 | # This configuration will setup a build for each channel & target combination (12 windows 20 | # combinations in all). 21 | # 22 | # There are 3 channels: stable, beta, and nightly. 23 | # 24 | # Alternatively, the full version may be specified for the channel to build using that specific 25 | # version (e.g. channel: 1.5.0) 26 | # 27 | # The values for target are the set of windows Rust build targets. Each value is of the form 28 | # 29 | # ARCH-pc-windows-TOOLCHAIN 30 | # 31 | # Where ARCH is the target architecture, either x86_64 or i686, and TOOLCHAIN is the linker 32 | # toolchain to use, either msvc or gnu. See https://www.rust-lang.org/downloads.html#win-foot for 33 | # a description of the toolchain differences. 34 | # See https://github.com/rust-lang-nursery/rustup.rs/#toolchain-specification for description of 35 | # toolchains and host triples. 36 | # 37 | # Comment out channel/target combos you do not wish to build in CI. 38 | # 39 | # You may use the `cargoflags` and `RUSTFLAGS` variables to set additional flags for cargo commands 40 | # and rustc, respectively. For instance, you can uncomment the cargoflags lines in the nightly 41 | # channels to enable unstable features when building for nightly. Or you could add additional 42 | # matrix entries to test different combinations of features. 43 | environment: 44 | matrix: 45 | 46 | ### MSVC Toolchains ### 47 | 48 | # Stable 64-bit MSVC 49 | - channel: stable 50 | target: x86_64-pc-windows-msvc 51 | # Stable 32-bit MSVC 52 | - channel: stable 53 | target: i686-pc-windows-msvc 54 | # # Beta 64-bit MSVC 55 | # - channel: beta 56 | # target: x86_64-pc-windows-msvc 57 | # # Beta 32-bit MSVC 58 | # - channel: beta 59 | # target: i686-pc-windows-msvc 60 | # # Nightly 64-bit MSVC 61 | # - channel: nightly 62 | # target: x86_64-pc-windows-msvc 63 | # #cargoflags: --features "unstable" 64 | # # Nightly 32-bit MSVC 65 | # - channel: nightly 66 | # target: i686-pc-windows-msvc 67 | # #cargoflags: --features "unstable" 68 | 69 | ### GNU Toolchains ### 70 | 71 | # Stable 64-bit GNU 72 | - channel: stable 73 | target: x86_64-pc-windows-gnu 74 | # Stable 32-bit GNU 75 | - channel: stable 76 | target: i686-pc-windows-gnu 77 | # # Beta 64-bit GNU 78 | # - channel: beta 79 | # target: x86_64-pc-windows-gnu 80 | # # Beta 32-bit GNU 81 | # - channel: beta 82 | # target: i686-pc-windows-gnu 83 | # # Nightly 64-bit GNU 84 | # - channel: nightly 85 | # target: x86_64-pc-windows-gnu 86 | # #cargoflags: --features "unstable" 87 | # # Nightly 32-bit GNU 88 | # - channel: nightly 89 | # target: i686-pc-windows-gnu 90 | # #cargoflags: --features "unstable" 91 | 92 | ### Allowed failures ### 93 | 94 | # See Appveyor documentation for specific details. In short, place any channel or targets you wish 95 | # to allow build failures on (usually nightly at least is a wise choice). This will prevent a build 96 | # or test failure in the matching channels/targets from failing the entire build. 97 | matrix: 98 | allow_failures: 99 | - channel: nightly 100 | 101 | # If you only care about stable channel build failures, uncomment the following line: 102 | #- channel: beta 103 | 104 | ## Install Script ## 105 | 106 | # This is the most important part of the Appveyor configuration. This installs the version of Rust 107 | # specified by the 'channel' and 'target' environment variables from the build matrix. This uses 108 | # rustup to install Rust. 109 | # 110 | # For simple configurations, instead of using the build matrix, you can simply set the 111 | # default-toolchain and default-host manually here. 112 | install: 113 | - appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe 114 | - rustup-init -yv --default-toolchain %channel% --default-host %target% 115 | - set PATH=%PATH%;%USERPROFILE%\.cargo\bin 116 | - rustc -vV 117 | - cargo -vV 118 | 119 | ## Build Script ## 120 | 121 | # 'cargo test' takes care of building for us, so disable Appveyor's build stage. This prevents 122 | # the "directory does not contain a project or solution file" error. 123 | build: false 124 | 125 | # Uses 'cargo test' to run tests and build. Alternatively, the project may call compiled programs 126 | #directly or perform other testing commands. Rust will automatically be placed in the PATH 127 | # environment variable. 128 | test_script: 129 | - cargo test --verbose --all %cargoflags% -- --nocapture 130 | -------------------------------------------------------------------------------- /ergo_sync/bors.toml: -------------------------------------------------------------------------------- 1 | status = [ 2 | "continuous-integration/travis-ci/push", 3 | "continuous-integration/appveyor/branch" 4 | ] 5 | 6 | # Uncomment this to use a two hour timeout. 7 | # The default is one hour. 8 | # timeout_sec = 7200 9 | -------------------------------------------------------------------------------- /ergo_sync/src/ch.rs: -------------------------------------------------------------------------------- 1 | //! Module for working with channels. Rexport of [`crossbeam_channel`] 2 | //! 3 | //! 4 | //! # Examples 5 | //! 6 | //! > Several of these examples are copies of the [`chan`] and [`crossbeam_channel`] crates. 7 | //! 8 | //! [`chan`]: https://github.com/BurntSushi/chan 9 | //! [`crossbeam_channel`]: ../../crossbeam_channel/index.html 10 | //! 11 | //! ## Example: unbounded (async) channel 12 | //! 13 | //! ```rust 14 | //! #[macro_use] extern crate ergo_sync; 15 | //! use ergo_sync::*; 16 | //! 17 | //! # fn main() { 18 | //! let (tx, rx) = ch::unbounded(); 19 | //! 20 | //! // Can send an arbitrarily large number of messages. 21 | //! for i in 0..1000 { 22 | //! ch!(tx <- i); 23 | //! } 24 | //! # } 25 | //! ``` 26 | //! 27 | //! ## Example: bounded (sync) channel 28 | //! 29 | //! ```rust 30 | //! #[macro_use] extern crate ergo_sync; 31 | //! use ergo_sync::*; 32 | //! 33 | //! # fn main() { 34 | //! // Create a channel that can hold at most 5 messages at a time. 35 | //! let (tx, rx) = ch::bounded(5); 36 | //! 37 | //! // Can send only 5 messages. 38 | //! for i in 0..5 { 39 | //! ch!(tx <- i); 40 | //! } 41 | //! 42 | //! // An attempt to send one more message will fail. 43 | //! assert!(tx.try_send(5).is_err()); 44 | //! # } 45 | //! ``` 46 | //! 47 | //! ## Example: rendevous channel 48 | //! 49 | //! ```rust 50 | //! #[macro_use] extern crate ergo_sync; 51 | //! use ergo_sync::*; 52 | //! 53 | //! # fn main() { 54 | //! let (send, recv) = ch::bounded(0); 55 | //! spawn(move || ch!(send <- 5)); 56 | //! assert_eq!(ch!(<- recv), 5); // blocks until the previous send occurs 57 | //! # } 58 | //! ``` 59 | //! 60 | //! ## Example: the sentinel channel idiom 61 | //! 62 | //! When writing concurrent programs with `ergo`, you will often find that you need 63 | //! to somehow "wait" until some operation is done. For example, let's say you want 64 | //! to run a function in a separate thread, but wait until it completes. Here's 65 | //! one way to do it: 66 | //! 67 | //! ```rust 68 | //! #[macro_use] extern crate ergo_sync; 69 | //! use ergo_sync::*; 70 | //! 71 | //! fn do_work(done: ch::Sender<()>) { 72 | //! // do something 73 | //! 74 | //! // signal that we're done. 75 | //! ch!(done <- ()); 76 | //! } 77 | //! 78 | //! fn main() { 79 | //! let (sdone, rdone) = ch::bounded(0); 80 | //! spawn(move || do_work(sdone)); 81 | //! // block until work is done, and then quit the program. 82 | //! ch!(<- rdone); 83 | //! } 84 | //! ``` 85 | //! 86 | //! In effect, we've created a new channel that sends unit values. When we're 87 | //! done doing work, we send a unit value and `main` waits for it to be delivered. 88 | //! 89 | //! Another way of achieving the same thing is to simply close the channel. Once 90 | //! the channel is closed, any previously blocked receive operations become 91 | //! immediately unblocked. What's even cooler is that channels are closed 92 | //! automatically when all senders are dropped. So the new program looks something 93 | //! like this: 94 | //! 95 | //! ```rust 96 | //! #[macro_use] extern crate ergo_sync; 97 | //! use ergo_sync::*; 98 | //! 99 | //! fn do_work(_done: ch::Sender<()>) { 100 | //! // do something 101 | //! } 102 | //! 103 | //! fn main() { 104 | //! let (sdone, rdone) = ch::bounded(0); 105 | //! spawn(move || do_work(sdone)); 106 | //! // Block until the channel is closed. 107 | //! // 108 | //! // Note: this _expects_ the error that 109 | //! // all senders have been dropped and will 110 | //! // panic if a value is sent instead. 111 | //! ch!(! <- rdone); 112 | //! } 113 | //! ``` 114 | //! 115 | //! We no longer need to explicitly do anything with the `_done` channel. We give 116 | //! `do_work` ownership of the channel, but as soon as the function stops 117 | //! executing, `_done` is dropped, the channel is closed and `rdone.recv()` 118 | //! unblocks returning an error, which we expect with `ch!(! <- rdone)`. 119 | //! 120 | //! ## Example: non-blocking sends/receives 121 | //! 122 | //! ``` 123 | //! #[macro_use] extern crate ergo_sync; 124 | //! use ergo_sync::*; 125 | //! 126 | //! # fn main() { 127 | //! let (send, recv) = ch::bounded(1); 128 | //! let data = "send data".to_string(); 129 | //! match ch!(send <-? data) { 130 | //! Some(data) => { 131 | //! println!("didn't send data, but got it back: {}", data); 132 | //! unreachable!(); // in this case we don't expect it 133 | //! } 134 | //! None => println!("message sent successfully"), 135 | //! } 136 | //! 137 | //! // attempting to send additional data fails 138 | //! let data = "more data".to_string(); 139 | //! assert_eq!(Some(data.clone()), ch!(send <-? data)); 140 | //! 141 | //! match ch!(<-? recv) { 142 | //! Some(data) => println!("received data: {}", data), 143 | //! None => { 144 | //! println!("didn't receive any data yet"); 145 | //! unreachable!(); // in this case we don't expect it 146 | //! } 147 | //! } 148 | //! # } 149 | //! ``` 150 | //! 151 | //! ## Example: using `select_loop` 152 | //! 153 | //! ```rust 154 | //! #[macro_use] extern crate ergo_sync; 155 | //! use ergo_sync::*; 156 | //! 157 | //! # fn main() { 158 | //! let (tx1, rx1) = ch::unbounded(); 159 | //! let (tx2, rx2) = ch::unbounded(); 160 | //! 161 | //! spawn(move || ch!(tx1 <- "foo")); 162 | //! spawn(move || ch!(tx2 <- "bar")); 163 | //! 164 | //! select_loop! { 165 | //! recv(rx1, msg) => { 166 | //! println!("Received a message from the first channel: {}", msg); 167 | //! } 168 | //! recv(rx2, msg) => { 169 | //! println!("Received a message from the second channel: {}", msg); 170 | //! } 171 | //! } 172 | //! # } 173 | //! ``` 174 | //! 175 | 176 | pub use crossbeam_channel::{bounded, unbounded, IntoIter, Iter, Receiver, RecvError, 177 | RecvTimeoutError, Select, SelectRecvError, SelectSendError, SendError, 178 | SendTimeoutError, Sender, TryIter, TryRecvError, TrySendError}; 179 | 180 | /// Use with channels with ergonomic syntax and panic with helpful error messages when 181 | /// sending/receiving on a channel is invalid. 182 | /// 183 | /// - `ch!(send <- 42)` for sending a value. 184 | /// - `let v = ch!(<- recv)` for receiving a value. 185 | /// - `ch!(! <- recv)` to wait for channels to close. 186 | /// - `<-?` for async operation support. 187 | /// 188 | /// **Blocking syntax:** 189 | /// 190 | /// - `ch!(send <- value)`: blocks until a value is sent, panics if all receivers are dropped. 191 | /// - `ch!(<- recv)`: blocks until a value is received, panics if all senders are dropped. 192 | /// - `ch!(! <- recv)`: blocks until all senders are dropped, panics if a value is received. Used 193 | /// for signaling. 194 | /// 195 | /// > This syntax works with both `crossbeam-channel` channels (which are exported by this crate) as 196 | /// > well as `std::mspc` channels. 197 | /// 198 | /// > Note that these operations can deadlock if a channel is leaked. 199 | /// 200 | /// **Non-Blocking syntax:** 201 | /// 202 | /// - `ch!(send <-? value)`: returns `None` if the value was sent, `Some(value)` if the value 203 | /// was not sent. Panics if all receivers are dropped. 204 | /// - `ch!(<-? recv)`: returns `None` if no value is received, `Some(value)` if a value is 205 | /// received. Panics if all senders are dropped. 206 | /// - `ch!(! <-? recv)`: returns `true` if there are still senders and `false` if the seners have 207 | /// been dropped. Panics if a value is received. Use with `while ch!(! <-? recv) { /* ... */ }` 208 | /// 209 | /// > Non-Blocking syntax does _not_ work with `std::mspc` channels. 210 | /// 211 | /// # Examples 212 | /// 213 | /// ## Example: Using `ergo::chan` channels 214 | /// 215 | /// ```rust 216 | /// #[macro_use] extern crate ergo_sync; 217 | /// use ergo_sync::*; 218 | /// # fn main() { 219 | /// let (send, recv) = ch::bounded(3); 220 | /// ch!(send <- 4); 221 | /// ch!(send <- 7); 222 | /// ch!(send <- 42); 223 | /// assert_eq!(4, ch!(<- recv)); 224 | /// assert_eq!(7, ch!(<- recv)); 225 | /// let v = ch!(<- recv); 226 | /// assert_eq!(42, v); 227 | /// 228 | /// drop(send); 229 | /// // ch!(<- recv); // panics 230 | /// ch!(! <- recv); // succeeds 231 | /// # } 232 | /// ``` 233 | /// 234 | /// ## Example: Using `std::mspc` channels 235 | /// 236 | /// ```rust 237 | /// #[macro_use] extern crate ergo_sync; 238 | /// use std::sync::mpsc::sync_channel; 239 | /// 240 | /// # fn main() { 241 | /// let (send, recv) = sync_channel(3); 242 | /// ch!(send <- 4); 243 | /// ch!(send <- 7); 244 | /// ch!(send <- 42); 245 | /// assert_eq!(4, ch!(<- recv)); 246 | /// assert_eq!(7, ch!(<- recv)); 247 | /// let v = ch!(<- recv); 248 | /// assert_eq!(42, v); 249 | /// 250 | /// drop(send); 251 | /// // ch!(<- recv); // panics 252 | /// ch!(! <- recv); // succeeds 253 | /// # } 254 | /// ``` 255 | /// 256 | /// ## Example: using non-blocking syntax 257 | /// 258 | /// ```rust 259 | /// #[macro_use] extern crate ergo_sync; 260 | /// use ergo_sync::*; 261 | /// # fn main() { 262 | /// let (send, recv) = ch::bounded(3); 263 | /// assert_eq!(None, ch!(<-? recv)); // no values sent yet 264 | /// 265 | /// assert!(ch!(send <-? 4).is_none()); 266 | /// assert_eq!(Some(4), ch!(<-? recv)); 267 | /// assert_eq!(None, ch!(<-? recv)); 268 | /// 269 | /// assert!(ch!(send <-? 7).is_none()); 270 | /// assert!(ch!(send <-? 42).is_none()); 271 | /// assert!(ch!(send <-? 1).is_none()); 272 | /// // further attempts return the value 273 | /// assert_eq!(Some(100), ch!(send <-? 100)); 274 | /// 275 | /// assert_eq!(Some(7), ch!(<-? recv)); 276 | /// 277 | /// assert_eq!(Some(42), ch!(<-? recv)); 278 | /// assert_eq!(Some(1), ch!(<-? recv)); 279 | /// assert_eq!(None, ch!(<-? recv)); 280 | /// assert!(ch!(! <-? recv)); // senders still exist 281 | /// 282 | /// drop(send); 283 | /// // ch!(<-? recv); // panics 284 | /// ch!(! <-? recv); // succeeds 285 | /// # } 286 | /// ``` 287 | #[macro_export] 288 | macro_rules! ch { 289 | [$send:ident <-? $value:expr] => { 290 | match $send.try_send($value) { 291 | Ok(()) => None, 292 | Err($crate::ch::TrySendError::Full(v)) => Some(v), 293 | Err($crate::ch::TrySendError::Disconnected(_)) => { 294 | panic!("Attempted to send a value but receivers are disconnected"); 295 | } 296 | } 297 | }; 298 | 299 | [$send:ident <- $value:expr] => { 300 | match $send.send($value) { 301 | Ok(_) => {}, 302 | Err(err) => panic!("{} for `send`.", err), 303 | } 304 | }; 305 | 306 | [<-? $recv:ident] => { 307 | match $recv.try_recv() { 308 | Ok(v) => Some(v), 309 | Err($crate::ch::TryRecvError::Empty) => None, 310 | Err($crate::ch::TryRecvError::Disconnected) => { 311 | panic!("Attempted to recv a value but senders are disconnected"); 312 | } 313 | } 314 | }; 315 | [<- $recv:ident] => { 316 | match $recv.recv() { 317 | Ok(v) => v, 318 | Err(err) => panic!("{} for `recv`.", err), 319 | } 320 | }; 321 | 322 | 323 | [! <-? $recv:ident] => { 324 | match $recv.try_recv() { 325 | Ok(v) => panic!("Got {:?} when expecting senders to be closed.", v), 326 | Err($crate::ch::TryRecvError::Empty) => true, // senders still exist 327 | Err($crate::ch::TryRecvError::Disconnected) => false, // no more senders 328 | } 329 | }; 330 | [! <- $recv:ident] => { 331 | match $recv.recv() { 332 | Ok(v) => panic!("Got {:?} when expecting senders to be closed.", v), 333 | Err(err) => (), 334 | } 335 | }; 336 | } 337 | 338 | /// Handle an expression that could be `Err` and send it over a channel if it is. 339 | /// 340 | /// This is the same as the builtin `try!` macro, except if the expression fails than the `Err` is 341 | /// sent on the `$send` channel and the requested action is performed. 342 | /// 343 | /// Suggested possible actions: 344 | /// - `continue` 345 | /// - `return` 346 | /// - `break` 347 | /// - some expression that evaluates to a "default value" for that context. 348 | /// 349 | /// # Examples 350 | /// 351 | /// ```rust 352 | /// #[macro_use] extern crate ergo_sync; 353 | /// use ergo_sync::*; 354 | /// # fn main() { 355 | /// let (send_err, recv_err) = ch::unbounded(); 356 | /// let items = &[Ok("this is alright"), Err("not ok"), Err("still not okay")]; 357 | /// # let mut okay = 0; 358 | /// for item in items.iter() { 359 | /// let v = ch_try!(send_err, *item, continue); 360 | /// println!("got: {}", v); 361 | /// # okay += 1; 362 | /// } 363 | /// 364 | /// drop(send_err); 365 | /// let errs: Vec<_> = recv_err.iter().collect(); 366 | /// assert_eq!(vec!["not ok", "still not okay"], errs); 367 | /// # assert_eq!(1, okay); 368 | /// # } 369 | /// ``` 370 | #[macro_export] 371 | macro_rules! ch_try { 372 | [$send:ident, $expr:expr, $action:expr] => { 373 | match $expr { 374 | Ok(v) => v, 375 | Err(e) => { 376 | ch!($send <- e); 377 | $action 378 | } 379 | } 380 | }; 381 | } 382 | -------------------------------------------------------------------------------- /ergo_sync/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! **make creating and synchronizing threads ergonomic, therefore fun!** 2 | //! 3 | //! This is the synchronization library as part of the [`ergo`] crates ecosystem. It contains useful 4 | //! types, traits and functions for spawning threads and synchronizing them. It is named `sync` 5 | //! because of `std::sync` and because it is _not_ async, which is/will be a separate part of the 6 | //! ergo ecocystem. 7 | //! 8 | //! This provides ergonomic access to threading/synchronization primitives and macros. It does 9 | //! _not_ provide an opinion on which threading primitives you use. See the following crates: 10 | //! 11 | //! - [`rayon`] for procesing data structures in parallel. Note that [rayon cannot be used for 12 | //! generic iterators][ray_iter] (like `recv.iter()`). 13 | //! - [`may`] for stackful coroutines, similar to golang's goroutines. 14 | //! - [`crossbeam_utils`] for scoped threads. 15 | //! 16 | //! However, please note that in _most_ cases using [`spawn`] with channels and [`num_cpus`] 17 | //! is sufficient for performing _most_ tasks. Obviously if you are a server servicing 100+ 18 | //! clients, or doing big data analysis, or have other specific requirements then you want more 19 | //! specialized concurrency primitives, which the above can provide separately from this crate. 20 | //! 21 | //! [`ergo`]: https://github.com/rust-crates/ergo 22 | //! [`rayon`]: https://github.com/rayon-rs/rayon 23 | //! [ray_iter]: https://github.com/rayon-rs/rayon/issues/46 24 | //! [`may`]: https://docs.rs/may 25 | //! [`crossbeam_utils`]: https://docs.rs/crossbeam-utils/ 26 | //! [`num_cpus`]: ../num_cpus/index.html 27 | //! 28 | //! ### Thankyou 29 | //! 30 | //! The crates that are wraped/exported are: 31 | //! 32 | //! - [`crossbeam_channel`](https://github.com/crossbeam-rs/crossbeam-channel): 33 | //! Multi-producer multi-consumer channels for message passing 34 | //! - [`num_cpus`](https://github.com/seanmonstar/num_cpus): Get the number of CPUs in Rust 35 | //! - [`taken`](https://github.com/vitiral/taken): Macros for taking ownership 36 | //! 37 | //! Consider supporting their development individually and starring them on github. 38 | //! 39 | //! # How to Use 40 | //! 41 | //! Use this library with: 42 | //! 43 | //! ```rust 44 | //! #[macro_use] extern crate ergo_sync; 45 | //! use ergo_sync::*; 46 | //! # fn main() {} 47 | //! ``` 48 | //! 49 | //! ## Types Functions and Modules 50 | //! 51 | //! - **[`ch` module]**: for channel types (also see the [`ch!`] and [`select_loop!`] macros). 52 | //! - **[`spawn`]**: the standad `std::thread::spawn` which spawns a regular OS thread. The 53 | //! advantage of this (over scoped threads) is that it can outlive the current function. The 54 | //! disadvantage is that as far as the compiler knows it _always_ outlives the current function, 55 | //! meaning it must own all of its variables (or they have to be `'static`). 56 | //! - **[`num_cpus`]**: for getting the number of cpus when creating your own thread pools. 57 | //! - **[`std_prelude`]**: Various concurrency related types from `std_prelude` including: 58 | //! - `Atomic*`, `Mutex`, `Arc` for concurrency safe types 59 | //! - `sleep` and (redefined non-deprecated) `sleep_ms`. 60 | //! 61 | //! In addition it provides the following helper macros: 62 | //! 63 | //! - **[`ch!`]**:Use with channels with ergonomic syntax and panic with helpful error messages 64 | //! when sending/receiving on a channel is invalid. 65 | //! - `ch!(send <- 42)` for sending a value. 66 | //! - `let v = ch!(<- recv)` for receiving a value. 67 | //! - `ch!(! <- recv)` to wait for channels to close. 68 | //! - `<-?` for async operation support. 69 | //! - **[`ch_try!`]**: to handle an expression that could be `Err` and send it over a channel if it 70 | //! is. 71 | //! - **[`select_loop!`]**: for selecting from multiple channels. 72 | //! - **[`take!`]**: for expressing ownership consisely. You will move or clone 73 | //! variables extremely often in threads, this helps you express that better than 74 | //! `let value = value`. 75 | //! 76 | //! [`ch` module]: ch/index.html 77 | //! [`spawn`]: fn.spawn.html 78 | //! [`take!`]: macro.take.html 79 | //! [`ch!`]: macro.ch.html 80 | //! [`ch_try!`]: macro.ch_try.html 81 | //! [`select_loop!`]: macro.select_loop.html 82 | //! [`std_prelude`]: ../std_prelude/index.html 83 | //! 84 | //! # Examples 85 | //! 86 | //! ## Example: Channels 87 | //! See the docs for the [`ch` module]. 88 | //! 89 | //! ## Example: producer / consumer 90 | //! 91 | //! The producer/consumer model is this library's bread and butter. Once you understand 92 | //! channels you should next learn producer/consumer. 93 | //! 94 | //! In the `ergo_sync` model you should: 95 | //! 96 | //! - Do "CPU work" by spawning up to `num_cpus::get()` threads. 97 | //! - Do "IO work" using between 4 - 16 threads since most storage devices only provide up to that 98 | //! many channels. I personally prefer to use 8. 99 | //! 100 | //! A typical application might look like this: 101 | //! 102 | //! 103 | //! ```no_compile 104 | //! +-----------------------+ 105 | //! | Get paths to parse | 106 | //! | (typically one thread | 107 | //! | using walkdir which | 108 | //! | is rediculously fast) | 109 | //! | Send them via channel | 110 | //! +-----------------------+ 111 | //! ___|___ 112 | //! / | \ 113 | //! v v v 114 | //! +------------------------+ 115 | //! | 4-16 threads receiving | 116 | //! | paths via channels and | 117 | //! | reading raw strings. | 118 | //! | | 119 | //! | These are sent to next | 120 | //! | stage via channels | 121 | //! +------------------------+ 122 | //! ___|___ 123 | //! / | \ 124 | //! v v v 125 | //! +------------------------+ 126 | //! | num_cpu threads | 127 | //! | reading the string | 128 | //! | iterators and | 129 | //! | processing them. | 130 | //! | | 131 | //! | This is pure cpu work. | 132 | //! +------------------------+ 133 | //! | 134 | //! | 135 | //! v 136 | //! +------------------------+ 137 | //! | Collect results in the | 138 | //! | current thread to | 139 | //! | prepare for next step | 140 | //! +------------------------+ 141 | //! ``` 142 | //! 143 | //! This example basically implements the above example using the source code 144 | //! of this crate as the example. The below code searches through the crate 145 | //! source looking for every use of the word _"example"_. 146 | //! 147 | //! > Note: it is recommended to use [`ergo_fs`] to do filesystem operations, as all errors will 148 | //! > have the _context_ (path and action) of what caused the error and you will have access to 149 | //! > best in class filesystem operations like walking the directory structure and expressing 150 | //! > the types you expect. We do not use it here so we can focus on `ergo_sync`'s API. 151 | //! 152 | //! [`ergo_fs`]: https://github.com/rust-crates/ergo_fs 153 | //! 154 | //! ```rust 155 | //! #[macro_use] extern crate ergo_sync; 156 | //! 157 | //! use std::fs; 158 | //! use std::io; 159 | //! use std::io::prelude::*; 160 | //! use std::path::{Path, PathBuf}; 161 | //! use ergo_sync::*; 162 | //! 163 | //! /// List the dir and return any paths found 164 | //! fn read_paths>( 165 | //! dir: P, send_paths: &Sender, 166 | //! errs: &Sender, 167 | //! ) { 168 | //! for entry in ch_try!(errs, fs::read_dir(dir), return) { 169 | //! let entry = ch_try!(errs, entry, continue); 170 | //! let meta = ch_try!(errs, entry.metadata(), continue); 171 | //! if meta.is_file() { 172 | //! ch!(send_paths <- entry.path()); 173 | //! } else if meta.is_dir() { 174 | //! // recurse into the path 175 | //! read_paths(entry.path(), send_paths, errs); 176 | //! } else { 177 | //! // ignore symlinks for this example 178 | //! } 179 | //! } 180 | //! } 181 | //! 182 | //! /// Send one line at a time from the file 183 | //! fn read_lines(path: PathBuf, send_lines: &Sender, errs: &Sender) { 184 | //! let file = ch_try!(errs, fs::File::open(path), return); 185 | //! let buf = io::BufReader::new(file); 186 | //! for line in buf.lines() { 187 | //! // send the line but return immediately if any `io::Error` is hit 188 | //! ch!(send_lines <- ch_try!(errs, line, return)); 189 | //! } 190 | //! } 191 | //! 192 | //! /// Parse each line for "example", counting the number of times it appears. 193 | //! fn count_examples(line: &str) -> u64 { 194 | //! // Probably use the `regex` crate in a real life example. 195 | //! line.match_indices("example").count() as u64 196 | //! } 197 | //! 198 | //! fn main() { 199 | //! let (recv_count, handle_errs) = { 200 | //! // This scope will drop channels that we are not returning. 201 | //! // This prevents deadlock, as recv channels will not stop 202 | //! // blocking until all their send counterparts are dropped. 203 | //! let (send_errs, recv_errs) = ch::bounded(128); 204 | //! let (send_paths, recv_paths) = ch::bounded(128); 205 | //! 206 | //! // First we spawn a single thread to handle errors. 207 | //! // In this case we will just count and log them. 208 | //! let handle_errs = spawn(|| { 209 | //! take!(recv_errs); 210 | //! let mut count = 0_u64; 211 | //! for err in recv_errs.iter() { 212 | //! eprintln!("ERROR: {}", err); 213 | //! count += 1; 214 | //! } 215 | //! count 216 | //! }); 217 | //! 218 | //! // We spawn a single thread to "walk" the directory for paths. 219 | //! let errs = send_errs.clone(); 220 | //! spawn(|| { 221 | //! take!(send_paths, errs); 222 | //! read_paths("src", &send_paths, &errs); 223 | //! }); 224 | //! 225 | //! // We read the lines using 8 threads (since this is IO bound) 226 | //! let (send_lines, recv_lines) = ch::bounded(128); 227 | //! for _ in 0..8 { 228 | //! take!(=recv_paths, =send_lines, =send_errs); 229 | //! spawn(|| { 230 | //! take!(recv_paths, send_lines, send_errs); 231 | //! for path in recv_paths { 232 | //! read_lines(path, &send_lines, &send_errs); 233 | //! } 234 | //! }); 235 | //! } 236 | //! 237 | //! // Now we do actual "CPU work" using the rayon thread pool 238 | //! let (send_count, recv_count) = ch::bounded(128); 239 | //! 240 | //! // Create a pool of threads for actually doing the "work" 241 | //! for _ in 0..num_cpus::get() { 242 | //! take!(=recv_lines, =send_count); 243 | //! spawn(move || { 244 | //! for line in recv_lines.iter() { 245 | //! let count = count_examples(&line); 246 | //! if count != 0 { 247 | //! ch!(send_count <- count); 248 | //! } 249 | //! } 250 | //! }); 251 | //! } 252 | //! (recv_count, handle_errs) 253 | //! }; 254 | //! 255 | //! // Finally we can get our count. 256 | //! let count: u64 = recv_count.iter().sum(); 257 | //! # // assert_eq!(839, count); 258 | //! 259 | //! // And assert we had no errors 260 | //! assert_eq!(0, handle_errs.finish()); 261 | //! } 262 | //! ``` 263 | #[allow(unused_imports)] 264 | #[macro_use(take)] 265 | extern crate taken; 266 | #[allow(unused_imports)] 267 | #[macro_use(select_loop)] 268 | pub extern crate crossbeam_channel; 269 | pub extern crate std_prelude; 270 | pub extern crate num_cpus; 271 | 272 | // -------- std_prelude exports -------- 273 | // Types 274 | pub use std_prelude::{Arc, Duration, Mutex}; 275 | // Atomics 276 | pub use std_prelude::{AtomicBool, AtomicIsize, AtomicOrdering, AtomicUsize, ATOMIC_USIZE_INIT}; 277 | // Functions 278 | pub use std_prelude::{sleep, spawn}; 279 | 280 | // -------- macro exports-------- 281 | #[allow(unused_imports)] 282 | #[doc(hidden)] 283 | pub mod reexports { 284 | // hack to rexport macros 285 | #[doc(hidden)] 286 | pub use taken::*; 287 | pub use crossbeam_channel::*; 288 | } 289 | pub use reexports::*; 290 | 291 | pub mod ch; 292 | 293 | use std_prelude::*; 294 | 295 | /// Convinience trait mimicking `std::thread::JoinHandle` with better ergonomics. 296 | pub trait FinishHandle 297 | where 298 | T: Send + 'static, 299 | { 300 | /// Finishes the thread, returning the value. 301 | /// 302 | /// This is the same as `JoinHandle::join()` except the unwrap is automatic. 303 | /// 304 | /// # Panics 305 | /// Panics if the thread is poisoned (if a panic happened inside the thread). 306 | /// 307 | /// # Examples 308 | /// ```rust 309 | /// # extern crate ergo_sync; 310 | /// # use ergo_sync::*; 311 | /// # fn main() { 312 | /// // sleep for half a second 313 | /// let th = spawn(|| sleep_ms(100)); 314 | /// th.finish(); // as opposed to `th.join().unwrap()` 315 | /// # } 316 | /// ``` 317 | fn finish(self) -> T; 318 | } 319 | 320 | impl FinishHandle for ::std::thread::JoinHandle { 321 | fn finish(self) -> T { 322 | self.join() 323 | .expect("finish failed to join, thread is poisoned") 324 | } 325 | } 326 | 327 | /// Just sleep for a certain number of milliseconds. 328 | /// 329 | /// Equivalent of `sleep(Duration::from_millis(millis))` 330 | /// 331 | /// This function exists in `std::thread` but is deprecated, so it created here instead. 332 | /// 333 | /// # Examples 334 | /// ```rust 335 | /// # extern crate ergo_sync; 336 | /// # use ergo_sync::*; 337 | /// # fn main() { 338 | /// // sleep for half a second 339 | /// sleep_ms(500); 340 | /// # } 341 | /// ``` 342 | #[inline(always)] 343 | pub fn sleep_ms(millis: u64) { 344 | sleep(Duration::from_millis(millis)) 345 | } 346 | 347 | -------------------------------------------------------------------------------- /ergo_sync/src/scoped.rs: -------------------------------------------------------------------------------- 1 | // TODO: this doesn't compile and rayon and crossbeam_utils were removed from this library. 2 | // figure out what to do with these examples. 3 | 4 | //! `ergo_sync` does not provide scoped threads. However, you can get access to them 5 | //! through the libraries [`rayon`] or [`crossbeam_utils`] 6 | //! 7 | //! However, the crate [`crossbeam_utils`] has excellent scoped threads 8 | //! if you should need them. The API for crossbeam's scoped-threads and 9 | //! rayon's is almost identical except with rayon you must make sure 10 | //! to _not_ put both your producers and consumers in the rayon thread pool. 11 | //! 12 | //! Note that scoped threads are only useful if: 13 | //! 14 | //! - Your threads need to take references to anything that can't simply be moved. 15 | //! - Your threads are extremely performance sensitive. 16 | //! 17 | //! [`crossbeam_utils`]: https://github.com/crossbeam-rs/crossbeam-utils 18 | //! [`rayon`]: (https://github.com/rayon-rs/rayon): Rayon: A data parallelism library for Rust 19 | //! 20 | //! # Examples 21 | //! ## Example: producers and consumers 22 | //! 23 | //! ```rust 24 | //! #[macro_use] extern crate ergo_sync; 25 | //! extern crate crossbeam_utils; 26 | //! use crossbeam_utils::scoped; 27 | //! use ergo_sync::*; 28 | //! 29 | //! # fn main() { 30 | //! let external_val = 42; 31 | //! 32 | //! // the thread scope allows us to access local variables 33 | //! // and ensures that threads get joined. 34 | //! let result = scoped::scope(|sc| { 35 | //! // rendevous channel 36 | //! let (send, recv) = ch::bounded(0); 37 | //! 38 | //! // ------------------------------- 39 | //! // ---- spawn your consumers ----- 40 | //! let consumer = sc.spawn(|| -> u64 { 41 | //! take!(recv); // same as `let recv = recv` 42 | //! recv.iter().sum() 43 | //! }); 44 | //! 45 | //! // ------------------------------- 46 | //! // ---- spawn your producers ----- 47 | //! take!(=send as s); // same as `let s = send.clone()` 48 | //! sc.spawn(|| { 49 | //! take!(s); 50 | //! // do some expensive function 51 | //! ch!(s <- 42_u64.pow(4)); 52 | //! }); 53 | //! 54 | //! take!(=send as s); 55 | //! sc.spawn(|| { 56 | //! take!(s); 57 | //! // Each function can also use rayon's traits to do 58 | //! // iteration in parallel. 59 | //! (0..1000_u64).into_par_iter().for_each(|n| { 60 | //! ch!(s <- n * 42); 61 | //! }); 62 | //! }); 63 | //! 64 | //! // Always have your final producer take `send` without 65 | //! // cloning it. This will drop it and and prevent 66 | //! // deadlocks. 67 | //! sc.spawn(|| { 68 | //! take!(send, &external_val as val); 69 | //! ch!(send <- expensive_fn(val)); 70 | //! }); 71 | //! 72 | //! consumer.join() 73 | //! }); 74 | //! 75 | //! assert_eq!(24_094_896, result); 76 | //! # } 77 | //! 78 | //! /// Really expensive function 79 | //! fn expensive_fn(v: &u32) -> u64 { 80 | //! println!("Doing expensive thing"); 81 | //! sleep_ms(300); 82 | //! *v as u64 * 100 83 | //! } 84 | //! ``` 85 | //! 86 | //! ## Example: multiple producers and multiple consumers using channels 87 | //! 88 | //! This example is addapted from the [chan docs]. 89 | //! 90 | //! [chan docs]: https://docs.rs/chan/0.1.20/chan/#example-multiple-producers-and-multiple-consumers 91 | //! 92 | //! ``` 93 | //! #[macro_use] extern crate ergo_sync; 94 | //! extern crate crossbeam_utils; 95 | //! use ergo_sync::*; 96 | //! use crossbeam_utils::scoped; 97 | //! 98 | //! # fn main() { 99 | //! scoped::scope(|sc| { 100 | //! let (send, recv) = ch::bounded(0); 101 | //! 102 | //! // Kick off the receiving threads as scoped threads 103 | //! for _ in 0..4 { 104 | //! take!(=recv); 105 | //! sc.spawn(|| { 106 | //! for letter in recv { 107 | //! println!("Received letter: {}", letter); 108 | //! } 109 | //! }); 110 | //! } 111 | //! 112 | //! // Send values in parallel using the rayon thread pool. 113 | //! let mut chars: Vec<_> = "A man, a plan, a canal - Panama!" 114 | //! .chars() 115 | //! .collect(); 116 | //! chars.into_par_iter().map(|letter| { 117 | //! take!(=send); // take a clone of `send` 118 | //! for _ in 0..10 { 119 | //! ch!(send <- letter); 120 | //! } 121 | //! }); 122 | //! 123 | //! // Note: the following occurs in order because of the scope: 124 | //! // - `send` and `recv` are dropped 125 | //! // - All threads are joined 126 | //! }) 127 | //! # } 128 | //! ``` 129 | -------------------------------------------------------------------------------- /ergo_sys/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Garrett Berg "] 3 | description = "Make accessing system resources more ergonomic, therefore more fun!" 4 | documentation = "https://docs.rs/ergo_sys" 5 | keywords = [ 6 | "ergo", 7 | "system", 8 | "os", 9 | ] 10 | license = "MIT OR Apache-2.0" 11 | name = "ergo_sys" 12 | readme = "README.md" 13 | repository = "https://github.com/rust-crates/ergo_sys" 14 | version = "0.0.1" 15 | 16 | [dependencies] 17 | ctrlc = "3.1.0" 18 | rand = "0.4.2" 19 | -------------------------------------------------------------------------------- /ergo_sys/LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Copyright 2018 Garrett Berg, vitiral@gmail.com 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /ergo_sys/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Garrett Berg, vitiral@gmail.com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /ergo_sys/README.md: -------------------------------------------------------------------------------- 1 | # ergo_sys: make accessing system resources more ergonomic, therefore more fun! 2 | 3 | [![Build Status](https://travis-ci.org/rust-crates/ergo_sys.svg?branch=master)](https://travis-ci.org/rust-crates/ergo_sys) 4 | [![Build status](https://ci.appveyor.com/api/projects/status/vgis54solhygre0n?svg=true)](https://ci.appveyor.com/project/rust-crates/path-abs) 5 | [![Docs](https://docs.rs/ergo_sys/badge.svg)](https://docs.rs/ergo_sys) 6 | 7 | **See the [library docs](https://docs.rs/ergo_sys) for more information** 8 | 9 | 10 | # LICENSE 11 | The source code in this repository is Licensed under either of 12 | - Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or 13 | http://www.apache.org/licenses/LICENSE-2.0) 14 | - MIT license ([LICENSE-MIT](LICENSE-MIT) or 15 | http://opensource.org/licenses/MIT) 16 | 17 | at your option. 18 | 19 | Unless you explicitly state otherwise, any contribution intentionally submitted 20 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall 21 | be dual licensed as above, without any additional terms or conditions. 22 | -------------------------------------------------------------------------------- /ergo_sys/appveyor.yml: -------------------------------------------------------------------------------- 1 | # Appveyor configuration template for Rust using rustup for Rust installation 2 | # https://github.com/starkat99/appveyor-rust 3 | 4 | ## Operating System (VM environment) ## 5 | 6 | # Rust needs at least Visual Studio 2013 Appveyor OS for MSVC targets. 7 | os: Visual Studio 2015 8 | 9 | # Bors configuration 10 | branches: 11 | only: 12 | # This is where pull requests from "bors r+" are built. 13 | - staging 14 | # This is where pull requests from "bors try" are built. 15 | - trying 16 | 17 | ## Build Matrix ## 18 | 19 | # This configuration will setup a build for each channel & target combination (12 windows 20 | # combinations in all). 21 | # 22 | # There are 3 channels: stable, beta, and nightly. 23 | # 24 | # Alternatively, the full version may be specified for the channel to build using that specific 25 | # version (e.g. channel: 1.5.0) 26 | # 27 | # The values for target are the set of windows Rust build targets. Each value is of the form 28 | # 29 | # ARCH-pc-windows-TOOLCHAIN 30 | # 31 | # Where ARCH is the target architecture, either x86_64 or i686, and TOOLCHAIN is the linker 32 | # toolchain to use, either msvc or gnu. See https://www.rust-lang.org/downloads.html#win-foot for 33 | # a description of the toolchain differences. 34 | # See https://github.com/rust-lang-nursery/rustup.rs/#toolchain-specification for description of 35 | # toolchains and host triples. 36 | # 37 | # Comment out channel/target combos you do not wish to build in CI. 38 | # 39 | # You may use the `cargoflags` and `RUSTFLAGS` variables to set additional flags for cargo commands 40 | # and rustc, respectively. For instance, you can uncomment the cargoflags lines in the nightly 41 | # channels to enable unstable features when building for nightly. Or you could add additional 42 | # matrix entries to test different combinations of features. 43 | environment: 44 | matrix: 45 | 46 | ### MSVC Toolchains ### 47 | 48 | # Stable 64-bit MSVC 49 | - channel: stable 50 | target: x86_64-pc-windows-msvc 51 | # Stable 32-bit MSVC 52 | - channel: stable 53 | target: i686-pc-windows-msvc 54 | # # Beta 64-bit MSVC 55 | # - channel: beta 56 | # target: x86_64-pc-windows-msvc 57 | # # Beta 32-bit MSVC 58 | # - channel: beta 59 | # target: i686-pc-windows-msvc 60 | # # Nightly 64-bit MSVC 61 | # - channel: nightly 62 | # target: x86_64-pc-windows-msvc 63 | # #cargoflags: --features "unstable" 64 | # # Nightly 32-bit MSVC 65 | # - channel: nightly 66 | # target: i686-pc-windows-msvc 67 | # #cargoflags: --features "unstable" 68 | 69 | ### GNU Toolchains ### 70 | 71 | # Stable 64-bit GNU 72 | - channel: stable 73 | target: x86_64-pc-windows-gnu 74 | # Stable 32-bit GNU 75 | - channel: stable 76 | target: i686-pc-windows-gnu 77 | # # Beta 64-bit GNU 78 | # - channel: beta 79 | # target: x86_64-pc-windows-gnu 80 | # # Beta 32-bit GNU 81 | # - channel: beta 82 | # target: i686-pc-windows-gnu 83 | # # Nightly 64-bit GNU 84 | # - channel: nightly 85 | # target: x86_64-pc-windows-gnu 86 | # #cargoflags: --features "unstable" 87 | # # Nightly 32-bit GNU 88 | # - channel: nightly 89 | # target: i686-pc-windows-gnu 90 | # #cargoflags: --features "unstable" 91 | 92 | ### Allowed failures ### 93 | 94 | # See Appveyor documentation for specific details. In short, place any channel or targets you wish 95 | # to allow build failures on (usually nightly at least is a wise choice). This will prevent a build 96 | # or test failure in the matching channels/targets from failing the entire build. 97 | matrix: 98 | allow_failures: 99 | - channel: nightly 100 | 101 | # If you only care about stable channel build failures, uncomment the following line: 102 | #- channel: beta 103 | 104 | ## Install Script ## 105 | 106 | # This is the most important part of the Appveyor configuration. This installs the version of Rust 107 | # specified by the 'channel' and 'target' environment variables from the build matrix. This uses 108 | # rustup to install Rust. 109 | # 110 | # For simple configurations, instead of using the build matrix, you can simply set the 111 | # default-toolchain and default-host manually here. 112 | install: 113 | - appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe 114 | - rustup-init -yv --default-toolchain %channel% --default-host %target% 115 | - set PATH=%PATH%;%USERPROFILE%\.cargo\bin 116 | - rustc -vV 117 | - cargo -vV 118 | 119 | ## Build Script ## 120 | 121 | # 'cargo test' takes care of building for us, so disable Appveyor's build stage. This prevents 122 | # the "directory does not contain a project or solution file" error. 123 | build: false 124 | 125 | # Uses 'cargo test' to run tests and build. Alternatively, the project may call compiled programs 126 | #directly or perform other testing commands. Rust will automatically be placed in the PATH 127 | # environment variable. 128 | test_script: 129 | - cargo test --verbose --all %cargoflags% -- --nocapture 130 | -------------------------------------------------------------------------------- /ergo_sys/bors.toml: -------------------------------------------------------------------------------- 1 | status = [ 2 | "continuous-integration/travis-ci/push", 3 | "continuous-integration/appveyor/branch" 4 | ] 5 | 6 | # Uncomment this to use a two hour timeout. 7 | # The default is one hour. 8 | # timeout_sec = 7200 9 | -------------------------------------------------------------------------------- /ergo_sys/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! **ergo_sys: make accessing system resources more ergonomic, therefore more fun!** 2 | //! 3 | //! This is the system/os library as part of the [`ergo`] crate ecosystem. 4 | //! 5 | //! TODO: flush out these docs more 6 | //! 7 | //! - add example of using ergo_sync with ctrlc. 8 | //! - talk about rand a bit and the different kinds of types and their usecases. 9 | //! 10 | //! [`ergo`]: https://github.com/rust-crates/ergo 11 | //! 12 | //! ### Special thanks 13 | //! 14 | //! The crates that are exported are: 15 | //! 16 | //! - [**ctrlc**](https://github.com/Detegr/rust-ctrlc): Easy Ctrl-C handler for Rust projects 17 | //! - [**rand**](https://github.com/rust-lang-nursery/rand): A Rust library for random number 18 | //! generators and other randomness functionality. 19 | //! 20 | //! Consider supporting their development individually and starring them on github. 21 | 22 | pub extern crate rand; 23 | pub extern crate ctrlc; 24 | --------------------------------------------------------------------------------