<commit_before>// Copyright:: Copyright (c) 2015-2016 The Habitat Maintainers
//
// The terms of the Evaluation Agreement (Habitat) between Chef Software Inc.
// and the party accessing this file ("Licensee") apply to Licensee's use of
// the Software until such time that the Software is made available under an
// open source license such as the Apache 2.0 License.

//! The service topologies.
//!
//! A service topology is a [state machine](../state_machine) that wraps the lifecycle events of a service around the
//! process supervisor and package manager. It is responsible for:
//!
//! 1. Processing the main event loop
//! 1. Registering callbacks with the [discovery](../discovery) system
//!
//! Typically, topologies are created from the [start](../command/start) command.

pub mod standalone;
pub mod leader;
pub mod initializer;

use std::mem;
use std::ops::DerefMut;
use std::sync::{Arc, RwLock};
use std::sync::mpsc::TryRecvError;
use std::thread;
use std::time::Duration;

use wonder;

use state_machine::StateMachine;
use census::{self, CensusList};
use common::config_file::ConfigFileList;
use package::{self, Package, PackageUpdaterActor};
use util::signals::SignalNotifier;
use error::{Result, SupError};
use config::Config;
use service_config::ServiceConfig;
use sidecar;
use supervisor::Supervisor;
use user_config;
use gossip;
use gossip::rumor::{Rumor, RumorList};
use gossip::member::MemberList;
use election::ElectionList;
use time::SteadyTime;
use util::signals;

static LOGKEY: &'static str = "TP";
static MINIMUM_LOOP_TIME_MS: i64 = 200;

#[derive(PartialEq, Eq, Debug, RustcEncodable)]
pub enum Topology {
    Standalone,
    Leader,
    Initializer,
}

impl Default for Topology {
    fn default() -> Topology {
        Topology::Standalone
    }
}

/// Viable states for the topologies. Not every topology will implement every state.
#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)]
pub enum State {
    Init,
    MinimumQuorum,
    WaitingForQuorum,
    RestoreDataset,
    DetermineViability,
    BecomeLeader,
    BecomeFollower,
    CheckForElection,
    Election,
    StartElection,
    InElection,
    Leader,
    Follower,
    Configure,
    Initializing,
    Starting,
    Running,
}

/// The topology `Worker` is where everything our state machine needs between states lives.
pub struct Worker<'a> {
    /// The package we are supervising
    pub package: Arc<RwLock<Package>>,
    /// Name of the package being supervised
    pub package_name: String,
    /// A pointer to our current Config
    pub config: &'a Config,
    /// The topology we are running
    pub topology: String,
    /// Our Service Configuration; manages changes to our configuration,
    pub service_config: Arc<RwLock<ServiceConfig>>,
    /// The Gossip Server; listens for inbound gossip traffic
    pub gossip_server: gossip::server::Server,
    pub census_list: Arc<RwLock<CensusList>>,
    pub rumor_list: Arc<RwLock<RumorList>>,
    pub election_list: Arc<RwLock<ElectionList>>,
    pub member_list: Arc<RwLock<MemberList>>,
    pub config_file_list: Arc<RwLock<ConfigFileList>>,
    /// Our Sidecar Actor; exposes a restful HTTP interface to the outside world
    pub sidecar_actor: sidecar::SidecarActor,
    /// Our User Configuration; reads the config periodically
    pub user_actor: wonder::actor::Actor<user_config::Message>,
    /// Watches a package Depot for updates and signals the main thread when an update is available. Optionally
    /// started if a value is passed for the url option on startup.
    pub pkg_updater: Option<PackageUpdaterActor>,
    /// The service supervisor
    pub supervisor: Arc<RwLock<Supervisor>>,
    pub return_state: Option<State>,
}

impl<'a> Worker<'a> {
    /// Create a new worker
    ///
    /// Automatically sets the backend to Etcd.
    pub fn new(package: Package, topology: String, config: &'a Config) -> Result<Worker<'a>> {
        let mut pkg_updater = None;

        let package_name = package.name.clone();
        let package_exposes = package.exposes().clone();
        let package_port = package_exposes.first().map(|e| e.clone());
        let package_ident = package.ident().clone();

        // Setup the User Data Configuration
        let user_actor_state = user_config::UserActorState::new(format!("{}/{}/config",
                                                                        package_name,
                                                                        config.group()));

        let pkg_lock = Arc::new(RwLock::new(package));
        let pkg_lock_1 = pkg_lock.clone();

        if let Some(ref url) = *config.url() {
            let pkg_lock_2 = pkg_lock.clone();
            pkg_updater = Some(package::PackageUpdater::start(url, pkg_lock_2));
        }

        let gossip_server = gossip::server::Server::new(String::from(config.gossip_listen()),
                                                        config.gossip_permanent(),
                                                        package_name.clone(),
                                                        config.group().to_string(),
                                                        Some(package_exposes),
                                                        package_port);

        try!(gossip_server.start_inbound());
        try!(gossip_server.initial_peers(config.gossip_peer()));
        gossip_server.start_outbound();
        gossip_server.start_failure_detector();
        census::start_health_adjuster(gossip_server.census_list.clone(),
                                      gossip_server.member_list.clone());

        // Setup the Service Configuration
        let service_config = {
            let cl = gossip_server.census_list.read().unwrap();
            let pkg = pkg_lock.read().unwrap();
            let sc = try!(ServiceConfig::new(&pkg, &cl));
            sc
        };
        let service_config_lock = Arc::new(RwLock::new(service_config));
        let service_config_lock_1 = service_config_lock.clone();

        let supervisor = Arc::new(RwLock::new(Supervisor::new(package_ident)));

        let sidecar_ml = gossip_server.member_list.clone();
        let sidecar_rl = gossip_server.rumor_list.clone();
        let sidecar_cl = gossip_server.census_list.clone();
        let sidecar_detector = gossip_server.detector.clone();
        let sidecar_el = gossip_server.election_list.clone();
        let sidecar_sup = supervisor.clone();

        Ok(Worker {
            package: pkg_lock,
            package_name: package_name,
            topology: topology,
            config: config,
            census_list: gossip_server.census_list.clone(),
            rumor_list: gossip_server.rumor_list.clone(),
            election_list: gossip_server.election_list.clone(),
            config_file_list: gossip_server.config_file_list.clone(),
            member_list: gossip_server.member_list.clone(),
            gossip_server: gossip_server,
            service_config: service_config_lock,
            sidecar_actor: sidecar::Sidecar::start(pkg_lock_1,
                                                   service_config_lock_1,
                                                   sidecar_ml,
                                                   sidecar_rl,
                                                   sidecar_cl,
                                                   sidecar_detector,
                                                   sidecar_el,
                                                   sidecar_sup),
            supervisor: supervisor,
            user_actor: wonder::actor::Builder::new(user_config::UserActor)
                            .name("user-config".to_string())
                            .start(user_actor_state)
                            .unwrap(),
            pkg_updater: pkg_updater,
            return_state: None,
        })
    }

    /// update a package, but does NOT restart the service
    pub fn update_package(&self, updated: Package) -> Result<()> {
        let service_config = self.service_config.read().unwrap();
        {
            let mut package = self.package.write().unwrap();
            mem::replace(package.deref_mut(), updated);
        }
        let package = self.package.read().unwrap();
        try!(package.copy_run(&service_config));
        Ok(())
    }
}

/// The main loop of a topology.
///
/// 1. Loops forever
/// 1. Checks if we have caught a signal; if so, acts on the signal. (May exit entirely)
/// 1. Checks the current `state` of our [StateMachine](../state_machine)
/// 1. If it is running, we run a non-blocking `waitpid`, and inspect why the child died;
///    depending on the circumstances, we may exit with an error here
/// 1. Process any discovery events
/// 1. Trigger the next iteration of the state machine
///
/// # Failures
///
/// * We fail to send a signal to the supervisor
/// * We fail to join the supervisor thread
/// * The supervisor dies unexpectedly
/// * The discovery subsystem returns an error
/// * The topology state machine returns an error
fn run_internal<'a>(sm: &mut StateMachine<State, Worker<'a>, SupError>,
                    worker: &mut Worker<'a>)
                    -> Result<()> {
    {
        let package = worker.package.read().unwrap();
        let service_config = worker.service_config.read().unwrap();
        try!(package.create_svc_path());
        try!(package.copy_run(&service_config));
    }
    let handler = wonder::actor::Builder::new(SignalNotifier)
                      .name("signal-handler".to_string())
                      .start(())
                      .unwrap();
    loop {
        let start_time = SteadyTime::now();
        match handler.receiver.try_recv() {
            Ok(wonder::actor::Message::Cast(signals::Message::Signal(sig))) => {
                debug!("SIG = {:?}", sig);
                match sig {
                    signals::Signal::SIGINT |
                    signals::Signal::SIGTERM => {
                        let mut supervisor = worker.supervisor.write().unwrap();
                        try!(supervisor.down());
                        break;
                    }
                    _ => {
                        outputln!("Forwarding {:?} on to the supervised process", sig);
                        let supervisor = worker.supervisor.write().unwrap();
                        try!(supervisor.send_unix_signal(sig.clone()));
                    }
                };
            }
            Ok(_) => {}
            Err(TryRecvError::Empty) => {}
            Err(TryRecvError::Disconnected) => {
                panic!("signal handler crashed!");
            }
        }

        {
            let mut supervisor = worker.supervisor.write().unwrap();
            try!(supervisor.check_process());
        }

        let mut restart_process = false;

        // This section, and the following really need to be refactored:
        //
        // 1. We check to see if we are in an event a bunch of times
        // 2. We potentially restart 3 different times - twice for reconfigure, and once for
        //    file_udpated. That's pretty yucky.
        //
        // Love, Adam
        {
            // Manage the census
            let (write_census, in_event, write_rumor, me_clone) = {
                let cl = worker.census_list.read().unwrap();
                let census = cl.local_census();
                (cl.needs_write(), census.in_event, census.me().needs_write(), census.me().clone())
            };

            if write_census {
                if !in_event {
                    let mut service_config = worker.service_config.write().unwrap();
                    let cl = worker.census_list.read().unwrap();
                    service_config.svc(&cl);
                }
                if write_rumor {
                    outputln!("Writing our census rumor: {:#?}", me_clone);
                    let mut rl = worker.rumor_list.write().unwrap();
                    rl.add_rumor(Rumor::census_entry(me_clone));
                }
                let mut cl = worker.census_list.write().unwrap();
                cl.written();
            }

            // Don't bother trying to reconfigure if we are in an event - just wait till
            // everything settles down.
            {
                let census_list = worker.census_list.read().unwrap();
                let census = census_list.local_census();
                if !census.in_event {
                    let mut service_config = worker.service_config.write().unwrap();
                    if service_config.needs_write {
                        let package = worker.package.read().unwrap();
                        // Write the configuration, and restart if needed
                        if try!(service_config.write(&package)) {
                            try!(package.copy_run(&service_config));
                            try!(package.reconfigure(&service_config));
                            println!("Restarting because the service config was updated via the census");
                            restart_process = true;
                        }
                    }
                }
            }
        }

        {
            let in_event = {
                let census_list = worker.census_list.read().unwrap();
                let census = census_list.local_census();
                census.in_event
            };
            let (needs_file_updated, needs_reconfigure) = if in_event {
                (false, false)
            } else {
                let mut config_file_list = worker.config_file_list.write().unwrap();
                let needs_write = {
                    config_file_list.needs_write()
                };
                if needs_write {
                    try!(config_file_list.write())
                } else {
                    (false, false)
                }
            };
            if needs_file_updated {
                let service_config = worker.service_config.read().unwrap();
                let package = worker.package.read().unwrap();
                let existed = try!(package.file_updated(&service_config));
                if !existed {
                    restart_process = true;
                }
            }
            if needs_reconfigure {
                let mut service_config = worker.service_config.write().unwrap();
                let package = worker.package.read().unwrap();
                service_config.cfg(&package);
                if try!(service_config.write(&package)) {
                    try!(package.copy_run(&service_config));
                    let existed = try!(package.reconfigure(&service_config));
                    if !existed {
                        restart_process = true;
                    }
                }
            }
        }

        if let Some(ref updater) = worker.pkg_updater {
            match updater.receiver.try_recv() {
                Ok(wonder::actor::Message::Cast(package::UpdaterMessage::Update(package))) => {
                    debug!("Main loop received package update notification: {:?}",
                           &package);
                    try!(worker.update_package(package));
                    try!(package::PackageUpdater::run(&updater));
                    // force the package to restart
                    println!("Restarting because the package was updated");
                    restart_process = true;
                }
                Ok(_) => {}
                Err(TryRecvError::Empty) => {}
                Err(TryRecvError::Disconnected) => {
                    panic!("package updater crashed!");
                }
            }
        }

        {
            let mut supervisor = worker.supervisor.write().unwrap();
            // If our target is that the process is up
            if supervisor.is_up() {
                // And no process is running
                if supervisor.pid.is_none() {
                    // Start a new one
                    try!(supervisor.start());
                } else {
                    // If we were supposed to restart
                    if restart_process {
                        // And we have ever started before...
                        if supervisor.has_started {
                            // Restart
                            try!(supervisor.restart());
                        }
                    }
                }
            }
        }

        // Next state!
        try!(sm.next(worker));

        // Slow down our loop
        let elapsed_time = SteadyTime::now() - start_time;
        let elapsed_millis = elapsed_time.num_milliseconds();

        if elapsed_millis < MINIMUM_LOOP_TIME_MS {
            thread::sleep(Duration::from_millis((MINIMUM_LOOP_TIME_MS - elapsed_millis) as u64));
        }
    }
    Ok(())
}
<commit_msg>Fix "restarting" output so it has the supervisor prefix<commit_after>// Copyright:: Copyright (c) 2015-2016 The Habitat Maintainers
//
// The terms of the Evaluation Agreement (Habitat) between Chef Software Inc.
// and the party accessing this file ("Licensee") apply to Licensee's use of
// the Software until such time that the Software is made available under an
// open source license such as the Apache 2.0 License.

//! The service topologies.
//!
//! A service topology is a [state machine](../state_machine) that wraps the lifecycle events of a service around the
//! process supervisor and package manager. It is responsible for:
//!
//! 1. Processing the main event loop
//! 1. Registering callbacks with the [discovery](../discovery) system
//!
//! Typically, topologies are created from the [start](../command/start) command.

pub mod standalone;
pub mod leader;
pub mod initializer;

use std::mem;
use std::ops::DerefMut;
use std::sync::{Arc, RwLock};
use std::sync::mpsc::TryRecvError;
use std::thread;
use std::time::Duration;

use wonder;

use state_machine::StateMachine;
use census::{self, CensusList};
use common::config_file::ConfigFileList;
use package::{self, Package, PackageUpdaterActor};
use util::signals::SignalNotifier;
use error::{Result, SupError};
use config::Config;
use service_config::ServiceConfig;
use sidecar;
use supervisor::Supervisor;
use user_config;
use gossip;
use gossip::rumor::{Rumor, RumorList};
use gossip::member::MemberList;
use election::ElectionList;
use time::SteadyTime;
use util::signals;

static LOGKEY: &'static str = "TP";
static MINIMUM_LOOP_TIME_MS: i64 = 200;

#[derive(PartialEq, Eq, Debug, RustcEncodable)]
pub enum Topology {
    Standalone,
    Leader,
    Initializer,
}

impl Default for Topology {
    fn default() -> Topology {
        Topology::Standalone
    }
}

/// Viable states for the topologies. Not every topology will implement every state.
#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)]
pub enum State {
    Init,
    MinimumQuorum,
    WaitingForQuorum,
    RestoreDataset,
    DetermineViability,
    BecomeLeader,
    BecomeFollower,
    CheckForElection,
    Election,
    StartElection,
    InElection,
    Leader,
    Follower,
    Configure,
    Initializing,
    Starting,
    Running,
}

/// The topology `Worker` is where everything our state machine needs between states lives.
pub struct Worker<'a> {
    /// The package we are supervising
    pub package: Arc<RwLock<Package>>,
    /// Name of the package being supervised
    pub package_name: String,
    /// A pointer to our current Config
    pub config: &'a Config,
    /// The topology we are running
    pub topology: String,
    /// Our Service Configuration; manages changes to our configuration,
    pub service_config: Arc<RwLock<ServiceConfig>>,
    /// The Gossip Server; listens for inbound gossip traffic
    pub gossip_server: gossip::server::Server,
    pub census_list: Arc<RwLock<CensusList>>,
    pub rumor_list: Arc<RwLock<RumorList>>,
    pub election_list: Arc<RwLock<ElectionList>>,
    pub member_list: Arc<RwLock<MemberList>>,
    pub config_file_list: Arc<RwLock<ConfigFileList>>,
    /// Our Sidecar Actor; exposes a restful HTTP interface to the outside world
    pub sidecar_actor: sidecar::SidecarActor,
    /// Our User Configuration; reads the config periodically
    pub user_actor: wonder::actor::Actor<user_config::Message>,
    /// Watches a package Depot for updates and signals the main thread when an update is available. Optionally
    /// started if a value is passed for the url option on startup.
    pub pkg_updater: Option<PackageUpdaterActor>,
    /// The service supervisor
    pub supervisor: Arc<RwLock<Supervisor>>,
    pub return_state: Option<State>,
}

impl<'a> Worker<'a> {
    /// Create a new worker
    ///
    /// Automatically sets the backend to Etcd.
    pub fn new(package: Package, topology: String, config: &'a Config) -> Result<Worker<'a>> {
        let mut pkg_updater = None;

        let package_name = package.name.clone();
        let package_exposes = package.exposes().clone();
        let package_port = package_exposes.first().map(|e| e.clone());
        let package_ident = package.ident().clone();

        // Setup the User Data Configuration
        let user_actor_state = user_config::UserActorState::new(format!("{}/{}/config",
                                                                        package_name,
                                                                        config.group()));

        let pkg_lock = Arc::new(RwLock::new(package));
        let pkg_lock_1 = pkg_lock.clone();

        if let Some(ref url) = *config.url() {
            let pkg_lock_2 = pkg_lock.clone();
            pkg_updater = Some(package::PackageUpdater::start(url, pkg_lock_2));
        }

        let gossip_server = gossip::server::Server::new(String::from(config.gossip_listen()),
                                                        config.gossip_permanent(),
                                                        package_name.clone(),
                                                        config.group().to_string(),
                                                        Some(package_exposes),
                                                        package_port);

        try!(gossip_server.start_inbound());
        try!(gossip_server.initial_peers(config.gossip_peer()));
        gossip_server.start_outbound();
        gossip_server.start_failure_detector();
        census::start_health_adjuster(gossip_server.census_list.clone(),
                                      gossip_server.member_list.clone());

        // Setup the Service Configuration
        let service_config = {
            let cl = gossip_server.census_list.read().unwrap();
            let pkg = pkg_lock.read().unwrap();
            let sc = try!(ServiceConfig::new(&pkg, &cl));
            sc
        };
        let service_config_lock = Arc::new(RwLock::new(service_config));
        let service_config_lock_1 = service_config_lock.clone();

        let supervisor = Arc::new(RwLock::new(Supervisor::new(package_ident)));

        let sidecar_ml = gossip_server.member_list.clone();
        let sidecar_rl = gossip_server.rumor_list.clone();
        let sidecar_cl = gossip_server.census_list.clone();
        let sidecar_detector = gossip_server.detector.clone();
        let sidecar_el = gossip_server.election_list.clone();
        let sidecar_sup = supervisor.clone();

        Ok(Worker {
            package: pkg_lock,
            package_name: package_name,
            topology: topology,
            config: config,
            census_list: gossip_server.census_list.clone(),
            rumor_list: gossip_server.rumor_list.clone(),
            election_list: gossip_server.election_list.clone(),
            config_file_list: gossip_server.config_file_list.clone(),
            member_list: gossip_server.member_list.clone(),
            gossip_server: gossip_server,
            service_config: service_config_lock,
            sidecar_actor: sidecar::Sidecar::start(pkg_lock_1,
                                                   service_config_lock_1,
                                                   sidecar_ml,
                                                   sidecar_rl,
                                                   sidecar_cl,
                                                   sidecar_detector,
                                                   sidecar_el,
                                                   sidecar_sup),
            supervisor: supervisor,
            user_actor: wonder::actor::Builder::new(user_config::UserActor)
                            .name("user-config".to_string())
                            .start(user_actor_state)
                            .unwrap(),
            pkg_updater: pkg_updater,
            return_state: None,
        })
    }

    /// update a package, but does NOT restart the service
    pub fn update_package(&self, updated: Package) -> Result<()> {
        let service_config = self.service_config.read().unwrap();
        {
            let mut package = self.package.write().unwrap();
            mem::replace(package.deref_mut(), updated);
        }
        let package = self.package.read().unwrap();
        try!(package.copy_run(&service_config));
        Ok(())
    }
}

/// The main loop of a topology.
///
/// 1. Loops forever
/// 1. Checks if we have caught a signal; if so, acts on the signal. (May exit entirely)
/// 1. Checks the current `state` of our [StateMachine](../state_machine)
/// 1. If it is running, we run a non-blocking `waitpid`, and inspect why the child died;
///    depending on the circumstances, we may exit with an error here
/// 1. Process any discovery events
/// 1. Trigger the next iteration of the state machine
///
/// # Failures
///
/// * We fail to send a signal to the supervisor
/// * We fail to join the supervisor thread
/// * The supervisor dies unexpectedly
/// * The discovery subsystem returns an error
/// * The topology state machine returns an error
fn run_internal<'a>(sm: &mut StateMachine<State, Worker<'a>, SupError>,
                    worker: &mut Worker<'a>)
                    -> Result<()> {
    {
        let package = worker.package.read().unwrap();
        let service_config = worker.service_config.read().unwrap();
        try!(package.create_svc_path());
        try!(package.copy_run(&service_config));
    }
    let handler = wonder::actor::Builder::new(SignalNotifier)
                      .name("signal-handler".to_string())
                      .start(())
                      .unwrap();
    loop {
        let start_time = SteadyTime::now();
        match handler.receiver.try_recv() {
            Ok(wonder::actor::Message::Cast(signals::Message::Signal(sig))) => {
                debug!("SIG = {:?}", sig);
                match sig {
                    signals::Signal::SIGINT |
                    signals::Signal::SIGTERM => {
                        let mut supervisor = worker.supervisor.write().unwrap();
                        try!(supervisor.down());
                        break;
                    }
                    _ => {
                        outputln!("Forwarding {:?} on to the supervised process", sig);
                        let supervisor = worker.supervisor.write().unwrap();
                        try!(supervisor.send_unix_signal(sig.clone()));
                    }
                };
            }
            Ok(_) => {}
            Err(TryRecvError::Empty) => {}
            Err(TryRecvError::Disconnected) => {
                panic!("signal handler crashed!");
            }
        }

        {
            let mut supervisor = worker.supervisor.write().unwrap();
            try!(supervisor.check_process());
        }

        let mut restart_process = false;

        // This section, and the following really need to be refactored:
        //
        // 1. We check to see if we are in an event a bunch of times
        // 2. We potentially restart 3 different times - twice for reconfigure, and once for
        //    file_udpated. That's pretty yucky.
        //
        // Love, Adam
        {
            // Manage the census
            let (write_census, in_event, write_rumor, me_clone) = {
                let cl = worker.census_list.read().unwrap();
                let census = cl.local_census();
                (cl.needs_write(), census.in_event, census.me().needs_write(), census.me().clone())
            };

            if write_census {
                if !in_event {
                    let mut service_config = worker.service_config.write().unwrap();
                    let cl = worker.census_list.read().unwrap();
                    service_config.svc(&cl);
                }
                if write_rumor {
                    outputln!("Writing our census rumor: {:#?}", me_clone);
                    let mut rl = worker.rumor_list.write().unwrap();
                    rl.add_rumor(Rumor::census_entry(me_clone));
                }
                let mut cl = worker.census_list.write().unwrap();
                cl.written();
            }

            // Don't bother trying to reconfigure if we are in an event - just wait till
            // everything settles down.
            {
                let census_list = worker.census_list.read().unwrap();
                let census = census_list.local_census();
                if !census.in_event {
                    let mut service_config = worker.service_config.write().unwrap();
                    if service_config.needs_write {
                        let package = worker.package.read().unwrap();
                        // Write the configuration, and restart if needed
                        if try!(service_config.write(&package)) {
                            try!(package.copy_run(&service_config));
                            try!(package.reconfigure(&service_config));
                            outputln!("Restarting because the service config was updated via the census");
                            restart_process = true;
                        }
                    }
                }
            }
        }

        {
            let in_event = {
                let census_list = worker.census_list.read().unwrap();
                let census = census_list.local_census();
                census.in_event
            };
            let (needs_file_updated, needs_reconfigure) = if in_event {
                (false, false)
            } else {
                let mut config_file_list = worker.config_file_list.write().unwrap();
                let needs_write = {
                    config_file_list.needs_write()
                };
                if needs_write {
                    try!(config_file_list.write())
                } else {
                    (false, false)
                }
            };
            if needs_file_updated {
                let service_config = worker.service_config.read().unwrap();
                let package = worker.package.read().unwrap();
                let existed = try!(package.file_updated(&service_config));
                if !existed {
                    restart_process = true;
                }
            }
            if needs_reconfigure {
                let mut service_config = worker.service_config.write().unwrap();
                let package = worker.package.read().unwrap();
                service_config.cfg(&package);
                if try!(service_config.write(&package)) {
                    try!(package.copy_run(&service_config));
                    let existed = try!(package.reconfigure(&service_config));
                    if !existed {
                        restart_process = true;
                    }
                }
            }
        }

        if let Some(ref updater) = worker.pkg_updater {
            match updater.receiver.try_recv() {
                Ok(wonder::actor::Message::Cast(package::UpdaterMessage::Update(package))) => {
                    debug!("Main loop received package update notification: {:?}",
                           &package);
                    try!(worker.update_package(package));
                    try!(package::PackageUpdater::run(&updater));
                    // force the package to restart
                    outputln!("Restarting because the package was updated");
                    restart_process = true;
                }
                Ok(_) => {}
                Err(TryRecvError::Empty) => {}
                Err(TryRecvError::Disconnected) => {
                    panic!("package updater crashed!");
                }
            }
        }

        {
            let mut supervisor = worker.supervisor.write().unwrap();
            // If our target is that the process is up
            if supervisor.is_up() {
                // And no process is running
                if supervisor.pid.is_none() {
                    // Start a new one
                    try!(supervisor.start());
                } else {
                    // If we were supposed to restart
                    if restart_process {
                        // And we have ever started before...
                        if supervisor.has_started {
                            // Restart
                            try!(supervisor.restart());
                        }
                    }
                }
            }
        }

        // Next state!
        try!(sm.next(worker));

        // Slow down our loop
        let elapsed_time = SteadyTime::now() - start_time;
        let elapsed_millis = elapsed_time.num_milliseconds();

        if elapsed_millis < MINIMUM_LOOP_TIME_MS {
            thread::sleep(Duration::from_millis((MINIMUM_LOOP_TIME_MS - elapsed_millis) as u64));
        }
    }
    Ok(())
}
<|endoftext|>


<commit_before>use libsyntax2::{
    File, TextUnit, AstNode,
    ast::self,
    algo::{
        ancestors,
    },
};

use {
    AtomEdit, find_node_at_offset,
    scope::{FnScopes, ModuleScope},
};

#[derive(Debug)]
pub struct
       CompletionItem {
    pub name: String,
    pub snippet: Option<String>
}

pub fn scope_completion(file: &File, offset: TextUnit) -> Option<Vec<CompletionItem>> {
    // Insert a fake ident to get a valid parse tree
    let file = {
        let edit = AtomEdit::insert(offset, "intellijRulezz".to_string());
        // Don't bother with completion if incremental reparse fails
        file.incremental_reparse(&edit)?
    };
    let name_ref = find_node_at_offset::<ast::NameRef>(file.syntax(), offset)?;
    if !is_ident_expr(name_ref) {
        return None;
    }

    let mut res = Vec::new();
    if let Some(fn_def) = ancestors(name_ref.syntax()).filter_map(ast::FnDef::cast).next() {
        complete_keywords(&file, Some(fn_def), name_ref, &mut res);
        let scopes = FnScopes::new(fn_def);
        complete_fn(name_ref, &scopes, &mut res);
    } else {
        complete_keywords(&file, None, name_ref, &mut res);
    }
    if let Some(root) = ancestors(name_ref.syntax()).filter_map(ast::Root::cast).next() {
        let scope = ModuleScope::new(root);
        res.extend(
            scope.entries().iter()
                .map(|entry| CompletionItem {
                    name: entry.name().to_string(),
                    snippet: None,
                })
        )
    }
    Some(res)
}

fn is_ident_expr(name_ref: ast::NameRef) -> bool {
    match ancestors(name_ref.syntax()).filter_map(ast::Expr::cast).next() {
        None => false,
        Some(expr) => {
            expr.syntax().range() == name_ref.syntax().range()
        }
    }
}

fn complete_keywords(file: &File, fn_def: Option<ast::FnDef>, name_ref: ast::NameRef, acc: &mut Vec<CompletionItem>) {
    acc.push(keyword("if", "if $0 { }"));
    acc.push(keyword("match", "match $0 { }"));
    acc.push(keyword("while", "while $0 { }"));
    acc.push(keyword("loop", "loop {$0}"));

    if let Some(off) = name_ref.syntax().range().start().checked_sub(2.into()) {
        if let Some(if_expr) = find_node_at_offset::<ast::IfExpr>(file.syntax(), off) {
            if if_expr.syntax().range().end() < name_ref.syntax().range().start() {
                acc.push(keyword("else", "else {$0}"));
                acc.push(keyword("else if", "else if $0 { }"));
            }
        }
    }

    // if let Some(fn_def) = fn_def {
    //     acc.push(keyword("return", ""))
    // }

    fn keyword(kw: &str, snip: &str) -> CompletionItem {
        CompletionItem {
            name: kw.to_string(),
            snippet: Some(snip.to_string()),
        }
    }
}

fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec<CompletionItem>) {
    acc.extend(
        scopes.scope_chain(name_ref.syntax())
            .flat_map(|scope| scopes.entries(scope).iter())
            .map(|entry| CompletionItem {
                name: entry.name().to_string(),
                snippet: None,
            })
    )
}

#[cfg(test)]
mod tests {
    use super::*;
    use test_utils::{assert_eq_dbg, extract_offset};

    fn check_scope_completion(code: &str, expected_completions: &str) {
        let (off, code) = extract_offset(&code);
        let file = File::parse(&code);
        let completions = scope_completion(&file, off)
            .unwrap()
            .into_iter()
            .filter(|c| c.snippet.is_none())
            .collect::<Vec<_>>();
        assert_eq_dbg(expected_completions, &completions);
    }

    fn check_snippet_completion(code: &str, expected_completions: &str) {
        let (off, code) = extract_offset(&code);
        let file = File::parse(&code);
        let completions = scope_completion(&file, off)
            .unwrap()
            .into_iter()
            .filter(|c| c.snippet.is_some())
            .collect::<Vec<_>>();
        assert_eq_dbg(expected_completions, &completions);
    }

    #[test]
    fn test_completion_let_scope() {
        check_scope_completion(r"
            fn quux(x: i32) {
                let y = 92;
                1 + <|>;
                let z = ();
            }
            ", r#"[CompletionItem { name: "y", snippet: None },
                   CompletionItem { name: "x", snippet: None },
                   CompletionItem { name: "quux", snippet: None }]"#);
    }

    #[test]
    fn test_completion_if_let_scope() {
        check_scope_completion(r"
            fn quux() {
                if let Some(x) = foo() {
                    let y = 92;
                };
                if let Some(a) = bar() {
                    let b = 62;
                    1 + <|>
                }
            }
            ", r#"[CompletionItem { name: "b", snippet: None },
                   CompletionItem { name: "a", snippet: None },
                   CompletionItem { name: "quux", snippet: None }]"#);
    }

    #[test]
    fn test_completion_for_scope() {
        check_scope_completion(r"
            fn quux() {
                for x in &[1, 2, 3] {
                    <|>
                }
            }
            ", r#"[CompletionItem { name: "x", snippet: None },
                   CompletionItem { name: "quux", snippet: None }]"#);
    }

    #[test]
    fn test_completion_mod_scope() {
        check_scope_completion(r"
            struct Foo;
            enum Baz {}
            fn quux() {
                <|>
            }
            ", r#"[CompletionItem { name: "Foo", snippet: None },
                   CompletionItem { name: "Baz", snippet: None },
                   CompletionItem { name: "quux", snippet: None }]"#);
    }

    #[test]
    fn test_completion_kewords() {
        check_snippet_completion(r"
            fn quux() {
                <|>
            }
            ", r#"[CompletionItem { name: "if", snippet: Some("if $0 { }") },
                   CompletionItem { name: "match", snippet: Some("match $0 { }") },
                   CompletionItem { name: "while", snippet: Some("while $0 { }") },
                   CompletionItem { name: "loop", snippet: Some("loop {$0}") }]"#);
    }

    #[test]
    fn test_completion_else() {
        check_snippet_completion(r"
            fn quux() {
                if true {
                    ()
                } <|>
            }
            ", r#"[CompletionItem { name: "if", snippet: Some("if $0 { }") },
                   CompletionItem { name: "match", snippet: Some("match $0 { }") },
                   CompletionItem { name: "while", snippet: Some("while $0 { }") },
                   CompletionItem { name: "loop", snippet: Some("loop {$0}") },
                   CompletionItem { name: "else", snippet: Some("else {$0}") },
                   CompletionItem { name: "else if", snippet: Some("else if $0 { }") }]"#);
    }
}
<commit_msg>Smart return completion<commit_after>use libsyntax2::{
    File, TextUnit, AstNode,
    ast::self,
    algo::{
        ancestors,
    },
};

use {
    AtomEdit, find_node_at_offset,
    scope::{FnScopes, ModuleScope},
};

#[derive(Debug)]
pub struct
       CompletionItem {
    pub name: String,
    pub snippet: Option<String>
}

pub fn scope_completion(file: &File, offset: TextUnit) -> Option<Vec<CompletionItem>> {
    // Insert a fake ident to get a valid parse tree
    let file = {
        let edit = AtomEdit::insert(offset, "intellijRulezz".to_string());
        // Don't bother with completion if incremental reparse fails
        file.incremental_reparse(&edit)?
    };
    let name_ref = find_node_at_offset::<ast::NameRef>(file.syntax(), offset)?;
    if !is_ident_expr(name_ref) {
        return None;
    }

    let mut res = Vec::new();
    if let Some(fn_def) = ancestors(name_ref.syntax()).filter_map(ast::FnDef::cast).next() {
        complete_keywords(&file, Some(fn_def), name_ref, &mut res);
        let scopes = FnScopes::new(fn_def);
        complete_fn(name_ref, &scopes, &mut res);
    } else {
        complete_keywords(&file, None, name_ref, &mut res);
    }
    if let Some(root) = ancestors(name_ref.syntax()).filter_map(ast::Root::cast).next() {
        let scope = ModuleScope::new(root);
        res.extend(
            scope.entries().iter()
                .map(|entry| CompletionItem {
                    name: entry.name().to_string(),
                    snippet: None,
                })
        )
    }
    Some(res)
}

fn is_ident_expr(name_ref: ast::NameRef) -> bool {
    match ancestors(name_ref.syntax()).filter_map(ast::Expr::cast).next() {
        None => false,
        Some(expr) => {
            expr.syntax().range() == name_ref.syntax().range()
        }
    }
}

fn complete_keywords(file: &File, fn_def: Option<ast::FnDef>, name_ref: ast::NameRef, acc: &mut Vec<CompletionItem>) {
    acc.push(keyword("if", "if $0 { }"));
    acc.push(keyword("match", "match $0 { }"));
    acc.push(keyword("while", "while $0 { }"));
    acc.push(keyword("loop", "loop {$0}"));

    if let Some(off) = name_ref.syntax().range().start().checked_sub(2.into()) {
        if let Some(if_expr) = find_node_at_offset::<ast::IfExpr>(file.syntax(), off) {
            if if_expr.syntax().range().end() < name_ref.syntax().range().start() {
                acc.push(keyword("else", "else {$0}"));
                acc.push(keyword("else if", "else if $0 { }"));
            }
        }
    }

    if let Some(fn_def) = fn_def {
        if fn_def.ret_type().is_some() {
            acc.push(keyword("return", "return $0;"))
        } else {
            acc.push(keyword("return", "return;"))
        }
    }

    fn keyword(kw: &str, snip: &str) -> CompletionItem {
        CompletionItem {
            name: kw.to_string(),
            snippet: Some(snip.to_string()),
        }
    }
}

fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec<CompletionItem>) {
    acc.extend(
        scopes.scope_chain(name_ref.syntax())
            .flat_map(|scope| scopes.entries(scope).iter())
            .map(|entry| CompletionItem {
                name: entry.name().to_string(),
                snippet: None,
            })
    )
}

#[cfg(test)]
mod tests {
    use super::*;
    use test_utils::{assert_eq_dbg, extract_offset};

    fn check_scope_completion(code: &str, expected_completions: &str) {
        let (off, code) = extract_offset(&code);
        let file = File::parse(&code);
        let completions = scope_completion(&file, off)
            .unwrap()
            .into_iter()
            .filter(|c| c.snippet.is_none())
            .collect::<Vec<_>>();
        assert_eq_dbg(expected_completions, &completions);
    }

    fn check_snippet_completion(code: &str, expected_completions: &str) {
        let (off, code) = extract_offset(&code);
        let file = File::parse(&code);
        let completions = scope_completion(&file, off)
            .unwrap()
            .into_iter()
            .filter(|c| c.snippet.is_some())
            .collect::<Vec<_>>();
        assert_eq_dbg(expected_completions, &completions);
    }

    #[test]
    fn test_completion_let_scope() {
        check_scope_completion(r"
            fn quux(x: i32) {
                let y = 92;
                1 + <|>;
                let z = ();
            }
            ", r#"[CompletionItem { name: "y", snippet: None },
                   CompletionItem { name: "x", snippet: None },
                   CompletionItem { name: "quux", snippet: None }]"#);
    }

    #[test]
    fn test_completion_if_let_scope() {
        check_scope_completion(r"
            fn quux() {
                if let Some(x) = foo() {
                    let y = 92;
                };
                if let Some(a) = bar() {
                    let b = 62;
                    1 + <|>
                }
            }
            ", r#"[CompletionItem { name: "b", snippet: None },
                   CompletionItem { name: "a", snippet: None },
                   CompletionItem { name: "quux", snippet: None }]"#);
    }

    #[test]
    fn test_completion_for_scope() {
        check_scope_completion(r"
            fn quux() {
                for x in &[1, 2, 3] {
                    <|>
                }
            }
            ", r#"[CompletionItem { name: "x", snippet: None },
                   CompletionItem { name: "quux", snippet: None }]"#);
    }

    #[test]
    fn test_completion_mod_scope() {
        check_scope_completion(r"
            struct Foo;
            enum Baz {}
            fn quux() {
                <|>
            }
            ", r#"[CompletionItem { name: "Foo", snippet: None },
                   CompletionItem { name: "Baz", snippet: None },
                   CompletionItem { name: "quux", snippet: None }]"#);
    }

    #[test]
    fn test_completion_kewords() {
        check_snippet_completion(r"
            fn quux() {
                <|>
            }
            ", r#"[CompletionItem { name: "if", snippet: Some("if $0 { }") },
                   CompletionItem { name: "match", snippet: Some("match $0 { }") },
                   CompletionItem { name: "while", snippet: Some("while $0 { }") },
                   CompletionItem { name: "loop", snippet: Some("loop {$0}") },
                   CompletionItem { name: "return", snippet: Some("return;") }]"#);
    }

    #[test]
    fn test_completion_else() {
        check_snippet_completion(r"
            fn quux() {
                if true {
                    ()
                } <|>
            }
            ", r#"[CompletionItem { name: "if", snippet: Some("if $0 { }") },
                   CompletionItem { name: "match", snippet: Some("match $0 { }") },
                   CompletionItem { name: "while", snippet: Some("while $0 { }") },
                   CompletionItem { name: "loop", snippet: Some("loop {$0}") },
                   CompletionItem { name: "else", snippet: Some("else {$0}") },
                   CompletionItem { name: "else if", snippet: Some("else if $0 { }") },
                   CompletionItem { name: "return", snippet: Some("return;") }]"#);
    }

    #[test]
    fn test_completion_return_value() {
        check_snippet_completion(r"
            fn quux() -> i32{
                <|>
            }
            ", r#"[CompletionItem { name: "if", snippet: Some("if $0 { }") },
                   CompletionItem { name: "match", snippet: Some("match $0 { }") },
                   CompletionItem { name: "while", snippet: Some("while $0 { }") },
                   CompletionItem { name: "loop", snippet: Some("loop {$0}") },
                   CompletionItem { name: "return", snippet: Some("return $0;") }]"#);
    }
}
<|endoftext|>


<commit_before>#![no_main]
#[macro_use] extern crate libfuzzer_sys;
extern crate quick_xml;

use quick_xml::reader::Reader;
use quick_xml::events::Event;
use std::io::Cursor;

fuzz_target!(|data: &[u8]| {
    // fuzzed code goes here
    let cursor = Cursor::new(data);
    let mut reader = Reader::from_reader(cursor);
    let mut buf = vec![];
    loop {
        match reader.read_event(&mut buf) {
            Ok(Event::Start(ref e)) | Ok(Event::Empty(ref e))=> {
                if e.unescaped(&reader).is_err() {
                    break;
                }
                for a in e.attributes() {
                    if a.and_then(|a| a.unescaped_value()).is_err() {
                        break;
                    }
                }
            }
            Ok(Event::Text(ref e)) => {
                if e.unescaped(&reader).is_err() {
                    break;
                }
            }
            Ok(Event::Eof) | Err(..) => break,
            _ => buf.clear(),
        }
    }
});
<commit_msg>update fuzz test<commit_after>#![no_main]
#[macro_use] extern crate libfuzzer_sys;
extern crate quick_xml;

use quick_xml::reader::Reader;
use quick_xml::events::Event;
use std::io::Cursor;

fuzz_target!(|data: &[u8]| {
    // fuzzed code goes here
    let cursor = Cursor::new(data);
    let mut reader = Reader::from_reader(cursor);
    let mut buf = vec![];
    loop {
        match reader.read_event(&mut buf) {
            Ok(Event::Start(ref e)) | Ok(Event::Empty(ref e))=> {
                if e.unescaped().is_err() {
                    break;
                }
                for a in e.attributes() {
                    if a.ok().map_or(false, |a| a.unescaped_value().is_err()) {
                        break;
                    }
                }
            }
            Ok(Event::Text(ref e)) | Ok(Event::Comment(ref e))
            | Ok(Event::CData(ref e)) | Ok(Event::PI(ref e))
            | Ok(Event::DocType(ref e)) => {
                if e.unescaped().is_err() {
                    break;
                }
            }
            Ok(Event::Decl(ref e)) => {
                let _ = e.version();
                let _ = e.encoding();
                let _ = e.encoder();
                let _ = e.standalone();
            }
            Ok(Event::End(_)) => (),
            Ok(Event::Eof) | Err(..) => break,
        }
        buf.clear();
    }
});
<|endoftext|>


<commit_before>// Copyright 2016 Alexander Reece
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::collections::{HashMap, HashSet};
use std::io;

use WriteRust;
use common::{Class, ClassMethod};

impl<'a> WriteRust for MethodStructWriter<'a> {
    fn write_rust_to<W>(&self, writer: &mut W) -> io::Result<()>
        where W: io::Write
    {
        try!(self.write_struct(writer));
        try!(self.write_inherent_impl(writer));
        try!(self.write_encodable_impl(writer));
        try!(self.write_amqp0_payload_impl(writer));

        Ok(())
    }
}

pub struct MethodStructWriter<'a> {
    class: &'a Class,
    method: &'a ClassMethod,

    /// For non-copy parameters, allow conversion using Into<>.
    /// Using Into requires defining generic parameters.
    /// We store the names of the generic parameters here
    generic_types: HashMap<&'a str, String>,
    has_fields: bool,
}

impl<'a> MethodStructWriter<'a> {
    pub fn new(class: &'a Class, method: &'a ClassMethod) -> Self {
        let has_fields = method.fields().iter().any(|f| !f.is_reserved());
        let generic_types = {
            let mut labels = HashSet::new();
            method.fields().iter()
                .filter(|f| !f.is_reserved() && !f.ty().is_copy())
                .map(|field| {
                    let name = field.var_name();
                    let first_char = field.var_name().chars().next().unwrap();
                    let prefix = first_char.to_uppercase().collect::<String>();

                    let mut label: String = prefix.clone();
                    let mut suffix = 0;

                    while labels.contains(label.as_str()) {
                        label = format!("{}{}", prefix, suffix);
                        suffix += 1;
                    }

                    labels.insert(label.clone());
                    (name, label)
                })
                .collect()
        };

        MethodStructWriter {
            class: class,
            method: method,
            generic_types: generic_types,
            has_fields: has_fields,
        }
    }

    pub fn write_struct<W>(&self, writer: &mut W) -> io::Result<()>
        where W: io::Write
    {
        try!(writeln!(writer, "\n// generated by primalgen::codegen::spec-module::class_mod::method_struct"));
        try!(writeln!(writer, "#[derive(Debug)]"));
        if !self.has_fields {
            try!(writeln!(writer, "pub struct {};", self.method.pascal_case()));
            return Ok(());
        }

        let lifetimes = if self.method.has_lifetimes() { "<'a>" } else { "" };

        try!(writeln!(writer, "pub struct {}{} {{", self.method.pascal_case(), lifetimes));
        for field in self.method.fields() {
            if field.is_reserved() {
                continue;
            }
            try!(write!(writer, "{}: ", field.var_name()));
            if field.ty().is_copy() || field.ty().is_owned() {
                try!(writeln!(writer, "{},", field.ty().owned_type()));
            }
            else {
                try!(writeln!(writer, "{},", field.ty().cow_definition("a")));
            }
        }
        try!(writeln!(writer, "}} // struct {}{}", self.method.pascal_case(), lifetimes));
        Ok(())
    }

    pub fn write_inherent_impl<W>(&self, writer: &mut W) -> io::Result<()>
        where W: io::Write
    {
        let lifetimes = if self.method.has_lifetimes() { "<'a>" } else { "" };

        try!(writeln!(writer, "\nimpl{1} {0}{1} {{", self.method.pascal_case(), lifetimes));
        try!(self.write_constructor(writer));
        try!(self.write_getters(writer));
        try!(writeln!(writer, "}} // impl{1} {0}{1}", self.method.pascal_case(), lifetimes));

        Ok(())
    }

    pub fn write_constructor<W>(&self, writer: &mut W) -> io::Result<()>
        where W: io::Write
    {
        if !self.has_fields {
            try!(writeln!(writer, "pub fn new() -> Self {{"));
            try!(writeln!(writer, "{}", self.method.pascal_case()));
            try!(writeln!(writer, "}} // fn new()"));
            return Ok(());
        }

        try!(write!(writer, "pub fn new"));

        println!("{:#?}", self.generic_types);

        // generic arguments: <A, B, C>
        if !self.generic_types.is_empty() {
            let generics = self.method.fields().iter()
                .filter_map(|f| {
                    let mapping = self.generic_types.get(f.var_name());
                    println!("Looking for {:?}, found {:?}", f.var_name(), mapping);
                    mapping
                })
                .map(|s| s.as_str())
                .collect::<Vec<_>>()
                .join(", ");
            try!(write!(writer, "<{}>", generics));
        }

        let arguments = self.method.fields().iter()
            .filter(|f| !f.is_reserved())
            .map(|field| {
                let ty = if let Some(generic) = self.generic_types.get(field.var_name()) {
                    generic
                } else {
                    field.ty().owned_type()
                };

                format!("{}: {}", field.var_name(), ty)
            }).collect::<Vec<_>>();

        // function arguments: (name1: ty1, name2: ty2)
        try!(write!(writer, "(\n{}\n) -> Self", arguments.join(",\n")));

        // generic conditions: where A: ..., B: ...
        if !self.generic_types.is_empty() {
            try!(write!(writer, "\n where "));
            for field in self.method.fields() {
                if let Some(label) = self.generic_types.get(field.var_name()) {
                    let ty = field.ty().cow_definition("a");
                    try!(writeln!(writer, "{}: Into<{}>,", label, ty));
                }
            }
        }

        try!(writeln!(writer, " {{"));

        // construction body
        try!(writeln!(writer, "{} {{", self.method.pascal_case()));
        for field in self.method.fields() {
            if field.is_reserved() {
                continue
            }

            let name = field.var_name();
            if self.generic_types.contains_key(field.var_name()) {
                try!(writeln!(writer, "{}: {}.into(),", name, name));
            }
            else {
                try!(writeln!(writer, "{}: {},", name, name));
            }
        }
        try!(writeln!(writer, "}} // {}", self.method.pascal_case())); // struct creation
        try!(writeln!(writer, "}} // fn new()")); // constructor

        Ok(())
    }

    pub fn write_getters<W>(&self, writer: &mut W) -> io::Result<()>
        where W: io::Write
    {
        if !self.has_fields {
            return Ok(());
        }

        try!(writeln!(writer, "impl_properties! {{"));
        for field in self.method.fields() {
            if field.is_reserved() {
                continue;
            }
            let name = field.var_name();
            let ty = field.ty().borrowed_type();
            try!(match (field.ty().is_copy(), field.ty().is_owned()) {
                (true, _) => writeln!(writer, "({0}, set_{0}) -> {1},", name, ty),
                (_, true) => writeln!(writer, "({0}, {0}_mut, set_{0}) -> &{1},", name, ty),
                _ => writeln!(writer, "({0}, {0}_mut, set_{0}) -> Cow<{1}>,", name, ty)
            });
        }
        try!(writeln!(writer, "}} // impl_properties"));

        Ok(())
    }

    pub fn write_encodable_impl<W>(&self, writer: &mut W) -> io::Result<()>
        where W: io::Write
    {
        let lifetimes = if self.method.has_lifetimes() { ("<'a>") } else { ("") };
        let static_size_bits = self.method.fields().iter()
            .map(|field| field.ty().num_bits_fixed())
            .fold(0, |sum, num_bits| sum + num_bits);

        let static_size = static_size_bits / 8 + if static_size_bits % 8 > 0 { 1 } else { 0 };
        let has_dynamic_field = self.method.fields().iter()
            .any(|field| field.ty().dynamic_bit_method().is_some());

        try!(writeln!(writer, "\nimpl{1} ::Encodable for {0}{1} {{", self.method.pascal_case(), lifetimes));
        try!(writeln!(writer, "fn encoded_size(&self) -> usize {{"));
        if has_dynamic_field {
            try!(writeln!(writer, "["));
            try!(writeln!(writer, "{},", static_size));
            for field in self.method.fields() {
                if field.is_reserved() {
                    continue;
                }

                if let Some(_) = field.ty().dynamic_bit_method() {
                    try!(writeln!(writer, "::Encodable::encoded_size(&self.{}),", field.var_name()));
                }
            }
            try!(writeln!(writer, "].iter().sum()"));
        } else {
            try!(writeln!(writer, "{}", static_size));
        }
        try!(writeln!(writer, "}} // fn encoded_size()"));
        try!(writeln!(writer, "}} // impl Encodable"));

        Ok(())
    }

    pub fn write_amqp0_payload_impl<W>(&self, writer: &mut W) -> io::Result<()>
        where W: io::Write
    {
        let lifetimes = if self.method.has_lifetimes() { ("<'a>") } else { ("") };
        try!(writeln!(writer, "\nimpl{1} ::ProtocolMethodPayload for {0}{1} {{", self.method.pascal_case(), lifetimes));

        try!(write!(writer, "fn class_id(&self) -> u16 {{"));
        try!(writeln!(writer, "{}", self.class.index()));
        try!(writeln!(writer, "}} // fn class_id()"));

        try!(writeln!(writer, "fn method_id(&self) -> u16 {{"));
        try!(writeln!(writer, "{}", self.method.index()));
        try!(writeln!(writer, "}} // fn method_id()"));

        try!(writeln!(writer, "}} // impl ::Payload for {}", self.method.pascal_case()));

        Ok(())
    }
}
<commit_msg>[codegen] Remove debugging lines from primalgen::MethodStructWriter<commit_after>// Copyright 2016 Alexander Reece
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::collections::{HashMap, HashSet};
use std::io;

use WriteRust;
use common::{Class, ClassMethod};

impl<'a> WriteRust for MethodStructWriter<'a> {
    fn write_rust_to<W>(&self, writer: &mut W) -> io::Result<()>
        where W: io::Write
    {
        try!(self.write_struct(writer));
        try!(self.write_inherent_impl(writer));
        try!(self.write_encodable_impl(writer));
        try!(self.write_amqp0_payload_impl(writer));

        Ok(())
    }
}

pub struct MethodStructWriter<'a> {
    class: &'a Class,
    method: &'a ClassMethod,

    /// For non-copy parameters, allow conversion using Into<>.
    /// Using Into requires defining generic parameters.
    /// We store the names of the generic parameters here
    generic_types: HashMap<&'a str, String>,
    has_fields: bool,
}

impl<'a> MethodStructWriter<'a> {
    pub fn new(class: &'a Class, method: &'a ClassMethod) -> Self {
        let has_fields = method.fields().iter().any(|f| !f.is_reserved());
        let generic_types = {
            let mut labels = HashSet::new();
            method.fields().iter()
                .filter(|f| !f.is_reserved() && !f.ty().is_copy())
                .map(|field| {
                    let name = field.var_name();
                    let first_char = field.var_name().chars().next().unwrap();
                    let prefix = first_char.to_uppercase().collect::<String>();

                    let mut label: String = prefix.clone();
                    let mut suffix = 0;

                    while labels.contains(label.as_str()) {
                        label = format!("{}{}", prefix, suffix);
                        suffix += 1;
                    }

                    labels.insert(label.clone());
                    (name, label)
                })
                .collect()
        };

        MethodStructWriter {
            class: class,
            method: method,
            generic_types: generic_types,
            has_fields: has_fields,
        }
    }

    pub fn write_struct<W>(&self, writer: &mut W) -> io::Result<()>
        where W: io::Write
    {
        try!(writeln!(writer, "\n// generated by primalgen::codegen::spec-module::class_mod::method_struct"));
        try!(writeln!(writer, "#[derive(Debug)]"));
        if !self.has_fields {
            try!(writeln!(writer, "pub struct {};", self.method.pascal_case()));
            return Ok(());
        }

        let lifetimes = if self.method.has_lifetimes() { "<'a>" } else { "" };

        try!(writeln!(writer, "pub struct {}{} {{", self.method.pascal_case(), lifetimes));
        for field in self.method.fields() {
            if field.is_reserved() {
                continue;
            }
            try!(write!(writer, "{}: ", field.var_name()));
            if field.ty().is_copy() || field.ty().is_owned() {
                try!(writeln!(writer, "{},", field.ty().owned_type()));
            }
            else {
                try!(writeln!(writer, "{},", field.ty().cow_definition("a")));
            }
        }
        try!(writeln!(writer, "}} // struct {}{}", self.method.pascal_case(), lifetimes));
        Ok(())
    }

    pub fn write_inherent_impl<W>(&self, writer: &mut W) -> io::Result<()>
        where W: io::Write
    {
        let lifetimes = if self.method.has_lifetimes() { "<'a>" } else { "" };

        try!(writeln!(writer, "\nimpl{1} {0}{1} {{", self.method.pascal_case(), lifetimes));
        try!(self.write_constructor(writer));
        try!(self.write_getters(writer));
        try!(writeln!(writer, "}} // impl{1} {0}{1}", self.method.pascal_case(), lifetimes));

        Ok(())
    }

    pub fn write_constructor<W>(&self, writer: &mut W) -> io::Result<()>
        where W: io::Write
    {
        if !self.has_fields {
            try!(writeln!(writer, "pub fn new() -> Self {{"));
            try!(writeln!(writer, "{}", self.method.pascal_case()));
            try!(writeln!(writer, "}} // fn new()"));
            return Ok(());
        }

        try!(write!(writer, "pub fn new"));

        // generic arguments: <A, B, C>
        if !self.generic_types.is_empty() {
            let generics = self.method.fields().iter()
                .filter_map(|f| self.generic_types.get(f.var_name()))
                .map(|s| s.as_str())
                .collect::<Vec<_>>()
                .join(", ");
            try!(write!(writer, "<{}>", generics));
        }

        let arguments = self.method.fields().iter()
            .filter(|f| !f.is_reserved())
            .map(|field| {
                let ty = if let Some(generic) = self.generic_types.get(field.var_name()) {
                    generic
                } else {
                    field.ty().owned_type()
                };

                format!("{}: {}", field.var_name(), ty)
            }).collect::<Vec<_>>();

        // function arguments: (name1: ty1, name2: ty2)
        try!(write!(writer, "(\n{}\n) -> Self", arguments.join(",\n")));

        // generic conditions: where A: ..., B: ...
        if !self.generic_types.is_empty() {
            try!(write!(writer, "\n where "));
            for field in self.method.fields() {
                if let Some(label) = self.generic_types.get(field.var_name()) {
                    let ty = field.ty().cow_definition("a");
                    try!(writeln!(writer, "{}: Into<{}>,", label, ty));
                }
            }
        }

        try!(writeln!(writer, " {{"));

        // construction body
        try!(writeln!(writer, "{} {{", self.method.pascal_case()));
        for field in self.method.fields() {
            if field.is_reserved() {
                continue
            }

            let name = field.var_name();
            if self.generic_types.contains_key(field.var_name()) {
                try!(writeln!(writer, "{}: {}.into(),", name, name));
            }
            else {
                try!(writeln!(writer, "{}: {},", name, name));
            }
        }
        try!(writeln!(writer, "}} // {}", self.method.pascal_case())); // struct creation
        try!(writeln!(writer, "}} // fn new()")); // constructor

        Ok(())
    }

    pub fn write_getters<W>(&self, writer: &mut W) -> io::Result<()>
        where W: io::Write
    {
        if !self.has_fields {
            return Ok(());
        }

        try!(writeln!(writer, "impl_properties! {{"));
        for field in self.method.fields() {
            if field.is_reserved() {
                continue;
            }
            let name = field.var_name();
            let ty = field.ty().borrowed_type();
            try!(match (field.ty().is_copy(), field.ty().is_owned()) {
                (true, _) => writeln!(writer, "({0}, set_{0}) -> {1},", name, ty),
                (_, true) => writeln!(writer, "({0}, {0}_mut, set_{0}) -> &{1},", name, ty),
                _ => writeln!(writer, "({0}, {0}_mut, set_{0}) -> Cow<{1}>,", name, ty)
            });
        }
        try!(writeln!(writer, "}} // impl_properties"));

        Ok(())
    }

    pub fn write_encodable_impl<W>(&self, writer: &mut W) -> io::Result<()>
        where W: io::Write
    {
        let lifetimes = if self.method.has_lifetimes() { ("<'a>") } else { ("") };
        let static_size_bits = self.method.fields().iter()
            .map(|field| field.ty().num_bits_fixed())
            .fold(0, |sum, num_bits| sum + num_bits);

        let static_size = static_size_bits / 8 + if static_size_bits % 8 > 0 { 1 } else { 0 };
        let has_dynamic_field = self.method.fields().iter()
            .any(|field| field.ty().dynamic_bit_method().is_some());

        try!(writeln!(writer, "\nimpl{1} ::Encodable for {0}{1} {{", self.method.pascal_case(), lifetimes));
        try!(writeln!(writer, "fn encoded_size(&self) -> usize {{"));
        if has_dynamic_field {
            try!(writeln!(writer, "["));
            try!(writeln!(writer, "{},", static_size));
            for field in self.method.fields() {
                if field.is_reserved() {
                    continue;
                }

                if let Some(_) = field.ty().dynamic_bit_method() {
                    try!(writeln!(writer, "::Encodable::encoded_size(&self.{}),", field.var_name()));
                }
            }
            try!(writeln!(writer, "].iter().sum()"));
        } else {
            try!(writeln!(writer, "{}", static_size));
        }
        try!(writeln!(writer, "}} // fn encoded_size()"));
        try!(writeln!(writer, "}} // impl Encodable"));

        Ok(())
    }

    pub fn write_amqp0_payload_impl<W>(&self, writer: &mut W) -> io::Result<()>
        where W: io::Write
    {
        let lifetimes = if self.method.has_lifetimes() { ("<'a>") } else { ("") };
        try!(writeln!(writer, "\nimpl{1} ::ProtocolMethodPayload for {0}{1} {{", self.method.pascal_case(), lifetimes));

        try!(write!(writer, "fn class_id(&self) -> u16 {{"));
        try!(writeln!(writer, "{}", self.class.index()));
        try!(writeln!(writer, "}} // fn class_id()"));

        try!(writeln!(writer, "fn method_id(&self) -> u16 {{"));
        try!(writeln!(writer, "{}", self.method.index()));
        try!(writeln!(writer, "}} // fn method_id()"));

        try!(writeln!(writer, "}} // impl ::Payload for {}", self.method.pascal_case()));

        Ok(())
    }
}
<|endoftext|>


<commit_before>extern crate pkg_config;

fn main () {
    pkg_config::probe_library("fuse").unwrap();
}
<commit_msg>Use recommended pkg-config method to discover libfuse<commit_after>extern crate pkg_config;

#[cfg(not(target_os = "macos"))]
static LIBFUSE_NAME: &str = "fuse";

#[cfg(target_os = "macos")]
static LIBFUSE_NAME: &str = "osxfuse";

fn main () {
    pkg_config::Config::new().atleast_version("2.6.0").probe(LIBFUSE_NAME).unwrap();
}
<|endoftext|>


<commit_before>extern crate gcc;

fn main() {
    println!("cargo:rustc-link-lib=dylib=gdi32");
    println!("cargo:rustc-link-lib=dylib=comdlg32");
    println!("cargo:rustc-link-lib=dylib=user32");

    gcc::Config::new()
        .file("src/PDCurses/pdcurses/addch.c") //Common PDCurses files
        .file("src/PDCurses/pdcurses/addchstr.c")
        .file("src/PDCurses/pdcurses/addstr.c")
        .file("src/PDCurses/pdcurses/attr.c")
        .file("src/PDCurses/pdcurses/beep.c")
        .file("src/PDCurses/pdcurses/bkgd.c")
        .file("src/PDCurses/pdcurses/border.c")
        .file("src/PDCurses/pdcurses/clear.c")
        .file("src/PDCurses/pdcurses/color.c")
        .file("src/PDCurses/pdcurses/debug.c")
        .file("src/PDCurses/pdcurses/delch.c")
        .file("src/PDCurses/pdcurses/deleteln.c")
        .file("src/PDCurses/pdcurses/deprec.c")
        .file("src/PDCurses/pdcurses/getch.c")
        .file("src/PDCurses/pdcurses/getstr.c")
        .file("src/PDCurses/pdcurses/getyx.c")
        .file("src/PDCurses/pdcurses/inch.c")
        .file("src/PDCurses/pdcurses/inchstr.c")
        .file("src/PDCurses/pdcurses/initscr.c")
        .file("src/PDCurses/pdcurses/inopts.c")
        .file("src/PDCurses/pdcurses/insch.c")
        .file("src/PDCurses/pdcurses/insstr.c")
        .file("src/PDCurses/pdcurses/instr.c")
        .file("src/PDCurses/pdcurses/kernel.c")
        .file("src/PDCurses/pdcurses/keyname.c")
        .file("src/PDCurses/pdcurses/mouse.c")
        .file("src/PDCurses/pdcurses/move.c")
        .file("src/PDCurses/pdcurses/outopts.c")
        .file("src/PDCurses/pdcurses/overlay.c")
        .file("src/PDCurses/pdcurses/pad.c")
        .file("src/PDCurses/pdcurses/panel.c")
        .file("src/PDCurses/pdcurses/printw.c")
        .file("src/PDCurses/pdcurses/refresh.c")
        .file("src/PDCurses/pdcurses/scanw.c")
        .file("src/PDCurses/pdcurses/scr_dump.c")
        .file("src/PDCurses/pdcurses/scroll.c")
        .file("src/PDCurses/pdcurses/slk.c")
        .file("src/PDCurses/pdcurses/termattr.c")
        .file("src/PDCurses/pdcurses/terminfo.c")
        .file("src/PDCurses/pdcurses/touch.c")
        .file("src/PDCurses/pdcurses/util.c")
        .file("src/PDCurses/pdcurses/window.c")
        .file("src/PDCurses/win32a/pdcclip.c") //win32a implementation files
        .file("src/PDCurses/win32a/pdcdisp.c")
        .file("src/PDCurses/win32a/pdcgetsc.c")
        .file("src/PDCurses/win32a/pdckbd.c")
        .file("src/PDCurses/win32a/pdcscrn.c")
        .file("src/PDCurses/win32a/pdcsetsc.c")
        .file("src/PDCurses/win32a/pdcutil.c")
        .include("src/PDCurses")
        .define("WIDE", Some("Y")) //Build with wide-character (Unicode) support
        .define("UTF8", Some("Y")) //Makes PDCurses ignore the system locale, and treat all narrow-character strings as UTF-8
        .compile("libpdcurses.a");
}
<commit_msg>Set correct flags for wide character support and forcing UTF8<commit_after>extern crate gcc;

fn main() {
    println!("cargo:rustc-link-lib=dylib=gdi32");
    println!("cargo:rustc-link-lib=dylib=comdlg32");
    println!("cargo:rustc-link-lib=dylib=user32");

    gcc::Config::new()
        .file("src/PDCurses/pdcurses/addch.c") //Common PDCurses files
        .file("src/PDCurses/pdcurses/addchstr.c")
        .file("src/PDCurses/pdcurses/addstr.c")
        .file("src/PDCurses/pdcurses/attr.c")
        .file("src/PDCurses/pdcurses/beep.c")
        .file("src/PDCurses/pdcurses/bkgd.c")
        .file("src/PDCurses/pdcurses/border.c")
        .file("src/PDCurses/pdcurses/clear.c")
        .file("src/PDCurses/pdcurses/color.c")
        .file("src/PDCurses/pdcurses/debug.c")
        .file("src/PDCurses/pdcurses/delch.c")
        .file("src/PDCurses/pdcurses/deleteln.c")
        .file("src/PDCurses/pdcurses/deprec.c")
        .file("src/PDCurses/pdcurses/getch.c")
        .file("src/PDCurses/pdcurses/getstr.c")
        .file("src/PDCurses/pdcurses/getyx.c")
        .file("src/PDCurses/pdcurses/inch.c")
        .file("src/PDCurses/pdcurses/inchstr.c")
        .file("src/PDCurses/pdcurses/initscr.c")
        .file("src/PDCurses/pdcurses/inopts.c")
        .file("src/PDCurses/pdcurses/insch.c")
        .file("src/PDCurses/pdcurses/insstr.c")
        .file("src/PDCurses/pdcurses/instr.c")
        .file("src/PDCurses/pdcurses/kernel.c")
        .file("src/PDCurses/pdcurses/keyname.c")
        .file("src/PDCurses/pdcurses/mouse.c")
        .file("src/PDCurses/pdcurses/move.c")
        .file("src/PDCurses/pdcurses/outopts.c")
        .file("src/PDCurses/pdcurses/overlay.c")
        .file("src/PDCurses/pdcurses/pad.c")
        .file("src/PDCurses/pdcurses/panel.c")
        .file("src/PDCurses/pdcurses/printw.c")
        .file("src/PDCurses/pdcurses/refresh.c")
        .file("src/PDCurses/pdcurses/scanw.c")
        .file("src/PDCurses/pdcurses/scr_dump.c")
        .file("src/PDCurses/pdcurses/scroll.c")
        .file("src/PDCurses/pdcurses/slk.c")
        .file("src/PDCurses/pdcurses/termattr.c")
        .file("src/PDCurses/pdcurses/terminfo.c")
        .file("src/PDCurses/pdcurses/touch.c")
        .file("src/PDCurses/pdcurses/util.c")
        .file("src/PDCurses/pdcurses/window.c")
        .file("src/PDCurses/win32a/pdcclip.c") //win32a implementation files
        .file("src/PDCurses/win32a/pdcdisp.c")
        .file("src/PDCurses/win32a/pdcgetsc.c")
        .file("src/PDCurses/win32a/pdckbd.c")
        .file("src/PDCurses/win32a/pdcscrn.c")
        .file("src/PDCurses/win32a/pdcsetsc.c")
        .file("src/PDCurses/win32a/pdcutil.c")
        .include("src/PDCurses")
        .define("PDC_WIDE", Some("Y")) //Build with wide-character (Unicode) support
        .define("PDC_FORCE_UTF8", Some("Y")) //Makes PDCurses ignore the system locale, and treat all narrow-character strings as UTF-8
        .compile("libpdcurses.a");
}
<|endoftext|>


<commit_before>extern crate bindgen;

const FRAMEWORKS_PATH: &'static str = "System/Library/Frameworks";

fn sdk_path(target: &str) -> Result<String, std::io::Error> {
    // Use environment variable if set
    println!("cargo:rerun-if-env-changed=COREAUDIO_SDK_PATH");
    if let Ok(path) = std::env::var("COREAUDIO_SDK_PATH") {
        return Ok(path);
    }

    use std::process::Command;

    let sdk = if target.contains("apple-darwin") {
        "macosx"
    } else if target.contains("apple-ios") {
        "iphoneos"
    } else {
        unreachable!();
    };
    let output = Command::new("xcrun")
        .args(&["--sdk", sdk, "--show-sdk-path"])
        .output()?
        .stdout;
    let prefix_str = std::str::from_utf8(&output).expect("invalid output from `xcrun`");
    Ok(prefix_str.trim_end().to_string())
}

fn build(sdk_path: &str, target: &str) {
    // Generate one large set of bindings for all frameworks.
    //
    // We do this rather than generating a module per framework as some frameworks depend on other
    // frameworks and in turn share types. To ensure all types are compatible across each
    // framework, we feed all headers to bindgen at once.
    //
    // Only link to each framework and include their headers if their features are enabled and they
    // are available on the target os.

    use std::env;
    use std::path::PathBuf;

    let mut headers = vec![];

    #[cfg(feature = "audio_toolbox")]
    {
        println!("cargo:rustc-link-lib=framework=AudioToolbox");
        headers.push("AudioToolbox.framework/Headers/AudioToolbox.h");
    }

    #[cfg(feature = "audio_unit")]
    {
        println!("cargo:rustc-link-lib=framework=AudioUnit");
        headers.push("AudioUnit.framework/Headers/AudioUnit.h");
    }

    #[cfg(feature = "core_audio")]
    {
        println!("cargo:rustc-link-lib=framework=CoreAudio");
        headers.push("CoreAudio.framework/Headers/CoreAudio.h");
    }

    #[cfg(feature = "open_al")]
    {
        println!("cargo:rustc-link-lib=framework=OpenAL");
        headers.push("OpenAL.framework/Headers/al.h");
        headers.push("OpenAL.framework/Headers/alc.h");
    }

    #[cfg(all(feature = "core_midi"))]
    {
        if target.contains("apple-darwin") {
            println!("cargo:rustc-link-lib=framework=CoreMIDI");
            headers.push("CoreMIDI.framework/Headers/CoreMIDI.h");
        }
    }

    println!("cargo:rerun-if-env-changed=BINDGEN_EXTRA_CLANG_ARGS");
    // Get the cargo out directory.
    let out_dir = PathBuf::from(env::var("OUT_DIR").expect("env variable OUT_DIR not found"));

    // Begin building the bindgen params.
    let mut builder = bindgen::Builder::default();

    builder = builder.clang_args(&[&format!("--target={}", target), "-isysroot", sdk_path]);

    // Add all headers.
    for relative_path in headers {
        let absolute_path = format!("{}/{}/{}", sdk_path, FRAMEWORKS_PATH, relative_path);
        builder = builder.header(absolute_path);
    }

    // Generate the bindings.
    builder = builder
        .trust_clang_mangling(false)
        .derive_default(true);

    let bindings = builder.generate().expect("unable to generate bindings");

    // Write them to the crate root.
    bindings
        .write_to_file(out_dir.join("coreaudio.rs"))
        .expect("could not write bindings");
}

fn main() {
    let target = std::env::var("TARGET").unwrap();
    if !(target.contains("apple-darwin") || target.contains("apple-ios")) {
        panic!("coreaudio-sys requires macos or ios target");
    }

    if let Ok(directory) = sdk_path(&target) {
        build(&directory, &target);
    } else {
        panic!("coreaudio-sys could not find an appropriate SDK");
    }
}
<commit_msg>Simplify the build script further<commit_after>extern crate bindgen;

fn sdk_path(target: &str) -> Result<String, std::io::Error> {
    // Use environment variable if set
    println!("cargo:rerun-if-env-changed=COREAUDIO_SDK_PATH");
    if let Ok(path) = std::env::var("COREAUDIO_SDK_PATH") {
        return Ok(path);
    }

    use std::process::Command;

    let sdk = if target.contains("apple-darwin") {
        "macosx"
    } else if target.contains("apple-ios") {
        "iphoneos"
    } else {
        unreachable!();
    };
    let output = Command::new("xcrun")
        .args(&["--sdk", sdk, "--show-sdk-path"])
        .output()?
        .stdout;
    let prefix_str = std::str::from_utf8(&output).expect("invalid output from `xcrun`");
    Ok(prefix_str.trim_end().to_string())
}

fn build(sdk_path: &str, target: &str) {
    // Generate one large set of bindings for all frameworks.
    //
    // We do this rather than generating a module per framework as some frameworks depend on other
    // frameworks and in turn share types. To ensure all types are compatible across each
    // framework, we feed all headers to bindgen at once.
    //
    // Only link to each framework and include their headers if their features are enabled and they
    // are available on the target os.

    use std::env;
    use std::path::PathBuf;

    let mut headers = vec![];

    #[cfg(feature = "audio_toolbox")]
    {
        println!("cargo:rustc-link-lib=framework=AudioToolbox");
        headers.push("AudioToolbox/AudioToolbox.h");
    }

    #[cfg(feature = "audio_unit")]
    {
        println!("cargo:rustc-link-lib=framework=AudioUnit");
        headers.push("AudioUnit/AudioUnit.h");
    }

    #[cfg(feature = "core_audio")]
    {
        println!("cargo:rustc-link-lib=framework=CoreAudio");
        headers.push("CoreAudio/CoreAudio.h");
    }

    #[cfg(feature = "open_al")]
    {
        println!("cargo:rustc-link-lib=framework=OpenAL");
        headers.push("OpenAL/al.h");
        headers.push("OpenAL/alc.h");
    }

    #[cfg(all(feature = "core_midi"))]
    {
        if target.contains("apple-darwin") {
            println!("cargo:rustc-link-lib=framework=CoreMIDI");
            headers.push("CoreMIDI/CoreMIDI.h");
        }
    }

    println!("cargo:rerun-if-env-changed=BINDGEN_EXTRA_CLANG_ARGS");
    // Get the cargo out directory.
    let out_dir = PathBuf::from(env::var("OUT_DIR").expect("env variable OUT_DIR not found"));

    // Begin building the bindgen params.
    let mut builder = bindgen::Builder::default();

    builder = builder.clang_args(&[&format!("--target={}", target), "-isysroot", sdk_path]);

    let meta_header: Vec<_> = headers
        .iter()
        .map(|h| format!("#include <{}>\n", h))
        .collect();

    builder = builder.header_contents("coreaudio.h", &meta_header.concat());

    // Generate the bindings.
    builder = builder
        .trust_clang_mangling(false)
        .derive_default(true);

    let bindings = builder.generate().expect("unable to generate bindings");

    // Write them to the crate root.
    bindings
        .write_to_file(out_dir.join("coreaudio.rs"))
        .expect("could not write bindings");
}

fn main() {
    let target = std::env::var("TARGET").unwrap();
    if !(target.contains("apple-darwin") || target.contains("apple-ios")) {
        panic!("coreaudio-sys requires macos or ios target");
    }

    if let Ok(directory) = sdk_path(&target) {
        build(&directory, &target);
    } else {
        panic!("coreaudio-sys could not find an appropriate SDK");
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::fs;
use std::path;

extern crate genecs;
extern crate copy_dir;
extern crate tomson;
extern crate handlebars;
extern crate rustc_serialize;

mod gensh;

fn main() {
    gensh::generate_spatial_hash("sh.toml", format!("src{}spatial_hash{}generated.rs",
                                                    path::MAIN_SEPARATOR,
                                                    path::MAIN_SEPARATOR));
    genecs::generate_ecs("ecs.toml", format!("src{}ecs{}generated.rs",
                                             path::MAIN_SEPARATOR,
                                             path::MAIN_SEPARATOR));
    copy_resources("resources");
    copy_resources("user");
}

fn target_dir_names() -> Result<Vec<String>, env::VarError> {
    let target = env::var("TARGET")?;
    let host = env::var("HOST")?;
    let profile = env::var("PROFILE")?;

    if target == host {
        Ok(vec![
            format!("target{}{}", path::MAIN_SEPARATOR, profile).to_string(),
            format!("target{}{}{}{}", path::MAIN_SEPARATOR, target, path::MAIN_SEPARATOR, profile).to_string(),
        ])
    } else {
        Ok(vec![format!("target{}{}{}{}", path::MAIN_SEPARATOR, target, path::MAIN_SEPARATOR, profile).to_string()])
    }
}

fn copy_resources(resources_dir_name: &str) {
    let target_dir_names = target_dir_names().expect("Failed to locate target directory");

    for target_dir_name in target_dir_names {

        if !path::PathBuf::from(&target_dir_name).is_dir() {
            continue;
        }

        let dest_name = format!("{}{}{}", target_dir_name, path::MAIN_SEPARATOR, resources_dir_name);
        let dest_path = path::PathBuf::from(dest_name);
        if dest_path.is_dir() {
            fs::remove_dir_all(&dest_path).expect("Failed to remove old resources directory");
        }
        if dest_path.is_file() {
            fs::remove_file(&dest_path).expect("Failed to remove file in place of resources directory");
        }
        copy_dir::copy_dir(resources_dir_name, &dest_path).expect("Failed to copy resources");
    }
}
<commit_msg>Tidy resource copying in build script<commit_after>use std::env;
use std::fs;
use std::path::{Path, PathBuf};

extern crate genecs;
extern crate copy_dir;
extern crate tomson;
extern crate handlebars;
extern crate rustc_serialize;

mod gensh;

fn main() {
    gensh::generate_spatial_hash("sh.toml", Path::new("src").join("spatial_hash").join("generated.rs"));
    genecs::generate_ecs("ecs.toml", Path::new("src").join("ecs").join("generated.rs"));

    copy_resources("resources");
    copy_resources("user");
}

fn target_dirs() -> Result<Vec<PathBuf>, env::VarError> {
    let target = env::var("TARGET")?;
    let host = env::var("HOST")?;
    let profile = env::var("PROFILE")?;

    if target == host {
        Ok(vec![
           Path::new("target").join(&profile),
           Path::new("target").join(&target).join(&profile),
        ])
    } else {
        Ok(vec![Path::new("target").join(&target).join(&profile)])
    }
}

fn copy_resources(resources_dir_name: &str) {

    for target_dir in target_dirs().expect("Failed to locate target directory") {

        if !target_dir.is_dir() {
            continue;
        }

        let dest_path = target_dir.join(resources_dir_name);

        if dest_path.is_dir() {
            fs::remove_dir_all(&dest_path).expect("Failed to remove old resources directory");
        }
        if dest_path.is_file() {
            fs::remove_file(&dest_path).expect("Failed to remove file in place of resources directory");
        }
        copy_dir::copy_dir(resources_dir_name, &dest_path).expect("Failed to copy resources");
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 fd developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0>
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

#[macro_use]
extern crate clap;
extern crate version_check;

use clap::Shell;
use std::io::{self, Write};
use std::process::exit;

include!("src/app.rs");

fn main() {
    match version_check::is_min_version("1.19") {
        // rustc >= 1.19
        Some((true, _)) => {}
        // rustc < 1.19 or can't figure it out
        _ => {
            writeln!(&mut io::stderr(), "This crate requires rustc >= 1.19").unwrap();
            exit(1);
        }
    }

    let var = std::env::var_os("SHELL_COMPLETIONS_DIR").or(std::env::var_os("OUT_DIR"));
    let outdir = match var {
        None => return,
        Some(outdir) => outdir,
    };

    let mut app = build_app();
    app.gen_completions("fd", Shell::Bash, &outdir);
    app.gen_completions("fd", Shell::Fish, &outdir);
    app.gen_completions("fd", Shell::Zsh, &outdir);
    app.gen_completions("fd", Shell::PowerShell, &outdir);
}
<commit_msg>Create shell completions OUT_DIR<commit_after>// Copyright (c) 2017 fd developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0>
// or the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

#[macro_use]
extern crate clap;
extern crate version_check;

use clap::Shell;
use std::io::{self, Write};
use std::process::exit;
use std::fs;

include!("src/app.rs");

fn main() {
    match version_check::is_min_version("1.19") {
        // rustc >= 1.19
        Some((true, _)) => {}
        // rustc < 1.19 or can't figure it out
        _ => {
            writeln!(&mut io::stderr(), "This crate requires rustc >= 1.19").unwrap();
            exit(1);
        }
    }

    let var = std::env::var_os("SHELL_COMPLETIONS_DIR").or(std::env::var_os("OUT_DIR"));
    let outdir = match var {
        None => return,
        Some(outdir) => outdir,
    };
    fs::create_dir_all(&outdir).unwrap();

    let mut app = build_app();
    app.gen_completions("fd", Shell::Bash, &outdir);
    app.gen_completions("fd", Shell::Fish, &outdir);
    app.gen_completions("fd", Shell::Zsh, &outdir);
    app.gen_completions("fd", Shell::PowerShell, &outdir);
}
<|endoftext|>