os_info-1.3.2/.circleci/config.yml010064400017500001750000000012211344425521400152150ustar0000000000000000version: 2 jobs: build_and_test: macos: xcode: "9.0" environment: - RUSTFLAGS: -D warnings steps: - checkout - restore_cache: keys: - cache-{{ arch }}-{{ .Branch }} - run: curl https://sh.rustup.rs -sSf | sh -s -- -y - run: echo 'export PATH=~/.cargo/bin:$PATH' >> $BASH_ENV - run: rustup show - run: cargo build - run: cargo test - save_cache: key: cache-{{ arch }}-{{ .Branch }} paths: - $HOME/.cargo - $HOME/.rustup - target workflows: version: 2 build_and_test: jobs: - build_and_test os_info-1.3.2/.cspell.json010064400017500001750000000002741344425521400136340ustar0000000000000000{ "version": "0.1", "language": "en", "dictionaries": ["en_US", "softwareTerms", "os_info"], "dictionaryDefinitions": [ { "name": "os_info", "path": "./cspell-dictionary.txt" } ] } os_info-1.3.2/.editorconfig010064400017500001750000000005031344425521400140510ustar0000000000000000# EditorConfig helps developers define and maintain consistent coding styles # between different editors and IDEs. # editorconfig.org root = true [*] end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true indent_style = space indent_size = 4 [*.md] trim_trailing_whitespace = false os_info-1.3.2/.gitattributes010064400017500001750000000000311344425521400142630ustar0000000000000000CHANGELOG.md merge=union os_info-1.3.2/.github/ISSUE_TEMPLATE.md010064400017500001750000000002231344425521400154400ustar0000000000000000 os_info-1.3.2/.github/PULL_REQUEST_TEMPLATE.md010064400017500001750000000001451344425521400165370ustar0000000000000000 os_info-1.3.2/.github/workflows/version.yml010064400017500001750000000011251361070542300171770ustar0000000000000000name: Rust version compatibility check on: [push, pull_request] jobs: build: runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-latest, windows-latest, macOS-latest] # Feel free to bump this version if you need features of newer Rust. # Sync with badge in README.md rust: [1.32.0] steps: - uses: hecrj/setup-rust-action@v1 with: rust-version: ${{ matrix.rust }} - uses: actions/checkout@master - name: Build run: cargo build --verbose - name: Run example run: cargo run --example print_version os_info-1.3.2/.gitignore010064400017500001750000000002101344425521400133570ustar0000000000000000# cargo target *.rs.bk Cargo.lock # node (for cspell) /node_modules /npm-debug.log /package-lock.json # IDE files .idea .vscode *.iml os_info-1.3.2/.travis.yml010064400017500001750000000036631361070542300135140ustar0000000000000000language: rust rust: - 1.40.0 branches: only: - master # Github release tags (for example "v0.9" or "v0.9.1"). - /^v\d+\.\d+(\.\d+)?(-\S*)?$/ cache: directories: - node_modules - $HOME/.cargo - $HOME/.local - $TRAVIS_BUILD_DIR/target dist: trusty sudo: required env: global: - DEADLINKS_VERS=0.3.0 - CARGO_INCREMENTAL=1 matrix: - FEATURE=test jobs: include: # Formatting & other lints that do not require compilation. - name: lints install: - cargo-audit -V || cargo install cargo-audit --force - cargo-deadlinks -V | grep $DEADLINKS_VERS || cargo install cargo-deadlinks --vers $DEADLINKS_VERS --force - cargo install --list - rustup component add rustfmt - rustfmt -V - nvm install 8 && nvm use 8 - npm install cspell - ./node_modules/.bin/cspell --version - npm install markdownlint-cli - ./node_modules/.bin/markdownlint --version script: - cargo fmt --all -- --check - ./node_modules/.bin/cspell src/**/*.rs - ./node_modules/.bin/cspell examples/**/*.rs - ./node_modules/.bin/cspell tests/**/*.rs - find . -not -path "./node_modules/*" -not -path "./target/*" -name "*.md" | xargs ./node_modules/.bin/cspell - find . -not -path "./node_modules/*" -not -path "./target/*" -name "*.md" | xargs ./node_modules/.bin/markdownlint - cargo doc --no-deps - cargo deadlinks --dir target/doc # Clippy linting. - name: clippy install: - rustup component add clippy - cargo clippy -V script: - cargo clippy --all -- -D warnings # Tests. - name: tests script: - cargo test --all - cargo run --example print_version # Coverage. - name: coverage rust: nightly before_install: - sudo apt-get install -y libssl-dev install: - RUSTFLAGS="--cfg procmacro2_semver_exempt" cargo install cargo-tarpaulin -f script: - cargo tarpaulin --out Xml - bash <(curl -s https://codecov.io/bash) os_info-1.3.2/CODE_OF_CONDUCT.md010064400017500001750000000062151344425521400142010ustar0000000000000000# Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at . The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at . [homepage]: http://contributor-covenant.org os_info-1.3.2/CONTRIBUTING.md010064400017500001750000000024511344425521400136310ustar0000000000000000# Contributing to os_info We welcome contribution from everyone. Here are the guidelines if you are thinking of helping us: ## Contributions Contributions to `os_info` or its dependencies should be made in the form of GitHub pull requests. Each pull request will be reviewed by a core contributor (someone with permission to land patches) and either landed in the main tree or given feedback for changes that would be required. All contributions should follow this format, even those from core contributors. Should you wish to work on an issue, please claim it first by commenting on the GitHub issue that you want to work on it. This is to prevent duplicated efforts from contributors on the same issue. ## Pull Request Checklist - Branch from the master branch and, if needed, rebase to the current master branch before submitting your pull request. If it doesn't merge cleanly with master you may be asked to rebase your changes. - Commits should be as small as possible, while ensuring that each commit is correct independently (i.e., each commit should compile and pass tests). - If your patch is not getting reviewed or you need a specific person to review it, you can @-reply a reviewer asking for a review in the pull request or a comment. - Add tests relevant to the fixed bug or new feature. os_info-1.3.2/Cargo.toml.orig010064400017500001750000000024101361071055600142620ustar0000000000000000[package] name = "os_info" version = "1.3.2" authors = ["Jan Schulte ", "Stanislav Tkach "] description = "Detect the operating system type and version." documentation = "https://docs.rs/os_info" homepage = "https://github.com/darkeld3r/os_info" repository = "https://github.com/darkeld3r/os_info" readme = "README.md" keywords = ["os", "os_type", "os_version", "os_info"] categories = ["os"] license = "MIT" build = "build.rs" edition = "2018" [badges] appveyor = { repository = "DarkEld3r/os_info", service = "github" } circle-ci = { repository = "DarkEld3r/os_info" } travis-ci = { repository = "DarkEld3r/os_info" } is-it-maintained-issue-resolution = { repository = "DarkEld3r/os_info" } is-it-maintained-open-issues = { repository = "DarkEld3r/os_info" } [dependencies] log = "0.4.5" serde = "1.0.0" serde_derive = "1.0.0" [target.'cfg(not(windows))'.dependencies] regex="1.0.5" [target.'cfg(target_os = "macos")'.dependencies] lazy_static = "1.1.0" [target.'cfg(windows)'.dependencies] winapi = { version = "0.3.8", features = ["minwindef", "ntdef", "ntstatus", "sysinfoapi", "winnt", "winuser", "libloaderapi", "processthreadsapi"] } [dev-dependencies] itertools = "0.8.2" pretty_assertions = "0.6.1" doc-comment = "0.3.1" os_info-1.3.2/Cargo.toml0000644000000036351361071056600106030ustar00# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] edition = "2018" name = "os_info" version = "1.3.2" authors = ["Jan Schulte ", "Stanislav Tkach "] build = "build.rs" description = "Detect the operating system type and version." homepage = "https://github.com/darkeld3r/os_info" documentation = "https://docs.rs/os_info" readme = "README.md" keywords = ["os", "os_type", "os_version", "os_info"] categories = ["os"] license = "MIT" repository = "https://github.com/darkeld3r/os_info" [dependencies.log] version = "0.4.5" [dependencies.serde] version = "1.0.0" [dependencies.serde_derive] version = "1.0.0" [dev-dependencies.doc-comment] version = "0.3.1" [dev-dependencies.itertools] version = "0.8.2" [dev-dependencies.pretty_assertions] version = "0.6.1" [target."cfg(not(windows))".dependencies.regex] version = "1.0.5" [target."cfg(target_os = \"macos\")".dependencies.lazy_static] version = "1.1.0" [target."cfg(windows)".dependencies.winapi] version = "0.3.8" features = ["minwindef", "ntdef", "ntstatus", "sysinfoapi", "winnt", "winuser", "libloaderapi", "processthreadsapi"] [badges.appveyor] repository = "DarkEld3r/os_info" service = "github" [badges.circle-ci] repository = "DarkEld3r/os_info" [badges.is-it-maintained-issue-resolution] repository = "DarkEld3r/os_info" [badges.is-it-maintained-open-issues] repository = "DarkEld3r/os_info" [badges.travis-ci] repository = "DarkEld3r/os_info" os_info-1.3.2/Cargo.toml.orig0000644000000024101361071056600115300ustar00[package] name = "os_info" version = "1.3.2" authors = ["Jan Schulte ", "Stanislav Tkach "] description = "Detect the operating system type and version." documentation = "https://docs.rs/os_info" homepage = "https://github.com/darkeld3r/os_info" repository = "https://github.com/darkeld3r/os_info" readme = "README.md" keywords = ["os", "os_type", "os_version", "os_info"] categories = ["os"] license = "MIT" build = "build.rs" edition = "2018" [badges] appveyor = { repository = "DarkEld3r/os_info", service = "github" } circle-ci = { repository = "DarkEld3r/os_info" } travis-ci = { repository = "DarkEld3r/os_info" } is-it-maintained-issue-resolution = { repository = "DarkEld3r/os_info" } is-it-maintained-open-issues = { repository = "DarkEld3r/os_info" } [dependencies] log = "0.4.5" serde = "1.0.0" serde_derive = "1.0.0" [target.'cfg(not(windows))'.dependencies] regex="1.0.5" [target.'cfg(target_os = "macos")'.dependencies] lazy_static = "1.1.0" [target.'cfg(windows)'.dependencies] winapi = { version = "0.3.8", features = ["minwindef", "ntdef", "ntstatus", "sysinfoapi", "winnt", "winuser", "libloaderapi", "processthreadsapi"] } [dev-dependencies] itertools = "0.8.2" pretty_assertions = "0.6.1" doc-comment = "0.3.1" os_info-1.3.2/Changelog.md010064400017500001750000000071631361071055600136160ustar0000000000000000# Change Log All notable changes to this project will be documented in this file. ## [Unreleased] ## [1.3.2] (2020-01-19) - Bitness detection has been implemented for Linux. (#125) ## [1.3.1] (2020-01-15) - Missing winapi features have been added. (#123) ## [1.3.0] (2020-01-14) - `Info` has been extended with operating system bitness. See `Info::bitness` for details. Currently implemented only for Windows. (#119) - `Info`'s `Display` implementation has been fixed. (#113) - `winapi` dependency version has been updated to `0.3`. (#115) ## [1.2.0] (2019-11-11) - Distinguish between Red Hat and Red Hat Enterprise operating system versions. (#107) ## [1.1.3] (2019-09-11) - Amazon Linux support has been added. (#105) ## [1.1.2] (2019-09-11) - OS X beta versions support has been added. (#103) ## [1.1.1] (2019-03-22) - Migrate to the 2018 edition. (#96) - Fix deprecation warnings. (#95) - Update dependencies versions. (#94) ## [1.1.0] (2018-10-13) - Serialization support (`serde`) has been added to all public data types. (#91) - Dependencies have been updated. (#92, #93) ## [1.0.3] (2018-09-23) - Fixed linker errors for 32-bit msvc builds. (#88) ## [1.0.2] (2018-09-05) - Fixed issue with incorrect Linux version detection. (#85). ## [1.0.1] (2018-05-27) - Compilation has been fixed for all "unsupported" operating systems. Now `Unknown` `Type` is returned in such cases. ## [1.0.0] (2018-05-21) - Better Linux, Windows and OS X support. - Numerous code improvements. - More and better testing. - Logging. ## [0.7.0] (2018-01-21) - Fixed issued with OS X build. ## [0.6.0] (2017-12-17) - Alpine Linux support (#48). - Use release files is possible (#48). ## [0.5.0] (2017-12-13) - Windows support (#45). - Fedora support (#46). ## [0.4.0] (2017-11-12) - Redox support (untested). ## [0.3.0] (2017-11-02) - Fix OS X build. ## [0.2.0] (2017-11-02) - Add "dead" links check (#32). - Fix Travis badge on crates.io. - Travis OS X build (#35). ## [0.1.1] (2017-10-03) - Examples have been updated slightly. - Readme has been updated. ## [0.1.0] (2017-10-03) The first release containing only minor infrastructural changes and based on [os_type](https://github.com/schultyy/os_type). [Unreleased]: https://github.com/darkeld3r/os_info/compare/v1.3.2...HEAD [1.3.2]: https://github.com/darkeld3r/os_info/compare/v1.3.1...v1.3.2 [1.3.1]: https://github.com/darkeld3r/os_info/compare/v1.3...v1.3.1 [1.3.0]: https://github.com/darkeld3r/os_info/compare/v1.2...v1.3 [1.2.0]: https://github.com/darkeld3r/os_info/compare/v1.1.3...v1.2 [1.1.3]: https://github.com/darkeld3r/os_info/compare/v1.1.2...v1.1.3 [1.1.2]: https://github.com/darkeld3r/os_info/compare/v1.1.1...v1.1.2 [1.1.1]: https://github.com/darkeld3r/os_info/compare/v1.1...v1.1.1 [1.1.0]: https://github.com/darkeld3r/os_info/compare/v1.0.3...v1.1 [1.0.3]: https://github.com/darkeld3r/os_info/compare/v1.0.2...v1.0.3 [1.0.2]: https://github.com/darkeld3r/os_info/compare/v1.0.1...v1.0.2 [1.0.1]: https://github.com/darkeld3r/os_info/compare/v1.0.1...v1.0.2 [1.0.0]: https://github.com/darkeld3r/os_info/compare/v0.7.0...v1.0 [0.7.0]: https://github.com/darkeld3r/os_info/compare/v0.6.0...v0.7.0 [0.6.0]: https://github.com/darkeld3r/os_info/compare/v0.5.0...v0.6.0 [0.5.0]: https://github.com/darkeld3r/os_info/compare/v0.4.0...v0.5.0 [0.4.0]: https://github.com/darkeld3r/os_info/compare/v0.3.0...v0.4.0 [0.3.0]: https://github.com/darkeld3r/os_info/compare/v0.2.0...v0.3.0 [0.2.0]: https://github.com/darkeld3r/os_info/compare/v.0.1.1...v0.2.0 [0.1.1]: https://github.com/darkeld3r/os_info/compare/v0.1.0...v.0.1.1 [0.1.0]: https://github.com/darkeld3r/os_info/tree/v0.1.0 os_info-1.3.2/LICENSE010064400017500001750000000020721344425521400124040ustar0000000000000000The MIT License (MIT) Copyright (c) 2017 Stanislav Tkach Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. os_info-1.3.2/README.md010064400017500001750000000047771361071055600126740ustar0000000000000000# os_info **Status:** [![Travis Build Status](https://img.shields.io/travis/DarkEld3r/os_info/master.svg?label=Linux)](https://travis-ci.org/DarkEld3r/os_info) [![CircleCI Build Status](https://img.shields.io/circleci/project/github/DarkEld3r/os_info/master.svg?label=MacOS)](https://circleci.com/gh/darkeld3r/os_info/tree/master) [![AppVeyor Build Status](https://img.shields.io/appveyor/ci/darkeld3r/os-info/master.svg?label=Windows)](https://ci.appveyor.com/project/DarkEld3r/os-info/branch/master) **Project info:** [![Docs.rs](https://docs.rs/os_info/badge.svg)](https://docs.rs/os_info) [![Latest Version](http://meritbadge.herokuapp.com/os_info)](https://crates.io/crates/os_info) [![License](https://img.shields.io/github/license/darkeld3r/os_info.svg)](https://github.com/darkeld3r/os_info) **Project details:** [![LoC](https://tokei.rs/b1/github/darkeld3r/os_info)](https://github.com/darkeld3r/os_info) ![rust 1.33+ required](https://img.shields.io/badge/rust-1.32+-blue.svg?label=Required%20Rust) [![dependency status](https://deps.rs/repo/github/darkeld3r/os_info/status.svg)](https://deps.rs/repo/github/darkeld3r/os_info) ## Overview Library for detecting the operating system type and version. Based on [os_type](https://github.com/schultyy/os_type). The main difference of `os_info` is that this library separates completely incompatible operating systems by conditional compilation and uses specific system API whenever is possible. ## Usage To use this crate, add `os_info` as a dependency to your project's Cargo.toml: ```toml [dependencies] os_info = "1.3.2" ``` ## Example ```rust let info = os_info::get(); // Print full information: println!("OS information: {}", info); // Print information separately: println!("Type: {}", info.os_type()); println!("Version: {}", info.version()); println!("Bitness: {}", info.bitness()); ``` Right now, the following operating system types can be returned: - Unknown - Android - Emscripten - Linux - Redhat - RedHatEnterprise - Ubuntu - Debian - Arch - CentOS - Fedora - Amazon - Alpine - Macos - Redox - Windows If you need support for more OS types, I am looking forward to your Pull Request. ## Requirements On Linux based systems this library requires that [lsb_release] is installed. ## License `os_info` is licensed under the MIT license. See [LICENSE] for the details. [lsb_release]: http://refspecs.linuxbase.org/LSB_2.0.1/LSB-PDA/LSB-PDA/lsbrelease.html [LICENSE]: https://github.com/darkeld3r/os_info/blob/master/LICENSE os_info-1.3.2/appveyor.yml010064400017500001750000000014031361070542300137610ustar0000000000000000os: Visual Studio 2015 cache: - '%USERPROFILE%\.cargo' - target environment: matrix: - channel: stable target: x86_64-pc-windows-msvc - channel: stable target: x86_64-pc-windows-gnu - channel: stable target: i686-pc-windows-msvc - channel: stable target: i686-pc-windows-gnu install: - appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe - rustup-init -yv --default-toolchain %channel% --default-host %target% - set PATH=%PATH%;%USERPROFILE%\.cargo\bin - rustc -vV - cargo -vV build: false test_script: - cargo test --verbose - cargo run --example print_version notifications: - provider: Email on_build_success: false on_build_failure: true on_build_status_changed: true os_info-1.3.2/build.rs010064400017500001750000000016161344425521400130470ustar0000000000000000fn main() { use std::env::var; use std::path::Path; // When targeting x86_64-pc-windows-gnu, we need to include the DLL libraries // found in the lib/x86_64 directory if var("TARGET") .map(|target| target == "x86_64-pc-windows-gnu") .unwrap_or(false) { let dir = var("CARGO_MANIFEST_DIR").unwrap(); println!( "cargo:rustc-link-search=native={}", Path::new(&dir).join("lib/x86_64").display() ) } // When targeting i686-pc-windows-gnu, we need to include the DLL libraries // found in the lib/i686 directory if var("TARGET") .map(|target| target == "i686-pc-windows-gnu") .unwrap_or(false) { let dir = var("CARGO_MANIFEST_DIR").unwrap(); println!( "cargo:rustc-link-search=native={}", Path::new(&dir).join("lib/i686").display() ) } } os_info-1.3.2/cspell-dictionary.txt010064400017500001750000000001151361070542300155560ustar0000000000000000bitness centos emscripten macos msvc println redhat serde toml winapi xenial os_info-1.3.2/examples/print_version.rs010064400017500001750000000004411361070542300164570ustar0000000000000000fn main() { let info = os_info::get(); // Print full information: println!("OS information: {}", info); // Print information separately: println!("Type: {}", info.os_type()); println!("Version: {}", info.version()); println!("Bitness: {}", info.bitness()); } os_info-1.3.2/src/android/mod.rs010064400017500001750000000010431361070542300147250ustar0000000000000000use log::trace; use crate::{Bitness, Info, Type, Version}; pub fn current_platform() -> Info { trace!("android::current_platform is called"); let info = Info { os_type: Type::Android, version: Version::unknown(), bitness: Bitness::Unknown, }; trace!("Returning {:?}", info); info } #[cfg(test)] mod tests { use super::*; use pretty_assertions::assert_eq; #[test] fn os_type() { let version = current_platform(); assert_eq!(Type::Android, version.os_type()); } } os_info-1.3.2/src/bitness.rs010064400017500001750000000012601361070542300141760ustar0000000000000000use std::fmt::{self, Display, Formatter}; use serde_derive::{Deserialize, Serialize}; /// Operating system architecture in terms of how many bits compose the basic values it can deal with. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] pub enum Bitness { /// Unknown bitness (unable to determine). Unknown, /// 32-bit. X32, /// 64-bit. X64, } impl Display for Bitness { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match *self { Bitness::Unknown => write!(f, "unknown"), Bitness::X32 => write!(f, "32-bit"), Bitness::X64 => write!(f, "64-bit"), } } } os_info-1.3.2/src/emscripten/mod.rs010064400017500001750000000011261361070542300154600ustar0000000000000000use log::trace; use crate::{Bitness, Info, Type, Version}; // TODO: Somehow get the real OS version? pub fn current_platform() -> Info { trace!("emscripten::current_platform is called"); let info = Info { os_type: Type::Emscripten, version: Version::unknown(), bitness: Bitness::Unknown, }; trace!("Returning {:?}", info); info } #[cfg(test)] mod tests { use super::*; use pretty_assertions::assert_eq; #[test] fn os_type() { let version = current_platform(); assert_eq!(Type::Emscripten, version.os_type()); } } os_info-1.3.2/src/info.rs010064400017500001750000000114761361070542300134740ustar0000000000000000use std::fmt::{self, Display, Formatter}; use serde_derive::{Deserialize, Serialize}; use super::{Bitness, Type, Version}; /// Holds information about operating system (type, version, etc.). /// /// The best way to get string representation of the operation system information is to use its /// `Display` implementation. /// /// # Examples /// /// ``` /// use os_info; /// /// let info = os_info::get(); /// println!("OS information: {}", info); /// ``` #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] pub struct Info { /// Operating system type. See `Type` for details. pub(crate) os_type: Type, /// Operating system version. See `Version` for details. pub(crate) version: Version, /// Operating system architecture in terms of how many bits compose the basic values it can deal /// with. See `Bitness` for details. pub(crate) bitness: Bitness, } impl Info { /// Constructs a new `Info` instance with unknown type, version and bitness. /// /// # Examples /// /// ``` /// use os_info::{Info, Type, Version, Bitness}; /// /// let info = Info::unknown(); /// assert_eq!(Type::Unknown, info.os_type()); /// assert_eq!(Version::unknown(), *info.version()); /// assert_eq!(Bitness::Unknown, info.bitness()); /// ``` pub fn unknown() -> Self { Self { os_type: Type::Unknown, version: Version::unknown(), bitness: Bitness::Unknown, } } /// Constructs a new `Info` instance with the given type, version and bitness. /// /// # Examples /// /// ``` /// use os_info::{Info, Type, Version, Bitness}; /// /// let os_type = Type::Unknown; /// let version = Version::unknown(); /// let bitness = Bitness::Unknown; /// let info = Info::new(os_type, version.clone(), bitness); /// assert_eq!(os_type, info.os_type()); /// assert_eq!(version, *info.version()); /// assert_eq!(bitness, info.bitness()); /// ``` pub fn new(os_type: Type, version: Version, bitness: Bitness) -> Self { Self { os_type, version, bitness, } } /// Returns operating system type. See `Type` for details. /// /// # Examples /// /// ``` /// use os_info::{Info, Type}; /// /// let info = Info::unknown(); /// assert_eq!(Type::Unknown, info.os_type()); /// ``` pub fn os_type(&self) -> Type { self.os_type } /// Returns operating system version. See `Version` for details. /// /// # Examples /// /// ``` /// use os_info::{Info, Version}; /// /// let info = Info::unknown(); /// assert_eq!(Version::unknown(), *info.version()); /// ``` pub fn version(&self) -> &Version { &self.version } /// Returns operating system bitness. See `Bitness` for details. /// /// # Examples /// /// ``` /// use os_info::{Info, Bitness}; /// /// let info = Info::unknown(); /// assert_eq!(Bitness::Unknown, info.bitness()); /// ``` pub fn bitness(&self) -> Bitness { self.bitness } } impl Default for Info { fn default() -> Self { Self::unknown() } } impl Display for Info { fn fmt(&self, f: &mut Formatter) -> fmt::Result { write!(f, "{}", self.os_type)?; write!(f, " ({})", self.version)?; write!(f, " ({})", self.bitness) } } #[cfg(test)] mod tests { use super::*; use itertools::iproduct; use pretty_assertions::assert_eq; #[test] fn unknown() { let info = Info::unknown(); assert_eq!(Type::Unknown, info.os_type()); assert_eq!(&Version::unknown(), info.version()); assert_eq!(Bitness::Unknown, info.bitness()); } #[test] fn new() { let types = [ Type::Unknown, Type::Android, Type::Emscripten, Type::Linux, Type::Redhat, Type::Ubuntu, Type::Debian, Type::Arch, Type::Centos, Type::Fedora, Type::Alpine, Type::Macos, Type::Redox, Type::Windows, ]; let versions = [ Version::unknown(), Version::semantic(0, 0, 0, None), Version::semantic(1, 2, 3, Some("e".to_owned())), Version::custom("version".to_owned(), None), Version::custom("different version".to_owned(), Some("edition".to_owned())), ]; let bitnesses = [Bitness::Unknown, Bitness::X32, Bitness::X64]; for (os_type, version, bitness) in iproduct!(&types, &versions, &bitnesses) { let info = Info::new(*os_type, version.clone(), *bitness); assert_eq!(*os_type, info.os_type()); assert_eq!(version, info.version()); } } } os_info-1.3.2/src/lib.rs010064400017500001750000000026551361070542300133060ustar0000000000000000//! `os_info` //! //! Provides interfaces for getting information about the current operating system, such as type, //! version and edition. #![deny(missing_debug_implementations, missing_docs, unsafe_code)] #[cfg(target_os = "android")] #[path = "android/mod.rs"] mod imp; #[cfg(target_os = "emscripten")] #[path = "emscripten/mod.rs"] mod imp; #[cfg(target_os = "linux")] #[path = "linux/mod.rs"] mod imp; #[cfg(target_os = "macos")] #[path = "macos/mod.rs"] mod imp; #[cfg(target_os = "redox")] #[path = "redox/mod.rs"] mod imp; #[cfg(windows)] #[path = "windows/mod.rs"] mod imp; #[cfg(not(any( target_os = "android", target_os = "emscripten", target_os = "linux", target_os = "macos", target_os = "redox", target_os = "windows" )))] #[path = "unknown/mod.rs"] mod imp; mod bitness; mod info; mod os_type; mod version; pub use bitness::Bitness; pub use info::Info; pub use os_type::Type; pub use version::{Version, VersionType}; /// Returns information about the current operating system (type, version, edition, etc.). /// /// # Examples /// /// ``` /// use os_info; /// /// let info = os_info::get(); /// /// // Print full information: /// println!("OS information: {}", info); /// /// // Print information separately: /// println!("Type: {}", info.os_type()); /// println!("Version: {}", info.version()); /// println!("Bitness: {}", info.bitness()); /// ``` pub fn get() -> Info { imp::current_platform() } os_info-1.3.2/src/linux/file_release.rs010064400017500001750000000104761361070542300163160ustar0000000000000000use std::{fs::File, io::Read, path::Path}; use log::{trace, warn}; use regex::Regex; use crate::{Bitness, Info, Type, Version}; pub fn get() -> Option { retrieve(&DISTRIBUTIONS) } fn retrieve(distributions: &[ReleaseInfo]) -> Option { for release_info in distributions { if !Path::new(release_info.path).exists() { trace!("Path '{}' doesn't exist", release_info.path); continue; } let mut file = match File::open(&release_info.path) { Ok(val) => val, Err(e) => { warn!("Unable to open {:?} file: {:?}", release_info.path, e); continue; } }; let mut file_content = String::new(); if let Err(e) = file.read_to_string(&mut file_content) { warn!("Unable to read {:?} file: {:?}", release_info.path, e); continue; } let version = if !release_info.version_regex.is_empty() { let version_regex = Regex::new(release_info.version_regex).unwrap(); version_regex .captures_iter(&file_content) .next() .and_then(|c| c.get(1)) .map(|v| v.as_str().trim_end().to_owned()) } else { Some(file_content.trim_end().to_string()) } .map(|x| Version::custom(x, None)) .unwrap_or_else(Version::unknown); return Some(Info::new(release_info.os_type, version, Bitness::Unknown)); } None } #[derive(Debug, Clone)] struct ReleaseInfo<'a> { os_type: Type, path: &'a str, version_regex: &'static str, } /// List of all supported distributions and the information on how to parse their version from the /// release file. const DISTRIBUTIONS: [ReleaseInfo; 4] = [ ReleaseInfo { os_type: Type::Centos, path: "/etc/centos-release", version_regex: r"release\s([\w\.]+)", }, ReleaseInfo { os_type: Type::Fedora, path: "/etc/fedora-release", version_regex: r"release\s([\w\.]+)", }, ReleaseInfo { os_type: Type::Redhat, path: "/etc/redhat-release", version_regex: r"release\s([\w\.]+)", }, ReleaseInfo { os_type: Type::Alpine, path: "/etc/alpine-release", version_regex: "", }, ]; #[cfg(test)] mod tests { use super::*; use pretty_assertions::assert_eq; use std::path::PathBuf; #[test] fn centos() { let mut file = PathBuf::from(env!("CARGO_MANIFEST_DIR")); file.push("src/linux/tests/centos-release"); let path = file.into_os_string().into_string().unwrap(); let mut distributions = [DISTRIBUTIONS[0].clone()]; distributions[0].path = &path; let info = retrieve(&distributions).unwrap(); assert_eq!(info.os_type(), Type::Centos); assert_eq!(info.version, Version::custom("XX", None)); } #[test] fn fedora() { let mut file = PathBuf::from(env!("CARGO_MANIFEST_DIR")); file.push("src/linux/tests/fedora-release"); let path = file.into_os_string().into_string().unwrap(); let mut distributions = [DISTRIBUTIONS[1].clone()]; distributions[0].path = &path; let info = retrieve(&distributions).unwrap(); assert_eq!(info.os_type(), Type::Fedora); assert_eq!(info.version, Version::custom("26", None)); } #[test] fn redhat() { let mut file = PathBuf::from(env!("CARGO_MANIFEST_DIR")); file.push("src/linux/tests/redhat-release"); let path = file.into_os_string().into_string().unwrap(); let mut distributions = [DISTRIBUTIONS[2].clone()]; distributions[0].path = &path; let info = retrieve(&distributions).unwrap(); assert_eq!(info.os_type(), Type::Redhat); assert_eq!(info.version, Version::custom("XX", None)); } #[test] fn alpine() { let mut file = PathBuf::from(env!("CARGO_MANIFEST_DIR")); file.push("src/linux/tests/alpine-release"); let path = file.into_os_string().into_string().unwrap(); let mut distributions = [DISTRIBUTIONS[3].clone()]; distributions[0].path = &path; let info = retrieve(&distributions).unwrap(); assert_eq!(info.os_type(), Type::Alpine); assert_eq!(info.version, Version::custom("A.B.C", None)); } } os_info-1.3.2/src/linux/lsb_release.rs010064400017500001750000000156421361070542300161570ustar0000000000000000// spell-checker:ignore codename, noarch, rhel, ootpa, maipo use std::process::Command; use log::{trace, warn}; use regex::Regex; use crate::{Bitness, Info, Type, Version}; pub fn get() -> Option { let release = retrieve()?; let version = release .version .map_or_else(Version::unknown, |v| Version::custom(v, None)); let os_type = match release.distribution.as_ref().map(String::as_ref) { Some("Ubuntu") => Type::Ubuntu, Some("Debian") => Type::Debian, Some("Arch") => Type::Arch, Some("CentOS") => Type::Centos, Some("RedHatEnterprise") | Some("RedHatEnterpriseServer") => Type::RedHatEnterprise, Some("Fedora") => Type::Fedora, Some("Amazon") | Some("AmazonAMI") => Type::Amazon, _ => Type::Linux, }; Some(Info::new(os_type, version, Bitness::Unknown)) } struct LsbRelease { pub distribution: Option, pub version: Option, } fn retrieve() -> Option { match Command::new("lsb_release").arg("-a").output() { Ok(output) => { trace!("lsb_release command returned {:?}", output); Some(parse(&String::from_utf8_lossy(&output.stdout))) } Err(e) => { warn!("lsb_release command failed with {:?}", e); None } } } fn parse(output: &str) -> LsbRelease { trace!("Trying to parse {:?}", output); let distribution_regex = Regex::new(r"Distributor ID:\s(\w+)").unwrap(); let distribution = distribution_regex .captures_iter(output) .next() .and_then(|c| c.get(1)) .map(|d| d.as_str().to_owned()); let version_regex = Regex::new(r"Release:\s+([\w]+[.]?[\w]*)?").unwrap(); let version = version_regex .captures_iter(output) .next() .and_then(|c| c.get(1)) .map(|v| v.as_str().to_owned()); trace!( "Parsed as '{:?}' distribution and '{:?}' version", distribution, version ); LsbRelease { distribution, version, } } #[cfg(test)] mod tests { use super::*; use pretty_assertions::assert_eq; #[test] pub fn debian() { let parse_results = parse(file()); assert_eq!(parse_results.distribution, Some("Debian".to_string())); assert_eq!(parse_results.version, Some("7.8".to_string())); } #[test] pub fn arch() { let parse_results = parse(arch_file()); assert_eq!(parse_results.distribution, Some("Arch".to_string())); assert_eq!(parse_results.version, Some("rolling".to_string())); } #[test] pub fn fedora() { let parse_results = parse(fedora_file()); assert_eq!(parse_results.distribution, Some("Fedora".to_string())); assert_eq!(parse_results.version, Some("26".to_string())); } #[test] pub fn ubuntu() { let parse_results = parse(ubuntu_file()); assert_eq!(parse_results.distribution, Some("Ubuntu".to_string())); assert_eq!(parse_results.version, Some("16.04".to_string())); } #[test] pub fn amazon1() { let parse_results = parse(amazon1_file()); assert_eq!(parse_results.distribution, Some("AmazonAMI".to_string())); assert_eq!(parse_results.version, Some("2018.03".to_string())); } #[test] pub fn amazon2() { let parse_results = parse(amazon2_file()); assert_eq!(parse_results.distribution, Some("Amazon".to_string())); assert_eq!(parse_results.version, Some("2".to_string())); } #[test] pub fn redhat_enterprise_8() { let parse_results = parse(rhel8_file()); assert_eq!( parse_results.distribution, Some("RedHatEnterprise".to_string()) ); assert_eq!(parse_results.version, Some("8.1".to_string())); } #[test] pub fn redhat_enterprise_7() { let parse_results = parse(rhel7_file()); assert_eq!( parse_results.distribution, Some("RedHatEnterpriseServer".to_string()) ); assert_eq!(parse_results.version, Some("7.7".to_string())); } #[test] pub fn redhat_enterprise_6() { let parse_results = parse(rhel6_file()); assert_eq!( parse_results.distribution, Some("RedHatEnterpriseServer".to_string()) ); assert_eq!(parse_results.version, Some("6.10".to_string())); } fn file() -> &'static str { "\nDistributor ID: Debian\n\ Description: Debian GNU/Linux 7.8 (wheezy)\n\ Release: 7.8\n\ Codename: wheezy\n\ " } fn arch_file() -> &'static str { "\nLSB Version: 1.4\n\ Distributor ID: Arch\n\ Description: Arch Linux\n\ Release: rolling\n\ Codename: n/a" } fn fedora_file() -> &'static str { "\nLSB Version: :core-4.1-amd64:core-4.1-noarch:cxx-4.1-amd64:cxx-4.1-noarch\n\ Distributor ID: Fedora\n\ Description: Fedora release 26 (Twenty Six)\n\ Release: 26\n\ Codename: TwentySix\n\ " } fn ubuntu_file() -> &'static str { "Distributor ID: Ubuntu\n\ Description: Ubuntu 16.04.5 LTS\n\ Release: 16.04\n\ Codename: xenial" } // Amazon Linux 1 uses a separate Distributor ID and Release format from Amazon Linux 2 fn amazon1_file() -> &'static str { "LSB Version: :base-4.0-amd64:base-4.0-noarch:core-4.0-amd64:core-4.0-noarch\n\ Distributor ID: AmazonAMI\n\ Description: Amazon Linux AMI release 2018.03\n\ Release: 2018.03\n\ Codename: n/a\n\ " } // Amazon Linux 2 uses a separate Distributor ID and Release format from Amazon Linux 1 fn amazon2_file() -> &'static str { "LSB Version: :core-4.1-amd64:core-4.1-noarch\n\ Distributor ID: Amazon\n\ Description: Amazon Linux release 2 (Karoo)\n\ Release: 2\n\ Codename: Karoo\n\ " } fn rhel8_file() -> &'static str { "LSB Version: :core-4.1-amd64:core-4.1-noarch\n\ Distributor ID: RedHatEnterprise\n\ Description: Red Hat Enterprise Linux release 8.1 (Ootpa)\n\ Release: 8.1\n\ Codename: Ootpa\n\ " } fn rhel7_file() -> &'static str { "LSB Version: :core-4.1-amd64:core-4.1-noarch\n\ Distributor ID: RedHatEnterpriseServer\n\ Description: Red Hat Enterprise Linux Server release 7.7 (Maipo)\n\ Release: 7.7\n\ Codename: Maipo\n\ " } fn rhel6_file() -> &'static str { "LSB Version: :base-4.0-amd64:base-4.0-noarch:core-4.0-amd64:core-4.0-noarch:graphics-4.0-amd64:graphics-4.0-noarch:printing-4.0-amd64:printing-4.0-noarch\n\ Distributor ID: RedHatEnterpriseServer\n\ Description: Red Hat Enterprise Linux Server release 6.10 (Santiago)\n\ Release: 6.10\n\ Codename: Santiago\n\ " } } os_info-1.3.2/src/linux/mod.rs010064400017500001750000000026371361070542300144560ustar0000000000000000// spell-checker:ignore getconf mod file_release; mod lsb_release; use std::process::{Command, Output}; use log::trace; use crate::{Bitness, Info, Type, Version}; pub fn current_platform() -> Info { trace!("linux::current_platform is called"); let mut info = lsb_release::get() .or_else(file_release::get) .unwrap_or_else(|| Info::new(Type::Linux, Version::unknown(), Bitness::Unknown)); info.bitness = bitness(); trace!("Returning {:?}", info); info } fn bitness() -> Bitness { match &Command::new("getconf").arg("LONG_BIT").output() { Ok(Output { stdout, .. }) if stdout == b"32\n" => Bitness::X32, Ok(Output { stdout, .. }) if stdout == b"64\n" => Bitness::X64, _ => Bitness::Unknown, } } #[cfg(test)] mod tests { use super::*; use pretty_assertions::assert_ne; #[test] fn os_type() { let version = current_platform(); match version.os_type() { Type::Linux | Type::Redhat | Type::RedHatEnterprise | Type::Ubuntu | Type::Debian | Type::Arch | Type::Centos | Type::Fedora | Type::Alpine => (), os_type => { panic!("Unexpected OS type: {}", os_type); } } } #[test] fn get_bitness() { let b = bitness(); assert_ne!(b, Bitness::Unknown); } } os_info-1.3.2/src/linux/tests/alpine-release010064400017500001750000000000061344425521400172730ustar0000000000000000A.B.C os_info-1.3.2/src/linux/tests/centos-release010064400017500001750000000000301344425521400173130ustar0000000000000000Centos Linux release XX os_info-1.3.2/src/linux/tests/fedora-release010064400017500001750000000000371344425521400172670ustar0000000000000000Fedora release 26 (Twenty Six) os_info-1.3.2/src/linux/tests/redhat-release010064400017500001750000000000301344425521400172670ustar0000000000000000Redhat Linux release XX os_info-1.3.2/src/macos/mod.rs010064400017500001750000000076421361070542300144220ustar0000000000000000use std::process::Command; use lazy_static::lazy_static; use log::trace; use regex::Regex; use crate::{Bitness, Info, Type, Version}; pub fn current_platform() -> Info { trace!("macos::current_platform is called"); let info = Info { os_type: Type::Macos, version: version(), bitness: Bitness::Unknown, }; trace!("Returning {:?}", info); info } fn version() -> Version { let version = match product_version() { None => { return Version::unknown(); } Some(val) => val, }; if let Some((major, minor, patch)) = parse_semantic_version(&version) { Version::semantic(major, minor, patch, None) } else { Version::custom(version, None) } } fn parse_semantic_version(version: &str) -> Option<(u64, u64, u64)> { let parts: Vec<_> = version.split('.').collect(); if parts.len() < 2 || parts.len() > 3 { return None; } let major: u64 = parts[0].parse().ok()?; let minor: u64 = parts[1].parse().ok()?; let patch: u64 = parts.get(2).unwrap_or(&"0").parse().ok()?; Some((major, minor, patch)) } fn product_version() -> Option { match Command::new("sw_vers").output() { Ok(val) => { let output = String::from_utf8_lossy(&val.stdout); trace!("sw_vers command returned {:?}", output); parse(&output) } Err(e) => { trace!("sw_vers command failed with {:?}", e); None } } } fn parse(sw_vers_output: &str) -> Option { lazy_static! { static ref VERSION: Regex = Regex::new(r"ProductVersion:\s(\w+\.\w+(\.\w+)?)").unwrap(); } Some( VERSION .captures(sw_vers_output)? .get(1)? .as_str() .to_owned(), ) } #[cfg(test)] mod tests { use super::*; use pretty_assertions::assert_eq; #[test] fn os_type() { let version = current_platform(); assert_eq!(Type::Macos, version.os_type()); } #[test] fn os_version() { let version = version(); assert_ne!(Version::unknown(), version); } #[test] fn string_product_version() { let version = product_version(); assert!(version.is_some()); } #[test] fn semantic_version() { let test_data = [ ("", None), ("some test", None), ("0", None), ("0.", None), ("0.1", Some((0, 1, 0))), ("0.1.", None), ("0.1.2", Some((0, 1, 2))), ("0.1.2.", None), ("1.0.0", Some((1, 0, 0))), ("0.0.1", Some((0, 0, 1))), ("10.1", Some((10, 1, 0))), ("a.b.c", None), ("hello.world", None), ]; for &(input, ref expected_result) in &test_data { let res = parse_semantic_version(input); assert_eq!(&res, expected_result); } } #[test] fn parse_version() { let parse_output = parse(sw_vers_output()); assert_eq!(parse_output, Some("10.10.5".to_string())); } fn sw_vers_output() -> &'static str { "ProductName: Mac OS X\n\ ProductVersion: 10.10.5\n\ BuildVersion: 14F27" } #[test] fn parse_beta_version() { let parse_output = parse(sw_vers_output_beta()); assert_eq!(parse_output, Some("10.15".to_string())); } fn sw_vers_output_beta() -> &'static str { "ProductName: Mac OS X\n\ ProductVersion: 10.15\n\ BuildVersion: 19A546d" } #[test] fn parse_double_digit_patch_version() { let parse_output = parse(sw_vers_output_double_digit_patch_version()); assert_eq!(parse_output, Some("10.15.21".to_string())); } fn sw_vers_output_double_digit_patch_version() -> &'static str { "ProductName: Mac OS X\n\ ProductVersion: 10.15.21\n\ BuildVersion: ABCD123" } } os_info-1.3.2/src/os_type.rs010064400017500001750000000036131360572621700142250ustar0000000000000000use std::fmt::{self, Display, Formatter}; use serde_derive::{Deserialize, Serialize}; /// A list of supported operating system types. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] pub enum Type { /// Unknown operating system. Unknown, /// Android (). Android, /// Emscripten (). Emscripten, /// Linux based operating system (). Linux, /// Red Hat Linux (). Redhat, /// Red Hat Enterprise Linux (). RedHatEnterprise, /// Ubuntu (). Ubuntu, /// Debian (). Debian, /// Arch Linux (). Arch, /// CentOS (). Centos, /// Fedora () Fedora, /// Amazon () Amazon, /// Alpine Linux () Alpine, /// Mac OS X/OS X/macOS (). Macos, /// Redox (). Redox, /// Windows (). Windows, } impl Display for Type { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match *self { Type::Redhat => write!(f, "Red Hat Linux"), Type::Arch => write!(f, "Arch Linux"), Type::Centos => write!(f, "CentOS"), Type::Macos => write!(f, "Mac OS"), _ => write!(f, "{:?}", self), } } } os_info-1.3.2/src/redox/mod.rs010064400017500001750000000022311361070542300144260ustar0000000000000000// spell-checker:ignore uname use std::{fs::File, io::Read}; use log::{error, trace}; use crate::{Bitness, Info, Type, Version}; const UNAME_FILE: &str = "sys:uname"; pub fn current_platform() -> Info { trace!("redox::current_platform is called"); let version = get_version().map_or_else(|| Version::unknown(), |v| Version::custom(v, None)); let info = Info { os_type: Type::Redox, version, bitness: Bitness::Unknown, }; trace!("Returning {:?}", info); info } fn get_version() -> Option { let mut file = match File::open(UNAME_FILE) { Ok(file) => file, Err(e) => { error!("Unable to open {} file: {:?}", UNAME_FILE, e); return None; } }; let mut version = String::new(); if let Err(e) = file.read_to_string(&mut version) { error!("Unable to read {} file: {:?}", UNAME_FILE, e); return None; } Some(version) } #[cfg(test)] mod tests { use super::*; use pretty_assertions::assert_eq; #[test] fn os_type() { let version = current_platform(); assert_eq!(Type::Redox, version.os_type()); } } os_info-1.3.2/src/unknown/mod.rs010064400017500001750000000006661360572621700150260ustar0000000000000000use log::trace; use crate::{Info, Type, Version}; pub fn current_platform() -> Info { trace!("unknown::current_platform is called"); Info::unknown() } #[cfg(test)] mod tests { use super::*; use pretty_assertions::assert_eq; #[test] fn os_type() { let version = current_platform(); assert_eq!(Type::Unknown, version.os_type()); assert_eq!(Version::unknown(), version.version()); } } os_info-1.3.2/src/version.rs010064400017500001750000000117051360572621700142310ustar0000000000000000use std::fmt::{self, Display, Formatter, Write}; use serde_derive::{Deserialize, Serialize}; /// Operating system version including version number and optional edition. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] pub struct Version { pub(crate) version: VersionType, pub(crate) edition: Option, } /// Operating system version. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] pub enum VersionType { /// Unknown version. Unknown, /// Semantic version (major.minor.patch). Semantic(u64, u64, u64), /// Custom version format. Custom(String), } impl Version { /// Constructs a new `Version` instance with unknown version and `None` edition. /// /// # Examples /// /// ``` /// use os_info::{Version, VersionType}; /// /// let version = Version::unknown(); /// assert_eq!(VersionType::Unknown, *version.version()); /// assert_eq!(None, version.edition()); /// ``` pub fn unknown() -> Self { Self { version: VersionType::Unknown, edition: None, } } /// Constructs a new `Version` instance with semantic version and given edition. /// /// # Examples /// /// ``` /// use os_info::{Version, VersionType}; /// /// let version = Version::semantic(0, 1, 2, None); /// assert_eq!(VersionType::Semantic(0, 1, 2), *version.version()); /// assert_eq!(None, version.edition()); /// ``` pub fn semantic(major: u64, minor: u64, patch: u64, edition: Option) -> Self { Self { version: VersionType::Semantic(major, minor, patch), edition, } } /// Construct a new `Version` instance with "custom" (non semantic) version and given edition. /// /// # Examples /// /// ``` /// use os_info::{Version, VersionType}; /// /// let ver = "version".to_string(); /// let edition = "edition".to_string(); /// let version = Version::custom(ver.clone(), Some(edition.clone())); /// assert_eq!(VersionType::Custom(ver), *version.version()); /// assert_eq!(Some(edition.as_ref()), version.edition()); /// ``` pub fn custom>(version: T, edition: Option) -> Self { Self { version: VersionType::Custom(version.into()), edition, } } /// Returns operating system version. See `VersionType` for details. /// /// # Examples /// /// ``` /// use os_info::{Version, VersionType}; /// /// let version = Version::unknown(); /// assert_eq!(VersionType::Unknown, *version.version()); pub fn version(&self) -> &VersionType { &self.version } /// Returns optional (can be absent) operation system edition. /// /// # Examples /// /// ``` /// use os_info::Version; /// /// let version = Version::unknown(); /// assert_eq!(None, version.edition()); pub fn edition(&self) -> Option<&str> { self.edition.as_ref().map(String::as_ref) } } impl Display for Version { fn fmt(&self, f: &mut Formatter) -> fmt::Result { if let Some(ref edition) = self.edition { write!(f, "{}", edition)?; } write!(f, "{}", self.version) } } impl Display for VersionType { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match *self { VersionType::Unknown => f.write_char('?'), VersionType::Semantic(major, minor, patch) => { write!(f, "{}.{}.{}", major, minor, patch) } VersionType::Custom(ref version) => write!(f, "{}", version), } } } #[cfg(test)] mod tests { use super::*; use pretty_assertions::assert_eq; #[test] fn unknown() { let version = Version::unknown(); assert_eq!(VersionType::Unknown, *version.version()); assert_eq!(None, version.edition()); } #[test] fn semantic() { let data = [ ((0, 0, 0), None), ((10, 20, 30), Some("edition".to_string())), ((3, 2, 1), None), ((1, 0, 0), Some("different edition".to_string())), ]; for &(v, ref edition) in &data { let version = Version::semantic(v.0, v.1, v.2, edition.clone()); assert_eq!(VersionType::Semantic(v.0, v.1, v.2), *version.version()); assert_eq!(edition.as_ref().map(String::as_ref), version.edition()); } } #[test] fn custom() { let data = [ ("OS", None), ("Another OS", Some("edition".to_string())), ("", None), ("Future OS", Some("e".to_string())), ]; for &(ref v, ref edition) in &data { let version = Version::custom(*v, edition.clone()); assert_eq!(VersionType::Custom(v.to_string()), *version.version()); assert_eq!(edition.as_ref().map(String::as_ref), version.edition()); } } } os_info-1.3.2/src/windows/mod.rs010064400017500001750000000007031360572621700150110ustar0000000000000000mod winapi; use log::trace; use crate::Info; pub fn current_platform() -> Info { trace!("windows::current_platform is called"); let info = winapi::get(); trace!("Returning {:?}", info); info } #[cfg(test)] mod tests { use super::*; use crate::Type; use pretty_assertions::assert_eq; #[test] fn os_type() { let version = current_platform(); assert_eq!(Type::Windows, version.os_type()); } } os_info-1.3.2/src/windows/winapi.rs010064400017500001750000000152061361070542300155150ustar0000000000000000// spell-checker:ignore dword, minwindef, ntdef, ntdll, ntstatus, osversioninfoex, osversioninfoexa // spell-checker:ignore osversioninfoexw, serverr, sysinfoapi, winnt, winuser, pbool, libloaderapi // spell-checker:ignore lpcstr, processthreadsapi #![allow(unsafe_code)] use std::mem; use winapi::{ shared::{minwindef::DWORD, ntdef::NTSTATUS, ntstatus::STATUS_SUCCESS}, um::{ sysinfoapi::{GetSystemInfo, SYSTEM_INFO}, winnt::{PROCESSOR_ARCHITECTURE_AMD64, VER_NT_WORKSTATION, VER_SUITE_WH_SERVER}, winuser::{GetSystemMetrics, SM_SERVERR2}, }, }; use crate::{Bitness, Info, Type, Version}; #[cfg(target_arch = "x86")] type OSVERSIONINFOEX = winapi::um::winnt::OSVERSIONINFOEXA; #[cfg(not(target_arch = "x86"))] type OSVERSIONINFOEX = winapi::um::winnt::OSVERSIONINFOEXW; #[link(name = "ntdll")] extern "system" { pub fn RtlGetVersion(lpVersionInformation: &mut OSVERSIONINFOEX) -> NTSTATUS; } pub fn get() -> Info { Info::new(Type::Windows, version(), bitness()) } fn version() -> Version { match version_info() { None => Version::unknown(), Some(v) => Version::semantic( v.dwMajorVersion as u64, v.dwMinorVersion as u64, v.dwBuildNumber as u64, edition(&v), ), } } #[cfg(target_pointer_width = "64")] fn bitness() -> Bitness { // x64 program can only run on x64 Windows. Bitness::X64 } #[cfg(target_pointer_width = "32")] fn bitness() -> Bitness { use winapi::{ shared::{ minwindef::{BOOL, FALSE, PBOOL}, ntdef::{HANDLE, LPCSTR}, }, um::{ libloaderapi::{GetModuleHandleA, GetProcAddress}, processthreadsapi::GetCurrentProcess, }, }; // IsWow64Process is not available on all supported versions of Windows. Use GetModuleHandle to // get a handle to the DLL that contains the function and GetProcAddress to get a pointer to the // function if available. let kernel = unsafe { GetModuleHandleA(b"kernel32\0".as_ptr() as LPCSTR) }; if kernel.is_null() { log::error!("GetModuleHandleA failed"); return Bitness::Unknown; } let is_wow_64 = unsafe { GetProcAddress(kernel, b"IsWow64Process\0".as_ptr() as LPCSTR) }; if is_wow_64.is_null() { log::error!("GetProcAddress failed"); return Bitness::Unknown; } type IsWow64 = unsafe extern "system" fn(HANDLE, PBOOL) -> BOOL; let is_wow_64: IsWow64 = unsafe { mem::transmute(is_wow_64) }; let mut result = FALSE; if unsafe { is_wow_64(GetCurrentProcess(), &mut result) } == 0 { log::error!("IsWow64Process failed"); return Bitness::Unknown; } if result == FALSE { Bitness::X32 } else { Bitness::X64 } } // Calls the Win32 API function RtlGetVersion to get the OS version information: // https://msdn.microsoft.com/en-us/library/mt723418(v=vs.85).aspx fn version_info() -> Option { let mut info: OSVERSIONINFOEX = unsafe { mem::zeroed() }; info.dwOSVersionInfoSize = mem::size_of::() as DWORD; if unsafe { RtlGetVersion(&mut info) } == STATUS_SUCCESS { Some(info) } else { None } } // Examines data in the OSVERSIONINFOEX structure to determine the Windows edition: // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724833(v=vs.85).aspx fn edition(version_info: &OSVERSIONINFOEX) -> Option { match ( version_info.dwMajorVersion, version_info.dwMinorVersion, version_info.wProductType, ) { // Windows 10. (10, 0, VER_NT_WORKSTATION) => Some("Windows 10"), (10, 0, _) => Some("Windows Server 2016"), // Windows Vista, 7, 8 and 8.1. (6, 3, VER_NT_WORKSTATION) => Some("Windows 8.1"), (6, 3, _) => Some("Windows Server 2012 R2"), (6, 2, VER_NT_WORKSTATION) => Some("Windows 8"), (6, 2, _) => Some("Windows Server 2012"), (6, 1, VER_NT_WORKSTATION) => Some("Windows 7"), (6, 1, _) => Some("Windows Server 2008 R2"), (6, 0, VER_NT_WORKSTATION) => Some("Windows Vista"), (6, 0, _) => Some("Windows Server 2008"), // Windows 2000, Home Server, 2003 Server, 2003 R2 Server, XP and XP Professional x64. (5, 1, _) => Some("Windows XP"), (5, 0, _) => Some("Windows 2000"), (5, 2, _) if unsafe { GetSystemMetrics(SM_SERVERR2) } == 0 => { let mut info: SYSTEM_INFO = unsafe { mem::zeroed() }; unsafe { GetSystemInfo(&mut info) }; if Into::::into(version_info.wSuiteMask) & VER_SUITE_WH_SERVER == VER_SUITE_WH_SERVER { Some("Windows Home Server") } else if version_info.wProductType == VER_NT_WORKSTATION && unsafe { info.u.s().wProcessorArchitecture } == PROCESSOR_ARCHITECTURE_AMD64 { Some("Windows XP Professional x64 Edition") } else { Some("Windows Server 2003") } } _ => None, } .map(str::to_string) } #[cfg(test)] mod tests { use super::*; use pretty_assertions::{assert_eq, assert_ne}; #[test] fn version() { let info = get(); assert_eq!(Type::Windows, info.os_type()); } #[test] fn get_version_info() { let version = version_info(); assert!(version.is_some()); } #[test] fn get_edition() { let test_data = [ (10, 0, VER_NT_WORKSTATION, "Windows 10"), (10, 0, 0, "Windows Server 2016"), (6, 3, VER_NT_WORKSTATION, "Windows 8.1"), (6, 3, 0, "Windows Server 2012 R2"), (6, 2, VER_NT_WORKSTATION, "Windows 8"), (6, 2, 0, "Windows Server 2012"), (6, 1, VER_NT_WORKSTATION, "Windows 7"), (6, 1, 0, "Windows Server 2008 R2"), (6, 0, VER_NT_WORKSTATION, "Windows Vista"), (6, 0, 0, "Windows Server 2008"), (5, 1, 0, "Windows XP"), (5, 1, 1, "Windows XP"), (5, 1, 100, "Windows XP"), (5, 0, 0, "Windows 2000"), (5, 0, 1, "Windows 2000"), (5, 0, 100, "Windows 2000"), ]; let mut info = version_info().unwrap(); for &(major, minor, product_type, expected_edition) in &test_data { info.dwMajorVersion = major; info.dwMinorVersion = minor; info.wProductType = product_type; let edition = edition(&info).unwrap(); assert_eq!(edition, expected_edition); } } #[test] fn get_bitness() { let b = bitness(); assert_ne!(b, Bitness::Unknown); } } os_info-1.3.2/tests/basic.rs010064400017500001750000000000611360572621700141710ustar0000000000000000#[test] fn get() { let _ = os_info::get(); } os_info-1.3.2/tests/md_doc.rs010064400017500001750000000001101346534407500143320ustar0000000000000000// spell-checker:ignore doctest doc_comment::doctest!("../README.md"); os_info-1.3.2/.cargo_vcs_info.json0000644000000001121361071056600125700ustar00{ "git": { "sha1": "d62ed14a0697ff8a5b71c854ab02590e02febc44" } } os_info-1.3.2/Cargo.lock0000644000000245161361071056600105610ustar00# This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] name = "aho-corasick" version = "0.6.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ansi_term" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cfg-if" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "ctor" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "difference" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "doc-comment" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "either" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "itertools" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "either 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lazy_static" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "log" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "memchr" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "os_info" version = "1.3.2" dependencies = [ "doc-comment 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "output_vt100" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "pretty_assertions" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "ctor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "output_vt100 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "proc-macro2" version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "quote" version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "regex" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "aho-corasick 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex-syntax 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "regex-syntax" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde" version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_derive" version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "syn" version = "0.15.29" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "thread_local" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ucd-util" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "unicode-xid" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "utf8-ranges" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum aho-corasick 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "81ce3d38065e618af2d7b77e10c5ad9a069859b4be3c2250f674af3840d9c8a5" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4" "checksum ctor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9a43db2bba5cafdc6aa068c892a518e477ee0df3705e53ec70247a9ff93546d5" "checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" "checksum doc-comment 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "923dea538cea0aa3025e8685b20d6ee21ef99c4f77e954a30febbaac5ec73a97" "checksum either 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c67353c641dc847124ea1902d69bd753dee9bb3beff9aa3662ecf86c971d1fac" "checksum itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484" "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" "checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" "checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39" "checksum output_vt100 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9" "checksum pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427" "checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915" "checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1" "checksum regex 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53ee8cfdddb2e0291adfb9f13d31d3bbe0a03c9a402c01b1e24188d86c35b24f" "checksum regex-syntax 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8c2f35eedad5295fdf00a63d7d4b238135723f92b434ec06774dad15c7ab0861" "checksum serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)" = "92514fb95f900c9b5126e32d020f5c6d40564c27a5ea6d1d7d9f157a96623560" "checksum serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6eabf4b5914e88e24eea240bb7c9f9a2cbc1bbbe8d961d381975ec3c6b806c" "checksum syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1825685f977249735d510a242a6727b46efe914bb67e38d30c071b1b72b1d5c2" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"