Skip to content
Permalink
Browse files

Initial Library/Binary Separation

The binary logic is still contained and now exposed within the library.
Yet now the binary will simply re-use the shell that was built from the library.
Therefore, there will no longer be double compiles and excessive error messages.
  • Loading branch information...
mmstick committed Dec 27, 2017
1 parent bc49acb commit c1c44ecbc51112bbeb765d6b32be7b1c77c8b1f0
Showing with 74 additions and 123 deletions.
  1. +3 −0 Cargo.toml
  2. 0 src/{ → lib}/ascii_helpers.rs
  3. 0 src/{ → lib}/builtins/README.md
  4. 0 src/{ → lib}/builtins/calc.rs
  5. 0 src/{ → lib}/builtins/conditionals.rs
  6. 0 src/{ → lib}/builtins/echo.rs
  7. 0 src/{ → lib}/builtins/exec.rs
  8. +9 −7 src/{ → lib}/builtins/exists.rs
  9. 0 src/{ → lib}/builtins/functions.rs
  10. 0 src/{ → lib}/builtins/ion.rs
  11. +2 −1 src/{ → lib}/builtins/is.rs
  12. 0 src/{ → lib}/builtins/job_control.rs
  13. 0 src/{ → lib}/builtins/man_pages.rs
  14. 0 src/{ → lib}/builtins/mod.rs
  15. 0 src/{ → lib}/builtins/random.rs
  16. 0 src/{ → lib}/builtins/set.rs
  17. 0 src/{ → lib}/builtins/source.rs
  18. 0 src/{ → lib}/builtins/status.rs
  19. 0 src/{ → lib}/builtins/test.rs
  20. 0 src/{ → lib}/builtins/time.rs
  21. 0 src/{ → lib}/builtins/variables.rs
  22. +1 −1 src/{ → lib}/lib.rs
  23. 0 src/{ → lib}/parser/arguments.rs
  24. 0 src/{ → lib}/parser/assignments/actions.rs
  25. 0 src/{ → lib}/parser/assignments/checker.rs
  26. 0 src/{ → lib}/parser/assignments/keys.rs
  27. 0 src/{ → lib}/parser/assignments/mod.rs
  28. 0 src/{ → lib}/parser/assignments/operator.rs
  29. 0 src/{ → lib}/parser/assignments/splitter.rs
  30. 0 src/{ → lib}/parser/loops/for_grammar.rs
  31. 0 src/{ → lib}/parser/loops/mod.rs
  32. 0 src/{ → lib}/parser/mod.rs
  33. 0 src/{ → lib}/parser/pipelines/collector.rs
  34. 0 src/{ → lib}/parser/pipelines/mod.rs
  35. 0 src/{ → lib}/parser/quotes.rs
  36. 0 src/{ → lib}/parser/shell_expand/README.md
  37. 0 src/{ → lib}/parser/shell_expand/braces.rs
  38. 0 src/{ → lib}/parser/shell_expand/mod.rs
  39. 0 src/{ → lib}/parser/shell_expand/ranges.rs
  40. 0 src/{ → lib}/parser/shell_expand/words/index.rs
  41. 0 src/{ → lib}/parser/shell_expand/words/methods/arrays.rs
  42. 0 src/{ → lib}/parser/shell_expand/words/methods/mod.rs
  43. 0 src/{ → lib}/parser/shell_expand/words/methods/strings.rs
  44. 0 src/{ → lib}/parser/shell_expand/words/mod.rs
  45. 0 src/{ → lib}/parser/shell_expand/words/range.rs
  46. 0 src/{ → lib}/parser/shell_expand/words/select.rs
  47. 0 src/{ → lib}/parser/shell_expand/words/tests.rs
  48. 0 src/{ → lib}/parser/statement/case.rs
  49. 0 src/{ → lib}/parser/statement/functions.rs
  50. 0 src/{ → lib}/parser/statement/mod.rs
  51. 0 src/{ → lib}/parser/statement/parse.rs
  52. 0 src/{ → lib}/parser/statement/splitter.rs
  53. 0 src/{ → lib}/shell/assignments.rs
  54. 0 src/{ → lib}/shell/binary/README.md
  55. 0 src/{ → lib}/shell/binary/designators.rs
  56. +1 −1 src/{ → lib}/shell/binary/mod.rs
  57. 0 src/{ → lib}/shell/binary/prompt.rs
  58. 0 src/{ → lib}/shell/binary/readln.rs
  59. 0 src/{ → lib}/shell/binary/terminate.rs
  60. 0 src/{ → lib}/shell/colors.rs
  61. 0 src/{ → lib}/shell/completer.rs
  62. 0 src/{ → lib}/shell/directory_stack.rs
  63. 0 src/{ → lib}/shell/flags.rs
  64. 0 src/{ → lib}/shell/flow.rs
  65. 0 src/{ → lib}/shell/flow_control.rs
  66. 0 src/{ → lib}/shell/fork.rs
  67. 0 src/{ → lib}/shell/history.rs
  68. 0 src/{ → lib}/shell/job.rs
  69. +48 −30 src/{ → lib}/shell/mod.rs
  70. 0 src/{ → lib}/shell/pipe_exec/README.md
  71. 0 src/{ → lib}/shell/pipe_exec/command_not_found.rs
  72. 0 src/{ → lib}/shell/pipe_exec/foreground.rs
  73. 0 src/{ → lib}/shell/pipe_exec/fork.rs
  74. 0 src/{ → lib}/shell/pipe_exec/job_control.rs
  75. 0 src/{ → lib}/shell/pipe_exec/mod.rs
  76. 0 src/{ → lib}/shell/pipe_exec/streams.rs
  77. 0 src/{ → lib}/shell/plugins/library_iter/mod.rs
  78. 0 src/{ → lib}/shell/plugins/library_iter/redox.rs
  79. 0 src/{ → lib}/shell/plugins/library_iter/unix.rs
  80. 0 src/{ → lib}/shell/plugins/methods/mod.rs
  81. 0 src/{ → lib}/shell/plugins/methods/redox.rs
  82. 0 src/{ → lib}/shell/plugins/methods/unix.rs
  83. 0 src/{ → lib}/shell/plugins/mod.rs
  84. 0 src/{ → lib}/shell/plugins/namespaces/mod.rs
  85. 0 src/{ → lib}/shell/plugins/namespaces/redox.rs
  86. 0 src/{ → lib}/shell/plugins/namespaces/unix.rs
  87. 0 src/{ → lib}/shell/plugins/string.rs
  88. 0 src/{ → lib}/shell/signals.rs
  89. 0 src/{ → lib}/shell/status.rs
  90. 0 src/{ → lib}/shell/variables/mod.rs
  91. 0 src/{ → lib}/sys/redox.rs
  92. 0 src/{ → lib}/sys/unix/job_control.rs
  93. 0 src/{ → lib}/sys/unix/mod.rs
  94. 0 src/{ → lib}/sys/unix/signals.rs
  95. 0 src/{ → lib}/types.rs
  96. +10 −83 src/main.rs
@@ -41,6 +41,9 @@ smallvec = "0.4"
unicode-segmentation = "1.2"
xdg = { git = "https://github.com/whitequark/rust-xdg" }

[lib]
path = "src/lib/lib.rs"

[profile.release]
lto = true
panic = "abort"
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -8,6 +8,8 @@ use std::os::unix::fs::PermissionsExt;
use shell::Shell;
#[cfg(test)]
use shell::flow_control::{Function, Statement};
#[cfg(test)]
use shell;

pub(crate) fn exists(args: &[&str], shell: &Shell) -> Result<bool, String> {
let arguments = &args[1..];
@@ -147,7 +149,7 @@ fn function_is_defined(function: &str, shell: &Shell) -> bool {
#[test]
fn test_evaluate_arguments() {
use parser::assignments::{KeyBuf, Primitive};
let mut shell = Shell::new();
let mut shell = shell::ShellBuilder::new().as_library();

// assert_eq!(evaluate_arguments(&[], &mut sink, &shell), Ok(false));
// no parameters
@@ -268,7 +270,7 @@ fn test_evaluate_arguments() {

#[test]
fn test_match_flag_argument() {
let shell = Shell::new();
let shell = shell::ShellBuilder::new().as_library();

// we don't really care about the passed values, as long as both sited return
// the same value
@@ -299,7 +301,7 @@ fn test_match_flag_argument() {

#[test]
fn test_match_option_argument() {
let shell = Shell::new();
let shell = shell::ShellBuilder::new().as_library();

// we don't really care about the passed values, as long as both sited return
// the same value
@@ -326,7 +328,7 @@ fn test_path_is_directory() {

#[test]
fn test_binary_is_in_path() {
let mut shell = Shell::new();
let mut shell = shell::ShellBuilder::new().as_library();

// TODO: We should probably also test with more complex PATH-variables:
// TODO: multiple/:directories/
@@ -357,7 +359,7 @@ fn test_string_is_nonzero() {

#[test]
fn test_array_var_is_not_empty() {
let mut shell = Shell::new();
let mut shell = shell::ShellBuilder::new().as_library();

shell
.variables
@@ -383,7 +385,7 @@ fn test_array_var_is_not_empty() {

#[test]
fn test_string_var_is_not_empty() {
let mut shell = Shell::new();
let mut shell = shell::ShellBuilder::new().as_library();

shell.set_var("EMPTY", "");
assert_eq!(string_var_is_not_empty("EMPTY", &shell), false);
@@ -407,7 +409,7 @@ fn test_string_var_is_not_empty() {
#[test]
fn test_function_is_defined() {
use parser::assignments::{KeyBuf, Primitive};
let mut shell = Shell::new();
let mut shell = shell::ShellBuilder::new().as_library();

// create a simple dummy function
let name_str = "test_function";
File renamed without changes.
File renamed without changes.
@@ -45,7 +45,8 @@ fn get_var_string(name: &str, shell: &mut Shell) -> String {

#[test]
fn test_is() {
let mut shell = Shell::new();
use shell::ShellBuilder;
let mut shell = ShellBuilder::new().as_library();
shell.set_var("x", "value");
shell.set_var("y", "0");

File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -49,6 +49,6 @@ mod builtins;
mod shell;
mod ascii_helpers;

pub use shell::{Capture, Fork, IonError, IonResult, Shell};
pub use shell::{Binary, Capture, Fork, IonError, IonResult, Shell, ShellBuilder};
pub use shell::flags;
pub use shell::status;
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -43,7 +43,7 @@ OPTIONS
prints the version, platform and revision of ion then exits.
"#;

pub(crate) trait Binary {
pub trait Binary {
/// Launches the shell, parses arguments, and then diverges into one of the `execution`
/// paths.
fn main(self);
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -15,7 +15,7 @@ pub(crate) mod signals;
pub mod status;
pub mod variables;

pub(crate) use self::binary::Binary;
pub use self::binary::Binary;
pub(crate) use self::flow::FlowLogic;
pub use self::fork::{Capture, Fork, IonResult};
pub(crate) use self::history::{IgnoreSetting, ShellHistory};
@@ -50,7 +50,6 @@ use sys;
use types::*;
use xdg::BaseDirectories;

#[allow(dead_code)]
#[derive(Debug, Fail)]
pub enum IonError {
#[fail(display = "failed to fork: {}", why)] Fork { why: io::Error },
@@ -106,33 +105,55 @@ pub struct Shell {
ignore_setting: IgnoreSetting,
}

impl<'a> Shell {
#[allow(dead_code)]
/// Panics if DirectoryStack construction fails
pub(crate) fn new_bin() -> Shell {
Shell {
builtins: BUILTINS,
context: None,
variables: Variables::default(),
flow_control: FlowControl::default(),
directory_stack: DirectoryStack::new(),
functions: FnvHashMap::default(),
previous_job: !0,
previous_status: 0,
flags: 0,
foreground: Vec::new(),
background: Arc::new(Mutex::new(Vec::new())),
is_background_shell: false,
is_library: false,
break_flow: false,
foreground_signals: Arc::new(ForegroundSignals::new()),
ignore_setting: IgnoreSetting::default(),
pub struct ShellBuilder;

impl ShellBuilder {
pub fn new() -> ShellBuilder { ShellBuilder }

pub fn install_signal_handler(self) -> ShellBuilder {
extern "C" fn handler(signal: i32) {
let signal = match signal {
sys::SIGINT => signals::SIGINT,
sys::SIGHUP => signals::SIGHUP,
sys::SIGTERM => signals::SIGTERM,
_ => unreachable!(),
};

signals::PENDING.store(signal, Ordering::SeqCst);
}

let _ = sys::signal(sys::SIGHUP, handler);
let _ = sys::signal(sys::SIGINT, handler);
let _ = sys::signal(sys::SIGTERM, handler);

self
}

#[allow(dead_code)]
/// Creates a new shell within memory.
pub fn new() -> Shell {
pub fn block_signals(self) -> ShellBuilder {
// This will block SIGTSTP, SIGTTOU, SIGTTIN, and SIGCHLD, which is required
// for this shell to manage its own process group / children / etc.
signals::block();

self
}

pub fn set_unique_pid(self) -> ShellBuilder {
if let Ok(pid) = sys::getpid() {
if sys::setpgid(0, pid).is_ok() {
let _ = sys::tcsetpgrp(0, pid);
}
}

self
}

pub fn as_library(self) -> Shell { Shell::new(true) }

pub fn as_binary(self) -> Shell { Shell::new(false) }
}

impl<'a> Shell {
pub(crate) fn new(is_library: bool) -> Shell {
Shell {
builtins: BUILTINS,
context: None,
@@ -146,7 +167,7 @@ impl<'a> Shell {
foreground: Vec::new(),
background: Arc::new(Mutex::new(Vec::new())),
is_background_shell: false,
is_library: true,
is_library,
break_flow: false,
foreground_signals: Arc::new(ForegroundSignals::new()),
ignore_setting: IgnoreSetting::default(),
@@ -327,7 +348,6 @@ impl<'a> Shell {
self.variables.get_array(name).map(SmallVec::as_ref)
}

#[allow(dead_code)]
/// A method for executing commands in the Ion shell without capturing. It takes command(s)
/// as
/// a string argument, parses them, and executes them the same as it would if you had
@@ -348,7 +368,6 @@ impl<'a> Shell {
}
}

#[allow(dead_code)]
/// A method for executing scripts in the Ion shell without capturing. Given a `Path`, this
/// method will attempt to execute that file as a script, and then returns the final exit
/// status of the evaluated script.
@@ -363,7 +382,6 @@ impl<'a> Shell {
Ok(self.previous_status)
}

#[allow(dead_code)]
/// A method for executing a function with the given `name`, using `args` as the input.
/// If the function does not exist, an `IonError::DoesNotExist` is returned.
pub fn execute_function(&mut self, name: &str, args: &[&str]) -> Result<i32, IonError> {
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -1,87 +1,14 @@
#![allow(unknown_lints)]
#![allow(while_let_on_iterator)]
#![feature(conservative_impl_trait)]
#![feature(integer_atomics)]
#![feature(pointer_methods)]
#![feature(getpid)]
extern crate ion_shell;

// For a performance boost on Linux
// #![feature(alloc_system)]
// extern crate alloc_system;

extern crate xdg;
#[macro_use]
extern crate bitflags;
extern crate calc;
#[cfg(all(unix, not(target_os = "redox")))]
extern crate errno;
extern crate failure;
#[macro_use]
extern crate failure_derive;
extern crate fnv;
extern crate glob;
extern crate itoa;
#[macro_use]
extern crate lazy_static;
#[cfg(all(unix, not(target_os = "redox")))]
extern crate libc;
#[cfg(all(unix, not(target_os = "redox")))]
extern crate libloading;
extern crate liner;
extern crate regex;
extern crate smallstring;
extern crate smallvec;
#[cfg(target_os = "redox")]
extern crate syscall;
extern crate unicode_segmentation;
#[cfg(all(unix, not(target_os = "redox")))]
extern crate users as users_unix;

#[cfg(target_os = "redox")]
#[path = "sys/redox.rs"]
mod sys;

#[cfg(unix)]
#[path = "sys/unix/mod.rs"]
mod sys;

#[macro_use]
mod types;
#[macro_use]
mod parser;
mod builtins;
mod shell;
mod ascii_helpers;

use shell::{signals, Binary, Shell};
use std::sync::atomic::Ordering;

extern "C" fn handler(signal: i32) {
let signal = match signal {
sys::SIGINT => signals::SIGINT,
sys::SIGHUP => signals::SIGHUP,
sys::SIGTERM => signals::SIGTERM,
_ => unreachable!(),
};

signals::PENDING.store(signal, Ordering::SeqCst);
}
use ion_shell::{Binary, ShellBuilder};

fn main() {
let _ = sys::signal(sys::SIGHUP, handler);
let _ = sys::signal(sys::SIGINT, handler);
let _ = sys::signal(sys::SIGTERM, handler);

// This will block SIGTSTP, SIGTTOU, SIGTTIN, and SIGCHLD, which is required
// for this shell to manage its own process group / children / etc.
signals::block();

if let Ok(pid) = sys::getpid() {
if sys::setpgid(0, pid).is_ok() {
let _ = sys::tcsetpgrp(0, pid);
}
}

let shell = Shell::new_bin();
shell.main();
ShellBuilder::new()
.install_signal_handler()
.block_signals()
.set_unique_pid()
.as_binary()
.main();
}

// TODO: The `Binary` / `main()` logic should be implemented here, and not within the library.

0 comments on commit c1c44ec

Please sign in to comment.
You can’t perform that action at this time.