Nitrogen Web Framework

Changes On Branch mainstream
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Changes In Branch origin/rebar3 Excluding Merge-Ins

This is equivalent to a diff from babd934386 to 4b882937df

2022-03-23
13:43
merge latest mainstream changes Leaf check-in: 4b882937df user: fran tags: mainstream, origin/rebar3, origin/ws
2021-09-09
18:22
bootstrap nitrogen_core from chiselapp. Add a modified rebar binary which is compatible with fossil repositories. Also set sc and pusher as deps check-in: f4c08fa13c user: fran tags: trunk
2021-05-28
02:52
More progress - rebar3 upgraded, chmod the start script, and improve the rebar.config generation check-in: ce056a3d58 user: gumm@sigma-star.com tags: mainstream, origin/rebar3, origin/ws
2020-12-24
02:01
+x to convert_to_rebar3.sh check-in: acd4db40fa user: gumm@sigma-star.com tags: mainstream, origin/rebar3, origin/ws
2020-12-14
20:58
Update changelog Leaf check-in: babd934386 user: gumm@sigma-star.com tags: mainstream, master, origin/ws
2020-11-29
14:46
update changelog check-in: da3c39cd2a user: gumm@sigma-star.com tags: mainstream, master, origin/ws

Added rebar3.

cannot compute difference between binary files

Deleted rel/copy_erl_interface.escript.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
#!/usr/bin/env escript
%% -*- erlang -*-
%% vim: ts=4 sw=4 et ft=erlang
%%
%% Coyright 2012 - Jesse Gumm
%% MIT License
%%
%% The purpoose of this file is due to a behavior or bug in Erlang's reltool
%% functionality, where the erl_interface directory is not copied using reltool.
%% This is a workaround for that shortcoming particularly for building Yaws
%% with Nitrogen, as Yaws requires erl_interface to compile.
%% 	
%% Much of this file has been straight up copied from rebar, most of it is
%% overkill for what it's doing, and can probably be stripped to its bare bones,
%% especially for whenever that shortcoming gets fixed.
%% 
%% So for now, this serves a simple purpose which will likely be rendered 
%% unnecessary in the future.

-define(CONSOLE(Str,Args), io:format(Str,Args)).
-define(FMT(Str,Args), lists:flatten(io_lib:format(Str,Args))).

main([]) ->
    Path = code:lib_dir(erl_interface),
    To = filename:join([get_cwd(), "nitrogen", "lib", filename:basename(Path)]),

    ?CONSOLE("~s~n",["Copying " ++ Path]),
    cp_r([Path],To),
    ok.


%% Copied from Rebar
cp_r(Sources, Dest) ->
    case os:type() of
        {unix, _} ->
            EscSources = [escape_spaces(Src) || Src <- Sources],
            SourceStr = string:join(EscSources, " "),
            {ok, []} = sh(?FMT("cp -R ~s \"~s\"",
                                           [SourceStr, Dest]),
                                      [{use_stdout, false}, return_on_error]),
            ok;
        {win32, _} ->
            lists:foreach(fun(Src) -> ok = cp_r_win32(Src,Dest) end, Sources),
            ok
    end.


%% Windows stuff	
xcopy_win32(Source,Dest)->
    {ok, R} = sh(
                ?FMT("xcopy \"~s\" \"~s\" /q /y /e 2> nul",
                     [filename:nativename(Source), filename:nativename(Dest)]),
                [{use_stdout, false}, return_on_error]),
    case length(R) > 0 of
        %% when xcopy fails, stdout is empty and and error message is printed
        %% to stderr (which is redirected to nul)
        true -> ok;
        false ->
            {error, lists:flatten(
                      io_lib:format("Failed to xcopy from ~s to ~s~n",
                                    [Source, Dest]))}
    end.

cp_r_win32({true, SourceDir}, {true, DestDir}) ->
    %% from directory to directory
    SourceBase = filename:basename(SourceDir),
    ok = case file:make_dir(filename:join(DestDir, SourceBase)) of
             {error, eexist} -> ok;
             Other -> Other
         end,
    ok = xcopy_win32(SourceDir, filename:join(DestDir, SourceBase));
cp_r_win32({false, Source} = S,{true, DestDir}) ->
    %% from file to directory
    cp_r_win32(S, {false, filename:join(DestDir, filename:basename(Source))});
cp_r_win32({false, Source},{false, Dest}) ->
    %% from file to file
    {ok,_} = file:copy(Source, Dest),
    ok;
cp_r_win32({true, SourceDir},{false,DestDir}) -> 
    IsFile = filelib:is_file(DestDir),
    case IsFile of
        true -> 
            %% From Directory to file? This shouldn't happen
            {error,[{rebar_file_utils,cp_r_win32},
                        {directory_to_file_makes_no_sense,
                            {source,SourceDir},{dest,DestDir}}]};
        false ->
            %% Specifying a target directory that doesn't currently exist.
            %% So Let's attempt to create this directory
            %% Will not recursively create parent directories
            ok = case file:make_dir(DestDir) of
                     {error, eexist} -> ok;
                     Other -> Other
                 end,
            ok = xcopy_win32(SourceDir, DestDir)
    end;
cp_r_win32(Source,Dest) ->
    Dst = {filelib:is_dir(Dest), Dest},
    lists:foreach(fun(Src) ->
                          ok = cp_r_win32({filelib:is_dir(Src), Src}, Dst)
                  end, filelib:wildcard(Source)),
    ok.

%% Shell Command Stuff (from rebar_utils)
sh(Command0, Options0) ->
    % ?CONSOLE("sh info:\n\tcwd: ~p\n\tcmd: ~s\n", [get_cwd(), Command0]),
    % ?DEBUG("\topts: ~p\n", [Options0]),

    DefaultOptions = [use_stdout, abort_on_error],
    Options = [expand_sh_flag(V)
               || V <- proplists:compact(Options0 ++ DefaultOptions)],

    ErrorHandler = proplists:get_value(error_handler, Options),
    OutputHandler = proplists:get_value(output_handler, Options),

    Command = patch_on_windows(Command0, proplists:get_value(env, Options, [])),
    PortSettings = proplists:get_all_values(port_settings, Options) ++
        [exit_status, {line, 16384}, use_stdio, stderr_to_stdout, hide],
    Port = open_port({spawn, Command}, PortSettings),

    case sh_loop(Port, OutputHandler, []) of
        {ok, _Output} = Ok ->
            Ok;
        {error, {_Rc, _Output}=Err} ->
            ErrorHandler(Command, Err)
    end.

get_cwd() ->
	{ok,Dir} = file:get_cwd(),
	Dir.

patch_on_windows(Cmd, Env) ->
    case os:type() of
        {win32,nt} ->
            "cmd /q /c "
                ++ lists:foldl(fun({Key, Value}, Acc) ->
                                       expand_env_variable(Acc, Key, Value)
                               end, Cmd, Env);
        _ ->
            Cmd
    end.

expand_env_variable(InStr, VarName, RawVarValue) ->
    case string:chr(InStr, $$) of
        0 ->
            %% No variables to expand
            InStr;
        _ ->
            VarValue = re:replace(RawVarValue, "\\\\", "\\\\\\\\", [global]),
            %% Use a regex to match/replace:
            %% Given variable "FOO": match $FOO\s | $FOOeol | ${FOO}
            RegEx = io_lib:format("\\\$(~s(\\s|$)|{~s})", [VarName, VarName]),
            ReOpts = [global, {return, list}],
            re:replace(InStr, RegEx, [VarValue, "\\2"], ReOpts)
    end.

sh_loop(Port, Fun, Acc) ->
    receive
        {Port, {data, {eol, Line}}} ->
            sh_loop(Port, Fun, Fun(Line ++ "\n", Acc));
        {Port, {data, {noeol, Line}}} ->
            sh_loop(Port, Fun, Fun(Line, Acc));
        {Port, {exit_status, 0}} ->
            {ok, lists:flatten(lists:reverse(Acc))};
        {Port, {exit_status, Rc}} ->
            {error, {Rc, lists:flatten(lists:reverse(Acc))}}
    end.

escape_spaces(Str) ->
    re:replace(Str, " ", "\\\\ ", [global, {return, list}]).


log_and_abort(Message) ->
	?CONSOLE("Aborting: ~s ~n",[Message]).


         
expand_sh_flag(return_on_error) ->
    {error_handler,
     fun(_Command, Err) ->
             {error, Err}
     end};
expand_sh_flag({abort_on_error, Message}) ->
    {error_handler,
		fun(Cmd,Err) ->
				log_and_abort({Message,{Cmd,Err}})
		end};
expand_sh_flag(abort_on_error) ->
	expand_sh_flag({abort_on_error, error});
expand_sh_flag(use_stdout) ->
    {output_handler,
     fun(Line, Acc) ->
             ?CONSOLE("~s", [Line]),
             [Line | Acc]
     end};
expand_sh_flag({use_stdout, false}) ->
    {output_handler,
     fun(Line, Acc) ->
             [Line | Acc]
     end};
expand_sh_flag({cd, _CdArg} = Cd) ->
    {port_settings, Cd};
expand_sh_flag({env, _EnvArg} = Env) ->
    {port_settings, Env}.


<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




























































































































































































































































































































































































































Deleted rel/make_slim.escript.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#!/usr/bin/env escript
%% -*- erlang -*-
%% vim: ts=4 sw=4 et ft=erlang
%%
%% Coyright 2012 - Jesse Gumm
%% MIT License
%%
%%
%% This merely takes a normal reltool.config file and add options to make it
%% a slim release for Nitrogen

main([File]) ->
    main([File,File]);
main([FromFile,ToFile]) ->
    {ok,Terms} = file:consult(FromFile),

    Sys = proplists:get_value(sys, Terms),
    Sys2 = [{profile, development}, {excl_lib,otp_root} | proplists:delete(profile, Sys)],
    SysFinal = Sys2,

    Overlay = proplists:get_value(overlay, Terms),
    Overlay2 = lists:delete({copy,"./overlay/erts/*","{{erts_vsn}}/bin"},Overlay),
    Overlay3 = [{copy,"./overlay/erts/nodetool","releases/{{rel_vsn}}/nodetool"} | Overlay2],
    OverlayFinal = Overlay3,

    Terms2 = proplists:delete(sys, Terms),
    Terms3 = proplists:delete(overlay, Terms2),
    Terms4 = [{sys, SysFinal}, {overlay, OverlayFinal} | Terms3],

    FinalTerms = [io_lib:format("~p.~n",[T]) || T <- Terms4],

    if
        FromFile=:=ToFile ->
            io:format("Turning ~p into a slim release~n", [FromFile]);
        true ->
            io:format("Making ~p a slim release as ~p~n", [FromFile, ToFile])
    end,
    file:write_file(ToFile, FinalTerms).

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<














































































Deleted rel/merge_platform_dependencies.escript.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/usr/bin/env escript
%% vim: ts=4 sw=4 et ft=erlang

main([SrcFile, DepsFile, DestFile]) ->
    io:format("Generating ~p~n", [DestFile]),
    {ok, Src} = file:read_file(SrcFile),
    {ok, Deps} = file:read_file(DepsFile),

    Regex = "%% START_PLATFORM_DEPENDENCIES.*END_PLATFORM_DEPENDENCIES",

    [Part1, Part2] = re:split(Src, Regex, [{return, binary},dotall]),

    NewContents = [Part1,"\n", Deps, "\n", Part2],
    ok = file:write_file(DestFile, NewContents).

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






























Deleted rel/overlay/common/.gitignore.

1
2
3
4
5
6
7
8
9
10
site/ebin/*
*.sw?
erl_crash.dump
*~
/log
/scratch
lib/nitrogen_core
lib/simple_bridge
lib/nprocreg
lib/sync
<
<
<
<
<
<
<
<
<
<




















Deleted rel/overlay/common/Makefile.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
.PHONY: fix-slim-release test

all: releases get-deps plugins compile

REBAR?=./rebar -q

cookie:
	@echo Generating a default cookie in /etc/vm.args
	@(echo -setcookie `openssl rand -base64 50 | head -n1 | sed -e 's/[^a-zA-Z0-9]//g'` >> etc/vm.args)

compile:
	@(export PATH=`pwd`/`echo erts-*/bin`:$$PATH; echo "Using Erlang in `which erl`"; $(REBAR) compile)

get-deps:
	@(export PATH=`pwd`/`echo erts-*/bin`:$$PATH; echo "Using Erlang in `which erl`"; $(REBAR) get-deps)

update-deps:
	@(export PATH=`pwd`/`echo erts-*/bin`:$$PATH; echo "Using Erlang in `which erl`"; $(REBAR) update-deps)

eunit: get-deps compile
	@(export PATH=`pwd`/`echo erts-*/bin`:$$PATH; echo "Using Erlang in `which erl`"; $(REBAR) skip_deps=true eunit)

releases:
	make fix-slim-release

copy-static:
	@(mkdir -p site/static/nitrogen)
	@(cp -r lib/nitrogen_core/www/* site/static/nitrogen/)

plugins:
	@(export PATH=`pwd`/`echo erts-*/bin`:$$PATH;escript do-plugins.escript)

## This is only applicable for slim releases
fix-slim-release:
	@echo Fixing slim release to the version of Erlang installed on this machine
	@(./fix-slim-release)

DEPS_PLT=$(CURDIR)/.deps_plt
DEPS=erts kernel stdlib sasl lib/nitrogen_core lib/simple_bridge lib/nprocreg lib/nitro_cache lib/rekt lib/qdate

$(DEPS_PLT):
	@echo Building local plt at $(DEPS_PLT)
	@echo 
	@(export PATH=`pwd`/`echo erts-*/bin`:$$PATH; echo "Using Dialyzer in `which dialyzer`"; dialyzer --output_plt $(DEPS_PLT) --build_plt --apps $(DEPS) -r ./lib)


dialyzer: all $(DEPS_PLT)
	@(export PATH=`pwd`/`echo erts-*/bin`:$$PATH; echo "Using Dialyzer in `which dialyzer`"; dialyzer --fullpath --plt $(DEPS_PLT) -Wrace_conditions -r ./site/ebin)

update: update-deps copy-static compile
	@(echo "*** CONGRATULATIONS ***")
	@(echo "Your Nitrogen installation has been upgraded.")
	@(echo "You may need to manually merge any changes that may have been made to")
	@(echo "configuration files as well as the initialization modules:")
	@(echo "    site/src/nitrogen_sup.erl")
	@(echo "    site/src/nitrogen_PLATFORM.erl")
	@(echo "    site/src/nitrogen_app.erl")
	@(echo "")

upgrade: update

clean:
	@(export PATH=`pwd`/`echo erts-*/bin`:$$PATH; $(REBAR) clean)
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






























































































































Deleted rel/overlay/common/README.md.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# About

This is an Erlang web application using the [Nitrogen Web
Framework](https://nitrogenproject.com).

# Building

You can rebuild the project by typing:

   make

If this fails, it likely means that its a slim release and Erlang is not
installed on this machine. Please [install
Erlang](https://www.erlang-solutions.com/resources/download.html).

# Running

You can start the application with:

  bin/nitrogen start

which will start it in daemon mode.  You can attach to this started daemon
with:

  bin/nitrogen attach

If you'd rather have an Erlang console right away, rather than starting a
daemon, type:

  bin/nitrogen console

# Config

The rebar.config file controls dependencies and build parameters using the
popular [rebar](http://github.com/rebar/rebar) tool.

The `plugins.config` file controls how Nitrogen plugins are handled.

The files in the `etc` directory control application configuration, including
ports, webserver set up, and the like.  Please see the files there for
configuration options, or view the Nitrogen documentation.

# Code

Dependency libraries (once being built) end up in the `lib` directory.

Source code can be found in `site/src`

Template code is in `site/templates`

Compiled Erlang modules (ebin files) go in `site/ebin`

# Live code reloading

By default Nitrogen comes with an application called [sync](http://github.com/rustyio/sync) which provides automatic code reloading when the related .erl file or .ebin file is updated.  To use this, run the following on the Erlang shell:

  sync:go().
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


















































































































Deleted rel/overlay/common/bin/dev.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#!/usr/bin/env bash

RUNNER_SCRIPT_DIR=$(cd ${0%/*} && pwd)

RUNNER_BASE_DIR=${RUNNER_SCRIPT_DIR%/*}
RUNNER_ETC_DIR=$RUNNER_BASE_DIR/etc
RUNNER_LOG_DIR=$RUNNER_BASE_DIR/log
RUNNER_USER=

# Make sure this script is running as the appropriate user
if [ ! -z "$RUNNER_USER" ] && [ `whoami` != "$RUNNER_USER" ]; then
    exec sudo -u $RUNNER_USER -i $0 $@
fi

# Make sure CWD is set to runner base dir
cd $RUNNER_BASE_DIR

# Extract the target node name from node.args
NAME_ARG=`grep -e '-[s]*name' $RUNNER_ETC_DIR/vm.args`
if [ -z "$NAME_ARG" ]; then
    echo "vm.args needs to have either -name or -sname parameter."
    exit 1
fi

# Learn how to specify node name for connection from remote nodes
if  echo $NAME_ARG | grep -E "^-sname" > /dev/null ; then
    NAME_PARAM="-sname"
    NAME_HOST=""
else
    NAME_PARAM="-name"
    if echo $NAME_ARG | grep -E "(@.*)" > /dev/null ; then
        NAME_HOST=${BASH_REMATCH[1]}
    else
        NAME_HOST=""
    fi
fi

# Extract the target cookie
COOKIE_ARG=`grep -e '-setcookie' $RUNNER_ETC_DIR/vm.args`
if [ -z "$COOKIE_ARG" ]; then
    echo "vm.args needs to have a -setcookie parameter."
    exit 1
fi

# Identify the script name
SCRIPT=`basename $0`

# Parse out release and erts info
START_ERL=`cat $RUNNER_BASE_DIR/releases/start_erl.data`
ERTS_VSN=${START_ERL% *}
APP_VSN=${START_ERL#* }

# Add ERTS bin dir to our path.
ERTS_PATH=$RUNNER_BASE_DIR/erts-$ERTS_VSN/bin

# Setup command to control the node
if [ -x $ERTS_PATH/escript ]; then
	NODETOOL="$ERTS_PATH/escript $ERTS_PATH/nodetool $NAME_ARG $COOKIE_ARG"
else
	NODETOOL="escript $RUNNER_BASE_DIR/releases/*/nodetool $NAME_ARG $COOKIE_ARG"
fi

# Make sure the local node IS running
RES=`$NODETOOL ping`
if [ "$RES" != "pong" ]; then
    echo "Node is not running!"
    exit 1
fi

$NODETOOL rpc nitrogen_dev command $@
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<












































































































































Deleted rel/overlay/common/bin/nitrogen.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
#!/bin/sh
# -*- tab-width:4;indent-tabs-mode:nil -*-
# ex: ts=4 sw=4 et

RUNNER_SCRIPT_DIR=$(cd ${0%/*} && pwd)

CALLER_DIR=$PWD

RUNNER_BASE_DIR=${RUNNER_SCRIPT_DIR%/*}
RUNNER_ETC_DIR=$RUNNER_BASE_DIR/etc
# Note the trailing slash on $PIPE_DIR/
PIPE_DIR=/tmp/`whoami`/$RUNNER_BASE_DIR/
RUNNER_USER=

# Make sure this script is running as the appropriate user
if [ ! -z "$RUNNER_USER" ] && [ `whoami` != "$RUNNER_USER" ]; then
    exec sudo -u $RUNNER_USER -i $0 $@
fi

# Identify the script name
SCRIPT=`basename $0`

# Parse out release and erts info
START_ERL=`cat $RUNNER_BASE_DIR/releases/start_erl.data`
ERTS_VSN=${START_ERL% *}
APP_VSN=${START_ERL#* }

# Use $CWD/vm.args if exists, otherwise releases/APP_VSN/vm.args, or else etc/vm.args
if [ -e "$CALLER_DIR/vm.args" ]; then
    VMARGS_PATH=$CALLER_DIR/vm.args
    USE_DIR=$CALLER_DIR
else
    USE_DIR=$RUNNER_BASE_DIR
    if [ -e "$RUNNER_BASE_DIR/releases/$APP_VSN/vm.args" ]; then
        VMARGS_PATH="$RUNNER_BASE_DIR/releases/$APP_VSN/vm.args"
    else
        VMARGS_PATH="$RUNNER_ETC_DIR/vm.args"
    fi
fi

RUNNER_LOG_DIR=$USE_DIR/log
# Make sure log directory exists
mkdir -p $RUNNER_LOG_DIR

# Use releases/VSN/sys.config if it exists otherwise use etc/app.config
## THIS SECTION MODIFIED FROM STOCK REBAR TO READ ALL *.config FILES FROM DIRECTORY
if [ -e "$USE_DIR/sys.config" ]; then
    CONFIG="-config $USE_DIR/sys.config"
else
    if [ -e "$RUNNER_BASE_DIR/releases/$APP_VSN/sys.config" ]; then
        CONFIG="-config $RUNNER_BASE_DIR/releases/$APP_VSN/sys.config"
    else
        ## NITROGEN CHANGE: Ensure that all .config files get loaded in /etc
        for f in `ls $RUNNER_ETC_DIR/*.config`; do CONFIG="$CONFIG -config $f"; done
    fi
fi

# Extract the target node name from node.args
NAME_ARG=`egrep '^-s?name' $VMARGS_PATH`
if [ -z "$NAME_ARG" ]; then
    echo "vm.args needs to have either -name or -sname parameter."
    exit 1
fi

# Extract the name type and name from the NAME_ARG for REMSH
REMSH_TYPE=`echo $NAME_ARG | awk '{print $1}'`
REMSH_NAME=`echo $NAME_ARG | awk '{print $2}'`

# Note the `date +%s`, used to allow multiple remsh to the same node transparently
REMSH_NAME_ARG="$REMSH_TYPE remsh`date +%s`@`echo $REMSH_NAME | awk -F@ '{print $2}'`"
REMSH_REMSH_ARG="-remsh $REMSH_NAME"

# Extract the target cookie
COOKIE_ARG=`grep '^-setcookie' $VMARGS_PATH`
if [ -z "$COOKIE_ARG" ]; then
    echo "vm.args needs to have a -setcookie parameter."
    exit 1
    
fi

# Make sure CWD is set to the right dir
cd $USE_DIR

# Make sure log directory exists
mkdir -p $USE_DIR/log

RUNNER_SCRIPT_DATA=
if [ -e "$RUNNER_BASE_DIR/releases/$APP_VSN/runner_script.data" ]; then
    RUNNER_SCRIPT_DATA=`cat $RUNNER_BASE_DIR/releases/$APP_VSN/runner_script.data`
fi

if [ -z "$RUNNER_SCRIPT_DATA" ]; then
    ROOTDIR=$RUNNER_BASE_DIR
    ERTS_PATH=$RUNNER_BASE_DIR/erts-$ERTS_VSN/bin
    if [ -e "$RUNNER_BASE_DIR/releases/$APP_VSN/nodetool" ]; then
        NODETOOL="$ERTS_PATH/escript $RUNNER_BASE_DIR/releases/$APP_VSN/nodetool $NAME_ARG $COOKIE_ARG"
    else
        NODETOOL="$ERTS_PATH/escript $ERTS_PATH/nodetool $NAME_ARG $COOKIE_ARG"
    fi
    ## Not a slim release, so no slim arguments
    SLIM_ARGS=
elif [ "$RUNNER_SCRIPT_DATA" = "slim" ]; then
    # Setup system paths
    SYSTEM_ERL_PATH=`which erl`
    if [ ! -x "$SYSTEM_ERL_PATH" ]; then
        echo "Failed to find erl. Is Erlang/OTP available in PATH?"
        exit 1
    fi
    SYSTEM_HOME_BIN=${SYSTEM_ERL_PATH%/*}
    ## This is a check for OSX using the Erlang Solutions installer
    if [ -d "$SYSTEM_HOME_BIN/../lib/erlang" ]; then
        ROOTDIR=$SYSTEM_HOME_BIN/../lib/erlang
    else
        ROOTDIR=$SYSTEM_HOME_BIN/..
    fi
    ERTS_PATH=$ROOTDIR/erts-$ERTS_VSN/bin
    unset SYSTEM_ERL_PATH
    unset SYSTEM_HOME_BIN

    LOCAL_ERTS_PATH=$RUNNER_BASE_DIR/erts-$ERTS_VSN/bin
    NODETOOL="$ERTS_PATH/escript $RUNNER_BASE_DIR/releases/$APP_VSN/nodetool $NAME_ARG $COOKIE_ARG"
    unset LOCAL_ERL_PATH

    # Setup additional arguments for slim release
    SLIM_ARGS="-boot_var RELTOOL_EXT_LIB $RUNNER_BASE_DIR/lib -sasl releases_dir \"$RUNNER_BASE_DIR/releases\""
else
    echo "Unknown runner_script.data"
    exit 1
fi

# Setup remote shell command to control node
REMSH="$ERTS_PATH/erl $REMSH_NAME_ARG $REMSH_REMSH_ARG $COOKIE_ARG"

# Check the first argument for instructions
case "$1" in
    start|start_boot)
        # Make sure there is not already a node running
        RES=`$NODETOOL ping`
        if [ "$RES" = "pong" ]; then
            echo "Node is already running!"
            exit 1
        fi
        case "$1" in
            start)
                shift
                START_OPTION="console"
                HEART_OPTION="start"
                ;;
            start_boot)
                shift
                START_OPTION="console_boot"
                HEART_OPTION="start_boot"
                ;;
        esac
        RUN_PARAM=$(printf "\'%s\' " "$@")
        HEART_COMMAND="$RUNNER_BASE_DIR/bin/$SCRIPT $HEART_OPTION $RUN_PARAM"
        export HEART_COMMAND
        mkdir -p $PIPE_DIR
        $ERTS_PATH/run_erl -daemon $PIPE_DIR $RUNNER_LOG_DIR "exec $RUNNER_BASE_DIR/bin/$SCRIPT $START_OPTION $RUN_PARAM" 2>&1
        ;;

    stop)
        # Wait for the node to completely stop...
        case `uname -s` in
            Linux|Darwin|FreeBSD|DragonFly|NetBSD|OpenBSD)
                # PID COMMAND
                PID=`ps ax -o pid= -o command=|\
                    grep "\-boot $RUNNER_BASE_DIR/[r]eleases"|awk '{print $1}'`
                ;;
            SunOS)
                # PID COMMAND
                PID=`ps -ef -o pid= -o args=|\
                    grep "\-boot $RUNNER_BASE_DIR/[r]eleases"|awk '{print $1}'`
                ;;
            CYGWIN*)
                # UID PID PPID TTY STIME COMMAND
                PID=`ps -efW|grep "\-boot $RUNNER_BASE_DIR/[r]eleases"|awk '{print $2}'`
                ;;
        esac
        $NODETOOL stop
        ES=$?
        if [ "$ES" -ne 0 ]; then
            exit $ES
        fi
        while `kill -0 $PID 2>/dev/null`;
        do
            sleep 1
        done
        ;;

    restart)
        ## Restart the VM without exiting the process
        $NODETOOL restart
        ES=$?
        if [ "$ES" -ne 0 ]; then
            exit $ES
        fi
        ;;

    reboot)
        ## Restart the VM completely (uses heart to restart it)
        $NODETOOL reboot
        ES=$?
        if [ "$ES" -ne 0 ]; then
            exit $ES
        fi
        ;;

    ping)
        ## See if the VM is alive
        $NODETOOL ping
        ES=$?
        if [ "$ES" -ne 0 ]; then
            exit $ES
        fi
        ;;

    attach)
        # Make sure a node IS running
        RES=`$NODETOOL ping`
        ES=$?
        if [ "$ES" -ne 0 ]; then
            echo "Node is not running!"
            exit $ES
        fi

        shift
        exec $ERTS_PATH/to_erl $PIPE_DIR
        ;;

    remote_console)
        # Make sure a node IS running
        RES=`$NODETOOL ping`
        ES=$?
        if [ "$ES" -ne 0 ]; then
            echo "Node is not running!"
            exit $ES
        fi

        shift
        exec $REMSH
        ;;

    upgrade)
        if [ -z "$2" ]; then
            echo "Missing upgrade package argument"
            echo "Usage: $SCRIPT upgrade {package base name}"
            echo "NOTE {package base name} MUST NOT include the .tar.gz suffix"
            exit 1
        fi

        # Make sure a node IS running
        RES=`$NODETOOL ping`
        ES=$?
        if [ "$ES" -ne 0 ]; then
            echo "Node is not running!"
            exit $ES
        fi

        node_name=`echo $NAME_ARG | awk '{print $2}'`
        erlang_cookie=`echo $COOKIE_ARG | awk '{print $2}'`

        $ERTS_PATH/escript $RUNNER_BASE_DIR/bin/install_upgrade.escript $node_name $erlang_cookie $2
        ;;

    console|console_clean|console_boot)
        # .boot file typically just $SCRIPT (ie, the app name)
        # however, for debugging, sometimes start_clean.boot is useful.
        # For e.g. 'setup', one may even want to name another boot script.
        case "$1" in
            console)        BOOTFILE=$SCRIPT ;;
            console_clean)  BOOTFILE=start_clean ;;
            console_boot)
                shift
                BOOTFILE="$1"
                shift
                ;;
        esac
        # Setup beam-required vars
        BINDIR=$ROOTDIR/erts-$ERTS_VSN/bin
        EMU=beam
        PROGNAME=`echo $0 | sed 's/.*\\///'`

        ## NITROGEN CHANGE: '-mode interactive' for dynamic code loading
        CMD="$BINDIR/erlexec $SLIM_ARGS -boot $RUNNER_BASE_DIR/releases/$APP_VSN/$BOOTFILE -mode interactive $CONFIG -args_file $VMARGS_PATH"
        export EMU
        export ROOTDIR
        export BINDIR
        export PROGNAME

        # Dump environment info for logging purposes
        echo "Exec: $CMD" -- ${1+"$@"}
        echo "Root: $ROOTDIR"

        # Log the startup
        logger -t "$SCRIPT[$$]" "Starting up"

        # Start the VM
        exec $CMD -- ${1+"$@"}
        ;;

    foreground)
        # start up the release in the foreground for use by runit
        # or other supervision services

        BOOTFILE=$SCRIPT
        FOREGROUNDOPTIONS="-noinput +Bd"

        # Setup beam-required vars
        BINDIR=$ROOTDIR/erts-$ERTS_VSN/bin
        EMU=beam
        PROGNAME=`echo $0 | sed 's/.*\///'`
        CMD="$BINDIR/erlexec $SLIM_ARGS $FOREGROUNDOPTIONS -boot $RUNNER_BASE_DIR/releases/$APP_VSN/$BOOTFILE $CONFIG -args_file $VMARGS_PATH"
        export EMU
        export ROOTDIR
        export BINDIR
        export PROGNAME

        # Dump environment info for logging purposes
        echo "Exec: $CMD" -- ${1+"$@"}
        echo "Root: $ROOTDIR"

        # Start the VM
        exec $CMD -- ${1+"$@"}
        ;;
    *)
        echo "Usage: $SCRIPT {start|start_boot <file>|foreground|stop|restart|reboot|ping|console|console_clean|console_boot <file>|attach|remote_console|upgrade}"
        exit 1
        ;;
esac

exit 0
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
























































































































































































































































































































































































































































































































































































































































































Deleted rel/overlay/common/do-plugins.escript.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
#!/usr/bin/env escript
%% -*- erlang -*-
%% vim: ts=4 sw=4 et ft=erlang
%%
%% Coyright 2013 - Jesse Gumm
%%
%% MIT License
%%
%% About
%%
%% This little script assists the Nitrogen Web Framework by simplifying the
%% process of including custom elements, actions, or validators without having
%% to worry about including a different header for each, or manually copying
%% records from each element's header into the "records.hrl".
%%
%% Further, this copies the plugin static information (javascript, images, etc)
%% into the site/static/plugins/<pluginname> directory. Then one doesn't need 
%% to copy that information for each upgrade.
%%
%% TO MAKE A PLUGIN WORK WITH THIS SCRIPT:
%%
%% 1) Make sure your plugin is able to be used as a rebar dependency
%% 2) Include a file "nitrogen.plugin" in the root of the plugin directory
%% 3) If you have any static resources (js, images) put them in a 'static'
%%    directory
%% 4) If this is a custom element, action, or validator, or requires anything
%%    else that should be included in a header, add them to (one or more) .hrl
%%    files in 'include'
%% 5) From your Nitrogen app's directory, include your plugin as a rebar
%%    dependency and run 'make'
%%
%% Sample Plugin Directory Structure:
%%
%% myplugin/
%%      ebin/
%%    
%%      src/
%%          element_myplugin.erl
%%          myplugin.app.src
%%      
%%      include/
%%          myplugin.hrl
%%      
%%      priv/
%%          templates/
%%              mytemplate.html
%%
%%          static/
%%              js/
%%                  myplugin.js
%%                  jquery-some-plugin.js
%%              images/
%%                  some_image.png
%%              css/
%%                  myplugin.css
%%
%%
%% When the plugin is processed, the following will be updated in your Nitrogen App
%%
%% site/
%%      include/
%%          plugins.hrl (will include a reference to all .hrl files from your plugin)
%%      static/
%%          plugins/
%%              myplugin/                
%%                  js/
%%                      myplugin.js
%%                      jquery-some-plugin.js
%%                  images/
%%                      some_image.png
%%                  css/
%%                      myplugin.css
%%      templates/
%%          plugins/
%%              mytemplate.html
%%
%% (Note: The Erlang/Nitrogen Element code is not copied, it'll be loaded just
%% like any rebar dependency's code)

main([]) ->
    io:format("Checking for Nitrogen Plugins\n"),
    RebarConfig = get_config("rebar.config"),
    PluginConfig = get_config("plugins.config"),
    DepDirs = proplists:get_value(deps_dir, RebarConfig, ["lib"]),
    {Includes,Statics,Templates} = lists:foldl(fun(Dir, {Inc, Stat, Temp}) ->
                            {ok, FoundIncludes, FoundStatics, FoundTemplates} = get_plugins(Dir),
                            {FoundIncludes ++ Inc, FoundStatics ++ Stat, FoundTemplates ++ Temp}
                        end, {[],[],[]}, DepDirs),
    case {Includes, Statics, Templates} of
        {[],[],[]} -> 
            io:format("No Nitrogen Plugins Found~n");
        _ ->
            io:format("Generating aggregate plugin header (plugins.hrl)~n"),
            generate_plugin_include(PluginConfig, Includes),
            io:format("Generating plugin static directories~n"),
            generate_plugin_static(PluginConfig, Statics),
            io:format("Generating plugin template directories~n"),
            generate_plugin_templates(PluginConfig, Templates),
            io:format("Plugin generation complete~n")
    end.


get_plugins(DepDir) ->
    Files = case file:list_dir(DepDir) of
        {ok, F} -> F;
        {error, _} -> []
    end,
    {Inc,Stat,Temp} = lists:foldl(fun(X,PluginInfo={Includes,Statics,Templates}) ->
                    PluginPath = filename:join(DepDir,X),
                    case analyze_path(PluginPath) of
                        undefined ->
                            %% Not a plugin, so just continue
                            PluginInfo;
                        {ok, FoundIncludes, FoundStatics, FoundTemplates} ->
                            {FoundIncludes++Includes, FoundStatics++Statics, FoundTemplates++Templates}
                    end
                end,{[],[],[]},Files),
    {ok, Inc, Stat, Temp}.
                          
get_config(File) ->
    case file:consult(File) of
        {error, _} -> [];
        {ok, Config} -> Config
    end.

analyze_path(Path) ->
    case is_dir_or_symlink_dir(Path) of
        true ->
            {ok, Files} = file:list_dir(Path),
            case lists:member("nitrogen.plugin",Files) of
                false -> 
                    undefined;
                true -> 
                    io:format("Found a Nitrogen plugin in ~p~n",[Path]),
                    IncludeDir = filename:join(Path,include),
                    StaticDir = filename:join(Path,static),
                    PrivStaticDir = filename:join([Path,priv,static]),
                    TemplateDir = filename:join([Path,priv,templates]),

                    Includes = analyze_path_include(IncludeDir),
                    %% Originally, the plugin spec called for statics to be
                    %% located in the "static" dir, however, it's more
                    %% OTP-compliant to have statics to be located in
                    %% "priv/static", so we support both here with StaticDir
                    %% and PrivStaticDir
                    Statics = analyze_path_exists_only(StaticDir) 
                              ++ analyze_path_exists_only(PrivStaticDir),

                    Templates = analyze_path_exists_only(TemplateDir),
                    {ok, Includes, Statics, Templates}
            end;
        false -> undefined
    end.

is_dir_or_symlink_dir(Path) ->
    case filelib:is_dir(Path) of
        true -> true;
        false ->
            case file:read_link(Path) of
                {ok, _} -> true;
                {error, _} -> false
            end
    end.
            

analyze_path_include(Path) ->
    case filelib:is_dir(Path) of
        false -> [];
        true -> list_includes(Path)
    end.
            
list_includes(Path) -> 
    {ok, Files} = file:list_dir(Path),
    Includes = filter_non_includes(Files),
    [filename:join(Path,Inc) || Inc <- Includes].

filter_non_includes([]) -> [];
filter_non_includes([File | Files]) ->
    case re:run(File,"\.hrl$",[{capture,none}]) of
        match -> [File | filter_non_includes(Files)];
        nomatch -> filter_non_includes(Files)
    end.

analyze_path_exists_only(Path) ->
    case filelib:is_dir(Path) of
        false -> [];
        true -> [Path]
    end.

generate_plugin_include(Config, Includes) ->
    IncludeFile = proplists:get_value(plugins_hrl, Config, "site/include/plugins.hrl"),
    HeaderLines = ["%% Automatically Generated by do-plugins.escript",
                   "%% Manually editing this file is not recommended."],
    PluginLines = [includify(I) || I <- Includes],
    PluginContents = string:join(HeaderLines ++ PluginLines,"\n"),
    FinalContents = iolist_to_binary(PluginContents),
    CurrentContents = get_current_include(IncludeFile),
    case FinalContents == CurrentContents of
        true -> io:format("No changes to ~p~n",[IncludeFile]);
        false -> file:write_file(IncludeFile,PluginContents)
    end.

get_current_include(File) ->
    case file:read_file(File) of
        {ok, Binary} -> Binary;
        {error, _} -> <<>>
    end.

includify("lib/" ++ Path) ->
    "-include_lib(\"" ++ Path ++ "\").";
includify(Path) ->
    "-include(\"" ++ filename:join("..",Path) ++ "\").".

generate_plugin_static(Config, Statics) ->
    PluginStaticBase = proplists:get_value(static_dir, Config, "site/static/plugins"),
    CopyMode = proplists:get_value(copy_mode, Config, copy),
    clear_plugin_dir(PluginStaticBase),
    filelib:ensure_dir(filename:join(PluginStaticBase,dummy)),
    [generate_plugin_copy_worker(PluginStaticBase,CopyMode,Static) || Static <- Statics].

clear_plugin_dir(Dir) ->
    rm_rf(Dir).

plugin_name_from_static_path(PluginStatic) ->
    PluginStaticParts = filename:split(PluginStatic),
    case lists:reverse(PluginStaticParts) of
        ["templates","priv",PluginName|_]   -> PluginName;
        ["templates",PluginName|_]          -> PluginName;
        ["static","priv",PluginName|_]      -> PluginName;
        ["static",PluginName|_]             -> PluginName
    end.

generate_plugin_copy_worker(PluginBase, CopyMode, PluginStatic) ->
    %% Split the Plugin Static Dir into parts and extract the name of the plugin
    %% ie "lib/whatever/static" - the Plugin Name is "whatever"
    PluginName = plugin_name_from_static_path(PluginStatic),
   
    %% And we're going to copy it into our system's plugin static dir
    %% (ie "site/static/plugins/whatever")
    FinalDestination = filename:join(PluginBase,PluginName),

    %% And let's copy or link them.
    case CopyMode of 
        link ->
            LinkPrefix = make_link_relative_prefix(FinalDestination),
               
            file:make_symlink(filename:join([LinkPrefix,PluginStatic]),FinalDestination);
        copy -> 
            %% We want to copy the contents of the Plugin's static dir,
            %% So we're copying from /lib/whatever/static/*
            PluginSource = filename:join(PluginStatic,"*"),

            %% Make sure the dir exists to copy into
            filelib:ensure_dir(filename:join(FinalDestination,dummy)),

            %% And copy the directory
            try cp_r([PluginSource],FinalDestination)
            catch _:_ -> ok  %% getting here usually just means that the source directory is empty
            end;
        Other ->
            throw({invalid_copy_mode, Other})
    end.

generate_plugin_templates(Config, Templates) ->
    TemplateBase = proplists:get_value(template_dir, Config, "site/templates/plugins"),
    CopyMode = proplists:get_value(copy_mode, Config, copy),
    clear_plugin_dir(TemplateBase),
    filelib:ensure_dir(filename:join(TemplateBase,dummy)),
    [generate_plugin_copy_worker(TemplateBase, CopyMode, Template) || Template <- Templates].

%% Because the symlink is relative, we need to make sure it includes the
%% proper relative path prefix (ie, the right number of "../../../" to get us
%% back before linking
make_link_relative_prefix("./" ++ Path) ->
    make_link_relative_prefix(Path);
make_link_relative_prefix(Path) ->
    Parts = filename:split(Path),
    Parts2 = lists:sublist(Parts, length(Parts)-1),
    Parts3 = [relative_path_helper(Part) || Part <- Parts2],
    filename:join(Parts3).

relative_path_helper(".") -> ".";
relative_path_helper("..") -> "";
relative_path_helper(_) -> "..".

%% -------------------------------------------------------------------------
%% ------------- File Actions (copied mostly from Rebar) -------------------
%% -------------------------------------------------------------------------


-define(CONSOLE(Str, Args), io:format(Str,Args)).
-define(FMT(Str,Args), lists:flatten(io_lib:format(Str,Args))).

rm_rf(Target) ->
    case os:type() of
        {unix, _} ->
            EscTarget = escape_spaces(Target),
            {ok, []} = sh(?FMT("rm -rf ~s", [EscTarget]),
                                      [{use_stdout, false}, return_on_error]),
            ok;
        {win32, _} ->
            Filelist = filelib:wildcard(Target),
            Dirs = [F || F <- Filelist, filelib:is_dir(F)],
            Files = Filelist -- Dirs,
            ok = delete_each(Files),
            ok = delete_each_dir_win32(Dirs),
            ok
    end.

delete_each([]) ->
    ok;
delete_each([File | Rest]) ->
    case file:delete(File) of
        ok ->
            delete_each(Rest);
        {error, enoent} ->
            delete_each(Rest);
        {error, Reason} ->
            ExitMsg = ?FMT("Error: Failed to delete file ~s: ~p\n", [File, Reason]),
            exit(ExitMsg)
    end.

delete_each_dir_win32([]) -> ok;
delete_each_dir_win32([Dir | Rest]) ->
    {ok, []} = sh(?FMT("rd /q /s \"~s\"",
                                   [filename:nativename(Dir)]),
                              [{use_stdout, false}, return_on_error]),
    delete_each_dir_win32(Rest).



cp_r(Sources, Dest) ->
    case os:type() of
        {unix, _} ->
            EscSources = [escape_spaces(Src) || Src <- Sources],
            SourceStr = string:join(EscSources, " "),
            {ok, []} = sh(?FMT("cp -R ~s \"~s\"",
                                           [SourceStr, Dest]),
                                      [{use_stdout, false}, return_on_error]),
            ok;
        {win32, _} ->
            lists:foreach(fun(Src) -> ok = cp_r_win32(Src,Dest) end, Sources),
            ok
    end.

%% Windows stuff	
xcopy_win32(Source,Dest)->
    {ok, R} = sh(
                ?FMT("xcopy \"~s\" \"~s\" /q /y /e 2> nul",
                     [filename:nativename(Source), filename:nativename(Dest)]),
                [{use_stdout, false}, return_on_error]),
    case length(R) > 0 of
        %% when xcopy fails, stdout is empty and and error message is printed
        %% to stderr (which is redirected to nul)
        true -> ok;
        false ->
            {error, lists:flatten(
                      io_lib:format("Failed to xcopy from ~s to ~s~n",
                                    [Source, Dest]))}
    end.

cp_r_win32({true, SourceDir}, {true, DestDir}) ->
    %% from directory to directory
    SourceBase = filename:basename(SourceDir),
    ok = case file:make_dir(filename:join(DestDir, SourceBase)) of
             {error, eexist} -> ok;
             Other -> Other
         end,
    ok = xcopy_win32(SourceDir, filename:join(DestDir, SourceBase));
cp_r_win32({false, Source} = S,{true, DestDir}) ->
    %% from file to directory
    cp_r_win32(S, {false, filename:join(DestDir, filename:basename(Source))});
cp_r_win32({false, Source},{false, Dest}) ->
    %% from file to file
    {ok,_} = file:copy(Source, Dest),
    ok;
cp_r_win32({true, SourceDir},{false,DestDir}) -> 
    IsFile = filelib:is_file(DestDir),
    case IsFile of
        true -> 
            %% From Directory to file? This shouldn't happen
            {error,[{rebar_file_utils,cp_r_win32},
                        {directory_to_file_makes_no_sense,
                            {source,SourceDir},{dest,DestDir}}]};
        false ->
            %% Specifying a target directory that doesn't currently exist.
            %% So Let's attempt to create this directory
            %% Will not recursively create parent directories
            ok = case file:make_dir(DestDir) of
                     {error, eexist} -> ok;
                     Other -> Other
                 end,
            ok = xcopy_win32(SourceDir, DestDir)
    end;
cp_r_win32(Source,Dest) ->
    Dst = {filelib:is_dir(Dest), Dest},
    lists:foreach(fun(Src) ->
                          ok = cp_r_win32({filelib:is_dir(Src), Src}, Dst)
                  end, filelib:wildcard(Source)),
    ok.

%% Shell Command Stuff (from rebar_utils)
sh(Command0, Options0) ->
    % ?CONSOLE("sh info:\n\tcwd: ~p\n\tcmd: ~s\n", [get_cwd(), Command0]),
    % ?DEBUG("\topts: ~p\n", [Options0]),

    DefaultOptions = [use_stdout, abort_on_error],
    Options = [expand_sh_flag(V)
               || V <- proplists:compact(Options0 ++ DefaultOptions)],

    ErrorHandler = proplists:get_value(error_handler, Options),
    OutputHandler = proplists:get_value(output_handler, Options),

    Command = patch_on_windows(Command0, proplists:get_value(env, Options, [])),
    PortSettings = proplists:get_all_values(port_settings, Options) ++
        [exit_status, {line, 16384}, use_stdio, stderr_to_stdout, hide],
    Port = open_port({spawn, Command}, PortSettings),

    case sh_loop(Port, OutputHandler, []) of
        {ok, _Output} = Ok ->
            Ok;
        {error, {_Rc, _Output}=Err} ->
            ErrorHandler(Command, Err)
    end.

%%get_cwd() ->
%%	{ok,Dir} = file:get_cwd(),
%%	Dir.

patch_on_windows(Cmd, Env) ->
    case os:type() of
        {win32,nt} ->
            "cmd /q /c "
                ++ lists:foldl(fun({Key, Value}, Acc) ->
                                       expand_env_variable(Acc, Key, Value)
                               end, Cmd, Env);
        _ ->
            Cmd
    end.

expand_env_variable(InStr, VarName, RawVarValue) ->
    case string:chr(InStr, $$) of
        0 ->
            %% No variables to expand
            InStr;
        _ ->
            VarValue = re:replace(RawVarValue, "\\\\", "\\\\\\\\", [global]),
            %% Use a regex to match/replace:
            %% Given variable "FOO": match $FOO\s | $FOOeol | ${FOO}
            RegEx = io_lib:format("\\\$(~s(\\s|$)|{~s})", [VarName, VarName]),
            ReOpts = [global, {return, list}],
            re:replace(InStr, RegEx, [VarValue, "\\2"], ReOpts)
    end.

sh_loop(Port, Fun, Acc) ->
    receive
        {Port, {data, {eol, Line}}} ->
            sh_loop(Port, Fun, Fun(Line ++ "\n", Acc));
        {Port, {data, {noeol, Line}}} ->
            sh_loop(Port, Fun, Fun(Line, Acc));
        {Port, {exit_status, 0}} ->
            {ok, lists:flatten(lists:reverse(Acc))};
        {Port, {exit_status, Rc}} ->
            {error, {Rc, lists:flatten(lists:reverse(Acc))}}
    end.

escape_spaces(Str) ->
    re:replace(Str, " ", "\\\\ ", [global, {return, list}]).


log_and_abort(Message) ->
	?CONSOLE("Aborting: ~s ~n",[Message]).


         
expand_sh_flag(return_on_error) ->
    {error_handler,
     fun(_Command, Err) ->
             {error, Err}
     end};
expand_sh_flag({abort_on_error, Message}) ->
    {error_handler,
		fun(Cmd,Err) ->
				log_and_abort({Message,{Cmd,Err}})
		end};
expand_sh_flag(abort_on_error) ->
	expand_sh_flag({abort_on_error, error});
expand_sh_flag(use_stdout) ->
    {output_handler,
     fun(Line, Acc) ->
             ?CONSOLE("~s", [Line]),
             [Line | Acc]
     end};
expand_sh_flag({use_stdout, false}) ->
    {output_handler,
     fun(Line, Acc) ->
             [Line | Acc]
     end};
expand_sh_flag({cd, _CdArg} = Cd) ->
    {port_settings, Cd};
expand_sh_flag({env, _EnvArg} = Env) ->
    {port_settings, Env}.


<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
















































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted rel/overlay/common/etc/app.config.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
%% -*- mode: erlang -*-
[
    {nitrogen_core, [
        % If a signkey is not specified, then Nitrogen uses the Erlang cookie.
        % {signkey, "SECRET"}, 

        % Default session timeout is 20 minutes.
        % {session_timeout, 20},

        % Specify a session cookie name. Uses "wf" by default.
        % {cookie_name, "wf"},
		
		% Setting the module_prefix to anything other than "" will change the
		% behaviour of the dynamic route handler (the default route handler) to
		% prefix page modules with it's value followed by an underscore.  For
		% example, setting module_prefix to "web" will make your page module
		% for "/mypage" be called "web_mypage".
		% {module_prefix, ""}
    ]},

    %% SASL config
    {sasl, [
        {sasl_error_logger, {file, "log/sasl-error.log"}},
        {errlog_type, error},
        {error_logger_mf_dir, "log/sasl"},      % Log directory
        {error_logger_mf_maxbytes, 10485760},   % 10 MB max file size
        {error_logger_mf_maxfiles, 5}           % 5 files max
    ]}
].
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


























































Deleted rel/overlay/common/etc/simple_bridge.config.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
%% vim: ts=4 sw=4 et ft=erlang
[
    {simple_bridge, [

        {handler, nitrogen},
        %% the name of the simple_bridge handler module, which should not
        %% change unless you're doing something custom to set up the context
        %% and simple_bridge, and also to interact with the request in a
        %% non-standard way. Generally speaking, it's not recommended to change
        %% this unless you really know what you are doing.

        {backend, BACKEND}, 
        %% cowboy | inets | mochiweb | webmachine | yaws

        {address, "0.0.0.0"},       
        %% IP address to bind, either in tuple format or string

        {port, 8000},               
        %% Port to bind

        {document_root, "./site/static"}, 
        %% The path on the local machine to handle static files

        {static_paths, ["js/", "css/", "images/", "nitrogen/", "favicon.ico"]},
        %% The list of paths to be automatically translated to static paths by simple_bridge


        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        %% FILE UPLOAD SETTINGS
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

        {max_post_size, 10},
        %% No multipart request greater than above will be accepted. Units are
        %% MB
        
        {max_file_size, 10},
        %% No single uploaded file will be accepted greater than the above.
        %% Units are MB.

        {max_file_in_memory_size,  0},
        %% If a file is less than the above, then instead of writing the file
        %% to disk, it'll be retained in memory and can be retrieved by
        %% sb_uploaded_file:data/1. See the README for more info.

        {scratch_dir, "./scratch"}
        %% This is the location of the temp directory where uploaded files will
        %% be placed.

        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        %% BACKEND-SPECIFIC DISPATCH TABLES:
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

        %% {webmachine_dispatch, DispatchTable},
        %% Webmachine dispatch table override (ignores static_paths above)

        %% {webmachine_dispatch_function, {Module, Function}}
        %% A Module:Function() that when evaluated will return a dispatch table
        %% for Webmachine, again ignores the static_paths above

        %% {cowboy_dispatch, DispatchTable}
        %% Cowboy dispatch table override (ignores static_paths)

        %% {cowboy_dispatch_function, {Module, Function}}
        %% A Module:Function() that when evaluated will return a dispatch tavle
        %% for Cowboy, again ignoring the static_paths above

    ]}
].

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<










































































































































Deleted rel/overlay/common/etc/sync.config.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
%% vim: ts=4 sw=4 et ft=erlang
%% Sync configuration for automatic recompilation
[
    {sync,[

        %% growl: Desktop notifications
        %% valid values: all | none | [success | warning | error]
        %% default: all
        {growl, all},
        
        %% log: Console notifications
        %% valid values: all | none | [success | warnings | errors]
        %% default: all
        {log, all},    
                       
        %% non_descendant: How to handle beams whose original source path is
        %% not a descendant of the current working directory.
        %%
        %% valid values: fix | allow | ignore
        %% * fix = attempt to find source files under current directory
        %% * allow = don't do anything special, use the non-descendant path and
        %%   watch that file
        %% * ignore = don't watch that module at all and ignore any changes to
        %%   its source path
        %% default: fix
        {non_descendant, fix},

        %% excluded_modules: Ignore any modules listed
        %% default: []
        {excluded_modules, []},

        %% executable: Identify the program that you want run by the "growl" notifications
        %% valid values: auto | notifu | 'notify-send' | growlnotify | emacsclient
        %% * auto = allow sync to autodetect which program to run
        %% * growlnotify = Use Growl for Mac
        %% * 'notify-send' = Use libnotify for Linux
        %% * notifu = The notifu program for Windows
        %% * emacsclient = Emacs notifications
        %% default: auto
        {executable, auto}
    ]}
].


<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
























































































Deleted rel/overlay/common/etc/vm.args.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

## Name of the nitrogen node
-name {{PROJECT}}@127.0.0.1

## Heartbeat management; auto-restarts VM if it dies or becomes unresponsive
## (Disabled by default..use with caution!)
##-heart

## Enable kernel poll and a few async threads
+K true
+A 5

## Increase number of concurrent ports/sockets
-env ERL_MAX_PORTS 4096

## Tweak GC to run more often 
-env ERL_FULLSWEEP_AFTER 10

## Include .beam files for site.
-pa ./site/ebin

## Include libraries and rebar dependency paths
-env ERL_LIBS ./lib

## Run code at startup.
-eval "application:start(nitrogen)"


<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
























































Deleted rel/overlay/common/log/sasl/.empty.

Deleted rel/overlay/common/plugins.config.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
%% vim: ts=2 sw=2 et ft=erlang
%% Nitrogen Plugin Installer Configuration
%% 
%% This will tell the plugin-installer script where to put Nitrogen plugin
%% information it finds.
%%

%% plugins_hrl tells the Nitrogen plugin installer where to put the .hrl file
%% containing links to all your plugins' respective header files.
%% The default is "./site/include/plugins.hrl".
{plugins_hrl, "./site/include/plugins.hrl"}.

%% static_dir tells the Nitrogen plugin installer where to copy your plugins'
%% static resources (images, js, etc).
%% The default is "./site/static/plugins"
{static_dir, "./site/static/plugins"}.

%% template_dir tells the Nitrogne plugin installer where to copy your plugins'
%% template files.
%% The default is "./site/templates"
{template_dir, "./site/templates/plugins"}.

%% copy_mode determines if static resources are copied or merely symlinked.
%% Keep in mind, symlinks do not work on Windows, so "copy" is the default.
%% Valid values are the atoms 'copy' or 'link'
%% Default: copy
{copy_mode, copy}.
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






















































Deleted rel/overlay/common/site/.prototypes/action.erl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
%% -*- mode: nitrogen -*-
%% vim: ts=4 sw=4 et
-module (action_[[[NAME]]]).
-include_lib ("nitrogen_core/include/wf.hrl").
-include("records.hrl").
-export([
    render_action/1
]).

%% move the following record definition to site/include/records.hrl
-record([[[NAME]]], {?ACTION_BASE(action_[[[NAME]]]),
        attr1 :: any(),
        attr2 :: any()
    }).

-spec render_action(#[[[NAME]]]{}) -> actions().
render_action(_Record = #[[[NAME]]]{}) ->
    "alert('Hello, from [[[NAME]]]!');".
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




































Deleted rel/overlay/common/site/.prototypes/element.erl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
%% -*- mode: nitrogen -*-
%% vim: ts=4 sw=4 et
-module (element_[[[NAME]]]).
-include_lib("nitrogen_core/include/wf.hrl").
-include("records.hrl").
-export([
    reflect/0,
    render_element/1
]).

%% Move the following record definition to records.hrl:
-record([[[NAME]]], {?ELEMENT_BASE(element_[[[NAME]]]),
        attr1 :: any(),
        attr2 :: any()
    }).

-spec reflect() -> [atom()].
reflect() -> record_info(fields, [[[NAME]]]).

-spec render_element(#[[[NAME]]]{}) -> body().
render_element(_Record = #[[[NAME]]]{}) ->
    "<b>Hello from [[[NAME]]]</b>".
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<












































Deleted rel/overlay/common/site/.prototypes/page.erl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
%% -*- mode: nitrogen -*-
%% vim: ts=4 sw=4 et
-module ([[[NAME]]]).
-compile(export_all).
-include_lib("nitrogen_core/include/wf.hrl").
-include("records.hrl").

main() -> #template { file="./site/templates/bare.html" }.

title() -> "Hello from [[[NAME]]].erl!".

body() -> 
    [
        #panel { style="margin: 50px 100px;", body=[
            #span { text="Hello from [[[NAME]]].erl!" },

            #p{},
            #button { text="Click me!", postback=click },

            #p{},
            #panel { id=placeholder }
        ]}
    ].
	
event(click) ->
    wf:insert_top(placeholder, "<p>You clicked the button!").
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<




















































Deleted rel/overlay/common/site/.prototypes/plugin.app.src.

1
2
3
4
5
6
7
8
9
10
11
{application, [[[NAME]]],
 [
  {description, "A sample plugin for the Nitrogen Web Framework"},
  {vsn, ""},
  {registered, []},
  {applications, [
                  kernel,
                  stdlib
                 ]},
  {env, []}
 ]}.
<
<
<
<
<
<
<
<
<
<
<






















Deleted rel/overlay/common/site/.prototypes/plugin.tgz.

cannot compute difference between binary files

Deleted rel/overlay/common/site/.prototypes/plugin_page.erl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
%% -*- mode: nitrogen -*-
%% vim: ts=4 sw=4 et
-module ([[[NAME]]]).
-compile(export_all).
-include_lib("nitrogen_core/include/wf.hrl").
-include("records.hrl").

main() -> #template { file="./site/templates/bare.html" }.

title() -> "Testing plugin [[[NAME]]]!".

body() -> 
	wf:wire(#sample_action{}),
	[
		"You should see some more content and an alert: <b>",
		#sample_element{}, "</b>"
	].
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


































Deleted rel/overlay/common/site/ebin/.empty.

Deleted rel/overlay/common/site/include/plugins.hrl.

1
2
%% This file starts empty and will be automatically generated. It's not
%% recommended to manually edit this file
<
<




Deleted rel/overlay/common/site/include/records.hrl.

1
2
3
4
%% Include the automatically generated plugins directory
-include("plugins.hrl").

%% Include any application-specific custom elements, actions, or validators below
<
<
<
<








Deleted rel/overlay/common/site/src/actions/.ignore.

Deleted rel/overlay/common/site/src/elements/.ignore.

Deleted rel/overlay/common/site/src/index.erl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
%% -*- mode: nitrogen -*-
-module (index).
-compile(export_all).
-include_lib("nitrogen_core/include/wf.hrl").

main() -> #template { file="./site/templates/bare.html" }.

title() -> "Welcome to Nitrogen".

body() ->
    #container_12 { body=[
        #grid_8 { alpha=true, prefix=2, suffix=2, omega=true, body=inner_body() }
    ]}.

inner_body() -> 
    [
        #h1 { text="Welcome to Nitrogen" },
        #p{},
        "
        If you can see this page, then your Nitrogen server is up and
        running. Click the button below to test postbacks.
        ",
        #p{}, 	
        #button { id=button, text="Click me!", postback=click },
		#p{},
        "
        Run <b>./bin/dev help</b> to see some useful developer commands.
        ",
		#p{},
		"
		<b>Want to see the ",#link{text="Sample Nitrogen jQuery Mobile Page",url="/mobile"},"?</b>
		"
    ].
	
event(click) ->
    wf:replace(button, #panel { 
        body="You clicked the button!", 
        actions=#effect { effect=highlight }
    }).
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<














































































Deleted rel/overlay/common/site/src/mobile.erl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
%% -*- mode: nitrogen -*-
%% vim: ts=4 sw=4 et
-module(mobile).
-include_lib("nitrogen_core/include/wf.hrl").
-compile(export_all).
-author("Jesse Gumm (gumm@sigma-star.com)").

main() -> #template{file="./site/templates/mobile.html"}.

title() -> "Nitrogen Web Framework - Mobile Sample".

body() ->
    [
        "If you can see this, then your Nitrogen installation is working.",
        #p{},
        "Go ahead and enable the sample menu below to test postbacks and links",
        #p{},
        #mobile_toggle{
            on_text="Menu Visible",
            off_text="Menu Hidden",
            selected="off",
            postback=toggle_menu,
            id=menu_on,
            width=200
        },
        #p{},
        #mobile_list{
            id=menu,
            theme=a,
            inset=true,
            style="display:none",
            body=[
                #mobile_list_divider{class=c, text="Sample Mobile Menu"},
                mobile_list_link("Non-mobile Sample Page","/"),
                mobile_list_link("Nitrogen Home","http://nitrogenproject.com"),
                mobile_list_link("jQuery Mobile Home","http://jquerymobile.com"),
                mobile_list_link("Erlang Home","http://erlang.org")
            ]
        }
    ].

mobile_list_link(Text,URL) ->
    #mobile_listitem{
        theme=c,
        body=#link{text=Text, url=URL, mobile_target=false}
    }.

event(toggle_menu) ->
    ShowMenu = wf:q(menu_on),
    case ShowMenu of
        "on" -> wf:wire(menu,#appear{});
        "off" -> wf:wire(menu,#fade{})
    end.
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<










































































































Deleted rel/overlay/common/site/src/nitrogen.app.src.

1
2
3
4
5
6
7
8
9
{application, nitrogen,
 [
  {description, "My Nitrogen Web Project"},
  {vsn, "1"},
  {registered, []},
  {applications, [kernel, stdlib]},
  {mod, { nitrogen_app, []}},
  {env, []}
 ]}.
<
<
<
<
<
<
<
<
<


















Deleted rel/overlay/common/site/src/nitrogen_app.erl.

1
2
3
4
5
6
7
8
9
10
11
12
13
-module(nitrogen_app).
-behaviour(application).
-export([start/2, stop/1]).

%% ===================================================================
%% Application callbacks
%% ===================================================================

start(_StartType, _StartArgs) ->
    nitrogen_sup:start_link().

stop(_State) ->
    ok.
<
<
<
<
<
<
<
<
<
<
<
<
<


























Deleted rel/overlay/common/site/src/nitrogen_main_handler.erl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
%% vim: ts=4 sw=4 et
-module(nitrogen_main_handler).
-export([
    run/0,
    ws_init/0
]).

handlers() ->
    %% Put any custom handlers here
    %% See http://nitrogenproject.com/doc/handlers.html
    %% Example:
    %%
    %%   nitrogen:handler(MySecurityHandler, HandlerConfig),
    %%
    %%
    %% The following enables the debug_crash_handler for development. If you
    %% wish to use the default_crash_handler, which just spits out "Internal
    %% Server Error", comment or delete this next line.
    nitrogen:handler(debug_crash_handler, []),
    ok.

ws_init() ->
    handlers().

run() ->
    handlers(),
    wf_core:run().
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






















































Deleted rel/overlay/common/site/src/nitrogen_sup.erl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
%% -*- mode: nitrogen -*-
%% vim: ts=4 sw=4 et
-module(nitrogen_sup).
-behaviour(supervisor).
-export([
    start_link/0,
    init/1
]).

%% Helper macro for declaring children of supervisor
-define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 5000, Type, [I]}).

%% ===================================================================
%% API functions
%% ===================================================================

start_link() ->
    supervisor:start_link({local, ?MODULE}, ?MODULE, []).

%% ===================================================================
%% Supervisor callbacks
%% ===================================================================

init([]) ->
    application:load(nitrogen_core),
    application:start(nitro_cache),
    application:start(crypto),
    application:start(nprocreg),
    application:start(simple_bridge),

    {ok, { {one_for_one, 5, 10}, []} }.
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






























































Deleted rel/overlay/common/site/static/css/style.css.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
/***** CSS RESET *****/
html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td{margin:0;padding:0;border:0;outline:0;font-size:100%;vertical-align:baseline;background:transparent}body{line-height:1}blockquote,q{quotes:none}blockquote:before,blockquote:after,q:before,q:after{content:'';content:none}:focus{outline:0}ins{text-decoration:none}del{text-decoration:line-through}table{border-collapse:collapse;border-spacing:0}

/***** STYLE *****/

body { 
    font-family: "Lucida Grande", "Segoe UI", Tahoma, Helvetica, Arial, sans-serif; 
    font-size: 16px;
    line-height: 32px;
}

.container_12 {
    margin-top: 40px;
}

h1 {
    font-family: Arial, sans-serif;
    font-weight: bold;
    padding-bottom: 7px;
    border-bottom: dashed 1px #DDD;
    text-transform: uppercase;
    font-size: 1.875em;
    line-height: 1.066667em;
    margin-top: 1.6em;
    margin-bottom: 1.6em;
}

h2 {
    font-family: Arial, sans-serif;
    font-size: 1.5em;
    line-height: 1.333333em;
    margin-top: 1.6em;
    margin-bottom: 1.6em;
}

h3 {
    font-family: Arial, sans-serif;
    font-size: 1.25em;
    line-height: 1.6em;
    margin-top: 1.333333em;
    margin-bottom: 1.333333em;
}

p {
    font-size: 1em;
    line-height: 2em;
    margin-top: 2em;
    margin-bottom: 2em;
}


a, a:visited { 
    color: #4488FF
    text-decoration: none; 
}

a:hover, a:active { 
    text-decoration: underline; 
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






















































































































Deleted rel/overlay/common/site/static/images/spinner.gif.

cannot compute difference between binary files

Deleted rel/overlay/common/site/static/js/.empty.

Deleted rel/overlay/common/site/templates/bare.html.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf8">
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <title>[[[page:title()]]]</title>
  <script src='/nitrogen/jquery.js' type='text/javascript' charset='utf-8'></script>
  <script src='/nitrogen/jquery-ui.min.js' type='text/javascript' charset='utf-8'></script>
  <script src='/nitrogen/livevalidation.min.js' type='text/javascript' charset='utf-8'></script>
  <script src='/nitrogen/nitrogen.min.js' type='text/javascript' charset='utf-8'></script>
  <script src='/nitrogen/bert.min.js' type='text/javascript' charset='utf-8'></script>
  <link rel="stylesheet" href="/nitrogen/jquery-ui/jquery.ui.all.css" type="text/css" media="screen" charset="utf-8" />
  <link rel="stylesheet" href="/nitrogen/nitrogen.css" />
  <link rel="stylesheet" href="/css/style.css" />
</head>
<body>
[[[page:body()]]]
<script>
[[[script]]]
</script>
</body>
</html>
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<












































Deleted rel/overlay/common/site/templates/mobile.html.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<!DOCTYPE html>
<html lang="en">
	<head>
		<title>[[[page:title()]]]</title>
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 
		<meta charset="utf8" />
		<meta name="viewport" content="width=device-width, initial-scale=1"> 


		<script type="text/javascript" src="/nitrogen/jquery.js"></script>
		<script type="text/javascript" src="/nitrogen/jquery.mobile.min.js"></script>
		<script type="text/javascript" src="/nitrogen/bert.min.js"></script>
		<script src='/nitrogen/livevalidation.min.js' type='text/javascript' charset='utf-8'></script>
		<script src='/nitrogen/nitrogen.min.js' type='text/javascript' charset='utf-8'></script>
		<script src='/nitrogen/nitrogen_jqm.js' type='text/javascript' charset='utf-8'></script>
		<link rel="stylesheet" href="/nitrogen/nitrogen.css" charset='utf-8'></script>
		<link rel="stylesheet" href="/nitrogen/jquery.mobile.min.css" />
	</head>
	<body>
		<div data-role="page" id="pagediv" data-code="[[[mobile_script]]]">
			<div data-role="header"> 
				<h1>[[[page:title()]]]</h1> 
			</div> 

			<div data-role="content">
				[[[page:body()]]]
			</div>

			<div data-role="footer"> 
				<h4>
					&copy; 2012 - Nitrogen Web Framework
				</h4> 
			</div>
		</div>
	</body>
</html>
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<








































































Deleted rel/overlay/cowboy.deps.

1
    {cowboy,        {git, "git://github.com/ninenines/cowboy",         {tag, "2.7.0"}}},
<


Deleted rel/overlay/inets.deps.

1
2
    %% Inets has no external dependencies
    {mimetypes, {git, "git://github.com/spawngrid/mimetypes.git", {branch, master}}},
<
<




Deleted rel/overlay/mochiweb.deps.

1
    {mochiweb, {git, "git://github.com/mochi/mochiweb.git",    {tag, "v2.20.1"}}},
<


Changes to rel/overlay/rebar.config.src.

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
    %% These lines will be replaced with any platform specific dependencies.
    %% The platform-sepecific dependencies can be located in
    %% rel/overlay/<platform>/rebar.config.deps
    %% END_PLATFORM_DEPENDENCIES

    %% Uncomment the following lines and comment the bottom lines with specific
    %% tags to always pull the latest versions
    {simple_bridge, {git, "git://github.com/nitrogen/simple_bridge",{branch, master}}},
    {qdate,         {git, "git://github.com/choptastic/qdate",      {branch, master}}},
    {nprocreg,      {git, "git://github.com/nitrogen/nprocreg",     {branch, master}}},
    {nitrogen_core, {git, "git://github.com/nitrogen/nitrogen_core",{branch, master}}},
    {sync,          {git, "git://github.com/rustyio/sync",          {branch, master}}},
    {nitro_cache,   {git, "git://github.com/nitrogen/nitro_cache",  {branch, master}}}

    %% Get specific tagged version
    % {simple_bridge, {git, "git://github.com/nitrogen/simple_bridge",{tag, "v2.1.0"}}},
    % {qdate,         {git, "git://github.com/choptastic/qdate",      {tag, "0.5.0"}}},
    % {nprocreg,      {git, "git://github.com/nitrogen/nprocreg",     {tag, "v0.3.0"}}},
    % {nitrogen_core, {git, "git://github.com/nitrogen/nitrogen_core",{tag, "v2.4.0"}}},
    % {sync,          {git, "git://github.com/rustyio/sync",          {tag, "v0.2.0"}}},
    % {nitro_cache,   {git, "git://github.com/nitrogen/nitro_cache",  {tag, "0.4.0"}}}
]}.







|
|
|
|
|
|


|
|
|
|
|
|

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
    %% These lines will be replaced with any platform specific dependencies.
    %% The platform-sepecific dependencies can be located in
    %% rel/overlay/<platform>/rebar.config.deps
    %% END_PLATFORM_DEPENDENCIES

    %% Uncomment the following lines and comment the bottom lines with specific
    %% tags to always pull the latest versions
    {simple_bridge, {git, "https://github.com/nitrogen/simple_bridge",{branch, master}}},
    {qdate,         {git, "https://github.com/choptastic/qdate",      {branch, master}}},
    {nprocreg,      {git, "https://github.com/nitrogen/nprocreg",     {branch, master}}},
    {nitrogen_core, {git, "https://github.com/nitrogen/nitrogen_core",{branch, master}}},
    {sync,          {git, "https://github.com/rustyio/sync",          {branch, master}}},
    {nitro_cache,   {git, "https://github.com/nitrogen/nitro_cache",  {branch, master}}}

    %% Get specific tagged version
    % {simple_bridge, {git, "https://github.com/nitrogen/simple_bridge",{tag, "v2.1.0"}}},
    % {qdate,         {git, "https://github.com/choptastic/qdate",      {tag, "0.5.0"}}},
    % {nprocreg,      {git, "https://github.com/nitrogen/nprocreg",     {tag, "v0.3.0"}}},
    % {nitrogen_core, {git, "https://github.com/nitrogen/nitrogen_core",{tag, "v2.4.0"}}},
    % {sync,          {git, "https://github.com/rustyio/sync",          {tag, "v0.2.0"}}},
    % {nitro_cache,   {git, "https://github.com/nitrogen/nitro_cache",  {tag, "0.4.0"}}}
]}.

Deleted rel/overlay/slim/fix-slim-release.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#!/usr/bin/env bash

## SCRIPT TO FIX SLIM RELEASES

## This script is a nasty bit of hackery.  Basically, instead of doing any kind
## of analysis, it solves the "erlang version mismatch" between a generated slim
## release and the installed erlang version.  Rather than using a scalpel and
## carefully upgrading scripts and regenerating the boot files, it activates
## "HULK SMASH MODE" to solve this problem:

## 1) It removes the releases directory
## 2) it clones nitrogen into /tmp
## 3) it generates a slim_release in /tmp/myapp
## 4) It moves the newly generated releases directory into our project's directory

## This is as inelegant as can possibly be done, but it works.


# so we can get back
home=`pwd`

# nasty: clone nitrogen and generate a slim release using the current version
# of erlang so we can just copy the releases directory. A little embarrassingly
# stupid.
mkdir -p /tmp/nitrogen
cd /tmp
git clone git://github.com/nitrogen/nitrogen
cd nitrogen
## The generated release doesn't need anything more, and slim_inets has the
## fewest dependencies to build and fetch (since dependencies don't do anything
## for our releases directory anyway)
make slim_inets

# back to project dir
cd $home
rm -fr releases
mv /tmp/myapp/releases .

# clean up
rm -fr /tmp/nitrogen
rm -fr /tmp/myapp
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


















































































Deleted rel/overlay/webmachine.deps.

1
2
%    {mochiweb,   {git, "git://github.com/mochi/mochiweb.git",    {tag, "v2.20.1"}}},
    {webmachine, {git, "git://github.com/webmachine/webmachine.git",  {tag, "518c94"}}},
<
<




Deleted rel/overlay/yaws.deps.

1
    {yaws, {git, "git://github.com/erlyaws/yaws",	{tag, "yaws-2.0.8"}}},
<


Deleted rel/reltool_base.config.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
%% vim: ts=4 sw=4 et ft=erlang

{sys, [
    {rel, "nitrogen", "2.4.0",
        [
            kernel,
            stdlib,
            sasl,
            crypto,
            runtime_tools,
            xmerl,
            compiler,
            ssl,
            common_test,
            parsetools
    ]},
    {rel, "start_clean", "",
        [
            kernel,
            stdlib
    ]},
    {boot_rel, "nitrogen"},
    {excl_sys_filters, [
        "^bin/.*",
        "^usr.*",
        "^doc.*",
        "^README$",
        "^Install\.ini$",
        "^Install\.exe$",
        "^Uninstall\.exe$",
        "^COPYRIGHT$",
        "^PR\.template$"
    ]},
    {excl_archive_filters, [".*"]},
    {incl_cond, include}
]}.

{overlay, [
    %% Copy common files...
    {copy,  "./overlay/common/*"},
    {copy,  "./overlay/common/.gitignore"},
    {copy,  "./overlay/erts/*", "{{erts_vsn}}/bin"}
]}.
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






















































































Deleted rel/reltool_slim.config.

1
2
3
4
5
%% vim: ts=4 sw=4 et ft=erlang
{overlay, [
    %% Copy slim-release-specific files
    {copy,  "./overlay/slim/*"}
]}.
<
<
<
<
<










Deleted rel/reltool_win.config.

1
2
3
4
5
%% vim: ts=4 sw=4 et ft=erlang
{overlay, [
    %% Copy windows-specific files
    {copy,  "./overlay/win/files/*"}
]}.
<
<
<
<
<










Added scripts/assemble_config.escript.















































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#!/usr/bin/env escript
%% -*- erlang -*-
%% vim: ts=4 sw=4 et ft=erlang
%%
%% Coyright 2020 - Jesse Gumm
%% MIT License
%%
%%
%% Usage: ./assemble_config.escript <DirectoryOfConfigFiles> <PathToNewConsolidatedConfigFile>
%%
%% Takes the a directory, loads all the .config files in it, and generates a new consolidated config file


main([ConfDir, OutFile]) ->
    Files0 = filelib:wildcard(filename:join(ConfDir,"*.config")),
    Files = Files0 -- [OutFile], %% We don't want to load our master config file
    Terms = lists:foldl(fun(F, Acc) ->
        io:format("CONFIG ASSEMBLER: Loading ~s...",[F]),
        case file:consult(F) of
            {error, {LineNo, Module, Error}} ->
                io:format("FAIL! Reason: ~s on line ~p (reported by ~p)~n",[Error, LineNo, Module]),
                halt(1);
            {error, Error} ->
                io:format("FAIL! Reason: ~p~n",[Error]),
                halt(1);
            {ok, Config} ->
                io:format("Success!~n"),
                Acc ++ Config
        end
    end, [], Files),
    io:format("CONFIG ASSEMBLER: Generating ~s...",[OutFile]),
    TopComment = io_lib:format("%% This file was autogenerated with the command: ~s ~s ~s",[escript:script_name(), ConfDir, OutFile]),
    case file:write_file(OutFile, io_lib:format("~s~n~p.", [TopComment, Terms])) of
        ok ->
            io:format("Success!~n");
        {error, Error} ->
            io:format("FAIL! Reason: ~p~n",[Error]),
            halt(1)
    end.

Added scripts/convert_to_rebar3.sh.















































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/bin/sh

mv site/src .
ln -s site/src ../src
mv site/include .
ln -s site/include ../include
rm -fr site/ebin
rm -fr releases
rm -fr fix-slim-release
rm -fr lib
mv bin/nitrogen bin/nitrogen.old
mv bin/dev bin/dev.old
mv Makefile Makefile.old

## Download new Makefile

## download rebar3

## download assemble_config.escript

## download new nitrogen/bin

## rewrite rebar.config based on current deps

Added src/nitrogen_plugin.app.src.





























>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
{application, nitrogen_plugin,
 [{description, "A rebar plugin"},
  {vsn, "0.1.0"},
  {registered, []},
  {applications,
   [kernel,
    stdlib
   ]},
  {env,[]},
  {modules, []},

  {licenses, ["Apache 2.0"]},
  {links, []}
 ]}.

Added src/nitrogen_plugin.erl.

















>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
-module(nitrogen_plugin).

-export([init/1]).

-spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
init(State) ->
    {ok, State1} = nitrogen_plugin_prv:init(State),
    {ok, State1}.

Added src/nitrogen_plugin_prv.erl.

































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
-module(nitrogen_plugin_prv).

-export([init/1, do/1, format_error/1]).

-define(PROVIDER, nitrogen_plugin).
-define(DEPS, [app_discovery]).

%% ===================================================================
%% Public API
%% ===================================================================
-spec init(rebar_state:t()) -> {ok, rebar_state:t()}.
init(State) ->
    Provider = providers:create([
            {name, ?PROVIDER},            % The 'user friendly' name of the task
            {module, ?MODULE},            % The module implementation of the task
            {bare, true},                 % The task can be run by the user, always true
            {deps, ?DEPS},                % The list of dependencies
            {example, "rebar3 nitrogen_plugin"}, % How to use the plugin
            {opts, []},                   % list of options understood by the plugin
            {short_desc, "A rebar plugin"},
            {desc, "A rebar plugin"}
    ]),
    {ok, rebar_state:add_provider(State, Provider)}.


-spec do(rebar_state:t()) -> {ok, rebar_state:t()} | {error, string()}.
do(State) ->
    {ok, State}.

-spec format_error(any()) ->  iolist().
format_error(Reason) ->
    io_lib:format("~p", [Reason]).

Added templates/backends/.gitignore.





>
>
1
2
rebar.*.config
rebar.*.config.script

Added templates/backends/build_backend_configs.escript.

























































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#!/usr/bin/env escript
%% vim: ts=4 sw=4 et ft=erlang

main([]) ->
    Backends = [
        "cowboy",
        "inets",
        "mochiweb",
        "webmachine",
        "yaws"
    ],
    [do_backend(B) || B <- Backends].

do_backend(Backend) ->
    RebarConfig = "rebar." ++ Backend ++ ".config",
    RebarConfigScript = RebarConfig ++ ".script",
    io:format("Generating ~s and ~s~n", [RebarConfig, RebarConfigScript]),

    DepsFile = "sources/" ++ Backend ++ ".deps",
    DepsScriptFile = DepsFile ++ ".script",
    LoadersFile = "sources/" ++ Backend ++ ".loaders",
    
    DepsComment = "%% BACKEND_DEPS",
    LoadersComment = "%% BACKEND_LOADERS",
    DepsScriptComment = "%% BACKEND_SCRIPT",

    replace("sources/rebar.base.config", RebarConfig, DepsComment, DepsFile),
    replace(RebarConfig, RebarConfig, LoadersComment, LoadersFile),
    replace("sources/rebar.base.config.script", RebarConfigScript, DepsScriptComment, DepsScriptFile).


replace(FromFile, ToFile, Comment, ContentsFile) ->
    {ok, FileBin} = file:read_file(FromFile),
    {ok, ContentsBin} = file:read_file(ContentsFile),
    
    FileStr = chomp(binary_to_list(FileBin)),
    ContentsStr = chomp(binary_to_list(ContentsBin)),

    NewStr = string:replace(FileStr, Comment, ContentsStr),

    ok = file:write_file(ToFile, NewStr).

chomp(Str) ->
    string:trim(Str, trailing, "\n").

Added templates/backends/sources/cowboy.deps.



>
1
{cowboy, "2.7.0"}

Added templates/backends/sources/cowboy.deps.script.



>
1
    {cowboy,        {git, "git://github.com/ninenines/cowboy",         {tag, "2.7.0"}}}

Added templates/backends/sources/cowboy.loaders.



>
1
{cowboy, load}

Added templates/backends/sources/inets.deps.



>
1
mimetypes

Added templates/backends/sources/inets.deps.script.





>
>
1
2
    %% Inets has no external dependencies
    {mimetypes, {git, "git://github.com/spawngrid/mimetypes.git", {branch, master}}},

Added templates/backends/sources/inets.loaders.



>
1
{mimetypes, load}

Added templates/backends/sources/mochiweb.deps.



>
1
mochiweb

Added templates/backends/sources/mochiweb.deps.script.



>
1
    {mochiweb, {git, "git://github.com/mochi/mochiweb.git",    {tag, "v2.20.1"}}}

Added templates/backends/sources/mochiweb.loaders.



>
1
{mochiweb, load}

Added templates/backends/sources/rebar.base.config.





































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
% vim:ts=4 sw=4 et ft=erlang
{cover_enabled, true}.

{erl_opts, [
    debug_info
%    {i,"site/include"}
]}.

{relx, [{release, {{{name}}, "0.0.1" }, [
            sasl,
            %% BACKEND_LOADERS,
            {inets, load},
            {qdate, load},
            {simple_bridge, load},
            {nprocreg, load},
            {nitro_cache, load},
            {nitrogen_core, load},
            {sync, load},
            {{name}}
        ]},
        {sys_config, "etc/autogenerated.config.all"},
        {vm_args, "etc/vm.args"},
        {dev_mode, true},
        {mode, dev},
        {include_erts, {{include_erts}}},
        {extended_start_script, true},
        {overlay, [
            {copy, "site", "site"}
%            {mkdir, "site"},
%            {copy, "site/templates", "site/templates"},
%            {copy, "site/static", "site/static"}
        ]}
       ]
}.


{shell, [
%     {apps, nitrogen},
%     {vm_args, "etc/vm.args"}
]}.

{plugins, [
    rebar3_run
]}.

{deps, [
    %% BACKEND_DEPS,
    {nitrogen_core, {git, "git://github.com/nitrogen/nitrogen_core", {branch, rebar3}}},
    sync
]}.

Added templates/backends/sources/rebar.base.config.script.

































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
%% -*- mode: erlang -*-
%% -*- tab-width: 4;erlang-indent-level: 4;indent-tabs-mode: nil -*-
%% ex: ts=4 sw=4 sts ft=erlang et

case erlang:function_exported(rebar3, main, 1) of
    true -> % rebar3
        CONFIG;
    false -> % rebar 2.x or older
        %% Rebuild deps, possibly including those that have been moved to
        %% profiles
        [{deps, [
            %% BACKEND_SCRIPT,
            {nitrogen_core, {git, "git://github.com/nitrogen/nitrogen_core", {branch, master}}},
            {sync, {git, "git://github.com/rustyio/sync", {branch, master}}}
        ]} | lists:keydelete(deps, 1, CONFIG)]
end.

Added templates/backends/sources/webmachine.deps.



>
1
webmachine

Added templates/backends/sources/webmachine.deps.script.



>
1
    {webmachine, {git, "git://github.com/webmachine/webmachine.git",  {tag, "518c94"}}}

Added templates/backends/sources/webmachine.loaders.





>
>
1
2
{mochiweb, load},
{webmachine, load}

Added templates/backends/sources/yaws.deps.



>
1
yaws

Added templates/backends/sources/yaws.deps.script.



>
1
    {yaws, {git, "git://github.com/erlyaws/yaws",	{tag, "yaws-2.0.8"}}},

Added templates/backends/sources/yaws.loaders.



>
1
{yaws, load}

Added templates/common/.gitignore.





















>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
site/ebin/*
*.sw?
erl_crash.dump
*~
/log
/scratch
lib/nitrogen_core
lib/simple_bridge
lib/nprocreg
lib/sync

Added templates/common/Makefile.

























































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
.PHONY: fix-slim-release test

all: plugins compile

REBAR?=./rebar3

cookie:
	@echo Generating a default cookie in /etc/vm.args
	@(echo -setcookie `openssl rand -base64 50 | head -n1 | sed -e 's/[^a-zA-Z0-9]//g'` >> etc/vm.args)

compile:
	@($(REBAR) compile)

get-deps:
	@(export PATH=`pwd`/`echo erts-*/bin`:$$PATH; echo "Using Erlang in `which erl`"; $(REBAR) get-deps)

update-deps:
	@(export PATH=`pwd`/`echo erts-*/bin`:$$PATH; echo "Using Erlang in `which erl`"; $(REBAR) update-deps)

eunit: get-deps compile
	@(export PATH=`pwd`/`echo erts-*/bin`:$$PATH; echo "Using Erlang in `which erl`"; $(REBAR) skip_deps=true eunit)

copy-static:
	@(mkdir -p priv/static/nitrogen)
	@(cp -r lib/nitrogen_core/www/* priv/static/nitrogen/)

link-static:
	@(ln -s lib/nitrogen_core/www priv/static/nitrogen)

plugins:
	@(escript do-plugins.escript)

rebar2_links: site site/static site/src site/templates site/include

site:
	@echo Making Nitrogen 2 compatible directory structure symlinks
	@(mkdir -p site)

site/static:
	@(ln -s ../priv/static site/static)

site/src:
	@(ln -s ../src site/src)

site/templates:
	@(ln -s ../priv/templates site/templates)

site/include:
	@(ln -s ../include site/include)

#DEPS_PLT=$(CURDIR)/.deps_plt
#DEPS=erts kernel stdlib sasl lib/nitrogen_core lib/simple_bridge lib/nprocreg lib/nitro_cache lib/rekt lib/qdate
#
#$(DEPS_PLT):
#	@echo Building local plt at $(DEPS_PLT)
#	@echo 
#	@(export PATH=`pwd`/`echo erts-*/bin`:$$PATH; echo "Using Dialyzer in `which dialyzer`"; dialyzer --output_plt $(DEPS_PLT) --build_plt --apps $(DEPS) -r ./lib)
#

dialyzer: all $(DEPS_PLT)
	@(export PATH=`pwd`/`echo erts-*/bin`:$$PATH; echo "Using Dialyzer in `which dialyzer`"; dialyzer --fullpath --plt $(DEPS_PLT) -Wrace_conditions -r ./site/ebin)

#update: update-deps copy-static compile
#	@(echo "*** CONGRATULATIONS ***")
#	@(echo "Your Nitrogen installation has been upgraded.")
#	@(echo "You may need to manually merge any changes that may have been made to")
#	@(echo "configuration files as well as the initialization modules:")
#	@(echo "    site/src/nitrogen_sup.erl")
#	@(echo "    site/src/nitrogen_PLATFORM.erl")
#	@(echo "    site/src/nitrogen_app.erl")
#	@(echo "")
#
#upgrade: update
#
#clean:
#	@(export PATH=`pwd`/`echo erts-*/bin`:$$PATH; $(REBAR) clean)

Added templates/common/README.md.



















































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# About

This is an Erlang web application using the [Nitrogen Web
Framework](https://nitrogenproject.com).

# Building

You can rebuild the project by typing:

   make

If this fails, it likely means that its a slim release and Erlang is not
installed on this machine. Please [install
Erlang](https://www.erlang-solutions.com/resources/download.html).

# Running

You can start the application with:

  bin/nitrogen start

which will start it in daemon mode.  You can attach to this started daemon
with:

  bin/nitrogen attach

If you'd rather have an Erlang console right away, rather than starting a
daemon, type:

  bin/nitrogen console

# Config

The rebar.config file controls dependencies and build parameters using the
popular [rebar](http://github.com/rebar/rebar) tool.

The `plugins.config` file controls how Nitrogen plugins are handled.

The files in the `etc` directory control application configuration, including
ports, webserver set up, and the like.  Please see the files there for
configuration options, or view the Nitrogen documentation.

# Code

Dependency libraries (once being built) end up in the `lib` directory.

Source code can be found in `site/src`

Template code is in `site/templates`

Compiled Erlang modules (ebin files) go in `site/ebin`

# Live code reloading

By default Nitrogen comes with an application called [sync](http://github.com/rustyio/sync) which provides automatic code reloading when the related .erl file or .ebin file is updated.  To use this, run the following on the Erlang shell:

  sync:go().

Added templates/common/bin/dev.old.













































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#!/usr/bin/env bash

RUNNER_SCRIPT_DIR=$(cd ${0%/*} && pwd)

RUNNER_BASE_DIR=${RUNNER_SCRIPT_DIR%/*}
RUNNER_ETC_DIR=$RUNNER_BASE_DIR/etc
RUNNER_LOG_DIR=$RUNNER_BASE_DIR/log
RUNNER_USER=

# Make sure this script is running as the appropriate user
if [ ! -z "$RUNNER_USER" ] && [ `whoami` != "$RUNNER_USER" ]; then
    exec sudo -u $RUNNER_USER -i $0 $@
fi

# Make sure CWD is set to runner base dir
cd $RUNNER_BASE_DIR

# Extract the target node name from node.args
NAME_ARG=`grep -e '-[s]*name' $RUNNER_ETC_DIR/vm.args`
if [ -z "$NAME_ARG" ]; then
    echo "vm.args needs to have either -name or -sname parameter."
    exit 1
fi

# Learn how to specify node name for connection from remote nodes
if  echo $NAME_ARG | grep -E "^-sname" > /dev/null ; then
    NAME_PARAM="-sname"
    NAME_HOST=""
else
    NAME_PARAM="-name"
    if echo $NAME_ARG | grep -E "(@.*)" > /dev/null ; then
        NAME_HOST=${BASH_REMATCH[1]}
    else
        NAME_HOST=""
    fi
fi

# Extract the target cookie
COOKIE_ARG=`grep -e '-setcookie' $RUNNER_ETC_DIR/vm.args`
if [ -z "$COOKIE_ARG" ]; then
    echo "vm.args needs to have a -setcookie parameter."
    exit 1
fi

# Identify the script name
SCRIPT=`basename $0`

# Parse out release and erts info
START_ERL=`cat $RUNNER_BASE_DIR/releases/start_erl.data`
ERTS_VSN=${START_ERL% *}
APP_VSN=${START_ERL#* }

# Add ERTS bin dir to our path.
ERTS_PATH=$RUNNER_BASE_DIR/erts-$ERTS_VSN/bin

# Setup command to control the node
if [ -x $ERTS_PATH/escript ]; then
	NODETOOL="$ERTS_PATH/escript $ERTS_PATH/nodetool $NAME_ARG $COOKIE_ARG"
else
	NODETOOL="escript $RUNNER_BASE_DIR/releases/*/nodetool $NAME_ARG $COOKIE_ARG"
fi

# Make sure the local node IS running
RES=`$NODETOOL ping`
if [ "$RES" != "pong" ]; then
    echo "Node is not running!"
    exit 1
fi

$NODETOOL rpc nitrogen_dev command $@

Added templates/common/bin/nitrogen.





































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#!/bin/sh
# -*- tab-width:4;indent-tabs-mode:nil -*-
# ex: ts=4 sw=4 et

RUNNER_SCRIPT_DIR=$(cd ${0%/*} && pwd)

CALLER_DIR=$PWD

RUNNER_BASE_DIR=${RUNNER_SCRIPT_DIR%/*}
RUNNER_ETC_DIR=$RUNNER_BASE_DIR/etc

APP_CONFIG=$RUNNER_ETC_DIR/autogenerated.config.all
VMARGS=$RUNNER_ETC_DIR/vm.args

RUNNER_USER=



case "$1" in
    start)
            
        ;;

    console)
        cat $RUNNER_ETC_DIR/*.config > $APP_CONFIG
        $RUNNER_ETC_DIR/assemble_config.escript $RUNNER_ETC_DIR $APP_CONFIG
        $RUNNER_BASE_DIR/rebar3 run
        ;;

    stop)

        ;;

esac

Added templates/common/bin/nitrogen.old.

























































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
#!/bin/sh
# -*- tab-width:4;indent-tabs-mode:nil -*-
# ex: ts=4 sw=4 et

RUNNER_SCRIPT_DIR=$(cd ${0%/*} && pwd)

CALLER_DIR=$PWD

RUNNER_BASE_DIR=${RUNNER_SCRIPT_DIR%/*}
RUNNER_ETC_DIR=$RUNNER_BASE_DIR/etc
# Note the trailing slash on $PIPE_DIR/
PIPE_DIR=/tmp/`whoami`/$RUNNER_BASE_DIR/
RUNNER_USER=

# Make sure this script is running as the appropriate user
if [ ! -z "$RUNNER_USER" ] && [ `whoami` != "$RUNNER_USER" ]; then
    exec sudo -u $RUNNER_USER -i $0 $@
fi

# Identify the script name
SCRIPT=`basename $0`

# Parse out release and erts info
START_ERL=`cat $RUNNER_BASE_DIR/releases/start_erl.data`
ERTS_VSN=${START_ERL% *}
APP_VSN=${START_ERL#* }

# Use $CWD/vm.args if exists, otherwise releases/APP_VSN/vm.args, or else etc/vm.args
if [ -e "$CALLER_DIR/vm.args" ]; then
    VMARGS_PATH=$CALLER_DIR/vm.args
    USE_DIR=$CALLER_DIR
else
    USE_DIR=$RUNNER_BASE_DIR
    if [ -e "$RUNNER_BASE_DIR/releases/$APP_VSN/vm.args" ]; then
        VMARGS_PATH="$RUNNER_BASE_DIR/releases/$APP_VSN/vm.args"
    else
        VMARGS_PATH="$RUNNER_ETC_DIR/vm.args"
    fi
fi

RUNNER_LOG_DIR=$USE_DIR/log
# Make sure log directory exists
mkdir -p $RUNNER_LOG_DIR

# Use releases/VSN/sys.config if it exists otherwise use etc/app.config
## THIS SECTION MODIFIED FROM STOCK REBAR TO READ ALL *.config FILES FROM DIRECTORY
if [ -e "$USE_DIR/sys.config" ]; then
    CONFIG="-config $USE_DIR/sys.config"
else
    if [ -e "$RUNNER_BASE_DIR/releases/$APP_VSN/sys.config" ]; then
        CONFIG="-config $RUNNER_BASE_DIR/releases/$APP_VSN/sys.config"
    else
        ## NITROGEN CHANGE: Ensure that all .config files get loaded in /etc
        for f in `ls $RUNNER_ETC_DIR/*.config`; do CONFIG="$CONFIG -config $f"; done
    fi
fi

# Extract the target node name from node.args
NAME_ARG=`egrep '^-s?name' $VMARGS_PATH`
if [ -z "$NAME_ARG" ]; then
    echo "vm.args needs to have either -name or -sname parameter."
    exit 1
fi

# Extract the name type and name from the NAME_ARG for REMSH
REMSH_TYPE=`echo $NAME_ARG | awk '{print $1}'`
REMSH_NAME=`echo $NAME_ARG | awk '{print $2}'`

# Note the `date +%s`, used to allow multiple remsh to the same node transparently
REMSH_NAME_ARG="$REMSH_TYPE remsh`date +%s`@`echo $REMSH_NAME | awk -F@ '{print $2}'`"
REMSH_REMSH_ARG="-remsh $REMSH_NAME"

# Extract the target cookie
COOKIE_ARG=`grep '^-setcookie' $VMARGS_PATH`
if [ -z "$COOKIE_ARG" ]; then
    echo "vm.args needs to have a -setcookie parameter."
    exit 1
    
fi

# Make sure CWD is set to the right dir
cd $USE_DIR

# Make sure log directory exists
mkdir -p $USE_DIR/log

RUNNER_SCRIPT_DATA=
if [ -e "$RUNNER_BASE_DIR/releases/$APP_VSN/runner_script.data" ]; then
    RUNNER_SCRIPT_DATA=`cat $RUNNER_BASE_DIR/releases/$APP_VSN/runner_script.data`
fi

if [ -z "$RUNNER_SCRIPT_DATA" ]; then
    ROOTDIR=$RUNNER_BASE_DIR
    ERTS_PATH=$RUNNER_BASE_DIR/erts-$ERTS_VSN/bin
    if [ -e "$RUNNER_BASE_DIR/releases/$APP_VSN/nodetool" ]; then
        NODETOOL="$ERTS_PATH/escript $RUNNER_BASE_DIR/releases/$APP_VSN/nodetool $NAME_ARG $COOKIE_ARG"
    else
        NODETOOL="$ERTS_PATH/escript $ERTS_PATH/nodetool $NAME_ARG $COOKIE_ARG"
    fi
    ## Not a slim release, so no slim arguments
    SLIM_ARGS=
elif [ "$RUNNER_SCRIPT_DATA" = "slim" ]; then
    # Setup system paths
    SYSTEM_ERL_PATH=`which erl`
    if [ ! -x "$SYSTEM_ERL_PATH" ]; then
        echo "Failed to find erl. Is Erlang/OTP available in PATH?"
        exit 1
    fi
    SYSTEM_HOME_BIN=${SYSTEM_ERL_PATH%/*}
    ## This is a check for OSX using the Erlang Solutions installer
    if [ -d "$SYSTEM_HOME_BIN/../lib/erlang" ]; then
        ROOTDIR=$SYSTEM_HOME_BIN/../lib/erlang
    else
        ROOTDIR=$SYSTEM_HOME_BIN/..
    fi
    ERTS_PATH=$ROOTDIR/erts-$ERTS_VSN/bin
    unset SYSTEM_ERL_PATH
    unset SYSTEM_HOME_BIN

    LOCAL_ERTS_PATH=$RUNNER_BASE_DIR/erts-$ERTS_VSN/bin
    NODETOOL="$ERTS_PATH/escript $RUNNER_BASE_DIR/releases/$APP_VSN/nodetool $NAME_ARG $COOKIE_ARG"
    unset LOCAL_ERL_PATH

    # Setup additional arguments for slim release
    SLIM_ARGS="-boot_var RELTOOL_EXT_LIB $RUNNER_BASE_DIR/lib -sasl releases_dir \"$RUNNER_BASE_DIR/releases\""
else
    echo "Unknown runner_script.data"
    exit 1
fi

# Setup remote shell command to control node
REMSH="$ERTS_PATH/erl $REMSH_NAME_ARG $REMSH_REMSH_ARG $COOKIE_ARG"

# Check the first argument for instructions
case "$1" in
    start|start_boot)
        # Make sure there is not already a node running
        RES=`$NODETOOL ping`
        if [ "$RES" = "pong" ]; then
            echo "Node is already running!"
            exit 1
        fi
        case "$1" in
            start)
                shift
                START_OPTION="console"
                HEART_OPTION="start"
                ;;
            start_boot)
                shift
                START_OPTION="console_boot"
                HEART_OPTION="start_boot"
                ;;
        esac
        RUN_PARAM=$(printf "\'%s\' " "$@")
        HEART_COMMAND="$RUNNER_BASE_DIR/bin/$SCRIPT $HEART_OPTION $RUN_PARAM"
        export HEART_COMMAND
        mkdir -p $PIPE_DIR
        $ERTS_PATH/run_erl -daemon $PIPE_DIR $RUNNER_LOG_DIR "exec $RUNNER_BASE_DIR/bin/$SCRIPT $START_OPTION $RUN_PARAM" 2>&1
        ;;

    stop)
        # Wait for the node to completely stop...
        case `uname -s` in
            Linux|Darwin|FreeBSD|DragonFly|NetBSD|OpenBSD)
                # PID COMMAND
                PID=`ps ax -o pid= -o command=|\
                    grep "\-boot $RUNNER_BASE_DIR/[r]eleases"|awk '{print $1}'`
                ;;
            SunOS)
                # PID COMMAND
                PID=`ps -ef -o pid= -o args=|\
                    grep "\-boot $RUNNER_BASE_DIR/[r]eleases"|awk '{print $1}'`
                ;;
            CYGWIN*)
                # UID PID PPID TTY STIME COMMAND
                PID=`ps -efW|grep "\-boot $RUNNER_BASE_DIR/[r]eleases"|awk '{print $2}'`
                ;;
        esac
        $NODETOOL stop
        ES=$?
        if [ "$ES" -ne 0 ]; then
            exit $ES
        fi
        while `kill -0 $PID 2>/dev/null`;
        do
            sleep 1
        done
        ;;

    restart)
        ## Restart the VM without exiting the process
        $NODETOOL restart
        ES=$?
        if [ "$ES" -ne 0 ]; then
            exit $ES
        fi
        ;;

    reboot)
        ## Restart the VM completely (uses heart to restart it)
        $NODETOOL reboot
        ES=$?
        if [ "$ES" -ne 0 ]; then
            exit $ES
        fi
        ;;

    ping)
        ## See if the VM is alive
        $NODETOOL ping
        ES=$?
        if [ "$ES" -ne 0 ]; then
            exit $ES
        fi
        ;;

    attach)
        # Make sure a node IS running
        RES=`$NODETOOL ping`
        ES=$?
        if [ "$ES" -ne 0 ]; then
            echo "Node is not running!"
            exit $ES
        fi

        shift
        exec $ERTS_PATH/to_erl $PIPE_DIR
        ;;

    remote_console)
        # Make sure a node IS running
        RES=`$NODETOOL ping`
        ES=$?
        if [ "$ES" -ne 0 ]; then
            echo "Node is not running!"
            exit $ES
        fi

        shift
        exec $REMSH
        ;;

    upgrade)
        if [ -z "$2" ]; then
            echo "Missing upgrade package argument"
            echo "Usage: $SCRIPT upgrade {package base name}"
            echo "NOTE {package base name} MUST NOT include the .tar.gz suffix"
            exit 1
        fi

        # Make sure a node IS running
        RES=`$NODETOOL ping`
        ES=$?
        if [ "$ES" -ne 0 ]; then
            echo "Node is not running!"
            exit $ES
        fi

        node_name=`echo $NAME_ARG | awk '{print $2}'`
        erlang_cookie=`echo $COOKIE_ARG | awk '{print $2}'`

        $ERTS_PATH/escript $RUNNER_BASE_DIR/bin/install_upgrade.escript $node_name $erlang_cookie $2
        ;;

    console|console_clean|console_boot)
        # .boot file typically just $SCRIPT (ie, the app name)
        # however, for debugging, sometimes start_clean.boot is useful.
        # For e.g. 'setup', one may even want to name another boot script.
        case "$1" in
            console)        BOOTFILE=$SCRIPT ;;
            console_clean)  BOOTFILE=start_clean ;;
            console_boot)
                shift
                BOOTFILE="$1"
                shift
                ;;
        esac
        # Setup beam-required vars
        BINDIR=$ROOTDIR/erts-$ERTS_VSN/bin
        EMU=beam
        PROGNAME=`echo $0 | sed 's/.*\\///'`

        ## NITROGEN CHANGE: '-mode interactive' for dynamic code loading
        CMD="$BINDIR/erlexec $SLIM_ARGS -boot $RUNNER_BASE_DIR/releases/$APP_VSN/$BOOTFILE -mode interactive $CONFIG -args_file $VMARGS_PATH"
        export EMU
        export ROOTDIR
        export BINDIR
        export PROGNAME

        # Dump environment info for logging purposes
        echo "Exec: $CMD" -- ${1+"$@"}
        echo "Root: $ROOTDIR"

        # Log the startup
        logger -t "$SCRIPT[$$]" "Starting up"

        # Start the VM
        exec $CMD -- ${1+"$@"}
        ;;

    foreground)
        # start up the release in the foreground for use by runit
        # or other supervision services

        BOOTFILE=$SCRIPT
        FOREGROUNDOPTIONS="-noinput +Bd"

        # Setup beam-required vars
        BINDIR=$ROOTDIR/erts-$ERTS_VSN/bin
        EMU=beam
        PROGNAME=`echo $0 | sed 's/.*\///'`
        CMD="$BINDIR/erlexec $SLIM_ARGS $FOREGROUNDOPTIONS -boot $RUNNER_BASE_DIR/releases/$APP_VSN/$BOOTFILE $CONFIG -args_file $VMARGS_PATH"
        export EMU
        export ROOTDIR
        export BINDIR
        export PROGNAME

        # Dump environment info for logging purposes
        echo "Exec: $CMD" -- ${1+"$@"}
        echo "Root: $ROOTDIR"

        # Start the VM
        exec $CMD -- ${1+"$@"}
        ;;
    *)
        echo "Usage: $SCRIPT {start|start_boot <file>|foreground|stop|restart|reboot|ping|console|console_clean|console_boot <file>|attach|remote_console|upgrade}"
        exit 1
        ;;
esac

exit 0

Added templates/common/do-plugins.escript.

















































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
#!/usr/bin/env escript
%% -*- erlang -*-
%% vim: ts=4 sw=4 et ft=erlang
%%
%% Coyright 2013 - Jesse Gumm
%%
%% MIT License
%%
%% About
%%
%% This little script assists the Nitrogen Web Framework by simplifying the
%% process of including custom elements, actions, or validators without having
%% to worry about including a different header for each, or manually copying
%% records from each element's header into the "records.hrl".
%%
%% Further, this copies the plugin static information (javascript, images, etc)
%% into the site/static/plugins/<pluginname> directory. Then one doesn't need 
%% to copy that information for each upgrade.
%%
%% TO MAKE A PLUGIN WORK WITH THIS SCRIPT:
%%
%% 1) Make sure your plugin is able to be used as a rebar dependency
%% 2) Include a file "nitrogen.plugin" in the root of the plugin directory
%% 3) If you have any static resources (js, images) put them in a 'static'
%%    directory
%% 4) If this is a custom element, action, or validator, or requires anything
%%    else that should be included in a header, add them to (one or more) .hrl
%%    files in 'include'
%% 5) From your Nitrogen app's directory, include your plugin as a rebar
%%    dependency and run 'make'
%%
%% Sample Plugin Directory Structure:
%%
%% myplugin/
%%      ebin/
%%    
%%      src/
%%          element_myplugin.erl
%%          myplugin.app.src
%%      
%%      include/
%%          myplugin.hrl
%%      
%%      priv/
%%          templates/
%%              mytemplate.html
%%
%%          static/
%%              js/
%%                  myplugin.js
%%                  jquery-some-plugin.js
%%              images/
%%                  some_image.png
%%              css/
%%                  myplugin.css
%%
%%
%% When the plugin is processed, the following will be updated in your Nitrogen App
%%
%% site/
%%      include/
%%          plugins.hrl (will include a reference to all .hrl files from your plugin)
%%      static/
%%          plugins/
%%              myplugin/                
%%                  js/
%%                      myplugin.js
%%                      jquery-some-plugin.js
%%                  images/
%%                      some_image.png
%%                  css/
%%                      myplugin.css
%%      templates/
%%          plugins/
%%              mytemplate.html
%%
%% (Note: The Erlang/Nitrogen Element code is not copied, it'll be loaded just
%% like any rebar dependency's code)

main([]) ->
    io:format("Checking for Nitrogen Plugins\n"),
    RebarConfig = get_config("rebar.config"),
    PluginConfig = get_config("plugins.config"),
    DepDirs = proplists:get_value(deps_dir, RebarConfig, ["lib"]),
    {Includes,Statics,Templates} = lists:foldl(fun(Dir, {Inc, Stat, Temp}) ->
                            {ok, FoundIncludes, FoundStatics, FoundTemplates} = get_plugins(Dir),
                            {FoundIncludes ++ Inc, FoundStatics ++ Stat, FoundTemplates ++ Temp}
                        end, {[],[],[]}, DepDirs),
    case {Includes, Statics, Templates} of
        {[],[],[]} -> 
            io:format("No Nitrogen Plugins Found~n");
        _ ->
            io:format("Generating aggregate plugin header (plugins.hrl)~n"),
            generate_plugin_include(PluginConfig, Includes),
            io:format("Generating plugin static directories~n"),
            generate_plugin_static(PluginConfig, Statics),
            io:format("Generating plugin template directories~n"),
            generate_plugin_templates(PluginConfig, Templates),
            io:format("Plugin generation complete~n")
    end.


get_plugins(DepDir) ->
    Files = case file:list_dir(DepDir) of
        {ok, F} -> F;
        {error, _} -> []
    end,
    {Inc,Stat,Temp} = lists:foldl(fun(X,PluginInfo={Includes,Statics,Templates}) ->
                    PluginPath = filename:join(DepDir,X),
                    case analyze_path(PluginPath) of
                        undefined ->
                            %% Not a plugin, so just continue
                            PluginInfo;
                        {ok, FoundIncludes, FoundStatics, FoundTemplates} ->
                            {FoundIncludes++Includes, FoundStatics++Statics, FoundTemplates++Templates}
                    end
                end,{[],[],[]},Files),
    {ok, Inc, Stat, Temp}.
                          
get_config(File) ->
    case file:consult(File) of
        {error, _} -> [];
        {ok, Config} -> Config
    end.

analyze_path(Path) ->
    case is_dir_or_symlink_dir(Path) of
        true ->
            {ok, Files} = file:list_dir(Path),
            case lists:member("nitrogen.plugin",Files) of
                false -> 
                    undefined;
                true -> 
                    io:format("Found a Nitrogen plugin in ~p~n",[Path]),
                    IncludeDir = filename:join(Path,include),
                    StaticDir = filename:join(Path,static),
                    PrivStaticDir = filename:join([Path,priv,static]),
                    TemplateDir = filename:join([Path,priv,templates]),

                    Includes = analyze_path_include(IncludeDir),
                    %% Originally, the plugin spec called for statics to be
                    %% located in the "static" dir, however, it's more
                    %% OTP-compliant to have statics to be located in
                    %% "priv/static", so we support both here with StaticDir
                    %% and PrivStaticDir
                    Statics = analyze_path_exists_only(StaticDir) 
                              ++ analyze_path_exists_only(PrivStaticDir),

                    Templates = analyze_path_exists_only(TemplateDir),
                    {ok, Includes, Statics, Templates}
            end;
        false -> undefined
    end.

is_dir_or_symlink_dir(Path) ->
    case filelib:is_dir(Path) of
        true -> true;
        false ->
            case file:read_link(Path) of
                {ok, _} -> true;
                {error, _} -> false
            end
    end.
            

analyze_path_include(Path) ->
    case filelib:is_dir(Path) of
        false -> [];
        true -> list_includes(Path)
    end.
            
list_includes(Path) -> 
    {ok, Files} = file:list_dir(Path),
    Includes = filter_non_includes(Files),
    [filename:join(Path,Inc) || Inc <- Includes].

filter_non_includes([]) -> [];
filter_non_includes([File | Files]) ->
    case re:run(File,"\.hrl$",[{capture,none}]) of
        match -> [File | filter_non_includes(Files)];
        nomatch -> filter_non_includes(Files)
    end.

analyze_path_exists_only(Path) ->
    case filelib:is_dir(Path) of
        false -> [];
        true -> [Path]
    end.

generate_plugin_include(Config, Includes) ->
    IncludeFile = proplists:get_value(plugins_hrl, Config, "site/include/plugins.hrl"),
    HeaderLines = ["%% Automatically Generated by do-plugins.escript",
                   "%% Manually editing this file is not recommended."],
    PluginLines = [includify(I) || I <- Includes],
    PluginContents = string:join(HeaderLines ++ PluginLines,"\n"),
    FinalContents = iolist_to_binary(PluginContents),
    CurrentContents = get_current_include(IncludeFile),
    case FinalContents == CurrentContents of
        true -> io:format("No changes to ~p~n",[IncludeFile]);
        false -> file:write_file(IncludeFile,PluginContents)
    end.

get_current_include(File) ->
    case file:read_file(File) of
        {ok, Binary} -> Binary;
        {error, _} -> <<>>
    end.

includify("lib/" ++ Path) ->
    "-include_lib(\"" ++ Path ++ "\").";
includify(Path) ->
    "-include(\"" ++ filename:join("..",Path) ++ "\").".

generate_plugin_static(Config, Statics) ->
    PluginStaticBase = proplists:get_value(static_dir, Config, "site/static/plugins"),
    CopyMode = proplists:get_value(copy_mode, Config, copy),
    clear_plugin_dir(PluginStaticBase),
    filelib:ensure_dir(filename:join(PluginStaticBase,dummy)),
    [generate_plugin_copy_worker(PluginStaticBase,CopyMode,Static) || Static <- Statics].

clear_plugin_dir(Dir) ->
    rm_rf(Dir).

plugin_name_from_static_path(PluginStatic) ->
    PluginStaticParts = filename:split(PluginStatic),
    case lists:reverse(PluginStaticParts) of
        ["templates","priv",PluginName|_]   -> PluginName;
        ["templates",PluginName|_]          -> PluginName;
        ["static","priv",PluginName|_]      -> PluginName;
        ["static",PluginName|_]             -> PluginName
    end.

generate_plugin_copy_worker(PluginBase, CopyMode, PluginStatic) ->
    %% Split the Plugin Static Dir into parts and extract the name of the plugin
    %% ie "lib/whatever/static" - the Plugin Name is "whatever"
    PluginName = plugin_name_from_static_path(PluginStatic),
   
    %% And we're going to copy it into our system's plugin static dir
    %% (ie "site/static/plugins/whatever")
    FinalDestination = filename:join(PluginBase,PluginName),

    %% And let's copy or link them.
    case CopyMode of 
        link ->
            LinkPrefix = make_link_relative_prefix(FinalDestination),
               
            file:make_symlink(filename:join([LinkPrefix,PluginStatic]),FinalDestination);
        copy -> 
            %% We want to copy the contents of the Plugin's static dir,
            %% So we're copying from /lib/whatever/static/*
            PluginSource = filename:join(PluginStatic,"*"),

            %% Make sure the dir exists to copy into
            filelib:ensure_dir(filename:join(FinalDestination,dummy)),

            %% And copy the directory
            try cp_r([PluginSource],FinalDestination)
            catch _:_ -> ok  %% getting here usually just means that the source directory is empty
            end;
        Other ->
            throw({invalid_copy_mode, Other})
    end.

generate_plugin_templates(Config, Templates) ->
    TemplateBase = proplists:get_value(template_dir, Config, "site/templates/plugins"),
    CopyMode = proplists:get_value(copy_mode, Config, copy),
    clear_plugin_dir(TemplateBase),
    filelib:ensure_dir(filename:join(TemplateBase,dummy)),
    [generate_plugin_copy_worker(TemplateBase, CopyMode, Template) || Template <- Templates].

%% Because the symlink is relative, we need to make sure it includes the
%% proper relative path prefix (ie, the right number of "../../../" to get us
%% back before linking
make_link_relative_prefix("./" ++ Path) ->
    make_link_relative_prefix(Path);
make_link_relative_prefix(Path) ->
    Parts = filename:split(Path),
    Parts2 = lists:sublist(Parts, length(Parts)-1),
    Parts3 = [relative_path_helper(Part) || Part <- Parts2],
    filename:join(Parts3).

relative_path_helper(".") -> ".";
relative_path_helper("..") -> "";
relative_path_helper(_) -> "..".

%% -------------------------------------------------------------------------
%% ------------- File Actions (copied mostly from Rebar) -------------------
%% -------------------------------------------------------------------------


-define(CONSOLE(Str, Args), io:format(Str,Args)).
-define(FMT(Str,Args), lists:flatten(io_lib:format(Str,Args))).

rm_rf(Target) ->
    case os:type() of
        {unix, _} ->
            EscTarget = escape_spaces(Target),
            {ok, []} = sh(?FMT("rm -rf ~s", [EscTarget]),
                                      [{use_stdout, false}, return_on_error]),
            ok;
        {win32, _} ->
            Filelist = filelib:wildcard(Target),
            Dirs = [F || F <- Filelist, filelib:is_dir(F)],
            Files = Filelist -- Dirs,
            ok = delete_each(Files),
            ok = delete_each_dir_win32(Dirs),
            ok
    end.

delete_each([]) ->
    ok;
delete_each([File | Rest]) ->
    case file:delete(File) of
        ok ->
            delete_each(Rest);
        {error, enoent} ->
            delete_each(Rest);
        {error, Reason} ->
            ExitMsg = ?FMT("Error: Failed to delete file ~s: ~p\n", [File, Reason]),
            exit(ExitMsg)
    end.

delete_each_dir_win32([]) -> ok;
delete_each_dir_win32([Dir | Rest]) ->
    {ok, []} = sh(?FMT("rd /q /s \"~s\"",
                                   [filename:nativename(Dir)]),
                              [{use_stdout, false}, return_on_error]),
    delete_each_dir_win32(Rest).



cp_r(Sources, Dest) ->
    case os:type() of
        {unix, _} ->
            EscSources = [escape_spaces(Src) || Src <- Sources],
            SourceStr = string:join(EscSources, " "),
            {ok, []} = sh(?FMT("cp -R ~s \"~s\"",
                                           [SourceStr, Dest]),
                                      [{use_stdout, false}, return_on_error]),
            ok;
        {win32, _} ->
            lists:foreach(fun(Src) -> ok = cp_r_win32(Src,Dest) end, Sources),
            ok
    end.

%% Windows stuff	
xcopy_win32(Source,Dest)->
    {ok, R} = sh(
                ?FMT("xcopy \"~s\" \"~s\" /q /y /e 2> nul",
                     [filename:nativename(Source), filename:nativename(Dest)]),
                [{use_stdout, false}, return_on_error]),
    case length(R) > 0 of
        %% when xcopy fails, stdout is empty and and error message is printed
        %% to stderr (which is redirected to nul)
        true -> ok;
        false ->
            {error, lists:flatten(
                      io_lib:format("Failed to xcopy from ~s to ~s~n",
                                    [Source, Dest]))}
    end.

cp_r_win32({true, SourceDir}, {true, DestDir}) ->
    %% from directory to directory
    SourceBase = filename:basename(SourceDir),
    ok = case file:make_dir(filename:join(DestDir, SourceBase)) of
             {error, eexist} -> ok;
             Other -> Other
         end,
    ok = xcopy_win32(SourceDir, filename:join(DestDir, SourceBase));
cp_r_win32({false, Source} = S,{true, DestDir}) ->
    %% from file to directory
    cp_r_win32(S, {false, filename:join(DestDir, filename:basename(Source))});
cp_r_win32({false, Source},{false, Dest}) ->
    %% from file to file
    {ok,_} = file:copy(Source, Dest),
    ok;
cp_r_win32({true, SourceDir},{false,DestDir}) -> 
    IsFile = filelib:is_file(DestDir),
    case IsFile of
        true -> 
            %% From Directory to file? This shouldn't happen
            {error,[{rebar_file_utils,cp_r_win32},
                        {directory_to_file_makes_no_sense,
                            {source,SourceDir},{dest,DestDir}}]};
        false ->
            %% Specifying a target directory that doesn't currently exist.
            %% So Let's attempt to create this directory
            %% Will not recursively create parent directories
            ok = case file:make_dir(DestDir) of
                     {error, eexist} -> ok;
                     Other -> Other
                 end,
            ok = xcopy_win32(SourceDir, DestDir)
    end;
cp_r_win32(Source,Dest) ->
    Dst = {filelib:is_dir(Dest), Dest},
    lists:foreach(fun(Src) ->
                          ok = cp_r_win32({filelib:is_dir(Src), Src}, Dst)
                  end, filelib:wildcard(Source)),
    ok.

%% Shell Command Stuff (from rebar_utils)
sh(Command0, Options0) ->
    % ?CONSOLE("sh info:\n\tcwd: ~p\n\tcmd: ~s\n", [get_cwd(), Command0]),
    % ?DEBUG("\topts: ~p\n", [Options0]),

    DefaultOptions = [use_stdout, abort_on_error],
    Options = [expand_sh_flag(V)
               || V <- proplists:compact(Options0 ++ DefaultOptions)],

    ErrorHandler = proplists:get_value(error_handler, Options),
    OutputHandler = proplists:get_value(output_handler, Options),

    Command = patch_on_windows(Command0, proplists:get_value(env, Options, [])),
    PortSettings = proplists:get_all_values(port_settings, Options) ++
        [exit_status, {line, 16384}, use_stdio, stderr_to_stdout, hide],
    Port = open_port({spawn, Command}, PortSettings),

    case sh_loop(Port, OutputHandler, []) of
        {ok, _Output} = Ok ->
            Ok;
        {error, {_Rc, _Output}=Err} ->
            ErrorHandler(Command, Err)
    end.

%%get_cwd() ->
%%	{ok,Dir} = file:get_cwd(),
%%	Dir.

patch_on_windows(Cmd, Env) ->
    case os:type() of
        {win32,nt} ->
            "cmd /q /c "
                ++ lists:foldl(fun({Key, Value}, Acc) ->
                                       expand_env_variable(Acc, Key, Value)
                               end, Cmd, Env);
        _ ->
            Cmd
    end.

expand_env_variable(InStr, VarName, RawVarValue) ->
    case string:chr(InStr, $$) of
        0 ->
            %% No variables to expand
            InStr;
        _ ->
            VarValue = re:replace(RawVarValue, "\\\\", "\\\\\\\\", [global]),
            %% Use a regex to match/replace:
            %% Given variable "FOO": match $FOO\s | $FOOeol | ${FOO}
            RegEx = io_lib:format("\\\$(~s(\\s|$)|{~s})", [VarName, VarName]),
            ReOpts = [global, {return, list}],
            re:replace(InStr, RegEx, [VarValue, "\\2"], ReOpts)
    end.

sh_loop(Port, Fun, Acc) ->
    receive
        {Port, {data, {eol, Line}}} ->
            sh_loop(Port, Fun, Fun(Line ++ "\n", Acc));
        {Port, {data, {noeol, Line}}} ->
            sh_loop(Port, Fun, Fun(Line, Acc));
        {Port, {exit_status, 0}} ->
            {ok, lists:flatten(lists:reverse(Acc))};
        {Port, {exit_status, Rc}} ->
            {error, {Rc, lists:flatten(lists:reverse(Acc))}}
    end.

escape_spaces(Str) ->
    re:replace(Str, " ", "\\\\ ", [global, {return, list}]).


log_and_abort(Message) ->
	?CONSOLE("Aborting: ~s ~n",[Message]).


         
expand_sh_flag(return_on_error) ->
    {error_handler,
     fun(_Command, Err) ->
             {error, Err}
     end};
expand_sh_flag({abort_on_error, Message}) ->
    {error_handler,
		fun(Cmd,Err) ->
				log_and_abort({Message,{Cmd,Err}})
		end};
expand_sh_flag(abort_on_error) ->
	expand_sh_flag({abort_on_error, error});
expand_sh_flag(use_stdout) ->
    {output_handler,
     fun(Line, Acc) ->
             ?CONSOLE("~s", [Line]),
             [Line | Acc]
     end};
expand_sh_flag({use_stdout, false}) ->
    {output_handler,
     fun(Line, Acc) ->
             [Line | Acc]
     end};
expand_sh_flag({cd, _CdArg} = Cd) ->
    {port_settings, Cd};
expand_sh_flag({env, _EnvArg} = Env) ->
    {port_settings, Env}.


Added templates/common/etc/app.config.



























































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
%% -*- mode: erlang -*-
[
    {nitrogen_core, [
        % If a signkey is not specified, then Nitrogen uses the Erlang cookie.
        % {signkey, "SECRET"}, 

        % Default session timeout is 20 minutes.
        % {session_timeout, 20},

        % Specify a session cookie name. Uses "wf" by default.
        % {cookie_name, "wf"},
		
		% Setting the module_prefix to anything other than "" will change the
		% behaviour of the dynamic route handler (the default route handler) to
		% prefix page modules with it's value followed by an underscore.  For
		% example, setting module_prefix to "web" will make your page module
		% for "/mypage" be called "web_mypage".
		% {module_prefix, ""}
    ]},

    %% SASL config
    {sasl, [
        {sasl_error_logger, {file, "log/sasl-error.log"}},
        {errlog_type, error},
        {error_logger_mf_dir, "log/sasl"},      % Log directory
        {error_logger_mf_maxbytes, 10485760},   % 10 MB max file size
        {error_logger_mf_maxfiles, 5}           % 5 files max
    ]}
].

Added templates/common/etc/simple_bridge.config.











































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
%% vim: ts=4 sw=4 et ft=erlang
[
    {simple_bridge, [

        {handler, nitrogen},
        %% the name of the simple_bridge handler module, which should not
        %% change unless you're doing something custom to set up the context
        %% and simple_bridge, and also to interact with the request in a
        %% non-standard way. Generally speaking, it's not recommended to change
        %% this unless you really know what you are doing.

        {backend, {{backend}}}, 
        %% cowboy | inets | mochiweb | webmachine | yaws

        {address, "0.0.0.0"},       
        %% IP address to bind, either in tuple format or string

        {port, {{port}}},               
        %% Port to bind

        {document_root, "./site/static"}, 
        %% The path on the local machine to handle static files

        {static_paths, ["js/", "css/", "images/", "nitrogen/", "favicon.ico"]},
        %% The list of paths to be automatically translated to static paths by simple_bridge


        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        %% FILE UPLOAD SETTINGS
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

        {max_post_size, 10},
        %% No multipart request greater than above will be accepted. Units are
        %% MB
        
        {max_file_size, 10},
        %% No single uploaded file will be accepted greater than the above.
        %% Units are MB.

        {max_file_in_memory_size,  0},
        %% If a file is less than the above, then instead of writing the file
        %% to disk, it'll be retained in memory and can be retrieved by
        %% sb_uploaded_file:data/1. See the README for more info.

        {scratch_dir, "./scratch"}
        %% This is the location of the temp directory where uploaded files will
        %% be placed.

        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
        %% BACKEND-SPECIFIC DISPATCH TABLES:
        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

        %% {webmachine_dispatch, DispatchTable},
        %% Webmachine dispatch table override (ignores static_paths above)

        %% {webmachine_dispatch_function, {Module, Function}}
        %% A Module:Function() that when evaluated will return a dispatch table
        %% for Webmachine, again ignores the static_paths above

        %% {cowboy_dispatch, DispatchTable}
        %% Cowboy dispatch table override (ignores static_paths)

        %% {cowboy_dispatch_function, {Module, Function}}
        %% A Module:Function() that when evaluated will return a dispatch tavle
        %% for Cowboy, again ignoring the static_paths above

    ]}
].

Added templates/common/etc/sync.config.

























































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
%% vim: ts=4 sw=4 et ft=erlang
%% Sync configuration for automatic recompilation
[
    {sync,[

        %% growl: Desktop notifications
        %% valid values: all | none | [success | warning | error]
        %% default: all
        {growl, all},
        
        %% log: Console notifications
        %% valid values: all | none | [success | warnings | errors]
        %% default: all
        {log, all},    
                       
        %% non_descendant: How to handle beams whose original source path is
        %% not a descendant of the current working directory.
        %%
        %% valid values: fix | allow | ignore
        %% * fix = attempt to find source files under current directory
        %% * allow = don't do anything special, use the non-descendant path and
        %%   watch that file
        %% * ignore = don't watch that module at all and ignore any changes to
        %%   its source path
        %% default: fix
        {non_descendant, fix},

        %% excluded_modules: Ignore any modules listed
        %% default: []
        {excluded_modules, []},

        %% executable: Identify the program that you want run by the "growl" notifications
        %% valid values: auto | notifu | 'notify-send' | growlnotify | emacsclient
        %% * auto = allow sync to autodetect which program to run
        %% * growlnotify = Use Growl for Mac
        %% * 'notify-send' = Use libnotify for Linux
        %% * notifu = The notifu program for Windows
        %% * emacsclient = Emacs notifications
        %% default: auto
        {executable, auto}
    ]}
].


Added templates/common/etc/vm.args.

























































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

## Name of the nitrogen node
-name {{PROJECT}}@127.0.0.1

## Heartbeat management; auto-restarts VM if it dies or becomes unresponsive
## (Disabled by default..use with caution!)
##-heart

## Enable kernel poll and a few async threads
+K true
+A 5

## Increase number of concurrent ports/sockets
-env ERL_MAX_PORTS 4096

## Tweak GC to run more often 
-env ERL_FULLSWEEP_AFTER 10

## Include .beam files for site.
-pa ./site/ebin

## Include libraries and rebar dependency paths
-env ERL_LIBS ./lib

## Run code at startup.
-eval "application:start(nitrogen)"


Added templates/common/include/plugins.hrl.





>
>
1
2
%% This file starts empty and will be automatically generated. It's not
%% recommended to manually edit this file

Added templates/common/include/records.hrl.









>
>
>
>
1
2
3
4
%% Include the automatically generated plugins directory
-include("plugins.hrl").

%% Include any application-specific custom elements, actions, or validators below

Added templates/common/plugins.config.























































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
%% vim: ts=2 sw=2 et ft=erlang
%% Nitrogen Plugin Installer Configuration
%% 
%% This will tell the plugin-installer script where to put Nitrogen plugin
%% information it finds.
%%

%% plugins_hrl tells the Nitrogen plugin installer where to put the .hrl file
%% containing links to all your plugins' respective header files.
%% The default is "./site/include/plugins.hrl".
{plugins_hrl, "./site/include/plugins.hrl"}.

%% static_dir tells the Nitrogen plugin installer where to copy your plugins'
%% static resources (images, js, etc).
%% The default is "./site/static/plugins"
{static_dir, "./site/static/plugins"}.

%% template_dir tells the Nitrogne plugin installer where to copy your plugins'
%% template files.
%% The default is "./site/templates"
{template_dir, "./site/templates/plugins"}.

%% copy_mode determines if static resources are copied or merely symlinked.
%% Keep in mind, symlinks do not work on Windows, so "copy" is the default.
%% Valid values are the atoms 'copy' or 'link'
%% Default: copy
{copy_mode, copy}.

Added templates/common/priv/static/css/style.css.























































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
/***** CSS RESET *****/
html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td{margin:0;padding:0;border:0;outline:0;font-size:100%;vertical-align:baseline;background:transparent}body{line-height:1}blockquote,q{quotes:none}blockquote:before,blockquote:after,q:before,q:after{content:'';content:none}:focus{outline:0}ins{text-decoration:none}del{text-decoration:line-through}table{border-collapse:collapse;border-spacing:0}

/***** STYLE *****/

body { 
    font-family: "Lucida Grande", "Segoe UI", Tahoma, Helvetica, Arial, sans-serif; 
    font-size: 16px;
    line-height: 32px;
}

.container_12 {
    margin-top: 40px;
}

h1 {
    font-family: Arial, sans-serif;
    font-weight: bold;
    padding-bottom: 7px;
    border-bottom: dashed 1px #DDD;
    text-transform: uppercase;
    font-size: 1.875em;
    line-height: 1.066667em;
    margin-top: 1.6em;
    margin-bottom: 1.6em;
}

h2 {
    font-family: Arial, sans-serif;
    font-size: 1.5em;
    line-height: 1.333333em;
    margin-top: 1.6em;
    margin-bottom: 1.6em;
}

h3 {
    font-family: Arial, sans-serif;
    font-size: 1.25em;
    line-height: 1.6em;
    margin-top: 1.333333em;
    margin-bottom: 1.333333em;
}

p {
    font-size: 1em;
    line-height: 2em;
    margin-top: 2em;
    margin-bottom: 2em;
}


a, a:visited { 
    color: #4488FF
    text-decoration: none; 
}

a:hover, a:active { 
    text-decoration: underline; 
}

Added templates/common/priv/static/images/spinner.gif.

cannot compute difference between binary files

Added templates/common/priv/static/js/.empty.

Added templates/common/priv/templates/bare.html.













































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf8">
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <title>[[[page:title()]]]</title>
  <script src='/nitrogen/jquery.js' type='text/javascript' charset='utf-8'></script>
  <script src='/nitrogen/jquery-ui.min.js' type='text/javascript' charset='utf-8'></script>
  <script src='/nitrogen/livevalidation.min.js' type='text/javascript' charset='utf-8'></script>
  <script src='/nitrogen/nitrogen.min.js' type='text/javascript' charset='utf-8'></script>
  <script src='/nitrogen/bert.min.js' type='text/javascript' charset='utf-8'></script>
  <link rel="stylesheet" href="/nitrogen/jquery-ui/jquery.ui.all.css" type="text/css" media="screen" charset="utf-8" />
  <link rel="stylesheet" href="/nitrogen/nitrogen.css" />
  <link rel="stylesheet" href="/css/style.css" />
</head>
<body>
[[[page:body()]]]
<script>
[[[script]]]
</script>
</body>
</html>

Added templates/common/priv/templates/mobile.html.









































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<!DOCTYPE html>
<html lang="en">
	<head>
		<title>[[[page:title()]]]</title>
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 
		<meta charset="utf8" />
		<meta name="viewport" content="width=device-width, initial-scale=1"> 


		<script type="text/javascript" src="/nitrogen/jquery.js"></script>
		<script type="text/javascript" src="/nitrogen/jquery.mobile.min.js"></script>
		<script type="text/javascript" src="/nitrogen/bert.min.js"></script>
		<script src='/nitrogen/livevalidation.min.js' type='text/javascript' charset='utf-8'></script>
		<script src='/nitrogen/nitrogen.min.js' type='text/javascript' charset='utf-8'></script>
		<script src='/nitrogen/nitrogen_jqm.js' type='text/javascript' charset='utf-8'></script>
		<link rel="stylesheet" href="/nitrogen/nitrogen.css" charset='utf-8'></script>
		<link rel="stylesheet" href="/nitrogen/jquery.mobile.min.css" />
	</head>
	<body>
		<div data-role="page" id="pagediv" data-code="[[[mobile_script]]]">
			<div data-role="header"> 
				<h1>[[[page:title()]]]</h1> 
			</div> 

			<div data-role="content">
				[[[page:body()]]]
			</div>

			<div data-role="footer"> 
				<h4>
					&copy; 2012 - Nitrogen Web Framework
				</h4> 
			</div>
		</div>
	</body>
</html>

Added templates/common/prototypes/action.erl.





































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
%% -*- mode: nitrogen -*-
%% vim: ts=4 sw=4 et
-module (action_[[[NAME]]]).
-include_lib ("nitrogen_core/include/wf.hrl").
-include("records.hrl").
-export([
    render_action/1
]).

%% move the following record definition to site/include/records.hrl
-record([[[NAME]]], {?ACTION_BASE(action_[[[NAME]]]),
        attr1 :: any(),
        attr2 :: any()
    }).

-spec render_action(#[[[NAME]]]{}) -> actions().
render_action(_Record = #[[[NAME]]]{}) ->
    "alert('Hello, from [[[NAME]]]!');".

Added templates/common/prototypes/element.erl.













































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
%% -*- mode: nitrogen -*-
%% vim: ts=4 sw=4 et
-module (element_[[[NAME]]]).
-include_lib("nitrogen_core/include/wf.hrl").
-include("records.hrl").
-export([
    reflect/0,
    render_element/1
]).

%% Move the following record definition to records.hrl:
-record([[[NAME]]], {?ELEMENT_BASE(element_[[[NAME]]]),
        attr1 :: any(),
        attr2 :: any()
    }).

-spec reflect() -> [atom()].
reflect() -> record_info(fields, [[[NAME]]]).

-spec render_element(#[[[NAME]]]{}) -> body().
render_element(_Record = #[[[NAME]]]{}) ->
    "<b>Hello from [[[NAME]]]</b>".

Added templates/common/prototypes/page.erl.





















































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
%% -*- mode: nitrogen -*-
%% vim: ts=4 sw=4 et
-module ([[[NAME]]]).
-compile(export_all).
-include_lib("nitrogen_core/include/wf.hrl").
-include("records.hrl").

main() -> #template { file="./site/templates/bare.html" }.

title() -> "Hello from [[[NAME]]].erl!".

body() -> 
    [
        #panel { style="margin: 50px 100px;", body=[
            #span { text="Hello from [[[NAME]]].erl!" },

            #p{},
            #button { text="Click me!", postback=click },

            #p{},
            #panel { id=placeholder }
        ]}
    ].
	
event(click) ->
    wf:insert_top(placeholder, "<p>You clicked the button!").

Added templates/common/prototypes/plugin.app.src.























>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
{application, [[[NAME]]],
 [
  {description, "A sample plugin for the Nitrogen Web Framework"},
  {vsn, ""},
  {registered, []},
  {applications, [
                  kernel,
                  stdlib
                 ]},
  {env, []}
 ]}.

Added templates/common/prototypes/plugin.tgz.

cannot compute difference between binary files

Added templates/common/prototypes/plugin_page.erl.



































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
%% -*- mode: nitrogen -*-
%% vim: ts=4 sw=4 et
-module ([[[NAME]]]).
-compile(export_all).
-include_lib("nitrogen_core/include/wf.hrl").
-include("records.hrl").

main() -> #template { file="./site/templates/bare.html" }.

title() -> "Testing plugin [[[NAME]]]!".

body() -> 
	wf:wire(#sample_action{}),
	[
		"You should see some more content and an alert: <b>",
		#sample_element{}, "</b>"
	].

Added templates/common/src/actions/.ignore.

Added templates/common/src/elements/.ignore.

Added templates/common/src/index.erl.















































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
%% -*- mode: nitrogen -*-
-module (index).
-compile(export_all).
-include_lib("nitrogen_core/include/wf.hrl").

main() -> #template { file="./site/templates/bare.html" }.

title() -> "Welcome to Nitrogen".

body() ->
    #container_12 { body=[
        #grid_8 { alpha=true, prefix=2, suffix=2, omega=true, body=inner_body() }
    ]}.

inner_body() -> 
    [
        #h1 { text="Welcome to Nitrogen" },
        #p{},
        "
        If you can see this page, then your Nitrogen server is up and
        running. Click the button below to test postbacks.
        ",
        #p{}, 	
        #button { id=button, text="Click me!", postback=click },
		#p{},
        "
        Run <b>./bin/dev help</b> to see some useful developer commands.
        ",
		#p{},
		"
		<b>Want to see the ",#link{text="Sample Nitrogen jQuery Mobile Page",url="/mobile"},"?</b>
		"
    ].
	
event(click) ->
    wf:replace(button, #panel { 
        body="You clicked the button!", 
        actions=#effect { effect=highlight }
    }).

Added templates/common/src/mobile.erl.











































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
%% -*- mode: nitrogen -*-
%% vim: ts=4 sw=4 et
-module(mobile).
-include_lib("nitrogen_core/include/wf.hrl").
-compile(export_all).
-author("Jesse Gumm (gumm@sigma-star.com)").

main() -> #template{file="./site/templates/mobile.html"}.

title() -> "Nitrogen Web Framework - Mobile Sample".

body() ->
    [
        "If you can see this, then your Nitrogen installation is working.",
        #p{},
        "Go ahead and enable the sample menu below to test postbacks and links",
        #p{},
        #mobile_toggle{
            on_text="Menu Visible",
            off_text="Menu Hidden",
            selected="off",
            postback=toggle_menu,
            id=menu_on,
            width=200
        },
        #p{},
        #mobile_list{
            id=menu,
            theme=a,
            inset=true,
            style="display:none",
            body=[
                #mobile_list_divider{class=c, text="Sample Mobile Menu"},
                mobile_list_link("Non-mobile Sample Page","/"),
                mobile_list_link("Nitrogen Home","http://nitrogenproject.com"),
                mobile_list_link("jQuery Mobile Home","http://jquerymobile.com"),
                mobile_list_link("Erlang Home","http://erlang.org")
            ]
        }
    ].

mobile_list_link(Text,URL) ->
    #mobile_listitem{
        theme=c,
        body=#link{text=Text, url=URL, mobile_target=false}
    }.

event(toggle_menu) ->
    ShowMenu = wf:q(menu_on),
    case ShowMenu of
        "on" -> wf:wire(menu,#appear{});
        "off" -> wf:wire(menu,#fade{})
    end.

Added templates/common/src/nitrogen.app.src.



















>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
{application, {{name}},
 [
  {description, "My Nitrogen Web Project"},
  {vsn, "1"},
  {registered, []},
  {applications, [kernel, stdlib]},
  {mod, { {{name}}_app, []}},
  {env, []}
 ]}.

Added templates/common/src/nitrogen_app.erl.



























>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
-module({{name}}_app).
-behaviour(application).
-export([start/2, stop/1]).

%% ===================================================================
%% Application callbacks
%% ===================================================================

start(_StartType, _StartArgs) ->
    {{name}}_sup:start_link().

stop(_State) ->
    ok.

Added templates/common/src/nitrogen_main_handler.erl.























































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
%% vim: ts=4 sw=4 et
-module(nitrogen_main_handler).
-export([
    run/0,
    ws_init/0
]).

handlers() ->
    %% Put any custom handlers here
    %% See http://nitrogenproject.com/doc/handlers.html
    %% Example:
    %%
    %%   nitrogen:handler(MySecurityHandler, HandlerConfig),
    %%
    %%
    %% The following enables the debug_crash_handler for development. If you
    %% wish to use the default_crash_handler, which just spits out "Internal
    %% Server Error", comment or delete this next line.
    nitrogen:handler(debug_crash_handler, []),
    ok.

ws_init() ->
    handlers().

run() ->
    handlers(),
    wf_core:run().

Added templates/common/src/nitrogen_sup.erl.































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
%% -*- mode: nitrogen -*-
%% vim: ts=4 sw=4 et
-module({{name}}_sup).
-behaviour(supervisor).
-export([
    start_link/0,
    init/1
]).

%% Helper macro for declaring children of supervisor
-define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 5000, Type, [I]}).

%% ===================================================================
%% API functions
%% ===================================================================

start_link() ->
    supervisor:start_link({local, ?MODULE}, ?MODULE, []).

%% ===================================================================
%% Supervisor callbacks
%% ===================================================================

init([]) ->
    application:load(nitrogen_core),
    application:start(nitro_cache),
    application:start(crypto),
    application:start(nprocreg),
    application:start(simple_bridge),

    {ok, { {one_for_one, 5, 10}, []} }.

Added templates/nitrogen.template.





































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
{description, "Nitrogen Installation Plugin"}.
{variables, [
	{name, "nitrogen", "Default app name will be nitrogen"},
    {prefix, ".", "Parent Directory will the app be installed"},
	{backend, "cowboy", "Default Backend"},
	{port, "8000", "Port"},
	{include_erts, "false", "Should a built release include ERTS (false = slim release, true = full release)"}
]}.

{dir, "{{prefix}}/{{name}}/priv"}.
{dir, "{{prefix}}/{{name}}/priv/templates"}.
{dir, "{{prefix}}/{{name}}/priv/static"}.
{dir, "{{prefix}}/{{name}}/priv/static/css"}.
{dir, "{{prefix}}/{{name}}/priv/static/js"}.
{dir, "{{prefix}}/{{name}}/priv/static/images"}.
{dir, "{{prefix}}/{{name}}/priv/prototypes"}.
{dir, "{{prefix}}/{{name}}/site"}.
{dir, "{{prefix}}/{{name}}/etc"}.
{dir, "{{prefix}}/{{name}}/src"}.
{dir, "{{prefix}}/{{name}}/src/actions"}.
{dir, "{{prefix}}/{{name}}/src/elements"}.
{dir, "{{prefix}}/{{name}}/include"}.
{dir, "{{prefix}}/{{name}}/bin"}.

{file, "common/README.md",  "{{prefix}}/{{name}}/README.md"}.
{file, "common/plugins.config",  "{{prefix}}/{{name}}/plugins.config"}.
{file, "common/.gitignore",  "{{prefix}}/{{name}}/.gitignore"}.
{file, "common/rebar3", "{{prefix}}/{{name}}/rebar3"}.
{file, "common/bin/nitrogen", "{{prefix}}/{{name}}/bin/nitrogen"}.
{chmod, "{{prefix}}/{{name}}/rebar3", 8#755}.
{chmod, "{{prefix}}/{{name}}/bin/nitrogen", 8#755}.

{file, "common/priv/static/css/style.css",  "{{prefix}}/{{name}}/priv/static/css/style.css"}.
{file, "common/priv/static/images/spinner.gif",  "{{prefix}}/{{name}}/priv/static/images/spinner.gif"}.
{file, "common/priv/templates/bare.html",  "{{prefix}}/{{name}}/priv/templates/bare.html"}.
{file, "common/src/nitrogen_main_handler.erl",  "{{prefix}}/{{name}}/src/nitrogen_main_handler.erl"}.
{template, "common/src/nitrogen.app.src",  "{{prefix}}/{{name}}/src/{{name}}.app.src"}.
{template, "common/src/nitrogen_sup.erl",  "{{prefix}}/{{name}}/src/{{name}}_sup.erl"}.
{template, "common/src/nitrogen_app.erl",  "{{prefix}}/{{name}}/src/{{name}}_app.erl"}.
{file, "common/src/index.erl",  "{{prefix}}/{{name}}/src/index.erl"}.
{file, "common/Makefile",  "{{prefix}}/{{name}}/Makefile"}.
{file, "common/do-plugins.escript",  "{{prefix}}/{{name}}/do-plugins.escript"}.

%% Symlinks
%{file, "common/site/src",  "{{prefix}}/{{name}}/site/src"}.
%{file, "common/site/static",  "{{prefix}}/{{name}}/site/static"}.
%{file, "common/site/templates",  "{{prefix}}/{{name}}/site/templates"}.
%{file, "common/site/include", "{{prefix}}/{{name}}/site/include"}.

{file, "common/prototypes/plugin.app.src",  "{{prefix}}/{{name}}/priv/prototypes/plugin.app.src"}.
{file, "common/prototypes/plugin_page.erl",  "{{prefix}}/{{name}}/priv/prototypes/plugin_page.erl"}.
{file, "common/prototypes/element.erl",  "{{prefix}}/{{name}}/priv/prototypes/element.erl"}.
{file, "common/prototypes/page.erl",  "{{prefix}}/{{name}}/priv/prototypes/page.erl"}.
{file, "common/prototypes/action.erl",  "{{prefix}}/{{name}}/priv/prototypes/action.erl"}.

{file, "common/etc/app.config",  "{{prefix}}/{{name}}/etc/app.config"}.
{file, "common/etc/vm.args",  "{{prefix}}/{{name}}/etc/vm.args"}.
{file, "common/etc/sync.config",  "{{prefix}}/{{name}}/etc/sync.config"}.
{template, "common/etc/simple_bridge.config",  "{{prefix}}/{{name}}/etc/simple_bridge.config"}.

{file, "common/include/records.hrl",  "{{prefix}}/{{name}}/include/records.hrl"}.
{file, "common/include/plugins.hrl",  "{{prefix}}/{{name}}/include/plugins.hrl"}.

{template, "backends/rebar.{{backend}}.config", "{{prefix}}/{{name}}/rebar.config"}.
{template, "backends/rebar.{{backend}}.config.script", "{{prefix}}/{{name}}/rebar.config.script"}.