<commit_before>pub mod bldr;
pub mod cli;
pub mod config;
pub mod file;
pub mod license;
pub mod origin;
pub mod pkg;
pub mod plan;
pub mod ring;
pub mod studio;
pub mod sup;
pub mod svc;
#[cfg(test)]
mod tests;
pub mod user;
pub mod util;

use self::{bldr::*,
           cli::{CliCompleters,
                 CliSetup,
                 ConfigOptCliCompleters,
                 ConfigOptCliSetup},
           config::{ConfigOptServiceConfigApply,
                    ConfigOptServiceConfigShow,
                    ServiceConfigApply,
                    ServiceConfigShow},
           file::{ConfigOptFileUpload,
                  FileUpload},
           license::{ConfigOptLicense,
                     License},
           origin::*,
           pkg::*,
           plan::{ConfigOptPlanInit,
                  ConfigOptPlanRender,
                  PlanInit,
                  PlanRender},
           ring::{ConfigOptRingKeyExport,
                  ConfigOptRingKeyGenerate,
                  ConfigOptRingKeyImport,
                  RingKeyExport,
                  RingKeyGenerate,
                  RingKeyImport},
           studio::{ConfigOptStudio,
                    Studio},
           sup::{ConfigOptHabSup,
                 ConfigOptSupRun,
                 HabSup,
                 SupRun},
           svc::{ConfigOptSvc,
                 ConfigOptSvcStart,
                 ConfigOptSvcStop,
                 Svc,
                 SvcStart,
                 SvcStop},
           user::{ConfigOptUserKeyGenerate,
                  UserKeyGenerate},
           util::{CacheKeyPath,
                  ConfigOptCacheKeyPath}};
use crate::{cli::AFTER_HELP,
            VERSION};
use configopt::ConfigOpt;
use structopt::{clap::AppSettings,
                StructOpt};

#[derive(ConfigOpt, StructOpt)]
#[structopt(name = "hab",
            version = VERSION,
            about = "Patents: https://chef.io/patents\n\"A Habitat is the natural environment for your services\" - Alan Turing",
            author = "\nThe Habitat Maintainers <humans@habitat.sh>\n",
            settings = &[AppSettings::GlobalVersion],
            after_help = AFTER_HELP
        )]
#[allow(clippy::large_enum_variant)]
pub enum Hab {
    #[structopt(no_version)]
    Bldr(Bldr),
    #[structopt(no_version)]
    Cli(Cli),
    #[structopt(no_version)]
    Config(ServiceConfig),
    #[structopt(no_version)]
    File(File),
    #[structopt(no_version, settings = &[AppSettings::ArgRequiredElseHelp, AppSettings::SubcommandRequiredElseHelp])]
    License(License),
    #[structopt(no_version)]
    Origin(Origin),
    #[structopt(no_version)]
    Pkg(Pkg),
    #[structopt(no_version)]
    Plan(Plan),
    #[structopt(no_version)]
    Ring(Ring),
    #[structopt(no_version, aliases = &["stu", "stud", "studi"])]
    Studio(Studio),
    #[structopt(no_version)]
    Sup(HabSup),
    /// Create a tarball of Habitat Supervisor data to send to support
    #[structopt(no_version)]
    Supportbundle,
    #[structopt(no_version)]
    Svc(Svc),
    #[structopt(no_version)]
    User(User),

    /// Alias for 'config apply'
    #[structopt(no_version, settings = &[AppSettings::Hidden])]
    Apply(ServiceConfigApply),
    /// Alias for 'pkg install'
    #[structopt(no_version, settings = &[AppSettings::Hidden], aliases = &["i", "in", "ins", "inst", "insta", "instal"])]
    Install(PkgInstall),
    #[cfg(not(target_os = "macos"))]
    /// Alias for 'sup run'
    #[structopt(no_version, settings = &[AppSettings::Hidden])]
    Run(SupRun),
    /// Alias for 'cli setup'
    #[structopt(no_version, settings = &[AppSettings::Hidden], aliases = &["set", "setu"])]
    Setup(CacheKeyPath),
    /// Alias for 'svc start'
    #[structopt(no_version, settings = &[AppSettings::Hidden], aliases = &["sta", "star"])]
    Start(SvcStart),
    /// Alias for 'svc stop'
    #[structopt(no_version, settings = &[AppSettings::Hidden], aliases = &["sto"])]
    Stop(SvcStop),
    #[cfg(not(target_os = "macos"))]
    /// Alias for 'sup term'
    #[structopt(no_version, settings = &[AppSettings::Hidden])]
    Term,
}

#[derive(ConfigOpt, StructOpt)]
#[structopt(no_version, aliases = &["b", "bl", "bld"], settings = &[AppSettings::ArgRequiredElseHelp, AppSettings::SubcommandRequiredElseHelp])]
/// Commands relating to Habitat Builder
pub enum Bldr {
    #[structopt(no_version)]
    Channel(Channel),
    #[structopt(no_version)]
    Job(Job),
}

#[derive(ConfigOpt, StructOpt)]
#[structopt(no_version, aliases = &["c", "ch", "cha", "chan", "chann", "channe"], settings = &[AppSettings::ArgRequiredElseHelp, AppSettings::SubcommandRequiredElseHelp])]
/// Commands relating to Habitat Builder channels
pub enum Channel {
    #[structopt(no_version, aliases = &["c", "cr", "cre", "crea", "creat"])]
    Create(ChannelCreate),
    Demote(ChannelDemote),
    #[structopt(no_version, aliases = &["d", "de", "des", "dest", "destr", "destro"])]
    Destroy(ChannelDestroy),
    #[structopt(no_version, aliases = &["l", "li", "lis"])]
    List(ChannelList),
    Promote(ChannelPromote),
}

#[derive(ConfigOpt, StructOpt)]
#[structopt(no_version, aliases = &["j", "jo"], settings = &[AppSettings::ArgRequiredElseHelp, AppSettings::SubcommandRequiredElseHelp])]
/// Commands relating to Habitat Builder jobs
pub enum Job {
    #[structopt(no_version, aliases = &["c", "ca", "can", "cance", "cancel"])]
    Cancel(JobCancel),
    #[structopt(no_version, aliases = &["d", "de", "dem", "demo", "demot"])]
    Demote(JobDemote),
    #[structopt(no_version, aliases = &["p", "pr", "pro", "prom", "promo", "promot"])]
    Promote(JobPromote),
    #[structopt(no_version, aliases = &["s", "st", "sta", "star"])]
    Start(JobStart),
    #[structopt(no_version, aliases = &["stat", "statu"])]
    Status(JobStatus),
}

#[derive(ConfigOpt, StructOpt)]
#[structopt(no_version, aliases = &["cl"], settings = &[AppSettings::ArgRequiredElseHelp, AppSettings::SubcommandRequiredElseHelp])]
/// Commands relating to Habitat runtime config
pub enum Cli {
    #[structopt(no_version, aliases = &["s", "se", "set", "setu"])]
    /// Sets up the CLI with reasonable defaults
    Setup(CliSetup),
    #[structopt(no_version, aliases = &["c", "co", "com", "comp"])]
    /// Creates command-line completers for your shell
    Completers(CliCompleters),
}

#[derive(ConfigOpt, StructOpt)]
#[structopt(no_version, aliases = &["co", "con", "conf", "confi"], settings = &[AppSettings::ArgRequiredElseHelp, AppSettings::SubcommandRequiredElseHelp])]
/// Commands relating to a Service's runtime config
pub enum ServiceConfig {
    #[structopt(no_version, aliases = &["ap", "app", "appl"])]
    Apply(ServiceConfigApply),
    #[structopt(no_version, aliases = &["sh", "sho"])]
    Show(ServiceConfigShow),
}

#[derive(ConfigOpt, StructOpt)]
#[structopt(no_version, aliases = &["f", "fi", "fil"], settings = &[AppSettings::ArgRequiredElseHelp, AppSettings::SubcommandRequiredElseHelp])]
/// Commands relating to Habitat files
pub enum File {
    #[structopt(no_version, aliases = &["u", "up", "upl", "uplo", "uploa"])]
    /// Uploads a file to be shared between members of a Service Group
    Upload(FileUpload),
}

/// Commands relating to Habitat users
#[derive(ConfigOpt, StructOpt)]
#[structopt(name = "user", no_version, aliases = &["u", "us", "use"], settings = &[AppSettings::ArgRequiredElseHelp, AppSettings::SubcommandRequiredElseHelp])]
pub enum User {
    Key(UserKey),
}

#[derive(ConfigOpt, StructOpt)]
#[structopt(name = "key", no_version, aliases = &["k", "ke"], settings = &[AppSettings::ArgRequiredElseHelp, AppSettings::SubcommandRequiredElseHelp])]
/// Commands relating to Habitat user keys
pub enum UserKey {
    #[structopt(no_version, aliases = &["g", "ge", "gen", "gene", "gener", "genera", "generat"])]
    Generate(UserKeyGenerate),
}

#[derive(ConfigOpt, StructOpt)]
#[structopt(no_version, aliases = &["o", "or", "ori", "orig", "origi"], settings = &[AppSettings::ArgRequiredElseHelp, AppSettings::SubcommandRequiredElseHelp])]
/// Commands relating to Habitat Builder origins
pub enum Origin {
    #[structopt(no_version, aliases = &["cre", "crea"])]
    Create(OriginCreate),
    #[structopt(no_version, aliases = &["del", "dele"])]
    Delete(OriginDelete),
    Depart(OriginDepart),
    Info(OriginInfo),
    Invitations(OriginInvitations),
    Key(OriginKey),
    /// Role Based Access Control for origin members
    Rbac(Rbac),
    Secret(OriginSecret),
    Transfer(OriginTransfer),
}

#[derive(ConfigOpt, StructOpt)]
#[structopt(no_version, settings = &[AppSettings::ArgRequiredElseHelp, AppSettings::SubcommandRequiredElseHelp])]
/// Manage origin member invitations
pub enum OriginInvitations {
    Accept(InvitationsAccept),
    Ignore(InvitationsIgnore),
    List(InvitationsList),
    Pending(InvitationsPending),
    Rescind(InvitationsRescind),
    Send(InvitationsSend),
}

#[derive(ConfigOpt, StructOpt)]
#[structopt(name = "key", no_version, aliases = &["k", "ke"], settings = &[AppSettings::ArgRequiredElseHelp, AppSettings::SubcommandRequiredElseHelp])]
/// Commands relating to Habitat origin key maintenance
pub enum OriginKey {
    #[structopt(no_version, aliases = &["d", "do", "dow", "down", "downl", "downlo", "downloa"])]
    Download(OriginKeyDownload),
    #[structopt(no_version, aliases = &["e", "ex", "exp", "expo", "expor"])]
    Export(OriginKeyExport),
    #[structopt(no_version, aliases = &["g", "ge", "gen", "gene", "gener", "genera", "generat"])]
    Generate(OriginKeyGenerate),
    #[structopt(no_version, aliases = &["i", "im", "imp", "impo", "impor"])]
    Import(OriginKeyImport),
    #[structopt(no_version, aliases = &["u", "up", "upl", "uplo", "uploa"])]
    Upload(OriginKeyUpload),
}

#[derive(ConfigOpt, StructOpt)]
#[structopt(name = "secret", no_version, settings = &[AppSettings::ArgRequiredElseHelp, AppSettings::SubcommandRequiredElseHelp])]
/// Commands related to secret management
pub enum OriginSecret {
    Delete(SecretDelete),
    List(SecretList),
    Upload(SecretUpload),
}

#[derive(ConfigOpt, StructOpt)]
#[structopt(no_version, aliases = &["p", "pk", "package"], settings = &[AppSettings::ArgRequiredElseHelp, AppSettings::SubcommandRequiredElseHelp])]
/// Commands relating to Habitat packages
pub enum Pkg {
    Binds(PkgBinds),
    #[structopt(no_version, aliases = &["bi", "bin", "binl", "binli", "binlin"])]
    Binlink(PkgBinlink),
    #[structopt(no_version)]
    Build(PkgBuild),
    #[structopt(no_version, aliases = &["conf", "cfg"])]
    Config(PkgConfig),
    Download(PkgDownload),
    Env(PkgEnv),
    Exec(PkgExec),
    Export(ExportCommand),
    #[structopt(no_version, aliases = &["ha", "has"])]
    Hash(PkgHash),
    #[structopt(no_version, aliases = &["i", "in", "ins", "inst", "insta", "instal"])]
    Install(PkgInstall),
    #[structopt(no_version, aliases = &["p", "pa", "pat"])]
    Path(PkgPath),
    #[structopt(no_version, aliases = &["li"])]
    List(PkgList),
    Provides(PkgProvides),
    Search(PkgSearch),
    #[structopt(no_version, aliases = &["s", "si", "sig"])]
    Sign(PkgSign),
    #[structopt(no_version, aliases = &["un", "unin"])]
    Uninstall(PkgUninstall),
    #[structopt(no_version, aliases = &["bul", "bulk"])]
    Bulkupload(PkgBulkupload),
    #[structopt(no_version, aliases = &["u", "up", "upl", "uplo", "uploa"])]
    Upload(PkgUpload),
    #[structopt(no_version, aliases = &["del", "dele"])]
    Delete(PkgDelete),
    #[structopt(no_version, aliases = &["pr", "pro", "promo", "promot"])]
    Promote(PkgPromote),
    #[structopt(no_version, aliases = &["de", "dem", "demo", "demot"])]
    Demote(PkgDemote),
    #[structopt(no_version, aliases = &["ch", "cha", "chan", "chann", "channe", "channel"])]
    Channels(PkgChannels),
    #[structopt(no_version, aliases = &["v", "ve", "ver", "veri", "verif"])]
    Verify(PkgVerify),
    #[structopt(no_version, aliases = &["hea", "head", "heade", "header"])]
    Header(PkgHeader),
    #[structopt(no_version, aliases = &["inf", "info"])]
    Info(PkgInfo),
    #[structopt(no_version, aliases = &["dep", "deps"])]
    Dependencies(PkgDependencies),
}

#[derive(ConfigOpt, StructOpt)]
#[structopt(no_version, aliases = &["pl", "pla"], settings = &[AppSettings::ArgRequiredElseHelp, AppSettings::SubcommandRequiredElseHelp])]
/// Commands relating to plans and other app-specific configuration
pub enum Plan {
    #[structopt(no_version, aliases = &["i", "in", "ini"])]
    Init(PlanInit),
    #[structopt(no_version, aliases = &["r", "re", "ren", "rend", "rende"])]
    Render(PlanRender),
}

#[derive(ConfigOpt, StructOpt)]
#[structopt(no_version, aliases = &["r", "ri", "rin"], settings = &[AppSettings::ArgRequiredElseHelp, AppSettings::SubcommandRequiredElseHelp])]
/// Commands relating to Habitat rings
pub enum Ring {
    Key(RingKey),
}

#[derive(ConfigOpt, StructOpt)]
#[structopt(name = "key", no_version, aliases = &["k", "ke"], settings = &[AppSettings::ArgRequiredElseHelp, AppSettings::SubcommandRequiredElseHelp])]
/// Commands relating to Habitat ring keys
pub enum RingKey {
    #[structopt(no_version, aliases = &["e", "ex", "exp", "expo", "expor"])]
    Export(RingKeyExport),
    #[structopt(no_version, aliases = &["i", "im", "imp", "impo", "impor"])]
    Import(RingKeyImport),
    #[structopt(no_version, aliases = &["g", "ge", "gen", "gene", "gener", "genera", "generat"])]
    Generate(RingKeyGenerate),
}
<commit_msg>remove some unnecesary aliases<commit_after>pub mod bldr;
pub mod cli;
pub mod config;
pub mod file;
pub mod license;
pub mod origin;
pub mod pkg;
pub mod plan;
pub mod ring;
pub mod studio;
pub mod sup;
pub mod svc;
#[cfg(test)]
mod tests;
pub mod user;
pub mod util;

use self::{bldr::*,
           cli::{CliCompleters,
                 CliSetup,
                 ConfigOptCliCompleters,
                 ConfigOptCliSetup},
           config::{ConfigOptServiceConfigApply,
                    ConfigOptServiceConfigShow,
                    ServiceConfigApply,
                    ServiceConfigShow},
           file::{ConfigOptFileUpload,
                  FileUpload},
           license::{ConfigOptLicense,
                     License},
           origin::*,
           pkg::*,
           plan::{ConfigOptPlanInit,
                  ConfigOptPlanRender,
                  PlanInit,
                  PlanRender},
           ring::{ConfigOptRingKeyExport,
                  ConfigOptRingKeyGenerate,
                  ConfigOptRingKeyImport,
                  RingKeyExport,
                  RingKeyGenerate,
                  RingKeyImport},
           studio::{ConfigOptStudio,
                    Studio},
           sup::{ConfigOptHabSup,
                 ConfigOptSupRun,
                 HabSup,
                 SupRun},
           svc::{ConfigOptSvc,
                 ConfigOptSvcStart,
                 ConfigOptSvcStop,
                 Svc,
                 SvcStart,
                 SvcStop},
           user::{ConfigOptUserKeyGenerate,
                  UserKeyGenerate},
           util::{CacheKeyPath,
                  ConfigOptCacheKeyPath}};
use crate::{cli::AFTER_HELP,
            VERSION};
use configopt::ConfigOpt;
use structopt::{clap::AppSettings,
                StructOpt};

#[derive(ConfigOpt, StructOpt)]
#[structopt(name = "hab",
            version = VERSION,
            about = "Patents: https://chef.io/patents\n\"A Habitat is the natural environment for your services\" - Alan Turing",
            author = "\nThe Habitat Maintainers <humans@habitat.sh>\n",
            settings = &[AppSettings::GlobalVersion],
            after_help = AFTER_HELP
        )]
#[allow(clippy::large_enum_variant)]
pub enum Hab {
    #[structopt(no_version)]
    Bldr(Bldr),
    #[structopt(no_version)]
    Cli(Cli),
    #[structopt(no_version)]
    Config(ServiceConfig),
    #[structopt(no_version)]
    File(File),
    #[structopt(no_version, settings = &[AppSettings::ArgRequiredElseHelp, AppSettings::SubcommandRequiredElseHelp])]
    License(License),
    #[structopt(no_version)]
    Origin(Origin),
    #[structopt(no_version)]
    Pkg(Pkg),
    #[structopt(no_version)]
    Plan(Plan),
    #[structopt(no_version)]
    Ring(Ring),
    #[structopt(no_version, aliases = &["stu", "stud", "studi"])]
    Studio(Studio),
    #[structopt(no_version)]
    Sup(HabSup),
    /// Create a tarball of Habitat Supervisor data to send to support
    #[structopt(no_version)]
    Supportbundle,
    #[structopt(no_version)]
    Svc(Svc),
    #[structopt(no_version)]
    User(User),

    /// Alias for 'config apply'
    #[structopt(no_version, settings = &[AppSettings::Hidden])]
    Apply(ServiceConfigApply),
    /// Alias for 'pkg install'
    #[structopt(no_version, settings = &[AppSettings::Hidden], aliases = &["i", "in", "ins", "inst", "insta", "instal"])]
    Install(PkgInstall),
    #[cfg(not(target_os = "macos"))]
    /// Alias for 'sup run'
    #[structopt(no_version, settings = &[AppSettings::Hidden])]
    Run(SupRun),
    /// Alias for 'cli setup'
    #[structopt(no_version, settings = &[AppSettings::Hidden], aliases = &["set", "setu"])]
    Setup(CacheKeyPath),
    /// Alias for 'svc start'
    #[structopt(no_version, settings = &[AppSettings::Hidden], aliases = &["sta", "star"])]
    Start(SvcStart),
    /// Alias for 'svc stop'
    #[structopt(no_version, settings = &[AppSettings::Hidden], aliases = &["sto"])]
    Stop(SvcStop),
    #[cfg(not(target_os = "macos"))]
    /// Alias for 'sup term'
    #[structopt(no_version, settings = &[AppSettings::Hidden])]
    Term,
}

#[derive(ConfigOpt, StructOpt)]
#[structopt(no_version, aliases = &["b", "bl", "bld"], settings = &[AppSettings::ArgRequiredElseHelp, AppSettings::SubcommandRequiredElseHelp])]
/// Commands relating to Habitat Builder
pub enum Bldr {
    #[structopt(no_version)]
    Channel(Channel),
    #[structopt(no_version)]
    Job(Job),
}

#[derive(ConfigOpt, StructOpt)]
#[structopt(no_version, aliases = &["c", "ch", "cha", "chan", "chann", "channe"], settings = &[AppSettings::ArgRequiredElseHelp, AppSettings::SubcommandRequiredElseHelp])]
/// Commands relating to Habitat Builder channels
pub enum Channel {
    #[structopt(no_version, aliases = &["c", "cr", "cre", "crea", "creat"])]
    Create(ChannelCreate),
    Demote(ChannelDemote),
    #[structopt(no_version, aliases = &["d", "de", "des", "dest", "destr", "destro"])]
    Destroy(ChannelDestroy),
    #[structopt(no_version, aliases = &["l", "li", "lis"])]
    List(ChannelList),
    Promote(ChannelPromote),
}

#[derive(ConfigOpt, StructOpt)]
#[structopt(no_version, aliases = &["j", "jo"], settings = &[AppSettings::ArgRequiredElseHelp, AppSettings::SubcommandRequiredElseHelp])]
/// Commands relating to Habitat Builder jobs
pub enum Job {
    #[structopt(no_version, aliases = &["c", "ca", "can", "cance"])]
    Cancel(JobCancel),
    #[structopt(no_version, aliases = &["d", "de", "dem", "demo", "demot"])]
    Demote(JobDemote),
    #[structopt(no_version, aliases = &["p", "pr", "pro", "prom", "promo", "promot"])]
    Promote(JobPromote),
    #[structopt(no_version, aliases = &["s", "st", "sta", "star"])]
    Start(JobStart),
    #[structopt(no_version, aliases = &["stat", "statu"])]
    Status(JobStatus),
}

#[derive(ConfigOpt, StructOpt)]
#[structopt(no_version, aliases = &["cl"], settings = &[AppSettings::ArgRequiredElseHelp, AppSettings::SubcommandRequiredElseHelp])]
/// Commands relating to Habitat runtime config
pub enum Cli {
    #[structopt(no_version, aliases = &["s", "se", "set", "setu"])]
    /// Sets up the CLI with reasonable defaults
    Setup(CliSetup),
    #[structopt(no_version, aliases = &["c", "co", "com", "comp"])]
    /// Creates command-line completers for your shell
    Completers(CliCompleters),
}

#[derive(ConfigOpt, StructOpt)]
#[structopt(no_version, aliases = &["co", "con", "conf", "confi"], settings = &[AppSettings::ArgRequiredElseHelp, AppSettings::SubcommandRequiredElseHelp])]
/// Commands relating to a Service's runtime config
pub enum ServiceConfig {
    #[structopt(no_version, aliases = &["ap", "app", "appl"])]
    Apply(ServiceConfigApply),
    #[structopt(no_version, aliases = &["sh", "sho"])]
    Show(ServiceConfigShow),
}

#[derive(ConfigOpt, StructOpt)]
#[structopt(no_version, aliases = &["f", "fi", "fil"], settings = &[AppSettings::ArgRequiredElseHelp, AppSettings::SubcommandRequiredElseHelp])]
/// Commands relating to Habitat files
pub enum File {
    #[structopt(no_version, aliases = &["u", "up", "upl", "uplo", "uploa"])]
    /// Uploads a file to be shared between members of a Service Group
    Upload(FileUpload),
}

/// Commands relating to Habitat users
#[derive(ConfigOpt, StructOpt)]
#[structopt(name = "user", no_version, aliases = &["u", "us", "use"], settings = &[AppSettings::ArgRequiredElseHelp, AppSettings::SubcommandRequiredElseHelp])]
pub enum User {
    Key(UserKey),
}

#[derive(ConfigOpt, StructOpt)]
#[structopt(name = "key", no_version, aliases = &["k", "ke"], settings = &[AppSettings::ArgRequiredElseHelp, AppSettings::SubcommandRequiredElseHelp])]
/// Commands relating to Habitat user keys
pub enum UserKey {
    #[structopt(no_version, aliases = &["g", "ge", "gen", "gene", "gener", "genera", "generat"])]
    Generate(UserKeyGenerate),
}

#[derive(ConfigOpt, StructOpt)]
#[structopt(no_version, aliases = &["o", "or", "ori", "orig", "origi"], settings = &[AppSettings::ArgRequiredElseHelp, AppSettings::SubcommandRequiredElseHelp])]
/// Commands relating to Habitat Builder origins
pub enum Origin {
    #[structopt(no_version, aliases = &["cre", "crea"])]
    Create(OriginCreate),
    #[structopt(no_version, aliases = &["del", "dele"])]
    Delete(OriginDelete),
    Depart(OriginDepart),
    Info(OriginInfo),
    Invitations(OriginInvitations),
    Key(OriginKey),
    /// Role Based Access Control for origin members
    Rbac(Rbac),
    Secret(OriginSecret),
    Transfer(OriginTransfer),
}

#[derive(ConfigOpt, StructOpt)]
#[structopt(no_version, settings = &[AppSettings::ArgRequiredElseHelp, AppSettings::SubcommandRequiredElseHelp])]
/// Manage origin member invitations
pub enum OriginInvitations {
    Accept(InvitationsAccept),
    Ignore(InvitationsIgnore),
    List(InvitationsList),
    Pending(InvitationsPending),
    Rescind(InvitationsRescind),
    Send(InvitationsSend),
}

#[derive(ConfigOpt, StructOpt)]
#[structopt(name = "key", no_version, aliases = &["k", "ke"], settings = &[AppSettings::ArgRequiredElseHelp, AppSettings::SubcommandRequiredElseHelp])]
/// Commands relating to Habitat origin key maintenance
pub enum OriginKey {
    #[structopt(no_version, aliases = &["d", "do", "dow", "down", "downl", "downlo", "downloa"])]
    Download(OriginKeyDownload),
    #[structopt(no_version, aliases = &["e", "ex", "exp", "expo", "expor"])]
    Export(OriginKeyExport),
    #[structopt(no_version, aliases = &["g", "ge", "gen", "gene", "gener", "genera", "generat"])]
    Generate(OriginKeyGenerate),
    #[structopt(no_version, aliases = &["i", "im", "imp", "impo", "impor"])]
    Import(OriginKeyImport),
    #[structopt(no_version, aliases = &["u", "up", "upl", "uplo", "uploa"])]
    Upload(OriginKeyUpload),
}

#[derive(ConfigOpt, StructOpt)]
#[structopt(name = "secret", no_version, settings = &[AppSettings::ArgRequiredElseHelp, AppSettings::SubcommandRequiredElseHelp])]
/// Commands related to secret management
pub enum OriginSecret {
    Delete(SecretDelete),
    List(SecretList),
    Upload(SecretUpload),
}

#[derive(ConfigOpt, StructOpt)]
#[structopt(no_version, aliases = &["p", "pk", "package"], settings = &[AppSettings::ArgRequiredElseHelp, AppSettings::SubcommandRequiredElseHelp])]
/// Commands relating to Habitat packages
pub enum Pkg {
    Binds(PkgBinds),
    #[structopt(no_version, aliases = &["bi", "bin", "binl", "binli", "binlin"])]
    Binlink(PkgBinlink),
    #[structopt(no_version)]
    Build(PkgBuild),
    #[structopt(no_version, aliases = &["conf", "cfg"])]
    Config(PkgConfig),
    Download(PkgDownload),
    Env(PkgEnv),
    Exec(PkgExec),
    Export(ExportCommand),
    #[structopt(no_version, aliases = &["ha", "has"])]
    Hash(PkgHash),
    #[structopt(no_version, aliases = &["i", "in", "ins", "inst", "insta", "instal"])]
    Install(PkgInstall),
    #[structopt(no_version, aliases = &["p", "pa", "pat"])]
    Path(PkgPath),
    #[structopt(no_version, aliases = &["li"])]
    List(PkgList),
    Provides(PkgProvides),
    Search(PkgSearch),
    #[structopt(no_version, aliases = &["s", "si", "sig"])]
    Sign(PkgSign),
    #[structopt(no_version, aliases = &["un", "unin"])]
    Uninstall(PkgUninstall),
    #[structopt(no_version, aliases = &["bul", "bulk"])]
    Bulkupload(PkgBulkupload),
    #[structopt(no_version, aliases = &["u", "up", "upl", "uplo", "uploa"])]
    Upload(PkgUpload),
    #[structopt(no_version, aliases = &["del", "dele"])]
    Delete(PkgDelete),
    #[structopt(no_version, aliases = &["pr", "pro", "promo", "promot"])]
    Promote(PkgPromote),
    #[structopt(no_version, aliases = &["de", "dem", "demo", "demot"])]
    Demote(PkgDemote),
    #[structopt(no_version, aliases = &["ch", "cha", "chan", "chann", "channe", "channel"])]
    Channels(PkgChannels),
    #[structopt(no_version, aliases = &["v", "ve", "ver", "veri", "verif"])]
    Verify(PkgVerify),
    #[structopt(no_version, aliases = &["hea", "head", "heade"])]
    Header(PkgHeader),
    #[structopt(no_version, aliases = &["inf"])]
    Info(PkgInfo),
    #[structopt(no_version, aliases = &["dep", "deps"])]
    Dependencies(PkgDependencies),
}

#[derive(ConfigOpt, StructOpt)]
#[structopt(no_version, aliases = &["pl", "pla"], settings = &[AppSettings::ArgRequiredElseHelp, AppSettings::SubcommandRequiredElseHelp])]
/// Commands relating to plans and other app-specific configuration
pub enum Plan {
    #[structopt(no_version, aliases = &["i", "in", "ini"])]
    Init(PlanInit),
    #[structopt(no_version, aliases = &["r", "re", "ren", "rend", "rende"])]
    Render(PlanRender),
}

#[derive(ConfigOpt, StructOpt)]
#[structopt(no_version, aliases = &["r", "ri", "rin"], settings = &[AppSettings::ArgRequiredElseHelp, AppSettings::SubcommandRequiredElseHelp])]
/// Commands relating to Habitat rings
pub enum Ring {
    Key(RingKey),
}

#[derive(ConfigOpt, StructOpt)]
#[structopt(name = "key", no_version, aliases = &["k", "ke"], settings = &[AppSettings::ArgRequiredElseHelp, AppSettings::SubcommandRequiredElseHelp])]
/// Commands relating to Habitat ring keys
pub enum RingKey {
    #[structopt(no_version, aliases = &["e", "ex", "exp", "expo", "expor"])]
    Export(RingKeyExport),
    #[structopt(no_version, aliases = &["i", "im", "imp", "impo", "impor"])]
    Import(RingKeyImport),
    #[structopt(no_version, aliases = &["g", "ge", "gen", "gene", "gener", "genera", "generat"])]
    Generate(RingKeyGenerate),
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use crate::dom::bindings::cell::{DomRefCell, Ref};
use crate::dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::root::{DomRoot, LayoutDom, MutNullableDom};
use crate::dom::bindings::str::DOMString;
use crate::dom::customelementregistry::CallbackReaction;
use crate::dom::document::Document;
use crate::dom::element::{AttributeMutation, Element};
use crate::dom::mutationobserver::{Mutation, MutationObserver};
use crate::dom::node::Node;
use crate::dom::virtualmethods::vtable_for;
use crate::script_thread::ScriptThread;
use devtools_traits::AttrInfo;
use dom_struct::dom_struct;
use html5ever::{LocalName, Namespace, Prefix};
use servo_atoms::Atom;
use std::borrow::ToOwned;
use std::mem;
use style::attr::{AttrIdentifier, AttrValue};

// https://dom.spec.whatwg.org/#interface-attr
#[dom_struct]
pub struct Attr {
    node_: Node,
    identifier: AttrIdentifier,
    value: DomRefCell<AttrValue>,

    /// the element that owns this attribute.
    owner: MutNullableDom<Element>,
}

impl Attr {
    fn new_inherited(
        document: &Document,
        local_name: LocalName,
        value: AttrValue,
        name: LocalName,
        namespace: Namespace,
        prefix: Option<Prefix>,
        owner: Option<&Element>,
    ) -> Attr {
        Attr {
            node_: Node::new_inherited(document),
            identifier: AttrIdentifier {
                local_name: local_name,
                name: name,
                namespace: namespace,
                prefix: prefix,
            },
            value: DomRefCell::new(value),
            owner: MutNullableDom::new(owner),
        }
    }

    pub fn new(
        document: &Document,
        local_name: LocalName,
        value: AttrValue,
        name: LocalName,
        namespace: Namespace,
        prefix: Option<Prefix>,
        owner: Option<&Element>,
    ) -> DomRoot<Attr> {
        Node::reflect_node(
            Box::new(Attr::new_inherited(
                document, local_name, value, name, namespace, prefix, owner,
            )),
            document,
        )
    }

    #[inline]
    pub fn name(&self) -> &LocalName {
        &self.identifier.name
    }

    #[inline]
    pub fn namespace(&self) -> &Namespace {
        &self.identifier.namespace
    }

    #[inline]
    pub fn prefix(&self) -> Option<&Prefix> {
        self.identifier.prefix.as_ref()
    }
}

impl AttrMethods for Attr {
    // https://dom.spec.whatwg.org/#dom-attr-localname
    fn LocalName(&self) -> DOMString {
        // FIXME(ajeffrey): convert directly from LocalName to DOMString
        DOMString::from(&**self.local_name())
    }

    // https://dom.spec.whatwg.org/#dom-attr-value
    fn Value(&self) -> DOMString {
        // FIXME(ajeffrey): convert directly from AttrValue to DOMString
        DOMString::from(&**self.value())
    }

    // https://dom.spec.whatwg.org/#dom-attr-value
    fn SetValue(&self, value: DOMString) {
        if let Some(owner) = self.owner() {
            let value = owner.parse_attribute(&self.identifier.namespace, self.local_name(), value);
            self.set_value(value, &owner);
        } else {
            *self.value.borrow_mut() = AttrValue::String(value.into());
        }
    }

    // https://dom.spec.whatwg.org/#dom-attr-name
    fn Name(&self) -> DOMString {
        // FIXME(ajeffrey): convert directly from LocalName to DOMString
        DOMString::from(&*self.identifier.name)
    }

    // https://dom.spec.whatwg.org/#dom-attr-namespaceuri
    fn GetNamespaceURI(&self) -> Option<DOMString> {
        match self.identifier.namespace {
            ns!() => None,
            ref url => Some(DOMString::from(&**url)),
        }
    }

    // https://dom.spec.whatwg.org/#dom-attr-prefix
    fn GetPrefix(&self) -> Option<DOMString> {
        // FIXME(ajeffrey): convert directly from LocalName to DOMString
        self.prefix().map(|p| DOMString::from(&**p))
    }

    // https://dom.spec.whatwg.org/#dom-attr-ownerelement
    fn GetOwnerElement(&self) -> Option<DomRoot<Element>> {
        self.owner()
    }

    // https://dom.spec.whatwg.org/#dom-attr-specified
    fn Specified(&self) -> bool {
        true // Always returns true
    }
}

impl Attr {
    pub fn set_value(&self, mut value: AttrValue, owner: &Element) {
        let name = self.local_name().clone();
        let namespace = self.namespace().clone();
        let old_value = DOMString::from(&**self.value());
        let new_value = DOMString::from(&*value);
        let mutation = Mutation::Attribute {
            name: name.clone(),
            namespace: namespace.clone(),
            old_value: Some(old_value.clone()),
        };

        MutationObserver::queue_a_mutation_record(owner.upcast::<Node>(), mutation);

        if owner.get_custom_element_definition().is_some() {
            let reaction = CallbackReaction::AttributeChanged(
                name,
                Some(old_value),
                Some(new_value),
                namespace,
            );
            ScriptThread::enqueue_callback_reaction(owner, reaction, None);
        }

        assert_eq!(Some(owner), self.owner().as_deref());
        owner.will_mutate_attr(self);
        self.swap_value(&mut value);
        if self.identifier.namespace == ns!() {
            vtable_for(owner.upcast())
                .attribute_mutated(self, AttributeMutation::Set(Some(&value)));
        }
    }

    /// Used to swap the attribute's value without triggering mutation events
    pub fn swap_value(&self, value: &mut AttrValue) {
        mem::swap(&mut *self.value.borrow_mut(), value);
    }

    pub fn identifier(&self) -> &AttrIdentifier {
        &self.identifier
    }

    pub fn value(&self) -> Ref<AttrValue> {
        self.value.borrow()
    }

    pub fn local_name(&self) -> &LocalName {
        &self.identifier.local_name
    }

    /// Sets the owner element. Should be called after the attribute is added
    /// or removed from its older parent.
    pub fn set_owner(&self, owner: Option<&Element>) {
        let ns = &self.identifier.namespace;
        match (self.owner(), owner) {
            (Some(old), None) => {
                // Already gone from the list of attributes of old owner.
                assert!(
                    old.get_attribute(&ns, &self.identifier.local_name)
                        .as_deref() !=
                        Some(self)
                )
            },
            (Some(old), Some(new)) => assert_eq!(&*old, new),
            _ => {},
        }
        self.owner.set(owner);
    }

    pub fn owner(&self) -> Option<DomRoot<Element>> {
        self.owner.get()
    }

    pub fn summarize(&self) -> AttrInfo {
        AttrInfo {
            namespace: (*self.identifier.namespace).to_owned(),
            name: String::from(self.Name()),
            value: String::from(self.Value()),
        }
    }

    pub fn qualified_name(&self) -> DOMString {
        match self.prefix() {
            Some(ref prefix) => DOMString::from(format!("{}:{}", prefix, &**self.local_name())),
            None => DOMString::from(&**self.local_name()),
        }
    }
}

#[allow(unsafe_code)]
pub trait AttrHelpersForLayout {
    unsafe fn value_forever(&self) -> &'static AttrValue;
    unsafe fn value_ref_forever(&self) -> &'static str;
    unsafe fn value_tokens_forever(&self) -> Option<&'static [Atom]>;
    unsafe fn local_name_atom_forever(&self) -> LocalName;
}

#[allow(unsafe_code)]
impl AttrHelpersForLayout for LayoutDom<'_, Attr> {
    #[inline]
    unsafe fn value_forever(&self) -> &'static AttrValue {
        // This transmute is used to cheat the lifetime restriction.
        mem::transmute::<&AttrValue, &AttrValue>((*self.unsafe_get()).value.borrow_for_layout())
    }

    #[inline]
    unsafe fn value_ref_forever(&self) -> &'static str {
        &**self.value_forever()
    }

    #[inline]
    unsafe fn value_tokens_forever(&self) -> Option<&'static [Atom]> {
        // This transmute is used to cheat the lifetime restriction.
        match *self.value_forever() {
            AttrValue::TokenList(_, ref tokens) => Some(tokens),
            _ => None,
        }
    }

    #[inline]
    unsafe fn local_name_atom_forever(&self) -> LocalName {
        (*self.unsafe_get()).identifier.local_name.clone()
    }
}
<commit_msg>Fix AttrHelpersForLayout<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use crate::dom::bindings::cell::{DomRefCell, Ref};
use crate::dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::root::{DomRoot, LayoutDom, MutNullableDom};
use crate::dom::bindings::str::DOMString;
use crate::dom::customelementregistry::CallbackReaction;
use crate::dom::document::Document;
use crate::dom::element::{AttributeMutation, Element};
use crate::dom::mutationobserver::{Mutation, MutationObserver};
use crate::dom::node::Node;
use crate::dom::virtualmethods::vtable_for;
use crate::script_thread::ScriptThread;
use devtools_traits::AttrInfo;
use dom_struct::dom_struct;
use html5ever::{LocalName, Namespace, Prefix};
use servo_atoms::Atom;
use std::borrow::ToOwned;
use std::mem;
use style::attr::{AttrIdentifier, AttrValue};

// https://dom.spec.whatwg.org/#interface-attr
#[dom_struct]
pub struct Attr {
    node_: Node,
    identifier: AttrIdentifier,
    value: DomRefCell<AttrValue>,

    /// the element that owns this attribute.
    owner: MutNullableDom<Element>,
}

impl Attr {
    fn new_inherited(
        document: &Document,
        local_name: LocalName,
        value: AttrValue,
        name: LocalName,
        namespace: Namespace,
        prefix: Option<Prefix>,
        owner: Option<&Element>,
    ) -> Attr {
        Attr {
            node_: Node::new_inherited(document),
            identifier: AttrIdentifier {
                local_name: local_name,
                name: name,
                namespace: namespace,
                prefix: prefix,
            },
            value: DomRefCell::new(value),
            owner: MutNullableDom::new(owner),
        }
    }

    pub fn new(
        document: &Document,
        local_name: LocalName,
        value: AttrValue,
        name: LocalName,
        namespace: Namespace,
        prefix: Option<Prefix>,
        owner: Option<&Element>,
    ) -> DomRoot<Attr> {
        Node::reflect_node(
            Box::new(Attr::new_inherited(
                document, local_name, value, name, namespace, prefix, owner,
            )),
            document,
        )
    }

    #[inline]
    pub fn name(&self) -> &LocalName {
        &self.identifier.name
    }

    #[inline]
    pub fn namespace(&self) -> &Namespace {
        &self.identifier.namespace
    }

    #[inline]
    pub fn prefix(&self) -> Option<&Prefix> {
        self.identifier.prefix.as_ref()
    }
}

impl AttrMethods for Attr {
    // https://dom.spec.whatwg.org/#dom-attr-localname
    fn LocalName(&self) -> DOMString {
        // FIXME(ajeffrey): convert directly from LocalName to DOMString
        DOMString::from(&**self.local_name())
    }

    // https://dom.spec.whatwg.org/#dom-attr-value
    fn Value(&self) -> DOMString {
        // FIXME(ajeffrey): convert directly from AttrValue to DOMString
        DOMString::from(&**self.value())
    }

    // https://dom.spec.whatwg.org/#dom-attr-value
    fn SetValue(&self, value: DOMString) {
        if let Some(owner) = self.owner() {
            let value = owner.parse_attribute(&self.identifier.namespace, self.local_name(), value);
            self.set_value(value, &owner);
        } else {
            *self.value.borrow_mut() = AttrValue::String(value.into());
        }
    }

    // https://dom.spec.whatwg.org/#dom-attr-name
    fn Name(&self) -> DOMString {
        // FIXME(ajeffrey): convert directly from LocalName to DOMString
        DOMString::from(&*self.identifier.name)
    }

    // https://dom.spec.whatwg.org/#dom-attr-namespaceuri
    fn GetNamespaceURI(&self) -> Option<DOMString> {
        match self.identifier.namespace {
            ns!() => None,
            ref url => Some(DOMString::from(&**url)),
        }
    }

    // https://dom.spec.whatwg.org/#dom-attr-prefix
    fn GetPrefix(&self) -> Option<DOMString> {
        // FIXME(ajeffrey): convert directly from LocalName to DOMString
        self.prefix().map(|p| DOMString::from(&**p))
    }

    // https://dom.spec.whatwg.org/#dom-attr-ownerelement
    fn GetOwnerElement(&self) -> Option<DomRoot<Element>> {
        self.owner()
    }

    // https://dom.spec.whatwg.org/#dom-attr-specified
    fn Specified(&self) -> bool {
        true // Always returns true
    }
}

impl Attr {
    pub fn set_value(&self, mut value: AttrValue, owner: &Element) {
        let name = self.local_name().clone();
        let namespace = self.namespace().clone();
        let old_value = DOMString::from(&**self.value());
        let new_value = DOMString::from(&*value);
        let mutation = Mutation::Attribute {
            name: name.clone(),
            namespace: namespace.clone(),
            old_value: Some(old_value.clone()),
        };

        MutationObserver::queue_a_mutation_record(owner.upcast::<Node>(), mutation);

        if owner.get_custom_element_definition().is_some() {
            let reaction = CallbackReaction::AttributeChanged(
                name,
                Some(old_value),
                Some(new_value),
                namespace,
            );
            ScriptThread::enqueue_callback_reaction(owner, reaction, None);
        }

        assert_eq!(Some(owner), self.owner().as_deref());
        owner.will_mutate_attr(self);
        self.swap_value(&mut value);
        if self.identifier.namespace == ns!() {
            vtable_for(owner.upcast())
                .attribute_mutated(self, AttributeMutation::Set(Some(&value)));
        }
    }

    /// Used to swap the attribute's value without triggering mutation events
    pub fn swap_value(&self, value: &mut AttrValue) {
        mem::swap(&mut *self.value.borrow_mut(), value);
    }

    pub fn identifier(&self) -> &AttrIdentifier {
        &self.identifier
    }

    pub fn value(&self) -> Ref<AttrValue> {
        self.value.borrow()
    }

    pub fn local_name(&self) -> &LocalName {
        &self.identifier.local_name
    }

    /// Sets the owner element. Should be called after the attribute is added
    /// or removed from its older parent.
    pub fn set_owner(&self, owner: Option<&Element>) {
        let ns = &self.identifier.namespace;
        match (self.owner(), owner) {
            (Some(old), None) => {
                // Already gone from the list of attributes of old owner.
                assert!(
                    old.get_attribute(&ns, &self.identifier.local_name)
                        .as_deref() !=
                        Some(self)
                )
            },
            (Some(old), Some(new)) => assert_eq!(&*old, new),
            _ => {},
        }
        self.owner.set(owner);
    }

    pub fn owner(&self) -> Option<DomRoot<Element>> {
        self.owner.get()
    }

    pub fn summarize(&self) -> AttrInfo {
        AttrInfo {
            namespace: (*self.identifier.namespace).to_owned(),
            name: String::from(self.Name()),
            value: String::from(self.Value()),
        }
    }

    pub fn qualified_name(&self) -> DOMString {
        match self.prefix() {
            Some(ref prefix) => DOMString::from(format!("{}:{}", prefix, &**self.local_name())),
            None => DOMString::from(&**self.local_name()),
        }
    }
}

#[allow(unsafe_code)]
pub trait AttrHelpersForLayout<'dom> {
    unsafe fn value_forever(self) -> &'dom AttrValue;
    unsafe fn value_ref_forever(self) -> &'dom str;
    unsafe fn value_tokens_forever(self) -> Option<&'dom [Atom]>;
    unsafe fn local_name_atom_forever(self) -> LocalName;
}

#[allow(unsafe_code)]
impl<'dom> AttrHelpersForLayout<'dom> for LayoutDom<'dom, Attr> {
    #[inline]
    unsafe fn value_forever(self) -> &'dom AttrValue {
        (*self.unsafe_get()).value.borrow_for_layout()
    }

    #[inline]
    unsafe fn value_ref_forever(self) -> &'dom str {
        &**self.value_forever()
    }

    #[inline]
    unsafe fn value_tokens_forever(self) -> Option<&'dom [Atom]> {
        // This transmute is used to cheat the lifetime restriction.
        match *self.value_forever() {
            AttrValue::TokenList(_, ref tokens) => Some(tokens),
            _ => None,
        }
    }

    #[inline]
    unsafe fn local_name_atom_forever(self) -> LocalName {
        (*self.unsafe_get()).identifier.local_name.clone()
    }
}
<|endoftext|>


<commit_before>use nom::{IResult, is_space};
use num_traits::One;
use std::fmt::Debug;
use std::marker::PhantomData;
use std::str::{FromStr, from_utf8};

use cfg::{CFG, CFGComposition, CFGRule, LetterT};
use util::parsing::*;

impl<N, T, W> FromStr for CFG<N, T, W>
    where N: FromStr,
          N::Err: Debug,
          T: Clone + FromStr,
          T::Err: Debug,
          W: FromStr + One,
          W::Err: Debug,
{
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let mut it = s.lines();
        let mut rules = Vec::new();
        let initial;

        match it.next() {
            Some(l) => {
                match parse_initials(l.as_bytes()) {
                    IResult::Done(_, result)
                        => initial = result,
                    _
                        => return Err(format!("Malformed declaration of initial nonterminals: \'{}\'", l))
                }
            },
            _ => return Err(String::from("Cannot parse an empty string as a CFG!"))
        }

        while let Some(l) = it.next() {
            if !l.is_empty() {
                rules.push(l.trim().parse()?);
            }
        }

        Ok(CFG {
            _dummy: PhantomData,
            initial,
            rules,
        })
    }
}

impl<N, T, W> FromStr for CFGRule<N, T, W>
    where N: FromStr,
          N::Err: Debug,
          T: Clone + FromStr,
          T::Err: Debug,
          W: FromStr + One,
          W::Err: Debug,
{
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match parse_cfg_rule(s.as_bytes()) {
            IResult::Done(_, result) => Ok(result),
            _                        => Err(format!("Could not parse \'{}\'", s))
        }
    }
}

fn parse_cfg_rule<N, T, W>(input: &[u8]) -> IResult<&[u8], CFGRule<N, T, W>>
    where N: FromStr,
          N::Err: Debug,
          T: FromStr,
          T::Err: Debug,
          W: FromStr + One,
          W::Err: Debug,
{
    do_parse!(
        input,
        head: parse_token >>
        take_while!(is_space) >>
        alt!(tag!("→") | tag!("->") | tag!("=>")) >>
        take_while!(is_space) >>
        composition: parse_composition >>
        take_while!(is_space) >>
        weight_o: opt!(
            complete!(
                do_parse!(
                    tag!("#") >>
                    take_while!(is_space) >>
                    weight_s: map_res!(is_not!(" "), from_utf8) >>
                    weight: expr_res!(weight_s.parse()) >>
                    (weight)
                )
            )
        ) >>
        take_while!(is_space) >>
        alt!(
            eof!() |
            preceded!(tag!("%"), take_while!(|_| true))
        ) >>
        (CFGRule {
            head: head,
            composition: CFGComposition { composition: composition },
            weight: weight_o.unwrap_or(W::one()),
        })
    )
}

fn parse_letter_t<N, T>(input: &[u8]) -> IResult<&[u8], LetterT<N,T>>
    where N: FromStr,
          N::Err: Debug,
          T: FromStr,
          T::Err: Debug,
{
    do_parse!(
        input,
        result: alt!(
            do_parse!(
                tag!("Nt") >>
                take_while!(is_space) >>
                token: parse_token >>
                (LetterT::Label(token))
            ) |
            do_parse!(
                tag!("T") >>
                take_while!(is_space) >>
                token: parse_token >>
                (LetterT::Value(token))
            )
        ) >>
        (result)
    )
}

fn parse_composition<N, T>(input: &[u8]) -> IResult<&[u8], Vec<LetterT<N,T>>>
    where N: FromStr,
          N::Err: Debug,
          T: FromStr,
          T::Err: Debug,
{
    parse_vec(input, parse_letter_t, "[", "]", ",")
}

#[cfg(test)]
pub mod tests {
    use super::*;

    #[test]
    fn test_cfg_from_str_leading_comment() {
        let grammar = "% leading comment\n\
                       initial: [S]\n\n\
                       S → [T a]";
        let _: CFG<char, char, usize> = grammar.parse().unwrap();
    }

    #[test]
    fn test_cfg_from_str_end_of_line_comment() {
        let grammar = "initial: [S] % end-of-line comment 1\n\n\
                       S → [T a] % end-of-line comment 2";
        let _: CFG<char, char, usize> = grammar.parse().unwrap();
    }

    #[test]
    fn test_cfg_from_str_trailing_comment() {
        let grammar = "initial: [S]\n\n\
                       S → [T a]\n\
                       % trailing comment";
        let _: CFG<char, char, usize> = grammar.parse().unwrap();
    }

    #[test]
    fn test_parse_letter_t_legal_input() {
        let legal_inputs = vec![
            ("Nt S xyz", " xyz", LetterT::Label('S')),
            ("Nt  S", "", LetterT::Label('S')),
            ("T a xyz", " xyz", LetterT::Value('a')),
        ];

        for (legal_input, control_rest, control_parsed) in legal_inputs {
            assert_eq!(
                (control_rest.as_bytes(), control_parsed),
                parse_letter_t::<char, char>(legal_input.as_bytes()).unwrap()
            );
        }
    }

    #[test]
    fn test_parse_letter_t_illegal_input() {
        let illegal_inputs = vec![
            " Nt 1",
            "nt 1",
            "t 1",
            "Nt:1",
            "Nt a",
            "T a",
        ];

        for illegal_input in illegal_inputs {
            match parse_letter_t::<u8, u8>(illegal_input.as_bytes()) {
                IResult::Done(_, _) | IResult::Incomplete(_) =>
                    panic!("Was able to parse the illegal input \'{}\'", illegal_input),
                IResult::Error(_) => (),
            }
        }
    }

    #[test]
    fn test_parse_letter_t_incomplete_input() {
        let incomplete_inputs = vec![
            "Nt",
            "T",
        ];

        for incomplete_input in incomplete_inputs {
            match parse_letter_t::<char, char>(incomplete_input.as_bytes()) {
                IResult::Done(_, _) | IResult::Error(_) =>
                    panic!("The input was not handled as incomplete: \'{}\'", incomplete_input),
                IResult::Incomplete(_) => (),
            }
        }
    }

    #[test]
    fn test_parse_cfg_rule_legal_input() {
        let rule = CFGRule {
            head: 'S',
            composition: CFGComposition { composition: vec![LetterT::Value('a')] },
            weight: 1.0
        };
        let legal_inputs = vec![
            ("S → [T a] # 1 % comment", "", rule.clone()),
            ("S  →    [T a]#1 %comment", "", rule.clone()),
            ("S → [T a] # 1.0", "", rule.clone()),
            ("S → [T a]", "", rule.clone()),
            ("S → [T a] % comment", "", rule.clone()),
            ("S -> [T a] # 1", "", rule.clone()),
            ("S => [T a] # 1", "", rule.clone()),
        ];

        for (legal_input, control_rest, control_parsed) in legal_inputs {
            assert_eq!(
                (control_rest.as_bytes(), control_parsed),
                parse_cfg_rule::<char, char, f32>(legal_input.as_bytes()).unwrap()
            );
        }
    }

    #[test]
    fn test_parse_cfg_rule_illegal_input() {
        let illegal_inputs = vec![
            " S → [T a] # 1 % comment",
            "S [T a] # 1 % comment",
            "S → [T a] # 1 comment",
            "S ~> [T a] # 1",
            "AB → [T a] # 1 % comment",
            "S → [T a] # a % comment",
            "S → [T a] #",
        ];

        for illegal_input in illegal_inputs {
            match parse_cfg_rule::<char, char, f32>(illegal_input.as_bytes()) {
                IResult::Done(_, _) | IResult::Incomplete(_) =>
                    panic!("Was able to parse the illegal input \'{}\'", illegal_input),
                IResult::Error(_) => (),
            }
        }
    }

    #[test]
    fn test_parse_cfg_rule_incomplete_input() {
        let incomplete_inputs = vec![
            "S →",
            "S",
        ];

        for incomplete_input in incomplete_inputs {
            match parse_cfg_rule::<char, char, f32>(incomplete_input.as_bytes()) {
                IResult::Done(_, output) =>
                    panic!("The input was not handled as incomplete: \'{}\'", output),
                IResult::Error(error) => panic!("Error with \'{}\'; {:?}", incomplete_input, error),
                IResult::Incomplete(_) => (),
            }
        }
    }
}
<commit_msg>src/cfg/from_str.rs: added tests for *::from_str()<commit_after>use nom::{IResult, is_space};
use num_traits::One;
use std::fmt::Debug;
use std::marker::PhantomData;
use std::str::{FromStr, from_utf8};

use cfg::{CFG, CFGComposition, CFGRule, LetterT};
use util::parsing::*;

impl<N, T, W> FromStr for CFG<N, T, W>
    where N: FromStr,
          N::Err: Debug,
          T: Clone + FromStr,
          T::Err: Debug,
          W: FromStr + One,
          W::Err: Debug,
{
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let mut it = s.lines();
        let mut rules = Vec::new();
        let initial;

        match it.next() {
            Some(l) => {
                match parse_initials(l.as_bytes()) {
                    IResult::Done(_, result)
                        => initial = result,
                    _
                        => return Err(format!("Malformed declaration of initial nonterminals: \'{}\'", l))
                }
            },
            _ => return Err(String::from("Cannot parse an empty string as a CFG!"))
        }

        while let Some(l) = it.next() {
            if !l.is_empty() {
                rules.push(l.trim().parse()?);
            }
        }

        Ok(CFG {
            _dummy: PhantomData,
            initial,
            rules,
        })
    }
}

impl<N, T, W> FromStr for CFGRule<N, T, W>
    where N: FromStr,
          N::Err: Debug,
          T: Clone + FromStr,
          T::Err: Debug,
          W: FromStr + One,
          W::Err: Debug,
{
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match parse_cfg_rule(s.as_bytes()) {
            IResult::Done(_, result) => Ok(result),
            _                        => Err(format!("Could not parse \'{}\'", s))
        }
    }
}

fn parse_cfg_rule<N, T, W>(input: &[u8]) -> IResult<&[u8], CFGRule<N, T, W>>
    where N: FromStr,
          N::Err: Debug,
          T: FromStr,
          T::Err: Debug,
          W: FromStr + One,
          W::Err: Debug,
{
    do_parse!(
        input,
        head: parse_token >>
        take_while!(is_space) >>
        alt!(tag!("→") | tag!("->") | tag!("=>")) >>
        take_while!(is_space) >>
        composition: parse_composition >>
        take_while!(is_space) >>
        weight_o: opt!(
            complete!(
                do_parse!(
                    tag!("#") >>
                    take_while!(is_space) >>
                    weight_s: map_res!(is_not!(" "), from_utf8) >>
                    weight: expr_res!(weight_s.parse()) >>
                    (weight)
                )
            )
        ) >>
        take_while!(is_space) >>
        alt!(
            eof!() |
            preceded!(tag!("%"), take_while!(|_| true))
        ) >>
        (CFGRule {
            head: head,
            composition: CFGComposition { composition: composition },
            weight: weight_o.unwrap_or(W::one()),
        })
    )
}

fn parse_letter_t<N, T>(input: &[u8]) -> IResult<&[u8], LetterT<N,T>>
    where N: FromStr,
          N::Err: Debug,
          T: FromStr,
          T::Err: Debug,
{
    do_parse!(
        input,
        result: alt!(
            do_parse!(
                tag!("Nt") >>
                take_while!(is_space) >>
                token: parse_token >>
                (LetterT::Label(token))
            ) |
            do_parse!(
                tag!("T") >>
                take_while!(is_space) >>
                token: parse_token >>
                (LetterT::Value(token))
            )
        ) >>
        (result)
    )
}

fn parse_composition<N, T>(input: &[u8]) -> IResult<&[u8], Vec<LetterT<N,T>>>
    where N: FromStr,
          N::Err: Debug,
          T: FromStr,
          T::Err: Debug,
{
    parse_vec(input, parse_letter_t, "[", "]", ",")
}

#[cfg(test)]
pub mod tests {
    use super::*;

    #[test]
    fn test_cfg_from_str_leading_comment() {
        let grammar = "% leading comment\n\
                       initial: [S]\n\n\
                       S → [T a]";
        let _: CFG<char, char, usize> = grammar.parse().unwrap();
    }

    #[test]
    fn test_cfg_from_str_end_of_line_comment() {
        let grammar = "initial: [S] % end-of-line comment 1\n\n\
                       S → [T a] % end-of-line comment 2";
        let _: CFG<char, char, usize> = grammar.parse().unwrap();
    }

    #[test]
    fn test_cfg_from_str_trailing_comment() {
        let grammar = "initial: [S]\n\n\
                       S → [T a]\n\
                       % trailing comment";
        let _: CFG<char, char, usize> = grammar.parse().unwrap();
    }

    #[test]
    fn test_parse_letter_t_legal_input() {
        let legal_inputs = vec![
            ("Nt S xyz", " xyz", LetterT::Label('S')),
            ("Nt  S", "", LetterT::Label('S')),
            ("T a xyz", " xyz", LetterT::Value('a')),
        ];

        for (legal_input, control_rest, control_parsed) in legal_inputs {
            assert_eq!(
                (control_rest.as_bytes(), control_parsed),
                parse_letter_t::<char, char>(legal_input.as_bytes()).unwrap()
            );
        }
    }

    #[test]
    fn test_parse_letter_t_illegal_input() {
        let illegal_inputs = vec![
            " Nt 1",
            "nt 1",
            "t 1",
            "Nt:1",
            "Nt a",
            "T a",
        ];

        for illegal_input in illegal_inputs {
            match parse_letter_t::<u8, u8>(illegal_input.as_bytes()) {
                IResult::Done(_, _) | IResult::Incomplete(_) =>
                    panic!("Was able to parse the illegal input \'{}\'", illegal_input),
                IResult::Error(_) => (),
            }
        }
    }

    #[test]
    fn test_parse_letter_t_incomplete_input() {
        let incomplete_inputs = vec![
            "Nt",
            "T",
        ];

        for incomplete_input in incomplete_inputs {
            match parse_letter_t::<char, char>(incomplete_input.as_bytes()) {
                IResult::Done(_, _) | IResult::Error(_) =>
                    panic!("The input was not handled as incomplete: \'{}\'", incomplete_input),
                IResult::Incomplete(_) => (),
            }
        }
    }

    #[test]
    fn test_parse_cfg_rule_legal_input() {
        let rule = CFGRule {
            head: 'S',
            composition: CFGComposition { composition: vec![LetterT::Value('a')] },
            weight: 1.0
        };
        let legal_inputs = vec![
            ("S → [T a] # 1 % comment", "", rule.clone()),
            ("S  →    [T a]#1 %comment", "", rule.clone()),
            ("S → [T a] # 1.0", "", rule.clone()),
            ("S → [T a]", "", rule.clone()),
            ("S → [T a] % comment", "", rule.clone()),
            ("S -> [T a] # 1", "", rule.clone()),
            ("S => [T a] # 1", "", rule.clone()),
        ];

        for (legal_input, control_rest, control_parsed) in legal_inputs {
            assert_eq!(
                (control_rest.as_bytes(), control_parsed),
                parse_cfg_rule::<char, char, f32>(legal_input.as_bytes()).unwrap()
            );
        }
    }

    #[test]
    fn test_parse_cfg_rule_illegal_input() {
        let illegal_inputs = vec![
            " S → [T a] # 1 % comment",
            "S [T a] # 1 % comment",
            "S → [T a] # 1 comment",
            "S ~> [T a] # 1",
            "AB → [T a] # 1 % comment",
            "S → [T a] # a % comment",
            "S → [T a] #",
        ];

        for illegal_input in illegal_inputs {
            match parse_cfg_rule::<char, char, f32>(illegal_input.as_bytes()) {
                IResult::Done(_, _) | IResult::Incomplete(_) =>
                    panic!("Was able to parse the illegal input \'{}\'", illegal_input),
                IResult::Error(_) => (),
            }
        }
    }

    #[test]
    fn test_parse_cfg_rule_incomplete_input() {
        let incomplete_inputs = vec![
            "S →",
            "S",
        ];

        for incomplete_input in incomplete_inputs {
            match parse_cfg_rule::<char, char, f32>(incomplete_input.as_bytes()) {
                IResult::Done(_, output) =>
                    panic!("The input was not handled as incomplete: \'{}\'", output),
                IResult::Error(error) => panic!("Error with \'{}\'; {:?}", incomplete_input, error),
                IResult::Incomplete(_) => (),
            }
        }
    }

    #[test]
    fn test_cfg_rule_from_str_legal_input() {
        let control_rule = CFGRule {
            head: 'S',
            composition: CFGComposition { composition: vec![LetterT::Value('a')] },
            weight: 1.0
        };

        assert_eq!(
            Ok(control_rule),
            CFGRule::from_str("S → [T a]")
        );
    }

    #[test]
    fn test_cfg_rule_from_str_illegal_input() {
        let incomplete_or_illegal_inputs = vec![
            "S → [T 1",
            "S → [T a]",
        ];

        for input in incomplete_or_illegal_inputs {
            assert_eq!(
                Err(format!("Could not parse \'{}\'", &input)),
                CFGRule::<u8, u8, f32>::from_str(input)
            );
        }
    }

    #[test]
    fn test_cfg_from_str_legal_input() {
        let input = "initial: [S]\n\n\
                     S → [T a, Nt S, T b] # 0.4\n\
                     S → []               # 0.6";

        let rule_s0 = CFGRule {
            head: 'S',
            composition: CFGComposition { composition: vec![
                LetterT::Value('a'), LetterT::Label('S'), LetterT::Value('b'),
            ] },
            weight: 0.4
        };
        let rule_s1 = CFGRule {
            head: 'S',
            composition: CFGComposition { composition: vec![]},
            weight: 0.6
        };
        let control_grammar = CFG {
            _dummy: PhantomData,
            initial: vec!['S'],
            rules: vec![rule_s0, rule_s1]
        };

        assert_eq!(
            control_grammar,
            CFG::from_str(input).unwrap()
        );
    }

    #[test]
    fn test_cfg_from_str_illegal_input() {
        assert_eq!(
            Err(String::from("Cannot parse an empty string as a CFG!")),
            CFG::<u8, u8, u8>::from_str("")
        );

        let malformed_initial = "initial: [a]";
        assert_eq!(
            Err(format!("Malformed declaration of initial nonterminals: \'{}\'", &malformed_initial)),
            CFG::<u8, u8, u8>::from_str(malformed_initial)
        );

        let malformed_rule = "initial: [0]\n\n\
                              S → [T a]";
        assert_eq!(
            Err(String::from("Could not parse \'S → [T a]\'")),
            CFG::<u8, u8, u8>::from_str(malformed_rule)
        );
    }
}
<|endoftext|>


<commit_before>use std::str::from_utf8;
use std::sync::Arc;
use std::io::BufWriter;
use std::mem;

use futures::Async;
use futures::future::{FutureResult, ok};
use tk_http::{Status, Version};
use tk_http::client as http;
use rustc_serialize::Encodable;
use rustc_serialize::json::{as_json, Json};

use chat::authorize::{parse_userinfo, good_status};
use chat::{Cid, ConnectionSender, ConnectionMessage, TangleAuth};
use chat::cid::{serialize_cid};
use chat::CloseReason::{AuthHttp};
use chat::ConnectionMessage::{Hello, StopSocket};
use chat::error::MessageError;
use chat::message::{AuthData, Auth, Call, Meta, Args, Kwargs};
use chat::processor::{ProcessorPool, Action};
use config::http_destinations::Destination;
use intern::SessionId;
use proxy::{Response};

const INACTIVITY_PAYLOAD: &'static [u8] = b"[{}, [], {}]";

enum AuthState {
    Init(String, AuthData),
    Wait,
    Headers(Status),
    Done(Response),
    Void,
}

enum CallState {
    Init {
        auth: Arc<String>,
        path: String, args: Args, kw: Kwargs
    },
    Wait,
    Headers(Status),
    Void,
}

pub struct AuthCodec {
    state: AuthState,
    chat: ProcessorPool,
    conn_id: Cid,
    destination: Arc<Destination>,
    sender: ConnectionSender,
}

pub struct CallCodec {
    state: CallState,
    meta: Arc<Meta>,
    conn_id: Cid,
    destination: Arc<Destination>,
    sender: ConnectionSender,
}

pub struct InactivityCodec {
    path: Arc<String>,
    destination: Arc<Destination>,
    session_id: SessionId,
}

impl AuthCodec {
    pub fn new(path: String, cid: Cid, req: AuthData,
        chat: ProcessorPool, destination: &Arc<Destination>,
        tx: ConnectionSender)
        -> AuthCodec
    {
        AuthCodec {
            state: AuthState::Init(path, req),
            chat: chat,
            conn_id: cid,
            destination: destination.clone(),
            sender: tx,
        }
    }
}

impl CallCodec {
    pub fn new(auth: Arc<String>, path: String, cid: Cid,
        meta: &Arc<Meta>, args: Args, kw: Kwargs,
        destination: &Arc<Destination>,
        sender: ConnectionSender)
        -> CallCodec
    {
        CallCodec {
            state: CallState::Init {
                auth: auth,
                path: path,
                args: args,
                kw: kw,
            },
            meta: meta.clone(),
            conn_id: cid,
            destination: destination.clone(),
            sender: sender,
        }
    }
}

impl InactivityCodec {
    pub fn new(path: &Arc<String>, sid: &SessionId,
        destination: &Arc<Destination>)
        -> InactivityCodec
    {
        InactivityCodec {
            path: path.clone(),
            destination: destination.clone(),
            session_id: sid.clone(),
        }
    }
}

fn write_json_request<S, E>(mut e: http::Encoder<S>, data: &E)
    -> http::EncoderDone<S>
    where E: Encodable,
{
    use std::io::Write;
    e.add_header("Content-Type", "application/json").unwrap();
    e.add_chunked().unwrap();
    e.done_headers().unwrap();
    let mut buf = BufWriter::new(e);
    write!(&mut buf, "{}", as_json(data)).unwrap();
    match buf.into_inner() {
        Ok(x) => x.done(),
        Err(_) => unreachable!(),
    }
}

impl<S> http::Codec<S> for AuthCodec {
    type Future = FutureResult<http::EncoderDone<S>, http::Error>;

    fn start_write(&mut self, mut e: http::Encoder<S>) -> Self::Future {
        use self::AuthState::*;
        if let Init(p, i) = mem::replace(&mut self.state, Void)
        {
            self.state = Wait;
            e.request_line("POST", &p, Version::Http11);
            if let Some(ref header) = self.destination.override_host_header {
                e.add_header("Host", header).unwrap();
            }
            ok(write_json_request(e,
                &Auth(&serialize_cid(&self.conn_id), &i)))
        } else {
            panic!("wrong state");
        }
    }
    fn headers_received(&mut self, headers: &http::Head)
        -> Result<http::RecvMode, http::Error>
    {
        use self::AuthState::*;
        if let Wait = mem::replace(&mut self.state, Void) {
            self.state = Headers(
                headers.status().unwrap_or(Status::InternalServerError));
            // TODO(tailhook) limit and streaming
            Ok(http::RecvMode::buffered(10_485_760))
        } else {
            panic!("wrong state");
        }
    }
    fn data_received(&mut self, data: &[u8], end: bool)
        -> Result<Async<usize>, http::Error>
    {
        use self::AuthState::*;
        // TODO(tailhook) streaming
        assert!(end);
        match mem::replace(&mut self.state, Void) {
            Headers(Status::Ok) => {
                let result = from_utf8(data)
                    .map_err(|e| debug!("Invalid utf-8 in auth data: {}", e))
                .and_then(|s| Json::from_str(s)
                    .map_err(|e| debug!("Invalid json in auth data: {}", e)))
                .and_then(|j| parse_userinfo(j)
                    .map_err(|e| debug!("Bad user info in auth data: {}", e)));
                match result {
                    Ok((sess_id, userinfo)) => {
                        let userinfo = Arc::new(userinfo);
                        debug!("Auth data received {:?}: {:?}",
                            sess_id, userinfo);
                        self.sender.send(Hello(sess_id.clone(),
                                               userinfo.clone()));
                        self.chat.send(Action::Associate {
                            conn_id: self.conn_id,
                            session_id: sess_id,
                            metadata: userinfo,
                        });
                    }
                    Err(()) => {
                        debug!("Auth error");
                        self.sender.send(StopSocket(
                            AuthHttp(Status::InternalServerError)));
                    }
                };
            }
            Headers(status) => {
                if good_status(status) {
                    self.sender.send(StopSocket(AuthHttp(status)));
                } else {
                    self.sender.send(StopSocket(
                        AuthHttp(Status::InternalServerError)));
                }
            }
            _ => unreachable!(),
        }
        Ok((Async::Ready(data.len())))
    }
}

impl<S> http::Codec<S> for CallCodec {
    type Future = FutureResult<http::EncoderDone<S>, http::Error>;

    fn start_write(&mut self, mut e: http::Encoder<S>) -> Self::Future {
        use self::CallState::*;
        if
            let Init { auth, path, args, kw} =
            mem::replace(&mut self.state, Void)
        {
            e.request_line("POST", &path, Version::Http11);
            if let Some(ref header) = self.destination.override_host_header {
                e.add_header("Host", header).unwrap();
            }
            // TODO(tailhook) implement authrization
            e.add_header("Authorization", &*auth).unwrap();
            let cid = serialize_cid(&self.conn_id);
            let done = write_json_request(e, &Call(&*self.meta, &cid, &args, &kw));
            self.state = Wait;
            ok(done)
        } else {
            panic!("wrong state");
        }
    }
    fn headers_received(&mut self, headers: &http::Head)
        -> Result<http::RecvMode, http::Error>
    {
        use self::CallState::*;
        if let Wait = mem::replace(&mut self.state, Void) {
            self.state = Headers(
                headers.status().unwrap_or(Status::InternalServerError));
            // TODO(tailhook) configure limit
            Ok(http::RecvMode::buffered(10_485_760))
        } else {
            panic!("wrong state");
        }
    }
    fn data_received(&mut self, data: &[u8], end: bool)
        -> Result<Async<usize>, http::Error>
    {
        use self::CallState::*;
        assert!(end);
        match mem::replace(&mut self.state, Void) {
            Headers(Status::Ok) => {
                // TODO: connection_id must be dropped from meta
                match parse_response(data) {
                    Ok(x) => {
                        self.sender.send(ConnectionMessage::Result(
                            self.meta.clone(), x));
                    }
                    Err(e) => {
                        self.sender.send(ConnectionMessage::Error(
                            self.meta.clone(), e));
                    }
                }
            }
            Headers(status) => {
                self.sender.send(ConnectionMessage::Error(self.meta.clone(),
                    // TODO(tailhook) should we put body here?
                    MessageError::HttpError(status, None)));
            }
            _ => unreachable!(),
        }
        Ok((Async::Ready(data.len())))
    }
}

impl<S> http::Codec<S> for InactivityCodec {
    type Future = FutureResult<http::EncoderDone<S>, http::Error>;

    fn start_write(&mut self, mut e: http::Encoder<S>) -> Self::Future {
        e.request_line("POST", &self.path, Version::Http11);
        if let Some(ref header) = self.destination.override_host_header {
            e.add_header("Host", header).unwrap();
        }
        // TODO(tailhook) implement authrization
        e.format_header("Authorization",
                        TangleAuth(&self.session_id)).unwrap();
        e.add_header("Content-Type", "application/json").unwrap();
        e.add_length(INACTIVITY_PAYLOAD.len() as u64).unwrap();
        e.done_headers().unwrap();
        e.write_body(INACTIVITY_PAYLOAD);
        ok(e.done())
    }
    fn headers_received(&mut self, _: &http::Head)
        -> Result<http::RecvMode, http::Error>
    {
        // TODO(tailhook) retry request if failed
        Ok(http::RecvMode::buffered(0))
    }
    fn data_received(&mut self, data: &[u8], end: bool)
        -> Result<Async<usize>, http::Error>
    {
        assert!(end);
        Ok((Async::Ready(data.len())))
    }
}

fn parse_response(data: &[u8]) -> Result<Json, MessageError> {
    Ok(Json::from_str(from_utf8(data)?)?)
}
<commit_msg>chat: switch off chunked encoding as python wsgi servers have problems with it<commit_after>use std::str::from_utf8;
use std::sync::Arc;
use std::io::BufWriter;
use std::mem;

use futures::Async;
use futures::future::{FutureResult, ok};
use tk_http::{Status, Version};
use tk_http::client as http;
use rustc_serialize::Encodable;
use rustc_serialize::json::{encode, as_json, Json};

use chat::authorize::{parse_userinfo, good_status};
use chat::{Cid, ConnectionSender, ConnectionMessage, TangleAuth};
use chat::cid::{serialize_cid};
use chat::CloseReason::{AuthHttp};
use chat::ConnectionMessage::{Hello, StopSocket};
use chat::error::MessageError;
use chat::message::{AuthData, Auth, Call, Meta, Args, Kwargs};
use chat::processor::{ProcessorPool, Action};
use config::http_destinations::Destination;
use intern::SessionId;
use proxy::{Response};

const INACTIVITY_PAYLOAD: &'static [u8] = b"[{}, [], {}]";

enum AuthState {
    Init(String, AuthData),
    Wait,
    Headers(Status),
    Done(Response),
    Void,
}

enum CallState {
    Init {
        auth: Arc<String>,
        path: String, args: Args, kw: Kwargs
    },
    Wait,
    Headers(Status),
    Void,
}

pub struct AuthCodec {
    state: AuthState,
    chat: ProcessorPool,
    conn_id: Cid,
    destination: Arc<Destination>,
    sender: ConnectionSender,
}

pub struct CallCodec {
    state: CallState,
    meta: Arc<Meta>,
    conn_id: Cid,
    destination: Arc<Destination>,
    sender: ConnectionSender,
}

pub struct InactivityCodec {
    path: Arc<String>,
    destination: Arc<Destination>,
    session_id: SessionId,
}

impl AuthCodec {
    pub fn new(path: String, cid: Cid, req: AuthData,
        chat: ProcessorPool, destination: &Arc<Destination>,
        tx: ConnectionSender)
        -> AuthCodec
    {
        AuthCodec {
            state: AuthState::Init(path, req),
            chat: chat,
            conn_id: cid,
            destination: destination.clone(),
            sender: tx,
        }
    }
}

impl CallCodec {
    pub fn new(auth: Arc<String>, path: String, cid: Cid,
        meta: &Arc<Meta>, args: Args, kw: Kwargs,
        destination: &Arc<Destination>,
        sender: ConnectionSender)
        -> CallCodec
    {
        CallCodec {
            state: CallState::Init {
                auth: auth,
                path: path,
                args: args,
                kw: kw,
            },
            meta: meta.clone(),
            conn_id: cid,
            destination: destination.clone(),
            sender: sender,
        }
    }
}

impl InactivityCodec {
    pub fn new(path: &Arc<String>, sid: &SessionId,
        destination: &Arc<Destination>)
        -> InactivityCodec
    {
        InactivityCodec {
            path: path.clone(),
            destination: destination.clone(),
            session_id: sid.clone(),
        }
    }
}

fn write_json_request<S, E>(mut e: http::Encoder<S>, data: &E)
    -> http::EncoderDone<S>
    where E: Encodable,
{
    use std::io::Write;
    e.add_header("Content-Type", "application/json").unwrap();
    let body = encode(data).unwrap();
    let body = body.as_bytes();
    e.add_length(body.len() as u64).unwrap();
    e.done_headers().unwrap();
    e.write_body(body);
    e.done()
    // NOTE: disabling chunked encoding because of the following:
    //      https://github.com/pallets/flask/issues/367
    //      yeap, its flask/werkzeug/wsgi, baby.

    // e.add_chunked().unwrap();
    // e.done_headers().unwrap();
    // let mut buf = BufWriter::new(e);
    // write!(&mut buf, "{}", body).unwrap();
    // match buf.into_inner() {
    //     Ok(x) => x.done(),
    //     Err(_) => unreachable!(),
    // }
}

impl<S> http::Codec<S> for AuthCodec {
    type Future = FutureResult<http::EncoderDone<S>, http::Error>;

    fn start_write(&mut self, mut e: http::Encoder<S>) -> Self::Future {
        use self::AuthState::*;
        if let Init(p, i) = mem::replace(&mut self.state, Void)
        {
            self.state = Wait;
            e.request_line("POST", &p, Version::Http11);
            if let Some(ref header) = self.destination.override_host_header {
                e.add_header("Host", header).unwrap();
            }
            ok(write_json_request(e,
                &Auth(&serialize_cid(&self.conn_id), &i)))
        } else {
            panic!("wrong state");
        }
    }
    fn headers_received(&mut self, headers: &http::Head)
        -> Result<http::RecvMode, http::Error>
    {
        use self::AuthState::*;
        if let Wait = mem::replace(&mut self.state, Void) {
            self.state = Headers(
                headers.status().unwrap_or(Status::InternalServerError));
            // TODO(tailhook) limit and streaming
            Ok(http::RecvMode::buffered(10_485_760))
        } else {
            panic!("wrong state");
        }
    }
    fn data_received(&mut self, data: &[u8], end: bool)
        -> Result<Async<usize>, http::Error>
    {
        use self::AuthState::*;
        // TODO(tailhook) streaming
        assert!(end);
        match mem::replace(&mut self.state, Void) {
            Headers(Status::Ok) => {
                let result = from_utf8(data)
                    .map_err(|e| debug!("Invalid utf-8 in auth data: {}", e))
                .and_then(|s| Json::from_str(s)
                    .map_err(|e| debug!("Invalid json in auth data: {}", e)))
                .and_then(|j| parse_userinfo(j)
                    .map_err(|e| debug!("Bad user info in auth data: {}", e)));
                match result {
                    Ok((sess_id, userinfo)) => {
                        let userinfo = Arc::new(userinfo);
                        debug!("Auth data received {:?}: {:?}",
                            sess_id, userinfo);
                        self.sender.send(Hello(sess_id.clone(),
                                               userinfo.clone()));
                        self.chat.send(Action::Associate {
                            conn_id: self.conn_id,
                            session_id: sess_id,
                            metadata: userinfo,
                        });
                    }
                    Err(()) => {
                        debug!("Auth error");
                        self.sender.send(StopSocket(
                            AuthHttp(Status::InternalServerError)));
                    }
                };
            }
            Headers(status) => {
                if good_status(status) {
                    self.sender.send(StopSocket(AuthHttp(status)));
                } else {
                    self.sender.send(StopSocket(
                        AuthHttp(Status::InternalServerError)));
                }
            }
            _ => unreachable!(),
        }
        Ok((Async::Ready(data.len())))
    }
}

impl<S> http::Codec<S> for CallCodec {
    type Future = FutureResult<http::EncoderDone<S>, http::Error>;

    fn start_write(&mut self, mut e: http::Encoder<S>) -> Self::Future {
        use self::CallState::*;
        if
            let Init { auth, path, args, kw} =
            mem::replace(&mut self.state, Void)
        {
            e.request_line("POST", &path, Version::Http11);
            if let Some(ref header) = self.destination.override_host_header {
                e.add_header("Host", header).unwrap();
            }
            // TODO(tailhook) implement authrization
            e.add_header("Authorization", &*auth).unwrap();
            let cid = serialize_cid(&self.conn_id);
            let done = write_json_request(e, &Call(&*self.meta, &cid, &args, &kw));
            self.state = Wait;
            ok(done)
        } else {
            panic!("wrong state");
        }
    }
    fn headers_received(&mut self, headers: &http::Head)
        -> Result<http::RecvMode, http::Error>
    {
        use self::CallState::*;
        if let Wait = mem::replace(&mut self.state, Void) {
            self.state = Headers(
                headers.status().unwrap_or(Status::InternalServerError));
            // TODO(tailhook) configure limit
            Ok(http::RecvMode::buffered(10_485_760))
        } else {
            panic!("wrong state");
        }
    }
    fn data_received(&mut self, data: &[u8], end: bool)
        -> Result<Async<usize>, http::Error>
    {
        use self::CallState::*;
        assert!(end);
        match mem::replace(&mut self.state, Void) {
            Headers(Status::Ok) => {
                // TODO: connection_id must be dropped from meta
                match parse_response(data) {
                    Ok(x) => {
                        self.sender.send(ConnectionMessage::Result(
                            self.meta.clone(), x));
                    }
                    Err(e) => {
                        self.sender.send(ConnectionMessage::Error(
                            self.meta.clone(), e));
                    }
                }
            }
            Headers(status) => {
                self.sender.send(ConnectionMessage::Error(self.meta.clone(),
                    // TODO(tailhook) should we put body here?
                    MessageError::HttpError(status, None)));
            }
            _ => unreachable!(),
        }
        Ok((Async::Ready(data.len())))
    }
}

impl<S> http::Codec<S> for InactivityCodec {
    type Future = FutureResult<http::EncoderDone<S>, http::Error>;

    fn start_write(&mut self, mut e: http::Encoder<S>) -> Self::Future {
        e.request_line("POST", &self.path, Version::Http11);
        if let Some(ref header) = self.destination.override_host_header {
            e.add_header("Host", header).unwrap();
        }
        // TODO(tailhook) implement authrization
        e.format_header("Authorization",
                        TangleAuth(&self.session_id)).unwrap();
        e.add_header("Content-Type", "application/json").unwrap();
        e.add_length(INACTIVITY_PAYLOAD.len() as u64).unwrap();
        e.done_headers().unwrap();
        e.write_body(INACTIVITY_PAYLOAD);
        ok(e.done())
    }
    fn headers_received(&mut self, _: &http::Head)
        -> Result<http::RecvMode, http::Error>
    {
        // TODO(tailhook) retry request if failed
        Ok(http::RecvMode::buffered(0))
    }
    fn data_received(&mut self, data: &[u8], end: bool)
        -> Result<Async<usize>, http::Error>
    {
        assert!(end);
        Ok((Async::Ready(data.len())))
    }
}

fn parse_response(data: &[u8]) -> Result<Json, MessageError> {
    Ok(Json::from_str(from_utf8(data)?)?)
}
<|endoftext|>


<commit_before>use std::io::Command;
use std::os;

fn main() {
    let curr_dir = Path::new(os::getenv("CARGO_MANIFEST_DIR").unwrap());
    Command::new("git").arg("submodule").arg("update").arg("--init").cwd(&curr_dir).status().unwrap();

    let nvim_dir = curr_dir.join("neovim");
    Command::new("make").arg("libnvim").cwd(&nvim_dir).status().unwrap();

    let nvim_lib_dir = nvim_dir.join_many(&["build", "lib"]);
    let deps_lib_dir = nvim_dir.join_many(&[".deps", "usr", "lib"]);
    println!("cargo:rustc-flags=-L {} -L {} -l nvim:static",
        nvim_lib_dir.as_str().unwrap(),
        deps_lib_dir.as_str().unwrap());
}
<commit_msg>Change std::io to std::old_io<commit_after>use std::old_io::Command;
use std::os;

fn main() {
    let curr_dir = Path::new(os::getenv("CARGO_MANIFEST_DIR").unwrap());
    Command::new("git").arg("submodule").arg("update").arg("--init").cwd(&curr_dir).status().unwrap();

    let nvim_dir = curr_dir.join("neovim");
    Command::new("make").arg("libnvim").cwd(&nvim_dir).status().unwrap();

    let nvim_lib_dir = nvim_dir.join_many(&["build", "lib"]);
    let deps_lib_dir = nvim_dir.join_many(&[".deps", "usr", "lib"]);
    println!("cargo:rustc-flags=-L {} -L {} -l nvim:static",
        nvim_lib_dir.as_str().unwrap(),
        deps_lib_dir.as_str().unwrap());
}
<|endoftext|>


<commit_before>extern crate flate2;
extern crate tar;

use std::process::Command;
use std::env;
use std::fs::rename;
use flate2::read::GzDecoder;
use tar::Archive;

fn main() {
    let target = env::var("TARGET").unwrap();
    if target == "x86_64-pc-windows-msvc"{
        match rename("target\\Nishikaku-Bin-0.1.0\\x86_64\\dll", "target\\win_rel") {
            Ok(()) => { },
            _ => { },
        };
    } else if target == "i686-pc-windows-msvc" {
        download_files();
        match rename("target\\Nishikaku-Bin-0.1.0\\i686\\dll", "target\\win_rel") {
            Ok(()) => { },
            _ => { },
        };
    }
}

fn download_files() {
    let output = Command::new("curl").arg("-s").arg("-L").arg("https://github.com/Luminarys/Nishikaku-Bin/archive/0.1.0.tar.gz")
       .output()
       .unwrap_or_else(|e| { panic!("failed to execute process: {}", e) });

    let resp = output.stdout;
    let d = GzDecoder::new(&resp[..]).unwrap();
    let mut a = Archive::new(d);
    a.unpack("./target/").unwrap();
}
<commit_msg>Fix build for x86_64 msvc platform<commit_after>extern crate flate2;
extern crate tar;

use std::process::Command;
use std::env;
use std::fs::rename;
use flate2::read::GzDecoder;
use tar::Archive;

fn main() {
    let target = env::var("TARGET").unwrap();
    if target == "x86_64-pc-windows-msvc" {
        download_files();
        match rename("target\\Nishikaku-Bin-0.1.0\\x86_64\\dll",
                     "target\\win_rel") {
            Ok(()) => {}
            _ => {}
        };
    } else if target == "i686-pc-windows-msvc" {
        download_files();
        match rename("target\\Nishikaku-Bin-0.1.0\\i686\\dll", "target\\win_rel") {
            Ok(()) => {}
            _ => {}
        };
    }
}

fn download_files() {
    let output = Command::new("curl")
                     .arg("-s")
                     .arg("-L")
                     .arg("https://github.com/Luminarys/Nishikaku-Bin/archive/0.1.0.tar.gz")
                     .output()
                     .unwrap_or_else(|e| panic!("failed to execute process: {}", e));

    let resp = output.stdout;
    let d = GzDecoder::new(&resp[..]).unwrap();
    let mut a = Archive::new(d);
    a.unpack("./target/").unwrap();
}
<|endoftext|>


<commit_before>// build.rs
//
// Execute Erlang script to generate API lists and extract config.
//

use std::process::Command;
use std::env;
use std::path::Path;

fn main() {
	// FIXME: take env escript if present
	let escript = "escript";

	// emit generated files to OUT_DIR
	let out_dir = env::var("OUT_DIR").unwrap();
	let dst = Path::new(&out_dir);
	Command::new(escript).arg("gen_api.erl").arg(dst).status().unwrap();
}
<commit_msg>remove build.rs<commit_after><|endoftext|>


<commit_before>#![feature(fs)]
#![feature(io)]
#![feature(process)]
#![feature(env)]
#![feature(path)]

use std::fs::File;
use std::io::Write;
use std::process::Command;
use std::path;
use std::env;

fn main()
{
    let dir_var = env::var("OUT_DIR").unwrap();
    let dir = path::Path::new(&dir_var).join("codegen");
    let out_file = dir.to_str().unwrap();
    Command::new("gcc").arg("src/codegen/type_size.c")
                       .arg("-o")
                       .arg(out_file)
                       .status()
                       .unwrap();
    let output = Command::new(out_file).output().unwrap();
    if !output.status.success() {
        panic!("{}", String::from_utf8_lossy(output.stderr.as_slice()));
    }
    let mut f = match File::create("src/type_size.rs") {
        Ok(f) => f,
        Err(e) => panic!("{:?}", e)
    };
    f.write_all(&output.stdout[..]).unwrap();
}
<commit_msg>Rust changes: Remove stabilized feature flags<commit_after>#![feature(io)]
#![feature(path)]

use std::fs::File;
use std::io::Write;
use std::process::Command;
use std::path;
use std::env;

fn main()
{
    let dir_var = env::var("OUT_DIR").unwrap();
    let dir = path::Path::new(&dir_var).join("codegen");
    let out_file = dir.to_str().unwrap();
    Command::new("gcc").arg("src/codegen/type_size.c")
                       .arg("-o")
                       .arg(out_file)
                       .status()
                       .unwrap();
    let output = Command::new(out_file).output().unwrap();
    if !output.status.success() {
        panic!("{}", String::from_utf8_lossy(output.stderr.as_slice()));
    }
    let mut f = match File::create("src/type_size.rs") {
        Ok(f) => f,
        Err(e) => panic!("{:?}", e)
    };
    f.write_all(&output.stdout[..]).unwrap();
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

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

fn main() {
    assert!(Command::new("make")
        .args(&["-f", "makefile.cargo"])
        .status()
        .unwrap()
        .success());
    println!("cargo:rustc-flags=-L native={}", env::var("OUT_DIR").unwrap());
}
<commit_msg>Disable initial values set by `make`.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

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

fn main() {
    assert!(Command::new("make")
        .args(&["-R", "-f", "makefile.cargo"])
        .status()
        .unwrap()
        .success());
    println!("cargo:rustc-flags=-L native={}", env::var("OUT_DIR").unwrap());
}
<|endoftext|>


<commit_before>// Copyright 2014 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

extern crate fs_utils;

use fs_utils::copy::copy_directory;

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

fn main() {
    let out = env::var("OUT_DIR").unwrap();
    let within_out = |p| format!("{}/{}", out, p);
    fs::remove_dir_all(within_out("htslib"));
    copy_directory("htslib", &out).unwrap();

    if Command::new("make").current_dir(within_out("htslib"))
                           .arg("CFLAGS=-g -Wall -O2 -fPIC")
                           .arg("lib-static")
                           .arg("-B")
                           .status().unwrap()
                           .success() != true {
        panic!("failed to build htslib");
    }
    if Command::new("gcc").arg("-I").arg(within_out("htslib"))
                          .arg("-c")
                          .arg("src/htslib/macros.c")
                          .arg("-o").arg(within_out("macros.o"))
                          .status().unwrap().success() != true {
        panic!("error building macro wrapper");
    }
    if Command::new("ar").arg("r")
                         .arg(within_out("libmacros.a"))
                         .arg(within_out("macros.o"))
                         .status().unwrap().success() != true {
        panic!("error buiding macro wrapper");
    }

    println!("cargo:rustc-flags=-L {out}/htslib -L {out} -l static=hts -l static=macros -l z",
             out=out);
}
<commit_msg>Minor.<commit_after>// Copyright 2014 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

extern crate fs_utils;

use fs_utils::copy::copy_directory;

use std::process::Command;
use std::env;
use std::path::Path;

fn main() {
    let out = env::var("OUT_DIR").unwrap();
    let within_out = |p| format!("{}/{}", out, p);
    if !Path::new(&within_out("htslib")).exists() {
        copy_directory("htslib", &out).unwrap();
    }

    if Command::new("make").current_dir(within_out("htslib"))
                           .arg("CFLAGS=-g -Wall -O2 -fPIC")
                           .arg("lib-static")
                           .arg("-B")
                           .status().unwrap()
                           .success() != true {
        panic!("failed to build htslib");
    }
    if Command::new("gcc").arg("-I").arg(within_out("htslib"))
                          .arg("-c")
                          .arg("src/htslib/macros.c")
                          .arg("-o").arg(within_out("macros.o"))
                          .status().unwrap().success() != true {
        panic!("error building macro wrapper");
    }
    if Command::new("ar").arg("r")
                         .arg(within_out("libmacros.a"))
                         .arg(within_out("macros.o"))
                         .status().unwrap().success() != true {
        panic!("error buiding macro wrapper");
    }

    println!("cargo:rustc-flags=-L {out}/htslib -L {out} -l static=hts -l static=macros -l z",
             out=out);
}
<|endoftext|>


<commit_before>fn main() {
    println!("cargo:rustc-link-lib=dylib=ffi");
}
<commit_msg>support windows ffi.lib<commit_after>fn main() {
    if cfg!(not(target_os = "windows")) {
        println!("cargo:rustc-link-lib=dylib=ffi");
    }
}
<|endoftext|>


<commit_before>#[cfg(any(target_os = "macos"))]
fn main() {
    println!("cargo:rustc-link-lib=framework=IOKit");
}
<commit_msg>Fix for non-OSX platforms<commit_after>fn main() {
    #[cfg(any(target_os = "macos"))]
    println!("cargo:rustc-link-lib=framework=IOKit");
}
<|endoftext|>


<commit_before>use std::io::Command;
use std::os;

fn main() {
    Command::new("make").status().unwrap();
    let out_dir = os::getenv("OUT_DIR").unwrap();
    println!("cargo:rustc-flags=-L {} -l parser:static", out_dir);
}
<commit_msg>Fix deadlock in builder<commit_after>use std::io::Command;
use std::io::process::StdioContainer::InheritFd;
use std::os;

fn main() {
    Command::new("make")
        .stdin(InheritFd(0))
        .stdout(InheritFd(1))
        .stderr(InheritFd(2))
        .status()
        .unwrap();
    let out_dir = os::getenv("OUT_DIR").unwrap();
    println!("cargo:rustc-flags=-L {} -l parser:static", out_dir);
}
<|endoftext|>


<commit_before>extern crate gcc;
extern crate semver;

use semver::{Version, VersionReq};
use semver::ParseError::IncorrectParse;
use std::process::Command;

/// Get the output from running `llvm-config` with the given argument.
fn llvm_config(arg: &str) -> String {
    let stdout = Command::new("llvm-config")
        .arg(arg)
        .output()
        .ok().expect("llvm-config not found. Install LLVM before attempting to build.")
        .stdout;

    String::from_utf8(stdout).ok().expect("llvm-config output was not UTF-8.")
}

/// Get the LLVM version using llvm-config.
fn llvm_version() -> Version {
    match Version::parse(&llvm_config("--version")) {
        // Ignore partial error; particularly constructs like '3.8.0svn' should be accepted,
        // despite being invalid semver.
        Err(IncorrectParse(v, _)) | Ok(v) => v,
        _ => panic!("Could not determine LLVM version from llvm-config."),
    }
}

fn main() {
    // Check for LLVM 3.6 or greater.
    let minimum_llvm_version = VersionReq::parse(">=3.6").unwrap();
    let version = llvm_version();
    if minimum_llvm_version.matches(&version) {
        println!("Found LLVM version {}", version);
    } else {
        panic!("LLVM version 3.6 or higher is required. (Found {})", version);
    };

    // Parse library linking flags from llvm-config.
    for arg in llvm_config("--ldflags").split_whitespace() {
        if arg.starts_with("-L") {
            println!("cargo:rustc-link-search=native={}", &arg[2..]);
        }
    }

    for arg in llvm_config("--libs").split_whitespace() {
        if arg.starts_with("-l") {
            println!("cargo:rustc-link-lib=static={}", &arg[2..]);
        }
    }

    for arg in llvm_config("--system-libs").split_whitespace() {
        if arg.starts_with("-l") {
            println!("cargo:rustc-link-lib=dylib={}", &arg[2..]);
        }
    }

    // This breaks the link step on Windows with MSVC.
    if !cfg!(windows) {
        // Determine which C++ standard library to use: LLVM's or GCC's.
        let cxxflags = llvm_config("--cxxflags");
        let libcpp = if cxxflags.contains("stdlib=libc++") { "c++" } else { "stdc++" };
        println!("cargo:rustc-link-lib={}", libcpp);
    }

    // Build the extra wrapper functions.
    std::env::set_var("CFLAGS", llvm_config("--cflags").trim());
    gcc::compile_library("libtargetwrappers.a", &["wrappers/target.c"]);
}
<commit_msg>Use a more accurate message for llvm-config errors.<commit_after>extern crate gcc;
extern crate semver;

use semver::{Version, VersionReq};
use semver::ParseError::IncorrectParse;
use std::process::Command;

/// Get the output from running `llvm-config` with the given argument.
fn llvm_config(arg: &str) -> String {
    let stdout = Command::new("llvm-config")
        .arg(arg)
        .output()
        .unwrap_or_else(|e| panic!("Couldn't execute llvm-config. Error: {}", e))
        .stdout;

    String::from_utf8(stdout).ok().expect("llvm-config output was not UTF-8.")
}

/// Get the LLVM version using llvm-config.
fn llvm_version() -> Version {
    match Version::parse(&llvm_config("--version")) {
        // Ignore partial error; particularly constructs like '3.8.0svn' should be accepted,
        // despite being invalid semver.
        Err(IncorrectParse(v, _)) | Ok(v) => v,
        _ => panic!("Could not determine LLVM version from llvm-config."),
    }
}

fn main() {
    // Check for LLVM 3.6 or greater.
    let minimum_llvm_version = VersionReq::parse(">=3.6").unwrap();
    let version = llvm_version();
    if minimum_llvm_version.matches(&version) {
        println!("Found LLVM version {}", version);
    } else {
        panic!("LLVM version 3.6 or higher is required. (Found {})", version);
    };

    // Parse library linking flags from llvm-config.
    for arg in llvm_config("--ldflags").split_whitespace() {
        if arg.starts_with("-L") {
            println!("cargo:rustc-link-search=native={}", &arg[2..]);
        }
    }

    for arg in llvm_config("--libs").split_whitespace() {
        if arg.starts_with("-l") {
            println!("cargo:rustc-link-lib=static={}", &arg[2..]);
        }
    }

    for arg in llvm_config("--system-libs").split_whitespace() {
        if arg.starts_with("-l") {
            println!("cargo:rustc-link-lib=dylib={}", &arg[2..]);
        }
    }

    // This breaks the link step on Windows with MSVC.
    if !cfg!(windows) {
        // Determine which C++ standard library to use: LLVM's or GCC's.
        let cxxflags = llvm_config("--cxxflags");
        let libcpp = if cxxflags.contains("stdlib=libc++") { "c++" } else { "stdc++" };
        println!("cargo:rustc-link-lib={}", libcpp);
    }

    // Build the extra wrapper functions.
    std::env::set_var("CFLAGS", llvm_config("--cflags").trim());
    gcc::compile_library("libtargetwrappers.a", &["wrappers/target.c"]);
}
<|endoftext|>