Browse Source

Merge branch 'master' of github.com:synrc/mad

Namdak Tonpa 6 years ago
parent
commit
7b11a50eec

+ 1 - 0
.gitignore

@@ -5,3 +5,4 @@ logs
 .mad.plt
 .mad.plt
 deps
 deps
 .DS_Store
 .DS_Store
+.applist

+ 2 - 7
.travis.yml

@@ -1,9 +1,4 @@
 language: erlang
 language: erlang
 otp_release:
 otp_release:
-  - 18.0
-  - R16B02
-  - R16B01
-notifications:
-  email: false
-  irc: "chat.freenode.net#n2o"
-script: "make"
+  - 19.3
+script: "curl -fsSL https://raw.github.com/synrc/mad/master/mad > mad && chmod +x mad && ./mad dep com"

+ 1 - 0
CNAME

@@ -0,0 +1 @@
+mad.n2o.space

+ 1 - 1
LICENSE

@@ -1,4 +1,4 @@
-Copyright (c) 2013—2015 Maxim Sokhatsky, Synrc Research Center
+Copyright (c) 2013—2018 Maxim Sokhatsky, Synrc Research Center
 
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 of this software and associated documentation files (the "Software"), to deal

+ 6 - 4
README.md

@@ -1,7 +1,9 @@
-MAD
-===
+MAD: Manage Dependencies
+========================
 
 
-A simple rebar-compatible dependency manager and developer tool with plugins.
+[![Build Status](https://travis-ci.org/synrc/mad.svg?branch=master)](https://travis-ci.org/synrc/mad)
+
+A simple rebar-compatible dependency manager and developer tool with plugins for Windows, Linux and Mac.
 
 
 ![MAD](http://synrc.com/images/mad.png)
 ![MAD](http://synrc.com/images/mad.png)
 
 
@@ -148,7 +150,7 @@ Eshell V6.3  (abort with ^G)
  {kernel,"ERTS  CXC 138 10","3.0.3"}]
  {kernel,"ERTS  CXC 138 10","3.0.3"}]
 ```
 ```
 
 
-See details in [http://maxim.livejournal.com/458016.html](http://maxim.livejournal.com/458016.html) 
+See details in [http://maxim.livejournal.com/458016.html](https://github.com/5HT/maxim.livejournal.com/blob/master/articles/2015/2015-05-05%20LING%20Bootstrap.txt) 
 
 
 Building OTP Release
 Building OTP Release
 --------------------
 --------------------

+ 14 - 0
brew.txt

@@ -0,0 +1,14 @@
+class Mad < Formula
+  desc "Erlang Containers"
+  homepage "http://synrc.com/apps/mad/"
+  url "https://github.com/synrc/mad/archive/1.9.tar.gz"
+  version "1.9"
+  sha256 "a1a19214497d416fc1c55cb89937cf881ced41e4ed8ca95cd35e6e7018091869"
+  bottle :unneeded
+  def install
+    bin.install "mad"
+  end
+  test do
+    assert_equal 'MAD Container Tool', pipe_output(bin/"mad")
+  end
+end

+ 1 - 1
include/mad.hrl

@@ -1 +1 @@
--define(VERSION,"f4aae7").
+-define(VERSION,"c3523f").

+ 190 - 0
index.html

@@ -0,0 +1,190 @@
+<!DOCTYPE html>
+<html >
+<head>
+
+  <link rel=stylesheet type="text/css" href="https://synrc.com/synrc.css?v=1">
+  <meta name="Author" content="5HT">
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+  <meta property="og:image" content="images/s_64.png"/>
+  <meta http-equiv="X-UA-Compatible" content="IE=IE10,chrome=1" />
+  <title>MAD</title>
+</head>
+<body >
+<!--HEVEA command line is: hevea index.tex -o index.htm -->
+<!--CUT STYLE article--><!--HTMLHEAD-->
+
+<div class="nonselectedwrapper white" style="padding: 10px 0px 10px 0px;margin: 0px 0px 10px 0px;">
+    <a href="//synrc.com/">
+    <img style="float:left; margin-left: 55px; margin-top: 5px; margin-bottom:-5px;" src="http://synrc.com/images/synrc.png" border="0"></a>
+
+    <form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top" style="display:none;margin-top:39px;">
+      <input type="hidden" name="cmd" value="_s-xclick">
+      <input type="hidden" name="hosted_button_id" value="P8WQHAQK5HWWW">
+      <input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif" border="0" name="submit" style="width:74px;margin-top:0px;">
+     </form>
+
+    <div align=right style="float:right;width:700px;height: auto; margin: 20px 50px 0px 0px;">
+          <script type="text/javascript">
+
+        var args = (window.location).toString().split('/');
+        var page_name = args[args.length-1];
+        var menu = {'https://synrc.com/index.htm':    'Home',
+                    'https://synrc.com/research.htm': 'Showcase',
+                    'https://synrc.com/apps/':   'Apps',
+                    'https://synrc.com/feedback.htm': 'Contacts', };
+
+        Object.keys(menu).forEach(function (key) {
+            if (page_name == key) { document.write('<div class="menu" style="font-weight: bold;">'+menu[key]+'</div>'); }
+            else { document.write('<a class="menu" href="'+key+'">'+menu[key]+'</a>'); }
+        });
+
+        </script>
+    </div>
+</div>
+
+<hr size="1">
+
+<!--ENDHTML-->
+<!--CUT DEF section 1 --><div class="nonselectedwrapper">
+<div class="article">
+<div class="toc">
+<!--TOC section id="sec1" TOC-->
+<h2 id="sec1" class="section">TOC</h2><!--SEC END -->
+<!--TOC paragraph id="sec2" -->
+<!--SEC END --><p>
+<a href="https://synrc.com/apps/mad/doc/web">Overview</a> <br>
+
+<a href="https://synrc.com/apps/mad/doc/web/setup.htm">1. Setup</a> <br>
+
+<a href="https://synrc.com/apps/mad/doc/web/deps.htm">2. Deps</a> <br>
+
+<a href="https://synrc.com/apps/mad/doc/web/config.htm">3. Configuration</a> <br>
+
+<a href="https://synrc.com/apps/mad/doc/web/commands.htm">4. Commands</a> <br>
+
+<a href="https://synrc.com/apps/mad/doc/web/bundles.htm">5. Bundles</a> <br>
+
+<a href="https://synrc.com/apps/mad/doc/book.pdf">Download PDF</a> <br>
+
+</p></div>
+
+<div class="articlecol">
+
+<!--TOC section id="sec3" MAD: Erlang Containers-->
+<h2 id="sec3" class="section">MAD: Erlang Containers</h2><!--SEC END -->
+<!--TOC subsection id="sec4" Purpose-->
+<h3 id="sec4" class="subsection">Purpose</h3><!--SEC END --><p>
+We were trying to make something minimalistic that fits out <a href="https://github.com/synrc">application stack</a>.
+The main idea of mad is to provide clean and simple rebar-like fast dependency manager that
+is able to build several types of packages and provides interface of containered deployments
+to virtualiezed environments.</p>
+<!--TOC subsection id="sec5" Several Types of Packaging-->
+<h3 id="sec5" class="subsection">Several Types of Packaging</h3><!--SEC END --><p>
+The key feature of mad is ability to create single-file bundled web sites.
+This target escript is ready to run on Windows, Linux and Mac.</p>
+<!--TOC subsection id="sec6" Deployment Options-->
+<h3 id="sec6" class="subsection">Deployment Options</h3><!--SEC END --><p>
+As a deploy tool mad is also supposed to launch, start, stop and manage containers, locally or remote.
+You can make containers from different type of packages, like making runc container with beam release.</p>
+<!--TOC subsection id="sec7" OTP Compliant-->
+<h3 id="sec7" class="subsection">OTP Compliant</h3><!--SEC END --><p>
+Mad supports ERTS boot files generation with systools and erlang application format used by OTP.
+This is the main format of application repository. Also boot files are suported on both LING and BEAM.</p>
+<!--TOC subsection id="sec8" Tiny Size-->
+<h3 id="sec8" class="subsection">Tiny Size</h3><!--SEC END --><p>
+And the good part:</p><div class="lstlisting">                      Sources        Binary
+    mad               967 LOC        52 KB
+    rebar             7717 LOC       181 KB</div>
+<!--TOC subsection id="sec9" History-->
+<h3 id="sec9" class="subsection">History</h3><!--SEC END --><p>We came to conclusion that no matter how perfect your libraries are,
+the comfort and ease come mostly from developing tools.
+Everything got started when <a href="https://github.com/proger">Vladimir Kirillov</a> decided to
+replace Rusty’s sync beam reloader. As you know sync uses
+filesystem polling which is neither energy-efficient nor elegant. Also
+sync is only able to recompile separate modules while
+common use-case in N2O is to recompile DTL templates
+and LESS/SCSS stylesheets. That is why we need to recompile
+the whole project. That’s the story how <a href="https://github.com/synrc/active">active</a> emerged.
+Under the hood active is a client subscriber
+of <a href="https://github.com/synrc/fs">fs</a> library, native filesystem listener for Linux, Windows and Mac.</p><p>De-facto standard in Erlang world is rebar.
+We love rebar interface despite its implementation.
+First we plugged rebar into active and then decided to drop its support,
+it was slow, especially in cold recompilation.
+It was designed to be a stand-alone tool, so it has some
+glitches while using as embedded library.
+Later we switched to Makefile-based build tool <a href="https://github.com/synrc/otp.mk">otp.mk</a>.</p><p>The idea to build rebar replacement was up in the air for a long time.
+The best minimal approach was picked up by <a href="https://github.com/s1n4">Sina Samavati</a>,
+who implemented the first prototype called ’mad’. Initially mad
+was able to compile DTL templates, YECC files, escript (like
+bundled in gproc), also it had support for caching with side-effects.
+In a month I forked mad and took over the development under the same name.</p><div class="center">Listing 1: Example of building N2O sample</div><p><br>
+</p><div class="lstlisting">                                   Cold       Hot
+    rebar get-deps compile         53.156s    4.714s
+    mad deps compile               54.097s    0.899s</div><div class="center">Listing 2: Example of building Cowboy</div><p><br>
+</p><div class="lstlisting">                                   Hot
+    make (erlang.mk)               2.588s
+    mad compile                    2.521s</div><p>
+
+<br><br>
+<h2><a name="testimonials"><b>About MAD</b></a></h2><blockquote>At the beginning, Mad was supposed to be only a Rebar-compatible dependency manager, after a while,
+I realized compiling applications as fast as possible with it could be a fascinating work as well.
+<div align=right>Sina Samavati,
+<a href="https://github.com/s1n4">Original MAD Author</a></div></blockquote>
+
+
+
+    <!--div id="disqus_thread"></div>
+    <script type="text/javascript">
+        var disqus_shortname = 'synrc'; // required: replace example with your forum shortname
+        (function() {
+            var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
+            dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
+            (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
+        })();
+    </script>
+    <noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
+    <a href="https://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a-->
+
+
+</p></div>
+</div>
+</div><div class="clear"> </div><!--CUT END -->
+<!--HTMLFOOT-->
+
+<div class="nonselectedwrapper">
+<div class="verywidecol">
+
+    <div style="width:100%;height:300px;float:left;font-size:16pt;" align=center>
+    	<hr size=1>
+    	<br><br><br>
+        <a href="//synrc.com/news/index.htm">Events</a> |
+    	<a href="//synrc.com/privacy.htm">Privacy Policy</a> |
+        <a href="//synrc.com/feedback.htm">Feedback</a> |
+        <a href="//synrc.com/brandbook.htm">Brandbook</a><br>
+    	Copyright &copy; 2005&ndash;2016 <a href="//synrc.com/index.htm"> Synrc Research Center s.r.o.</a>
+    </div>
+
+</div>
+</div>
+
+
+<div class="clear"></div>
+
+<script type="text/javascript">
+
+  var _gaq = _gaq || [];
+    _gaq.push(['_setAccount', 'UA-29227518-1']);
+      _gaq.push(['_trackPageview']);
+      
+        (function() {
+            var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
+                ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'https://www') + '.google-analytics.com/ga.js';
+                    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
+                      })();
+                      
+                      </script>
+
+<script type="text/javascript" src="https://synrc.com/hi.js"></script>
+<!--ENDHTML-->
+</body>
+</html>

BIN
mad


+ 8 - 0
make.bat

@@ -0,0 +1,8 @@
+@echo off
+Setlocal EnableDelayedExpansion
+FOR /F "delims==" %%I IN ('git rev-parse HEAD ^| head -c 6') DO (
+     < nul set /p str="-define(VERSION, "%%I%")." > include/mad.hrl
+)
+@echo on
+escript.exe mad cle dep com bun mad
+pause

+ 1 - 1
mix.exs

@@ -3,7 +3,7 @@ defmodule MAD.Mixfile do
 
 
   def project do
   def project do
     [app: :mad,
     [app: :mad,
-     version: "2.3.0",
+     version: "4.10.0",
      description: "Small and fast rebar replacement",
      description: "Small and fast rebar replacement",
      package: package]
      package: package]
   end
   end

+ 2 - 1
rebar.config

@@ -1,3 +1,4 @@
 {deps_dir,"deps"}.
 {deps_dir,"deps"}.
+{erl_opts, [nowarn_export_all]}.
 {deps, [%{ling, ".*", {git, "git://github.com/cloudozer/ling", {tag, "master"}}},
 {deps, [%{ling, ".*", {git, "git://github.com/cloudozer/ling", {tag, "master"}}},
-        {sh, ".*",   {git, "git://github.com/synrc/sh",       {tag, "master"}}}]}.
+        {sh, ".*",   {git, "git://github.com/synrc/sh", []}}]}.

+ 33 - 33
src/compile/mad_compile.erl

@@ -22,7 +22,7 @@ deps(Cwd, Conf, ConfigFile, [H|T]) ->
          true  -> {error,Name};
          true  -> {error,Name};
          false -> deps(Cwd, Conf, ConfigFile, T) end.
          false -> deps(Cwd, Conf, ConfigFile, T) end.
 
 
-bool({ok,_}) -> false;
+bool({ok,_})    -> false;
 bool({error,_}) -> true.
 bool({error,_}) -> true.
 
 
 dep(Cwd, _Conf, ConfigFile, Name) ->
 dep(Cwd, _Conf, ConfigFile, Name) ->
@@ -31,57 +31,57 @@ dep(Cwd, _Conf, ConfigFile, Name) ->
     DepPath = filename:join([Cwd, DepsDir, Name]),
     DepPath = filename:join([Cwd, DepsDir, Name]),
     mad:info("==> ~p~n",[Name]),
     mad:info("==> ~p~n",[Name]),
 
 
-    DepConfigFile = filename:join(DepPath, ConfigFile),
-    Conf = mad_utils:consult(DepConfigFile),
-    Conf1 = mad_script:script(DepConfigFile, Conf, Name),
-    Deps = mad_utils:get_value(deps, Conf1, []),
-    DepsRes = bool(deps(Cwd, Conf, ConfigFile, Deps)),
-
-    SrcDir = filename:join([mad_utils:src(DepPath)]),
-    AllFiles = files(SrcDir,".yrl") ++ 
-               files(SrcDir,".xrl") ++ 
-               files(SrcDir,".erl") ++ % comment this to build with erlc/1
-               files(SrcDir,".app.src"),
-    Files = case mad_utils:get_value(erl_first_files, Conf1, []) of
-              []         -> AllFiles;
-              FirstFiles ->
-                FirstFiles1 = lists:map(fun (F) -> filename:join(SrcDir, F ++ ".erl") end, FirstFiles),
-                FirstFiles1 ++ lists:filter(fun (F) -> lists:member(F, FirstFiles) == false end, AllFiles)
-            end,
+    DepConfig = filename:join(DepPath, ConfigFile),
+    Conf      = mad_utils:consult(DepConfig),
+    Conf1     = mad_script:script(DepConfig, Conf, Name),
+    Deps      = mad_utils:get_value(deps, Conf1, []),
+    DepsRes   = bool(deps(Cwd, Conf, ConfigFile, Deps)),
+    SrcDir    = filename:join([mad_utils:src(DepPath)]),
+    PrivDir   = filename:join([mad_utils:priv(DepPath)]),
+    PrivFiles = case application:get_env(mad,cubical,[]) of [] -> []; _ -> files(PrivDir,".ctt") end,
+
+    AllFiles  = files(SrcDir,".yrl") ++
+                files(SrcDir,".xrl") ++
+                files(SrcDir,".erl"),
+
+    AppSrcFiles = files(SrcDir,".app.src"),
+    FirstFiles = [ filename:join([SrcDir,Y]) || Y <- mad_utils:get_value(erl_first_files, Conf1, []) ],
+    Files = lists:filter(fun (F) -> lists:member(F, FirstFiles) == false end, AllFiles),
 
 
     case Files of
     case Files of
         [] -> {ok,Name};
         [] -> {ok,Name};
         Files ->
         Files ->
-            IncDir = mad_utils:include(DepPath),
-            EbinDir = mad_utils:ebin(DepPath),
-            LibDirs = mad_utils:get_value(lib_dirs, Conf, []),
+            IncDir   = mad_utils:include(DepPath),
+            EbinDir  = mad_utils:ebin(DepPath),
+            LibDirs  = mad_utils:get_value(lib_dirs, Conf, []),
             Includes = lists:flatten([
             Includes = lists:flatten([
-                [{i,filename:join([DepPath,L,D,include])} || D<-mad_utils:raw_deps(Deps) ] % for -include
-             ++ [{i,filename:join([DepPath,L])}] || L <- LibDirs ]), % for -include_lib
-            %mad:info("DepPath ~p~n Includes: ~p~nLibDirs: ~p~n",[DepPath,Includes,LibDirs]),
+                       [{i,filename:join([DepPath,L,D,include])} || D <- mad_utils:raw_deps(Deps) ]
+                    ++ [{i,filename:join([DepPath,L])}] || L <- LibDirs ]),
 
 
-            % create EbinDir and add it to code path
             file:make_dir(EbinDir),
             file:make_dir(EbinDir),
             code:replace_path(Name,EbinDir),
             code:replace_path(Name,EbinDir),
+            code:add_path(EbinDir),
 
 
-            Opts = mad_utils:get_value(erl_opts, Conf1, []),
-            FilesStatus = compile_files(Files,IncDir, EbinDir, Opts,Includes),
-            DTLStatus = mad_dtl:compile(DepPath,Conf1),
-            PortStatus = lists:any(fun(X)->X end,mad_port:compile(DepPath,Conf1)),
+            PortStatus  = lists:any(fun(X)->X end,mad_port:compile(DepPath,Conf1)),
+            Opts        = mad_utils:get_value(erl_opts, Conf1, []),
+            DTLStatus   = mad_dtl:compile(DepPath,Conf1),
+            FilesStatus = compile_files(FirstFiles++lists:sort(Files++PrivFiles)++AppSrcFiles,
+                                        IncDir, EbinDir, Opts,Includes),
 
 
             put(Name, compiled),
             put(Name, compiled),
-            case DepsRes orelse FilesStatus orelse DTLStatus orelse PortStatus of
-                 true -> {error,Name};
+            case (DepsRes orelse FilesStatus orelse DTLStatus orelse PortStatus) of
+                 true  -> {error,Name};
                  false -> {ok,Name} end end.
                  false -> {ok,Name} end end.
 
 
 compile_files([],_,_,_,_) -> false;
 compile_files([],_,_,_,_) -> false;
 compile_files([File|Files],Inc,Bin,Opt,Deps) ->
 compile_files([File|Files],Inc,Bin,Opt,Deps) ->
     case (module(filetype(File))):compile(File,Inc,Bin,Opt,Deps) of
     case (module(filetype(File))):compile(File,Inc,Bin,Opt,Deps) of
-         true -> true;
+         true -> io:format("Broken Compilation in ~p~n",[File]), true;
          false -> compile_files(Files,Inc,Bin,Opt,Deps);
          false -> compile_files(Files,Inc,Bin,Opt,Deps);
-         X -> mad:info("Compilation Error: ~p~n",[{X,File}]), true end.
+         X -> mad:info("Unknown Error: ~p~n",[{X,File}]), true end.
 
 
 module("erl")      -> mad_erl;
 module("erl")      -> mad_erl;
+module("ctt")      -> mad_cubical;
 module("erl.src")  -> mad_utils;
 module("erl.src")  -> mad_utils;
 module("yrl")      -> mad_yecc;
 module("yrl")      -> mad_yecc;
 module("xrl")      -> mad_leex;
 module("xrl")      -> mad_leex;

+ 11 - 0
src/compile/mad_cubical.erl

@@ -0,0 +1,11 @@
+-module(mad_cubical).
+-copyright('Maxim Sokhatsky').
+-compile(export_all).
+
+compile(File,_Inc,_Bin,_Opt,_Deps) ->
+    {_,Res,Msg} = sh:run(sh:executable("cubical"), ["-b", File], binary, "."),
+    case Res of
+         1 -> true;
+         0 -> case binary:match(Msg,[<<"File loaded.">>]) of
+                   nomatch -> io:format("Error: ~p~n",[Msg]), true;
+                   _ -> io:format("OK: ~p.~n",[filename:basename(File)]), false end end.

+ 7 - 2
src/compile/mad_erl.erl

@@ -1,17 +1,22 @@
 -module(mad_erl).
 -module(mad_erl).
 -copyright('Sina Samavati').
 -copyright('Sina Samavati').
 -compile(export_all).
 -compile(export_all).
--define(COMPILE_OPTS(Inc, Ebin, Opts, Deps), [return_errors, return_warnings, debug_info, {i, [Inc]}, {outdir, Ebin}] ++ Opts++Deps).
+-define(COMPILE_OPTS(Inc, Ebin, Opts, Deps),
+    [return_errors, return_warnings, %debug_info,
+    {i, [Inc]}, {outdir, Ebin}] ++ Opts ++ Deps).
 
 
 erl_to_beam(Bin, F) -> filename:join(Bin, filename:basename(F, ".erl") ++ ".beam").
 erl_to_beam(Bin, F) -> filename:join(Bin, filename:basename(F, ".erl") ++ ".beam").
 
 
+filter(I) -> [ X || X <- I, X /= warnings_as_errors, X /= warn_export_all, X /=warn_unused_import] .
+
 compile(File,Inc,Bin,Opt,Deps) ->
 compile(File,Inc,Bin,Opt,Deps) ->
     BeamFile = erl_to_beam(Bin, File),
     BeamFile = erl_to_beam(Bin, File),
     Compiled = mad_compile:is_compiled(BeamFile, File),
     Compiled = mad_compile:is_compiled(BeamFile, File),
     if  Compiled =:= false ->
     if  Compiled =:= false ->
         Opts1 = ?COMPILE_OPTS(Inc, Bin, Opt, Deps),
         Opts1 = ?COMPILE_OPTS(Inc, Bin, Opt, Deps),
+        NewCompile = compile:file(File, filter(Opts1)),
         mad:info("Compiling ~s~n", [File -- mad_utils:cwd()]),
         mad:info("Compiling ~s~n", [File -- mad_utils:cwd()]),
-        ret(compile:file(File, Opts1));
+        ret(NewCompile);
     true -> false end.
     true -> false end.
 
 
 ret(error) -> true;
 ret(error) -> true;

+ 8 - 8
src/compile/mad_port.erl

@@ -54,11 +54,11 @@ compile_port(Dir,Specs0,Config) ->
                              Cmd = expand(System,CmdLD,[{"CXXFLAGS",""},{"LDFLAGS",""},{"CFLAGS",""}]),
                              Cmd = expand(System,CmdLD,[{"CXXFLAGS",""},{"LDFLAGS",""},{"CFLAGS",""}]),
                              mad:info("cc ~s~n",[Cmd]),
                              mad:info("cc ~s~n",[Cmd]),
                              {_,Status,Report} = sh:run("cc",string:tokens(Cmd," "),binary,Dir,Env),
                              {_,Status,Report} = sh:run("cc",string:tokens(Cmd," "),binary,Dir,Env),
-                             case Status of 
+                             case Status of
                               0 -> false;
                               0 -> false;
                               _ -> mad:info("Port Compilation Error:~n" ++ io_lib:format("~ts",[Report]),[]),
                               _ -> mad:info("Port Compilation Error:~n" ++ io_lib:format("~ts",[Report]),[]),
-                                   {error, Report},true
-                             end                      
+                                   true
+                             end
                   end;
                   end;
             Errors -> mad:info("Port Compilation Error:~p~n",[Errors]),
             Errors -> mad:info("Port Compilation Error:~p~n",[Errors]),
                       true
                       true
@@ -69,7 +69,7 @@ compile_port(Dir,Specs0,Config) ->
 to_obj(F) -> filename:rootname(F) ++ ".o".
 to_obj(F) -> filename:rootname(F) ++ ".o".
 
 
 %%FIXME
 %%FIXME
-expand(System, String, []) -> String;
+expand(_System, String, []) -> String;
 expand(System, String, [{K,V}|Env]) ->
 expand(System, String, [{K,V}|Env]) ->
   New = re:replace(String, io_lib:format("\\${?(~s)}?",[K]), V, [global, {return, list}]),
   New = re:replace(String, io_lib:format("\\${?(~s)}?",[K]), V, [global, {return, list}]),
   expand(System,New,Env);
   expand(System,New,Env);
@@ -81,7 +81,7 @@ expand(System, String, [{Sys,K,V}|Env]) ->
   end.
   end.
 
 
 extension(F)       -> filename:extension(F).
 extension(F)       -> filename:extension(F).
-is_compiled(O,F)   -> filelib:is_file(O) andalso (mad_utils:last_modified(O) >= mad_utils:last_modified(F)). 
+is_compiled(O,F)   -> filelib:is_file(O) andalso (mad_utils:last_modified(O) >= mad_utils:last_modified(F)).
 join(A,B)          -> filename:join(A,B).
 join(A,B)          -> filename:join(A,B).
 concat(X)          -> lists:concat(X).
 concat(X)          -> lists:concat(X).
 system(Sys,System) -> Sys == System orelse match(Sys,System).
 system(Sys,System) -> Sys == System orelse match(Sys,System).
@@ -91,7 +91,7 @@ erts_dir(include)  -> " -I"++join(erts_dir(), "include").
 ei_dir()           -> case code:lib_dir(erl_interface) of {error,bad_name} -> ""; E -> E end.
 ei_dir()           -> case code:lib_dir(erl_interface) of {error,bad_name} -> ""; E -> E end.
 ei_dir(include)    -> case ei_dir() of "" -> ""; E -> " -I"++join(E,"include") end;
 ei_dir(include)    -> case ei_dir() of "" -> ""; E -> " -I"++join(E,"include") end;
 ei_dir(lib)        -> case ei_dir() of "" -> ""; E -> " -L"++join(E,"lib") end.
 ei_dir(lib)        -> case ei_dir() of "" -> ""; E -> " -L"++join(E,"lib") end.
-link_lang(Files)   -> lists:foldl(fun(F,cxx) -> cxx;
+link_lang(Files)   -> lists:foldl(fun(_,cxx) -> cxx;
                                      (F,cc) -> case compiler(extension(F)) == "$CXX" of 
                                      (F,cc) -> case compiler(extension(F)) == "$CXX" of 
                                                 true -> cxx;false -> cc end
                                                 true -> cxx;false -> cc end
                                   end,cc,Files).
                                   end,cc,Files).
@@ -120,8 +120,8 @@ tpl_ld(exe,cxx) -> " $PORT_IN_FILES $LDFLAGS $EXE_LDFLAGS -o $PORT_OUT_FILE".
 erl_ldflag() -> concat([ei_dir(include), erts_dir(include), " "]).
 erl_ldflag() -> concat([ei_dir(include), erts_dir(include), " "]).
 
 
 default_env() ->
 default_env() ->
-    Arch = os:getenv("REBAR_TARGET_ARCH"),
-    Vsn = os:getenv("REBAR_TARGET_ARCH_VSN"),
+    _Arch = os:getenv("REBAR_TARGET_ARCH"),
+    _Vsn = os:getenv("REBAR_TARGET_ARCH_VSN"),
     [
     [
      {"darwin", "DRV_LDFLAGS", "-bundle -flat_namespace -undefined suppress " ++ei_dir(lib) ++" -lerl_interface -lei"},
      {"darwin", "DRV_LDFLAGS", "-bundle -flat_namespace -undefined suppress " ++ei_dir(lib) ++" -lerl_interface -lei"},
      {"DRV_CFLAGS" , "-g -Wall -fPIC -MMD " ++ erl_ldflag()},
      {"DRV_CFLAGS" , "-g -Wall -fPIC -MMD " ++ erl_ldflag()},

+ 1 - 1
src/compile/mad_yecc.erl

@@ -8,6 +8,6 @@ compile(File,Inc,Bin,Opt,Deps) ->
     ErlFile = yrl_to_erl(File),
     ErlFile = yrl_to_erl(File),
     Compiled = mad_compile:is_compiled(ErlFile,File),
     Compiled = mad_compile:is_compiled(ErlFile,File),
     if Compiled == false ->
     if Compiled == false ->
-        yecc:file(File),
+        yecc:file(File,[{verbose,true}]),
         mad_erl:compile(ErlFile,Inc,Bin,Opt,Deps); true -> false end.
         mad_erl:compile(ErlFile,Inc,Bin,Opt,Deps); true -> false end.
 
 

+ 2 - 2
src/mad.app.src

@@ -1,6 +1,6 @@
 {application, mad,
 {application, mad,
- [{description, "MAD Erlang/OTP Containers"},
-  {vsn, "2.3"},
+ [{description, "MAD Manage Dependencies"},
+  {vsn, "4.10"},
   {registered, []},
   {registered, []},
   {applications, [kernel,stdlib,inets]},
   {applications, [kernel,stdlib,inets]},
   {env, []}]}.
   {env, []}]}.

+ 24 - 27
src/mad.erl

@@ -12,21 +12,18 @@ main(Params)      ->
                                    (X,{C,R}) -> {[X|C],R} end,
                                    (X,{C,R}) -> {[X|C],R} end,
                                {[],[]}, lists:map(fun atomize/1, Params)),
                                {[],[]}, lists:map(fun atomize/1, Params)),
 
 
-    return(
+    halt(return(
         lists:any(fun({error,_}) -> true; (_) -> false end,
         lists:any(fun({error,_}) -> true; (_) -> false end,
-            lists:flatten(
-                lists:foldl(fun({Fun,Arg},[]) ->
-                    mad_hooks:run_hooks(pre, Fun),
-                    Errors = errors((profile()):Fun(Arg)),
-                    mad_hooks:run_hooks(post, Fun),
-                    Errors;
-                ({_,_},Err) ->
-                    errors(Invalid), {return,Err}
-                end,
-                [], Valid)
-           )
-        )
-    ).
+        lists:flatten(
+        lists:foldl(
+        fun ({Fun,Arg},[]) ->
+                mad_hooks:run_hooks(pre, Fun),
+                Errors = errors((profile()):Fun(Arg)),
+                mad_hooks:run_hooks(post, Fun),
+                Errors;
+            ({_,_},Err) ->
+                errors(Invalid), {return,Err}
+        end, [], Valid))))).
 
 
 atomize("static") -> 'static';
 atomize("static") -> 'static';
 atomize("deploy") -> 'deploy';
 atomize("deploy") -> 'deploy';
@@ -35,6 +32,7 @@ atomize("dep")    -> 'deps';
 atomize("deps")   -> 'deps';
 atomize("deps")   -> 'deps';
 atomize("cle"++_) -> 'clean';
 atomize("cle"++_) -> 'clean';
 atomize("com"++_) -> 'compile';
 atomize("com"++_) -> 'compile';
+atomize("eunit")  -> 'eunit';
 atomize("up")     -> 'up';
 atomize("up")     -> 'up';
 atomize("rel"++_) -> 'release';
 atomize("rel"++_) -> 'release';
 atomize("bun"++_) -> 'release';
 atomize("bun"++_) -> 'release';
@@ -44,20 +42,19 @@ atomize("att"++_) -> 'attach';
 atomize("sh")     -> 'sh';
 atomize("sh")     -> 'sh';
 atomize("rep"++_) -> 'sh';
 atomize("rep"++_) -> 'sh';
 atomize("pla"++_) -> 'resolve';
 atomize("pla"++_) -> 'resolve';
+atomize("str"++_) -> 'strip';
 atomize(Else)     -> Else.
 atomize(Else)     -> Else.
 
 
 profile()         -> application:get_env(mad,profile,mad_local).
 profile()         -> application:get_env(mad,profile,mad_local).
 
 
-errors([])        -> [];
-errors(false)     -> [];
-errors(true)      -> {error,unknown};
-errors({error,L}) -> info("ERROR: ~tp~n",[L]), [{error,L}];
-errors({ok,_})    -> info("OK~n",[]), [];
-errors(X)         -> info("RETURN: ~tp~n",[X]), [{error,X}].
+errors([])            -> [];
+errors(false)         -> [];
+errors(true)          -> {error,unknown};
+errors({error,Where}) -> info("ERROR~n"), [{error,Where}];
+errors({ok,_})        -> info("OK~n",[]), [].
 
 
 return(true)      -> 1;
 return(true)      -> 1;
-return(false)     -> 0;
-return(X)         -> X.
+return(false)     -> 0.
 
 
 host()            -> try {ok,H} = inet:gethostname(), H catch _:_ -> <<>> end.
 host()            -> try {ok,H} = inet:gethostname(), H catch _:_ -> <<>> end.
 
 
@@ -68,9 +65,9 @@ help(Reason,D)    -> help(io_lib:format("~s ~p", [Reason, D])).
 help(_Msg)        -> help().
 help(_Msg)        -> help().
 help()            -> info("MAD Container Tool version ~s~n",[?VERSION]),
 help()            -> info("MAD Container Tool version ~s~n",[?VERSION]),
                      info("~n"),
                      info("~n"),
-                     info("    invoke = mad params~n"),
-                     info("    params = [] | command [ options  ] params ~n"),
-                     info("   command = app     | deps  | clean | compile | up~n"),
-                     info("           | release [ beam  | ling  | script  | runc | depot ]~n"),
-                     info("           | deploy  | start | stop  | attach  | sh | static [ <watch|min> ] ~n"),
+                     info("    invoke = mad | mad params~n"),
+                     info("    params = command [ options ] params ~n"),
+                     info("   command = app     | deps  | clean | compile | up   | eunit  | strip~n"),
+                     info("           | bundle  [ beam  | ling  | script  | runc | depot  ]~n"),
+                     info("           | deploy  | start | stop  | attach  | sh   | static [ <watch|min> ] ~n"),
                      return(false).
                      return(false).

+ 1 - 1
src/mad_resolve.erl

@@ -47,6 +47,6 @@ system_deps(A) ->
 
 
 main(_) ->
 main(_) ->
     case orderapps() of
     case orderapps() of
-         {ok,Ordered}   -> mad:info("Ordered: ~p~n",[Ordered]),
+         {ok,Ordered}   -> mad:info("Generating .applist ~p~n",[Ordered]),
                            file:write_file(".applist",io_lib:format("~w",[Ordered])), {ok,Ordered};
                            file:write_file(".applist",io_lib:format("~w",[Ordered])), {ok,Ordered};
          {error,Reason} -> {error,Reason} end.
          {error,Reason} -> {error,Reason} end.

+ 7 - 6
src/mad_static.erl

@@ -3,13 +3,13 @@
 -compile(export_all).
 -compile(export_all).
 -define(NODE(Bin), "node_modules/.bin/"++Bin).
 -define(NODE(Bin), "node_modules/.bin/"++Bin).
 
 
-main(Config, ["min"]) ->
+main(_Config, ["min"]) ->
     {ok,[SysConfig]} = file:consult("sys.config"),
     {ok,[SysConfig]} = file:consult("sys.config"),
     N2O     = proplists:get_value(n2o,SysConfig,[]),
     N2O     = proplists:get_value(n2o,SysConfig,[]),
     AppName = proplists:get_value(app,N2O,sample),
     AppName = proplists:get_value(app,N2O,sample),
     Minify  = proplists:get_value(minify,N2O,[]),
     Minify  = proplists:get_value(minify,N2O,[]),
-    Command = lists:concat(["uglifyjs ",string:join(element(2,Minify)," "),
-                                 " -o ",element(1,Minify),"/",AppName,".min.js -p 5 -c -m"]),
+    Command = lists:concat(["uglify -s ",string:join(element(2,Minify),","),
+                                 " -o ",element(1,Minify),"/",AppName,".min.js"]),
     io:format("Minify: ~p~n",[Command]),
     io:format("Minify: ~p~n",[Command]),
     case sh:run(Command) of
     case sh:run(Command) of
          {_,0,_} -> {ok,static};
          {_,0,_} -> {ok,static};
@@ -61,9 +61,10 @@ app(Params) ->
     mad_repl:load(),
     mad_repl:load(),
     Apps = ets:tab2list(filesystem),
     Apps = ets:tab2list(filesystem),
     [ case string:str(File,"priv/web") of
     [ case string:str(File,"priv/web") of
-       1 -> Relative = Name ++ string:substr(File, 9),
+       1 -> Relative = unicode:characters_to_list(Name ++ string:replace(string:substr(File, 9), "sample", Name, all), utf8),
             mad:info("Create File: ~p~n",[Relative]),
             mad:info("Create File: ~p~n",[Relative]),
             filelib:ensure_dir(Relative),
             filelib:ensure_dir(Relative),
-            file:write_file(Relative,Bin);
+            BinNew = string:replace(Bin, "sample", Name, all),
+            file:write_file(Relative, BinNew);
        _ -> skip
        _ -> skip
-       end || {File,Bin} <- Apps ], {ok,Name}.
+       end || {File,Bin} <- Apps, is_list(File) ], {ok,Name}.

+ 7 - 0
src/mad_strip.erl

@@ -0,0 +1,7 @@
+-module(mad_strip).
+-export([main/1]).
+
+main(_) ->
+ Res = beam_lib:strip_files(mad_repl:wildcards(["{apps,deps,lib}/*/ebin/*.beam","ebin/*.beam"])),
+ mad:info("~p~n",[Res]),
+ false.

+ 1 - 0
src/mad_utils.erl

@@ -25,6 +25,7 @@ consult(File) ->
 src(Dir) -> filename:join(Dir, "src").
 src(Dir) -> filename:join(Dir, "src").
 include(Dir) -> filename:join(Dir, "include").
 include(Dir) -> filename:join(Dir, "include").
 ebin(Dir) -> filename:join(Dir, "ebin").
 ebin(Dir) -> filename:join(Dir, "ebin").
+priv(Dir) -> filename:join(Dir, "priv").
 deps(File) -> get_value(deps, consult(File), []).
 deps(File) -> get_value(deps, consult(File), []).
 
 
 get_value(Key, Opts, undefined) -> get_value(Key, Opts, []);
 get_value(Key, Opts, undefined) -> get_value(Key, Opts, []);

+ 7 - 7
src/package/mad_systools.erl

@@ -7,12 +7,12 @@
 scripts(N) ->
 scripts(N) ->
     mad_repl:load(),
     mad_repl:load(),
     {ok,Bin} = mad_repl:load_file("priv/systools/start"),
     {ok,Bin} = mad_repl:load_file("priv/systools/start"),
-    [{"/bin/start",list_to_binary(re:replace(binary_to_list(Bin),"{release}",N,[global,{return,list}]))},
-     {"/bin/attach",element(2,mad_repl:load_file("priv/systools/attach"))},
-     {"/bin/daemon",element(2,mad_repl:load_file("priv/systools/daemon"))},
-     {"/etc/"++N++".boot",N++".boot"},
-     {"/etc/vm.args","vm.args"},
-     {"/etc/sys.config","sys.config"}].
+    [{"bin/start",list_to_binary(re:replace(binary_to_list(Bin),"{release}",N,[global,{return,list}]))},
+     {"bin/attach",element(2,mad_repl:load_file("priv/systools/attach"))},
+     {"bin/daemon",element(2,mad_repl:load_file("priv/systools/daemon"))},
+     {"etc/"++N++".boot",N++".boot"},
+     {"etc/vm.args","vm.args"},
+     {"etc/sys.config","sys.config"}].
 
 
 apps(List) ->
 apps(List) ->
     lists:flatten([[[ {filename:join([lib,
     lists:flatten([[[ {filename:join([lib,
@@ -48,7 +48,7 @@ beam_release(N) ->
     Files = [ {"/bin/" ++ filename:basename(F), F}
     Files = [ {"/bin/" ++ filename:basename(F), F}
         || F <- mad_repl:wildcards([code:root_dir() ++
         || F <- mad_repl:wildcards([code:root_dir() ++
             "/erts-" ++ erlang:system_info(version) ++
             "/erts-" ++ erlang:system_info(version) ++
-            "/bin/{epmd,erlexec,run_erl,to_erl,escript,beam.smp,erl_child_setup}"]) ] ++
+            "/bin/{epmd,erlexec,run_erl,to_erl,escript,beam.smp,erl_child_setup,inet_gethost}"]) ] ++
         apps(Apps) ++ scripts(N),
         apps(Apps) ++ scripts(N),
     erl_tar:create(N ++ ".tgz",Files,[compressed]),
     erl_tar:create(N ++ ".tgz",Files,[compressed]),
     mad:info("~s.boot: ~p~n",[N,Res]),
     mad:info("~s.boot: ~p~n",[N,Res]),

+ 2 - 0
src/profile/mad_local.erl

@@ -14,3 +14,5 @@ deps(Params)      -> mad_git:deps(Params).
 up(Params)        -> mad_git:up(Params).
 up(Params)        -> mad_git:up(Params).
 fetch(Params)     -> mad_git:fetch(Params).
 fetch(Params)     -> mad_git:fetch(Params).
 static(Params)    -> mad_static:main([],Params).
 static(Params)    -> mad_static:main([],Params).
+eunit(Params)     -> mad_eunit:main_test(Params).
+strip(Params)     -> mad_strip:main(Params).

+ 1 - 1
src/profile/mad_vz.erl

@@ -9,7 +9,7 @@ attach(Params)    -> mad_vz:attach(Params).
 stop(Params)      -> mad_vz:stop(Params).
 stop(Params)      -> mad_vz:stop(Params).
 release(Params)   -> mad_release:release(Params).
 release(Params)   -> mad_release:release(Params).
 resolve(Params)   -> mad_resolve:main(Params).
 resolve(Params)   -> mad_resolve:main(Params).
-sh(Params)        -> {error,'N/A'}.
+sh(_Params)       -> {error,'N/A'}.
 deps(Params)      -> mad_synrc:deps(Params).
 deps(Params)      -> mad_synrc:deps(Params).
 up(Params)        -> mad_synrc:up(Params).
 up(Params)        -> mad_synrc:up(Params).
 fetch(Params)     -> mad_synrc:fetch(Params).
 fetch(Params)     -> mad_synrc:fetch(Params).

+ 49 - 26
src/provision/mad_repl.erl

@@ -4,7 +4,10 @@
 
 
 disabled() -> [].
 disabled() -> [].
 system() -> [compiler,syntax_tools,sasl,tools,mnesia,reltool,xmerl,crypto,kernel,stdlib,ssh,eldap,
 system() -> [compiler,syntax_tools,sasl,tools,mnesia,reltool,xmerl,crypto,kernel,stdlib,ssh,eldap,
-             wx,ssl,runtime_tools,public_key,observer,inets,asn1,et,eunit,hipe,os_mon,parsetools,odbc].
+             wx,ssl,runtime_tools,public_key,observer,inets,asn1,et,eunit,hipe,os_mon,parsetools,odbc,snmp].
+
+escript_name() ->
+    try escript:script_name() of N -> N catch _:_ -> [] end.
 
 
 local_app() ->
 local_app() ->
     case filename:basename(filelib:wildcard("ebin/*.app"),".app") of
     case filename:basename(filelib:wildcard("ebin/*.app"),".app") of
@@ -23,48 +26,62 @@ applist() ->
 wildcards(List) -> lists:concat([filelib:wildcard(X)||X<-List]).
 wildcards(List) -> lists:concat([filelib:wildcard(X)||X<-List]).
 
 
 parse_applist(AppList) ->
 parse_applist(AppList) ->
-   Res = string:tokens(string:strip(string:strip(binary_to_list(AppList),right,$]),left,$[),","),
-   [ list_to_atom(R) || R <-Res ]  -- disabled().
+    Res = string:tokens(string:strip(string:strip(binary_to_list(AppList),right,$]),left,$[),","),
+    [ list_to_atom(R) || R <-Res ]  -- disabled().
 
 
-load_config() ->
-   Config = wildcards(["sys.config",lists:concat(["etc/",mad:host(),"/sys.config"])]),
-   _Apps = case Config of
+load_sysconfig() ->
+    Config = wildcards(["sys.config",lists:concat(["etc/",mad:host(),"/sys.config"])]),
+    _Apps = case Config of
         [] -> case mad_repl:load_file("sys.config") of
         [] -> case mad_repl:load_file("sys.config") of
               {error,_} -> [];
               {error,_} -> [];
               {ok,Bin} -> parse(unicode:characters_to_list(Bin)) end;
               {ok,Bin} -> parse(unicode:characters_to_list(Bin)) end;
       File -> case file:consult(hd(File)) of
       File -> case file:consult(hd(File)) of
               {error,_} -> [];
               {error,_} -> [];
-              {ok,[A]} -> A end end.
+              {ok,[A]} -> merge_include(A, []) end end.
+
+application_config(AppConfigs) ->
+    [[application:set_env(App,K,V) || {K,V} <- Cfg] || {App,Cfg} <- AppConfigs].
+
+merge_include([], Acc) -> Acc;
+merge_include([H | Rest], Acc) -> merge_include(Rest, merge_config(H, Acc)).
 
 
-load_config(AppConfigs,[]) ->
-    [ [ application:set_env(App,K,V) || {K,V} <- Cfg] || {App,Cfg} <- AppConfigs],
-    load_includes(AppConfigs).
+merge_config({App, NewConfig} = Add, Acc) ->
+    lists:keystore(App, 1, Acc, case lists:keyfind(App, 1, Acc) of
+        false ->  Add;
+        {App, AppConfigs} -> merge_config(App, AppConfigs, NewConfig)
+    end);
 
 
-load_includes(AppConfigs) ->
-    [ begin Apps = case file:consult(File) of
-                        {error,_} -> [];
-                        {ok,[A]} -> A end,
-             load_config(Apps, []) end || File <- AppConfigs, is_list(File) ].
+merge_config(File, Acc) when is_list(File) ->
+    BFName = filename:basename(File, ".config"),
+    FName = filename:join(filename:dirname(File), BFName ++ ".config"),
+    case file:consult(FName) of
+        {ok,[A]} -> merge_include(A, Acc);
+        _ -> Acc
+    end.
+
+merge_config(App, AppConfigs, []) -> {App, AppConfigs};
+merge_config(App, AppConfigs, [{Key, _} = Tuple | Rest]) ->
+    merge_config(App, lists:keystore(Key, 1, AppConfigs, Tuple), Rest).
 
 
 acc_start(A,Acc) ->
 acc_start(A,Acc) ->
     application:ensure_all_started(A), Acc.
     application:ensure_all_started(A), Acc.
 
 
 % for system application we just start, forgot about env merging
 % for system application we just start, forgot about env merging
 
 
-load(true,A,Acc,Config) ->
-    load_config(Config,[]),
+load(true,A,Acc,_Config) ->
     acc_start(A,Acc);
     acc_start(A,Acc);
 
 
 % for user application we should merge app from ebin and from sys.config
 % for user application we should merge app from ebin and from sys.config
 % and start application using tuple argument in app controller
 % and start application using tuple argument in app controller
 
 
-load(_,A,Acc,Config) ->
-    {application,Name,Map} = load_config(A),
-    NewEnv = merge(Config,Map,Name),
-    acc_start({application,Name,set_value(env,1,Map,{env,NewEnv})},Acc).
+load(X,A,Acc,Config) ->
+    try {application,Name,Map} = load_config(A),
+        NewEnv = merge(Config,Map,Name),
+        acc_start({application,Name,set_value(env,1,Map,{env,NewEnv})},Acc)
+    catch _:_ -> io:format("Application Load Error: ~p",[{X,A,Acc}]) end.
 
 
 merge(Config,Map,Name) ->
 merge(Config,Map,Name) ->
-    lists:foldl(fun({Name,E},Acc2)   ->
+    lists:foldl(fun({Name2,E},Acc2) when Name2 =:= Name ->
     lists:foldl(fun({K,V},Acc1)      -> set_value(K,1,Acc1,{K,V}) end,Acc2,E);
     lists:foldl(fun({K,V},Acc1)      -> set_value(K,1,Acc1,{K,V}) end,Acc2,E);
                           (_,Acc2)   -> Acc2 end, proplists:get_value(env,Map,[]), Config).
                           (_,Acc2)   -> Acc2 end, proplists:get_value(env,Map,[]), Config).
 
 
@@ -73,7 +90,7 @@ load_apps(["applist"],Config,Acc)    -> load_apps([],Config,Acc);
 load_apps(Params,_,_Acc)             -> [ application:ensure_all_started(list_to_atom(A))||A<-Params].
 load_apps(Params,_,_Acc)             -> [ application:ensure_all_started(list_to_atom(A))||A<-Params].
 
 
 set_value(Name,Pos,List,New)         -> add_replace(lists:keyfind(Name,Pos,List),Name,Pos,List,New).
 set_value(Name,Pos,List,New)         -> add_replace(lists:keyfind(Name,Pos,List),Name,Pos,List,New).
-add_replace(false,Name,Pos,List,New) -> [New|List];
+add_replace(false,_N,_P,List,New)    -> [New|List];
 add_replace(_____,Name,Pos,List,New) -> lists:keyreplace(Name,Pos,List,New).
 add_replace(_____,Name,Pos,List,New) -> lists:keyreplace(Name,Pos,List,New).
 
 
 cwd() -> case  file:get_cwd() of {ok, Cwd} -> Cwd; _ -> "." end.
 cwd() -> case  file:get_cwd() of {ok, Cwd} -> Cwd; _ -> "." end.
@@ -84,9 +101,15 @@ sh(Params) ->
               ++ string:join([atom_to_list(X)||X<-mad_repl:system()],",") ++ "}-*/ebin"),
               ++ string:join([atom_to_list(X)||X<-mad_repl:system()],",") ++ "}-*/ebin"),
     UserPath   = wildcards(["{apps,deps}/*/ebin","ebin"]),
     UserPath   = wildcards(["{apps,deps}/*/ebin","ebin"]),
     code:set_path(SystemPath++UserPath),
     code:set_path(SystemPath++UserPath),
-    code:add_path(filename:join([cwd(),filename:basename(escript:script_name())])),
-    load(),
-    Config = load_config(),
+
+    case escript_name() of
+        [] -> ok; % VSCode
+         N -> code:add_path(filename:join([cwd(),filename:basename(N)])),
+              load()
+    end,
+
+    Config = load_sysconfig(),
+    application_config(Config),
     Driver = mad_utils:get_value(shell_driver,_Config,user_drv),
     Driver = mad_utils:get_value(shell_driver,_Config,user_drv),
     repl_intro(Config),
     repl_intro(Config),
     case os:type() of
     case os:type() of

+ 2 - 2
src/provision/mad_run.erl

@@ -16,6 +16,6 @@ attach(_) -> mad:info("to_erl .~n"). % use like $(mad attach)
 
 
 stop(_) -> {ok,[]}.
 stop(_) -> {ok,[]}.
 
 
-clean(_) -> [ file:delete(X) || X <- filelib:wildcard("{apps,deps}/*/ebin/**") ++
-                                     filelib:wildcard("ebin/**")], {ok,[]}.
+clean(_) -> [ file:delete(X) || X <- filelib:wildcard("{apps,deps}/*/ebin/*.beam") ++
+                                     filelib:wildcard("ebin/*.beam")], {ok,[]}.
 
 

+ 5 - 3
src/sources/mad_git.erl

@@ -19,7 +19,8 @@ fetch(Cwd, Config, ConfigFile, [H|T]) ->
             {Cmd, Uri, Co} = case Repo of
             {Cmd, Uri, Co} = case Repo of
                                  V={_, _, _}          -> V;
                                  V={_, _, _}          -> V;
                                  {_Cmd, _Url, _Co, _} -> {_Cmd, _Url, _Co};
                                  {_Cmd, _Url, _Co, _} -> {_Cmd, _Url, _Co};
-                                 {_Cmd, _Url}         -> {_Cmd, _Url, "master"}
+                                 {_Cmd, _Url}         -> {_Cmd, _Url, "master"};
+                                 Url when is_list(Url) -> {git, Url, "master"}
                              end,
                              end,
             Cmd1 = atom_to_list(Cmd),
             Cmd1 = atom_to_list(Cmd),
             Cache = mad_utils:get_value(cache, Config, deps_fetch),
             Cache = mad_utils:get_value(cache, Config, deps_fetch),
@@ -29,7 +30,7 @@ fetch(Cwd, Config, ConfigFile, [H|T]) ->
          {error,E} -> {error,E};
          {error,E} -> {error,E};
          {ok,_} -> fetch(Cwd, Config, ConfigFile, T) end.
          {ok,_} -> fetch(Cwd, Config, ConfigFile, T) end.
 
 
-git_clone(Uri,Fast,TrunkPath,Rev) when Rev == "head" orelse Rev == "HEAD" orelse Rev == "master" ->
+git_clone(Uri,Fast,TrunkPath,Rev) when Rev == "head" orelse Rev == "HEAD" orelse Rev == "master" orelse Rev == [] ->
     {["git clone ",Fast,Uri," ",TrunkPath],Rev};
     {["git clone ",Fast,Uri," ",TrunkPath],Rev};
 git_clone(Uri,_Fast,TrunkPath,Rev) ->
 git_clone(Uri,_Fast,TrunkPath,Rev) ->
     {["git clone ",Uri," ",TrunkPath," && cd ",TrunkPath," && git checkout \"",Rev,"\"" ],Rev}.
     {["git clone ",Uri," ",TrunkPath," && cd ",TrunkPath," && git checkout \"",Rev,"\"" ],Rev}.
@@ -90,10 +91,11 @@ pull(_,[])         -> {ok,[]};
 pull(Config,[F|T]) ->
 pull(Config,[F|T]) ->
     mad:info("==> up: ~p~n", [F]),
     mad:info("==> up: ~p~n", [F]),
     {_,Status,Message} = sh:run(lists:concat(["cd ",F," && git pull && cd -"])),
     {_,Status,Message} = sh:run(lists:concat(["cd ",F," && git pull && cd -"])),
+    %io:format("status: ~p~n",[{Status,Message}]),
     case Status of
     case Status of
          0 -> mad_utils:verbose(Config,Message), pull(Config,T);
          0 -> mad_utils:verbose(Config,Message), pull(Config,T);
          _ -> case binary:match(Message,[<<"You are not currently on a branch">>]) of
          _ -> case binary:match(Message,[<<"You are not currently on a branch">>]) of
-                   nomatch -> mad_utils:verbose(Config,Message), true;
+                   nomatch -> mad_utils:verbose(Config,Message), {error,Message};
                    _ -> pull(Config,T) end end.
                    _ -> pull(Config,T) end end.
 
 
 up(Params) ->
 up(Params) ->

+ 8 - 0
src/test/mad_eunit.erl

@@ -0,0 +1,8 @@
+-module(mad_eunit).
+-compile(export_all).
+
+main_test(_Params) ->
+    case application:get_application() of
+      {ok, App} -> eunit:test([{application, App}]);
+              _ -> eunit:test()
+    end.