diff --git a/Cargo.lock b/Cargo.lock index a099bc3..55a0191 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ [root] name = "tokei" -version = "3.0.1" +version = "3.0.2" dependencies = [ "clap 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index fb6aa2f..311e7d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,9 +21,18 @@ name = "tokei" path = "src/main.rs" doc = false +[features] +default = [] +io = ["serde_codegen", "serde", "serializable_enum"] +json = ["io", "serde_json"] +cbor = ["io", "rustc-serialize","serde_cbor"] +toml-io = ["io", "toml/serde"] +yaml = ["io", "serde_yaml"] +all = ["json", "cbor", "toml-io", "yaml"] + # For building serde in stable. [build-dependencies] -serde_codegen = "0.7.10" +serde_codegen = {version = "0.7.10", optional = true} # Dependencies, and why they are used. # - Clap: For CLI argument parsing. @@ -43,15 +52,16 @@ clap = {version = "2.5.1", features = ["yaml"]} glob = "0.2.11" maplit = "0.1.3" rayon = "0.3.1" -rustc-serialize = "0.3.19" -serde = "0.7.10" -serde_cbor = "0.3.3" -serde_json = "0.7.1" -serde_yaml = "0.2.5" -serializable_enum = "0.3.0" +rustc-serialize = { version = "0.3.19", optional = true } +serde = { version = "0.7.10", optional = true } +serde_cbor = {version = "0.3.3", optional = true } +serde_json = { version = "0.7.1", optional = true } +serde_yaml = { version = "0.2.5", optional = true } +serializable_enum = { version = "0.3.0", optional = true } walkdir = "0.1.5" [dependencies.toml] version = "0.1.30" default-features = false features = ["serde"] +optional = true diff --git a/src/lib/build.rs b/src/lib/build.rs index e608484..906d19b 100644 --- a/src/lib/build.rs +++ b/src/lib/build.rs @@ -1,13 +1,23 @@ +#[cfg(feature = "io")] extern crate serde_codegen; use std::env; use std::path::Path; pub fn main() { + expand(); +} + + +#[cfg(feature = "io")] +fn expand() { let out_dir = env::var_os("OUT_DIR").unwrap(); let src = Path::new("src/lib/lib.rs.in"); - let dst = Path::new(&out_dir).join("lib.rs"); + let dst = Path::new(&out_dir).join("lib.rs.in"); serde_codegen::expand(&src, &dst).unwrap(); } + +#[cfg(not(feature = "io"))] +fn expand() {} diff --git a/src/lib/language/language.rs b/src/lib/language/language.rs index eb9c85e..5236aed 100644 --- a/src/lib/language/language.rs +++ b/src/lib/language/language.rs @@ -6,7 +6,8 @@ use sort::Sort::*; use stats::Stats; /// Struct representing a single Language. -#[derive(Clone, Debug, Default, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)] +#[cfg_attr(feature = "io", derive(Deserialize, Serialize))] +#[derive(Clone, Debug, Default, Eq, Ord, PartialEq, PartialOrd)] pub struct Language { /// Number of blank lines. pub blanks: usize, @@ -15,20 +16,20 @@ pub struct Language { /// Number of comments(both single, and multi-line) pub comments: usize, /// A collection of files to be analysed. - #[serde(skip_deserializing, skip_serializing)] + #[cfg_attr(feature = "io", serde(skip_deserializing, skip_serializing))] pub files: Vec, /// A collection of statistics based on the files provide from `files` pub stats: Vec, /// Number of total lines. pub lines: usize, /// A collection of single line comments in the language. ie. `//` in Rust. - #[serde(skip_deserializing, skip_serializing)] + #[cfg_attr(feature = "io", serde(skip_deserializing, skip_serializing))] pub line_comment: Vec<&'static str>, /// A collection of tuples representing the start and end of multi line comments. ie. `/* comment */` in Rust. - #[serde(skip_deserializing, skip_serializing)] + #[cfg_attr(feature = "io", serde(skip_deserializing, skip_serializing))] pub multi_line: Vec<(&'static str, &'static str)>, /// Whether the language supports nested multi line comments or not. - #[serde(skip_deserializing, skip_serializing)] + #[cfg_attr(feature = "io", serde(skip_deserializing, skip_serializing))] pub nested: bool, } diff --git a/src/lib/language/language_type.rs b/src/lib/language/language_type.rs index 45f3b25..b3cf95b 100644 --- a/src/lib/language/language_type.rs +++ b/src/lib/language/language_type.rs @@ -10,159 +10,157 @@ use std::path::Path; use utils::*; use self::LanguageType::*; -serializable_enum! { - #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] - pub enum LanguageType { - /// ActionScript - ActionScript, - /// Assembly - Assembly, - /// Autoconf - Autoconf, - /// Bash - Bash, - /// Batch - Batch, - /// C - C, - /// CHeader - CHeader, - /// Clojure - Clojure, - /// CoffeeScript - CoffeeScript, - /// ColdFusion - ColdFusion, - /// ColdFusionScript - ColdFusionScript, - /// Coq - Coq, - /// Cpp - Cpp, - /// CppHeader - CppHeader, - /// CSharp - CSharp, - /// CShell - CShell, - /// Css - Css, - /// D - D, - /// Dart - Dart, - /// DeviceTree - DeviceTree, - /// Erlang - Erlang, - /// FortranLegacy - FortranLegacy, - /// FortranModern - FortranModern, - /// Go - Go, - /// Haskell - Haskell, - /// Html - Html, - /// Idris - Idris, - /// Isabelle - Isabelle, - /// Jai - Jai, - /// Java - Java, - /// JavaScript - JavaScript, - /// Julia - Julia, - /// Json - Json, - /// Jsx - Jsx, - /// Kotlin - Kotlin, - /// Less - Less, - /// LinkerScript - LinkerScript, - /// Lisp - Lisp, - /// Lua - Lua, - /// Makefile - Makefile, - /// Markdown - Markdown, - /// Mustache - Mustache, - /// Nim - Nim, - /// ObjectiveC - ObjectiveC, - /// ObjectiveCpp - ObjectiveCpp, - /// OCaml - OCaml, - /// Oz - Oz, - /// Pascal - Pascal, - /// Perl - Perl, - /// Polly - Polly, - /// Php - Php, - /// Protobuf - Protobuf, - /// Prolog - Prolog, - /// Python - Python, - /// Qcl - Qcl, - /// R - R, - /// Ruby - Ruby, - /// RubyHtml - RubyHtml, - /// Rust - Rust, - /// Sass - Sass, - /// Scala - Scala, - /// Sml - Sml, - /// Sql - Sql, - /// Swift - Swift, - /// Tex - Tex, - /// Text - Text, - /// Toml - Toml, - /// TypeScript - TypeScript, - /// VimScript - VimScript, - /// UnrealScript - UnrealScript, - /// Wolfram - Wolfram, - /// Xml - Xml, - /// Yaml - Yaml, - /// Zsh - Zsh, - } - LanguageTypeVisitor +#[cfg_attr(feature = "io", derive(Deserialize, Serialize))] +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] +pub enum LanguageType { + /// ActionScript + ActionScript, + /// Assembly + Assembly, + /// Autoconf + Autoconf, + /// Bash + Bash, + /// Batch + Batch, + /// C + C, + /// CHeader + CHeader, + /// Clojure + Clojure, + /// CoffeeScript + CoffeeScript, + /// ColdFusion + ColdFusion, + /// ColdFusionScript + ColdFusionScript, + /// Coq + Coq, + /// Cpp + Cpp, + /// CppHeader + CppHeader, + /// CSharp + CSharp, + /// CShell + CShell, + /// Css + Css, + /// D + D, + /// Dart + Dart, + /// DeviceTree + DeviceTree, + /// Erlang + Erlang, + /// FortranLegacy + FortranLegacy, + /// FortranModern + FortranModern, + /// Go + Go, + /// Haskell + Haskell, + /// Html + Html, + /// Idris + Idris, + /// Isabelle + Isabelle, + /// Jai + Jai, + /// Java + Java, + /// JavaScript + JavaScript, + /// Julia + Julia, + /// Json + Json, + /// Jsx + Jsx, + /// Kotlin + Kotlin, + /// Less + Less, + /// LinkerScript + LinkerScript, + /// Lisp + Lisp, + /// Lua + Lua, + /// Makefile + Makefile, + /// Markdown + Markdown, + /// Mustache + Mustache, + /// Nim + Nim, + /// ObjectiveC + ObjectiveC, + /// ObjectiveCpp + ObjectiveCpp, + /// OCaml + OCaml, + /// Oz + Oz, + /// Pascal + Pascal, + /// Perl + Perl, + /// Polly + Polly, + /// Php + Php, + /// Protobuf + Protobuf, + /// Prolog + Prolog, + /// Python + Python, + /// Qcl + Qcl, + /// R + R, + /// Ruby + Ruby, + /// RubyHtml + RubyHtml, + /// Rust + Rust, + /// Sass + Sass, + /// Scala + Scala, + /// Sml + Sml, + /// Sql + Sql, + /// Swift + Swift, + /// Tex + Tex, + /// Text + Text, + /// Toml + Toml, + /// TypeScript + TypeScript, + /// VimScript + VimScript, + /// UnrealScript + UnrealScript, + /// Wolfram + Wolfram, + /// Xml + Xml, + /// Yaml + Yaml, + /// Zsh + Zsh, } #[derive(Debug)] @@ -175,86 +173,86 @@ impl ::std::fmt::Display for Error { write!(f, "{:?}", self) } } - -impl_as_ref_from_str! { - LanguageType { - ActionScript => "ActionScript", - Assembly => "Assembly", - Autoconf => "Autoconf", - Bash => "BASH", - Batch => "Batch", - C => "C", - CHeader => "C Header", - Clojure => "Clojure", - CoffeeScript => "CoffeeScript", - ColdFusion => "ColdFusion", - ColdFusionScript => "ColdFusion CFScript", - Coq => "Coq", - Cpp => "C++", - CppHeader => "C++ Header", - CSharp => "C#", - CShell => "C Shell", - Css => "CSS", - D => "D", - Dart => "Dart", - DeviceTree => "Device Tree", - Erlang => "Erlang", - FortranLegacy => "FORTRAN Legacy", - FortranModern => "FORTRAN Modern", - Go => "Go", - Haskell => "Haskell", - Html => "HTML", - Idris => "Idris", - Isabelle => "Isabelle", - Jai => "JAI", - Java => "Java", - JavaScript => "JavaScript", - Json => "JSON", - Jsx => "JSX", - Julia => "Julia", - Kotlin => "Kotlin", - Less => "LESS", - LinkerScript => "LD Script", - Lisp => "LISP", - Lua => "Lua", - Makefile => "Makefile", - Markdown => "Markdown", - Mustache => "Mustache", - Nim => "Nim", - ObjectiveC => "Objective C", - ObjectiveCpp => "Objective C++", - OCaml => "OCaml", - Oz => "Oz", - Pascal => "Pascal", - Perl => "Perl", - Polly => "Polly", - Php => "PHP", - Protobuf => "Protocol Buffers", - Prolog => "Prolog", - Python => "Python", - Qcl => "QCL", - R => "R", - Ruby => "Ruby", - RubyHtml => "Ruby HTML", - Rust => "Rust", - Sass => "Sass", - Scala => "Scala", - Sml => "Standard ML", - Sql => "SQL", - Swift => "Swift", - Tex => "TeX", - Text => "Plain Text", - Toml => "TOML", - TypeScript => "TypeScript", - UnrealScript => "Unreal Script", - VimScript => "Vim Script", - Wolfram => "Wolfram", - Xml => "XML", - Yaml => "YAML", - Zsh => "Zsh", - } - Error::Parse -} +// #[cfg(feature = "io")] +// impl_as_ref_from_str! { +// LanguageType { +// ActionScript => "ActionScript", +// Assembly => "Assembly", +// Autoconf => "Autoconf", +// Bash => "BASH", +// Batch => "Batch", +// C => "C", +// CHeader => "C Header", +// Clojure => "Clojure", +// CoffeeScript => "CoffeeScript", +// ColdFusion => "ColdFusion", +// ColdFusionScript => "ColdFusion CFScript", +// Coq => "Coq", +// Cpp => "C++", +// CppHeader => "C++ Header", +// CSharp => "C#", +// CShell => "C Shell", +// Css => "CSS", +// D => "D", +// Dart => "Dart", +// DeviceTree => "Device Tree", +// Erlang => "Erlang", +// FortranLegacy => "FORTRAN Legacy", +// FortranModern => "FORTRAN Modern", +// Go => "Go", +// Haskell => "Haskell", +// Html => "HTML", +// Idris => "Idris", +// Isabelle => "Isabelle", +// Jai => "JAI", +// Java => "Java", +// JavaScript => "JavaScript", +// Json => "JSON", +// Jsx => "JSX", +// Julia => "Julia", +// Kotlin => "Kotlin", +// Less => "LESS", +// LinkerScript => "LD Script", +// Lisp => "LISP", +// Lua => "Lua", +// Makefile => "Makefile", +// Markdown => "Markdown", +// Mustache => "Mustache", +// Nim => "Nim", +// ObjectiveC => "Objective C", +// ObjectiveCpp => "Objective C++", +// OCaml => "OCaml", +// Oz => "Oz", +// Pascal => "Pascal", +// Perl => "Perl", +// Polly => "Polly", +// Php => "PHP", +// Protobuf => "Protocol Buffers", +// Prolog => "Prolog", +// Python => "Python", +// Qcl => "QCL", +// R => "R", +// Ruby => "Ruby", +// RubyHtml => "Ruby HTML", +// Rust => "Rust", +// Sass => "Sass", +// Scala => "Scala", +// Sml => "Standard ML", +// Sql => "SQL", +// Swift => "Swift", +// Tex => "TeX", +// Text => "Plain Text", +// Toml => "TOML", +// TypeScript => "TypeScript", +// UnrealScript => "Unreal Script", +// VimScript => "Vim Script", +// Wolfram => "Wolfram", +// Xml => "XML", +// Yaml => "YAML", +// Zsh => "Zsh", +// } +// Error::Parse +// } impl LanguageType { diff --git a/src/lib/language/languages.rs b/src/lib/language/languages.rs index 7f459b5..ac27580 100644 --- a/src/lib/language/languages.rs +++ b/src/lib/language/languages.rs @@ -9,9 +9,13 @@ use std::io::Read; use std::iter::IntoIterator; use std::ops::{AddAssign, Deref, DerefMut}; +#[cfg(feature = "cbor")] use serde_cbor; +#[cfg(feature = "json")] use serde_json; +#[cfg(feature = "yaml")] use serde_yaml; +#[cfg(feature = "toml-io")] use toml; use rayon::prelude::*; @@ -20,6 +24,11 @@ use super::{Language, LanguageType}; use super::LanguageType::*; use stats::Stats; +const CBOR_ERROR: &'static str = "Tokei was not compiled with the `cbor` flag."; +const JSON_ERROR: &'static str = "Tokei was not compiled with the `json` flag."; +const TOML_ERROR: &'static str = "Tokei was not compiled with the `toml-io` flag."; +const YAML_ERROR: &'static str = "Tokei was not compiled with the `yaml` flag."; + /// A collection of existing languages([_List of Languages_](https://github.com/Aaronepower/tokei#supported-languages)) #[derive(Debug, Clone)] pub struct Languages { @@ -45,12 +54,17 @@ impl Languages { /// assert_eq!(12, languages.get_mut(&LanguageType::Rust).unwrap().code); /// # } /// ``` + #[cfg(feature = "cbor")] pub fn from_cbor<'a, I: Into<&'a [u8]>>(cbor: I) -> serde_cbor::Result { let map = try!(serde_cbor::from_slice(cbor.into())); Ok(Self::from_previous(map)) } + #[cfg(not(feature = "cbor"))] + pub fn from_cbor<'a, I: Into<&'a [u8]>>(cbor: I) -> ! { + panic!(CBOR_ERROR) + } /// Creates a `Languages` struct from json. /// @@ -76,12 +90,18 @@ impl Languages { /// let mut languages = Languages::from_json(json.as_bytes()).unwrap(); /// assert_eq!(12, languages.get_mut(&LanguageType::Rust).unwrap().code); /// ``` + #[cfg(feature = "json")] pub fn from_json<'a, I: Into<&'a [u8]>>(json: I) -> serde_json::Result { let map = try!(serde_json::from_slice(json.into())); Ok(Self::from_previous(map)) } + #[cfg(not(feature = "json"))] + pub fn from_json<'a, I: Into<&'a [u8]>>(json: I) -> ! { + panic!(JSON_ERROR) + } + /// Creates a `Languages` struct from json. /// /// ```no_run @@ -106,12 +126,18 @@ impl Languages { /// /// assert_eq!(12, languages.get_mut(&LanguageType::Rust).unwrap().code); /// ``` + #[cfg(feature = "yaml")] pub fn from_yaml<'a, I: Into<&'a [u8]>>(yaml: I) -> serde_yaml::Result { let map = try!(serde_yaml::from_slice(yaml.into())); Ok(Self::from_previous(map)) } + #[cfg(not(feature = "yaml"))] + pub fn from_yaml<'a, I: Into<&'a [u8]>>(yaml: I) -> ! { + panic!(YAML_ERROR) + } + fn from_previous(map: BTreeMap) -> Self { let mut _self = Self::new(); @@ -373,10 +399,16 @@ impl Languages { /// assert_eq!(cbor, languages.to_cbor().unwrap().to_hex()); /// # } /// ``` + #[cfg(feature = "cbor")] pub fn to_cbor(&self) -> Result, serde_cbor::Error> { serde_cbor::to_vec(&self.remove_empty()) } + #[cfg(not(feature = "cbor"))] + pub fn to_cbor(&self) -> ! { + panic!(CBOR_ERROR) + } + /// Converts `Languages` to JSON. /// /// ```no_run @@ -404,14 +436,26 @@ impl Languages { /// /// assert_eq!(json, languages.to_json().unwrap()); /// ``` + #[cfg(feature = "json")] pub fn to_json(&self) -> Result { serde_json::to_string(&self.remove_empty()) } + #[cfg(not(feature = "json"))] + pub fn to_json(&self) -> ! { + panic!(JSON_ERROR) + } + + #[cfg(feature = "toml-io")] pub fn to_toml(&self) -> String { toml::encode_str(&self.remove_empty()) } + #[cfg(not(feature = "toml-io"))] + pub fn to_toml(&self) -> ! { + panic!(TOML_ERROR) + } + /// Converts `Languages` to YAML. /// /// ```no_run @@ -434,9 +478,15 @@ impl Languages { /// languages.get_statistics(&*vec!["src/lib/build.rs"], &*vec![".git"]); /// /// assert_eq!(yaml, languages.to_yaml().unwrap()); + #[cfg(feature = "yaml")] pub fn to_yaml(&self) -> Result { serde_yaml::to_string(&self.remove_empty()) } + + #[cfg(not(feature = "yaml"))] + pub fn to_yaml(&self) -> ! { + panic!(YAML_ERROR) + } } impl IntoIterator for Languages { diff --git a/src/lib/lib.rs b/src/lib/lib.rs index f0264f2..357a7b2 100644 --- a/src/lib/lib.rs +++ b/src/lib/lib.rs @@ -49,14 +49,24 @@ #[macro_use] extern crate maplit; #[macro_use] +#[cfg(feature = "io")] extern crate serializable_enum; extern crate glob; extern crate rayon; +#[cfg(feature = "io")] extern crate serde; +#[cfg(feature = "cbor")] extern crate serde_cbor; +#[cfg(feature = "json")] extern crate serde_json; +#[cfg(feature = "yaml")] extern crate serde_yaml; +#[cfg(feature = "toml")] extern crate toml; extern crate walkdir; -include!(concat!(env!("OUT_DIR"), "/lib.rs")); +#[cfg(feature = "io")] +include!(concat!(env!("OUT_DIR"), "/lib.rs.in")); + +#[not(cfg(feature = "io"))] +include!("lib.rs.in"); diff --git a/src/lib/stats.rs b/src/lib/stats.rs index 4ca9a0b..b5481df 100644 --- a/src/lib/stats.rs +++ b/src/lib/stats.rs @@ -1,7 +1,8 @@ use std::fmt; /// A struct representing the statistics of a file. -#[derive(Clone, Default, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize)] +#[cfg_attr(feature = "io", derive(Deserialize, Serialize))] +#[derive(Clone, Default, Debug, Eq, Ord, PartialEq, PartialOrd)] pub struct Stats { /// Number of blank lines within the file. pub blanks: usize, diff --git a/src/main.rs b/src/main.rs index 813d509..ccdcf62 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,10 +4,15 @@ #[macro_use] extern crate clap; +#[cfg(feature = "cbor")] extern crate serde_cbor; +#[cfg(feature = "json")] extern crate serde_json; +#[cfg(feature = "yaml")] extern crate serde_yaml; +#[cfg(feature = "toml-io")] extern crate toml; +#[cfg(feature = "cbor")] extern crate rustc_serialize; extern crate tokei; @@ -20,17 +25,38 @@ use std::time::Duration; use std::sync::mpsc::channel; use clap::App; +#[cfg(feature = "cbor")] use rustc_serialize::hex::FromHex; use tokei::{Languages, Language, LanguageType}; use tokei::Sort::*; -pub const ROW: &'static str = "-------------------------------------------------------------------\ +const ROW: &'static str = "-------------------------------------------------------------------\ ------------"; -pub const BLANKS: &'static str = "blanks"; -pub const COMMENTS: &'static str = "comments"; -pub const CODE: &'static str = "code"; -pub const FILES: &'static str = "files"; -pub const LINES: &'static str = "lines"; +const BLANKS: &'static str = "blanks"; +const COMMENTS: &'static str = "comments"; +const CODE: &'static str = "code"; +const FILES: &'static str = "files"; +const LINES: &'static str = "lines"; +const OUTPUT_ERROR: &'static str = "This version of tokei was compiled without any serialization + formats, to enable serialization, reinstall tokei with the features flag. + + ALL: + cargo install tokei --features all + + JSON: + cargo install tokei --features json + + CBOR: + cargo install tokei --features cbor + + TOML: + cargo install tokei --features toml + + YAML: + cargo install toke --features yaml + + You can also have any mix of json cbor toml, or yaml. +"; fn main() { // Get options at the beginning, so the program doesn't have to make any extra calls to get the @@ -158,19 +184,7 @@ fn main() { } if let Some(format) = output_option { - match &*format { - "cbor" => { - let cbor: Vec<_> = languages.to_cbor().unwrap(); - - for byte in cbor { - print!("{:02x}", byte); - } - } - "json" => print!("{}", languages.to_json().unwrap()), - "toml" => print!("{}", languages.to_toml()), - "yaml" => print!("{}", languages.to_yaml().unwrap()), - _ => unreachable!(), - } + match_output(&format); } else if let Some(sort_category) = sort_option { for (_, ref mut language) in &mut languages { @@ -229,8 +243,8 @@ fn main() { /// This originally too a &[u8], but the u8 didn't directly correspond with the hexadecimal u8, so /// it had to be changed to a String, and add the rustc_serialize dependency. +#[cfg(feature = "io")] pub fn convert_input(contents: String) -> Option> { - if contents.is_empty() { None } else if let Ok(result) = serde_json::from_str(&*contents) { @@ -250,6 +264,34 @@ pub fn convert_input(contents: String) -> Option { + // let cbor: Vec = languages.to_cbor().unwrap(); + + // for byte in cbor { + // print!("{:02x}", byte); + // } + } + "json" => print!("{}", languages.to_json().unwrap()), + "toml" => print!("{}", languages.to_toml()), + "yaml" => print!("{}", languages.to_yaml().unwrap()), + _ => unreachable!(), + } +} + +#[cfg(not(feature = "io"))] +fn match_output(format: &str) -> ! { + panic!(OUTPUT_ERROR) +} + + +#[cfg(not(feature = "io"))] +pub fn convert_input(contents: String) -> ! { + panic!(OUTPUT_ERROR); +} + fn print_language<'a, C>(language: &'a Language, name: C) where C: Into> {