restructuring igloo majorly. im simplifying the hierarchy for now and will improve it later. learning rust is a weird tree of unknowns is hard. this should make development faster for now

unstable
Penguin 3 years ago
parent 3f638f6475
commit d33f842166

@ -5,16 +5,19 @@ authors = ["Penguin <...>"]
edition = "2018"
repository = "https://github.com/Embedded-Penguin/ePenguin-igloo/"
readme = "README.md"
description = "Igloo is a package and project manager. It is used for bare metal (for now only bare metal) embedded systems. In the embedded world, there is a big gap between how one would write code for embedded systems between manufacturers. As of today, 7/2/20, there is really no easy way to go about writing code for any embedded system from scratch. Most of the time, you need to download headers from some unknown location, figure out your hardware interface, find the proper toolchain, etc. This forces embedded developers and engineers to spend a lot of unnecessary time on DevOps and less time on firmware engineering. Igloo aims to solve this problem. Igloo is in its early stages of development."
license="GPL-3.0+"
description = "
Igloo is a package/project manager. It is used for bare metal embedded systems. It is in its early stages of development. The goal of this project is to reduce the pain of writing embedded code by bridging the gap between many different manufacturers. It is can be thought of as glue for many of the fragmented pieces in the embedded world.
This is also a learning project for me. Not all of this code will be the most efficient. I wanted to use a problem I saw as an opportunity to learn rust. Advice is welcome.
"
license="GPL-2.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
igloo_core = { path = "./igloo_core" }
igloo_cli = { path = "./igloo_cli" }
igloo_agent = { path = "./igloo_agent" }
igloo_manifest = { path = "./igloo_manifest" }
[workspace]
members = ["igloo_base", "igloo_core", "igloo_cli", "igloo_agent", "igloo_manifest"]
members = ["igloo_core", "igloo_cli", "igloo_agent"]

@ -1,10 +0,0 @@
[package]
name = "igloo_base"
version = "0.1.0"
authors = ["Penguin <penguin@epenguin.net>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
directories = "3.0.1"

@ -1,128 +0,0 @@
use std::path::PathBuf;
use std::env;
use directories::*;
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
}
// #[macro_export]
// macro_rules! igloo_println
// {
// }
#[derive(Debug)]
#[derive(PartialEq)]
pub enum IglooInstType
{
Null = -1,
New = 0,
Run = 1,
Push = 2,
Pull = 3,
Debug = 4,
Clean = 5,
Erase = 6,
GenDoc = 7,
Info = 8,
Target = 9,
}
#[derive(Debug)]
#[derive(PartialEq)]
pub enum IglooDebugSeverity
{
CRITICAL = 0,
WARNING = 1,
INFO = 2,
TRACE = 3,
}
#[derive(Debug)]
#[derive(PartialEq)]
/// Igloo Error Type
pub enum IglooErrType
{
ErrNone = 0,
ErrUnknown = 1,
ConfigNotFound = 2,
ConfigFound = 3,
UnknownInstType = 4,
NewCalledInsideProject = 5,
FolderAlreadyExists = 6,
InvalidProjectName = 7,
InvalidEnvInfo = 8,
InvalidTarget = 9,
/// Failed to load ePenguin Make Manifest
/// This means igloo couldn't find the master
/// make manifest
FailedToLoadMasterMakeManifest = 10,
/// Failed to load ePenguin Target Manifest
/// This means igloo couldn't find the master
/// target manifest
FailedToLoadMasterTargetManifest = 11,
/// This means igloo couldn't find the scripts dir
/// which should be located within a target directory
/// It should be impossible for igloo to generate a target
/// inside a project without also generating a scripts directory.
/// The likely culprit of this failure is a user has messed with the folder
FailedToFindTargetScriptsDir = 12,
ActionCalledOutsideProject = 13,
}
#[derive(Debug)]
#[derive(PartialEq)]
#[derive(Clone)]
pub struct IglooEnvInfo
{
// Current Working Directory
pub cwd: PathBuf,
// Home Directory
pub hd: PathBuf,
// ESF Directory
pub esfd: PathBuf,
}
impl IglooEnvInfo
{
/// Returns the environment information for the igloo call
pub fn get_env_info() -> IglooEnvInfo
{
IglooEnvInfo
{
cwd: env::current_dir().unwrap(),
hd: match UserDirs::new()
{
Some(v) => v.home_dir().to_owned(),
None =>
{
println!("Error: Failed to get home directory.\n\
This should never happen. Exiting...");
std::process::exit(1);
}
},
esfd: match std::env::var("ESF_DIR")
{
Ok(v) =>
{
std::path::PathBuf::from(&v.to_owned())
}
Err(e) =>
{
// Note: Need to change new to return errors
// instead of exiting early
println!("Error: $ESF_DIR not defined as an environment\
variable -- {:?}", e);
std::process::exit(1);
}
}
}
}
}

@ -1,12 +0,0 @@
[package]
name = "igloo_cli"
version = "0.1.0"
authors = ["Penguin <penguin@epenguin.net>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
igloo_base = { path = "../igloo_base" }
clap = "3.0.0-beta.2"
config = "0.10"

@ -1,15 +1,10 @@
[package]
name = "igloo_core"
version = "0.1.0"
authors = ["Penguin <penguin@epenguin.net>"]
edition = "2018"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
clap = "3.0.0-beta.2"
config = "0.10"
igloo_base = { path = "../igloo_base" }
igloo_cli = { path = "../igloo_cli" }
igloo_manifest = { path = "../igloo_manifest" }
sscanf = "0.1.2"

@ -1,58 +0,0 @@
use igloo_base::*;
use igloo_base::IglooErrType::*;
use crate::Igloo;
use crate::igloo_project::IglooPrj;
pub fn iac_run(prj_name: &str, target: &str) -> IglooErrType
{
let res_err: IglooErrType = ErrNone;
res_err
}
pub fn new(inst: &Igloo, prj_name: &str, target: &str)
-> IglooErrType
{
let mut res_err: IglooErrType = ErrNone;
// Check if we are already inside of an igloo project
// Creating an igloo project inside an igloo project
// is a no no
if IglooPrj::is_igloo_prj(&std::env::current_dir().unwrap())
{
println!("Calling igloo new from igloo project...");
res_err = NewCalledInsideProject;
return res_err
}
// Check if the project folder already exists
// Don't want to accidentally overwrite anything
if std::path::Path::new(prj_name).exists()
{
res_err = FolderAlreadyExists;
return res_err
}
let project = IglooPrj::new(inst, prj_name, target);
match project
{
Err(e) =>
{
println!("Error spawning project: {:?}", e);
res_err = e;
return res_err
}
_ => (),
}
let res_err = project.unwrap().populate();
if res_err != ErrNone
{
return res_err
}
res_err
}
pub fn push(inst: &Igloo)
{
}

@ -1,24 +1,10 @@
extern crate clap;
extern crate config;
use igloo_base::*;
use igloo_base::IglooInstType::*;
use igloo_base::IglooErrType::*;
use clap::{App, Arg, ArgMatches};
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
}
use IglooType::*;
use IglooStatus::*;
/// IglooCliConfig stores information about the igloo command being run.
/// It is all handled in active memory because we only care about this
/// information during the execution of that command.
pub struct IglooCliConfig
/// Information input via cli will be stored here for the lifetime of the process
pub struct IglooCliInfo
{
pub raw: clap::ArgMatches,
pub version_major: i8,
@ -27,7 +13,7 @@ pub struct IglooCliConfig
pub description: String,
}
impl IglooCliConfig
impl IglooCliInfo
{
pub fn new() -> Self
{
@ -52,7 +38,7 @@ impl IglooCliConfig
}
/// runs the clap initializer to get command line arguments
fn igloo_app() -> clap::ArgMatches
fn igloo_run_cli() -> clap::ArgMatches
{
let ret_app = App::new("igloo")
.about(clap::crate_description!())
@ -111,46 +97,53 @@ fn igloo_app() -> clap::ArgMatches
.required(false)
.about("List of supported boards for the current version"),)))
.get_matches();
ret_app
}
pub fn igloo_subcommand(args: &ArgMatches) -> Result<IglooInstType, IglooErrType>
pub fn igloo_subcommand(args: &ArgMatches) -> Result<IglooType, IglooStatus>
{
let mut _res_type: IglooInstType = Null;
let mut _res_type: IglooType = Null;
match args.subcommand_name()
{
Some("new") =>
{
println!("Igloo new was called!");
_res_type = New;
_res_type = IT_NEW;
}
Some("run") =>
{
println!("Igloo run was called!");
_res_type = Run;
_res_type = IT_RUN;
}
Some("build") =>
{
println!("Igloo build was called!");
_res_type = IT_BUILD;
}
Some("push") =>
{
println!("Igloo flash was called!");
_res_type = Push;
_res_type = IT_PUSH;
}
Some("pull") =>
{
println!("Igloo pull was called!");
_res_type = IT_PULL;
}
Some("erase") =>
{
println!("Igloo erase was called!");
_res_type = Erase;
_res_type = IT_ERASE;
}
Some("info") =>
{
println!("Igloo info was called!");
_res_type = Info;
_res_type = IT_INFO;
}
Some("target") =>
{
println!("Igloo target was called");
_res_type = Target;
_res_type = IT_TARGET;
}
None => unreachable!(),
_ => unreachable!(),

File diff suppressed because it is too large Load Diff

@ -1,207 +0,0 @@
use igloo_base::*;
use igloo_base::IglooErrType::*;
use crate::IglooPrj;
use crate::Igloo;
use crate::config::Config;
use std::collections::HashMap;
use std::path::PathBuf;
use std::fs::OpenOptions;
use std::fs::File;
use std::io::prelude::*;
pub struct IglooTarget
{
// name, links, and includes are extracted from a manifest
pub name: String,
pub links: HashMap<String, config::Value>,
pub includes: Vec<config::Value>,
pub openocd: HashMap<String, config::Value>,
pub make_manifest: HashMap<String, config::Value>,
pub root: PathBuf,
}
impl IglooTarget
{
pub fn default() -> IglooTarget
{
IglooTarget
{
name: String::from(""),
root: PathBuf::default(),
make_manifest: HashMap::default(),
links: HashMap::default(),
includes: Vec::default(),
openocd: HashMap::default(),
}
}
pub fn from(root: PathBuf, inst: &Igloo, name_in: String,
target_make_loc: &str,
target_man_loc: &str) -> Result<IglooTarget, IglooErrType>
{
// target man first
let mut target_man = Config::new();
target_man.merge(
config::File::with_name(
IglooEnvInfo::get_env_info().esfd.join(target_man_loc)
.to_str().unwrap()))
.unwrap();
// now make man
let mut makefile: HashMap<String, config::Value> = HashMap::new();
let mut make_table_head = &target_make_loc[0..target_make_loc.len()];
let mut b_quit: bool = false;
loop
{
let mut _active_table = inst.master_make_man.get_table(&make_table_head).unwrap();
for (name, val) in _active_table
{
match val.clone().into_table()
{
Err(_e) =>
{
if !makefile.contains_key(&name)
{
makefile.insert(name, val);
}
else
{
let mut newval = val.clone().into_array().unwrap();
let mut newvec = makefile.get_key_value(&name).unwrap().1.clone().into_array().unwrap();
newvec.append(&mut newval);
makefile.insert(name, config::Value::from(newvec));
}
}
Ok(_v) => {}
}
}
match make_table_head.rfind('.')
{
None => b_quit = true,
Some(v) => make_table_head = &make_table_head[0..v],
}
if b_quit
{
break;
}
}
Ok(IglooTarget
{
name: String::from(name_in),
make_manifest: makefile,
links: target_man.get_table("esf.links").unwrap(),
includes: target_man.get_table("esf.includes")
.unwrap()
.get("IGLOO_INCLUDES")
.unwrap()
.clone()
.into_array()
.unwrap(),
openocd: target_man.get_table("esf.openocd")
.unwrap(),
root: root,
})
}
/// generate all folders needed for the target
pub fn generate(&self) -> IglooErrType
{
// Create target root directory
match std::fs::create_dir(&self.root)
{
Err(e) => println!("{:?}", e),
_ => (),
}
// Create target scripts directory
match std::fs::create_dir(&self.root.join("scripts"))
{
Err(e) => println!("{:?}", e),
_ => (),
}
ErrNone
}
/// populates all folders needed for the target
pub fn populate(&self) -> IglooErrType
{
let mut target_scripts_dir: PathBuf = PathBuf::from(
self.root.join("scripts"));
// Read the gdb scripts directory in ESF
let esf_target_scripts_dir = std::fs::read_dir(
&(String::from(
IglooEnvInfo::get_env_info()
.esfd.to_str()
.unwrap()) + "/scripts"))
.unwrap();
// Creating a vector to hold our gdb script file names
let mut gdb_scripts: std::vec::Vec<std::path::PathBuf>
= std::vec::Vec::new();
// Grab the files only
for entry in esf_target_scripts_dir
{
match &entry
{
Ok(v) => if !v.path().is_dir() {
gdb_scripts.push(v.path()) },
Err(e) => println!("{:?}", e),
}
}
// Generate each GDB script
for file in gdb_scripts
{
std::os::unix::fs::symlink(
&file, &target_scripts_dir.join(&file.file_name().unwrap())).unwrap();
}
// Populate the project ESF folder with our targets relevant files
let mut prj_esf_dir = self.root
.parent().unwrap()
.parent().unwrap()
.parent().unwrap().join("ESF");
println!("PRINTING {:?}", prj_esf_dir);
for (sym_dir, loc_in_esf) in &self.links
{
let link_to_dir = IglooEnvInfo::get_env_info()
.esfd
.join(&loc_in_esf.clone().into_str().unwrap());
std::os::unix::fs::symlink(link_to_dir, prj_esf_dir.join(sym_dir)).unwrap();
}
ErrNone
}
/// generates the makefile for a target
/// this will be updated as the user edits their project toml
pub fn generate_makefile(&self) -> IglooErrType
{
ErrNone
}
/// generates the openocd config for a target
/// this will be updated as the user edits their project toml
pub fn generate_openocd_config(&self) -> IglooErrType
{
let mut fromPath = IglooEnvInfo::get_env_info()
.esfd.join(self.openocd.get("scripts")
.unwrap()
.clone()
.into_str()
.unwrap())
.join(&self.name).with_extension("cfg");
let mut toPath = self.root.join("scripts")
.join(&self.name).with_extension("cfg");
std::fs::copy(&fromPath, &toPath).unwrap();
ErrNone
}
}

@ -1,156 +1,60 @@
#![allow(warnings)]
extern crate clap;
extern crate config;
/// Igloo Core
mod igloo_action;
mod igloo_project;
pub mod igloo_target;
mod igloo_target;
mod igloo_manifest;
mod igloo_cli;
use igloo_base::*;
use igloo_base::IglooInstType::*;
use igloo_base::IglooErrType::*;
use igloo_cli::*;
use igloo_manifest::*;
use igloo_project::IglooPrj;
pub enum IglooType
{
IT_NEW = 0,
IT_RUN,
IT_PUSH,
IT_PULL,
IT_HELP,
IT_BUILD,
IT_NULL,
}
use config::Config;
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
pub enum IglooStatus
{
IS_GOOD = 0x00,
IS_BAD = 0x01,
IS_UNKNOWN = 0x02,
}
/// Igloo should contain a config and any important environment information.
/// Upon running igloo, an instanc is created, env information is stored, and then
/// things happen.
pub struct Igloo
{
cli_conf: IglooCliConfig,
master_target_man: Config,
master_target_manifest: Config,
}
impl Igloo
{
/// The new function creates an instance of igloo. The idea is I create an igloo,
/// run start on it so I can collect environment information and process what command
/// the user would like to run, and then I run that command or deal with errors.
///
/// This function handles all cli input and stores it. It is parsed for errors in the
/// start function.
pub fn new() -> Self
{
Igloo
{
master_target_man: Config::new(),
master_target_manifest: Config::new(),
cli_conf: IglooCliConfig::new(),
}
}
/// The start function processes the command you want igloo to run
/// It theoretically should never return an error. It should just exit.
/// If an error was returned, It was my fault and not the users.
/// It is really only here to help me debug.
///
/// The Inst Type is only returned for usage outside of this struct.
pub fn start(&mut self) -> Result<IglooInstType, IglooErrType>
{
let mut res: IglooInstType = Null;
match IglooManifest::get_master_target_manifest(&mut self.master_target_man)
{
ErrNone => (),
v =>
{
println!("{:?}", v);
return Err(v)
},
}
// Assign our instance type (new, run, flash, etc..)
match igloo_subcommand(&self.cli_conf.raw)
{
Ok(v) => res = v,
Err(e) => return Err(e),
}
if res == Null
{
return Err(ErrUnknown)
}
Ok(res)
}
/// The run function processes the request from the user.
/// On success, it will give some string indicating the success of the operation.
/// On failure, it will return some error type.
pub fn run(&self, inst_type: IglooInstType) -> Result<String, IglooErrType>
{
let mut res_err = ErrNone;
let mut prj: IglooPrj;
loop { match inst_type
{
Null => res_err = ErrNone,
New =>
{
let prj_name: &str = self
.cli_conf
.raw
.subcommand()
.unwrap().1
.value_of("project_name")
.unwrap();
let target: &str = self
.cli_conf
.raw
.subcommand()
.unwrap().1
.value_of("target")
.unwrap();
let res_err = igloo_action::new(
self, prj_name, target);
if res_err != ErrNone
{
return Err(res_err)
}
}
Push =>
{
}
Run =>
{
}
Info =>
{
// list current version
println!("Igloo Version: {0}.{1}.{2}\n",
self.cli_conf.version_major,
self.cli_conf.version_minor,
self.cli_conf.version_patch);
// list esf version
// list supported mcus
}
// if we're in a project, list the project info
// list targets/boards
println!("Info in run handler");
}
Target =>
{
}
_ => println!("Unhandled case: {:?}", inst_type),
} break; }
if res_err == ErrNone
{
Ok(String::from("We won!"))
}
else
{
Err(res_err)
}
// Tests
#[cfg (test)]
mod tests {
#[test]
fn it_works() {
let result = 2 + 2;
assert_eq!(result, 4);
}
}

@ -1,12 +0,0 @@
[package]
name = "igloo_manifest"
version = "0.1.0"
authors = ["Penguin <penguin@epenguin.net>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
igloo_base = { path = "../igloo_base" }
config = "0.10"
sscanf = "0.1.2"

@ -1 +0,0 @@
penguin@gpenguin.3110:1639883851

@ -1,141 +0,0 @@
/// Igloo Manifest is a subproject responsible for working with manifests.
/// Manifests are anything from config files to giant lists or ... manifests.
/// For now, all functionality is going to sit in this lib.rs until I figure out
/// how I want to structure manifests
extern crate config;
extern crate sscanf;
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
}
pub mod IglooManifest
{
use igloo_base::*;
use igloo_base::IglooErrType::*;
use config::Config;
/// master_mm -- Master Make Manifest
/// master_tm -- Master Target Manifest
/// name -- name of target
pub fn target_is_valid(master_tm: &Config, name: &str)
-> Result<bool, IglooErrType>
{
let mut ret: bool = true;
if name.is_empty()
{
return Err(InvalidTarget)
}
let mut target_man_path: String = String::default();
// Confirm the target.make table exists in the master target manifest
match master_tm.get_table("target.make")
{
Ok(v) =>
{
// Confirm the target exists in the target.make table
// What this actually means is make sure we can use the target name
// to acquire the target's name in the master make manifest
match v.get(name)
{
Some(v) =>
{
// Now we've confirmed the target has an entry in the target.make table
println!("target.make entry for \"{}\" exists!", v);
// store the target's full name for use in the master make manifest later
target_man_path = v.to_string();
}
None =>
{
// if we've gotten to this point and failed, it simply means the target doesn't have
// a full name set in the target.make table. We need this for accessing it's makefile parameters
// later, so we'll need to go add that now.
println!("target.make entry for \"{}\" does not exist", name);
ret = false;
}
}
}
Err(e) =>
{
println!("{:?}", e);
return Err(FailedToLoadMasterMakeManifest)
}
}
if !ret
{
return Ok(ret)
}
let target_table = master_tm.get_table("target.manifest");
match target_table
{
Ok(v) =>
{
match v.get(name)
{
Some(v) =>
{
println!("target.manifest entry for \"{}\" exists!", v);
}
None =>
{
ret = false;
}
}
}
Err(e) =>
{
println!("{:?}", e);
return Err(FailedToLoadMasterTargetManifest)
}
}
Ok(ret)
}
/// Igloo Manifest -- Responsible for all lookups in manifest files
pub fn get_master_make_manifest(man: &mut Config) -> IglooErrType
{
let mut ret: IglooErrType = ErrNone;
match man.merge(
config::File::with_name(
IglooEnvInfo::get_env_info().esfd.join("manifest/make-manifest.toml")
.to_str()
.unwrap()))
{
Ok(_v) => (),
Err(e) =>
{
println!("Error: {:?}", e);
ret = FailedToLoadMasterMakeManifest;
}
}
ret
}
pub fn get_master_target_manifest(man: &mut Config) -> IglooErrType
{
let mut ret: IglooErrType = ErrNone;
match man.merge(
config::File::with_name(
IglooEnvInfo::get_env_info().esfd.join("manifest/target-manifest.toml")
.to_str()
.unwrap()))
{
Ok(_v) => (),
Err(e) =>
{
println!("Error: {:?}", e);
ret = FailedToLoadMasterTargetManifest;
}
}
ret
}
}
Loading…
Cancel
Save