<commit_before>//! Sanity checking performed by rustbuild before actually executing anything.
//!
//! This module contains the implementation of ensuring that the build
//! environment looks reasonable before progressing. This will verify that
//! various programs like git and python exist, along with ensuring that all C
//! compilers for cross-compiling are found.
//!
//! In theory if we get past this phase it's a bug if a build fails, but in
//! practice that's likely not true!

use std::collections::HashMap;
use std::env;
use std::ffi::{OsStr, OsString};
use std::fs;
use std::path::PathBuf;
use std::process::Command;

use build_helper::{output, t};

use crate::cache::INTERNER;
use crate::config::Target;
use crate::Build;

pub struct Finder {
    cache: HashMap<OsString, Option<PathBuf>>,
    path: OsString,
}

impl Finder {
    pub fn new() -> Self {
        Self { cache: HashMap::new(), path: env::var_os("PATH").unwrap_or_default() }
    }

    pub fn maybe_have<S: Into<OsString>>(&mut self, cmd: S) -> Option<PathBuf> {
        let cmd: OsString = cmd.into();
        let path = &self.path;
        self.cache
            .entry(cmd.clone())
            .or_insert_with(|| {
                for path in env::split_paths(path) {
                    let target = path.join(&cmd);
                    let mut cmd_exe = cmd.clone();
                    cmd_exe.push(".exe");

                    if target.is_file()                   // some/path/git
                    || path.join(&cmd_exe).exists()   // some/path/git.exe
                    || target.join(&cmd_exe).exists()
                    // some/path/git/git.exe
                    {
                        return Some(target);
                    }
                }
                None
            })
            .clone()
    }

    pub fn must_have<S: AsRef<OsStr>>(&mut self, cmd: S) -> PathBuf {
        self.maybe_have(&cmd).unwrap_or_else(|| {
            panic!("\n\ncouldn't find required command: {:?}\n\n", cmd.as_ref());
        })
    }
}

pub fn check(build: &mut Build) {
    let path = env::var_os("PATH").unwrap_or_default();
    // On Windows, quotes are invalid characters for filename paths, and if
    // one is present as part of the PATH then that can lead to the system
    // being unable to identify the files properly. See
    // https://github.com/rust-lang/rust/issues/34959 for more details.
    if cfg!(windows) && path.to_string_lossy().contains('\"') {
        panic!("PATH contains invalid character '\"'");
    }

    let mut cmd_finder = Finder::new();
    // If we've got a git directory we're gonna need git to update
    // submodules and learn about various other aspects.
    if build.rust_info.is_git() {
        cmd_finder.must_have("git");
    }

    // We need cmake, but only if we're actually building LLVM or sanitizers.
    let building_llvm = build.config.rust_codegen_backends.contains(&INTERNER.intern_str("llvm"))
        && build
            .hosts
            .iter()
            .map(|host| {
                build
                    .config
                    .target_config
                    .get(host)
                    .map(|config| config.llvm_config.is_none())
                    .unwrap_or(true)
            })
            .any(|build_llvm_ourselves| build_llvm_ourselves);
    let need_cmake = building_llvm || build.config.any_sanitizers_enabled();
    if need_cmake {
        cmd_finder.must_have("cmake");
    }

    build.config.python = build
        .config
        .python
        .take()
        .map(|p| cmd_finder.must_have(p))
        .or_else(|| env::var_os("BOOTSTRAP_PYTHON").map(PathBuf::from)) // set by bootstrap.py
        .or_else(|| Some(cmd_finder.must_have("python")));

    build.config.nodejs = build
        .config
        .nodejs
        .take()
        .map(|p| cmd_finder.must_have(p))
        .or_else(|| cmd_finder.maybe_have("node"))
        .or_else(|| cmd_finder.maybe_have("nodejs"));

    build.config.npm = build
        .config
        .npm
        .take()
        .map(|p| cmd_finder.must_have(p))
        .or_else(|| cmd_finder.maybe_have("npm"));

    build.config.gdb = build
        .config
        .gdb
        .take()
        .map(|p| cmd_finder.must_have(p))
        .or_else(|| cmd_finder.maybe_have("gdb"));

    // We're gonna build some custom C code here and there, host triples
    // also build some C++ shims for LLVM so we need a C++ compiler.
    for target in &build.targets {
        // On emscripten we don't actually need the C compiler to just
        // build the target artifacts, only for testing. For the sake
        // of easier bot configuration, just skip detection.
        if target.contains("emscripten") {
            continue;
        }

        // We don't use a C compiler on wasm32
        if target.contains("wasm32") {
            continue;
        }

        if !build.config.dry_run {
            cmd_finder.must_have(build.cc(*target));
            if let Some(ar) = build.ar(*target) {
                cmd_finder.must_have(ar);
            }
        }
    }

    for host in &build.hosts {
        if !build.config.dry_run {
            cmd_finder.must_have(build.cxx(*host).unwrap());
        }
    }

    if build.config.rust_codegen_backends.contains(&INTERNER.intern_str("llvm")) {
        // Externally configured LLVM requires FileCheck to exist
        let filecheck = build.llvm_filecheck(build.build);
        if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests {
            panic!("FileCheck executable {:?} does not exist", filecheck);
        }
    }

    for target in &build.targets {
        // Can't compile for iOS unless we're on macOS
        if target.contains("apple-ios") && !build.build.contains("apple-darwin") {
            panic!("the iOS target is only supported on macOS");
        }

        build
            .config
            .target_config
            .entry(*target)
            .or_insert_with(|| Target::from_triple(&target.triple));

        if target.contains("-none-") || target.contains("nvptx") {
            if build.no_std(*target) == Some(false) {
                panic!("All the *-none-* and nvptx* targets are no-std targets")
            }
        }

        // Make sure musl-root is valid
        if target.contains("musl") {
            // If this is a native target (host is also musl) and no musl-root is given,
            // fall back to the system toolchain in /usr before giving up
            if build.musl_root(*target).is_none() && build.config.build == *target {
                let target = build.config.target_config.entry(*target).or_default();
                target.musl_root = Some("/usr".into());
            }
            match build.musl_libdir(*target) {
                Some(libdir) => {
                    if fs::metadata(libdir.join("libc.a")).is_err() {
                        panic!("couldn't find libc.a in musl libdir: {}", libdir.display());
                    }
                }
                None => panic!(
                    "when targeting MUSL either the rust.musl-root \
                            option or the target.$TARGET.musl-root option must \
                            be specified in config.toml"
                ),
            }
        }

        if need_cmake && target.contains("msvc") {
            // There are three builds of cmake on windows: MSVC, MinGW, and
            // Cygwin. The Cygwin build does not have generators for Visual
            // Studio, so detect that here and error.
            let out = output(Command::new("cmake").arg("--help"));
            if !out.contains("Visual Studio") {
                panic!(
                    "
cmake does not support Visual Studio generators.

This is likely due to it being an msys/cygwin build of cmake,
rather than the required windows version, built using MinGW
or Visual Studio.

If you are building under msys2 try installing the mingw-w64-x86_64-cmake
package instead of cmake:

$ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake
"
                );
            }
        }
    }

    if let Some(ref s) = build.config.ccache {
        cmd_finder.must_have(s);
    }

    if build.config.channel == "stable" {
        let stage0 = t!(fs::read_to_string(build.src.join("src/stage0.txt")));
        if stage0.contains("\ndev:") {
            panic!(
                "bootstrapping from a dev compiler in a stable release, but \
                    should only be bootstrapping from a released compiler!"
            );
        }
    }
}
<commit_msg>Allow the iOS toolchain to be built on Linux<commit_after>//! Sanity checking performed by rustbuild before actually executing anything.
//!
//! This module contains the implementation of ensuring that the build
//! environment looks reasonable before progressing. This will verify that
//! various programs like git and python exist, along with ensuring that all C
//! compilers for cross-compiling are found.
//!
//! In theory if we get past this phase it's a bug if a build fails, but in
//! practice that's likely not true!

use std::collections::HashMap;
use std::env;
use std::ffi::{OsStr, OsString};
use std::fs;
use std::path::PathBuf;
use std::process::Command;

use build_helper::{output, t};

use crate::cache::INTERNER;
use crate::config::Target;
use crate::Build;

pub struct Finder {
    cache: HashMap<OsString, Option<PathBuf>>,
    path: OsString,
}

impl Finder {
    pub fn new() -> Self {
        Self { cache: HashMap::new(), path: env::var_os("PATH").unwrap_or_default() }
    }

    pub fn maybe_have<S: Into<OsString>>(&mut self, cmd: S) -> Option<PathBuf> {
        let cmd: OsString = cmd.into();
        let path = &self.path;
        self.cache
            .entry(cmd.clone())
            .or_insert_with(|| {
                for path in env::split_paths(path) {
                    let target = path.join(&cmd);
                    let mut cmd_exe = cmd.clone();
                    cmd_exe.push(".exe");

                    if target.is_file()                   // some/path/git
                    || path.join(&cmd_exe).exists()   // some/path/git.exe
                    || target.join(&cmd_exe).exists()
                    // some/path/git/git.exe
                    {
                        return Some(target);
                    }
                }
                None
            })
            .clone()
    }

    pub fn must_have<S: AsRef<OsStr>>(&mut self, cmd: S) -> PathBuf {
        self.maybe_have(&cmd).unwrap_or_else(|| {
            panic!("\n\ncouldn't find required command: {:?}\n\n", cmd.as_ref());
        })
    }
}

pub fn check(build: &mut Build) {
    let path = env::var_os("PATH").unwrap_or_default();
    // On Windows, quotes are invalid characters for filename paths, and if
    // one is present as part of the PATH then that can lead to the system
    // being unable to identify the files properly. See
    // https://github.com/rust-lang/rust/issues/34959 for more details.
    if cfg!(windows) && path.to_string_lossy().contains('\"') {
        panic!("PATH contains invalid character '\"'");
    }

    let mut cmd_finder = Finder::new();
    // If we've got a git directory we're gonna need git to update
    // submodules and learn about various other aspects.
    if build.rust_info.is_git() {
        cmd_finder.must_have("git");
    }

    // We need cmake, but only if we're actually building LLVM or sanitizers.
    let building_llvm = build.config.rust_codegen_backends.contains(&INTERNER.intern_str("llvm"))
        && build
            .hosts
            .iter()
            .map(|host| {
                build
                    .config
                    .target_config
                    .get(host)
                    .map(|config| config.llvm_config.is_none())
                    .unwrap_or(true)
            })
            .any(|build_llvm_ourselves| build_llvm_ourselves);
    let need_cmake = building_llvm || build.config.any_sanitizers_enabled();
    if need_cmake {
        cmd_finder.must_have("cmake");
    }

    build.config.python = build
        .config
        .python
        .take()
        .map(|p| cmd_finder.must_have(p))
        .or_else(|| env::var_os("BOOTSTRAP_PYTHON").map(PathBuf::from)) // set by bootstrap.py
        .or_else(|| Some(cmd_finder.must_have("python")));

    build.config.nodejs = build
        .config
        .nodejs
        .take()
        .map(|p| cmd_finder.must_have(p))
        .or_else(|| cmd_finder.maybe_have("node"))
        .or_else(|| cmd_finder.maybe_have("nodejs"));

    build.config.npm = build
        .config
        .npm
        .take()
        .map(|p| cmd_finder.must_have(p))
        .or_else(|| cmd_finder.maybe_have("npm"));

    build.config.gdb = build
        .config
        .gdb
        .take()
        .map(|p| cmd_finder.must_have(p))
        .or_else(|| cmd_finder.maybe_have("gdb"));

    // We're gonna build some custom C code here and there, host triples
    // also build some C++ shims for LLVM so we need a C++ compiler.
    for target in &build.targets {
        // On emscripten we don't actually need the C compiler to just
        // build the target artifacts, only for testing. For the sake
        // of easier bot configuration, just skip detection.
        if target.contains("emscripten") {
            continue;
        }

        // We don't use a C compiler on wasm32
        if target.contains("wasm32") {
            continue;
        }

        if !build.config.dry_run {
            cmd_finder.must_have(build.cc(*target));
            if let Some(ar) = build.ar(*target) {
                cmd_finder.must_have(ar);
            }
        }
    }

    for host in &build.hosts {
        if !build.config.dry_run {
            cmd_finder.must_have(build.cxx(*host).unwrap());
        }
    }

    if build.config.rust_codegen_backends.contains(&INTERNER.intern_str("llvm")) {
        // Externally configured LLVM requires FileCheck to exist
        let filecheck = build.llvm_filecheck(build.build);
        if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests {
            panic!("FileCheck executable {:?} does not exist", filecheck);
        }
    }

    for target in &build.targets {
        build
            .config
            .target_config
            .entry(*target)
            .or_insert_with(|| Target::from_triple(&target.triple));

        if target.contains("-none-") || target.contains("nvptx") {
            if build.no_std(*target) == Some(false) {
                panic!("All the *-none-* and nvptx* targets are no-std targets")
            }
        }

        // Make sure musl-root is valid
        if target.contains("musl") {
            // If this is a native target (host is also musl) and no musl-root is given,
            // fall back to the system toolchain in /usr before giving up
            if build.musl_root(*target).is_none() && build.config.build == *target {
                let target = build.config.target_config.entry(*target).or_default();
                target.musl_root = Some("/usr".into());
            }
            match build.musl_libdir(*target) {
                Some(libdir) => {
                    if fs::metadata(libdir.join("libc.a")).is_err() {
                        panic!("couldn't find libc.a in musl libdir: {}", libdir.display());
                    }
                }
                None => panic!(
                    "when targeting MUSL either the rust.musl-root \
                            option or the target.$TARGET.musl-root option must \
                            be specified in config.toml"
                ),
            }
        }

        if need_cmake && target.contains("msvc") {
            // There are three builds of cmake on windows: MSVC, MinGW, and
            // Cygwin. The Cygwin build does not have generators for Visual
            // Studio, so detect that here and error.
            let out = output(Command::new("cmake").arg("--help"));
            if !out.contains("Visual Studio") {
                panic!(
                    "
cmake does not support Visual Studio generators.

This is likely due to it being an msys/cygwin build of cmake,
rather than the required windows version, built using MinGW
or Visual Studio.

If you are building under msys2 try installing the mingw-w64-x86_64-cmake
package instead of cmake:

$ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake
"
                );
            }
        }
    }

    if let Some(ref s) = build.config.ccache {
        cmd_finder.must_have(s);
    }

    if build.config.channel == "stable" {
        let stage0 = t!(fs::read_to_string(build.src.join("src/stage0.txt")));
        if stage0.contains("\ndev:") {
            panic!(
                "bootstrapping from a dev compiler in a stable release, but \
                    should only be bootstrapping from a released compiler!"
            );
        }
    }
}
<|endoftext|>


<commit_before>#![recursion_limit="128"]
#![cfg_attr(feature = "cargo-clippy", allow(cyclomatic_complexity, trivial_regex))]
use std::io::stderr;
use std::io::Write;
use std::collections::HashMap;

extern crate bam2bedgraph;
use bam2bedgraph::errors::*;
use bam2bedgraph::indexed_annotation::IndexedAnnotation;

extern crate bio;

extern crate structopt;
#[macro_use]
extern crate structopt_derive;
use structopt::StructOpt;

#[derive(StructOpt, Debug)]
#[structopt(name = "cassette_lengths", about = "Histogram of cassette exon lengths within the intron of tr of another gene")]
struct Options {
    // input files
    #[structopt(long="gff", help = "A genome annotation file in gff3 format", name="ANNOT_GFF_FILE")]
    annotfile_gff: Option<String>,
}

fn run() -> Result<()> {
    let options = Options::from_args();
    let annot = IndexedAnnotation::from_gff(
        &options.annotfile_gff.r()?,
        &None,
        &None)?;
    println!("row\tgene_name\tother_gene_name\tcassette_location\tcassette_length");
    for (row, record) in annot.rows.iter().enumerate() {
        if let Some(exon_type) = record.attributes.get("exon_type") {
            if exon_type == "cassette" && record.feature_type == "exon" {
                if let Some(record_gene_name) = record.attributes.get("gene_name") {
                    let mut other_genes = HashMap::<String,u64>::new();
                    for overlap_row in annot.tree[&record.seqname].find(record.start-1..record.end) {
                        let overlaps = &annot.rows[*overlap_row.data()];
                        if overlaps.strand == record.strand &&
                            (overlaps.feature_type == "gene" || overlaps.feature_type == "exon")
                        {
                            if let Some(overlaps_gene_name) = overlaps.attributes.get("gene_name") {
                                if overlaps_gene_name != record_gene_name &&
                                    &format!("{}.reannot", overlaps_gene_name) != record_gene_name
                                {
                                    if overlaps.feature_type == "exon" {
                                        *other_genes.entry(overlaps_gene_name.clone()).or_insert(0) += 1;
                                    }
                                    else {
                                        other_genes.entry(overlaps_gene_name.clone()).or_insert(0);
                                    }
                                }
                            }
                        }
                    }
                    let mut overlapping_genes = Vec::<String>::new();
                    for (gene_name,overlapping_exons) in other_genes {
                        if overlapping_exons == 0 {
                            overlapping_genes.push(gene_name.clone());
                        }
                    }
                    if !overlapping_genes.is_empty() {
                        println!("{}\t{}\t{}\t{}:{}..{}:{}\t{}",
                            row,
                            record_gene_name,
                            overlapping_genes.join(","),
                            record.seqname,
                            record.start,
                            record.end,
                            record.strand,
                            record.end-record.start+1);
                    }
                }
            }
        }
    }

    Ok(())
}

fn main() {
    std::env::set_var("RUST_BACKTRACE", "full");
    if let Err(ref e) = run() {
        writeln!(stderr(), "error: {}", e).unwrap();
        for e in e.iter().skip(1) {
            writeln!(stderr(), "caused by: {}", e).unwrap();
        }
        if let Some(backtrace) = e.backtrace() {
            writeln!(stderr(), "backtrace: {:?}", backtrace).unwrap();
        }
        ::std::process::exit(1);
    }
}
<commit_msg>add --overlapping_genes flag<commit_after>#![recursion_limit="128"]
#![cfg_attr(feature = "cargo-clippy", allow(cyclomatic_complexity, trivial_regex))]
use std::io::stderr;
use std::io::Write;
use std::collections::HashMap;

extern crate bam2bedgraph;
use bam2bedgraph::errors::*;
use bam2bedgraph::indexed_annotation::IndexedAnnotation;

extern crate bio;

extern crate structopt;
#[macro_use]
extern crate structopt_derive;
use structopt::StructOpt;

#[derive(StructOpt, Debug)]
#[structopt(name = "cassette_lengths", about = "Histogram of cassette exon lengths within the intron of tr of another gene")]
struct Options {
    // input files
    #[structopt(long="overlapping_genes", help = "Only show cassettes which overlap other genes?")]
    overlapping_genes: bool,
    // input files
    #[structopt(long="gff", help = "A genome annotation file in gff3 format", name="ANNOT_GFF_FILE")]
    annotfile_gff: Option<String>,
}

fn run() -> Result<()> {
    let options = Options::from_args();
    let annot = IndexedAnnotation::from_gff(
        &options.annotfile_gff.r()?,
        &None,
        &None)?;
    println!("row\tgene_name\tother_gene_name\tcassette_location\tcassette_length");
    for (row, record) in annot.rows.iter().enumerate() {
        if let Some(exon_type) = record.attributes.get("exon_type") {
            if exon_type == "cassette" && record.feature_type == "exon" {
                if let Some(record_gene_name) = record.attributes.get("gene_name") {
                    let mut other_genes = HashMap::<String,u64>::new();
                    for overlap_row in annot.tree[&record.seqname].find(record.start-1..record.end) {
                        let overlaps = &annot.rows[*overlap_row.data()];
                        if overlaps.strand == record.strand &&
                            (overlaps.feature_type == "gene" || overlaps.feature_type == "exon")
                        {
                            if let Some(overlaps_gene_name) = overlaps.attributes.get("gene_name") {
                                if overlaps_gene_name != record_gene_name &&
                                    &format!("{}.reannot", overlaps_gene_name) != record_gene_name
                                {
                                    if overlaps.feature_type == "exon" {
                                        *other_genes.entry(overlaps_gene_name.clone()).or_insert(0) += 1;
                                    }
                                    else {
                                        other_genes.entry(overlaps_gene_name.clone()).or_insert(0);
                                    }
                                }
                            }
                        }
                    }
                    let mut overlapping_genes = Vec::<String>::new();
                    for (gene_name,overlapping_exons) in other_genes {
                        if overlapping_exons == 0 {
                            overlapping_genes.push(gene_name.clone());
                        }
                    }
                    if options.overlapping_genes && !overlapping_genes.is_empty() {
                        println!("{}\t{}\t{}\t{}:{}..{}:{}\t{}",
                            row,
                            record_gene_name,
                            overlapping_genes.join(","),
                            record.seqname,
                            record.start,
                            record.end,
                            record.strand,
                            record.end-record.start+1);
                    }
                }
            }
        }
    }

    Ok(())
}

fn main() {
    std::env::set_var("RUST_BACKTRACE", "full");
    if let Err(ref e) = run() {
        writeln!(stderr(), "error: {}", e).unwrap();
        for e in e.iter().skip(1) {
            writeln!(stderr(), "caused by: {}", e).unwrap();
        }
        if let Some(backtrace) = e.backtrace() {
            writeln!(stderr(), "backtrace: {:?}", backtrace).unwrap();
        }
        ::std::process::exit(1);
    }
}
<|endoftext|>


<commit_before>extern crate failure;
#[macro_use]
extern crate failure_derive;
extern crate getopts;
extern crate libc;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate varlink;

use failure::Fail;
use org_example_ping::*;
use std::collections::HashMap;
use std::env;
use std::io::{self, BufRead, BufReader, Error, Read, Write};
use std::process::exit;
use std::sync::{Arc, RwLock};
use std::thread;
use varlink::{Call, Connection, ConnectionHandler, Listener, ServerStream, VarlinkService};

// Dynamically build the varlink rust code.
mod org_example_ping;

#[cfg(test)]
mod test;

// Main

fn print_usage(program: &str, opts: &getopts::Options) {
    let brief = format!("Usage: {} [--varlink=<address>] [--client]", program);
    print!("{}", opts.usage(&brief));
}

fn main() {
    let args: Vec<_> = env::args().collect();
    let program = args[0].clone();

    let mut opts = getopts::Options::new();
    opts.optopt("", "varlink", "varlink address URL", "<address>");
    opts.optflag("", "client", "run in client mode");
    opts.optflag("m", "multiplex", "run in multiplex mode");
    opts.optflag("h", "help", "print this help menu");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => {
            eprintln!("{}", f.to_string());
            print_usage(&program, &opts);
            return;
        }
    };

    if matches.opt_present("h") {
        print_usage(&program, &opts);
        return;
    }

    let client_mode = matches.opt_present("client");

    let ret = if client_mode {
        let connection = match matches.opt_str("varlink") {
            None => Connection::with_activate(&format!("{} --varlink=$VARLINK_ADDRESS", program))
                .unwrap(),
            Some(address) => Connection::with_address(&address).unwrap(),
        };
        run_client(&connection)
    } else if let Some(address) = matches.opt_str("varlink") {
        run_server(&address, 0, matches.opt_present("m")).map_err(|e| e.into())
    } else {
        print_usage(&program, &opts);
        eprintln!("Need varlink address in server mode.");
        exit(1);
    };
    exit(match ret {
        Ok(_) => 0,
        Err(err) => {
            eprintln!("error: {:?}", err);
            1
        }
    });
}

// Client

fn run_client(connection: &Arc<RwLock<varlink::Connection>>) -> Result<()> {
    {
        let mut iface = VarlinkClient::new(connection.clone());
        let ping = String::from("Test");

        let reply = iface.ping(ping.clone()).call()?;
        assert_eq!(ping, reply.pong);
        println!("Pong: '{}'", reply.pong);

        let reply = iface.ping(ping.clone()).call()?;
        assert_eq!(ping, reply.pong);
        println!("Pong: '{}'", reply.pong);

        let reply = iface.ping(ping.clone()).call()?;
        assert_eq!(ping, reply.pong);
        println!("Pong: '{}'", reply.pong);

        let _reply = iface.upgrade().upgrade()?;
        println!("Client: upgrade()");
    }
    {
        // serve upgraded connection
        let mut conn = connection.write().unwrap();
        let mut writer = conn.writer.take().unwrap();
        writer.write_all(b"test test\nEnd\n")?;
        conn.writer = Some(writer);
        let mut buf = Vec::new();
        let mut reader = conn.reader.take().unwrap();
        if reader.read_until(b'\n', &mut buf)? == 0 {
            // incomplete data, in real life, store all bytes for the next call
            // for now just read the rest
            reader.read_to_end(&mut buf)?;
        };
        eprintln!("Client: upgraded got: {}", String::from_utf8_lossy(&buf));
        conn.reader = Some(reader);
    }
    Ok(())
}

// Server

struct MyOrgExamplePing;

impl org_example_ping::VarlinkInterface for MyOrgExamplePing {
    fn ping(&self, call: &mut Call_Ping, ping: String) -> varlink::Result<()> {
        call.reply(ping)
    }

    fn upgrade(&self, call: &mut Call_Upgrade) -> varlink::Result<()> {
        eprintln!("Server: called upgrade");
        call.to_upgraded();
        call.reply()
    }

    // An upgraded connection has its own application specific protocol.
    // Normally, there is no way back to the varlink protocol with this connection.
    fn call_upgraded(&self, call: &mut Call, bufreader: &mut BufRead) -> varlink::Result<Vec<u8>> {
        loop {
            let mut buf = String::new();
            let len = bufreader.read_line(&mut buf)?;
            if len == 0 {
                eprintln!("Server: upgraded got: none");
                // incomplete data, in real life, store all bytes for the next call
                // return Ok(buf.as_bytes().to_vec());
                return Err(varlink::ErrorKind::ConnectionClosed.into());
            }
            eprintln!("Server: upgraded got: {}", buf);

            call.writer.write_all(b"server reply: ")?;
            call.writer.write_all(buf.as_bytes())?;
            if buf.eq("End\n") {
                break;
            }
        }
        eprintln!("Server: upgraded ending");
        Ok(Vec::new())
    }
}

struct FdTracker {
    stream: Option<ServerStream>,
    buffer: Option<Vec<u8>>,
}

impl FdTracker {
    fn shutdown(&mut self) -> varlink::Result<()> {
        self.stream.as_mut().unwrap().shutdown()
    }
    fn chain_buffer(&mut self, buf: &mut Vec<u8>) {
        self.buffer.as_mut().unwrap().append(buf);
    }
    fn fill_buffer(&mut self, buf: &Vec<u8>) {
        self.buffer.as_mut().unwrap().clone_from(buf);
    }
    fn buf_as_slice(&mut self) -> &[u8] {
        self.buffer.as_mut().unwrap().as_slice()
    }
    fn write(&mut self, out: &[u8]) -> io::Result<usize> {
        self.stream.as_mut().unwrap().write(out)
    }
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.stream.as_mut().unwrap().read(buf)
    }
}

// listen_multiplex is just an example, if you don't want to use varlink::listen()
// and how to build your own main-loop and use the low-level varlink::handle() instead
pub fn listen_multiplex<S: ?Sized + AsRef<str>, H: ::ConnectionHandler + Send + Sync + 'static>(
    handler: H,
    address: &S,
    idle_timeout: u64,
) -> varlink::Result<()> {
    let timeout: i32 = match idle_timeout {
        0 => -1,
        n => (n * 1000) as i32,
    };

    let handler = Arc::new(handler);
    let mut fdmap: HashMap<i32, FdTracker> = HashMap::new();
    let mut fds = Vec::new();
    let mut threads = Vec::new();
    let listener = Listener::new(address)?;
    listener.set_nonblocking(true)?;

    fds.push(libc::pollfd {
        fd: listener.as_raw_fd(),
        revents: 0,
        events: libc::POLLIN,
    });

    loop {
        // Read activity on listening socket
        if fds[0].revents != 0 {
            let mut client = listener.accept(0)?;

            client.set_nonblocking(true)?;

            let fd = client.as_raw_fd();
            fds.push(libc::pollfd {
                fd,
                revents: 0,
                events: libc::POLLIN,
            });

            fdmap.insert(
                fd,
                FdTracker {
                    stream: Some(client),
                    buffer: Some(Vec::new()),
                },
            );
        }

        // Store which indices to remove
        let mut indices_to_remove = vec![];

        // Check client connections ...
        for (i, fds_item) in fds.iter().enumerate().skip(1) {
            if fds_item.revents != 0 {
                let mut upgraded_iface: Option<String> = None;
                let mut tracker = fdmap.get_mut(&fds_item.fd).unwrap();
                loop {
                    let mut readbuf: [u8; 8192] = [0; 8192];

                    match tracker.read(&mut readbuf) {
                        Ok(0) => {
                            let _ = tracker.shutdown();
                            indices_to_remove.push(i);
                            break;
                        }
                        Ok(len) => {
                            let mut out: Vec<u8> = Vec::new();
                            tracker.chain_buffer(&mut readbuf[0..len].to_vec());
                            eprintln!(
                                "Handling: {}",
                                String::from_utf8_lossy(&tracker.buf_as_slice())
                            );

                            match handler.handle(&mut tracker.buf_as_slice(), &mut out, None) {
                                // TODO: buffer output and write only on POLLOUT
                                Ok((unprocessed_bytes, last_iface)) => {
                                    upgraded_iface = last_iface;
                                    if !unprocessed_bytes.is_empty() {
                                        eprintln!(
                                            "Unprocessed bytes: {}",
                                            String::from_utf8_lossy(&unprocessed_bytes)
                                        );
                                    }
                                    tracker.fill_buffer(&unprocessed_bytes);

                                    if let Err(err) = tracker.write(out.as_ref()) {
                                        eprintln!("write error: {}", err);
                                        for cause in Fail::iter_causes(&err) {
                                            eprintln!("  caused by: {}", cause);
                                        }
                                        let _ = tracker.shutdown();
                                        indices_to_remove.push(i);
                                        break;
                                    }
                                }
                                Err(e) => match e.kind() {
                                    err => {
                                        eprintln!("handler error: {}", err);
                                        for cause in Fail::iter_causes(&err).skip(1) {
                                            eprintln!("  caused by: {}", cause);
                                        }
                                        let _ = tracker.shutdown();
                                        indices_to_remove.push(i);
                                        break;
                                    }
                                },
                            }
                        }
                        Err(e) => match e.kind() {
                            io::ErrorKind::WouldBlock => {
                                break;
                            }
                            _ => {
                                let _ = tracker.shutdown();
                                indices_to_remove.push(i);
                                eprintln!("IO error: {}", e);
                                break;
                            }
                        },
                    }
                }
                if upgraded_iface.is_some() {
                    eprintln!("Upgraded MODE");
                    // upgraded mode... thread away the server
                    // feed it directly with the client stream
                    // If you have a better idea, open an Issue or PR on github
                    indices_to_remove.push(i);

                    let j = thread::spawn({
                        eprintln!("upgraded thread");
                        let handler = handler.clone();
                        let mut stream = tracker.stream.take().unwrap();
                        let mut buffer = tracker.buffer.take().unwrap();
                        move || {
                            let _r = stream.set_nonblocking(false);
                            let (reader, mut writer) = stream.split().unwrap();
                            let br = BufReader::new(reader);
                            let mut bufreader = Box::new(buffer.chain(br));
                            let mut upgraded_iface = upgraded_iface.take();
                            loop {
                                match handler.handle(&mut bufreader, &mut writer, upgraded_iface) {
                                    Ok((unread, iface)) => {
                                        upgraded_iface = iface;
                                        match bufreader.fill_buf() {
                                            Err(_) => {
                                                eprintln!("Upgraded end");
                                                break;
                                            }
                                            Ok(buf) if buf.is_empty() && unread.is_empty() => {
                                                eprintln!("Upgraded end");
                                                break;
                                            }
                                            _ => {
                                                if !unread.is_empty() {
                                                    eprintln!(
                                                        "Unhandled bytes: {}",
                                                        String::from_utf8_lossy(&unread)
                                                    );
                                                    break;
                                                }
                                            }
                                        }
                                    }
                                    Err(err) => match err.kind() {
                                        varlink::ErrorKind::ConnectionClosed => {
                                            eprintln!("Upgraded end");
                                            break;
                                        }
                                        _ => {
                                            eprintln!("Upgraded end: {}", err);
                                            for cause in Fail::iter_causes(&err).skip(1) {
                                                eprintln!("  caused by: {}", cause);
                                            }
                                            break;
                                        }
                                    },
                                }
                            }
                        }
                    });
                    threads.push(j);
                }
            }
        }

        // We can't modify the vector while we are traversing it, so update now.
        for i in indices_to_remove {
            fdmap.remove(&fds[i].fd);
            fds.remove(i);
        }

        let r = unsafe { libc::poll(fds.as_mut_ptr(), (fds.len() as u32).into(), timeout) };

        if r < 0 {
            return Err(Error::last_os_error().into());
        }

        if r == 0 && fds.len() == 1 {
            eprintln!("listen_multiplex: Waiting for threads to end.");
            for t in threads {
                let _r = t.join();
            }

            return Err(varlink::Error::from(varlink::ErrorKind::Timeout));
        }
    }
}

fn run_server(address: &str, timeout: u64, multiplex: bool) -> varlink::Result<()> {
    let myorgexampleping = MyOrgExamplePing;
    let myinterface = org_example_ping::new(Box::new(myorgexampleping));
    let service = VarlinkService::new(
        "org.varlink",
        "test ping service",
        "0.1",
        "http://varlink.org",
        vec![Box::new(myinterface)],
    );

    if multiplex {
        // Demonstrate a single process, single-threaded service
        listen_multiplex(service, &address, timeout)?;
    } else {
        varlink::listen(service, &address, 1, 10, timeout)?;
    }
    Ok(())
}
<commit_msg>examples/ping:listen_multiplex(): add counter for upgraded threads<commit_after>extern crate failure;
#[macro_use]
extern crate failure_derive;
extern crate getopts;
extern crate libc;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate varlink;

use failure::Fail;
use org_example_ping::*;
use std::collections::HashMap;
use std::env;
use std::io::{self, BufRead, BufReader, Error, Read, Write};
use std::process::exit;
use std::sync::{Arc, RwLock};
use std::thread;
use varlink::{Call, Connection, ConnectionHandler, Listener, ServerStream, VarlinkService};

// Dynamically build the varlink rust code.
mod org_example_ping;

#[cfg(test)]
mod test;

// Main

fn print_usage(program: &str, opts: &getopts::Options) {
    let brief = format!("Usage: {} [--varlink=<address>] [--client]", program);
    print!("{}", opts.usage(&brief));
}

fn main() {
    let args: Vec<_> = env::args().collect();
    let program = args[0].clone();

    let mut opts = getopts::Options::new();
    opts.optopt("", "varlink", "varlink address URL", "<address>");
    opts.optflag("", "client", "run in client mode");
    opts.optflag("m", "multiplex", "run in multiplex mode");
    opts.optflag("h", "help", "print this help menu");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => {
            eprintln!("{}", f.to_string());
            print_usage(&program, &opts);
            return;
        }
    };

    if matches.opt_present("h") {
        print_usage(&program, &opts);
        return;
    }

    let client_mode = matches.opt_present("client");

    let ret = if client_mode {
        let connection = match matches.opt_str("varlink") {
            None => Connection::with_activate(&format!("{} --varlink=$VARLINK_ADDRESS", program))
                .unwrap(),
            Some(address) => Connection::with_address(&address).unwrap(),
        };
        run_client(&connection)
    } else if let Some(address) = matches.opt_str("varlink") {
        run_server(&address, 0, matches.opt_present("m")).map_err(|e| e.into())
    } else {
        print_usage(&program, &opts);
        eprintln!("Need varlink address in server mode.");
        exit(1);
    };
    exit(match ret {
        Ok(_) => 0,
        Err(err) => {
            eprintln!("error: {:?}", err);
            1
        }
    });
}

// Client

fn run_client(connection: &Arc<RwLock<varlink::Connection>>) -> Result<()> {
    {
        let mut iface = VarlinkClient::new(connection.clone());
        let ping = String::from("Test");

        let reply = iface.ping(ping.clone()).call()?;
        assert_eq!(ping, reply.pong);
        println!("Pong: '{}'", reply.pong);

        let reply = iface.ping(ping.clone()).call()?;
        assert_eq!(ping, reply.pong);
        println!("Pong: '{}'", reply.pong);

        let reply = iface.ping(ping.clone()).call()?;
        assert_eq!(ping, reply.pong);
        println!("Pong: '{}'", reply.pong);

        let _reply = iface.upgrade().upgrade()?;
        println!("Client: upgrade()");
    }
    {
        // serve upgraded connection
        let mut conn = connection.write().unwrap();
        let mut writer = conn.writer.take().unwrap();
        writer.write_all(b"test test\nEnd\n")?;
        conn.writer = Some(writer);
        let mut buf = Vec::new();
        let mut reader = conn.reader.take().unwrap();
        if reader.read_until(b'\n', &mut buf)? == 0 {
            // incomplete data, in real life, store all bytes for the next call
            // for now just read the rest
            reader.read_to_end(&mut buf)?;
        };
        eprintln!("Client: upgraded got: {}", String::from_utf8_lossy(&buf));
        conn.reader = Some(reader);
    }
    Ok(())
}

// Server

struct MyOrgExamplePing;

impl org_example_ping::VarlinkInterface for MyOrgExamplePing {
    fn ping(&self, call: &mut Call_Ping, ping: String) -> varlink::Result<()> {
        call.reply(ping)
    }

    fn upgrade(&self, call: &mut Call_Upgrade) -> varlink::Result<()> {
        eprintln!("Server: called upgrade");
        call.to_upgraded();
        call.reply()
    }

    // An upgraded connection has its own application specific protocol.
    // Normally, there is no way back to the varlink protocol with this connection.
    fn call_upgraded(&self, call: &mut Call, bufreader: &mut BufRead) -> varlink::Result<Vec<u8>> {
        loop {
            let mut buf = String::new();
            let len = bufreader.read_line(&mut buf)?;
            if len == 0 {
                eprintln!("Server: upgraded got: none");
                // incomplete data, in real life, store all bytes for the next call
                // return Ok(buf.as_bytes().to_vec());
                return Err(varlink::ErrorKind::ConnectionClosed.into());
            }
            eprintln!("Server: upgraded got: {}", buf);

            call.writer.write_all(b"server reply: ")?;
            call.writer.write_all(buf.as_bytes())?;
            if buf.eq("End\n") {
                break;
            }
        }
        eprintln!("Server: upgraded ending");
        Ok(Vec::new())
    }
}

struct FdTracker {
    stream: Option<ServerStream>,
    buffer: Option<Vec<u8>>,
}

impl FdTracker {
    fn shutdown(&mut self) -> varlink::Result<()> {
        self.stream.as_mut().unwrap().shutdown()
    }
    fn chain_buffer(&mut self, buf: &mut Vec<u8>) {
        self.buffer.as_mut().unwrap().append(buf);
    }
    fn fill_buffer(&mut self, buf: &Vec<u8>) {
        self.buffer.as_mut().unwrap().clone_from(buf);
    }
    fn buf_as_slice(&mut self) -> &[u8] {
        self.buffer.as_mut().unwrap().as_slice()
    }
    fn write(&mut self, out: &[u8]) -> io::Result<usize> {
        self.stream.as_mut().unwrap().write(out)
    }
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.stream.as_mut().unwrap().read(buf)
    }
}

// listen_multiplex is just an example, if you don't want to use varlink::listen()
// and how to build your own main-loop and use the low-level varlink::handle() instead
pub fn listen_multiplex<S: ?Sized + AsRef<str>, H: ::ConnectionHandler + Send + Sync + 'static>(
    handler: H,
    address: &S,
    idle_timeout: u64,
) -> varlink::Result<()> {
    let timeout: i32 = match idle_timeout {
        0 => -1,
        n => (n * 1000) as i32,
    };

    let handler = Arc::new(handler);
    let mut fdmap: HashMap<i32, FdTracker> = HashMap::new();
    let mut fds = Vec::new();
    let mut threads = Vec::new();
    let listener = Listener::new(address)?;
    let upgraded_in_use = Arc::new(RwLock::new(0));

    listener.set_nonblocking(true)?;

    fds.push(libc::pollfd {
        fd: listener.as_raw_fd(),
        revents: 0,
        events: libc::POLLIN,
    });

    loop {
        // Read activity on listening socket
        if fds[0].revents != 0 {
            let mut client = listener.accept(0)?;

            client.set_nonblocking(true)?;

            let fd = client.as_raw_fd();
            fds.push(libc::pollfd {
                fd,
                revents: 0,
                events: libc::POLLIN,
            });

            fdmap.insert(
                fd,
                FdTracker {
                    stream: Some(client),
                    buffer: Some(Vec::new()),
                },
            );
        }

        // Store which indices to remove
        let mut indices_to_remove = vec![];

        // Check client connections ...
        for (i, fds_item) in fds.iter().enumerate().skip(1) {
            if fds_item.revents != 0 {
                let mut upgraded_iface: Option<String> = None;
                let mut tracker = fdmap.get_mut(&fds_item.fd).unwrap();
                loop {
                    let mut readbuf: [u8; 8192] = [0; 8192];

                    match tracker.read(&mut readbuf) {
                        Ok(0) => {
                            let _ = tracker.shutdown();
                            indices_to_remove.push(i);
                            break;
                        }
                        Ok(len) => {
                            let mut out: Vec<u8> = Vec::new();
                            tracker.chain_buffer(&mut readbuf[0..len].to_vec());
                            eprintln!(
                                "Handling: {}",
                                String::from_utf8_lossy(&tracker.buf_as_slice())
                            );

                            match handler.handle(&mut tracker.buf_as_slice(), &mut out, None) {
                                // TODO: buffer output and write only on POLLOUT
                                Ok((unprocessed_bytes, last_iface)) => {
                                    upgraded_iface = last_iface;
                                    if !unprocessed_bytes.is_empty() {
                                        eprintln!(
                                            "Unprocessed bytes: {}",
                                            String::from_utf8_lossy(&unprocessed_bytes)
                                        );
                                    }
                                    tracker.fill_buffer(&unprocessed_bytes);

                                    if let Err(err) = tracker.write(out.as_ref()) {
                                        eprintln!("write error: {}", err);
                                        for cause in Fail::iter_causes(&err) {
                                            eprintln!("  caused by: {}", cause);
                                        }
                                        let _ = tracker.shutdown();
                                        indices_to_remove.push(i);
                                        break;
                                    }
                                }
                                Err(e) => match e.kind() {
                                    err => {
                                        eprintln!("handler error: {}", err);
                                        for cause in Fail::iter_causes(&err).skip(1) {
                                            eprintln!("  caused by: {}", cause);
                                        }
                                        let _ = tracker.shutdown();
                                        indices_to_remove.push(i);
                                        break;
                                    }
                                },
                            }
                        }
                        Err(e) => match e.kind() {
                            io::ErrorKind::WouldBlock => {
                                break;
                            }
                            _ => {
                                let _ = tracker.shutdown();
                                indices_to_remove.push(i);
                                eprintln!("IO error: {}", e);
                                break;
                            }
                        },
                    }
                }
                if upgraded_iface.is_some() {
                    eprintln!("Upgraded MODE");
                    // upgraded mode... thread away the server
                    // feed it directly with the client stream
                    // If you have a better idea, open an Issue or PR on github
                    indices_to_remove.push(i);

                    let j = thread::spawn({
                        eprintln!("upgraded thread");
                        let handler = handler.clone();
                        let mut stream = tracker.stream.take().unwrap();
                        let mut buffer = tracker.buffer.take().unwrap();
                        let mut upgraded_in_use = upgraded_in_use.clone();
                        move || {
                            let _r = stream.set_nonblocking(false);
                            let (reader, mut writer) = stream.split().unwrap();
                            let br = BufReader::new(reader);
                            let mut bufreader = Box::new(buffer.chain(br));
                            let mut upgraded_iface = upgraded_iface.take();

                            {
                                let mut ctr = upgraded_in_use.write().unwrap();
                                *ctr += 1;
                            }
                            loop {
                                match handler.handle(&mut bufreader, &mut writer, upgraded_iface) {
                                    Ok((unread, iface)) => {
                                        upgraded_iface = iface;
                                        match bufreader.fill_buf() {
                                            Err(_) => {
                                                eprintln!("Upgraded end");
                                                break;
                                            }
                                            Ok(buf) if buf.is_empty() && unread.is_empty() => {
                                                eprintln!("Upgraded end");
                                                break;
                                            }
                                            _ => {
                                                if !unread.is_empty() {
                                                    eprintln!(
                                                        "Unhandled bytes: {}",
                                                        String::from_utf8_lossy(&unread)
                                                    );
                                                    break;
                                                }
                                            }
                                        }
                                    }
                                    Err(err) => match err.kind() {
                                        varlink::ErrorKind::ConnectionClosed => {
                                            eprintln!("Upgraded end");
                                            break;
                                        }
                                        _ => {
                                            eprintln!("Upgraded end: {}", err);
                                            for cause in Fail::iter_causes(&err).skip(1) {
                                                eprintln!("  caused by: {}", cause);
                                            }
                                            break;
                                        }
                                    },
                                }
                            }
                            {
                                let mut ctr = upgraded_in_use.write().unwrap();
                                *ctr -= 1;
                            }
                        }
                    });
                    threads.push(j);
                }
            }
        }

        // We can't modify the vector while we are traversing it, so update now.
        for i in indices_to_remove {
            fdmap.remove(&fds[i].fd);
            fds.remove(i);
        }

        let r = unsafe { libc::poll(fds.as_mut_ptr(), (fds.len() as u32).into(), timeout) };

        if r < 0 {
            for t in threads {
                let _r = t.join();
            }
            return Err(Error::last_os_error().into());
        }

        if r == 0 && fds.len() == 1 && *upgraded_in_use.read().unwrap() == 0 {
            eprintln!("listen_multiplex: Waiting for threads to end.");
            for t in threads {
                let _r = t.join();
            }

            return Err(varlink::Error::from(varlink::ErrorKind::Timeout));
        }
    }
}

fn run_server(address: &str, timeout: u64, multiplex: bool) -> varlink::Result<()> {
    let myorgexampleping = MyOrgExamplePing;
    let myinterface = org_example_ping::new(Box::new(myorgexampleping));
    let service = VarlinkService::new(
        "org.varlink",
        "test ping service",
        "0.1",
        "http://varlink.org",
        vec![Box::new(myinterface)],
    );

    if multiplex {
        // Demonstrate a single process, single-threaded service
        listen_multiplex(service, &address, timeout)?;
    } else {
        varlink::listen(service, &address, 1, 10, timeout)?;
    }
    Ok(())
}
<|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

#![deny(
    non_camel_case_types,
    non_snake_case,
    path_statements,
    trivial_numeric_casts,
    unstable_features,
    unused_allocation,
    unused_import_braces,
    unused_imports,
    unused_must_use,
    unused_mut,
    unused_qualifications,
    while_true,
)]

#[macro_use] extern crate log;
extern crate clap;
#[macro_use] extern crate semver;
extern crate toml;
extern crate url;
#[macro_use] extern crate version;

extern crate libimagentrylink;
extern crate libimagrt;
extern crate libimagstore;
extern crate libimagerror;
extern crate libimagutil;

use std::ops::Deref;

use libimagrt::runtime::Runtime;
use libimagrt::setup::generate_runtime_setup;
use libimagstore::error::StoreError;
use libimagstore::store::Entry;
use libimagstore::store::FileLockEntry;
use libimagstore::store::Store;
use libimagerror::trace::{MapErrTrace, trace_error, trace_error_exit};
use libimagentrylink::external::ExternalLinker;
use libimagutil::warn_result::*;
use libimagutil::warn_exit::warn_exit;
use libimagutil::info_result::*;
use clap::ArgMatches;
use url::Url;

mod ui;

use ui::build_ui;

fn main() {
    let rt = generate_runtime_setup("imag-link",
                                    &version!()[..],
                                    "Link entries",
                                    build_ui);

    rt.cli()
        .subcommand_name()
        .map(|name| {
            match name {
                "internal" => handle_internal_linking(&rt),
                "external" => handle_external_linking(&rt),
                _ => warn_exit("No commandline call", 1)
            }
        });
}

fn handle_internal_linking(rt: &Runtime) {
    use libimagentrylink::internal::InternalLinker;
    use libimagentrylink::external::is_external_link_storeid;

    debug!("Handle internal linking call");
    let cmd = rt.cli().subcommand_matches("internal").unwrap();

    match cmd.value_of("list") {
        Some(list) => {
            debug!("List...");
            for entry in list.split(',') {
                debug!("Listing for '{}'", entry);
                match get_entry_by_name(rt, entry) {
                    Ok(Some(e)) => {
                        e.get_internal_links()
                            .map(|iter| {
                                iter.filter(move |id| {
                                    cmd.is_present("list-externals-too") || !is_external_link_storeid(&id)
                                })
                            })
                            .map(|links| {
                                let i = links
                                    .filter_map(|l| {
                                        l.to_str()
                                            .map_warn_err(|e| format!("Failed to convert StoreId to string: {:?}", e))
                                            .ok()
                                    })
                                    .enumerate();

                                for (i, link) in i {
                                    println!("{: <3}: {}", i, link);
                                }
                            })
                            .map_err_trace()
                            .ok();
                    },

                    Ok(None) => {
                        warn!("Entry not found: {:?}", entry);
                        break;
                    }

                    Err(e) => {
                        trace_error(&e);
                        break;
                    },
                }
            }
            debug!("Listing ready!");
        },
        None => {
            let mut from = match get_from_entry(&rt) {
                None => warn_exit("No 'from' entry", 1),
                Some(s) => s,
            };
            debug!("Link from = {:?}", from.deref());

            let to = match get_to_entries(&rt) {
                None => warn_exit("No 'to' entry", 1),
                Some(to) => to,
            };
            debug!("Link to = {:?}", to.iter().map(|f| f.deref()).collect::<Vec<&Entry>>());

            match cmd.subcommand_name() {
                Some("add") => {
                    for mut to_entry in to {
                        if let Err(e) = to_entry.add_internal_link(&mut from) {
                            trace_error_exit(&e, 1);
                        }
                    }
                },

                Some("remove") => {
                    for mut to_entry in to {
                        if let Err(e) = to_entry.remove_internal_link(&mut from) {
                            trace_error_exit(&e, 1);
                        }
                    }
                },

                _ => unreachable!(),
            };
        }
    }
}

fn get_from_entry<'a>(rt: &'a Runtime) -> Option<FileLockEntry<'a>> {
    rt.cli()
        .subcommand_matches("internal")
        .unwrap() // safe, we know there is an "internal" subcommand"
        .subcommand_matches("add")
        .unwrap() // safe, we know there is an "add" subcommand
        .value_of("from")
        .and_then(|from_name| {
            match get_entry_by_name(rt, from_name) {
                Err(e) => {
                    debug!("We couldn't get the entry from name: '{:?}'", from_name);
                    trace_error(&e); None
                },
                Ok(Some(e)) => Some(e),
                Ok(None)    => None,
            }

        })
}

fn get_to_entries<'a>(rt: &'a Runtime) -> Option<Vec<FileLockEntry<'a>>> {
    rt.cli()
        .subcommand_matches("internal")
        .unwrap() // safe, we know there is an "internal" subcommand"
        .subcommand_matches("add")
        .unwrap() // safe, we know there is an "add" subcommand
        .values_of("to")
        .map(|values| {
            let mut v = vec![];
            for entry in values.map(|v| get_entry_by_name(rt, v)) {
                match entry {
                    Err(e) => trace_error(&e),
                    Ok(Some(e)) => v.push(e),
                    Ok(None) => warn!("Entry not found: {:?}", v),
                }
            }
            v
        })
}

fn get_entry_by_name<'a>(rt: &'a Runtime, name: &str) -> Result<Option<FileLockEntry<'a>>, StoreError> {
    use std::path::PathBuf;
    use libimagstore::storeid::StoreId;

    StoreId::new(Some(rt.store().path().clone()), PathBuf::from(name))
        .and_then(|id| rt.store().get(id))
}

fn handle_external_linking(rt: &Runtime) {
    let scmd       = rt.cli().subcommand_matches("external").unwrap();
    let entry_name = scmd.value_of("id").unwrap(); // enforced by clap
    let mut entry  = match get_entry_by_name(rt, entry_name) {
        Err(e) => trace_error_exit(&e, 1),
        Ok(None) => {
            warn!("Entry not found: {:?}", entry_name);
            return;
        },
        Ok(Some(entry)) => entry
    };

    if scmd.is_present("add") {
        debug!("Adding link to entry!");
        add_link_to_entry(rt.store(), scmd, &mut entry);
        return;
    }

    if scmd.is_present("remove") {
        debug!("Removing link from entry!");
        remove_link_from_entry(rt.store(), scmd, &mut entry);
        return;
    }

    if scmd.is_present("set") {
        debug!("Setting links in entry!");
        set_links_for_entry(rt.store(), scmd, &mut entry);
        return;
    }

    if scmd.is_present("list") {
        debug!("Listing links in entry!");
        list_links_for_entry(rt.store(), &mut entry);
        return;
    }

    panic!("Clap failed to enforce one of 'add', 'remove', 'set' or 'list'");
}

fn add_link_to_entry(store: &Store, matches: &ArgMatches, entry: &mut FileLockEntry) {
    Url::parse(matches.value_of("add").unwrap())
        .map_err_trace_exit(1)
        .map(|link| entry.add_external_link(store, link).map_err_trace().map_info_str("Ok"))
        .ok();
}

fn remove_link_from_entry(store: &Store, matches: &ArgMatches, entry: &mut FileLockEntry) {
    Url::parse(matches.value_of("remove").unwrap())
        .map_err_trace_exit(1)
        .map(|link| entry.remove_external_link(store, link).map_err_trace().map_info_str("Ok"))
        .ok();
}

fn set_links_for_entry(store: &Store, matches: &ArgMatches, entry: &mut FileLockEntry) {
    let links = matches
        .value_of("links")
        .map(String::from)
        .unwrap()
        .split(',')
        .map(|uri| {
            match Url::parse(uri) {
                Err(e) => {
                    warn!("Could not parse '{}' as URL, ignoring", uri);
                    trace_error(&e);
                    None
                },
                Ok(u) => Some(u),
            }
        })
        .filter_map(|x| x)
        .collect();

    entry.set_external_links(store, links)
        .map_err_trace()
        .map_info_str("Ok")
        .ok();
}

fn list_links_for_entry(store: &Store, entry: &mut FileLockEntry) {
    entry.get_external_links(store)
        .and_then(|links| {
            for (i, link) in links.enumerate() {
                match link {
                    Ok(link) => println!("{: <3}: {}", i, link),
                    Err(e)   => trace_error(&e),
                }
            }
            Ok(())
        })
        .map_err_trace()
        .map_info_str("Ok")
        .ok();
}

<commit_msg>imag-link: Remove macro_use which is not needed<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

#![deny(
    non_camel_case_types,
    non_snake_case,
    path_statements,
    trivial_numeric_casts,
    unstable_features,
    unused_allocation,
    unused_import_braces,
    unused_imports,
    unused_must_use,
    unused_mut,
    unused_qualifications,
    while_true,
)]

#[macro_use] extern crate log;
extern crate clap;
extern crate semver;
extern crate toml;
extern crate url;
#[macro_use] extern crate version;

extern crate libimagentrylink;
extern crate libimagrt;
extern crate libimagstore;
extern crate libimagerror;
extern crate libimagutil;

use std::ops::Deref;

use libimagrt::runtime::Runtime;
use libimagrt::setup::generate_runtime_setup;
use libimagstore::error::StoreError;
use libimagstore::store::Entry;
use libimagstore::store::FileLockEntry;
use libimagstore::store::Store;
use libimagerror::trace::{MapErrTrace, trace_error, trace_error_exit};
use libimagentrylink::external::ExternalLinker;
use libimagutil::warn_result::*;
use libimagutil::warn_exit::warn_exit;
use libimagutil::info_result::*;
use clap::ArgMatches;
use url::Url;

mod ui;

use ui::build_ui;

fn main() {
    let rt = generate_runtime_setup("imag-link",
                                    &version!()[..],
                                    "Link entries",
                                    build_ui);

    rt.cli()
        .subcommand_name()
        .map(|name| {
            match name {
                "internal" => handle_internal_linking(&rt),
                "external" => handle_external_linking(&rt),
                _ => warn_exit("No commandline call", 1)
            }
        });
}

fn handle_internal_linking(rt: &Runtime) {
    use libimagentrylink::internal::InternalLinker;
    use libimagentrylink::external::is_external_link_storeid;

    debug!("Handle internal linking call");
    let cmd = rt.cli().subcommand_matches("internal").unwrap();

    match cmd.value_of("list") {
        Some(list) => {
            debug!("List...");
            for entry in list.split(',') {
                debug!("Listing for '{}'", entry);
                match get_entry_by_name(rt, entry) {
                    Ok(Some(e)) => {
                        e.get_internal_links()
                            .map(|iter| {
                                iter.filter(move |id| {
                                    cmd.is_present("list-externals-too") || !is_external_link_storeid(&id)
                                })
                            })
                            .map(|links| {
                                let i = links
                                    .filter_map(|l| {
                                        l.to_str()
                                            .map_warn_err(|e| format!("Failed to convert StoreId to string: {:?}", e))
                                            .ok()
                                    })
                                    .enumerate();

                                for (i, link) in i {
                                    println!("{: <3}: {}", i, link);
                                }
                            })
                            .map_err_trace()
                            .ok();
                    },

                    Ok(None) => {
                        warn!("Entry not found: {:?}", entry);
                        break;
                    }

                    Err(e) => {
                        trace_error(&e);
                        break;
                    },
                }
            }
            debug!("Listing ready!");
        },
        None => {
            let mut from = match get_from_entry(&rt) {
                None => warn_exit("No 'from' entry", 1),
                Some(s) => s,
            };
            debug!("Link from = {:?}", from.deref());

            let to = match get_to_entries(&rt) {
                None => warn_exit("No 'to' entry", 1),
                Some(to) => to,
            };
            debug!("Link to = {:?}", to.iter().map(|f| f.deref()).collect::<Vec<&Entry>>());

            match cmd.subcommand_name() {
                Some("add") => {
                    for mut to_entry in to {
                        if let Err(e) = to_entry.add_internal_link(&mut from) {
                            trace_error_exit(&e, 1);
                        }
                    }
                },

                Some("remove") => {
                    for mut to_entry in to {
                        if let Err(e) = to_entry.remove_internal_link(&mut from) {
                            trace_error_exit(&e, 1);
                        }
                    }
                },

                _ => unreachable!(),
            };
        }
    }
}

fn get_from_entry<'a>(rt: &'a Runtime) -> Option<FileLockEntry<'a>> {
    rt.cli()
        .subcommand_matches("internal")
        .unwrap() // safe, we know there is an "internal" subcommand"
        .subcommand_matches("add")
        .unwrap() // safe, we know there is an "add" subcommand
        .value_of("from")
        .and_then(|from_name| {
            match get_entry_by_name(rt, from_name) {
                Err(e) => {
                    debug!("We couldn't get the entry from name: '{:?}'", from_name);
                    trace_error(&e); None
                },
                Ok(Some(e)) => Some(e),
                Ok(None)    => None,
            }

        })
}

fn get_to_entries<'a>(rt: &'a Runtime) -> Option<Vec<FileLockEntry<'a>>> {
    rt.cli()
        .subcommand_matches("internal")
        .unwrap() // safe, we know there is an "internal" subcommand"
        .subcommand_matches("add")
        .unwrap() // safe, we know there is an "add" subcommand
        .values_of("to")
        .map(|values| {
            let mut v = vec![];
            for entry in values.map(|v| get_entry_by_name(rt, v)) {
                match entry {
                    Err(e) => trace_error(&e),
                    Ok(Some(e)) => v.push(e),
                    Ok(None) => warn!("Entry not found: {:?}", v),
                }
            }
            v
        })
}

fn get_entry_by_name<'a>(rt: &'a Runtime, name: &str) -> Result<Option<FileLockEntry<'a>>, StoreError> {
    use std::path::PathBuf;
    use libimagstore::storeid::StoreId;

    StoreId::new(Some(rt.store().path().clone()), PathBuf::from(name))
        .and_then(|id| rt.store().get(id))
}

fn handle_external_linking(rt: &Runtime) {
    let scmd       = rt.cli().subcommand_matches("external").unwrap();
    let entry_name = scmd.value_of("id").unwrap(); // enforced by clap
    let mut entry  = match get_entry_by_name(rt, entry_name) {
        Err(e) => trace_error_exit(&e, 1),
        Ok(None) => {
            warn!("Entry not found: {:?}", entry_name);
            return;
        },
        Ok(Some(entry)) => entry
    };

    if scmd.is_present("add") {
        debug!("Adding link to entry!");
        add_link_to_entry(rt.store(), scmd, &mut entry);
        return;
    }

    if scmd.is_present("remove") {
        debug!("Removing link from entry!");
        remove_link_from_entry(rt.store(), scmd, &mut entry);
        return;
    }

    if scmd.is_present("set") {
        debug!("Setting links in entry!");
        set_links_for_entry(rt.store(), scmd, &mut entry);
        return;
    }

    if scmd.is_present("list") {
        debug!("Listing links in entry!");
        list_links_for_entry(rt.store(), &mut entry);
        return;
    }

    panic!("Clap failed to enforce one of 'add', 'remove', 'set' or 'list'");
}

fn add_link_to_entry(store: &Store, matches: &ArgMatches, entry: &mut FileLockEntry) {
    Url::parse(matches.value_of("add").unwrap())
        .map_err_trace_exit(1)
        .map(|link| entry.add_external_link(store, link).map_err_trace().map_info_str("Ok"))
        .ok();
}

fn remove_link_from_entry(store: &Store, matches: &ArgMatches, entry: &mut FileLockEntry) {
    Url::parse(matches.value_of("remove").unwrap())
        .map_err_trace_exit(1)
        .map(|link| entry.remove_external_link(store, link).map_err_trace().map_info_str("Ok"))
        .ok();
}

fn set_links_for_entry(store: &Store, matches: &ArgMatches, entry: &mut FileLockEntry) {
    let links = matches
        .value_of("links")
        .map(String::from)
        .unwrap()
        .split(',')
        .map(|uri| {
            match Url::parse(uri) {
                Err(e) => {
                    warn!("Could not parse '{}' as URL, ignoring", uri);
                    trace_error(&e);
                    None
                },
                Ok(u) => Some(u),
            }
        })
        .filter_map(|x| x)
        .collect();

    entry.set_external_links(store, links)
        .map_err_trace()
        .map_info_str("Ok")
        .ok();
}

fn list_links_for_entry(store: &Store, entry: &mut FileLockEntry) {
    entry.get_external_links(store)
        .and_then(|links| {
            for (i, link) in links.enumerate() {
                match link {
                    Ok(link) => println!("{: <3}: {}", i, link),
                    Err(e)   => trace_error(&e),
                }
            }
            Ok(())
        })
        .map_err_trace()
        .map_info_str("Ok")
        .ok();
}

<|endoftext|>


<commit_before><commit_msg>[mtl] disable use of buffer mutability<commit_after><|endoftext|>


<commit_before>// Copyright 2017 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Different assorted utilities.

use log::{LogRecord, LogLevel, SetLoggerError};
use env_logger::LogBuilder;
use colored::*;

use std::env;
use std::time::{SystemTime, UNIX_EPOCH};

use blockchain::{GenesisConfig, ValidatorKeys};
use node::NodeConfig;
use crypto::gen_keypair;

pub mod fabric;
pub mod config;

/// Performs the logger initialization.
pub fn init_logger() -> Result<(), SetLoggerError> {
    let mut builder = LogBuilder::new();
    builder.format(format_log_record);

    if env::var("RUST_LOG").is_ok() {
        builder.parse(&env::var("RUST_LOG").unwrap());
    }

    builder.init()
}

/// Generates testnet configuration.
pub fn generate_testnet_config(count: u8, start_port: u16) -> Vec<NodeConfig> {
    let (validators, services): (Vec<_>, Vec<_>) = (0..count as usize)
        .map(|_| (gen_keypair(), gen_keypair()))
        .unzip();
    let genesis = GenesisConfig::new(validators.iter().zip(services.iter()).map(|x| {
        ValidatorKeys {
            consensus_key: (x.0).0,
            service_key: (x.1).0,
        }
    }));
    let peers = (0..validators.len())
        .map(|x| {
            format!("127.0.0.1:{}", start_port + x as u16)
                .parse()
                .unwrap()
        })
        .collect::<Vec<_>>();

    validators
        .into_iter()
        .zip(services.into_iter())
        .enumerate()
        .map(|(idx, (validator, service))| {
            NodeConfig {
                listen_address: peers[idx],
                external_address: Some(peers[idx]),
                network: Default::default(),
                peers: peers.clone(),
                consensus_public_key: validator.0,
                consensus_secret_key: validator.1,
                service_public_key: service.0,
                service_secret_key: service.1,
                genesis: genesis.clone(),
                whitelist: Default::default(),
                api: Default::default(),
                mempool: Default::default(),
                services_configs: Default::default(),
            }
        })
        .collect::<Vec<_>>()
}

fn has_colors() -> bool {
    use term::terminfo::TerminfoTerminal;
    use term::Terminal;
    use std::io;

    let out = io::stderr();
    if let Some(term) = TerminfoTerminal::new(out) {
        term.supports_color()
    } else {
        false
    }
}

fn format_log_record(record: &LogRecord) -> String {
    let ts = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
    let secs = ts.as_secs().to_string();
    let millis = (ts.subsec_nanos() as u64 / 1000000).to_string();

    let module = record.location().module_path();
    let file = record.location().file();
    let line = record.location().line();

    let source_path;
    let verbose_src_path = match env::var("RUST_VERBOSE_PATH") {
        Ok(val) => val.parse::<bool>().unwrap_or(false),
        Err(_) => false,
    };
    if verbose_src_path {
        source_path = format!("{}:{}:{}", module, file, line);
    } else {
        source_path = module.to_string();
    }

    if has_colors() {
        let level = match record.level() {
            LogLevel::Error => "ERROR".red(),
            LogLevel::Warn => "WARN".yellow(),
            LogLevel::Info => "INFO".green(),
            LogLevel::Debug => "DEBUG".cyan(),
            LogLevel::Trace => "TRACE".white(),
        };
        format!(
            "[{} : {}] - [ {} ] - {} - {}",
            secs.bold(),
            millis.bold(),
            level,
            &source_path,
            record.args()
        )
    } else {
        let level = match record.level() {
            LogLevel::Error => "ERROR",
            LogLevel::Warn => "WARN",
            LogLevel::Info => "INFO",
            LogLevel::Debug => "DEBUG",
            LogLevel::Trace => "TRACE",
        };
        format!(
            "[{} : {}] - [ {} ] - {} - {}",
            secs,
            millis,
            level,
            &source_path,
            record.args()
        )
    }
}
<commit_msg>Set fixed width for value of milliseconds in a log entity<commit_after>// Copyright 2017 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Different assorted utilities.

use log::{LogRecord, LogLevel, SetLoggerError};
use env_logger::LogBuilder;
use colored::*;

use std::env;
use std::time::{SystemTime, UNIX_EPOCH};

use blockchain::{GenesisConfig, ValidatorKeys};
use node::NodeConfig;
use crypto::gen_keypair;

pub mod fabric;
pub mod config;

/// Performs the logger initialization.
pub fn init_logger() -> Result<(), SetLoggerError> {
    let mut builder = LogBuilder::new();
    builder.format(format_log_record);

    if env::var("RUST_LOG").is_ok() {
        builder.parse(&env::var("RUST_LOG").unwrap());
    }

    builder.init()
}

/// Generates testnet configuration.
pub fn generate_testnet_config(count: u8, start_port: u16) -> Vec<NodeConfig> {
    let (validators, services): (Vec<_>, Vec<_>) = (0..count as usize)
        .map(|_| (gen_keypair(), gen_keypair()))
        .unzip();
    let genesis = GenesisConfig::new(validators.iter().zip(services.iter()).map(|x| {
        ValidatorKeys {
            consensus_key: (x.0).0,
            service_key: (x.1).0,
        }
    }));
    let peers = (0..validators.len())
        .map(|x| {
            format!("127.0.0.1:{}", start_port + x as u16)
                .parse()
                .unwrap()
        })
        .collect::<Vec<_>>();

    validators
        .into_iter()
        .zip(services.into_iter())
        .enumerate()
        .map(|(idx, (validator, service))| {
            NodeConfig {
                listen_address: peers[idx],
                external_address: Some(peers[idx]),
                network: Default::default(),
                peers: peers.clone(),
                consensus_public_key: validator.0,
                consensus_secret_key: validator.1,
                service_public_key: service.0,
                service_secret_key: service.1,
                genesis: genesis.clone(),
                whitelist: Default::default(),
                api: Default::default(),
                mempool: Default::default(),
                services_configs: Default::default(),
            }
        })
        .collect::<Vec<_>>()
}

fn has_colors() -> bool {
    use term::terminfo::TerminfoTerminal;
    use term::Terminal;
    use std::io;

    let out = io::stderr();
    if let Some(term) = TerminfoTerminal::new(out) {
        term.supports_color()
    } else {
        false
    }
}

fn format_log_record(record: &LogRecord) -> String {
    let ts = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
    let secs = ts.as_secs().to_string();
    let millis = (ts.subsec_nanos() as u64 / 1000000).to_string();

    let module = record.location().module_path();
    let file = record.location().file();
    let line = record.location().line();

    let source_path;
    let verbose_src_path = match env::var("RUST_VERBOSE_PATH") {
        Ok(val) => val.parse::<bool>().unwrap_or(false),
        Err(_) => false,
    };
    if verbose_src_path {
        source_path = format!("{}:{}:{}", module, file, line);
    } else {
        source_path = module.to_string();
    }

    if has_colors() {
        let level = match record.level() {
            LogLevel::Error => "ERROR".red(),
            LogLevel::Warn => "WARN".yellow(),
            LogLevel::Info => "INFO".green(),
            LogLevel::Debug => "DEBUG".cyan(),
            LogLevel::Trace => "TRACE".white(),
        };
        format!(
            "[{} : {:03}] - [ {} ] - {} - {}",
            secs.bold(),
            millis.bold(),
            level,
            &source_path,
            record.args()
        )
    } else {
        let level = match record.level() {
            LogLevel::Error => "ERROR",
            LogLevel::Warn => "WARN",
            LogLevel::Info => "INFO",
            LogLevel::Debug => "DEBUG",
            LogLevel::Trace => "TRACE",
        };
        format!(
            "[{} : {:03}] - [ {} ] - {} - {}",
            secs,
            millis,
            level,
            &source_path,
            record.args()
        )
    }
}
<|endoftext|>


<commit_before><commit_msg>Added notes<commit_after><|endoftext|>


<commit_before><commit_msg>fix number not recognizing floats<commit_after><|endoftext|>