summaryrefslogtreecommitdiffstats
path: root/src/paint.rs
blob: bf85fb138a8a6cc80873dc19c1d13ad0576c5643 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
1
%define contentdir %{_datadir}/netdata
%if 0%{?suse_version}
%define distro_post %service_add_post netdata.service
%define distro_preun %service_del_preun netdata.service
%define distro_postun %service_del_postun netdata.service
%define distro_buildrequires BuildRequires:\ systemd-rpm-macros
%else
%define distro_post %systemd_post netdata.service
%define distro_preun %systemd_preun netdata.service
%define distro_postun %systemd_postun_with_restart netdata.service
%define distro_buildrequires %{nil}
%endif

# This is temporary and should eventually be resolved. This bypasses
# the default rhel __os_install_post which throws a python compile
# error.
%define __os_install_post %{nil}

#
# Conditional build:
%bcond_without  systemd  # systemd
%bcond_with     nfacct   # build with nfacct plugin

%if 0%{?fedora} || 0%{?rhel} >= 7 || 0%{?suse_version} >= 1140
%else
%undefine	with_systemd
%endif

Summary:	Real-time performance monitoring, done right
Name:		@PACKAGE_NAME@
Version:	@PACKAGE_RPM_VERSION@
Release:	1%{?dist}
License:	GPL v3+
Group:		Applications/System
Source0:	http://firehol.org/download/netdata/releases/v@PACKAGE_VERSION@/%{name}-@PACKAGE_VERSION@.tar.xz
URL:		http://my-netdata.io/
%distro_buildrequires
BuildRequires:	/usr/bin/autoconf
BuildRequires:	/usr/bin/automake
BuildRequires:	pkgconfig
BuildRequires:	xz
BuildRequires:	zlib-devel
BuildRequires:	libuuid-devel
Requires:	zlib
Requires:	libuuid
Requires(post): libcap
Recommends:	curl
Recommends:	iproute-tc
Recommends:	lm_sensors
Recommends:	nmap-ncat
Recommends:	nodejs
Recommends:	python
Recommends:	PyYAML
Recommends:	python2-PyMySQL
Recommends:	python2-psycopg2

# Packages can be found in the EPEL repo
%if %{with nfacct}
BuildRequires:	libmnl-devel
BuildRequires:	libnetfilter_acct-devel
Requires: libmnl
Requires: libnetfilter_acct
%endif

Requires(pre): /usr/sbin/groupadd
Requires(pre): /usr/sbin/useradd

%if %{with systemd}
%if 0%{?suse_version}
%{?systemd_requires}
%else
Requires(preun):  systemd-units
Requires(postun): systemd-units
Requires(post):   systemd-units
%endif
%else
Requires(post):   chkconfig
%endif

%description
netdata is the fastest way to visualize metrics. It is a resource
efficient, highly optimized system for collecting and visualizing any
type of realtime timeseries data, from CPU usage, disk activity, SQL
queries, API calls, web site visitors, etc.

netdata tries to visualize the truth of now, in its greatest detail,
so that you can get insights of what is happening now and what just
happened, on your systems and applications.

%prep
%setup -q

%build
./autogen.sh
%configure \
	--with-zlib \
	--with-math \
	%{?with_nfacct:--enable-plugin-nfacct} \
	--with-user=netdata
%{__make} %{?_smp_mflags}

%install
rm -rf $RPM_BUILD_ROOT
%{__make} %{?_smp_mflags} DESTDIR=$RPM_BUILD_ROOT install

find $RPM_BUILD_ROOT -name .keep -delete

install -m 644 -p system/netdata.conf $RPM_BUILD_ROOT%{_sysconfdir}/%{name}
install -d $RPM_BUILD_ROOT%{_sysconfdir}/logrotate.d
install -m 644 -p system/netdata.logrotate $RPM_BUILD_ROOT%{_sysconfdir}/logrotate.d/%{name}

%if %{with systemd}
install -d $RPM_BUILD_ROOT%{_unitdir}
install -m 644 -p system/netdata.service $RPM_BUILD_ROOT%{_unitdir}/netdata.service
%else
# install SYSV init stuff
install -d $RPM_BUILD_ROOT/etc/rc.d/init.d
install -m755 system/netdata-init-d \
        $RPM_BUILD_ROOT/etc/rc.d/init.d/netdata
%endif

%if %{with systemd}
%pre
# Add the "netdata" user
/usr/sbin/groupadd -r netdata 2> /dev/null || :
/usr/sbin/useradd -c "netdata" -g netdata \
        -s /sbin/nologin -r -d %{contentdir} netdata 2> /dev/null || :

%post
%distro_post
setcap cap_dac_read,cap_sys_ptrace+ep /usr/libexec/netdata/plugins.d/apps.plugin || chmod 1755 /usr/libexec/netdata/plugins.d/apps.plugin

%preun
%distro_preun

%postun
%distro_postun
%else
%pre
# Add the "netdata" user
getent group netdata >/dev/null || groupadd -r netdata
getent group docker >/dev/null || groupadd -r docker
getent passwd netdata >/dev/null || \
  useradd -r -g netdata -G docker -s /sbin/nologin \
    -d %{contentdir} -c "netdata" netdata
exit 0

%post
setcap cap_dac_read,cap_sys_ptrace+ep /usr/libexec/netdata/plugins.d/apps.plugin || chmod 1755 /usr/libexec/netdata/plugins.d/apps.plugin
# Register the netdata service
/sbin/chkconfig --add netdata
# Only gets run on initial install (not upgrades or uninstalls)
if [ $1 = 1 ]; then
        # Start the netdata service
        /sbin/service netdata start
fi
exit 0

%preun
# Only gets run on uninstall (not upgrades)
if [ $1 = 0 ]; then
        /sbin/service netdata stop > /dev/null 2>&1
        /sbin/chkconfig --del netdata
fi
exit 0

%postun
# Only gets run on upgrade (not uninstalls)
if [ $1 != 0 ]; then
        /sbin/service netdata condrestart 2>&1 > /dev/null
fi
exit 0
%endif

%clean
rm -rf $RPM_BUILD_ROOT

%files
%doc README.md
%defattr(-,root,root)

%dir %{_sysconfdir}/%{name}

%config(noreplace) %{_sysconfdir}/%{name}/*.conf
%config(noreplace) %{_sysconfdir}/%{name}/charts.d/*.conf
%config(noreplace) %{_sysconfdir}/%{name}/health.d/*.conf
#%%config(noreplace) %{_sysconfdir}/%{name}/node.d/*.conf
%config(noreplace) %{_sysconfdir}/%{name}/python.d/*.conf
%config(noreplace) %{_sysconfdir}/logrotate.d/%{name}

# To be eventually moved to %%_defaultdocdir
%{_sysconfdir}/%{name}/node.d/*.md

%caps(cap_dac_read_search,cap_sys_ptrace=ep) %{_libexecdir}/%{name}/plugins.d/apps.plugin

%{_libexecdir}/%{name}
%{_sbindir}/%{name}

%attr(0700,netdata,netdata) %dir %{_localstatedir}/cache/%{name}
%attr(0700,netdata,netdata) %dir %{_localstatedir}/log/%{name}
%attr(0700,netdata,netdata) %dir %{_localstatedir}/lib/%{name}

%dir %{_datadir}/%{name}
%dir %{_sysconfdir}/%{name}/health.d
%dir %{_sysconfdir}/%{name}/python.d

%if %{with systemd}
%{_unitdir}/netdata.service
%else
%{_sysconfdir}/rc.d/init.d/netdata
%endif

# Enforce 0644 for files and 0755 for directories
# for the netdata web directory
%defattr(0644,root,netdata,0755)
%{_datadir}/%{name}/web

%changelog
* Tue Oct 4 2016 Costa Tsaousis <costa@tsaousis.gr> - 1.4.0-1
- the fastest netdata ever (with a better look too)!
- improved IoT and containers support!
- alarms improved in almost every way!
- Several more improvements, new features and bugfixes.
* Sun Aug 28 2016 Costa Tsaousis <costa@tsaousis.gr> - 1.3.0-1
- netdata now has health monitoring
- netdata now generates badges
- netdata now has python plugins
- Several more improvements, new features and bugfixes.
* Tue Jul 26 2016 Jason Barnett <J@sonBarnett.com> - 1.2.0-2
- Added support for EL6
- Corrected several Requires statements
- Changed default to build without nfacct
- Removed --docdir from configure
* Mon May 16 2016 Costa Tsaousis <costa@tsaousis.gr> - 1.2.0-1
- netdata is now 30% faster.
- netdata now has a registry (my-netdata menu on the dashboard).
- netdata now monitors Linux containers.
- Several more improvements, new features and bugfixes.
* Wed Apr 20 2016 Costa Tsaousis <costa@tsaousis.gr> - 1.1.0-1
- Several new features (IPv6, SYNPROXY, Users, Users Groups).
- A lot of bug fixes and optimizations.
* Tue Mar 22 2016 Costa Tsaousis <costa@tsaousis.gr> - 1.0.0-1
- First public release.
* Sun Nov 15 2015 Alon Bar-Lev <alonbl@redhat.com> - 0.0.0-1
- Initial add.
n495'>495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826
use std::io::Write;

use itertools::Itertools;
use syntect::easy::HighlightLines;
use syntect::highlighting::Style as SyntectStyle;
use syntect::parsing::{SyntaxReference, SyntaxSet};
use unicode_segmentation::UnicodeSegmentation;

use crate::ansi;
use crate::config::{self, delta_unreachable};
use crate::delta::State;
use crate::edits;
use crate::features::line_numbers;
use crate::features::side_by_side;
use crate::paint::superimpose_style_sections::superimpose_style_sections;
use crate::style::Style;

pub struct Painter<'a> {
    pub minus_lines: Vec<(String, State)>,
    pub plus_lines: Vec<(String, State)>,
    pub writer: &'a mut dyn Write,
    pub syntax: &'a SyntaxReference,
    pub highlighter: HighlightLines<'a>,
    pub config: &'a config::Config,
    pub output_buffer: String,
    pub line_numbers_data: line_numbers::LineNumbersData<'a>,
}

impl<'a> Painter<'a> {
    pub fn new(writer: &'a mut dyn Write, config: &'a config::Config) -> Self {
        let default_syntax = Self::get_syntax(&config.syntax_set, None);
        // TODO: Avoid doing this.
        let dummy_highlighter = HighlightLines::new(default_syntax, &config.syntax_dummy_theme);

        let line_numbers_data = if config.line_numbers {
            line_numbers::LineNumbersData::from_format_strings(
                &config.line_numbers_left_format,
                &config.line_numbers_right_format,
            )
        } else {
            line_numbers::LineNumbersData::default()
        };
        Self {
            minus_lines: Vec::new(),
            plus_lines: Vec::new(),
            output_buffer: String::new(),
            syntax: default_syntax,
            highlighter: dummy_highlighter,
            writer,
            config,
            line_numbers_data,
        }
    }

    pub fn set_syntax(&mut self, extension: Option<&str>) {
        self.syntax = Painter::get_syntax(&self.config.syntax_set, extension);
    }

    fn get_syntax(syntax_set: &'a SyntaxSet, extension: Option<&str>) -> &'a SyntaxReference {
        if let Some(extension) = extension {
            if let Some(syntax) = syntax_set.find_syntax_by_extension(extension) {
                return syntax;
            }
        }
        syntax_set
            .find_syntax_by_extension("txt")
            .unwrap_or_else(|| delta_unreachable("Failed to find any language syntax definitions."))
    }

    pub fn set_highlighter(&mut self) {
        if let Some(ref syntax_theme) = self.config.syntax_theme {
            self.highlighter = HighlightLines::new(self.syntax, &syntax_theme)
        };
    }

    /// Replace initial -/+ character with ' ', expand tabs as spaces, and optionally terminate with
    /// newline.
    // Terminating with newline character is necessary for many of the sublime syntax definitions to
    // highlight correctly.
    // See https://docs.rs/syntect/3.2.0/syntect/parsing/struct.SyntaxSetBuilder.html#method.add_from_folder
    pub fn prepare(&self, line: &str) -> String {
        if !line.is_empty() {
            let mut line = line.graphemes(true);

            // The first column contains a -/+/space character, added by git. We substitute it for
            // a space now, so that it is not present during syntax highlighting. When emitting the
            // line in Painter::paint_line, we drop the space (unless --keep-plus-minus-markers is
            // in effect in which case we replace it with the appropriate marker).
            // TODO: Things should, but do not, work if this leading space is omitted at this stage.
            // See comment in align::Alignment::new.
            line.next();
            format!(" {}\n", self.expand_tabs(line))
        } else {
            "\n".to_string()
        }
    }

    /// Remove the initial +/- character of a line that will be emitted unchanged, including any
    /// ANSI escape sequences.
    pub fn prepare_raw_line(&self, line: &str) -> String {
        ansi::ansi_preserving_slice(
            &self.expand_tabs(line.graphemes(true)),
            if self.config.keep_plus_minus_markers {
                0
            } else {
                1
            },
        )
    }

    /// Expand tabs as spaces.
    /// tab_width = 0 is documented to mean do not replace tabs.
    pub fn expand_tabs<'b, I>(&self, line: I) -> String
    where
        I: Iterator<Item = &'b str>,
    {
        <