You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

143 lines
4.5KB

  1. use lazy_static::lazy_static;
  2. use std::env;
  3. use std::error::Error as StdError;
  4. use std::io::Write;
  5. use std::time::Instant;
  6. use atty;
  7. use chrono::Duration;
  8. use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
  9. use errors::Error;
  10. use site::Site;
  11. lazy_static! {
  12. /// Termcolor color choice.
  13. /// We do not rely on ColorChoice::Auto behavior
  14. /// as the check is already performed by has_color.
  15. static ref COLOR_CHOICE: ColorChoice =
  16. if has_color() {
  17. ColorChoice::Always
  18. } else {
  19. ColorChoice::Never
  20. };
  21. }
  22. pub fn info(message: &str) {
  23. colorize(message, ColorSpec::new().set_bold(true));
  24. }
  25. pub fn warn(message: &str) {
  26. colorize(message, ColorSpec::new().set_bold(true).set_fg(Some(Color::Yellow)));
  27. }
  28. pub fn success(message: &str) {
  29. colorize(message, ColorSpec::new().set_bold(true).set_fg(Some(Color::Green)));
  30. }
  31. pub fn error(message: &str) {
  32. colorize(message, ColorSpec::new().set_bold(true).set_fg(Some(Color::Red)));
  33. }
  34. /// Print a colorized message to stdout
  35. fn colorize(message: &str, color: &ColorSpec) {
  36. let mut stdout = StandardStream::stdout(*COLOR_CHOICE);
  37. stdout.set_color(color).unwrap();
  38. write!(&mut stdout, "{}", message).unwrap();
  39. stdout.set_color(&ColorSpec::new()).unwrap();
  40. writeln!(&mut stdout).unwrap();
  41. }
  42. /// Display in the console the number of pages/sections in the site, and number of images to process
  43. pub fn notify_site_size(site: &Site) {
  44. let library = site.library.read().unwrap();
  45. println!(
  46. "-> Creating {} pages ({} orphan), {} sections, and processing {} images",
  47. library.pages().len(),
  48. site.get_number_orphan_pages(),
  49. library.sections().len() - 1, // -1 since we do not count the index as a section there
  50. site.num_img_ops(),
  51. );
  52. }
  53. /// Display in the console only the number of pages/sections in the site
  54. pub fn check_site_summary(site: &Site) {
  55. let library = site.library.read().unwrap();
  56. let orphans = library.get_all_orphan_pages();
  57. println!(
  58. "-> Site content: {} pages ({} orphan), {} sections",
  59. library.pages().len(),
  60. orphans.len(),
  61. library.sections().len() - 1, // -1 since we do not count the index as a section there
  62. );
  63. for orphan in orphans {
  64. warn(&format!("Orphan page found: {}", orphan.path));
  65. }
  66. }
  67. /// Display a warning in the console if there are ignored pages in the site
  68. pub fn warn_about_ignored_pages(site: &Site) {
  69. let library = site.library.read().unwrap();
  70. let ignored_pages: Vec<_> = library
  71. .sections_values()
  72. .iter()
  73. .flat_map(|s| s.ignored_pages.iter().map(|k| library.get_page_by_key(*k).file.path.clone()))
  74. .collect();
  75. if !ignored_pages.is_empty() {
  76. warn(&format!(
  77. "{} page(s) ignored (missing date or weight in a sorted section):",
  78. ignored_pages.len()
  79. ));
  80. for path in ignored_pages {
  81. warn(&format!("- {}", path.display()));
  82. }
  83. }
  84. }
  85. pub fn report_n_pages_indexed(n_pages_indexed: usize, took: std::time::Duration) {
  86. let duration_sec = took.as_secs_f64();
  87. let duration_ms = duration_sec * 1000.0;
  88. if duration_ms < 1000.0 {
  89. success(&format!("Search: indexed {} pages in {}ms.\n", n_pages_indexed, duration_ms));
  90. } else {
  91. success(&format!("Search: indexed {} pages in {:.1}s.\n", n_pages_indexed, ((duration_sec * 10.0).round() / 10.0)));
  92. }
  93. }
  94. /// Print the time elapsed rounded to 1 decimal
  95. pub fn report_elapsed_time(instant: Instant) {
  96. let duration_ms = Duration::from_std(instant.elapsed()).unwrap().num_milliseconds() as f64;
  97. if duration_ms < 1000.0 {
  98. success(&format!("Done in {}ms.\n", duration_ms));
  99. } else {
  100. let duration_sec = duration_ms / 1000.0;
  101. success(&format!("Done in {:.1}s.\n", ((duration_sec * 10.0).round() / 10.0)));
  102. }
  103. }
  104. /// Display an error message and the actual error(s)
  105. pub fn unravel_errors(message: &str, error: &Error) {
  106. if !message.is_empty() {
  107. self::error(message);
  108. }
  109. self::error(&format!("Error: {}", error));
  110. let mut cause = error.source();
  111. while let Some(e) = cause {
  112. self::error(&format!("Reason: {}", e));
  113. cause = e.source();
  114. }
  115. }
  116. /// Check whether to output colors
  117. fn has_color() -> bool {
  118. let use_colors = env::var("CLICOLOR").unwrap_or_else(|_| "1".to_string()) != "0"
  119. && env::var("NO_COLOR").is_err();
  120. let force_colors = env::var("CLICOLOR_FORCE").unwrap_or_else(|_| "0".to_string()) != "0";
  121. force_colors || use_colors && atty::is(atty::Stream::Stdout)
  122. }