Browse Source

Document use of the template command

Bob Mottram 7 years ago
parent
commit
511a8c1683
2 changed files with 50 additions and 461 deletions
  1. 18
    224
      doc/EN/devguide.org
  2. 32
    237
      website/EN/devguide.html

+ 18
- 224
doc/EN/devguide.org View File

@@ -19,253 +19,47 @@ Freedombone consists of a set of bash scripts. There are a lot of them, but they
19 19
 * Adding extra apps
20 20
 Suppose you have some internet application which you want to add to the system. To do this you need to create an app script which tells the system how to install/remove and also backup/restore. The script should be designed to work with the current stable version of Debian.
21 21
 
22
-On an installed system the app scripts go into the directory:
22
+There's a command which you can use to generate scripts for new apps. Some examples are as follows:
23
+
24
+To create a script for a generic PHP plus MySql/MariaDB web app:
23 25
 
24 26
 #+begin_src bash
25
-/usr/share/freedombone/apps
27
+freedombone-template --app [name] -e [email] -r [repo url] -c [commit] --php yes -d mariadb > src/freedombone-app-myappname
26 28
 #+end_src
27 29
 
28
-and within the project repo they appear within the /src/ directory. Your new app script should have the name:
30
+For a Nodejs app with MySql/MariaDB database:
29 31
 
30 32
 #+begin_src bash
31
-freedombone-app-[myappname]
33
+freedombone-template --app [name] -e [email] -r [repo url] -c [commit] --node yes -d mariadb --dir /etc/myappname --daemon yes > src/freedombone-app-myappname
32 34
 #+end_src
33 35
 
34
-The /myappname/ value should not contain any spaces and will appear in the list of available apps.
35
-
36
-An example template for an app script is shown below. Copy this and add whatever variables and configuration you need. Search and replace /myappname/ with your own.
36
+For a Python app with Postgresql database:
37 37
 
38 38
 #+begin_src bash
39
-#!/bin/bash
40
-# Copyright (C) Year YourName <YourEmail>
41
-#
42
-# This program is free software: you can redistribute it
43
-# and/or modify it under the terms of the GNU Affero General
44
-# Public License as published by the Free Software Foundation,
45
-# either version 3 of the License, or (at your option) any
46
-# later version.
47
-#
48
-# This program is distributed in the hope that it will be useful,
49
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
50
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
51
-# GNU Affero General Public License for more details.
52
-
53
-# 'full' includes your app in the full installation and you
54
-# can also add other variants, separated by spaces. The
55
-# available variants will be detected automatically from the
56
-# app scripts. In most cases don't change this.
57
-VARIANTS='full'
58
-
59
-# If you want this to appear on the control panel About screen
60
-SHOW_ON_ABOUT=1
61
-
62
-# If you want this app to be in the default installation,
63
-# otherwise it will be available but not selected by default
64
-IN_DEFAULT_INSTALL=1
65
-
66
-SOME_IMPORTANT_CONFIG_VARIABLE='some important value'
67
-ANOTHER_IMPORTANT_CONFIG_VARIABLE='foo'
68
-MY_FUNKY_AVATAR=https://some-domain-or-other/fro.png
69
-MYAPPNAME_ONION_PORT=[port number]
70
-MYAPPNAME_DB_PASSWORD=
71
-
72
-# A directory where the data for this app exists
73
-MYAPP_DATA_DIR=/var/lib/somedirectory
74
-
75
-# List of configuration variables used by the app
76
-myappname_variables=(ONION_ONLY
77
-                     MY_USERNAME
78
-                     SOME_IMPORTANT_CONFIG_VARIABLE
79
-                     ANOTHER_IMPORTANT_CONFIG_VARIABLE
80
-                     MY_FUNKY_AVATAR
81
-                     MYAPPNAME_ONION_PORT
82
-                     MYAPPNAME_DB_PASSWORD)
83
-
84
-function logging_on_myappname {
85
-    echo -n ''
86
-    # Commands to turn on logging go here
87
-}
88
-
89
-function logging_off_myappname {
90
-    echo -n ''
91
-    # Commands to turn off logging go here
92
-}
93
-
94
-function change_password_myappname {
95
-    PASSWORD_USERNAME="$1"
96
-    PASSWORD_NEW="$2"
97
-    # Do something to change the password
98
-}
99
-
100
-function reconfigure_myappname {
101
-    echo -n ''
102
-    # Do something to delete existing keys/identity and
103
-    # generate new ones
104
-}
105
-
106
-function upgrade_myappname {
107
-    echo -n ''
108
-    # Do something to upgrade this app.
109
-    # If it's a debian package then it will be maintained by the
110
-    # operating system and you don't need anything here
111
-}
112
-
113
-function backup_local_myappname {
114
-    # If your app has a MariaDB/MySQL database
115
-    backup_database_to_usb myappname
116
-
117
-    # To backup a directory
118
-    backup_directory_to_usb $MYAPP_DATA_DIR myappname
119
-
120
-    # if you need to backup data within individual user
121
-    # home directories
122
-    for d in /home/*/ ; do
123
-        USERNAME=$(echo "$d" | awk -F '/' '{print $3}')
124
-        if [[ $(is_valid_user "$USERNAME") == "1" ]]; then
125
-            echo $"Backing up myappname config for $USERNAME"
126
-            if [ -d /home/$USERNAME/.config/myappname ]; then
127
-                backup_directory_to_usb \
128
-                    /home/$USERNAME/.config/myappname \
129
-                    myappname_users/$USERNAME
130
-            fi
131
-        fi
132
-    done
133
-}
134
-
135
-function restore_local_myappname {
136
-    temp_restore_dir=/root/tempmyappname
137
-
138
-    # If your app has a MariaDB/MySQL database
139
-    restore_database myappname
140
-
141
-    # Restore some data from a directory
142
-    # Note that we don't restore directly but to a temporary
143
-    # directory and then copy the files. This ensures that if
144
-    # there is a restore failure you don't end up with
145
-    # half-copied or corrupted files
146
-    restore_directory_from_usb $MYAPP_DATA_DIR myappname
147
-    cp -r $temp_restore_dir/$MYAPP_DATA_DIR $MYAPP_DATA_DIR
148
-    rm -rf $temp_restore_dir
149
-
150
-    # If you need to restore a configuration directory for each user
151
-    if [ -d $USB_MOUNT/backup/myappname_users ]; then
152
-        for d in $USB_MOUNT/backup/myappname_users/*/ ; do
153
-            USERNAME=$(echo "$d" | awk -F '/' '{print $6}')
154
-            if [[ $(is_valid_user "$USERNAME") == "1" ]]; then
155
-                if [ ! -d /home/$USERNAME ]; then
156
-                    ${PROJECT_NAME}-adduser $USERNAME
157
-                fi
158
-                echo $"Restoring Vim config for $USERNAME"
159
-                function_check restore_directory_from_usb
160
-                restore_directory_from_usb $temp_restore_dir \
161
-                                           myappname_users/$USERNAME
162
-                cp -r $temp_restore_dir/home/$USERNAME/.config \
163
-                      /home/$USERNAME/
164
-                if [ ! "$?" = "0" ]; then
165
-                    rm -rf $temp_restore_dir
166
-                    set_user_permissions
167
-                    backup_unmount_drive
168
-                    exit 664
169
-                fi
170
-                rm -rf $temp_restore_dir
171
-            fi
172
-        done
173
-    fi
174
-}
175
-
176
-function backup_remote_myappname {
177
-    # this should be the same as backup_local_myappname,
178
-    # but call the backup functions backup_directory_to_friend
179
-    # and backup_database_to_friend
180
-}
181
-
182
-function restore_remote_vim {
183
-    # this should be the same as restore_local_myappname,
184
-    # but call the restore function restore_directory_from_friend
185
-    # and restore_database_from_friend
186
-}
187
-
188
-function remove_myappname {
189
-    # if it's a debian package then:
190
-    apt-get -y remove --purge [my-app-package-name]
191
-
192
-    # If your app has a MariaDB/MySQL database
193
-    drop_database myappname
194
-
195
-    # If your app uses an onion address
196
-    remove_onion_service myappname ${MYAPPNAME_ONION_PORT}
197
-}
198
-
199
-function install_myappname {
200
-    # if it's a debian package then:
201
-    apt-get -y install [my-app-package-name]
202
-
203
-    # If you need to create a MariaDB/MySQL database for the app
204
-    MYAPPNAME_DB_PASSWORD="$(create_password 20)"
205
-    create_database myappname "$MYAPPNAME_DB_PASSWORD" $MY_USERNAME
206
-
207
-    # If you need to create an onion address for the app
208
-    MYAPPNAME_ONION_HOSTNAME=$(add_onion_service myappname \
209
-                               80 ${MYAPPNAME_ONION_PORT})
210
-
211
-    # Do any other configuration
212
-    # Here you might use $ONION_ONLY or
213
-    # $SOME_IMPORTANT_CONFIG_VARIABLE
214
-
215
-    # Mark the app as having installed successfully
216
-    # If this variable isn't set then it will be assumed that
217
-    # the install has failed
218
-    APP_INSTALLED=1
219
-}
220
-
221
-function install_interactive_myappname {
222
-    # Interactively obtain some values using dialog, such as
223
-    # domain names. An avatar changing example is:
224
-    data=$(tempfile 2>/dev/null)
225
-    trap "rm -f $data" 0 1 2 5 15
226
-    dialog --title $"Change your avatar" \
227
-           --backtitle $"Freedombone Control Panel" \
228
-           --inputbox $"Enter a URL for an image. It should be " \
229
-                      $"approximately a square image." 8 75 2>$data
230
-    sel=$?
231
-    case $sel in
232
-        0)
233
-            MY_FUNKY_AVATAR=$(<$data)
234
-            if [ ${#MY_FUNKY_AVATAR} -gt 3 ]; then
235
-                clear
236
-
237
-                # do whatever is needed to change the avatar
238
-                # in your app
239
-
240
-                dialog --title $"Change your avatar" \
241
-                       --msgbox $"Your avatar has been changed" 6 40
242
-            fi
243
-            ;;
244
-    esac
39
+freedombone-template --app [name] -e [email] -r [repo url] -c [commit] -d postgresql --dir /etc/myappname --daemon yes > src/freedombone-app-myappname
40
+#+end_src
245 41
 
246
-    # install_myappname will be called automatically after this function
247
-}
42
+For a Python app without any database:
248 43
 
249
-# NOTE: deliberately no exit 0
44
+#+begin_src bash
45
+freedombone-template --app [name] -e [email] -r [repo url] -c [commit] --dir /etc/myappname --daemon yes > src/freedombone-app-myappname
250 46
 #+end_src
251 47
 
252
-To test your app log into your system, select *Exit to command line* then gain root powers with:
48
+For more details see the manpage:
253 49
 
254 50
 #+begin_src bash
255
-sudo su
51
+man freedombone-template
256 52
 #+end_src
257 53
 
258
-Copy your app script to */usr/share/freedombone/apps/freedombone-app-myappname*.
259
-
260
-And run the admin control panel:
54
+When your new script is ready for testing you can install it with:
261 55
 
262 56
 #+begin_src bash
263
-control
57
+make install
264 58
 #+end_src
265 59
 
266
-Select *Add/Remove Apps* and if all is well then you should see your app listed as installable. Test that installing and removing it works as expected.
60
+Then run the administrator control panel and you should see the new app within *Add/Remove apps*.
267 61
 
268
-Submit your working app to *https://github.com/bashrc/freedombone/issues*
62
+Submit your working app to *https://github.com/bashrc/freedombone/issues* or create a pull request.
269 63
 
270 64
 * Customising mesh images
271 65
 If you want to make your own specially branded version of the mesh images, such as for a particular event, then to change the default desktop backgrounds edit the images within *img/backgrounds* and to change the available avatars and desktop icons edit the images within *img/avatars*. Re-create disk images using the instructions shown previously.

+ 32
- 237
website/EN/devguide.html View File

@@ -3,7 +3,7 @@
3 3
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
4 4
 <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
5 5
 <head>
6
-<!-- 2017-12-20 Wed 12:42 -->
6
+<!-- 2018-02-06 Tue 21:55 -->
7 7
 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
8 8
 <meta name="viewport" content="width=device-width, initial-scale=1" />
9 9
 <title>&lrm;</title>
@@ -246,297 +246,92 @@ for the JavaScript code in this tag.
246 246
 
247 247
 <center><h1>Developers Guide</h1></center>
248 248
 
249
-<div id="outline-container-org6818d03" class="outline-2">
250
-<h2 id="org6818d03">Introduction</h2>
251
-<div class="outline-text-2" id="text-org6818d03">
249
+<div id="outline-container-org178b393" class="outline-2">
250
+<h2 id="org178b393">Introduction</h2>
251
+<div class="outline-text-2" id="text-org178b393">
252 252
 <p>
253 253
 Freedombone consists of a set of bash scripts. There are a lot of them, but they're not very complicated. If you're familiar with the GNU/Linux commandline and can hack a bash script then you can probably add a new app or fix a bug in the system. There are no trendy development frameworks to learn or to get in your way. You might also want to consult the <a href="./codeofconduct.html">Code of Conduct</a>.
254 254
 </p>
255 255
 </div>
256 256
 </div>
257
-<div id="outline-container-org080672c" class="outline-2">
258
-<h2 id="org080672c">Adding extra apps</h2>
259
-<div class="outline-text-2" id="text-org080672c">
257
+<div id="outline-container-org694dd79" class="outline-2">
258
+<h2 id="org694dd79">Adding extra apps</h2>
259
+<div class="outline-text-2" id="text-org694dd79">
260 260
 <p>
261 261
 Suppose you have some internet application which you want to add to the system. To do this you need to create an app script which tells the system how to install/remove and also backup/restore. The script should be designed to work with the current stable version of Debian.
262 262
 </p>
263 263
 
264 264
 <p>
265
-On an installed system the app scripts go into the directory:
265
+There's a command which you can use to generate scripts for new apps. Some examples are as follows:
266
+</p>
267
+
268
+<p>
269
+To create a script for a generic PHP plus MySql/MariaDB web app:
266 270
 </p>
267 271
 
268 272
 <div class="org-src-container">
269
-<pre class="src src-bash">/usr/share/freedombone/apps
273
+<pre class="src src-bash">freedombone-template --app [name] -e [email] -r [repo url] -c [commit] --php yes -d mariadb &gt; src/freedombone-app-myappname
270 274
 </pre>
271 275
 </div>
272 276
 
273 277
 <p>
274
-and within the project repo they appear within the <i>src</i> directory. Your new app script should have the name:
278
+For a Nodejs app with MySql/MariaDB database:
275 279
 </p>
276 280
 
277 281
 <div class="org-src-container">
278
-<pre class="src src-bash">freedombone-app-[myappname]
282
+<pre class="src src-bash">freedombone-template --app [name] -e [email] -r [repo url] -c [commit] --node yes -d mariadb --dir /etc/myappname --daemon yes &gt; src/freedombone-app-myappname
279 283
 </pre>
280 284
 </div>
281 285
 
282 286
 <p>
283
-The <i>myappname</i> value should not contain any spaces and will appear in the list of available apps.
284
-</p>
285
-
286
-<p>
287
-An example template for an app script is shown below. Copy this and add whatever variables and configuration you need. Search and replace <i>myappname</i> with your own.
287
+For a Python app with Postgresql database:
288 288
 </p>
289 289
 
290 290
 <div class="org-src-container">
291
-<pre class="src src-bash"><span class="org-comment-delimiter">#</span><span class="org-comment">!/bin/</span><span class="org-keyword">bash</span>
292
-<span class="org-comment-delimiter"># </span><span class="org-comment">Copyright (C) Year YourName &lt;YourEmail&gt;</span>
293
-<span class="org-comment-delimiter">#</span>
294
-<span class="org-comment-delimiter"># </span><span class="org-comment">This program is free software: you can redistribute it</span>
295
-<span class="org-comment-delimiter"># </span><span class="org-comment">and/or modify it under the terms of the GNU Affero General</span>
296
-<span class="org-comment-delimiter"># </span><span class="org-comment">Public License as published by the Free Software Foundation,</span>
297
-<span class="org-comment-delimiter"># </span><span class="org-comment">either version 3 of the License, or (at your option) any</span>
298
-<span class="org-comment-delimiter"># </span><span class="org-comment">later version.</span>
299
-<span class="org-comment-delimiter">#</span>
300
-<span class="org-comment-delimiter"># </span><span class="org-comment">This program is distributed in the hope that it will be useful,</span>
301
-<span class="org-comment-delimiter"># </span><span class="org-comment">but WITHOUT ANY WARRANTY; without even the implied warranty of</span>
302
-<span class="org-comment-delimiter"># </span><span class="org-comment">MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span>
303
-<span class="org-comment-delimiter"># </span><span class="org-comment">GNU Affero General Public License for more details.</span>
304
-
305
-<span class="org-comment-delimiter"># </span><span class="org-comment">'full' includes your app in the full installation and you</span>
306
-<span class="org-comment-delimiter"># </span><span class="org-comment">can also add other variants, separated by spaces. The</span>
307
-<span class="org-comment-delimiter"># </span><span class="org-comment">available variants will be detected automatically from the</span>
308
-<span class="org-comment-delimiter"># </span><span class="org-comment">app scripts. In most cases don't change this.</span>
309
-<span class="org-variable-name">VARIANTS</span>=<span class="org-string">'full'</span>
310
-
311
-<span class="org-comment-delimiter"># </span><span class="org-comment">If you want this to appear on the control panel About screen</span>
312
-<span class="org-variable-name">SHOW_ON_ABOUT</span>=1
313
-
314
-<span class="org-comment-delimiter"># </span><span class="org-comment">If you want this app to be in the default installation,</span>
315
-<span class="org-comment-delimiter"># </span><span class="org-comment">otherwise it will be available but not selected by default</span>
316
-<span class="org-variable-name">IN_DEFAULT_INSTALL</span>=1
317
-
318
-<span class="org-variable-name">SOME_IMPORTANT_CONFIG_VARIABLE</span>=<span class="org-string">'some important value'</span>
319
-<span class="org-variable-name">ANOTHER_IMPORTANT_CONFIG_VARIABLE</span>=<span class="org-string">'foo'</span>
320
-<span class="org-variable-name">MY_FUNKY_AVATAR</span>=https://some-domain-or-other/fro.png
321
-<span class="org-variable-name">MYAPPNAME_ONION_PORT</span>=[port number]
322
-<span class="org-variable-name">MYAPPNAME_DB_PASSWORD</span>=
323
-
324
-<span class="org-comment-delimiter"># </span><span class="org-comment">A directory where the data for this app exists</span>
325
-<span class="org-variable-name">MYAPP_DATA_DIR</span>=/var/lib/somedirectory
326
-
327
-<span class="org-comment-delimiter"># </span><span class="org-comment">List of configuration variables used by the app</span>
328
-<span class="org-variable-name">myappname_variables</span>=(ONION_ONLY
329
-                     MY_USERNAME
330
-                     SOME_IMPORTANT_CONFIG_VARIABLE
331
-                     ANOTHER_IMPORTANT_CONFIG_VARIABLE
332
-                     MY_FUNKY_AVATAR
333
-                     MYAPPNAME_ONION_PORT
334
-                     MYAPPNAME_DB_PASSWORD)
335
-
336
-<span class="org-keyword">function</span> <span class="org-function-name">logging_on_myappname</span> {
337
-    <span class="org-builtin">echo</span> -n <span class="org-string">''</span>
338
-    <span class="org-comment-delimiter"># </span><span class="org-comment">Commands to turn on logging go here</span>
339
-}
340
-
341
-<span class="org-keyword">function</span> <span class="org-function-name">logging_off_myappname</span> {
342
-    <span class="org-builtin">echo</span> -n <span class="org-string">''</span>
343
-    <span class="org-comment-delimiter"># </span><span class="org-comment">Commands to turn off logging go here</span>
344
-}
345
-
346
-<span class="org-keyword">function</span> <span class="org-function-name">change_password_myappname</span> {
347
-    <span class="org-variable-name">PASSWORD_USERNAME</span>=<span class="org-string">"$1"</span>
348
-    <span class="org-variable-name">PASSWORD_NEW</span>=<span class="org-string">"$2"</span>
349
-    <span class="org-comment-delimiter"># </span><span class="org-comment">Do something to change the password</span>
350
-}
351
-
352
-<span class="org-keyword">function</span> <span class="org-function-name">reconfigure_myappname</span> {
353
-    <span class="org-builtin">echo</span> -n <span class="org-string">''</span>
354
-    <span class="org-comment-delimiter"># </span><span class="org-comment">Do something to delete existing keys/identity and</span>
355
-    <span class="org-comment-delimiter"># </span><span class="org-comment">generate new ones</span>
356
-}
357
-
358
-<span class="org-keyword">function</span> <span class="org-function-name">upgrade_myappname</span> {
359
-    <span class="org-builtin">echo</span> -n <span class="org-string">''</span>
360
-    <span class="org-comment-delimiter"># </span><span class="org-comment">Do something to upgrade this app.</span>
361
-    <span class="org-comment-delimiter"># </span><span class="org-comment">If it's a debian package then it will be maintained by the</span>
362
-    <span class="org-comment-delimiter"># </span><span class="org-comment">operating system and you don't need anything here</span>
363
-}
364
-
365
-<span class="org-keyword">function</span> <span class="org-function-name">backup_local_myappname</span> {
366
-    <span class="org-comment-delimiter"># </span><span class="org-comment">If your app has a MariaDB/MySQL database</span>
367
-    backup_database_to_usb myappname
368
-
369
-    <span class="org-comment-delimiter"># </span><span class="org-comment">To backup a directory</span>
370
-    backup_directory_to_usb $<span class="org-variable-name">MYAPP_DATA_DIR</span> myappname
371
-
372
-    <span class="org-comment-delimiter"># </span><span class="org-comment">if you need to backup data within individual user</span>
373
-    <span class="org-comment-delimiter"># </span><span class="org-comment">home directories</span>
374
-    <span class="org-keyword">for</span> d<span class="org-keyword"> in</span> /home/*/ ; <span class="org-keyword">do</span>
375
-        <span class="org-variable-name">USERNAME</span>=$(<span class="org-sh-quoted-exec">echo</span> <span class="org-string">"$d"</span> | awk -F <span class="org-string">'/'</span> <span class="org-string">'{print $3}'</span>)
376
-        <span class="org-keyword">if</span> [[ $(<span class="org-sh-quoted-exec">is_valid_user</span> <span class="org-string">"$USERNAME"</span>) == <span class="org-string">"1"</span> ]]; <span class="org-keyword">then</span>
377
-            <span class="org-builtin">echo</span> $<span class="org-string">"Backing up myappname config for $USERNAME"</span>
378
-            <span class="org-keyword">if</span> [ -d /home/$<span class="org-variable-name">USERNAME</span>/.config/myappname ]; <span class="org-keyword">then</span>
379
-                backup_directory_to_usb <span class="org-sh-escaped-newline">\</span>
380
-                    /home/$<span class="org-variable-name">USERNAME</span>/.config/myappname <span class="org-sh-escaped-newline">\</span>
381
-                    myappname_users/$<span class="org-variable-name">USERNAME</span>
382
-            <span class="org-keyword">fi</span>
383
-        <span class="org-keyword">fi</span>
384
-    <span class="org-keyword">done</span>
385
-}
386
-
387
-<span class="org-keyword">function</span> <span class="org-function-name">restore_local_myappname</span> {
388
-    <span class="org-variable-name">temp_restore_dir</span>=/root/tempmyappname
389
-
390
-    <span class="org-comment-delimiter"># </span><span class="org-comment">If your app has a MariaDB/MySQL database</span>
391
-    restore_database myappname
392
-
393
-    <span class="org-comment-delimiter"># </span><span class="org-comment">Restore some data from a directory</span>
394
-    <span class="org-comment-delimiter"># </span><span class="org-comment">Note that we don't restore directly but to a temporary</span>
395
-    <span class="org-comment-delimiter"># </span><span class="org-comment">directory and then copy the files. This ensures that if</span>
396
-    <span class="org-comment-delimiter"># </span><span class="org-comment">there is a restore failure you don't end up with</span>
397
-    <span class="org-comment-delimiter"># </span><span class="org-comment">half-copied or corrupted files</span>
398
-    restore_directory_from_usb $<span class="org-variable-name">MYAPP_DATA_DIR</span> myappname
399
-    cp -r $<span class="org-variable-name">temp_restore_dir</span>/$<span class="org-variable-name">MYAPP_DATA_DIR</span> $<span class="org-variable-name">MYAPP_DATA_DIR</span>
400
-    rm -rf $<span class="org-variable-name">temp_restore_dir</span>
401
-
402
-    <span class="org-comment-delimiter"># </span><span class="org-comment">If you need to restore a configuration directory for each user</span>
403
-    <span class="org-keyword">if</span> [ -d $<span class="org-variable-name">USB_MOUNT</span>/backup/myappname_users ]; <span class="org-keyword">then</span>
404
-        <span class="org-keyword">for</span> d<span class="org-keyword"> in</span> $<span class="org-variable-name">USB_MOUNT</span>/backup/myappname_users/*/ ; <span class="org-keyword">do</span>
405
-            <span class="org-variable-name">USERNAME</span>=$(<span class="org-sh-quoted-exec">echo</span> <span class="org-string">"$d"</span> | awk -F <span class="org-string">'/'</span> <span class="org-string">'{print $6}'</span>)
406
-            <span class="org-keyword">if</span> [[ $(<span class="org-sh-quoted-exec">is_valid_user</span> <span class="org-string">"$USERNAME"</span>) == <span class="org-string">"1"</span> ]]; <span class="org-keyword">then</span>
407
-                <span class="org-keyword">if</span> [ <span class="org-negation-char">!</span> -d /home/$<span class="org-variable-name">USERNAME</span> ]; <span class="org-keyword">then</span>
408
-                    ${<span class="org-variable-name">PROJECT_NAME</span>}-adduser $<span class="org-variable-name">USERNAME</span>
409
-                <span class="org-keyword">fi</span>
410
-                <span class="org-builtin">echo</span> $<span class="org-string">"Restoring Vim config for $USERNAME"</span>
411
-                function_check restore_directory_from_usb
412
-                restore_directory_from_usb $<span class="org-variable-name">temp_restore_dir</span> <span class="org-sh-escaped-newline">\</span>
413
-                                           myappname_users/$<span class="org-variable-name">USERNAME</span>
414
-                cp -r $<span class="org-variable-name">temp_restore_dir</span>/home/$<span class="org-variable-name">USERNAME</span>/.config <span class="org-sh-escaped-newline">\</span>
415
-                      /home/$<span class="org-variable-name">USERNAME</span>/
416
-                <span class="org-keyword">if</span> [ <span class="org-negation-char">!</span> <span class="org-string">"$?"</span> = <span class="org-string">"0"</span> ]; <span class="org-keyword">then</span>
417
-                    rm -rf $<span class="org-variable-name">temp_restore_dir</span>
418
-                    set_user_permissions
419
-                    backup_unmount_drive
420
-                    <span class="org-keyword">exit</span> 664
421
-                <span class="org-keyword">fi</span>
422
-                rm -rf $<span class="org-variable-name">temp_restore_dir</span>
423
-            <span class="org-keyword">fi</span>
424
-        <span class="org-keyword">done</span>
425
-    <span class="org-keyword">fi</span>
426
-}
427
-
428
-<span class="org-keyword">function</span> <span class="org-function-name">backup_remote_myappname</span> {
429
-    <span class="org-comment-delimiter"># </span><span class="org-comment">this should be the same as backup_local_myappname,</span>
430
-    <span class="org-comment-delimiter"># </span><span class="org-comment">but call the backup functions backup_directory_to_friend</span>
431
-    <span class="org-comment-delimiter"># </span><span class="org-comment">and backup_database_to_friend</span>
432
-}
433
-
434
-<span class="org-keyword">function</span> <span class="org-function-name">restore_remote_vim</span> {
435
-    <span class="org-comment-delimiter"># </span><span class="org-comment">this should be the same as restore_local_myappname,</span>
436
-    <span class="org-comment-delimiter"># </span><span class="org-comment">but call the restore function restore_directory_from_friend</span>
437
-    <span class="org-comment-delimiter"># </span><span class="org-comment">and restore_database_from_friend</span>
438
-}
439
-
440
-<span class="org-keyword">function</span> <span class="org-function-name">remove_myappname</span> {
441
-    <span class="org-comment-delimiter"># </span><span class="org-comment">if it's a debian package then:</span>
442
-    apt-get -y remove --purge [my-app-package-name]
443
-
444
-    <span class="org-comment-delimiter"># </span><span class="org-comment">If your app has a MariaDB/MySQL database</span>
445
-    drop_database myappname
446
-
447
-    <span class="org-comment-delimiter"># </span><span class="org-comment">If your app uses an onion address</span>
448
-    remove_onion_service myappname ${<span class="org-variable-name">MYAPPNAME_ONION_PORT</span>}
449
-}
450
-
451
-<span class="org-keyword">function</span> <span class="org-function-name">install_myappname</span> {
452
-    <span class="org-comment-delimiter"># </span><span class="org-comment">if it's a debian package then:</span>
453
-    apt-get -y install [my-app-package-name]
454
-
455
-    <span class="org-comment-delimiter"># </span><span class="org-comment">If you need to create a MariaDB/MySQL database for the app</span>
456
-    <span class="org-variable-name">MYAPPNAME_DB_PASSWORD</span>=<span class="org-string">"$(</span><span class="org-sh-quoted-exec">create_password</span><span class="org-string"> 20)"</span>
457
-    create_database myappname <span class="org-string">"$MYAPPNAME_DB_PASSWORD"</span> $<span class="org-variable-name">MY_USERNAME</span>
458
-
459
-    <span class="org-comment-delimiter"># </span><span class="org-comment">If you need to create an onion address for the app</span>
460
-    <span class="org-variable-name">MYAPPNAME_ONION_HOSTNAME</span>=$(<span class="org-sh-quoted-exec">add_onion_service</span> myappname <span class="org-sh-escaped-newline">\</span>
461
-                               80 ${<span class="org-variable-name">MYAPPNAME_ONION_PORT</span>})
462
-
463
-    <span class="org-comment-delimiter"># </span><span class="org-comment">Do any other configuration</span>
464
-    <span class="org-comment-delimiter"># </span><span class="org-comment">Here you might use $ONION_ONLY or</span>
465
-    <span class="org-comment-delimiter"># </span><span class="org-comment">$SOME_IMPORTANT_CONFIG_VARIABLE</span>
466
-
467
-    <span class="org-comment-delimiter"># </span><span class="org-comment">Mark the app as having installed successfully</span>
468
-    <span class="org-comment-delimiter"># </span><span class="org-comment">If this variable isn't set then it will be assumed that</span>
469
-    <span class="org-comment-delimiter"># </span><span class="org-comment">the install has failed</span>
470
-    <span class="org-variable-name">APP_INSTALLED</span>=1
471
-}
472
-
473
-<span class="org-keyword">function</span> <span class="org-function-name">install_interactive_myappname</span> {
474
-    <span class="org-comment-delimiter"># </span><span class="org-comment">Interactively obtain some values using dialog, such as</span>
475
-    <span class="org-comment-delimiter"># </span><span class="org-comment">domain names. An avatar changing example is:</span>
476
-    <span class="org-variable-name">data</span>=$(<span class="org-sh-quoted-exec">tempfile</span> 2&gt;/dev/null)
477
-    <span class="org-keyword">trap</span> <span class="org-string">"rm -f $data"</span> 0 1 2 5 15
478
-    dialog --title $<span class="org-string">"Change your avatar"</span> <span class="org-sh-escaped-newline">\</span>
479
-           --backtitle $<span class="org-string">"Freedombone Control Panel"</span> <span class="org-sh-escaped-newline">\</span>
480
-           --inputbox $<span class="org-string">"Enter a URL for an image. It should be "</span> <span class="org-sh-escaped-newline">\</span>
481
-                      $<span class="org-string">"approximately a square image."</span> 8 75 2&gt;$<span class="org-variable-name">data</span>
482
-    <span class="org-variable-name">sel</span>=$<span class="org-variable-name">?</span>
483
-    <span class="org-keyword">case</span> $<span class="org-variable-name">sel</span><span class="org-keyword"> in</span>
484
-        0)
485
-            <span class="org-variable-name">MY_FUNKY_AVATAR</span>=$(&lt;$<span class="org-variable-name">data</span>)
486
-            <span class="org-keyword">if</span> [ ${#<span class="org-variable-name">MY_FUNKY_AVATAR</span>} -gt 3 ]; <span class="org-keyword">then</span>
487
-                clear
488
-
489
-                <span class="org-comment-delimiter"># </span><span class="org-comment">do whatever is needed to change the avatar</span>
490
-                <span class="org-comment-delimiter"># </span><span class="org-comment">in your app</span>
491
-
492
-                dialog --title $<span class="org-string">"Change your avatar"</span> <span class="org-sh-escaped-newline">\</span>
493
-                       --msgbox $<span class="org-string">"Your avatar has been changed"</span> 6 40
494
-            <span class="org-keyword">fi</span>
495
-            ;;
496
-    <span class="org-keyword">esac</span>
497
-
498
-    <span class="org-comment-delimiter"># </span><span class="org-comment">install_myappname will be called automatically after this function</span>
499
-}
500
-
501
-<span class="org-comment-delimiter"># </span><span class="org-comment">NOTE: deliberately no exit 0</span>
291
+<pre class="src src-bash">freedombone-template --app [name] -e [email] -r [repo url] -c [commit] -d postgresql --dir /etc/myappname --daemon yes &gt; src/freedombone-app-myappname
502 292
 </pre>
503 293
 </div>
504 294
 
505 295
 <p>
506
-To test your app log into your system, select <b>Exit to command line</b> then gain root powers with:
296
+For a Python app without any database:
507 297
 </p>
508 298
 
509 299
 <div class="org-src-container">
510
-<pre class="src src-bash">sudo su
300
+<pre class="src src-bash">freedombone-template --app [name] -e [email] -r [repo url] -c [commit] --dir /etc/myappname --daemon yes &gt; src/freedombone-app-myappname
511 301
 </pre>
512 302
 </div>
513 303
 
514 304
 <p>
515
-Copy your app script to <b>/usr/share/freedombone/apps/freedombone-app-myappname</b>.
305
+For more details see the manpage:
516 306
 </p>
517 307
 
308
+<div class="org-src-container">
309
+<pre class="src src-bash">man freedombone-template
310
+</pre>
311
+</div>
312
+
518 313
 <p>
519
-And run the admin control panel:
314
+When your new script is ready for testing you can install it with:
520 315
 </p>
521 316
 
522 317
 <div class="org-src-container">
523
-<pre class="src src-bash">control
318
+<pre class="src src-bash">make install
524 319
 </pre>
525 320
 </div>
526 321
 
527 322
 <p>
528
-Select <b>Add/Remove Apps</b> and if all is well then you should see your app listed as installable. Test that installing and removing it works as expected.
323
+Then run the administrator control panel and you should see the new app within <b>Add/Remove apps</b>.
529 324
 </p>
530 325
 
531 326
 <p>
532
-Submit your working app to <b><a href="https://github.com/bashrc/freedombone/issues">https://github.com/bashrc/freedombone/issues</a></b>
327
+Submit your working app to <b><a href="https://github.com/bashrc/freedombone/issues">https://github.com/bashrc/freedombone/issues</a></b> or create a pull request.
533 328
 </p>
534 329
 </div>
535 330
 </div>
536 331
 
537
-<div id="outline-container-orge29cd52" class="outline-2">
538
-<h2 id="orge29cd52">Customising mesh images</h2>
539
-<div class="outline-text-2" id="text-orge29cd52">
332
+<div id="outline-container-orge25d226" class="outline-2">
333
+<h2 id="orge25d226">Customising mesh images</h2>
334
+<div class="outline-text-2" id="text-orge25d226">
540 335
 <p>
541 336
 If you want to make your own specially branded version of the mesh images, such as for a particular event, then to change the default desktop backgrounds edit the images within <b>img/backgrounds</b> and to change the available avatars and desktop icons edit the images within <b>img/avatars</b>. Re-create disk images using the instructions shown previously.
542 337
 </p>