<commit_before>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015-2016 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! # SOS kernel
//! This crate contains the kernel for SOS, the Stupid Operating System.
//!
//! # SOS: the Stupid Operating System
//! SOS is a simple, tiny toy OS implemented in Rust. It targets the x86,
//! x86_64, and ARM v7 CPU architectures.
//!
//! I'm writing this mostly for fun, to learn more about OS design and kernel
//! hacking, so don't expect anything new or exciting out of this project.
//!
//! SOS is copyright 2015-2016 Hawk Weisman, and is released under the terms
//! of the MIT license.

// #![crate_name = "sos_kernel"]
// #![crate_type = "staticlib"]

#![doc(html_root_url = "https://hawkw.github.io/sos-kernel/")]

#![feature(core_intrinsics)]
#![feature( lang_items, asm, naked_functions )]
#![feature( const_fn
          , slice_patterns
          , associated_consts
          , unique
          , type_ascription
          , custom_derive )]
#![feature(collections)]
#![feature(question_mark)]

#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]

#![no_std]
#![cfg_attr(not(test), no_main)]

// -- non-SOS dependencies --------------------------------------------------
extern crate collections;
extern crate rlibc;
extern crate spin;

#[macro_use] extern crate lazy_static;
#[macro_use] extern crate bitflags;
#[macro_use] extern crate custom_derive;

// -- SOS dependencies ------------------------------------------------------
extern crate sos_alloc as alloc;

#[macro_use] extern crate sos_vga as vga;

#[macro_use] pub mod macros;
#[macro_use] pub mod memory;
#[macro_use] pub mod io;

pub mod util;
pub mod multiboot2;
pub mod elf;
pub mod arch;

// Since the test module contains lang items, it can't be compiled when
// running tests.
#[cfg(not(test))] pub mod panic;

use arch::cpu;
use memory::PAddr;

#[macro_use]
macro_rules! init_log {
    (f$dots:expr, $task:expr, $msg:expr) => (
        println!( "{task:<40}{res:>38}\n{msg:>.width$}"
                , task = format!("{:>.width$}", $task, width = $dots)
                , res = "[ FAIL ]"
                , msg = $msg
                , width = $dots + 1
                )
    );
    (fail: $dots:expr, $task:expr) => (
            println!( "{task:<40}{res:>38}"
                    , task = format!("{:>.width$}", $task, width = $dots)
                    , res = "[ FAIL ]"
                    )
    );
    (okay: $dots:expr, $task:expr, $msg:expr) => (
        println!( "{task:<40}{res:>38}\n{msg:>.width$}"
                , task = format!("{:>.width$}", $task, width = $dots)
                , res = "[ OKAY ]"
                , msg = $msg
                , width = $dots + 1
                )
    );
    (okay: $dots:expr, $task:expr) => (
            println!( "{task:<40}{res:>38}"
                    , task = format!("{:>.width$}", $task, width = $dots)
                    , res = "[ OKAY ]"
                    )
    );
}

macro_rules! init_try {
    ($dots:expr, $task:expr, $result:expr) => (
        match $result {
            Ok(value) => {
                println!( "{task:<40}{res:>38}"
                        , task = format!("{:>.width$}", $task, width = $dots)
                        , res = "[ OKAY ]"
                        );
                value
            }
          , Err(why) => {
                println!( "{task:<40}{res:>38}\n\n{msg:>.width$}"
                        , task = format!("{:>.width$}", $task, width = $dots)
                        , res = "[ FAIL ]"
                        , msg = why
                        , width = $dots + 1
                        );
                return $expr
            }
        }
    )
}

/// Kernel main loop
pub fn kernel_main() {
    let mut a_vec = collections::vec::Vec::<usize>::new();
    println!( "TEST: Created a vector in kernel space! {:?}", a_vec);
    a_vec.push(1);
    println!( "TEST: pushed to vec: {:?}", a_vec);
    a_vec.push(2);
    println!( "TEST: pushed to vec: {:?}", a_vec);
    // loop {
    //     unsafe { asm!("int $0" :: "N" (0x80)) };
    //     println!("Test interrupt okay");
    // }
    loop { }
}

/// Kernel initialization function called from ASM
///
/// The kernel main loop expects to be passed the address of a valid
/// Multiboot 2 info struct. It's the bootloader's responsibility to ensure
/// that this is passed in the correct register as expected by the calling
/// convention (`edi` on x86). If this isn't there, you can expect to have a
/// bad problem and not go to space today.
//  TODO: since multiboot2 is x86-specific, this needs to move to `arch`.
//  we then want the kernel entry point to be `arch_init`. we can then
//  call into `kernel_init`.
#[no_mangle]
pub extern "C" fn kernel_start(multiboot_addr: PAddr) {
    io::term::CONSOLE.lock().clear();

    println!("Hello from the kernel!");

    // -- jump to architecture-specific init ---------------------------------
    arch::arch_init(multiboot_addr);

    // -- initialize interrupts ----------------------------------------------
    unsafe {
        println!(" . Enabling interrupts:");
        cpu::interrupts::initialize();
        println!("{:<38}{:>40}", " . Enabling interrupts", "[ OKAY ]");
    };

    // -- initialize the heap ------------------------------------------------
    unsafe {
        println!( "{:<38}{:>40}\n \
                    . . Heap begins at {:#x} and ends at {:#x}"
                , " . Intializing heap"
                , memory::init_heap().unwrap_or("[ FAIL ]")
                , memory::HEAP_BASE
                , memory::HEAP_TOP);
    };
    // -- call into kernel main loop ------------------------------------------
    // (currently, this does nothing)
    kernel_main()
}

/// This fake `main` function exists only to placate `cargo test`.
#[cfg(test)]
fn main() {

}
<commit_msg>[kernel] fist pass on recording kernel versions<commit_after>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015-2016 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! # SOS kernel
//! This crate contains the kernel for SOS, the Stupid Operating System.
//!
//! # SOS: the Stupid Operating System
//! SOS is a simple, tiny toy OS implemented in Rust. It targets the x86,
//! x86_64, and ARM v7 CPU architectures.
//!
//! I'm writing this mostly for fun, to learn more about OS design and kernel
//! hacking, so don't expect anything new or exciting out of this project.
//!
//! SOS is copyright 2015-2016 Hawk Weisman, and is released under the terms
//! of the MIT license.

// #![crate_name = "sos_kernel"]
// #![crate_type = "staticlib"]

#![doc(html_root_url = "https://hawkw.github.io/sos-kernel/")]

#![feature(core_intrinsics)]
#![feature( lang_items, asm, naked_functions )]
#![feature( const_fn
          , slice_patterns
          , associated_consts
          , unique
          , type_ascription
          , custom_derive )]
#![feature(collections)]
#![feature(question_mark)]

#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]

#![no_std]
#![cfg_attr(not(test), no_main)]

// -- non-SOS dependencies --------------------------------------------------
extern crate collections;
extern crate rlibc;
extern crate spin;

#[macro_use] extern crate lazy_static;
#[macro_use] extern crate bitflags;
#[macro_use] extern crate custom_derive;

// -- SOS dependencies ------------------------------------------------------
extern crate sos_alloc as alloc;

#[macro_use] extern crate sos_vga as vga;

#[macro_use] pub mod macros;
#[macro_use] pub mod memory;
#[macro_use] pub mod io;

pub mod util;
pub mod multiboot2;
pub mod elf;
pub mod arch;

/// SOS version number
pub const VERSION_STRING: &'static str
    = concat!("Stupid Operating System v", env!("CARGO_PKG_VERSION"));

// pub const BUILD_STRING: &'static str
//     = concat!("Built with ", env!("RUST_VERSION"));
//
// Since the test module contains lang items, it can't be compiled when
// running tests.
#[cfg(not(test))] pub mod panic;

use arch::cpu;
use memory::PAddr;

#[macro_use]
macro_rules! init_log {
    (f$dots:expr, $task:expr, $msg:expr) => (
        println!( "{task:<40}{res:>38}\n{msg:>.width$}"
                , task = format!("{:>.width$}", $task, width = $dots)
                , res = "[ FAIL ]"
                , msg = $msg
                , width = $dots + 1
                )
    );
    (fail: $dots:expr, $task:expr) => (
            println!( "{task:<40}{res:>38}"
                    , task = format!("{:>.width$}", $task, width = $dots)
                    , res = "[ FAIL ]"
                    )
    );
    (okay: $dots:expr, $task:expr, $msg:expr) => (
        println!( "{task:<40}{res:>38}\n{msg:>.width$}"
                , task = format!("{:>.width$}", $task, width = $dots)
                , res = "[ OKAY ]"
                , msg = $msg
                , width = $dots + 1
                )
    );
    (okay: $dots:expr, $task:expr) => (
            println!( "{task:<40}{res:>38}"
                    , task = format!("{:>.width$}", $task, width = $dots)
                    , res = "[ OKAY ]"
                    )
    );
}

macro_rules! init_try {
    ($dots:expr, $task:expr, $result:expr) => (
        match $result {
            Ok(value) => {
                println!( "{task:<40}{res:>38}"
                        , task = format!("{:>.width$}", $task, width = $dots)
                        , res = "[ OKAY ]"
                        );
                value
            }
          , Err(why) => {
                println!( "{task:<40}{res:>38}\n\n{msg:>.width$}"
                        , task = format!("{:>.width$}", $task, width = $dots)
                        , res = "[ FAIL ]"
                        , msg = why
                        , width = $dots + 1
                        );
                return $expr
            }
        }
    )
}

/// Kernel main loop
pub fn kernel_main() {
    let mut a_vec = collections::vec::Vec::<usize>::new();
    println!( "TEST: Created a vector in kernel space! {:?}", a_vec);
    a_vec.push(1);
    println!( "TEST: pushed to vec: {:?}", a_vec);
    a_vec.push(2);
    println!( "TEST: pushed to vec: {:?}", a_vec);
    // loop {
    //     unsafe { asm!("int $0" :: "N" (0x80)) };
    //     println!("Test interrupt okay");
    // }
    loop { }
}

/// Kernel initialization function called from ASM
///
/// The kernel main loop expects to be passed the address of a valid
/// Multiboot 2 info struct. It's the bootloader's responsibility to ensure
/// that this is passed in the correct register as expected by the calling
/// convention (`edi` on x86). If this isn't there, you can expect to have a
/// bad problem and not go to space today.
//  TODO: since multiboot2 is x86-specific, this needs to move to `arch`.
//  we then want the kernel entry point to be `arch_init`. we can then
//  call into `kernel_init`.
#[no_mangle]
pub extern "C" fn kernel_start(multiboot_addr: PAddr) {
    io::term::CONSOLE.lock().clear();

    println!("Hello from the kernel!");

    // -- jump to architecture-specific init ---------------------------------
    arch::arch_init(multiboot_addr);

    // -- initialize interrupts ----------------------------------------------
    unsafe {
        println!(" . Enabling interrupts:");
        cpu::interrupts::initialize();
        println!("{:<38}{:>40}", " . Enabling interrupts", "[ OKAY ]");
    };

    // -- initialize the heap ------------------------------------------------
    unsafe {
        println!( "{:<38}{:>40}\n \
                    . . Heap begins at {:#x} and ends at {:#x}"
                , " . Intializing heap"
                , memory::init_heap().unwrap_or("[ FAIL ]")
                , memory::HEAP_BASE
                , memory::HEAP_TOP);
    };

    println!("\n{} {}-bit\n", VERSION_STRING, arch::ARCH_BITS);
    // -- call into kernel main loop ------------------------------------------
    // (currently, this does nothing)
    kernel_main()

}

/// This fake `main` function exists only to placate `cargo test`.
#[cfg(test)]
fn main() {

}
<|endoftext|>


<commit_before>#![feature(advanced_slice_patterns, slice_patterns)]

extern crate git_together;

use std::env;
use std::process::Command;

use git_together::GitTogether;
use git_together::errors::*;

fn main() {
  run(|| {
    let all_args: Vec<_> = env::args().skip(1).collect();
    let args: Vec<&str> = all_args.iter().map(String::as_ref).collect();

    match *args.as_slice() {
      ["with"] => {
        println!("{} {}",
                 option_env!("CARGO_PKG_NAME").unwrap_or("git-together"),
                 option_env!("CARGO_PKG_VERSION").unwrap_or("unknown version"));

        let mut gt = GitTogether::new()?;

        let _ = gt.set_active(&[]);
        let authors = gt.all_authors()?;
        let mut sorted: Vec<_> = authors.iter().collect();
        sorted.sort_by(|a, b| a.0.cmp(b.0));

        for (initials, author) in sorted {
          println!("{}: {}", initials, author);
        }
      }
      ["with", ref inits..] => {
        let mut gt = GitTogether::new()?;

        let authors = gt.set_active(inits)?;
        for author in authors {
          println!("{}", author);
        }
      }
      [sub_cmd, ref rest..] if ["commit", "merge", "revert"]
        .contains(&sub_cmd) => {
        let mut gt = GitTogether::new()?;

        if sub_cmd == "merge" {
          env::set_var("GIT_TOGETHER_NO_SIGNOFF", "1");
        }

        let mut cmd = Command::new("git");
        let cmd = cmd.arg(sub_cmd).args(rest);

        let signoff = gt.signoff(cmd)?;
        let status = signoff.status()
          .chain_err(|| "failed to execute process")?;
        if status.success() {
          gt.rotate_active()?;
        }
      }
      [ref args..] => {
        Command::new("git").args(args)
          .status()
          .chain_err(|| "failed to execute process")?;
      }
    };

    Ok(())
  })
}

fn run<F>(f: F)
  where F: Fn() -> Result<()>
{
  if let Err(e) = f() {
    println!("error: {}", e);

    for e in e.iter().skip(1) {
      println!("caused by: {}", e);
    }

    if let Some(backtrace) = e.backtrace() {
      println!("backtrace: {:?}", backtrace);
    }

    std::process::exit(1);
  }
}
<commit_msg>rustfmt main.rs<commit_after>#![feature(advanced_slice_patterns, slice_patterns)]

extern crate git_together;

use std::env;
use std::process::Command;

use git_together::GitTogether;
use git_together::errors::*;

fn main() {
    run(|| {
        let all_args: Vec<_> = env::args().skip(1).collect();
        let args: Vec<&str> = all_args.iter().map(String::as_ref).collect();

        match *args.as_slice() {
            ["with"] => {
                println!("{} {}",
                         option_env!("CARGO_PKG_NAME")
                             .unwrap_or("git-together"),
                         option_env!("CARGO_PKG_VERSION")
                             .unwrap_or("unknown version"));

                let mut gt = GitTogether::new()?;

                let _ = gt.set_active(&[]);
                let authors = gt.all_authors()?;
                let mut sorted: Vec<_> = authors.iter().collect();
                sorted.sort_by(|a, b| a.0.cmp(b.0));

                for (initials, author) in sorted {
                    println!("{}: {}", initials, author);
                }
            }
            ["with", ref inits..] => {
                let mut gt = GitTogether::new()?;

                let authors = gt.set_active(inits)?;
                for author in authors {
                    println!("{}", author);
                }
            }
            [sub_cmd, ref rest..] if ["commit", "merge", "revert"]
                .contains(&sub_cmd) => {
                let mut gt = GitTogether::new()?;

                if sub_cmd == "merge" {
                    env::set_var("GIT_TOGETHER_NO_SIGNOFF", "1");
                }

                let mut cmd = Command::new("git");
                let cmd = cmd.arg(sub_cmd).args(rest);

                let signoff = gt.signoff(cmd)?;
                let status = signoff.status()
                    .chain_err(|| "failed to execute process")?;
                if status.success() {
                    gt.rotate_active()?;
                }
            }
            [ref args..] => {
                Command::new("git").args(args)
                    .status()
                    .chain_err(|| "failed to execute process")?;
            }
        };

        Ok(())
    })
}

fn run<F>(f: F)
    where F: Fn() -> Result<()>
{
    if let Err(e) = f() {
        println!("error: {}", e);

        for e in e.iter().skip(1) {
            println!("caused by: {}", e);
        }

        if let Some(backtrace) = e.backtrace() {
            println!("backtrace: {:?}", backtrace);
        }

        std::process::exit(1);
    }
}
<|endoftext|>


<commit_before>use pyembed::{ExtensionModule, MainPythonInterpreter};
use std::path::PathBuf;
use structopt::{clap::AppSettings::*, StructOpt};

include!(env!("PYOXIDIZER_DEFAULT_PYTHON_CONFIG_RS"));

#[derive(Debug, StructOpt)]
enum IOSCommands {
    Init,
    Ids,
}

#[derive(Debug, StructOpt)]
enum BuildCommands {
    #[structopt(about = "Demonstration SVG output for debugging")]
    Svg {
        #[structopt(flatten)]
        in_out: InOutPaths,
    },

    #[structopt(about = "Generates an .apk for Android")]
    Android {
        #[structopt(long = "kbd-repo", default_value = "divvun/giellakbd-android")]
        kbd_repo: String,

        #[structopt(long = "kbd-branch", default_value = "develop")]
        kbd_branch: String,

        #[structopt(long = "divvunspell-repo", default_value = "divvun/divvunspell")]
        divvunspell_repo: String,

        #[structopt(long = "divvunspell-branch", default_value = "develop")]
        divvunspell_branch: String,

        #[structopt(flatten)]
        in_out: InOutPaths,

        #[structopt(short = "D", long = "dry-run")]
        dry_run: bool,

        #[structopt(flatten)]
        build_mode: BuildMode,
    },

    #[cfg(target_os = "macos")]
    #[structopt(about = "Generates an .ipa for iOS")]
    IOS {
        #[structopt(subcommand)]
        command: Option<IOSCommands>,

        #[structopt(long = "kbd-repo", default_value = "divvun/giellakbd-ios")]
        kbd_repo: String,

        #[structopt(long = "kbd-branch", default_value = "develop")]
        kbd_branch: String,

        #[structopt(flatten)]
        in_out: InOutPaths,

        #[structopt(short = "D", long = "dry-run")]
        dry_run: bool,

        #[structopt(flatten)]
        build_mode: BuildMode,
    },

    #[structopt(about = "Generates installers for Windows 7/8 and 8.1+")]
    Win {
        #[structopt(flatten)]
        in_out: InOutPaths,

        #[structopt(short = "D", long = "dry-run")]
        dry_run: bool,

        #[structopt(flatten)]
        build_mode: BuildMode,
    },

    #[cfg(target_os = "macos")]
    #[structopt(about = "Generates installers for macOS")]
    Mac {
        #[structopt(flatten)]
        in_out: InOutPaths,

        #[structopt(short = "D", long = "dry-run")]
        dry_run: bool,

        #[structopt(flatten)]
        build_mode: BuildMode,
    },

    #[structopt(about = "Generates X11 output suitable for upstreaming")]
    X11 {
        #[structopt(flatten)]
        in_out: InOutPaths,

        #[structopt(flatten)]
        build_mode: BuildMode,
    },
    X11RS {
        #[structopt(flatten)]
        in_out: InOutPaths,

        #[structopt(flatten)]
        build_mode: BuildMode,

        #[structopt(long = "standalone")]
        standalone: bool,
    },

    #[structopt(about = "Generates m17n output")]
    M17n {
        #[structopt(flatten)]
        in_out: InOutPaths,

        #[structopt(flatten)]
        build_mode: BuildMode,
    },

    #[structopt(about = "Generates Chrome OS bundles for putting on the Chrome App Store")]
    Chrome {
        #[structopt(flatten)]
        in_out: InOutPaths,

        #[structopt(flatten)]
        build_mode: BuildMode,
    },

    #[structopt(setting(Hidden))]
    Qr {
        #[structopt(flatten)]
        in_out: InOutPaths,

        #[structopt(short, long = "layout")]
        layout: String,
    },

    #[structopt(setting(Hidden))]
    ErrorModel {
        #[structopt(flatten)]
        in_out: InOutPaths,

        #[structopt(short, long = "layout")]
        layout: String,
    },
}

#[derive(Debug, StructOpt)]
struct InOutPaths {
    #[structopt(short, long = "output", default_value = ".", parse(from_os_str))]
    output_path: PathBuf,

    #[structopt(parse(from_os_str))]
    project_path: PathBuf,
}

#[derive(Debug, StructOpt)]
struct BuildMode {
    /// Compile in 'release' mode (where necessary).
    #[structopt(short = "R", long = "release")]
    release: bool,

    /// Continuous integration build
    #[structopt(long = "ci")]
    ci: bool,
}

#[derive(Debug, StructOpt)]
enum NewCommands {
    Layout {
        #[structopt(short, long = "output", default_value = ".", parse(from_os_str))]
        output_path: PathBuf,

        #[structopt(parse(from_os_str))]
        project_path: PathBuf,
    },
    Bundle {
        #[structopt(short, long = "output", default_value = ".", parse(from_os_str))]
        output_path: PathBuf,

        bundle_name: String,
    },
}

#[derive(Debug, StructOpt)]
enum Commands {
    #[structopt(
        about = "Generate output for a given .kbdgen bundle",
        setting(DisableHelpSubcommand)
    )]
    Build {
        #[structopt(long = "github-username")]
        github_username: Option<String>,

        #[structopt(long = "github-token")]
        github_token: Option<String>,

        #[structopt(subcommand)]
        command: BuildCommands,
    },
    #[structopt(
        about = "Generate new bundles or layout templates",
        setting(DisableHelpSubcommand)
    )]
    New {
        #[structopt(subcommand)]
        command: NewCommands,
    },
}

#[derive(Debug, StructOpt)]
#[structopt(
    name = "kbdgen",
    about = "The best solution to generating keyboards.",
    setting(DisableHelpSubcommand)
)]
struct Opts {
    #[structopt(long = "logging", default_value = "info")]
    logging: String,

    #[structopt(subcommand)]
    command: Commands,
}

impl BuildCommands {
    fn to_py_args<'a>(
        &'a self,
        github_username: Option<&'a str>,
        github_token: Option<&'a str>,
        logging: &'a str,
    ) -> Result<Vec<&'a str>, Box<dyn std::error::Error>> {
        use BuildCommands::*;

        let mut args = match self {
            Svg {
                in_out:
                    InOutPaths {
                        output_path,
                        project_path,
                    },
            } => vec![
                "-t",
                "svg",
                "-o",
                &*output_path.to_str().unwrap(),
                &*project_path.to_str().unwrap(),
            ],
            Android {
                kbd_repo,
                kbd_branch,
                divvunspell_repo,
                divvunspell_branch,
                in_out:
                    InOutPaths {
                        output_path,
                        project_path,
                    },
                dry_run,
                build_mode: BuildMode { release, ci },
            } => {
                let mut args = vec![
                    "-t",
                    "android",
                    "--kbd-repo",
                    kbd_repo,
                    "--kbd-branch",
                    kbd_branch,
                    "--divvunspell-repo",
                    divvunspell_repo,
                    "--divvunspell-branch",
                    divvunspell_branch,
                    "-o",
                    &*output_path.to_str().unwrap(),
                ];

                if *release {
                    args.push("-R");
                }

                if *dry_run {
                    args.push("-D");
                }

                if *ci {
                    args.push("--ci");
                }

                args.push(&*project_path.to_str().unwrap());

                args
            }
            #[cfg(target_os = "macos")]
            IOS {
                command,
                kbd_repo,
                kbd_branch,
                in_out:
                    InOutPaths {
                        output_path,
                        project_path,
                    },
                dry_run,
                build_mode: BuildMode { release, ci },
            } => {
                let mut args = vec![
                    "-t",
                    "ios",
                    "--kbd-repo",
                    kbd_repo,
                    "--kbd-branch",
                    kbd_branch,
                    "-o",
                    &*output_path.to_str().unwrap(),
                ];

                if *release {
                    args.push("-R");
                }

                if *dry_run {
                    args.push("-D");
                }

                if *ci {
                    args.push("--ci");
                }

                match command {
                    Some(IOSCommands::Init) => {
                        args.push("--command");
                        args.push("init");
                    }
                    Some(IOSCommands::Ids) => {
                        args.push("--command");
                        args.push("ids");
                    }
                    _ => {}
                }

                args.push(&*project_path.to_str().unwrap());
                args
            }
            Chrome {
                in_out:
                    InOutPaths {
                        output_path,
                        project_path,
                    },
                build_mode: BuildMode { release, ci },
            } => {
                let mut args = vec!["-t", "chrome", "-o", &*output_path.to_str().unwrap()];

                if *release {
                    args.push("-R");
                }

                if *ci {
                    args.push("--ci");
                }

                args.push(&*project_path.to_str().unwrap());
                args
            }
            Win {
                in_out:
                    InOutPaths {
                        output_path,
                        project_path,
                    },
                dry_run,
                build_mode: BuildMode { release, ci },
            } => {
                let mut args = vec!["-t", "win", "-o", &*output_path.to_str().unwrap()];

                if *release {
                    args.push("-R");
                }

                if *dry_run {
                    args.push("-D");
                }

                if *ci {
                    args.push("--ci");
                }

                args.push(&*project_path.to_str().unwrap());
                args
            }
            #[cfg(target_os = "macos")]
            Mac {
                in_out:
                    InOutPaths {
                        output_path,
                        project_path,
                    },
                dry_run,
                build_mode: BuildMode { release, ci },
            } => {
                let mut args = vec!["-t", "mac", "-o", &*output_path.to_str().unwrap()];

                if *release {
                    args.push("-R");
                }

                if *dry_run {
                    args.push("-D");
                }

                if *ci {
                    args.push("--ci");
                }

                args.push(&*project_path.to_str().unwrap());
                args
            }
            M17n { .. } => return Err(From::from("M17n isn't supported in Python".to_string())),
            X11 { .. } => return Err(From::from("X11 isn't supported in Python".to_string())),
            Qr {
                in_out:
                    InOutPaths {
                        output_path,
                        project_path,
                    },
                layout,
            } => vec![
                "-t",
                "qr",
                "-o",
                &*output_path.to_str().unwrap(),
                "--command",
                layout,
                &*project_path.to_str().unwrap(),
            ],
            ErrorModel {
                in_out:
                    InOutPaths {
                        output_path,
                        project_path,
                    },
                layout,
            } => vec![
                "-t",
                "errormodel",
                "-o",
                &*output_path.to_str().unwrap(),
                "--command",
                layout,
                &*project_path.to_str().unwrap(),
            ],
            X11RS { .. } => unreachable!("covered in previous match"),
        };

        if let Some(gh_username) = github_username {
            args.push("--github-username");
            args.push(&*gh_username);
        }

        if let Some(gh_token) = github_token {
            args.push("--github-token");
            args.push(&*gh_token);
        }

        args.push("--logging");
        args.push(logging);

        Ok(args)
    }
}

fn launch_py_kbdgen(args: &[&str]) -> i32 {
    // Load the default Python configuration as derived by the PyOxidizer config
    // file used at build time.
    let mut config = default_python_config();

    let mod_language_tags = ExtensionModule {
        name: std::ffi::CString::new("language_tags").unwrap(),
        init_func: py_language_tags::PyInit_language_tags,
    };

    let mod_logger = ExtensionModule {
        name: std::ffi::CString::new("rust_logger").unwrap(),
        init_func: py_logger::PyInit_rust_logger,
    };

    config.extra_extension_modules = vec![mod_language_tags, mod_logger];

    // Construct a new Python interpreter using that config, handling any errors
    // from construction.
    match MainPythonInterpreter::new(config) {
        Ok(mut interp) => {
            // And run it using the default run configuration as specified by the
            // configuration. If an uncaught Python exception is raised, handle it.
            // This includes the special SystemExit, which is a request to terminate the
            // process.
            let args = format!(
                "[{}]",
                args.iter()
                    .map(|x| format!("{:?}", x))
                    .collect::<Vec<_>>()
                    .join(", ")
            );
            match interp.run_code(&format!("import kbdgen.cli; kbdgen.cli.run_cli({})", args)) {
                Ok(_) => 0,
                Err(msg) => {
                    let py = interp.acquire_gil();
                    msg.print(py);
                    1
                }
            }
        }
        Err(msg) => {
            eprintln!("{}", msg);
            1
        }
    }
}

fn main() {
    env_logger::Builder::from_default_env()
        .filter(Some("kbdgen"), log::LevelFilter::Info)
        .target(env_logger::Target::Stderr)
        .init();

    let opt = Opts::from_args();

    let logging = match &*opt.logging {
        "trace" => log::Level::Trace,
        "debug" => log::Level::Debug,
        "info" => log::Level::Info,
        "warn" => log::Level::Warn,
        "error" => log::Level::Error,
        x => {
            eprintln!("Invalid logging level: {}", x);
            std::process::exit(1);
        }
    };

    std::env::set_var("RUST_LOG", logging.to_string());

    match opt.command {
        Commands::Build {
            github_username,
            github_token,
            command,
        } => match command {
            BuildCommands::X11RS {
                in_out:
                    InOutPaths {
                        output_path,
                        project_path,
                    },
                build_mode: BuildMode { .. },
                standalone,
            } => kbdgen::cli::to_xkb::kbdgen_to_xkb(
                &project_path,
                &output_path,
                &kbdgen::cli::to_xkb::Options { standalone },
            )
            .unwrap(),
            command => match command.to_py_args(
                github_username.as_ref().map(|x| &**x),
                github_token.as_ref().map(|x| &**x),
                &opt.logging,
            ) {
                Ok(args) => std::process::exit(launch_py_kbdgen(&args)),
                Err(e) => {
                    eprintln!("{:?}", e);
                    std::process::exit(1);
                }
            },
        },

        Commands::New { command } => match command {
            NewCommands::Bundle {
                bundle_name,
                output_path,
            } => match kbdgen::cli::from_cldr::cldr_to_kbdgen(&*output_path, &*bundle_name) {
                Ok(_) => std::process::exit(0),
                Err(e) => {
                    eprintln!("{:?}", e);
                    std::process::exit(1);
                }
            },
            NewCommands::Layout { .. } => {
                eprintln!("Not yet supported.");
                std::process::exit(1)
            }
        },
    }
}
<commit_msg>Rename X11RS to X11<commit_after>use pyembed::{ExtensionModule, MainPythonInterpreter};
use std::path::PathBuf;
use structopt::{clap::AppSettings::*, StructOpt};

include!(env!("PYOXIDIZER_DEFAULT_PYTHON_CONFIG_RS"));

#[derive(Debug, StructOpt)]
enum IOSCommands {
    Init,
    Ids,
}

#[derive(Debug, StructOpt)]
enum BuildCommands {
    #[structopt(about = "Demonstration SVG output for debugging")]
    Svg {
        #[structopt(flatten)]
        in_out: InOutPaths,
    },

    #[structopt(about = "Generates an .apk for Android")]
    Android {
        #[structopt(long = "kbd-repo", default_value = "divvun/giellakbd-android")]
        kbd_repo: String,

        #[structopt(long = "kbd-branch", default_value = "develop")]
        kbd_branch: String,

        #[structopt(long = "divvunspell-repo", default_value = "divvun/divvunspell")]
        divvunspell_repo: String,

        #[structopt(long = "divvunspell-branch", default_value = "develop")]
        divvunspell_branch: String,

        #[structopt(flatten)]
        in_out: InOutPaths,

        #[structopt(short = "D", long = "dry-run")]
        dry_run: bool,

        #[structopt(flatten)]
        build_mode: BuildMode,
    },

    #[cfg(target_os = "macos")]
    #[structopt(about = "Generates an .ipa for iOS")]
    IOS {
        #[structopt(subcommand)]
        command: Option<IOSCommands>,

        #[structopt(long = "kbd-repo", default_value = "divvun/giellakbd-ios")]
        kbd_repo: String,

        #[structopt(long = "kbd-branch", default_value = "develop")]
        kbd_branch: String,

        #[structopt(flatten)]
        in_out: InOutPaths,

        #[structopt(short = "D", long = "dry-run")]
        dry_run: bool,

        #[structopt(flatten)]
        build_mode: BuildMode,
    },

    #[structopt(about = "Generates installers for Windows 7/8 and 8.1+")]
    Win {
        #[structopt(flatten)]
        in_out: InOutPaths,

        #[structopt(short = "D", long = "dry-run")]
        dry_run: bool,

        #[structopt(flatten)]
        build_mode: BuildMode,
    },

    #[cfg(target_os = "macos")]
    #[structopt(about = "Generates installers for macOS")]
    Mac {
        #[structopt(flatten)]
        in_out: InOutPaths,

        #[structopt(short = "D", long = "dry-run")]
        dry_run: bool,

        #[structopt(flatten)]
        build_mode: BuildMode,
    },

    X11 {
        #[structopt(flatten)]
        in_out: InOutPaths,

        #[structopt(flatten)]
        build_mode: BuildMode,

        #[structopt(long = "standalone")]
        standalone: bool,
    },

    #[structopt(about = "Generates m17n output")]
    M17n {
        #[structopt(flatten)]
        in_out: InOutPaths,

        #[structopt(flatten)]
        build_mode: BuildMode,
    },

    #[structopt(about = "Generates Chrome OS bundles for putting on the Chrome App Store")]
    Chrome {
        #[structopt(flatten)]
        in_out: InOutPaths,

        #[structopt(flatten)]
        build_mode: BuildMode,
    },

    #[structopt(setting(Hidden))]
    Qr {
        #[structopt(flatten)]
        in_out: InOutPaths,

        #[structopt(short, long = "layout")]
        layout: String,
    },

    #[structopt(setting(Hidden))]
    ErrorModel {
        #[structopt(flatten)]
        in_out: InOutPaths,

        #[structopt(short, long = "layout")]
        layout: String,
    },
}

#[derive(Debug, StructOpt)]
struct InOutPaths {
    #[structopt(short, long = "output", default_value = ".", parse(from_os_str))]
    output_path: PathBuf,

    #[structopt(parse(from_os_str))]
    project_path: PathBuf,
}

#[derive(Debug, StructOpt)]
struct BuildMode {
    /// Compile in 'release' mode (where necessary).
    #[structopt(short = "R", long = "release")]
    release: bool,

    /// Continuous integration build
    #[structopt(long = "ci")]
    ci: bool,
}

#[derive(Debug, StructOpt)]
enum NewCommands {
    Layout {
        #[structopt(short, long = "output", default_value = ".", parse(from_os_str))]
        output_path: PathBuf,

        #[structopt(parse(from_os_str))]
        project_path: PathBuf,
    },
    Bundle {
        #[structopt(short, long = "output", default_value = ".", parse(from_os_str))]
        output_path: PathBuf,

        bundle_name: String,
    },
}

#[derive(Debug, StructOpt)]
enum Commands {
    #[structopt(
        about = "Generate output for a given .kbdgen bundle",
        setting(DisableHelpSubcommand)
    )]
    Build {
        #[structopt(long = "github-username")]
        github_username: Option<String>,

        #[structopt(long = "github-token")]
        github_token: Option<String>,

        #[structopt(subcommand)]
        command: BuildCommands,
    },
    #[structopt(
        about = "Generate new bundles or layout templates",
        setting(DisableHelpSubcommand)
    )]
    New {
        #[structopt(subcommand)]
        command: NewCommands,
    },
}

#[derive(Debug, StructOpt)]
#[structopt(
    name = "kbdgen",
    about = "The best solution to generating keyboards.",
    setting(DisableHelpSubcommand)
)]
struct Opts {
    #[structopt(long = "logging", default_value = "info")]
    logging: String,

    #[structopt(subcommand)]
    command: Commands,
}

impl BuildCommands {
    fn to_py_args<'a>(
        &'a self,
        github_username: Option<&'a str>,
        github_token: Option<&'a str>,
        logging: &'a str,
    ) -> Result<Vec<&'a str>, Box<dyn std::error::Error>> {
        use BuildCommands::*;

        let mut args = match self {
            Svg {
                in_out:
                    InOutPaths {
                        output_path,
                        project_path,
                    },
            } => vec![
                "-t",
                "svg",
                "-o",
                &*output_path.to_str().unwrap(),
                &*project_path.to_str().unwrap(),
            ],
            Android {
                kbd_repo,
                kbd_branch,
                divvunspell_repo,
                divvunspell_branch,
                in_out:
                    InOutPaths {
                        output_path,
                        project_path,
                    },
                dry_run,
                build_mode: BuildMode { release, ci },
            } => {
                let mut args = vec![
                    "-t",
                    "android",
                    "--kbd-repo",
                    kbd_repo,
                    "--kbd-branch",
                    kbd_branch,
                    "--divvunspell-repo",
                    divvunspell_repo,
                    "--divvunspell-branch",
                    divvunspell_branch,
                    "-o",
                    &*output_path.to_str().unwrap(),
                ];

                if *release {
                    args.push("-R");
                }

                if *dry_run {
                    args.push("-D");
                }

                if *ci {
                    args.push("--ci");
                }

                args.push(&*project_path.to_str().unwrap());

                args
            }
            #[cfg(target_os = "macos")]
            IOS {
                command,
                kbd_repo,
                kbd_branch,
                in_out:
                    InOutPaths {
                        output_path,
                        project_path,
                    },
                dry_run,
                build_mode: BuildMode { release, ci },
            } => {
                let mut args = vec![
                    "-t",
                    "ios",
                    "--kbd-repo",
                    kbd_repo,
                    "--kbd-branch",
                    kbd_branch,
                    "-o",
                    &*output_path.to_str().unwrap(),
                ];

                if *release {
                    args.push("-R");
                }

                if *dry_run {
                    args.push("-D");
                }

                if *ci {
                    args.push("--ci");
                }

                match command {
                    Some(IOSCommands::Init) => {
                        args.push("--command");
                        args.push("init");
                    }
                    Some(IOSCommands::Ids) => {
                        args.push("--command");
                        args.push("ids");
                    }
                    _ => {}
                }

                args.push(&*project_path.to_str().unwrap());
                args
            }
            Chrome {
                in_out:
                    InOutPaths {
                        output_path,
                        project_path,
                    },
                build_mode: BuildMode { release, ci },
            } => {
                let mut args = vec!["-t", "chrome", "-o", &*output_path.to_str().unwrap()];

                if *release {
                    args.push("-R");
                }

                if *ci {
                    args.push("--ci");
                }

                args.push(&*project_path.to_str().unwrap());
                args
            }
            Win {
                in_out:
                    InOutPaths {
                        output_path,
                        project_path,
                    },
                dry_run,
                build_mode: BuildMode { release, ci },
            } => {
                let mut args = vec!["-t", "win", "-o", &*output_path.to_str().unwrap()];

                if *release {
                    args.push("-R");
                }

                if *dry_run {
                    args.push("-D");
                }

                if *ci {
                    args.push("--ci");
                }

                args.push(&*project_path.to_str().unwrap());
                args
            }
            #[cfg(target_os = "macos")]
            Mac {
                in_out:
                    InOutPaths {
                        output_path,
                        project_path,
                    },
                dry_run,
                build_mode: BuildMode { release, ci },
            } => {
                let mut args = vec!["-t", "mac", "-o", &*output_path.to_str().unwrap()];

                if *release {
                    args.push("-R");
                }

                if *dry_run {
                    args.push("-D");
                }

                if *ci {
                    args.push("--ci");
                }

                args.push(&*project_path.to_str().unwrap());
                args
            }
            M17n { .. } => return Err(From::from("M17n isn't supported in Python".to_string())),
            Qr {
                in_out:
                    InOutPaths {
                        output_path,
                        project_path,
                    },
                layout,
            } => vec![
                "-t",
                "qr",
                "-o",
                &*output_path.to_str().unwrap(),
                "--command",
                layout,
                &*project_path.to_str().unwrap(),
            ],
            ErrorModel {
                in_out:
                    InOutPaths {
                        output_path,
                        project_path,
                    },
                layout,
            } => vec![
                "-t",
                "errormodel",
                "-o",
                &*output_path.to_str().unwrap(),
                "--command",
                layout,
                &*project_path.to_str().unwrap(),
            ],
            X11 { .. } => unreachable!("covered in previous match"),
        };

        if let Some(gh_username) = github_username {
            args.push("--github-username");
            args.push(&*gh_username);
        }

        if let Some(gh_token) = github_token {
            args.push("--github-token");
            args.push(&*gh_token);
        }

        args.push("--logging");
        args.push(logging);

        Ok(args)
    }
}

fn launch_py_kbdgen(args: &[&str]) -> i32 {
    // Load the default Python configuration as derived by the PyOxidizer config
    // file used at build time.
    let mut config = default_python_config();

    let mod_language_tags = ExtensionModule {
        name: std::ffi::CString::new("language_tags").unwrap(),
        init_func: py_language_tags::PyInit_language_tags,
    };

    let mod_logger = ExtensionModule {
        name: std::ffi::CString::new("rust_logger").unwrap(),
        init_func: py_logger::PyInit_rust_logger,
    };

    config.extra_extension_modules = vec![mod_language_tags, mod_logger];

    // Construct a new Python interpreter using that config, handling any errors
    // from construction.
    match MainPythonInterpreter::new(config) {
        Ok(mut interp) => {
            // And run it using the default run configuration as specified by the
            // configuration. If an uncaught Python exception is raised, handle it.
            // This includes the special SystemExit, which is a request to terminate the
            // process.
            let args = format!(
                "[{}]",
                args.iter()
                    .map(|x| format!("{:?}", x))
                    .collect::<Vec<_>>()
                    .join(", ")
            );
            match interp.run_code(&format!("import kbdgen.cli; kbdgen.cli.run_cli({})", args)) {
                Ok(_) => 0,
                Err(msg) => {
                    let py = interp.acquire_gil();
                    msg.print(py);
                    1
                }
            }
        }
        Err(msg) => {
            eprintln!("{}", msg);
            1
        }
    }
}

fn main() {
    env_logger::Builder::from_default_env()
        .filter(Some("kbdgen"), log::LevelFilter::Info)
        .target(env_logger::Target::Stderr)
        .init();

    let opt = Opts::from_args();

    let logging = match &*opt.logging {
        "trace" => log::Level::Trace,
        "debug" => log::Level::Debug,
        "info" => log::Level::Info,
        "warn" => log::Level::Warn,
        "error" => log::Level::Error,
        x => {
            eprintln!("Invalid logging level: {}", x);
            std::process::exit(1);
        }
    };

    std::env::set_var("RUST_LOG", logging.to_string());

    match opt.command {
        Commands::Build {
            github_username,
            github_token,
            command,
        } => match command {
            BuildCommands::X11 {
                in_out:
                    InOutPaths {
                        output_path,
                        project_path,
                    },
                build_mode: BuildMode { .. },
                standalone,
            } => kbdgen::cli::to_xkb::kbdgen_to_xkb(
                &project_path,
                &output_path,
                &kbdgen::cli::to_xkb::Options { standalone },
            )
            .unwrap(),
            command => match command.to_py_args(
                github_username.as_ref().map(|x| &**x),
                github_token.as_ref().map(|x| &**x),
                &opt.logging,
            ) {
                Ok(args) => std::process::exit(launch_py_kbdgen(&args)),
                Err(e) => {
                    eprintln!("{:?}", e);
                    std::process::exit(1);
                }
            },
        },

        Commands::New { command } => match command {
            NewCommands::Bundle {
                bundle_name,
                output_path,
            } => match kbdgen::cli::from_cldr::cldr_to_kbdgen(&*output_path, &*bundle_name) {
                Ok(_) => std::process::exit(0),
                Err(e) => {
                    eprintln!("{:?}", e);
                    std::process::exit(1);
                }
            },
            NewCommands::Layout { .. } => {
                eprintln!("Not yet supported.");
                std::process::exit(1)
            }
        },
    }
}
<|endoftext|>


<commit_before>// Worklog is for recording your hours.
//

extern crate chrono;
extern crate csv;
extern crate getopts;
extern crate rustc_serialize;

mod error;
mod timeclock;
mod util;

use chrono::*;
use error::WorklogError;
use getopts::Options;
use std::env;
use std::fs::OpenOptions;
use std::io::prelude::*;
use std::path::PathBuf;
use timeclock::Direction;
use timeclock::now;

#[cfg(target_family = "unix")]
static CSV_FILE_NAME: &'static str = ".worklog.csv";
#[cfg(target_family = "windows")]
static CSV_FILE_NAME: &'static str = "worklog.csv";

// TODO This belongs in a config file somewhere
const WEEKSTART: i64 = Weekday::Sat as i64;

fn print_csv_entries<R: Read>(file: R) -> Result<(), WorklogError> {
    let csv_entries = try!(timeclock::read_timesheet(file));
    for rec in csv_entries {
        println!("{}", rec);
    }
    Ok(())
}

fn print_full_summary<R: Read>(file: R) -> Result<(), WorklogError> {
    let csv_entries = try!(timeclock::read_timesheet(file));
    let records = timeclock::collect_date_records(csv_entries);

    let mut total_hours: f64 = 0.0;
    for rec in records {
        total_hours += rec.hours();
        println!("{}", rec);
    }

    println!("Total Hours: {:.2}", total_hours);
    Ok(())
}

fn print_short_summary<R: Read>(file: R,
                                since: Date<FixedOffset>)
                                -> Result<(), WorklogError> {
    let csv_entries = try!(timeclock::read_timesheet(file));
    let records = timeclock::collect_date_records(csv_entries);

    let mut total_hours: f64 = 0.0;
    for rec in records {
        if rec.date() >= since {
            total_hours += rec.hours();
            println!("{}", rec);
        }
    }

    println!("Total Hours: {:.2}", total_hours);
    Ok(())
}

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", opts.usage(&brief));
}

/// Get the path for the csv data file
fn get_csv_path() -> Result<PathBuf, WorklogError> {
    let mut data_path = match env::home_dir() {
        Some(path) => path,
        None => {
            return Err(env::VarError::NotPresent).map_err(WorklogError::Env)
        }
    };

    data_path.push(CSV_FILE_NAME);
    Ok(data_path)
}

fn main0() -> Result<i8, WorklogError> {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    let mut opts = Options::new();
    opts.optflagopt("i", "in", "in time", "TIME");
    opts.optflagopt("o", "out", "out time", "TIME");
    opts.optopt("m", "memo", "the memo", "MEMO");
    opts.optflag("s", "summary", "show the full summary");
    opts.optflag("e", "entries", "show all entries");
    opts.optflag("h", "help", "print this help menu");

    let matches = try!(opts.parse(&args[1..]));

    let csv_path = try!(get_csv_path());

    let mut csv_file = try!(OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .open(csv_path));

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

    } else if matches.opts_present(&["i".to_owned(), "o".to_owned()]) {
        // The ridiculous array above isn't my fault.

        // Reject --in and --out if present at the same time
        if matches.opt_present("i") && matches.opt_present("o") {
            println!("--in or --out, not both");
            return Ok(1);
        }

        let dir = if matches.opt_present("i") {
            Direction::In
        } else {
            Direction::Out
        };

        let time = matches.opt_str("i")
            .or(matches.opt_str("o"))
            .or_else(|| Some("now".to_owned()))
            .unwrap();
        let time = try!(util::parse_multi_time_fmt(&time));

        let memo =
            matches.opt_str("m").or_else(|| Some("".to_owned())).unwrap();
        timeclock::mark_time(dir, time, memo, &mut csv_file);

        println!("Clocked {:#} at {}", dir, time.format("%F %I:%M %P"));

    } else if matches.opt_present("s") {
        try!(print_full_summary(&csv_file));

    } else if matches.opt_present("e") {
        try!(print_csv_entries(&csv_file));

    } else {
        let days_back = (-WEEKSTART + 7) % 7;
        let start_date = now().date() - Duration::days(days_back);
        try!(print_short_summary(&csv_file, start_date));
    }

    Ok(0)
}

fn main() {
    match main0() {
        Ok(_) => {}
        Err(err) => {
            let _ = writeln!(&mut std::io::stderr(), "Error: {}", err);
        }
    };
}
<commit_msg>Rename --entries option to --log<commit_after>// Worklog is for recording your hours.
//

extern crate chrono;
extern crate csv;
extern crate getopts;
extern crate rustc_serialize;

mod error;
mod timeclock;
mod util;

use chrono::*;
use error::WorklogError;
use getopts::Options;
use std::env;
use std::fs::OpenOptions;
use std::io::prelude::*;
use std::path::PathBuf;
use timeclock::Direction;
use timeclock::now;

#[cfg(target_family = "unix")]
static CSV_FILE_NAME: &'static str = ".worklog.csv";
#[cfg(target_family = "windows")]
static CSV_FILE_NAME: &'static str = "worklog.csv";

// TODO This belongs in a config file somewhere
const WEEKSTART: i64 = Weekday::Sat as i64;

fn print_csv_entries<R: Read>(file: R) -> Result<(), WorklogError> {
    let csv_entries = try!(timeclock::read_timesheet(file));
    for rec in csv_entries {
        println!("{}", rec);
    }
    Ok(())
}

fn print_full_summary<R: Read>(file: R) -> Result<(), WorklogError> {
    let csv_entries = try!(timeclock::read_timesheet(file));
    let records = timeclock::collect_date_records(csv_entries);

    let mut total_hours: f64 = 0.0;
    for rec in records {
        total_hours += rec.hours();
        println!("{}", rec);
    }

    println!("Total Hours: {:.2}", total_hours);
    Ok(())
}

fn print_short_summary<R: Read>(file: R,
                                since: Date<FixedOffset>)
                                -> Result<(), WorklogError> {
    let csv_entries = try!(timeclock::read_timesheet(file));
    let records = timeclock::collect_date_records(csv_entries);

    let mut total_hours: f64 = 0.0;
    for rec in records {
        if rec.date() >= since {
            total_hours += rec.hours();
            println!("{}", rec);
        }
    }

    println!("Total Hours: {:.2}", total_hours);
    Ok(())
}

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", opts.usage(&brief));
}

/// Get the path for the csv data file
fn get_csv_path() -> Result<PathBuf, WorklogError> {
    let mut data_path = match env::home_dir() {
        Some(path) => path,
        None => {
            return Err(env::VarError::NotPresent).map_err(WorklogError::Env)
        }
    };

    data_path.push(CSV_FILE_NAME);
    Ok(data_path)
}

fn main0() -> Result<i8, WorklogError> {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    let mut opts = Options::new();
    opts.optflagopt("i", "in", "in time", "TIME");
    opts.optflagopt("o", "out", "out time", "TIME");
    opts.optopt("m", "memo", "the memo", "MEMO");
    opts.optflag("s", "summary", "show the full summary");
    opts.optflag("l", "log", "show the full log");
    opts.optflag("h", "help", "print this help menu");

    let matches = try!(opts.parse(&args[1..]));

    let csv_path = try!(get_csv_path());

    let mut csv_file = try!(OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .open(csv_path));

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

    } else if matches.opts_present(&["i".to_owned(), "o".to_owned()]) {
        // The ridiculous array above isn't my fault.

        // Reject --in and --out if present at the same time
        if matches.opt_present("i") && matches.opt_present("o") {
            println!("--in or --out, not both");
            return Ok(1);
        }

        let dir = if matches.opt_present("i") {
            Direction::In
        } else {
            Direction::Out
        };

        let time = matches.opt_str("i")
            .or(matches.opt_str("o"))
            .or_else(|| Some("now".to_owned()))
            .unwrap();
        let time = try!(util::parse_multi_time_fmt(&time));

        let memo =
            matches.opt_str("m").or_else(|| Some("".to_owned())).unwrap();
        timeclock::mark_time(dir, time, memo, &mut csv_file);

        println!("Clocked {:#} at {}", dir, time.format("%F %I:%M %P"));

    } else if matches.opt_present("s") {
        try!(print_full_summary(&csv_file));

    } else if matches.opt_present("l") {
        try!(print_csv_entries(&csv_file));

    } else {
        let days_back = (-WEEKSTART + 7) % 7;
        let start_date = now().date() - Duration::days(days_back);
        try!(print_short_summary(&csv_file, start_date));
    }

    Ok(0)
}

fn main() {
    match main0() {
        Ok(_) => {}
        Err(err) => {
            let _ = writeln!(&mut std::io::stderr(), "Error: {}", err);
        }
    };
}
<|endoftext|>


<commit_before>extern crate git2;
extern crate "rustc-serialize" as rustc_serialize;
extern crate docopt;

use git2::{Repository, Branch, BranchType};
use docopt::Docopt;
use std::old_io as io;

// Write the Docopt usage string.
static USAGE: &'static str = "
Usage: transit [options] <repo> [<branch>]

Options:
    -f, --flag  Flags a flag, note the multiple spaces!
";

#[derive(RustcDecodable, Show)]
struct Args {
    arg_repo: String,
    arg_branch: Option<String>,
    flag_flag: bool,
}

fn main() {
    // Parse the args above or die.
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());

    let path = Path::new(args.arg_repo);
    let repo = Repository::discover(&path)
        .ok().expect("Could not discover a repository.");
    let branch = match args.arg_branch {
        Some(branch) => repo.find_branch(branch.as_slice(), BranchType::Local),
        None => choose_branch(&repo),
    }.ok().expect("Could not get branch.");
    println!("Repo: {:?}, Branch: {:?}", path, branch.name()
        .ok().expect("Branch name was not valid UTF-8"));
}

fn choose_branch(repo: &Repository) -> Result<Branch, git2::Error> {
    println!("Please choose a branch:");
    let mut branches = repo.branches(Some(BranchType::Local))
        .ok().expect("Could find any branches.");
    for (branch, variant) in branches {
        let name = branch.name()
            .ok().expect("Could not get branch name.")
            .expect("Branch name was not valid UTF-8");
        println!("{:?}", name);
    }
    let chosen = io::stdin().lock().read_to_string()
        .ok().expect("Could not read from stdin");
    repo.find_branch(chosen.as_slice(), BranchType::Local)
}

<commit_msg>Improve codebase.<commit_after>extern crate git2;
extern crate "rustc-serialize" as rustc_serialize;
extern crate docopt;

use git2::{Repository, Branch, BranchType};
use docopt::Docopt;
use std::old_io as io;

// Write the Docopt usage string.
static USAGE: &'static str = "
Usage: transit [options] <repo> [<branch>]

Options:
    -f, --flag  Flags a flag, note the multiple spaces!
";

#[derive(RustcDecodable, Show)]
struct Args {
    arg_repo: String,
    arg_branch: Option<String>,
    flag_flag: bool,
}

fn main() {
    // Parse the args above or die.
    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.decode())
        .unwrap_or_else(|e| e.exit());

    let path = Path::new(args.arg_repo);
    let repo = Repository::discover(&path)
        .ok().expect("Could not discover a repository.");
    let branch = match args.arg_branch {
        Some(branch) => repo.find_branch(&branch[], BranchType::Local),
        None => choose_branch(&repo),
    }.ok().expect("Could not get branch.");
    println!("Repo: {:?}, Branch: {:?}", path, branch.name()
        .ok().expect("Branch name was not valid UTF-8"));
}

fn choose_branch(repo: &Repository) -> Result<Branch, git2::Error> {
    println!("Please choose a branch:");
    let mut branches = repo.branches(Some(BranchType::Local))
        .ok().expect("Could find any branches.");
    for (branch, _) in branches {
        let name = branch.name()
            .ok().expect("Could not get branch name.")
            .expect("Branch name was not valid UTF-8");
        println!("{}", name);
    }
    io::stdout().write_str(&"Choose your branch: "[]);
    let chosen = io::stdin().lock().read_line()
        .ok().expect("Could not read from stdin");
    repo.find_branch(&chosen.trim()[], BranchType::Local)
}

<|endoftext|>


<commit_before>extern crate time;

use std::collections::LinkedList;

fn main() {
    let dow = ["Duinday", "Sitaday", "Wikiday", "Tuxday", "Gnuday", "Commonday"];
    let moy = ["Jabim", "Zodrak", "Trogool", "Yanar", "Shkumbe", "Habniah", "Skarl", "Mikon", "Pertunda", "Kib", "Broket"];
    let dpm = 33;
    let dpw = dow.len();
    let mpy = moy.len();
    let (year, month, day, yoff) = current_day(time::now());
    let wd = (yoff + month * 3 + day) % dpw;
    let mut moff = yoff;
    let mut months_across = LinkedList::<String>::new();

    for mm in 0..mpy {
        let spaces = (17 - moy[mm].len()) / 2;
        let mut month_text = format!("");
        for _ in 0..spaces {
            month_text = format!("{} ", month_text);
        }

        month_text = format!("{}{}\n", month_text, moy[mm]);
        for dd in 0..dpw {
            let mut abbrd = String::from(dow[dd]);
            abbrd.truncate(2);
            month_text = format!("{}{} ", month_text, abbrd);
        }

        let dd = if mm == month { day } else { 1000 };
        let days = format_days(moff, dpm, dpw, dd);
        month_text = format!("{}{}", month_text, days.0);
        moff = days.1;
        if mm == 2 {
            month_text = format!("{}--  Peer  Day  --", month_text);
        }
        else if mm == 6 {
            month_text = format!("{}--Torrent Feast--", month_text);
        }
        else if is_leap_year(year) && mm == 10 {
            month_text = format!("{}--Immersion Day--", month_text);
        }

        month_text = format!("{}\n", month_text);
        print!("{}", month_text);
        months_across.push_back(month_text);
    }

    let mut datestr = format!("{}, {:02} of {}", dow[wd], day, moy[month]);
    let mut daystr = format!("{:02}.{:02}", month + 1, day);
    if day == 34 {
        if month == 2 {
            datestr = format!("Peer Day");
            daystr = format!("P");
        }
        else if month == 6 {
            datestr = format!("Torrent Feast");
            daystr = format!("T");
        }
        else if month == 10 {
            datestr = format!("Immersion Feast");
            daystr = format!("T");
        }
    }
    let hol = format!("{}", what_holiday(month, day));
    println!("Today is {} {}{}.  [{}.{}]", datestr, year, hol, year, daystr);
}

fn format_days(moff: usize, dpm: usize, dpw: usize, highlight: usize) -> (String, usize) {
    let mut month = format!("");

    if moff != 0 {
        month = format!("{}\n", month);
    }

    for _ in 0 .. moff {
        month = format!("{}   ", month);
    }

    for day in 1 .. dpm + 1 {
        if (day + moff) % dpw == 1 {
            month = format!("{}\n", month);
        }

        let ch = if day == highlight { ">" } else if day + 1 == highlight { "<" } else { " " };
        month = format!("{}{:2}{}", month, day, ch);
    }

    month = format!("{}\n", month);
    return (month, if moff == 0 { 3 } else { 0 });
}

fn current_day(current_time: time::Tm) -> (usize, usize, usize, usize) {
    let epoch_days_offset = 1483889;
    let seconds_per_day = 86400;
    let now = current_time.to_timespec();
    let days_since_epoch = (epoch_days_offset + now.sec / seconds_per_day) as i32;
    let days_per_year = 365;
    let leap_year = 4;
    let not_leap_year = 33;
    let days_per_month = 33;

    let mut count = 1;
    let mut days_remaining = days_since_epoch;
    let mut year = 0;
    while days_remaining > days_per_year + 1 {
        days_remaining -= days_per_year;
        year += 1;
        if count > not_leap_year {
            count = 1;
        }
        if count % leap_year == 0 {
            days_remaining -= 1;
        }
        count += 1;
    }
    if days_remaining == days_per_year + 1 && count % leap_year == 0 {
        days_remaining = 0;
        year += 1;
    }

    let mut month = 0;
    while days_remaining > days_per_month {
        month += 1;
        days_remaining -= days_per_month;
        if month == 3 || month == 7 || month == 11 {
            days_remaining -= 1;
        }
    }

    let day = days_remaining;
    return (year, month as usize, day as usize + 1, (year % 2 * 3) as usize);
}

fn is_leap_year(year: usize) -> bool {
    let rem = year % 33;
    return rem != 0 && rem % 4 == 0;
}

fn what_holiday(month: usize, day: usize) -> String {
    let mut result = format!("");
    if month == 0 && day == 1 {
        result = format!(", New Year's Day");
    }
    else if month == 2 && day == 12 {
        result = format!(", Purification Day");
    }
    else if month == 2 && day == 24 {
        result = format!(", Document Freedom Day");
    }
    else if month == 3 && day == 33 {
        result = format!(", Hardware Freedom Day");
    }
    else if month == 5 && day == 4 {
        result = format!(", Harvest Gift");
    }
    else if month == 5 && day == 9 {
        result = format!(", Culture Freedom Day");
    }
    else if month == 7 && day == 29 {
        result = format!(", Familytide");
    }
    else if month == 8 && day == 33 {
        result = format!(", Software Freedom Day");
    }
    else if month == 9 && day == 30 {
        result = format!(", Open Access Day");
    }
    else if month == 10 && day == 21 {
        result = format!(", Freedom Day");
    }
    else if month == 0 && day == 27 {
        result = format!(", International Workers' Day");
    }
    return result;
}

<commit_msg>Add routine to print multiple multi-line strings across screen<commit_after>extern crate time;

use std::collections::LinkedList;
use std::str::Split;

fn main() {
    let dow = ["Duinday", "Sitaday", "Wikiday", "Tuxday", "Gnuday", "Commonday"];
    let moy = ["Jabim", "Zodrak", "Trogool", "Yanar", "Shkumbe", "Habniah", "Skarl", "Mikon", "Pertunda", "Kib", "Broket"];
    let dpm = 33;
    let dpw = dow.len();
    let mpy = moy.len();
    let (year, month, day, yoff) = current_day(time::now());
    let wd = (yoff + month * 3 + day) % dpw;
    let mut moff = yoff;
    let mut months_across = LinkedList::<String>::new();

    for mm in 0..mpy {
        let spaces = (17 - moy[mm].len()) / 2;
        let mut month_text = format!("");
        for _ in 0..spaces {
            month_text = format!("{} ", month_text);
        }

        month_text = format!("{}{}\n", month_text, moy[mm]);
        for dd in 0..dpw {
            let mut abbrd = String::from(dow[dd]);
            abbrd.truncate(2);
            month_text = format!("{}{} ", month_text, abbrd);
        }

        let dd = if mm == month { day } else { 1000 };
        let days = format_days(moff, dpm, dpw, dd);
        month_text = format!("{}{}", month_text, days.0);
        moff = days.1;
        if mm == 2 {
            month_text = format!("{}--  Peer  Day  --", month_text);
        }
        else if mm == 6 {
            month_text = format!("{}--Torrent Feast--", month_text);
        }
        else if is_leap_year(year) && mm == 10 {
            month_text = format!("{}--Immersion Day--", month_text);
        }

        month_text = format!("{}\n", month_text);
        print!("{}", month_text);
        months_across.push_back(month_text);
    }

    let mut datestr = format!("{}, {:02} of {}", dow[wd], day, moy[month]);
    let mut daystr = format!("{:02}.{:02}", month + 1, day);
    if day == 34 {
        if month == 2 {
            datestr = format!("Peer Day");
            daystr = format!("P");
        }
        else if month == 6 {
            datestr = format!("Torrent Feast");
            daystr = format!("T");
        }
        else if month == 10 {
            datestr = format!("Immersion Feast");
            daystr = format!("T");
        }
    }
    let hol = format!("{}", what_holiday(month, day));
    println!("Today is {} {}{}.  [{}.{}]", datestr, year, hol, year, daystr);
}

fn format_days(moff: usize, dpm: usize, dpw: usize, highlight: usize) -> (String, usize) {
    let mut month = format!("");

    if moff != 0 {
        month = format!("{}\n", month);
    }

    for _ in 0 .. moff {
        month = format!("{}   ", month);
    }

    for day in 1 .. dpm + 1 {
        if (day + moff) % dpw == 1 {
            month = format!("{}\n", month);
        }

        let ch = if day == highlight { ">" } else if day + 1 == highlight { "<" } else { " " };
        month = format!("{}{:2}{}", month, day, ch);
    }

    month = format!("{}\n", month);
    return (month, if moff == 0 { 3 } else { 0 });
}

fn current_day(current_time: time::Tm) -> (usize, usize, usize, usize) {
    let epoch_days_offset = 1483889;
    let seconds_per_day = 86400;
    let now = current_time.to_timespec();
    let days_since_epoch = (epoch_days_offset + now.sec / seconds_per_day) as i32;
    let days_per_year = 365;
    let leap_year = 4;
    let not_leap_year = 33;
    let days_per_month = 33;

    let mut count = 1;
    let mut days_remaining = days_since_epoch;
    let mut year = 0;
    while days_remaining > days_per_year + 1 {
        days_remaining -= days_per_year;
        year += 1;
        if count > not_leap_year {
            count = 1;
        }
        if count % leap_year == 0 {
            days_remaining -= 1;
        }
        count += 1;
    }
    if days_remaining == days_per_year + 1 && count % leap_year == 0 {
        days_remaining = 0;
        year += 1;
    }

    let mut month = 0;
    while days_remaining > days_per_month {
        month += 1;
        days_remaining -= days_per_month;
        if month == 3 || month == 7 || month == 11 {
            days_remaining -= 1;
        }
    }

    let day = days_remaining;
    return (year, month as usize, day as usize + 1, (year % 2 * 3) as usize);
}

fn is_leap_year(year: usize) -> bool {
    let rem = year % 33;
    return rem != 0 && rem % 4 == 0;
}

fn what_holiday(month: usize, day: usize) -> String {
    let mut result = format!("");
    if month == 0 && day == 1 {
        result = format!(", New Year's Day");
    }
    else if month == 2 && day == 12 {
        result = format!(", Purification Day");
    }
    else if month == 2 && day == 24 {
        result = format!(", Document Freedom Day");
    }
    else if month == 3 && day == 33 {
        result = format!(", Hardware Freedom Day");
    }
    else if month == 5 && day == 4 {
        result = format!(", Harvest Gift");
    }
    else if month == 5 && day == 9 {
        result = format!(", Culture Freedom Day");
    }
    else if month == 7 && day == 29 {
        result = format!(", Familytide");
    }
    else if month == 8 && day == 33 {
        result = format!(", Software Freedom Day");
    }
    else if month == 9 && day == 30 {
        result = format!(", Open Access Day");
    }
    else if month == 10 && day == 21 {
        result = format!(", Freedom Day");
    }
    else if month == 0 && day == 27 {
        result = format!(", International Workers' Day");
    }
    return result;
}

fn month_zipper(months: LinkedList<String>, buffer: &str, front: usize) {
    let month_iterator = months.iter();
    let mut length = 0;
    let mut split_months = LinkedList::<Split<&str>>::new();
    for m in month_iterator {
        let split = m.split("\n");
        if split.clone().count() > length {
            length = split.clone().count();
        }
        split_months.push_back(split);
    }

    for i in 0..(length - 1) {
        for _ in 0..front {
            print!(" ");
        }

        let split_iterator = split_months.iter();
        for m in split_iterator {
            let line = m.clone().nth(i);
            match line {
                Some(l) => print!("{}{}", if l == "" { "                  " } else { l }, buffer),
                None => {},
            }
        }

        println!("");
    }
}

<|endoftext|>


<commit_before>#[macro_use] extern crate clap;
#[macro_use] extern crate log;
extern crate env_logger;

extern crate nerve;

use clap::{Arg, App, SubCommand};

use nerve::cmd;
use nerve::format::{OutputFormat};
use nerve::validators::{is_repopath};

fn main() {
    env_logger::init().unwrap();

    let upload_about = "Upload issues from a CSV file. If the first line is
detected to be a header it will be ignored. The fields are identified and
consumed in order:

1. `title`
2. `body`
3. `labels`
4. `assignees`
5. `milestone_id`";

    let matches = App::new("github-issues")
                      .version(env!("CARGO_PKG_VERSION"))
                      .author("Arnau Siches <arnau@ustwo.com>")
                      .about("Github issues consumer.")
                      .subcommand(SubCommand::with_name("upload-template")
                                             .about("Generates a CSV example as an easy start for the upload command.")
                                             .arg(Arg::with_name("output")
                                                      .help("Write output to <file>")
                                                      .long("output")
                                                      .value_name("file")))
                      .subcommand(SubCommand::with_name("upload")
                                             .about(upload_about)
                                             .arg(Arg::with_name("repopath")
                                                      .help("Repo path (e.g. ustwo/mastermind)")
                                                      .index(1)
                                                      .validator(is_repopath)
                                                      .required(true))
                                             .arg(Arg::with_name("oauth-token")
                                                      .help("Github OAuth authorisation token")
                                                      .long("oauth-token")
                                                      .value_name("oauth_token")
                                                      .required(true))
                                             .arg(Arg::with_name("input")
                                                      .help("Read input from <file>")
                                                      .long("input")
                                                      .value_name("file")
                                                      .required(true))
                                             .arg(Arg::with_name("check")
                                                      .help("Check if any records in the provided CSV have potential collisions in existing Issues. This flag makes the command noop.")
                                                      .long("check")))
                      .subcommand(SubCommand::with_name("fetch")
                                             .about("Fetch issues from Github.")
                                             .arg(Arg::with_name("repopath")
                                                      .help("Repo path (e.g. ustwo/mastermind)")
                                                      .index(1)
                                                      .validator(is_repopath)
                                                      .required(true))
                                             .arg(Arg::with_name("oauth-token")
                                                      .help("Github OAuth authorisation token")
                                                      .long("oauth-token")
                                                      .value_name("oauth_token")
                                                      .required(true))
                                             .arg(Arg::with_name("format")
                                                      .help("Output format")
                                                      .long("format")
                                                      .value_name("format")
                                                      .possible_values(&["csv", "json"])
                                                      .required(true))
                                             .arg(Arg::with_name("output")
                                                      .help("Write output to <file>")
                                                      .long("output")
                                                      .value_name("file")
                                                      .required(true))
                                             .arg(Arg::with_name("state")
                                                      .help("Issue state. Defaults to \"all\"")
                                                      .long("state")
                                                      .value_name("state")
                                                      .possible_values(&["all", "open", "closed"]))
                                             .arg(Arg::with_name("label")
                                                      .help("Github label to filter with")
                                                      .long("label")
                                                      .value_name("label")
                                                      .multiple(true)))
                      .get_matches();

    if let Some(ref matches) = matches.subcommand_matches("fetch") {
        let labels: Vec<String> = values_t!(matches, "label", String).unwrap_or(vec![]);
        let state = matches.value_of("state").unwrap_or("all").to_owned();
        let repopath = matches.value_of("repopath").unwrap().to_owned();
        let oauth_token = matches.value_of("oauth-token").unwrap().to_owned();
        let format = value_t!(matches, "format", OutputFormat).unwrap_or_else(|e| e.exit());
        let output = matches.value_of("output").unwrap().to_owned();

        cmd::fetch::run(repopath,
                        oauth_token,
                        labels,
                        state,
                        format,
                        output);
    }

    if let Some(ref matches) = matches.subcommand_matches("upload-template") {
        cmd::template::run(matches.value_of("output"));
    }

    if let Some(ref matches) = matches.subcommand_matches("upload") {
        let repopath = matches.value_of("repopath").unwrap().to_owned();
        let oauth_token = matches.value_of("oauth-token").unwrap().to_owned();
        let input_file = matches.value_of("input").unwrap().to_owned();

        if matches.is_present("check") {
            cmd::check::run(repopath,
                            oauth_token,
                            input_file);
        } else {
            cmd::upload::run(repopath,
                             oauth_token,
                             input_file);
        }
    }

}
<commit_msg>fix: Print help when no command provided<commit_after>#[macro_use] extern crate clap;
#[macro_use] extern crate log;
extern crate env_logger;

extern crate nerve;

use std::io;
use clap::{Arg, App, SubCommand, Shell};

use nerve::cmd;
use nerve::format::{OutputFormat};
use nerve::validators::{is_repopath};

fn cli() -> App<'static, 'static> {
    let upload_about = "Upload issues from a CSV file. If the first line is
detected to be a header it will be ignored. The fields are identified and
consumed in order:

1. `title`
2. `body`
3. `labels`
4. `assignees`
5. `milestone_id`";

    App::new("github-issues")
        .version(env!("CARGO_PKG_VERSION"))
        .author("Arnau Siches <arnau@ustwo.com>")
        .about("Github issues consumer.")
        .subcommand(SubCommand::with_name("completions")
                               .about("Generates completion scripts for your shell")
                               .arg(Arg::with_name("SHELL")
                                        .required(true)
                                        .possible_values(&["bash", "fish", "zsh"])
                                        .help("The shell to generate the script for")))
        .subcommand(SubCommand::with_name("upload-template")
                               .about("Generates a CSV example as an easy start for the upload command.")
                               .arg(Arg::with_name("output")
                                        .help("Write output to <file>")
                                        .long("output")
                                        .value_name("file")))
        .subcommand(SubCommand::with_name("upload")
                               .about(upload_about)
                               .arg(Arg::with_name("repopath")
                                        .help("Repo path (e.g. ustwo/mastermind)")
                                        .index(1)
                                        .validator(is_repopath)
                                        .required(true))
                               .arg(Arg::with_name("oauth-token")
                                        .help("Github OAuth authorisation token")
                                        .long("oauth-token")
                                        .value_name("oauth_token")
                                        .required(true))
                               .arg(Arg::with_name("input")
                                        .help("Read input from <file>")
                                        .long("input")
                                        .value_name("file")
                                        .required(true))
                               .arg(Arg::with_name("check")
                                        .help("Check if any records in the provided CSV have potential collisions in existing Issues. This flag makes the command noop.")
                                        .long("check")))
        .subcommand(SubCommand::with_name("fetch")
                               .about("Fetch issues from Github.")
                               .arg(Arg::with_name("repopath")
                                        .help("Repo path (e.g. ustwo/mastermind)")
                                        .index(1)
                                        .validator(is_repopath)
                                        .required(true))
                               .arg(Arg::with_name("oauth-token")
                                        .help("Github OAuth authorisation token")
                                        .long("oauth-token")
                                        .value_name("oauth_token")
                                        .required(true))
                               .arg(Arg::with_name("format")
                                        .help("Output format")
                                        .long("format")
                                        .value_name("format")
                                        .possible_values(&["csv", "json"])
                                        .required(true))
                               .arg(Arg::with_name("output")
                                        .help("Write output to <file>")
                                        .long("output")
                                        .value_name("file")
                                        .required(true))
                               .arg(Arg::with_name("state")
                                        .help("Issue state. Defaults to \"all\"")
                                        .long("state")
                                        .value_name("state")
                                        .possible_values(&["all", "open", "closed"]))
                               .arg(Arg::with_name("label")
                                        .help("Github label to filter with")
                                        .long("label")
                                        .value_name("label")
                                        .multiple(true)))
}

fn main() {
    env_logger::init().unwrap();
    let matches = cli().get_matches();

    match matches.subcommand() {
        ("fetch", Some(sub_matches)) => {
            let labels: Vec<String> = values_t!(sub_matches, "label", String).unwrap_or(vec![]);
            let state = sub_matches.value_of("state").unwrap_or("all").to_owned();
            let repopath = sub_matches.value_of("repopath").unwrap().to_owned();
            let oauth_token = sub_matches.value_of("oauth-token").unwrap().to_owned();
            let format = value_t!(sub_matches, "format", OutputFormat).unwrap_or_else(|e| e.exit());
            let output = matches.value_of("output").unwrap().to_owned();

            cmd::fetch::run(repopath,
                            oauth_token,
                            labels,
                            state,
                            format,
                            output);

        },

        ("upload-template", Some(sub_matches)) => {
            cmd::template::run(sub_matches.value_of("output"));
        },

        ("upload", Some(sub_matches)) => {
            let repopath = sub_matches.value_of("repopath").unwrap().to_owned();
            let oauth_token = sub_matches.value_of("oauth-token").unwrap().to_owned();
            let input_file = sub_matches.value_of("input").unwrap().to_owned();

            if sub_matches.is_present("check") {
                cmd::check::run(repopath,
                                oauth_token,
                                input_file);
            } else {
                cmd::upload::run(repopath,
                                 oauth_token,
                                 input_file);
            }
        },

        ("completions", Some(sub_matches)) => {
            let shell = sub_matches.value_of("SHELL").unwrap();

            cli().gen_completions_to("github-issues",
                                     shell.parse::<Shell>().unwrap(),
                                     &mut io::stdout());
        },

        // (_, _) => unimplemented!(), // for brevity
        (_, _) => {
            cli().print_help().unwrap();
            println!("");
        },
    }
}
<|endoftext|>


<commit_before>// Genetic Algorithm for convergence to a given string
// Author: Duncan Dean
extern crate rand;
use rand::Rng;

fn rand_string(size: usize) -> String {
    return rand::thread_rng().gen_ascii_chars().take(size).collect();
}

fn crossover(chrome1: Chromosome, chrome2: Chromosome, cross_prob: f32, solution: &str) -> Chromosome {
    if rand::thread_rng().gen_range::<f32>(0.0, 1.0) <= cross_prob {
        let code_len = chrome1.code.len();
        let rand_index = rand::thread_rng().gen_range(0, code_len);
        let first_half = &chrome1.code[0..rand_index];
        let second_half = &chrome2.code[rand_index..code_len];
        let new_code = first_half.to_string() + second_half;
        Chromosome {
            code: new_code.to_string(),
            cost_score: cost_function(&new_code, solution),
            solution: solution.to_string(),
        }
    } else if chrome1.cost_score < chrome2.cost_score {
        chrome1.clone()
    } else {
        chrome2.clone()
    }
}

fn cost_function(code: &str, solution: &str) -> u32 {
    let chars: Vec<char> = solution.to_string().chars().collect();
    let code_chars: Vec<char> = code.to_string().chars().collect();
    let mut cost: u32 = 0;
    for i in 0..chars.len() {
        cost += ((chars[i] as u8 as i32) - (code_chars[i] as u8 as i32)).abs() as u32;
    }
    cost
}

#[derive(Clone)]
struct Chromosome {
    code: String,
    cost_score: u32,
    solution: String,
}

impl Chromosome {
    fn new(solution: String) -> Chromosome {
        let random_string = rand_string(solution.len());
        Chromosome {
            code: random_string.clone(),
            cost_score: cost_function(&random_string, &solution),
            solution: solution,
        }
    }

    fn mutate(&mut self, mut_prob:f64) -> Chromosome {
        if rand::thread_rng().gen_range::<f64>(0.0, 1.0) <= mut_prob {
            let rand_index = rand::thread_rng().gen_range(0, self.code.len());
            let mut new_code_vec: Vec<char> = self.code.chars().collect();
            new_code_vec[rand_index] = rand::thread_rng().gen_range(32, 123) as u8 as char;
            self.code = new_code_vec.iter().fold("".to_string(), |acc, s| acc + &s.to_string());
            self.cost_score = cost_function(&self.code, &self.solution);
            self.clone()

        } else {
            self.clone()
        }

    }

}

fn main() {
    let solution = "The quick brown fox jumps over the lazy dog.".to_string();
    let pop_size = 30; // Must be greater than 1
    let max_pop = pop_size * 5;
    let mut_prob = 0.4;
    let kill_constant = 0.45;
    let cross_prob = 0.6;
    let mut population = Vec::new();

    // Initialize population
    for i in 0..pop_size {
        population.push(Chromosome::new(solution.to_string()));
        println!("{}, cost: {}", population[i].code, population[i].cost_score);
    }

    population.sort_by(|ref a, ref b| a.cost_score.cmp(&b.cost_score));
    let mut winner: Chromosome = population[0].clone();
    // Step generation
    let mut j = 1;
    while  winner.cost_score != 0 {

        // Mutations
        for i in 0..population.len() {
            population[i] = population[i].mutate(mut_prob);
        }

        // Kill the weaklings
        population.sort_by(|ref a, ref b| a.cost_score.cmp(&b.cost_score));
        for _ in 0..((( population.len() as f32)*kill_constant) as u32) {
            population.pop();
        }

        // Crossovers
        if population.len() < max_pop {
            for i in 0..(population.len() - 2) {
                let chrome1 = population[i].clone();
                let chrome2 = population[i+1].clone();
                population.push(crossover(chrome1, chrome2, cross_prob, &solution));
            }
        }

        population.sort_by(|ref a, ref b| a.cost_score.cmp(&b.cost_score));
        winner = population[0].clone();
        println!("\nGeneration: {}\nString: {}\nCost: {}\n", j, winner.code, winner.cost_score);

        j += 1;

    }

}
<commit_msg>Simplified cost_function<commit_after>// Genetic Algorithm for convergence to a given string
// Author: Duncan Dean
extern crate rand;
use rand::Rng;

fn rand_string(size: usize) -> String {
    return rand::thread_rng().gen_ascii_chars().take(size).collect();
}

fn crossover(chrome1: Chromosome, chrome2: Chromosome, cross_prob: f32, solution: &str) -> Chromosome {
    if rand::thread_rng().gen_range::<f32>(0.0, 1.0) <= cross_prob {
        let code_len = chrome1.code.len();
        let rand_index = rand::thread_rng().gen_range(0, code_len);
        let first_half = &chrome1.code[0..rand_index];
        let second_half = &chrome2.code[rand_index..code_len];
        let new_code = first_half.to_string() + second_half;
        Chromosome {
            code: new_code.to_string(),
            cost_score: cost_function(&new_code, solution),
            solution: solution.to_string(),
        }
    } else if chrome1.cost_score < chrome2.cost_score {
        chrome1.clone()
    } else {
        chrome2.clone()
    }
}

fn cost_function(code: &str, solution: &str) -> u32 {
    let chars = solution.as_bytes();
    let code_chars = code.as_bytes();
    let mut cost: u32 = 0;
    for i in 0..chars.len() {
        cost += ((chars[i] as i32) - (code_chars[i] as i32)).abs() as u32;
    }
    return cost;
}

#[derive(Clone)]
struct Chromosome {
    code: String,
    cost_score: u32,
    solution: String,
}

impl Chromosome {
    fn new(solution: String) -> Chromosome {
        let random_string = rand_string(solution.len());
        Chromosome {
            code: random_string.clone(),
            cost_score: cost_function(&random_string, &solution),
            solution: solution,
        }
    }

    fn mutate(&mut self, mut_prob:f64) -> Chromosome {
        if rand::thread_rng().gen_range::<f64>(0.0, 1.0) <= mut_prob {
            let rand_index = rand::thread_rng().gen_range(0, self.code.len());
            let mut new_code_vec: Vec<char> = self.code.chars().collect();
            new_code_vec[rand_index] = rand::thread_rng().gen_range(32, 123) as u8 as char;
            self.code = new_code_vec.iter().fold("".to_string(), |acc, s| acc + &s.to_string());
            self.cost_score = cost_function(&self.code, &self.solution);
            self.clone()

        } else {
            self.clone()
        }

    }

}

fn main() {
    let solution = "The quick brown fox jumps over the lazy dog.".to_string();
    let pop_size = 30; // Must be greater than 1
    let max_pop = pop_size * 5;
    let mut_prob = 0.4;
    let kill_constant = 0.45;
    let cross_prob = 0.6;
    let mut population = Vec::new();

    // Initialize population
    for i in 0..pop_size {
        population.push(Chromosome::new(solution.to_string()));
        println!("{}, cost: {}", population[i].code, population[i].cost_score);
    }

    population.sort_by(|ref a, ref b| a.cost_score.cmp(&b.cost_score));
    let mut winner: Chromosome = population[0].clone();
    // Step generation
    let mut j = 1;
    while  winner.cost_score != 0 {

        // Mutations
        for i in 0..population.len() {
            population[i] = population[i].mutate(mut_prob);
        }

        // Kill the weaklings
        population.sort_by(|ref a, ref b| a.cost_score.cmp(&b.cost_score));
        for _ in 0..((( population.len() as f32)*kill_constant) as u32) {
            population.pop();
        }

        // Crossovers
        if population.len() < max_pop {
            for i in 0..(population.len() - 2) {
                let chrome1 = population[i].clone();
                let chrome2 = population[i+1].clone();
                population.push(crossover(chrome1, chrome2, cross_prob, &solution));
            }
        }

        population.sort_by(|ref a, ref b| a.cost_score.cmp(&b.cost_score));
        winner = population[0].clone();
        println!("\nGeneration: {}\nString: {}\nCost: {}\n", j, winner.code, winner.cost_score);

        j += 1;

    }

}
<|endoftext|>