// This file was derived from rust's own libstd/process.rs with the following
// copyright:
//
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
use std::ffi::OsStr;

use nix::{errno::Errno, fcntl::OFlag};

use crate::{
    compat::pipe2_raw,
    unshare::{config::Config, ffi_util::ToCString, Command},
};

impl Command {
    /// Constructs a new `Command` for launching the program at
    /// path `program`, with the following default configuration:
    ///
    /// * No arguments to the program
    /// * Inherit the current process's environment
    /// * Inherit the current process's working directory
    /// * Inherit stdin/stdout/stderr for `spawn` or `status`, but create pipes for `output`
    ///
    /// Builder methods are provided to change these defaults and
    /// otherwise configure the process.
    pub fn new<S: AsRef<OsStr>>(program: S) -> Result<Command, Errno> {
        Ok(Command {
            config: Config::default(),
            exe_file: Some(program.to_cstring()),
            exe_args: Some(vec![program.to_cstring()]),
            before_unfreeze: None,
            pre_exec: None,
            pty_fd: None,
            ioctl_denylist: None,
            seccomp_filter: None,
            seccomp_pipefd: (pipe2_raw(OFlag::O_CLOEXEC)?, pipe2_raw(OFlag::O_CLOEXEC)?),
        })
    }

    /// Add an argument to pass to the program.
    pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Command {
        if let Some(ref mut exe_args) = self.exe_args {
            exe_args.push(arg.to_cstring());
        } else {
            self.exe_args = Some(vec![arg.to_cstring()]);
        }
        self
    }

    /// Add multiple arguments to pass to the program.
    pub fn args<I, S>(&mut self, args: I) -> &mut Command
    where
        I: IntoIterator<Item = S>,
        S: AsRef<OsStr>,
    {
        for arg in args {
            self.arg(arg.as_ref());
        }
        self
    }
}
