<commit_before>use super::{svc::{ConfigOptSharedLoad,
                  SharedLoad},
            util::{self,
                   CacheKeyPath,
                   ConfigOptCacheKeyPath,
                   ConfigOptRemoteSup,
                   RemoteSup}};
use crate::VERSION;
use configopt::{self,
                configopt_fields,
                ConfigOpt};
use habitat_common::{cli::{RING_ENVVAR,
                           RING_KEY_ENVVAR},
                     command::package::install::InstallSource,
                     types::{EventStreamConnectMethod,
                             EventStreamMetaPair,
                             EventStreamServerCertificate,
                             EventStreamToken,
                             GossipListenAddr,
                             HttpListenAddr,
                             ListenCtlAddr}};
use habitat_core::{env::Config,
                   package::PackageIdent,
                   util::serde_string};
use rants::{error::Error as RantsError,
            Address as NatsAddress};
use std::{fmt,
          io,
          net::{IpAddr,
                SocketAddr},
          path::PathBuf,
          str::FromStr};
use structopt::{clap::AppSettings,
                StructOpt};

#[derive(ConfigOpt, StructOpt)]
#[structopt(name = "hab",
            version = VERSION,
            about = "The Habitat Supervisor",
            author = "\nThe Habitat Maintainers <humans@habitat.sh>\n",
            usage = "hab sup <SUBCOMMAND>",
            settings = &[AppSettings::VersionlessSubcommands],
        )]
#[allow(clippy::large_enum_variant)]
pub enum Sup {
    /// Start an interactive Bash-like shell
    #[structopt(usage = "hab sup bash", no_version)]
    Bash,
    /// Depart a Supervisor from the gossip ring; kicking and banning the target from joining again
    /// with the same member-id
    #[structopt(no_version)]
    Depart {
        /// The member-id of the Supervisor to depart
        #[structopt(name = "MEMBER_ID")]
        member_id:  String,
        #[structopt(flatten)]
        remote_sup: RemoteSup,
    },
    /// Run the Habitat Supervisor
    #[structopt(no_version)]
    Run(SupRun),
    #[structopt(no_version)]
    Secret(Secret),
    /// Start an interactive Bourne-like shell
    #[structopt(usage = "hab sup sh", no_version)]
    Sh,
    /// Query the status of Habitat services
    #[structopt(no_version)]
    Status {
        /// A package identifier (ex: core/redis, core/busybox-static/1.42.2)
        #[structopt(name = "PKG_IDENT")]
        pkg_ident:  Option<PackageIdent>,
        #[structopt(flatten)]
        remote_sup: RemoteSup,
    },
    /// Gracefully terminate the Habitat Supervisor and all of its running services
    #[structopt(usage = "hab sup term [OPTIONS]", no_version)]
    Term,
}

// TODO (DM): This is unnecessarily difficult due to this issue in serde
// https://github.com/serde-rs/serde/issues/723. The easiest way to get around the issue is by
// using a wrapper type since NatsAddress is not defined in this crate.
#[derive(Deserialize, Serialize, Debug)]
pub struct EventStreamAddress(#[serde(with = "serde_string")] NatsAddress);

impl fmt::Display for EventStreamAddress {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.0) }
}

impl FromStr for EventStreamAddress {
    type Err = RantsError;

    fn from_str(s: &str) -> Result<Self, Self::Err> { Ok(EventStreamAddress(s.parse()?)) }
}

impl From<EventStreamAddress> for NatsAddress {
    fn from(address: EventStreamAddress) -> Self { address.0 }
}

fn parse_peer(s: &str) -> io::Result<SocketAddr> {
    util::socket_addr_with_default_port(s, GossipListenAddr::DEFAULT_PORT)
}

#[configopt_fields]
#[derive(ConfigOpt, StructOpt, Deserialize)]
#[configopt(attrs(serde))]
#[cfg_attr(linux,
           configopt(default_config_file("/hab/sup/default/config/sup.toml")))]
#[cfg_attr(windows,
           configopt(default_config_file("\\hab\\sup\\default\\config\\sup.toml")))]
#[serde(deny_unknown_fields)]
#[structopt(name = "run",
            no_version,
            about = "Run the Habitat Supervisor",
            // set custom usage string, otherwise the binary
            // is displayed confusingly as `hab-sup`
            // see: https://github.com/kbknapp/clap-rs/blob/2724ec5399c500b12a1a24d356f4090f4816f5e2/src/app/mod.rs#L373-L394
            usage = "hab sup run [FLAGS] [OPTIONS] [--] [PKG_IDENT_OR_ARTIFACT]",
            rename_all = "screamingsnake",
        )]
#[allow(dead_code)]
pub struct SupRun {
    /// The listen address for the Gossip Gateway
    #[structopt(long = "listen-gossip",
                env = GossipListenAddr::ENVVAR,
                default_value = GossipListenAddr::default_as_str())]
    pub listen_gossip: GossipListenAddr,
    /// Start the supervisor in local mode
    #[structopt(long = "local-gossip-mode",
                conflicts_with_all = &["LISTEN_GOSSIP", "PEER", "PEER_WATCH_FILE"])]
    pub local_gossip_mode: bool,
    /// The listen address for the HTTP Gateway
    #[structopt(long = "listen-http",
                env = HttpListenAddr::ENVVAR,
                default_value = HttpListenAddr::default_as_str())]
    pub listen_http: HttpListenAddr,
    /// Disable the HTTP Gateway completely
    #[structopt(long = "http-disable", short = "D")]
    pub http_disable: bool,
    /// The listen address for the Control Gateway
    #[structopt(long = "listen-ctl",
                env = ListenCtlAddr::ENVVAR,
                default_value = ListenCtlAddr::default_as_str())]
    pub listen_ctl: ListenCtlAddr,
    /// The organization the Supervisor and its services are part of
    #[structopt(long = "org")]
    pub organization: Option<String>,
    /// The listen address of one or more initial peers (IP[:PORT])
    // TODO (DM): Currently there is not a good way to use `parse_peer` when deserializing. Due to
    // https://github.com/serde-rs/serde/issues/723. There are workarounds but they are all ugly.
    // This means that you have to specify the port when setting this with a config file.
    #[structopt(long = "peer", parse(try_from_str = parse_peer))]
    #[serde(default)]
    pub peer: Vec<SocketAddr>,
    /// Make this Supervisor a permanent peer
    #[structopt(long = "permanent-peer", short = "I")]
    pub permanent_peer: bool,
    /// Watch this file for connecting to the ring
    #[structopt(long = "peer-watch-file", conflicts_with = "PEER")]
    pub peer_watch_file: Option<PathBuf>,
    #[structopt(flatten)]
    #[serde(flatten)]
    pub cache_key_path: CacheKeyPath,
    /// The name of the ring used by the Supervisor when running with wire encryption
    #[structopt(long = "ring",
                short = "r",
                env = RING_ENVVAR,
                conflicts_with = "RING_KEY")]
    pub ring: Option<String>,
    /// The contents of the ring key when running with wire encryption
    ///
    /// This option is explicitly undocumented and for testing purposes only. Do not use it in a
    /// production system. Use the corresponding environment variable instead. (ex:
    /// 'SYM-SEC-1\nfoo-20181113185935\n\nGCrBOW6CCN75LMl0j2V5QqQ6nNzWm6and9hkKBSUFPI=')
    #[structopt(long = "ring-key",
                env = RING_KEY_ENVVAR,
                hidden = true)]
    pub ring_key: Option<String>,
    /// Use the package config from this path rather than the package itself
    #[structopt(long = "config-from")]
    pub config_from: Option<PathBuf>,
    /// Enable automatic updates for the Supervisor itself
    #[structopt(long = "auto-update", short = "A")]
    pub auto_update: bool,
    /// The private key for HTTP Gateway TLS encryption
    ///
    /// Read the private key from KEY_FILE. This should be an RSA private key or PKCS8-encoded
    /// private key in PEM format.
    #[structopt(long = "key", requires = "CERT_FILE")]
    pub key_file: Option<PathBuf>,
    /// The server certificates for HTTP Gateway TLS encryption
    ///
    /// Read server certificates from CERT_FILE. This should contain PEM-format certificates in
    /// the right order. The first certificate should certify KEY_FILE. The last should be a
    /// root CA.
    #[structopt(long = "certs", requires = "KEY_FILE")]
    pub cert_file: Option<PathBuf>,
    /// The CA certificate for HTTP Gateway TLS encryption
    ///
    /// Read the CA certificate from CA_CERT_FILE. This should contain PEM-format certificate that
    /// can be used to validate client requests
    #[structopt(long = "ca-certs",
                requires_all = &["CERT_FILE", "KEY_FILE"])]
    pub ca_cert_file: Option<PathBuf>,
    /// Load a Habitat package as part of the Supervisor startup
    ///
    /// The package can be specified by a package identifier (ex: core/redis) or filepath to a
    /// Habitat artifact (ex: /home/core-redis-3.0.7-21120102031201-x86_64-linux.hart).
    #[structopt()]
    pub pkg_ident_or_artifact: Option<InstallSource>,
    /// Verbose output showing file and line/column numbers
    #[structopt(short = "v")]
    pub verbose: bool,
    /// Turn ANSI color off
    #[structopt(long = "no-color")]
    pub no_color: bool,
    /// Use structured JSON logging for the Supervisor
    ///
    /// This option also sets NO_COLOR.
    #[structopt(long = "json-logging")]
    pub json_logging: bool,
    /// The IPv4 address to use as the `sys.ip` template variable
    ///
    /// If this argument is not set, the supervisor tries to dynamically determine an IP address.
    /// If that fails, the supervisor defaults to using `127.0.0.1`.
    #[structopt(long = "sys-ip-address")]
    pub sys_ip_address: Option<IpAddr>,
    /// The name of the application for event stream purposes
    ///
    /// This will be attached to all events generated by this Supervisor.
    #[structopt(long = "event-stream-application", empty_values = false)]
    pub event_stream_application: Option<String>,
    /// The name of the environment for event stream purposes
    ///
    /// This will be attached to all events generated by this Supervisor.
    #[structopt(long = "event-stream-environment", empty_values = false)]
    pub event_stream_environment: Option<String>,
    /// Event stream connection timeout before exiting the Supervisor
    ///
    /// Set to '0' to immediately start the Supervisor and continue running regardless of the
    /// initial connection status.
    #[structopt(long = "event-stream-connect-timeout",
                env = EventStreamConnectMethod::ENVVAR,
                default_value = "0")]
    pub event_stream_connect_timeout: EventStreamConnectMethod,
    /// The event stream connection url used to send events to Chef Automate
    ///
    /// This enables the event stream and requires EVENT_STREAM_APPLICATION,
    /// EVENT_STREAM_ENVIRONMENT, and EVENT_STREAM_TOKEN also be set.
    #[structopt(long = "event-stream-url",
                requires_all = &["EVENT_STREAM_APPLICATION",
                                 "EVENT_STREAM_ENVIRONMENT",
                                 EventStreamToken::ARG_NAME])]
    pub event_stream_url: Option<EventStreamAddress>,
    /// The name of the site where this Supervisor is running for event stream purposes
    #[structopt(long = "event-stream-site", empty_values = false)]
    pub event_stream_site: Option<String>,
    /// The authentication token for connecting the event stream to Chef Automate
    #[structopt(long = "event-stream-token",
                env = EventStreamToken::ENVVAR)]
    pub event_stream_token: Option<EventStreamToken>,
    /// An arbitrary key-value pair to add to each event generated by this Supervisor
    #[structopt(long = "event-meta")]
    #[serde(default)]
    pub event_meta: Vec<EventStreamMetaPair>,
    /// The path to Chef Automate's event stream certificate used to establish a TLS connection
    ///
    /// The certificate should be in PEM format.
    #[structopt(long = "event-stream-server-certificate")]
    pub event_stream_server_certificate: Option<EventStreamServerCertificate>,
    /// Automatically cleanup old packages
    ///
    /// The Supervisor will automatically cleanup old packages only keeping the
    /// KEEP_LATEST_PACKAGES latest packages. If this argument is not specified, no
    /// automatic package cleanup is performed.
    #[structopt(long = "keep-latest-packages", env = "HAB_KEEP_LATEST_PACKAGES")]
    pub keep_latest_packages: Option<usize>,
    #[structopt(flatten)]
    #[serde(flatten)]
    pub shared_load: SharedLoad,
}

#[derive(ConfigOpt, StructOpt)]
#[structopt(no_version)]
/// Commands relating to a Habitat Supervisor's Control Gateway secret
pub enum Secret {
    /// Generate a secret key to use as a Supervisor's Control Gateway secret
    Generate,
}
<commit_msg>Use not(windows) cfg predicate for default_config_file<commit_after>use super::{svc::{ConfigOptSharedLoad,
                  SharedLoad},
            util::{self,
                   CacheKeyPath,
                   ConfigOptCacheKeyPath,
                   ConfigOptRemoteSup,
                   RemoteSup}};
use crate::VERSION;
use configopt::{self,
                configopt_fields,
                ConfigOpt};
use habitat_common::{cli::{RING_ENVVAR,
                           RING_KEY_ENVVAR},
                     command::package::install::InstallSource,
                     types::{EventStreamConnectMethod,
                             EventStreamMetaPair,
                             EventStreamServerCertificate,
                             EventStreamToken,
                             GossipListenAddr,
                             HttpListenAddr,
                             ListenCtlAddr}};
use habitat_core::{env::Config,
                   package::PackageIdent,
                   util::serde_string};
use rants::{error::Error as RantsError,
            Address as NatsAddress};
use std::{fmt,
          io,
          net::{IpAddr,
                SocketAddr},
          path::PathBuf,
          str::FromStr};
use structopt::{clap::AppSettings,
                StructOpt};

#[derive(ConfigOpt, StructOpt)]
#[structopt(name = "hab",
            version = VERSION,
            about = "The Habitat Supervisor",
            author = "\nThe Habitat Maintainers <humans@habitat.sh>\n",
            usage = "hab sup <SUBCOMMAND>",
            settings = &[AppSettings::VersionlessSubcommands],
        )]
#[allow(clippy::large_enum_variant)]
pub enum Sup {
    /// Start an interactive Bash-like shell
    #[structopt(usage = "hab sup bash", no_version)]
    Bash,
    /// Depart a Supervisor from the gossip ring; kicking and banning the target from joining again
    /// with the same member-id
    #[structopt(no_version)]
    Depart {
        /// The member-id of the Supervisor to depart
        #[structopt(name = "MEMBER_ID")]
        member_id:  String,
        #[structopt(flatten)]
        remote_sup: RemoteSup,
    },
    /// Run the Habitat Supervisor
    #[structopt(no_version)]
    Run(SupRun),
    #[structopt(no_version)]
    Secret(Secret),
    /// Start an interactive Bourne-like shell
    #[structopt(usage = "hab sup sh", no_version)]
    Sh,
    /// Query the status of Habitat services
    #[structopt(no_version)]
    Status {
        /// A package identifier (ex: core/redis, core/busybox-static/1.42.2)
        #[structopt(name = "PKG_IDENT")]
        pkg_ident:  Option<PackageIdent>,
        #[structopt(flatten)]
        remote_sup: RemoteSup,
    },
    /// Gracefully terminate the Habitat Supervisor and all of its running services
    #[structopt(usage = "hab sup term [OPTIONS]", no_version)]
    Term,
}

// TODO (DM): This is unnecessarily difficult due to this issue in serde
// https://github.com/serde-rs/serde/issues/723. The easiest way to get around the issue is by
// using a wrapper type since NatsAddress is not defined in this crate.
#[derive(Deserialize, Serialize, Debug)]
pub struct EventStreamAddress(#[serde(with = "serde_string")] NatsAddress);

impl fmt::Display for EventStreamAddress {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.0) }
}

impl FromStr for EventStreamAddress {
    type Err = RantsError;

    fn from_str(s: &str) -> Result<Self, Self::Err> { Ok(EventStreamAddress(s.parse()?)) }
}

impl From<EventStreamAddress> for NatsAddress {
    fn from(address: EventStreamAddress) -> Self { address.0 }
}

fn parse_peer(s: &str) -> io::Result<SocketAddr> {
    util::socket_addr_with_default_port(s, GossipListenAddr::DEFAULT_PORT)
}

#[configopt_fields]
#[derive(ConfigOpt, StructOpt, Deserialize)]
#[configopt(attrs(serde))]
#[cfg_attr(not(windows),
           configopt(default_config_file("/hab/sup/default/config/sup.toml")))]
#[cfg_attr(windows,
           configopt(default_config_file("\\hab\\sup\\default\\config\\sup.toml")))]
#[serde(deny_unknown_fields)]
#[structopt(name = "run",
            no_version,
            about = "Run the Habitat Supervisor",
            // set custom usage string, otherwise the binary
            // is displayed confusingly as `hab-sup`
            // see: https://github.com/kbknapp/clap-rs/blob/2724ec5399c500b12a1a24d356f4090f4816f5e2/src/app/mod.rs#L373-L394
            usage = "hab sup run [FLAGS] [OPTIONS] [--] [PKG_IDENT_OR_ARTIFACT]",
            rename_all = "screamingsnake",
        )]
#[allow(dead_code)]
pub struct SupRun {
    /// The listen address for the Gossip Gateway
    #[structopt(long = "listen-gossip",
                env = GossipListenAddr::ENVVAR,
                default_value = GossipListenAddr::default_as_str())]
    pub listen_gossip: GossipListenAddr,
    /// Start the supervisor in local mode
    #[structopt(long = "local-gossip-mode",
                conflicts_with_all = &["LISTEN_GOSSIP", "PEER", "PEER_WATCH_FILE"])]
    pub local_gossip_mode: bool,
    /// The listen address for the HTTP Gateway
    #[structopt(long = "listen-http",
                env = HttpListenAddr::ENVVAR,
                default_value = HttpListenAddr::default_as_str())]
    pub listen_http: HttpListenAddr,
    /// Disable the HTTP Gateway completely
    #[structopt(long = "http-disable", short = "D")]
    pub http_disable: bool,
    /// The listen address for the Control Gateway
    #[structopt(long = "listen-ctl",
                env = ListenCtlAddr::ENVVAR,
                default_value = ListenCtlAddr::default_as_str())]
    pub listen_ctl: ListenCtlAddr,
    /// The organization the Supervisor and its services are part of
    #[structopt(long = "org")]
    pub organization: Option<String>,
    /// The listen address of one or more initial peers (IP[:PORT])
    // TODO (DM): Currently there is not a good way to use `parse_peer` when deserializing. Due to
    // https://github.com/serde-rs/serde/issues/723. There are workarounds but they are all ugly.
    // This means that you have to specify the port when setting this with a config file.
    #[structopt(long = "peer", parse(try_from_str = parse_peer))]
    #[serde(default)]
    pub peer: Vec<SocketAddr>,
    /// Make this Supervisor a permanent peer
    #[structopt(long = "permanent-peer", short = "I")]
    pub permanent_peer: bool,
    /// Watch this file for connecting to the ring
    #[structopt(long = "peer-watch-file", conflicts_with = "PEER")]
    pub peer_watch_file: Option<PathBuf>,
    #[structopt(flatten)]
    #[serde(flatten)]
    pub cache_key_path: CacheKeyPath,
    /// The name of the ring used by the Supervisor when running with wire encryption
    #[structopt(long = "ring",
                short = "r",
                env = RING_ENVVAR,
                conflicts_with = "RING_KEY")]
    pub ring: Option<String>,
    /// The contents of the ring key when running with wire encryption
    ///
    /// This option is explicitly undocumented and for testing purposes only. Do not use it in a
    /// production system. Use the corresponding environment variable instead. (ex:
    /// 'SYM-SEC-1\nfoo-20181113185935\n\nGCrBOW6CCN75LMl0j2V5QqQ6nNzWm6and9hkKBSUFPI=')
    #[structopt(long = "ring-key",
                env = RING_KEY_ENVVAR,
                hidden = true)]
    pub ring_key: Option<String>,
    /// Use the package config from this path rather than the package itself
    #[structopt(long = "config-from")]
    pub config_from: Option<PathBuf>,
    /// Enable automatic updates for the Supervisor itself
    #[structopt(long = "auto-update", short = "A")]
    pub auto_update: bool,
    /// The private key for HTTP Gateway TLS encryption
    ///
    /// Read the private key from KEY_FILE. This should be an RSA private key or PKCS8-encoded
    /// private key in PEM format.
    #[structopt(long = "key", requires = "CERT_FILE")]
    pub key_file: Option<PathBuf>,
    /// The server certificates for HTTP Gateway TLS encryption
    ///
    /// Read server certificates from CERT_FILE. This should contain PEM-format certificates in
    /// the right order. The first certificate should certify KEY_FILE. The last should be a
    /// root CA.
    #[structopt(long = "certs", requires = "KEY_FILE")]
    pub cert_file: Option<PathBuf>,
    /// The CA certificate for HTTP Gateway TLS encryption
    ///
    /// Read the CA certificate from CA_CERT_FILE. This should contain PEM-format certificate that
    /// can be used to validate client requests
    #[structopt(long = "ca-certs",
                requires_all = &["CERT_FILE", "KEY_FILE"])]
    pub ca_cert_file: Option<PathBuf>,
    /// Load a Habitat package as part of the Supervisor startup
    ///
    /// The package can be specified by a package identifier (ex: core/redis) or filepath to a
    /// Habitat artifact (ex: /home/core-redis-3.0.7-21120102031201-x86_64-linux.hart).
    #[structopt()]
    pub pkg_ident_or_artifact: Option<InstallSource>,
    /// Verbose output showing file and line/column numbers
    #[structopt(short = "v")]
    pub verbose: bool,
    /// Turn ANSI color off
    #[structopt(long = "no-color")]
    pub no_color: bool,
    /// Use structured JSON logging for the Supervisor
    ///
    /// This option also sets NO_COLOR.
    #[structopt(long = "json-logging")]
    pub json_logging: bool,
    /// The IPv4 address to use as the `sys.ip` template variable
    ///
    /// If this argument is not set, the supervisor tries to dynamically determine an IP address.
    /// If that fails, the supervisor defaults to using `127.0.0.1`.
    #[structopt(long = "sys-ip-address")]
    pub sys_ip_address: Option<IpAddr>,
    /// The name of the application for event stream purposes
    ///
    /// This will be attached to all events generated by this Supervisor.
    #[structopt(long = "event-stream-application", empty_values = false)]
    pub event_stream_application: Option<String>,
    /// The name of the environment for event stream purposes
    ///
    /// This will be attached to all events generated by this Supervisor.
    #[structopt(long = "event-stream-environment", empty_values = false)]
    pub event_stream_environment: Option<String>,
    /// Event stream connection timeout before exiting the Supervisor
    ///
    /// Set to '0' to immediately start the Supervisor and continue running regardless of the
    /// initial connection status.
    #[structopt(long = "event-stream-connect-timeout",
                env = EventStreamConnectMethod::ENVVAR,
                default_value = "0")]
    pub event_stream_connect_timeout: EventStreamConnectMethod,
    /// The event stream connection url used to send events to Chef Automate
    ///
    /// This enables the event stream and requires EVENT_STREAM_APPLICATION,
    /// EVENT_STREAM_ENVIRONMENT, and EVENT_STREAM_TOKEN also be set.
    #[structopt(long = "event-stream-url",
                requires_all = &["EVENT_STREAM_APPLICATION",
                                 "EVENT_STREAM_ENVIRONMENT",
                                 EventStreamToken::ARG_NAME])]
    pub event_stream_url: Option<EventStreamAddress>,
    /// The name of the site where this Supervisor is running for event stream purposes
    #[structopt(long = "event-stream-site", empty_values = false)]
    pub event_stream_site: Option<String>,
    /// The authentication token for connecting the event stream to Chef Automate
    #[structopt(long = "event-stream-token",
                env = EventStreamToken::ENVVAR)]
    pub event_stream_token: Option<EventStreamToken>,
    /// An arbitrary key-value pair to add to each event generated by this Supervisor
    #[structopt(long = "event-meta")]
    #[serde(default)]
    pub event_meta: Vec<EventStreamMetaPair>,
    /// The path to Chef Automate's event stream certificate used to establish a TLS connection
    ///
    /// The certificate should be in PEM format.
    #[structopt(long = "event-stream-server-certificate")]
    pub event_stream_server_certificate: Option<EventStreamServerCertificate>,
    /// Automatically cleanup old packages
    ///
    /// The Supervisor will automatically cleanup old packages only keeping the
    /// KEEP_LATEST_PACKAGES latest packages. If this argument is not specified, no
    /// automatic package cleanup is performed.
    #[structopt(long = "keep-latest-packages", env = "HAB_KEEP_LATEST_PACKAGES")]
    pub keep_latest_packages: Option<usize>,
    #[structopt(flatten)]
    #[serde(flatten)]
    pub shared_load: SharedLoad,
}

#[derive(ConfigOpt, StructOpt)]
#[structopt(no_version)]
/// Commands relating to a Habitat Supervisor's Control Gateway secret
pub enum Secret {
    /// Generate a secret key to use as a Supervisor's Control Gateway secret
    Generate,
}
<|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/. */

<commit_msg>Auto merge of #2404 - mrobinson:remove-empty-api.rs, r=kvark<commit_after><|endoftext|>


<commit_before>use winapi::shared::windef::{HWND, HMENU};
use crate::win32::window_helper as wh;

/**
    Inner handle type used internally by each control.
*/
#[derive(Debug, Clone, Copy)]
pub enum ControlHandle {
    NoHandle,
    Hwnd(HWND),

    /// (Parent menu / Menu).
    /// Parent menu must be there as WINAPI does not have any function to fetch the parent
    Menu(HMENU, HMENU),

    /// (Parent window / Menu).
    PopMenu(HWND, HMENU),

    /// (Parent menu / Unique ID).
    MenuItem(HMENU, u32),

    /// Notice control
    Notice(HWND, u32),

    /// Timer control
    Timer(HWND, u32),

    /// System tray control
    SystemTray(HWND)
}

impl ControlHandle {

    /// Destroy the underlying object and set the handle to `NoHandle`
    /// Can be used to "reset" a UI component
    pub fn destroy(&mut self) {
        match self {
            &mut ControlHandle::Hwnd(h) => wh::destroy_window(h),
            &mut ControlHandle::Menu(_parent, m) => wh::destroy_menu(m),
            &mut ControlHandle::MenuItem(parent, id) => wh::destroy_menu_item(parent, id),
            &mut ControlHandle::PopMenu(_parent, m) => wh::destroy_menu(m),
            _ => {}
        }

        *self = ControlHandle::NoHandle;
    }

    pub fn blank(&self) -> bool {
        match self {
            &ControlHandle::NoHandle => true,
            _ => false
        }
    }

    pub fn hwnd(&self) -> Option<HWND> {
        match self {
            &ControlHandle::Hwnd(h) => Some(h),
            _ => None,
        }
    }

    pub fn hmenu(&self) -> Option<(HMENU, HMENU)> {
        match self {
            &ControlHandle::Menu(h1, h2) => Some((h1, h2)),
            _ => None,
        }
    }

    pub fn pop_hmenu(&self) -> Option<(HWND, HMENU)> {
        match self {
            &ControlHandle::PopMenu(h1, h2) => Some((h1, h2)),
            _ => None,
        }
    }

    pub fn hmenu_item(&self) -> Option<(HMENU, u32)> {
        match self {
            &ControlHandle::MenuItem(h, i) => Some((h, i)),
            _ => None,
        }
    }

    pub fn timer(&self) -> Option<(HWND, u32)> {
        match self {
            &ControlHandle::Timer(h, i) => Some((h, i)),
            _ => None,
        }
    }

    pub fn notice(&self) -> Option<(HWND, u32)> {
        match self {
            &ControlHandle::Notice(h, i) => Some((h, i)),
            _ => None,
        }
    }

    pub fn tray(&self) -> Option<HWND> {
        match self {
            &ControlHandle::SystemTray(h) => Some(h),
            _ => None,
        }
    }

}

impl Default for ControlHandle {

    fn default() -> ControlHandle {
        ControlHandle::NoHandle
    }

}

impl PartialEq for ControlHandle {
    fn eq(&self, other: &Self) -> bool {
        match self {
            // NoHandle
            &ControlHandle::NoHandle => match other {
                &ControlHandle::NoHandle => true,
                _ => false
            },
            // HWND
            &ControlHandle::Hwnd(hwnd1) => match other {
                &ControlHandle::Hwnd(hwnd2) => hwnd1 == hwnd2,
                _ => false
            },
            // HMENU
            &ControlHandle::Menu(_, h1) => match other {
                &ControlHandle::Menu(_, h2) => h1 == h2,
                _ => false
            },
            // HMENU
            &ControlHandle::PopMenu(_, h1) => match other {
                &ControlHandle::Menu(_, h2) => h1 == h2,
                _ => false
            },
            // HMENU / ITEM
            &ControlHandle::MenuItem(_, id1) => match other {
                &ControlHandle::MenuItem(_, id2) => id1 == id2,
                _ => false
            },
            // TIMER
            &ControlHandle::Timer(hwnd1, id1) => match other {
                &ControlHandle::Timer(hwnd2, id2) => hwnd1 == hwnd2 && id1 == id2,
                _ => false
            },
            // Notice
            &ControlHandle::Notice(hwnd1, id1) => match other {
                &ControlHandle::Notice(hwnd2, id2) => hwnd1 == hwnd2 && id1 == id2,
                _ => false
            },
            // System tray
            &ControlHandle::SystemTray(hwnd1) => match other {
                &ControlHandle::SystemTray(hwnd2) => hwnd1 == hwnd2,
                _ => false
            }
        }
    }
}

impl Eq for ControlHandle {}

impl From<&ControlHandle> for ControlHandle {
    fn from(control: &ControlHandle) -> Self { *control }
}
<commit_msg>Fix `PartialEq` for `ControlHandle`<commit_after>use winapi::shared::windef::{HWND, HMENU};
use crate::win32::window_helper as wh;

/**
    Inner handle type used internally by each control.
*/
#[derive(Debug, Clone, Copy)]
pub enum ControlHandle {
    NoHandle,
    Hwnd(HWND),

    /// (Parent menu / Menu).
    /// Parent menu must be there as WINAPI does not have any function to fetch the parent
    Menu(HMENU, HMENU),

    /// (Parent window / Menu).
    PopMenu(HWND, HMENU),

    /// (Parent menu / Unique ID).
    MenuItem(HMENU, u32),

    /// Notice control
    Notice(HWND, u32),

    /// Timer control
    Timer(HWND, u32),

    /// System tray control
    SystemTray(HWND)
}

impl ControlHandle {

    /// Destroy the underlying object and set the handle to `NoHandle`
    /// Can be used to "reset" a UI component
    pub fn destroy(&mut self) {
        match self {
            &mut ControlHandle::Hwnd(h) => wh::destroy_window(h),
            &mut ControlHandle::Menu(_parent, m) => wh::destroy_menu(m),
            &mut ControlHandle::MenuItem(parent, id) => wh::destroy_menu_item(parent, id),
            &mut ControlHandle::PopMenu(_parent, m) => wh::destroy_menu(m),
            _ => {}
        }

        *self = ControlHandle::NoHandle;
    }

    pub fn blank(&self) -> bool {
        match self {
            &ControlHandle::NoHandle => true,
            _ => false
        }
    }

    pub fn hwnd(&self) -> Option<HWND> {
        match self {
            &ControlHandle::Hwnd(h) => Some(h),
            _ => None,
        }
    }

    pub fn hmenu(&self) -> Option<(HMENU, HMENU)> {
        match self {
            &ControlHandle::Menu(h1, h2) => Some((h1, h2)),
            _ => None,
        }
    }

    pub fn pop_hmenu(&self) -> Option<(HWND, HMENU)> {
        match self {
            &ControlHandle::PopMenu(h1, h2) => Some((h1, h2)),
            _ => None,
        }
    }

    pub fn hmenu_item(&self) -> Option<(HMENU, u32)> {
        match self {
            &ControlHandle::MenuItem(h, i) => Some((h, i)),
            _ => None,
        }
    }

    pub fn timer(&self) -> Option<(HWND, u32)> {
        match self {
            &ControlHandle::Timer(h, i) => Some((h, i)),
            _ => None,
        }
    }

    pub fn notice(&self) -> Option<(HWND, u32)> {
        match self {
            &ControlHandle::Notice(h, i) => Some((h, i)),
            _ => None,
        }
    }

    pub fn tray(&self) -> Option<HWND> {
        match self {
            &ControlHandle::SystemTray(h) => Some(h),
            _ => None,
        }
    }

}

impl Default for ControlHandle {

    fn default() -> ControlHandle {
        ControlHandle::NoHandle
    }

}

impl PartialEq for ControlHandle {
    fn eq(&self, other: &Self) -> bool {
        match self {
            // NoHandle
            &ControlHandle::NoHandle => match other {
                &ControlHandle::NoHandle => true,
                _ => false
            },
            // HWND
            &ControlHandle::Hwnd(hwnd1) => match other {
                &ControlHandle::Hwnd(hwnd2) => hwnd1 == hwnd2,
                _ => false
            },
            // HMENU
            &ControlHandle::Menu(_, h1) => match other {
                &ControlHandle::Menu(_, h2) => h1 == h2,
                _ => false
            },
            // HMENU
            &ControlHandle::PopMenu(_, h1) => match other {
                &ControlHandle::PopMenu(_, h2) => h1 == h2,
                _ => false
            },
            // HMENU / ITEM
            &ControlHandle::MenuItem(_, id1) => match other {
                &ControlHandle::MenuItem(_, id2) => id1 == id2,
                _ => false
            },
            // TIMER
            &ControlHandle::Timer(hwnd1, id1) => match other {
                &ControlHandle::Timer(hwnd2, id2) => hwnd1 == hwnd2 && id1 == id2,
                _ => false
            },
            // Notice
            &ControlHandle::Notice(hwnd1, id1) => match other {
                &ControlHandle::Notice(hwnd2, id2) => hwnd1 == hwnd2 && id1 == id2,
                _ => false
            },
            // System tray
            &ControlHandle::SystemTray(hwnd1) => match other {
                &ControlHandle::SystemTray(hwnd2) => hwnd1 == hwnd2,
                _ => false
            }
        }
    }
}

impl Eq for ControlHandle {}

impl From<&ControlHandle> for ControlHandle {
    fn from(control: &ControlHandle) -> Self { *control }
}
<|endoftext|>


<commit_before>extern crate libc;

use libc::c_char;

use std::ffi::{
    CStr,
    CString,
};

#[no_mangle]
pub extern fn hello() {
    println!("hello")
}

#[no_mangle]
pub extern fn add(a: i64, b: i64) -> i64 {
    a + b
}

#[no_mangle]
pub extern fn length(str: *const c_char) -> i64 {
    let c_str = unsafe { CStr::from_ptr(str) };

    c_str.to_bytes().len() as i64
}

fn to_str<'a>(c_str: *const c_char) -> &'a str {
    unsafe { CStr::from_ptr(c_str) }
        .to_str()
        .unwrap()

}

fn to_c_string(string: String) -> *const c_char {
    CString::new(string)
        .unwrap()
        .into_raw()
}

#[no_mangle]
pub extern fn duplicate(
    count: i64,
    c_msg: *const c_char,
) -> *mut c_char {
    let msg = to_str(c_msg);

    let out = std::iter::repeat(msg)
        .take(count as usize)
        .collect::<String>();

    CString::new(out)  // TODO unable to to_c_string here.. (mut vs. const)
        .unwrap()
        .into_raw()
}

#[no_mangle]
pub extern fn release(msg: *mut c_char) {
    unsafe { CString::from_raw(msg) };
}

#[repr(C)]
pub struct DuplicateString {
    msg: *const c_char,
    count: i32,
}

#[no_mangle]
pub extern fn add_duplicate_strings(
    c_ds1: *const DuplicateString,
    c_ds2: *const DuplicateString,
    c_result: *mut DuplicateString,
) {
    let (ds1, ds2, mut result) = unsafe { (
        &*c_ds1,
        &*c_ds2,
        &mut *c_result
    ) };

    let ds1msg = to_str(ds1.msg);
    let ds2msg = to_str(ds2.msg);

    result.msg = to_c_string([ds1msg, ds2msg].join("|"));
    result.count = ds1.count + ds2.count;
}

#[repr(C)]
pub struct Point {
    x: i32,
    y: i32,
}

#[no_mangle]
pub extern fn add_points(
    c_p1: *const Point,
    c_p2: *const Point,
    c_result: *mut Point,
) {
    let (p1, p2, mut result) = unsafe { (&*c_p1, &*c_p2, &mut *c_result) };

    result.x = p1.x + p2.x;
    result.y = p1.y + p2.y;
}
<commit_msg>Use to_c_string<commit_after>extern crate libc;

use libc::c_char;

use std::ffi::{
    CStr,
    CString,
};

#[no_mangle]
pub extern fn hello() {
    println!("hello")
}

#[no_mangle]
pub extern fn add(a: i64, b: i64) -> i64 {
    a + b
}

#[no_mangle]
pub extern fn length(str: *const c_char) -> i64 {
    let c_str = unsafe { CStr::from_ptr(str) };

    c_str.to_bytes().len() as i64
}

fn to_str<'a>(c_str: *const c_char) -> &'a str {
    unsafe { CStr::from_ptr(c_str) }
        .to_str()
        .unwrap()

}

fn to_c_string(string: String) -> *mut c_char {
    CString::new(string)
        .unwrap()
        .into_raw()
}

#[no_mangle]
pub extern fn duplicate(
    count: i64,
    c_msg: *const c_char,
) -> *mut c_char {
    let msg = to_str(c_msg);

    let out = std::iter::repeat(msg)
        .take(count as usize)
        .collect::<String>();

    to_c_string(out)
}

#[no_mangle]
pub extern fn release(msg: *mut c_char) {
    unsafe { CString::from_raw(msg) };
}

#[repr(C)]
pub struct DuplicateString {
    msg: *const c_char,
    count: i32,
}

#[no_mangle]
pub extern fn add_duplicate_strings(
    c_ds1: *const DuplicateString,
    c_ds2: *const DuplicateString,
    c_result: *mut DuplicateString,
) {
    let (ds1, ds2, mut result) = unsafe { (
        &*c_ds1,
        &*c_ds2,
        &mut *c_result
    ) };

    let (ds1msg, ds2msg) = (to_str(ds1.msg), to_str(ds2.msg));

    result.msg = to_c_string([ds1msg, ds2msg].join("|"));
    result.count = ds1.count + ds2.count;
}

#[repr(C)]
pub struct Point {
    x: i32,
    y: i32,
}

#[no_mangle]
pub extern fn add_points(
    c_p1: *const Point,
    c_p2: *const Point,
    c_result: *mut Point,
) {
    let (p1, p2, mut result) = unsafe { (&*c_p1, &*c_p2, &mut *c_result) };

    result.x = p1.x + p2.x;
    result.y = p1.y + p2.y;
}
<|endoftext|>


<commit_before>use tokio::sync::oneshot;

use crate::ipc_protocol::{ServerOneshotSender, ServerResponse, DrawingProp, DrawingPropValue};

use super::HandlerError;
use super::super::{
    event_loop_notifier::EventLoopNotifier,
    state::DrawingState,
    access_control::{AccessControl, RequiredData},
};

pub(crate) async fn drawing_prop(
    data_req_queued: oneshot::Sender<()>,
    conn: ServerOneshotSender,
    app_control: &AccessControl,
    prop: DrawingProp,
) -> Result<(), HandlerError> {
    let mut data = app_control.get(RequiredData {
        drawing: true,
        turtles: None,
    }, data_req_queued).await;

    let drawing = data.drawing_mut();

    use DrawingProp::*;
    let value = match prop {
        Title => DrawingPropValue::Title(drawing.title.clone()),
        Background => DrawingPropValue::Background(drawing.background),
        Center => DrawingPropValue::Center(drawing.center),
        Size => DrawingPropValue::Size(crate::Size {width: drawing.width, height: drawing.height}),
        Width => DrawingPropValue::Width(drawing.width),
        Height => DrawingPropValue::Height(drawing.height),
        IsMaximized => DrawingPropValue::IsMaximized(drawing.is_maximized),
        IsFullscreen => DrawingPropValue::IsFullscreen(drawing.is_fullscreen),
    };

    conn.send(ServerResponse::DrawingProp(value))?;

    Ok(())
}

pub(crate) async fn set_drawing_prop(
    data_req_queued: oneshot::Sender<()>,
    app_control: &AccessControl,
    event_loop: EventLoopNotifier,
    prop_value: DrawingPropValue,
) -> Result<(), HandlerError> {
    let mut data = app_control.get(RequiredData {
        drawing: true,
        turtles: None,
    }, data_req_queued).await;

    let drawing = data.drawing_mut();

    modify_drawing(drawing, event_loop, prop_value).await
}

pub(crate) async fn reset_drawing_prop(
    data_req_queued: oneshot::Sender<()>,
    app_control: &AccessControl,
    event_loop: EventLoopNotifier,
    prop: DrawingProp,
) -> Result<(), HandlerError> {
    let mut data = app_control.get(RequiredData {
        drawing: true,
        turtles: None,
    }, data_req_queued).await;

    let drawing = data.drawing_mut();

    use DrawingProp::*;
    modify_drawing(drawing, event_loop, match prop {
        Title => DrawingPropValue::Title(DrawingState::DEFAULT_TITLE.to_string()),
        Background => DrawingPropValue::Background(DrawingState::DEFAULT_BACKGROUND),
        Center => DrawingPropValue::Center(DrawingState::DEFAULT_CENTER),
        Size => DrawingPropValue::Size(crate::Size {
            width: DrawingState::DEFAULT_WIDTH,
            height: DrawingState::DEFAULT_HEIGHT,
        }),
        Width => DrawingPropValue::Width(DrawingState::DEFAULT_WIDTH),
        Height => DrawingPropValue::Height(DrawingState::DEFAULT_HEIGHT),
        IsMaximized => DrawingPropValue::IsMaximized(DrawingState::DEFAULT_IS_MAXIMIZED),
        IsFullscreen => DrawingPropValue::IsFullscreen(DrawingState::DEFAULT_IS_FULLSCREEN),
    }).await
}

async fn modify_drawing(
    drawing: &mut DrawingState,
    event_loop: EventLoopNotifier,
    prop_value: DrawingPropValue,
) -> Result<(), HandlerError> {
    use DrawingPropValue::*;
    match prop_value {
        Title(title) => {
            drawing.title = title.clone();

            // Signal the main thread to change this property on the window
            event_loop.set_title(title)?;
        },

        Background(background) => drawing.background = background,

        Center(center) => drawing.center = center,

        Size(crate::Size {width, height}) => {
            drawing.width = width;
            drawing.height = height;

            // Signal the main thread to change this property on the window
            event_loop.set_size((width, height))?;
        },

        Width(width) => {
            drawing.width = width;

            // Signal the main thread to change this property on the window
            event_loop.set_size((width, drawing.height))?;
        },

        Height(height) => {
            drawing.height = height;

            // Signal the main thread to change this property on the window
            event_loop.set_size((drawing.width, height))?;
        },

        IsMaximized(is_maximized) => {
            drawing.is_maximized = is_maximized;

            // Signal the main thread to change this property on the window
            event_loop.set_is_maximized(is_maximized)?;
        },

        IsFullscreen(is_fullscreen) => {
            drawing.is_fullscreen = is_fullscreen;

            // Signal the main thread to change this property on the window
            event_loop.set_is_fullscreen(is_fullscreen)?;
        },
    }

    Ok(())
}
<commit_msg>Need to request redraw after changing background or center<commit_after>use tokio::sync::oneshot;

use crate::ipc_protocol::{ServerOneshotSender, ServerResponse, DrawingProp, DrawingPropValue};

use super::HandlerError;
use super::super::{
    event_loop_notifier::EventLoopNotifier,
    state::DrawingState,
    access_control::{AccessControl, RequiredData},
};

pub(crate) async fn drawing_prop(
    data_req_queued: oneshot::Sender<()>,
    conn: ServerOneshotSender,
    app_control: &AccessControl,
    prop: DrawingProp,
) -> Result<(), HandlerError> {
    let mut data = app_control.get(RequiredData {
        drawing: true,
        turtles: None,
    }, data_req_queued).await;

    let drawing = data.drawing_mut();

    use DrawingProp::*;
    let value = match prop {
        Title => DrawingPropValue::Title(drawing.title.clone()),
        Background => DrawingPropValue::Background(drawing.background),
        Center => DrawingPropValue::Center(drawing.center),
        Size => DrawingPropValue::Size(crate::Size {width: drawing.width, height: drawing.height}),
        Width => DrawingPropValue::Width(drawing.width),
        Height => DrawingPropValue::Height(drawing.height),
        IsMaximized => DrawingPropValue::IsMaximized(drawing.is_maximized),
        IsFullscreen => DrawingPropValue::IsFullscreen(drawing.is_fullscreen),
    };

    conn.send(ServerResponse::DrawingProp(value))?;

    Ok(())
}

pub(crate) async fn set_drawing_prop(
    data_req_queued: oneshot::Sender<()>,
    app_control: &AccessControl,
    event_loop: EventLoopNotifier,
    prop_value: DrawingPropValue,
) -> Result<(), HandlerError> {
    let mut data = app_control.get(RequiredData {
        drawing: true,
        turtles: None,
    }, data_req_queued).await;

    let drawing = data.drawing_mut();

    modify_drawing(drawing, event_loop, prop_value).await
}

pub(crate) async fn reset_drawing_prop(
    data_req_queued: oneshot::Sender<()>,
    app_control: &AccessControl,
    event_loop: EventLoopNotifier,
    prop: DrawingProp,
) -> Result<(), HandlerError> {
    let mut data = app_control.get(RequiredData {
        drawing: true,
        turtles: None,
    }, data_req_queued).await;

    let drawing = data.drawing_mut();

    use DrawingProp::*;
    modify_drawing(drawing, event_loop, match prop {
        Title => DrawingPropValue::Title(DrawingState::DEFAULT_TITLE.to_string()),
        Background => DrawingPropValue::Background(DrawingState::DEFAULT_BACKGROUND),
        Center => DrawingPropValue::Center(DrawingState::DEFAULT_CENTER),
        Size => DrawingPropValue::Size(crate::Size {
            width: DrawingState::DEFAULT_WIDTH,
            height: DrawingState::DEFAULT_HEIGHT,
        }),
        Width => DrawingPropValue::Width(DrawingState::DEFAULT_WIDTH),
        Height => DrawingPropValue::Height(DrawingState::DEFAULT_HEIGHT),
        IsMaximized => DrawingPropValue::IsMaximized(DrawingState::DEFAULT_IS_MAXIMIZED),
        IsFullscreen => DrawingPropValue::IsFullscreen(DrawingState::DEFAULT_IS_FULLSCREEN),
    }).await
}

async fn modify_drawing(
    drawing: &mut DrawingState,
    event_loop: EventLoopNotifier,
    prop_value: DrawingPropValue,
) -> Result<(), HandlerError> {
    use DrawingPropValue::*;
    match prop_value {
        Title(title) => {
            drawing.title = title.clone();

            // Signal the main thread to change this property on the window
            event_loop.set_title(title)?;
        },

        Background(background) => {
            drawing.background = background;

            // Signal the main thread that the image has changed
            event_loop.request_redraw()?;
        },

        Center(center) => {
            drawing.center = center;

            // Signal the main thread that the image has changed
            event_loop.request_redraw()?;
        },

        Size(crate::Size {width, height}) => {
            drawing.width = width;
            drawing.height = height;

            // Signal the main thread to change this property on the window
            event_loop.set_size((width, height))?;
        },

        Width(width) => {
            drawing.width = width;

            // Signal the main thread to change this property on the window
            event_loop.set_size((width, drawing.height))?;
        },

        Height(height) => {
            drawing.height = height;

            // Signal the main thread to change this property on the window
            event_loop.set_size((drawing.width, height))?;
        },

        IsMaximized(is_maximized) => {
            drawing.is_maximized = is_maximized;

            // Signal the main thread to change this property on the window
            event_loop.set_is_maximized(is_maximized)?;
        },

        IsFullscreen(is_fullscreen) => {
            drawing.is_fullscreen = is_fullscreen;

            // Signal the main thread to change this property on the window
            event_loop.set_is_fullscreen(is_fullscreen)?;
        },
    }

    Ok(())
}
<|endoftext|>


<commit_before><commit_msg>make all the tests pass again<commit_after><|endoftext|>


<commit_before>// Copyright 2021 Pants project contributors (see CONTRIBUTORS.md).
// Licensed under the Apache License, Version 2.0 (see LICENSE).

fn main() {
  // NB: The native extension only works with the Python interpreter version it was built with
  // (e.g. Python 3.7 vs 3.8).
  println!("cargo:rerun-if-env-changed=PY");

  if cfg!(target_os = "macos") {
    // N.B. On OSX, we force weak linking by passing the param `-undefined dynamic_lookup` to
    // the underlying linker. This avoids "missing symbol" errors for Python symbols
    // (e.g. `_PyImport_ImportModule`) at build time when bundling the PyO3 sources.
    // The missing symbols will instead by dynamically resolved in the address space of the parent
    // binary (e.g. `python`) at runtime. We do this to avoid needing to link to libpython
    // (which would constrain us to specific versions of Python).
    println!("cargo:rustc-cdylib-link-arg=-undefined");
    println!("cargo:rustc-cdylib-link-arg=dynamic_lookup");
  }
}
<commit_msg>Fix engine_pyo3/build.rs missing clippy. (#12196)<commit_after>// Copyright 2021 Pants project contributors (see CONTRIBUTORS.md).
// Licensed under the Apache License, Version 2.0 (see LICENSE).

#![deny(warnings)]
// Enable all clippy lints except for many of the pedantic ones. It's a shame this needs to be copied and pasted across crates, but there doesn't appear to be a way to include inner attributes from a common source.
#![deny(
  clippy::all,
  clippy::default_trait_access,
  clippy::expl_impl_clone_on_copy,
  clippy::if_not_else,
  clippy::needless_continue,
  clippy::unseparated_literal_suffix,
  // TODO: Falsely triggers for async/await:
  //   see https://github.com/rust-lang/rust-clippy/issues/5360
  // clippy::used_underscore_binding
)]
// It is often more clear to show that nothing is being moved.
#![allow(clippy::match_ref_pats)]
// Subjective style.
#![allow(
  clippy::len_without_is_empty,
  clippy::redundant_field_names,
  clippy::too_many_arguments
)]
// Default isn't as big a deal as people seem to think it is.
#![allow(clippy::new_without_default, clippy::new_ret_no_self)]
// Arc<Mutex> can be more clear than needing to grok Orderings:
#![allow(clippy::mutex_atomic)]

fn main() {
  // NB: The native extension only works with the Python interpreter version it was built with
  // (e.g. Python 3.7 vs 3.8).
  println!("cargo:rerun-if-env-changed=PY");

  if cfg!(target_os = "macos") {
    // N.B. On OSX, we force weak linking by passing the param `-undefined dynamic_lookup` to
    // the underlying linker. This avoids "missing symbol" errors for Python symbols
    // (e.g. `_PyImport_ImportModule`) at build time when bundling the PyO3 sources.
    // The missing symbols will instead by dynamically resolved in the address space of the parent
    // binary (e.g. `python`) at runtime. We do this to avoid needing to link to libpython
    // (which would constrain us to specific versions of Python).
    println!("cargo:rustc-cdylib-link-arg=-undefined");
    println!("cargo:rustc-cdylib-link-arg=dynamic_lookup");
  }
}
<|endoftext|>


<commit_before>import syntax::print::pprust;

fn check_alt(fcx: @fn_ctxt,
             expr: @ast::expr,
             discrim: @ast::expr,
             arms: ~[ast::arm]) -> bool {
    let tcx = fcx.ccx.tcx;
    let mut bot;

    let pattern_ty = fcx.infcx.next_ty_var();
    bot = check_expr_with(fcx, discrim, pattern_ty);

    // Typecheck the patterns first, so that we get types for all the
    // bindings.
    for arms.each |arm| {
        let pcx = {
            fcx: fcx,
            map: pat_id_map(tcx.def_map, arm.pats[0]),
            alt_region: ty::re_scope(expr.id),
            block_region: ty::re_scope(arm.body.node.id),
            pat_region: ty::re_scope(expr.id)
        };

        for arm.pats.each |p| { check_pat(pcx, p, pattern_ty);}
    }
    // Now typecheck the blocks.
    let mut result_ty = fcx.infcx.next_ty_var();
    let mut arm_non_bot = false;
    for arms.each |arm| {
        match arm.guard {
          some(e) => { check_expr_with(fcx, e, ty::mk_bool(tcx)); },
          none => ()
        }
        if !check_block(fcx, arm.body) { arm_non_bot = true; }
        let bty = fcx.node_ty(arm.body.node.id);
        demand::suptype(fcx, arm.body.span, result_ty, bty);
    }
    bot |= !arm_non_bot;
    if !arm_non_bot { result_ty = ty::mk_bot(tcx); }
    fcx.write_ty(expr.id, result_ty);
    return bot;
}

type pat_ctxt = {
    fcx: @fn_ctxt,
    map: pat_id_map,
    alt_region: ty::region,
    block_region: ty::region,
    /* Equal to either alt_region or block_region. */
    pat_region: ty::region
};

fn check_pat_variant(pcx: pat_ctxt, pat: @ast::pat, path: @ast::path,
                     subpats: option<~[@ast::pat]>, expected: ty::t) {

    // Typecheck the path.
    let fcx = pcx.fcx;
    let tcx = pcx.fcx.ccx.tcx;

    // Lookup the enum and variant def ids:
    let v_def = lookup_def(pcx.fcx, path.span, pat.id);
    let v_def_ids = ast_util::variant_def_ids(v_def);

    // Assign the pattern the type of the *enum*, not the variant.
    let enum_tpt = ty::lookup_item_type(tcx, v_def_ids.enm);
    instantiate_path(pcx.fcx, path, enum_tpt, pat.span, pat.id);

    // Take the enum type params out of `expected`.
    match structure_of(pcx.fcx, pat.span, expected) {
      ty::ty_enum(_, ref expected_substs) => {
        // check that the type of the value being matched is a subtype
        // of the type of the pattern:
        let pat_ty = fcx.node_ty(pat.id);
        demand::suptype(fcx, pat.span, pat_ty, expected);

        // Get the expected types of the arguments.
        let arg_types = {
            let vinfo =
                ty::enum_variant_with_id(
                    tcx, v_def_ids.enm, v_def_ids.var);
            vinfo.args.map(|t| { ty::subst(tcx, expected_substs, t) })
        };
        let arg_len = arg_types.len(), subpats_len = match subpats {
            none => arg_len,
            some(ps) => ps.len()
        };
        if arg_len > 0u {
            // N-ary variant.
            if arg_len != subpats_len {
                let s = fmt!{"this pattern has %u field%s, but the \
                              corresponding variant has %u field%s",
                             subpats_len,
                             if subpats_len == 1u { ~"" } else { ~"s" },
                             arg_len,
                             if arg_len == 1u { ~"" } else { ~"s" }};
                tcx.sess.span_fatal(pat.span, s);
            }

            do option::iter(subpats) |pats| {
                do vec::iter2(pats, arg_types) |subpat, arg_ty| {
                  check_pat(pcx, subpat, arg_ty);
                }
            };
        } else if subpats_len > 0u {
            tcx.sess.span_fatal
                (pat.span, fmt!{"this pattern has %u field%s, \
                                 but the corresponding variant has no fields",
                                subpats_len,
                                if subpats_len == 1u { ~"" }
                                else { ~"s" }});
        }
      }
      _ => {
        tcx.sess.span_fatal
            (pat.span,
             fmt!{"mismatched types: expected enum but found `%s`",
                  fcx.infcx.ty_to_str(expected)});
      }
    }
}

// Pattern checking is top-down rather than bottom-up so that bindings get
// their types immediately.
fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) {
    let fcx = pcx.fcx;
    let tcx = pcx.fcx.ccx.tcx;

    match pat.node {
      ast::pat_wild => {
        fcx.write_ty(pat.id, expected);
      }
      ast::pat_lit(lt) => {
        check_expr_with(fcx, lt, expected);
        fcx.write_ty(pat.id, fcx.expr_ty(lt));
      }
      ast::pat_range(begin, end) => {
        check_expr_with(fcx, begin, expected);
        check_expr_with(fcx, end, expected);
        let b_ty =
            fcx.infcx.resolve_type_vars_if_possible(fcx.expr_ty(begin));
        let e_ty =
            fcx.infcx.resolve_type_vars_if_possible(fcx.expr_ty(end));
        debug!{"pat_range beginning type: %?", b_ty};
        debug!{"pat_range ending type: %?", e_ty};
        if !require_same_types(
            tcx, some(fcx.infcx), pat.span, b_ty, e_ty,
            || ~"mismatched types in range") {
            // no-op
        } else if !ty::type_is_numeric(b_ty) {
            tcx.sess.span_err(pat.span, ~"non-numeric type used in range");
        } else if !valid_range_bounds(fcx.ccx, begin, end) {
            tcx.sess.span_err(begin.span, ~"lower range bound must be less \
                                           than upper");
        }
        fcx.write_ty(pat.id, b_ty);
      }
      ast::pat_ident(bm, name, sub) if !pat_is_variant(tcx.def_map, pat) => {
        let vid = lookup_local(fcx, pat.span, pat.id);
        let mut typ = ty::mk_var(tcx, vid);

        match bm {
          ast::bind_by_ref(mutbl) => {
            // if the binding is like
            //    ref x | ref const x | ref mut x
            // then the type of x is &M T where M is the mutability
            // and T is the expected type
            let region_var =
                fcx.infcx.next_region_var({lb: some(pcx.block_region),
                                           ub: none});
            let mt = {ty: expected, mutbl: mutbl};
            let region_ty = ty::mk_rptr(tcx, region_var, mt);
            demand::eqtype(fcx, pat.span, region_ty, typ);
          }
          ast::bind_by_value | ast::bind_by_implicit_ref => {
            // otherwise the type of x is the expected type T
            demand::eqtype(fcx, pat.span, expected, typ);
          }
        }

        let canon_id = pcx.map.get(ast_util::path_to_ident(name));
        if canon_id != pat.id {
            let tv_id = lookup_local(fcx, pat.span, canon_id);
            let ct = ty::mk_var(tcx, tv_id);
            demand::eqtype(fcx, pat.span, ct, typ);
        }
        fcx.write_ty(pat.id, typ);
        match sub {
          some(p) => check_pat(pcx, p, expected),
          _ => ()
        }
      }
      ast::pat_ident(_, path, c) => {
        check_pat_variant(pcx, pat, path, some(~[]), expected);
      }
      ast::pat_enum(path, subpats) => {
        check_pat_variant(pcx, pat, path, subpats, expected);
      }
      ast::pat_rec(fields, etc) => {
        let ex_fields = match structure_of(fcx, pat.span, expected) {
          ty::ty_rec(fields) => fields,
          _ => {
            tcx.sess.span_fatal
                (pat.span,
                fmt!{"mismatched types: expected `%s` but found record",
                     fcx.infcx.ty_to_str(expected)});
          }
        };
        let f_count = vec::len(fields);
        let ex_f_count = vec::len(ex_fields);
        if ex_f_count < f_count || !etc && ex_f_count > f_count {
            tcx.sess.span_fatal
                (pat.span, fmt!{"mismatched types: expected a record \
                      with %u fields, found one with %u \
                      fields",
                                ex_f_count, f_count});
        }
        fn matches(name: ast::ident, f: ty::field) -> bool {
            str::eq(name, f.ident)
        }
        for fields.each |f| {
            match vec::find(ex_fields, |a| matches(f.ident, a)) {
              some(field) => {
                check_pat(pcx, f.pat, field.mt.ty);
              }
              none => {
                tcx.sess.span_fatal(pat.span,
                                    fmt!{"mismatched types: did not \
                                          expect a record with a field `%s`",
                                         *f.ident});
              }
            }
        }
        fcx.write_ty(pat.id, expected);
      }
      ast::pat_struct(path, fields, etc) => {
        // Grab the class data that we care about.
        let class_fields, class_id, substitutions;
        // FIXME(#3217) If this were "match structure_of...", this bug causes
        // it to not live long enough for 'substitutions'.
        let structure = structure_of(fcx, pat.span, expected);
        match structure {
            ty::ty_class(cid, ref substs) => {
                class_id = cid;
                substitutions = substs;
                class_fields = ty::lookup_class_fields(tcx, class_id);
            }
            _ => {
                // XXX: This should not be fatal.
                tcx.sess.span_fatal(pat.span,
                                    fmt!("mismatched types: expected `%s` \
                                          but found struct",
                                         fcx.infcx.ty_to_str(expected)));
            }
        }

        // Check to ensure that the struct is the one specified.
        match tcx.def_map.get(pat.id) {
            ast::def_class(supplied_def_id, _)
                    if supplied_def_id == class_id => {
                // OK.
            }
            ast::def_class(*) => {
                let name = syntax::print::pprust::path_to_str(path);
                tcx.sess.span_err(pat.span,
                                  fmt!("mismatched types: expected `%s` but \
                                        found `%s`",
                                       fcx.infcx.ty_to_str(expected),
                                       name));
            }
            _ => {
                tcx.sess.span_bug(pat.span, ~"resolve didn't write in class");
            }
        }

        // Index the class fields.
        let field_map = std::map::box_str_hash();
        for class_fields.eachi |i, class_field| {
            field_map.insert(class_field.ident, i);
        }

        // Typecheck each field.
        let found_fields = std::map::uint_hash();
        for fields.each |field| {
            match field_map.find(field.ident) {
                some(index) => {
                    let class_field = class_fields[index];
                    let field_type = ty::lookup_field_type(tcx,
                                                           class_id,
                                                           class_field.id,
                                                           substitutions);
                    check_pat(pcx, field.pat, field_type);
                    found_fields.insert(index, ());
                }
                none => {
                    let name = syntax::print::pprust::path_to_str(path);
                    tcx.sess.span_err(pat.span,
                                      fmt!("struct `%s` does not have a field
                                            named `%s`", name, *field.ident));
                }
            }
        }

        // Report an error if not all the fields were specified.
        if !etc {
            for class_fields.eachi |i, field| {
                if found_fields.contains_key(i) {
                    again;
                }
                tcx.sess.span_err(pat.span,
                                  fmt!("pattern does not mention field `%s`",
                                       *field.ident));
            }
        }

        // Finally, write in the type.
        fcx.write_ty(pat.id, expected);
      }
      ast::pat_tup(elts) => {
        let ex_elts = match structure_of(fcx, pat.span, expected) {
          ty::ty_tup(elts) => elts,
          _ => {
            tcx.sess.span_fatal
                (pat.span,
                 fmt!{"mismatched types: expected `%s`, found tuple",
                      fcx.infcx.ty_to_str(expected)});
          }
        };
        let e_count = vec::len(elts);
        if e_count != vec::len(ex_elts) {
            tcx.sess.span_fatal
                (pat.span, fmt!{"mismatched types: expected a tuple \
                      with %u fields, found one with %u \
                      fields", vec::len(ex_elts), e_count});
        }
        let mut i = 0u;
        for elts.each |elt| {
            check_pat(pcx, elt, ex_elts[i]);
            i += 1u;
        }

        fcx.write_ty(pat.id, expected);
      }
      ast::pat_box(inner) => {
        match structure_of(fcx, pat.span, expected) {
          ty::ty_box(e_inner) => {
            check_pat(pcx, inner, e_inner.ty);
            fcx.write_ty(pat.id, expected);
          }
          _ => {
            tcx.sess.span_fatal(
                pat.span,
                ~"mismatched types: expected `" +
                fcx.infcx.ty_to_str(expected) +
                ~"` found box");
          }
        }
      }
      ast::pat_uniq(inner) => {
        match structure_of(fcx, pat.span, expected) {
          ty::ty_uniq(e_inner) => {
            check_pat(pcx, inner, e_inner.ty);
            fcx.write_ty(pat.id, expected);
          }
          _ => {
            tcx.sess.span_fatal(
                pat.span,
                ~"mismatched types: expected `" +
                fcx.infcx.ty_to_str(expected) +
                ~"` found uniq");
          }
        }
      }
    }
}

<commit_msg>remove fixme in check::alt<commit_after>import syntax::print::pprust;

fn check_alt(fcx: @fn_ctxt,
             expr: @ast::expr,
             discrim: @ast::expr,
             arms: ~[ast::arm]) -> bool {
    let tcx = fcx.ccx.tcx;
    let mut bot;

    let pattern_ty = fcx.infcx.next_ty_var();
    bot = check_expr_with(fcx, discrim, pattern_ty);

    // Typecheck the patterns first, so that we get types for all the
    // bindings.
    for arms.each |arm| {
        let pcx = {
            fcx: fcx,
            map: pat_id_map(tcx.def_map, arm.pats[0]),
            alt_region: ty::re_scope(expr.id),
            block_region: ty::re_scope(arm.body.node.id),
            pat_region: ty::re_scope(expr.id)
        };

        for arm.pats.each |p| { check_pat(pcx, p, pattern_ty);}
    }
    // Now typecheck the blocks.
    let mut result_ty = fcx.infcx.next_ty_var();
    let mut arm_non_bot = false;
    for arms.each |arm| {
        match arm.guard {
          some(e) => { check_expr_with(fcx, e, ty::mk_bool(tcx)); },
          none => ()
        }
        if !check_block(fcx, arm.body) { arm_non_bot = true; }
        let bty = fcx.node_ty(arm.body.node.id);
        demand::suptype(fcx, arm.body.span, result_ty, bty);
    }
    bot |= !arm_non_bot;
    if !arm_non_bot { result_ty = ty::mk_bot(tcx); }
    fcx.write_ty(expr.id, result_ty);
    return bot;
}

type pat_ctxt = {
    fcx: @fn_ctxt,
    map: pat_id_map,
    alt_region: ty::region,
    block_region: ty::region,
    /* Equal to either alt_region or block_region. */
    pat_region: ty::region
};

fn check_pat_variant(pcx: pat_ctxt, pat: @ast::pat, path: @ast::path,
                     subpats: option<~[@ast::pat]>, expected: ty::t) {

    // Typecheck the path.
    let fcx = pcx.fcx;
    let tcx = pcx.fcx.ccx.tcx;

    // Lookup the enum and variant def ids:
    let v_def = lookup_def(pcx.fcx, path.span, pat.id);
    let v_def_ids = ast_util::variant_def_ids(v_def);

    // Assign the pattern the type of the *enum*, not the variant.
    let enum_tpt = ty::lookup_item_type(tcx, v_def_ids.enm);
    instantiate_path(pcx.fcx, path, enum_tpt, pat.span, pat.id);

    // Take the enum type params out of `expected`.
    match structure_of(pcx.fcx, pat.span, expected) {
      ty::ty_enum(_, ref expected_substs) => {
        // check that the type of the value being matched is a subtype
        // of the type of the pattern:
        let pat_ty = fcx.node_ty(pat.id);
        demand::suptype(fcx, pat.span, pat_ty, expected);

        // Get the expected types of the arguments.
        let arg_types = {
            let vinfo =
                ty::enum_variant_with_id(
                    tcx, v_def_ids.enm, v_def_ids.var);
            vinfo.args.map(|t| { ty::subst(tcx, expected_substs, t) })
        };
        let arg_len = arg_types.len(), subpats_len = match subpats {
            none => arg_len,
            some(ps) => ps.len()
        };
        if arg_len > 0u {
            // N-ary variant.
            if arg_len != subpats_len {
                let s = fmt!{"this pattern has %u field%s, but the \
                              corresponding variant has %u field%s",
                             subpats_len,
                             if subpats_len == 1u { ~"" } else { ~"s" },
                             arg_len,
                             if arg_len == 1u { ~"" } else { ~"s" }};
                tcx.sess.span_fatal(pat.span, s);
            }

            do option::iter(subpats) |pats| {
                do vec::iter2(pats, arg_types) |subpat, arg_ty| {
                  check_pat(pcx, subpat, arg_ty);
                }
            };
        } else if subpats_len > 0u {
            tcx.sess.span_fatal
                (pat.span, fmt!{"this pattern has %u field%s, \
                                 but the corresponding variant has no fields",
                                subpats_len,
                                if subpats_len == 1u { ~"" }
                                else { ~"s" }});
        }
      }
      _ => {
        tcx.sess.span_fatal
            (pat.span,
             fmt!{"mismatched types: expected enum but found `%s`",
                  fcx.infcx.ty_to_str(expected)});
      }
    }
}

// Pattern checking is top-down rather than bottom-up so that bindings get
// their types immediately.
fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) {
    let fcx = pcx.fcx;
    let tcx = pcx.fcx.ccx.tcx;

    match pat.node {
      ast::pat_wild => {
        fcx.write_ty(pat.id, expected);
      }
      ast::pat_lit(lt) => {
        check_expr_with(fcx, lt, expected);
        fcx.write_ty(pat.id, fcx.expr_ty(lt));
      }
      ast::pat_range(begin, end) => {
        check_expr_with(fcx, begin, expected);
        check_expr_with(fcx, end, expected);
        let b_ty =
            fcx.infcx.resolve_type_vars_if_possible(fcx.expr_ty(begin));
        let e_ty =
            fcx.infcx.resolve_type_vars_if_possible(fcx.expr_ty(end));
        debug!{"pat_range beginning type: %?", b_ty};
        debug!{"pat_range ending type: %?", e_ty};
        if !require_same_types(
            tcx, some(fcx.infcx), pat.span, b_ty, e_ty,
            || ~"mismatched types in range") {
            // no-op
        } else if !ty::type_is_numeric(b_ty) {
            tcx.sess.span_err(pat.span, ~"non-numeric type used in range");
        } else if !valid_range_bounds(fcx.ccx, begin, end) {
            tcx.sess.span_err(begin.span, ~"lower range bound must be less \
                                           than upper");
        }
        fcx.write_ty(pat.id, b_ty);
      }
      ast::pat_ident(bm, name, sub) if !pat_is_variant(tcx.def_map, pat) => {
        let vid = lookup_local(fcx, pat.span, pat.id);
        let mut typ = ty::mk_var(tcx, vid);

        match bm {
          ast::bind_by_ref(mutbl) => {
            // if the binding is like
            //    ref x | ref const x | ref mut x
            // then the type of x is &M T where M is the mutability
            // and T is the expected type
            let region_var =
                fcx.infcx.next_region_var({lb: some(pcx.block_region),
                                           ub: none});
            let mt = {ty: expected, mutbl: mutbl};
            let region_ty = ty::mk_rptr(tcx, region_var, mt);
            demand::eqtype(fcx, pat.span, region_ty, typ);
          }
          ast::bind_by_value | ast::bind_by_implicit_ref => {
            // otherwise the type of x is the expected type T
            demand::eqtype(fcx, pat.span, expected, typ);
          }
        }

        let canon_id = pcx.map.get(ast_util::path_to_ident(name));
        if canon_id != pat.id {
            let tv_id = lookup_local(fcx, pat.span, canon_id);
            let ct = ty::mk_var(tcx, tv_id);
            demand::eqtype(fcx, pat.span, ct, typ);
        }
        fcx.write_ty(pat.id, typ);
        match sub {
          some(p) => check_pat(pcx, p, expected),
          _ => ()
        }
      }
      ast::pat_ident(_, path, c) => {
        check_pat_variant(pcx, pat, path, some(~[]), expected);
      }
      ast::pat_enum(path, subpats) => {
        check_pat_variant(pcx, pat, path, subpats, expected);
      }
      ast::pat_rec(fields, etc) => {
        let ex_fields = match structure_of(fcx, pat.span, expected) {
          ty::ty_rec(fields) => fields,
          _ => {
            tcx.sess.span_fatal
                (pat.span,
                fmt!{"mismatched types: expected `%s` but found record",
                     fcx.infcx.ty_to_str(expected)});
          }
        };
        let f_count = vec::len(fields);
        let ex_f_count = vec::len(ex_fields);
        if ex_f_count < f_count || !etc && ex_f_count > f_count {
            tcx.sess.span_fatal
                (pat.span, fmt!{"mismatched types: expected a record \
                      with %u fields, found one with %u \
                      fields",
                                ex_f_count, f_count});
        }
        fn matches(name: ast::ident, f: ty::field) -> bool {
            str::eq(name, f.ident)
        }
        for fields.each |f| {
            match vec::find(ex_fields, |a| matches(f.ident, a)) {
              some(field) => {
                check_pat(pcx, f.pat, field.mt.ty);
              }
              none => {
                tcx.sess.span_fatal(pat.span,
                                    fmt!{"mismatched types: did not \
                                          expect a record with a field `%s`",
                                         *f.ident});
              }
            }
        }
        fcx.write_ty(pat.id, expected);
      }
      ast::pat_struct(path, fields, etc) => {
        // Grab the class data that we care about.
        let class_fields, class_id, substitutions;
        let structure = structure_of(fcx, pat.span, expected);
        match structure {
            ty::ty_class(cid, ref substs) => {
                class_id = cid;
                substitutions = substs;
                class_fields = ty::lookup_class_fields(tcx, class_id);
            }
            _ => {
                // XXX: This should not be fatal.
                tcx.sess.span_fatal(pat.span,
                                    fmt!("mismatched types: expected `%s` \
                                          but found struct",
                                         fcx.infcx.ty_to_str(expected)));
            }
        }

        // Check to ensure that the struct is the one specified.
        match tcx.def_map.get(pat.id) {
            ast::def_class(supplied_def_id, _)
                    if supplied_def_id == class_id => {
                // OK.
            }
            ast::def_class(*) => {
                let name = syntax::print::pprust::path_to_str(path);
                tcx.sess.span_err(pat.span,
                                  fmt!("mismatched types: expected `%s` but \
                                        found `%s`",
                                       fcx.infcx.ty_to_str(expected),
                                       name));
            }
            _ => {
                tcx.sess.span_bug(pat.span, ~"resolve didn't write in class");
            }
        }

        // Index the class fields.
        let field_map = std::map::box_str_hash();
        for class_fields.eachi |i, class_field| {
            field_map.insert(class_field.ident, i);
        }

        // Typecheck each field.
        let found_fields = std::map::uint_hash();
        for fields.each |field| {
            match field_map.find(field.ident) {
                some(index) => {
                    let class_field = class_fields[index];
                    let field_type = ty::lookup_field_type(tcx,
                                                           class_id,
                                                           class_field.id,
                                                           substitutions);
                    check_pat(pcx, field.pat, field_type);
                    found_fields.insert(index, ());
                }
                none => {
                    let name = syntax::print::pprust::path_to_str(path);
                    tcx.sess.span_err(pat.span,
                                      fmt!("struct `%s` does not have a field
                                            named `%s`", name, *field.ident));
                }
            }
        }

        // Report an error if not all the fields were specified.
        if !etc {
            for class_fields.eachi |i, field| {
                if found_fields.contains_key(i) {
                    again;
                }
                tcx.sess.span_err(pat.span,
                                  fmt!("pattern does not mention field `%s`",
                                       *field.ident));
            }
        }

        // Finally, write in the type.
        fcx.write_ty(pat.id, expected);
      }
      ast::pat_tup(elts) => {
        let ex_elts = match structure_of(fcx, pat.span, expected) {
          ty::ty_tup(elts) => elts,
          _ => {
            tcx.sess.span_fatal
                (pat.span,
                 fmt!{"mismatched types: expected `%s`, found tuple",
                      fcx.infcx.ty_to_str(expected)});
          }
        };
        let e_count = vec::len(elts);
        if e_count != vec::len(ex_elts) {
            tcx.sess.span_fatal
                (pat.span, fmt!{"mismatched types: expected a tuple \
                      with %u fields, found one with %u \
                      fields", vec::len(ex_elts), e_count});
        }
        let mut i = 0u;
        for elts.each |elt| {
            check_pat(pcx, elt, ex_elts[i]);
            i += 1u;
        }

        fcx.write_ty(pat.id, expected);
      }
      ast::pat_box(inner) => {
        match structure_of(fcx, pat.span, expected) {
          ty::ty_box(e_inner) => {
            check_pat(pcx, inner, e_inner.ty);
            fcx.write_ty(pat.id, expected);
          }
          _ => {
            tcx.sess.span_fatal(
                pat.span,
                ~"mismatched types: expected `" +
                fcx.infcx.ty_to_str(expected) +
                ~"` found box");
          }
        }
      }
      ast::pat_uniq(inner) => {
        match structure_of(fcx, pat.span, expected) {
          ty::ty_uniq(e_inner) => {
            check_pat(pcx, inner, e_inner.ty);
            fcx.write_ty(pat.id, expected);
          }
          _ => {
            tcx.sess.span_fatal(
                pat.span,
                ~"mismatched types: expected `" +
                fcx.infcx.ty_to_str(expected) +
                ~"` found uniq");
          }
        }
      }
    }
}

<|endoftext|>


<commit_before>extern crate bindgen;
#[cfg(feature = "static")]
extern crate meson;
extern crate pkg_config;
extern crate wayland_scanner;

use std::path::{Path, PathBuf};
use std::process::Command;
use std::{env, fs, io};

fn main() {
    meson();
    let protocol_header_path =
        generate_protocol_headers().expect("Could not generate header files for wayland protocols");
    let target_dir = env::var("OUT_DIR").expect("$OUT_DIR not set!");
    let mut builder = bindgen::builder()
        .derive_debug(true)
        .derive_default(true)
        .generate_comments(true)
        .header("src/wlroots.h")
        .whitelisted_type(r"^wlr_.*$")
        .whitelisted_type(r"^xkb_.*$")
        .whitelisted_type(r"^XKB_.*$")
        .whitelisted_function(r"^_?pixman_.*$")
        .whitelisted_function(r"^_?wlr_.*$")
        .whitelisted_function(r"^xkb_.*$")
        .ctypes_prefix("libc")
        .clang_arg("-Iwlroots/include")
        .clang_arg("-Iwlroots/include/wlr")
        // NOTE Necessary because they use the out directory to put
        // pragma information on what features are available in a header file
        // titled "config.h"
        .clang_arg(format!("-I{}{}", target_dir, "/include/"))
        .clang_arg(format!("-I{}", protocol_header_path.to_str().unwrap()))
        .clang_arg("-Iwlroots/include/xcursor")
        .clang_arg("-I/usr/include/pixman-1")
        // Work around bug https://github.com/rust-lang-nursery/rust-bindgen/issues/687
        .hide_type("FP_NAN")
        .hide_type("FP_INFINITE")
        .hide_type("FP_ZERO")
        .hide_type("FP_SUBNORMAL")
        .hide_type("FP_NORMAL");
    if cfg!(feature = "unstable") {
        builder = builder.clang_arg("-DWLR_USE_UNSTABLE");
    }
    if !cfg!(feature = "static") {
        // config.h won't exist, so make a dummy file.
        // We don't need it because of the following -D defines.
        fs::create_dir_all(format!("{}{}", target_dir, "/include/wlr/"))
            .expect("Could not create <out>/include/wlr");
        fs::File::create(format!("{}{}", target_dir, "/include/wlr/config.h"))
            .expect("Could not create dummy config.h file");
        // meson automatically sets up variables, but if we are linking
        // dynamically bindgen will no longer have them.
        builder = builder.clang_args(
            [
                format!("-DWLR_HAS_LIBCAP={}", cfg!(feature = "libcap") as u8),
                format!("-DWLR_HAS_SYSTEMD={}", cfg!(feature = "systemd") as u8),
                format!("-DWLR_HAS_ELOGIND={}", cfg!(feature = "elogind") as u8),
                format!("-DWLR_HAS_X11_BACKEND={}", cfg!(feature = "x11_backend") as u8),
                format!("-DWLR_HAS_XWAYLAND={}", cfg!(feature = "xwayland") as u8),
                format!("-DWLR_HAS_XCB_ERRORS={}", cfg!(feature = "xcb_errors") as u8),
                format!("-DWLR_HAS_XCB_ICCCM={}", cfg!(feature = "xcb_icccm") as u8)
            ]
            .iter()
        )
    }
    let generated = builder.generate().unwrap();

    println!("cargo:rustc-link-lib=dylib=X11");
    println!("cargo:rustc-link-lib=dylib=X11-xcb");
    println!("cargo:rustc-link-lib=dylib=xkbcommon");
    println!("cargo:rustc-link-lib=dylib=xcb-composite");
    println!("cargo:rustc-link-lib=dylib=xcb-xfixes");
    println!("cargo:rustc-link-lib=dylib=xcb-image");
    println!("cargo:rustc-link-lib=dylib=xcb-render");
    println!("cargo:rustc-link-lib=dylib=xcb-shm");
    println!("cargo:rustc-link-lib=dylib=xcb-icccm");
    println!("cargo:rustc-link-lib=dylib=xcb-xkb");
    println!("cargo:rustc-link-lib=dylib=xcb-xinput");
    println!("cargo:rustc-link-lib=dylib=wayland-egl");
    println!("cargo:rustc-link-lib=dylib=wayland-client");
    println!("cargo:rustc-link-lib=dylib=wayland-server");
    println!("cargo:rustc-link-lib=dylib=EGL");
    println!("cargo:rustc-link-lib=dylib=GL");
    println!("cargo:rustc-link-lib=dylib=gbm");
    println!("cargo:rustc-link-lib=dylib=drm");
    println!("cargo:rustc-link-lib=dylib=input");
    println!("cargo:rustc-link-lib=dylib=udev");
    println!("cargo:rustc-link-lib=dylib=dbus-1");
    println!("cargo:rustc-link-lib=dylib=pixman-1");

    link_optional_libs();

    if !cfg!(feature = "static") {
        println!("cargo:rustc-link-lib=dylib=wlroots");
        println!("cargo:rustc-link-search=native=/usr/local/lib");
    }

    // generate the bindings
    println!("cargo:rerun-if-changed={}", "src/gen.rs");
    generated.write_to_file("src/gen.rs").unwrap();

    generate_protocols();
}

#[cfg(not(feature = "static"))]
fn meson() {}

#[cfg(feature = "static")]
fn meson() {
    let build_path = PathBuf::from(env::var("OUT_DIR").expect("Could not get OUT_DIR env variable"));
    build_path.join("build");
    let build_path_str = build_path
        .to_str()
        .expect("Could not turn build path into a string");
    println!("cargo:rustc-link-search=native=wlroots");
    println!("cargo:rustc-link-search=native={}/lib", build_path_str);
    println!("cargo:rustc-link-search=native={}/lib64", build_path_str);
    println!("cargo:rustc-link-search=native={}/build/", build_path_str);
    if cfg!(feature = "static") {
        println!("cargo:rustc-link-search=native={}/util/", build_path_str);
        println!("cargo:rustc-link-search=native={}/types/", build_path_str);
        println!("cargo:rustc-link-search=native={}/protocol/", build_path_str);
        println!("cargo:rustc-link-search=native={}/xcursor/", build_path_str);
        println!("cargo:rustc-link-search=native={}/xwayland/", build_path_str);
        println!("cargo:rustc-link-search=native={}/backend/", build_path_str);
        println!("cargo:rustc-link-search=native={}/backend/x11", build_path_str);
        println!("cargo:rustc-link-search=native={}/render/", build_path_str);

        println!("cargo:rustc-link-lib=static=wlr_util");
        println!("cargo:rustc-link-lib=static=wlr_types");
        println!("cargo:rustc-link-lib=static=wlr_xcursor");
        println!("cargo:rustc-link-lib=static=wlr_xwayland");
        println!("cargo:rustc-link-lib=static=wlr_backend");
        println!("cargo:rustc-link-lib=static=wlr_backend_x11");
        println!("cargo:rustc-link-lib=static=wlr_render");
        println!("cargo:rustc-link-lib=static=wl_protos");
    }

    if Path::new("wlroots").exists() {
        meson::build("wlroots", build_path_str);
    } else {
        panic!("The `wlroots` submodule does not exist");
    }
}

/// Gets the unstable and stable protocols in /usr/share-wayland-protocols and
/// generates server headers for them.
///
/// The path to the folder with the generated headers is returned. It will
/// have two directories, `stable`, and `unstable`.
fn generate_protocol_headers() -> io::Result<PathBuf> {
    let output_dir_str = env::var("OUT_DIR").unwrap();
    let out_path: PathBuf = format!("{}/wayland-protocols", output_dir_str).into();
    fs::create_dir(&out_path).ok();
    let protocols_prefix = pkg_config::get_variable("wayland-protocols", "prefix").unwrap();
    let protocols = fs::read_dir(format!("{}/share/wayland-protocols/stable", protocols_prefix))?.chain(
        fs::read_dir(format!("{}/share/wayland-protocols/unstable", protocols_prefix))?
    );
    for entry in protocols {
        let entry = entry?;
        for entry in fs::read_dir(entry.path())? {
            let entry = entry?;
            let path = entry.path();
            let mut filename = entry.file_name().into_string().unwrap();
            if filename.ends_with(".xml") {
                let new_length = filename.len() - 4;
                filename.truncate(new_length);
            }
            filename.push_str("-protocol");
            Command::new("wayland-scanner")
                .arg("server-header")
                .arg(path.clone())
                .arg(format!("{}/{}.h", out_path.to_str().unwrap(), filename))
                .status()
                .unwrap();
        }
    }
    Ok(out_path)
}

fn generate_protocols() {
    let output_dir_str = env::var("OUT_DIR").unwrap();

    let output_dir = Path::new(&output_dir_str);

    let protocols = &[
        ("./wlroots/protocol/server-decoration.xml", "server_decoration"),
        (
            "./wlroots/protocol/wlr-gamma-control-unstable-v1.xml",
            "gamma_control"
        ),
        ("./wlroots/protocol/wlr-screencopy-unstable-v1.xml", "screencopy"),
        ("./wlroots/protocol/screenshooter.xml", "screenshooter"),
        ("./wlroots/protocol/idle.xml", "idle")
    ];

    for protocol in protocols {
        wayland_scanner::generate_c_code(
            protocol.0,
            output_dir.join(format!("{}_server_api.rs", protocol.1)),
            wayland_scanner::Side::Server
        );
        wayland_scanner::generate_c_code(
            protocol.0,
            output_dir.join(format!("{}_client_api.rs", protocol.1)),
            wayland_scanner::Side::Client
        );
        wayland_scanner::generate_c_interfaces(
            protocol.0,
            output_dir.join(format!("{}_interfaces.rs", protocol.1))
        );
    }
}

fn link_optional_libs() {
    if cfg!(feature = "libcap") && pkg_config::probe_library("libcap").is_ok() {
        println!("cargo:rustc-link-lib=dylib=cap");
    }
    if cfg!(feature = "systemd") && pkg_config::probe_library("libsystemd").is_ok() {
        println!("cargo:rustc-link-lib=dylib=systemd");
    }
    if cfg!(feature = "elogind") && pkg_config::probe_library("elogind").is_ok() {
        println!("cargo:rustc-link-lib=dylib=elogind");
    }
    if pkg_config::probe_library("xcb-errors").is_ok() {
        println!("cargo:rustc-link-lib=dylib=xcb-errors");
    }
}
<commit_msg>Revert "Removed redundant linker flag"<commit_after>extern crate bindgen;
#[cfg(feature = "static")]
extern crate meson;
extern crate pkg_config;
extern crate wayland_scanner;

use std::path::{Path, PathBuf};
use std::process::Command;
use std::{env, fs, io};

fn main() {
    meson();
    let protocol_header_path =
        generate_protocol_headers().expect("Could not generate header files for wayland protocols");
    let target_dir = env::var("OUT_DIR").expect("$OUT_DIR not set!");
    let mut builder = bindgen::builder()
        .derive_debug(true)
        .derive_default(true)
        .generate_comments(true)
        .header("src/wlroots.h")
        .whitelisted_type(r"^wlr_.*$")
        .whitelisted_type(r"^xkb_.*$")
        .whitelisted_type(r"^XKB_.*$")
        .whitelisted_function(r"^_?pixman_.*$")
        .whitelisted_function(r"^_?wlr_.*$")
        .whitelisted_function(r"^xkb_.*$")
        .ctypes_prefix("libc")
        .clang_arg("-Iwlroots/include")
        .clang_arg("-Iwlroots/include/wlr")
        // NOTE Necessary because they use the out directory to put
        // pragma information on what features are available in a header file
        // titled "config.h"
        .clang_arg(format!("-I{}{}", target_dir, "/include/"))
        .clang_arg(format!("-I{}", protocol_header_path.to_str().unwrap()))
        .clang_arg("-Iwlroots/include/xcursor")
        .clang_arg("-I/usr/include/pixman-1")
        // Work around bug https://github.com/rust-lang-nursery/rust-bindgen/issues/687
        .hide_type("FP_NAN")
        .hide_type("FP_INFINITE")
        .hide_type("FP_ZERO")
        .hide_type("FP_SUBNORMAL")
        .hide_type("FP_NORMAL");
    if cfg!(feature = "unstable") {
        builder = builder.clang_arg("-DWLR_USE_UNSTABLE");
    }
    if !cfg!(feature = "static") {
        // config.h won't exist, so make a dummy file.
        // We don't need it because of the following -D defines.
        fs::create_dir_all(format!("{}{}", target_dir, "/include/wlr/"))
            .expect("Could not create <out>/include/wlr");
        fs::File::create(format!("{}{}", target_dir, "/include/wlr/config.h"))
            .expect("Could not create dummy config.h file");
        // meson automatically sets up variables, but if we are linking
        // dynamically bindgen will no longer have them.
        builder = builder.clang_args(
            [
                format!("-DWLR_HAS_LIBCAP={}", cfg!(feature = "libcap") as u8),
                format!("-DWLR_HAS_SYSTEMD={}", cfg!(feature = "systemd") as u8),
                format!("-DWLR_HAS_ELOGIND={}", cfg!(feature = "elogind") as u8),
                format!("-DWLR_HAS_X11_BACKEND={}", cfg!(feature = "x11_backend") as u8),
                format!("-DWLR_HAS_XWAYLAND={}", cfg!(feature = "xwayland") as u8),
                format!("-DWLR_HAS_XCB_ERRORS={}", cfg!(feature = "xcb_errors") as u8),
                format!("-DWLR_HAS_XCB_ICCCM={}", cfg!(feature = "xcb_icccm") as u8)
            ]
            .iter()
        )
    }
    let generated = builder.generate().unwrap();

    println!("cargo:rustc-link-lib=dylib=X11");
    println!("cargo:rustc-link-lib=dylib=X11-xcb");
    println!("cargo:rustc-link-lib=dylib=xkbcommon");
    println!("cargo:rustc-link-lib=dylib=xcb");
    println!("cargo:rustc-link-lib=dylib=xcb-composite");
    println!("cargo:rustc-link-lib=dylib=xcb-xfixes");
    println!("cargo:rustc-link-lib=dylib=xcb-image");
    println!("cargo:rustc-link-lib=dylib=xcb-render");
    println!("cargo:rustc-link-lib=dylib=xcb-shm");
    println!("cargo:rustc-link-lib=dylib=xcb-icccm");
    println!("cargo:rustc-link-lib=dylib=xcb-xkb");
    println!("cargo:rustc-link-lib=dylib=xcb-xinput");
    println!("cargo:rustc-link-lib=dylib=wayland-egl");
    println!("cargo:rustc-link-lib=dylib=wayland-client");
    println!("cargo:rustc-link-lib=dylib=wayland-server");
    println!("cargo:rustc-link-lib=dylib=EGL");
    println!("cargo:rustc-link-lib=dylib=GL");
    println!("cargo:rustc-link-lib=dylib=gbm");
    println!("cargo:rustc-link-lib=dylib=drm");
    println!("cargo:rustc-link-lib=dylib=input");
    println!("cargo:rustc-link-lib=dylib=udev");
    println!("cargo:rustc-link-lib=dylib=dbus-1");
    println!("cargo:rustc-link-lib=dylib=pixman-1");

    link_optional_libs();

    if !cfg!(feature = "static") {
        println!("cargo:rustc-link-lib=dylib=wlroots");
        println!("cargo:rustc-link-search=native=/usr/local/lib");
    }

    // generate the bindings
    println!("cargo:rerun-if-changed={}", "src/gen.rs");
    generated.write_to_file("src/gen.rs").unwrap();

    generate_protocols();
}

#[cfg(not(feature = "static"))]
fn meson() {}

#[cfg(feature = "static")]
fn meson() {
    let build_path = PathBuf::from(env::var("OUT_DIR").expect("Could not get OUT_DIR env variable"));
    build_path.join("build");
    let build_path_str = build_path
        .to_str()
        .expect("Could not turn build path into a string");
    println!("cargo:rustc-link-search=native=wlroots");
    println!("cargo:rustc-link-search=native={}/lib", build_path_str);
    println!("cargo:rustc-link-search=native={}/lib64", build_path_str);
    println!("cargo:rustc-link-search=native={}/build/", build_path_str);
    if cfg!(feature = "static") {
        println!("cargo:rustc-link-search=native={}/util/", build_path_str);
        println!("cargo:rustc-link-search=native={}/types/", build_path_str);
        println!("cargo:rustc-link-search=native={}/protocol/", build_path_str);
        println!("cargo:rustc-link-search=native={}/xcursor/", build_path_str);
        println!("cargo:rustc-link-search=native={}/xwayland/", build_path_str);
        println!("cargo:rustc-link-search=native={}/backend/", build_path_str);
        println!("cargo:rustc-link-search=native={}/backend/x11", build_path_str);
        println!("cargo:rustc-link-search=native={}/render/", build_path_str);

        println!("cargo:rustc-link-lib=static=wlr_util");
        println!("cargo:rustc-link-lib=static=wlr_types");
        println!("cargo:rustc-link-lib=static=wlr_xcursor");
        println!("cargo:rustc-link-lib=static=wlr_xwayland");
        println!("cargo:rustc-link-lib=static=wlr_backend");
        println!("cargo:rustc-link-lib=static=wlr_backend_x11");
        println!("cargo:rustc-link-lib=static=wlr_render");
        println!("cargo:rustc-link-lib=static=wl_protos");
    }

    if Path::new("wlroots").exists() {
        meson::build("wlroots", build_path_str);
    } else {
        panic!("The `wlroots` submodule does not exist");
    }
}

/// Gets the unstable and stable protocols in /usr/share-wayland-protocols and
/// generates server headers for them.
///
/// The path to the folder with the generated headers is returned. It will
/// have two directories, `stable`, and `unstable`.
fn generate_protocol_headers() -> io::Result<PathBuf> {
    let output_dir_str = env::var("OUT_DIR").unwrap();
    let out_path: PathBuf = format!("{}/wayland-protocols", output_dir_str).into();
    fs::create_dir(&out_path).ok();
    let protocols_prefix = pkg_config::get_variable("wayland-protocols", "prefix").unwrap();
    let protocols = fs::read_dir(format!("{}/share/wayland-protocols/stable", protocols_prefix))?.chain(
        fs::read_dir(format!("{}/share/wayland-protocols/unstable", protocols_prefix))?
    );
    for entry in protocols {
        let entry = entry?;
        for entry in fs::read_dir(entry.path())? {
            let entry = entry?;
            let path = entry.path();
            let mut filename = entry.file_name().into_string().unwrap();
            if filename.ends_with(".xml") {
                let new_length = filename.len() - 4;
                filename.truncate(new_length);
            }
            filename.push_str("-protocol");
            Command::new("wayland-scanner")
                .arg("server-header")
                .arg(path.clone())
                .arg(format!("{}/{}.h", out_path.to_str().unwrap(), filename))
                .status()
                .unwrap();
        }
    }
    Ok(out_path)
}

fn generate_protocols() {
    let output_dir_str = env::var("OUT_DIR").unwrap();

    let output_dir = Path::new(&output_dir_str);

    let protocols = &[
        ("./wlroots/protocol/server-decoration.xml", "server_decoration"),
        (
            "./wlroots/protocol/wlr-gamma-control-unstable-v1.xml",
            "gamma_control"
        ),
        ("./wlroots/protocol/wlr-screencopy-unstable-v1.xml", "screencopy"),
        ("./wlroots/protocol/screenshooter.xml", "screenshooter"),
        ("./wlroots/protocol/idle.xml", "idle")
    ];

    for protocol in protocols {
        wayland_scanner::generate_c_code(
            protocol.0,
            output_dir.join(format!("{}_server_api.rs", protocol.1)),
            wayland_scanner::Side::Server
        );
        wayland_scanner::generate_c_code(
            protocol.0,
            output_dir.join(format!("{}_client_api.rs", protocol.1)),
            wayland_scanner::Side::Client
        );
        wayland_scanner::generate_c_interfaces(
            protocol.0,
            output_dir.join(format!("{}_interfaces.rs", protocol.1))
        );
    }
}

fn link_optional_libs() {
    if cfg!(feature = "libcap") && pkg_config::probe_library("libcap").is_ok() {
        println!("cargo:rustc-link-lib=dylib=cap");
    }
    if cfg!(feature = "systemd") && pkg_config::probe_library("libsystemd").is_ok() {
        println!("cargo:rustc-link-lib=dylib=systemd");
    }
    if cfg!(feature = "elogind") && pkg_config::probe_library("elogind").is_ok() {
        println!("cargo:rustc-link-lib=dylib=elogind");
    }
    if pkg_config::probe_library("xcb-errors").is_ok() {
        println!("cargo:rustc-link-lib=dylib=xcb-errors");
    }
}
<|endoftext|>