0xGA: Check-in [e913d85986]

Yet another PHP framework, but made for org-mode and geeks.

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

Overview
Comment:Fix various bugs. Seems very close of a prod ready status.
Timelines: family | ancestors | descendants | both | narv
Files: files | file ages | folders
SHA1:e913d8598618fb08b28e7dd3a4376249fa3b27d7
User & Date: milouse 2014-05-03 20:12:54
Context
2014-05-04
16:55
Add logging facility. Ready to serve my own website check-in: 341670f849 user: milouse tags: narv
2014-05-03
20:12
Fix various bugs. Seems very close of a prod ready status. check-in: e913d85986 user: milouse tags: narv
14:41
Add install instruction to the home page check-in: 9451eb76cb user: milouse tags: narv
Changes

Changes to narv.

226
227
228
229
230
231
232


233
234
235
236
237
238
239
...
263
264
265
266
267
268
269









































































































































270
271
272
273
274
275
276
if __name__ == "__main__":
    app = Narv(('', 8000), MyBeautifulApp)
    app.start()
EOF

        exec > $WORKINGREP/var/$APPNAME.el
        cat <<EOF


;;; Default to HTML5
(setq org-html-doctype "html5")
(setq org-html-html5-fancy t)

;;; Disable default org style (you DO want to use your own style)
(setq org-html-head-include-default-style nil)

................................................................................
        ("${APPNAME}-style"
         :base-directory "${WORKINGREP}/home/${APPNAME}/.themes"
         :recursive t
         :base-extension "css\\\|js\\\|png\\\|jpg\\\|otf"
         :publishing-function org-publish-attachment
         :publishing-directory "${WORKINGREP}/srv/${APPNAME}/.themes")
        ("$APPNAME" :components ("${APPNAME}-org" "${APPNAME}-data" "${APPNAME}-style"))))









































































































































EOF

        exec 1>&6 6>&- # Restore stdout and close fd #6

        chmod u+x $WORKINGREP/usr/bin/$APPNAME.py

        echo "Application installation finished."







>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
...
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
if __name__ == "__main__":
    app = Narv(('', 8000), MyBeautifulApp)
    app.start()
EOF

        exec > $WORKINGREP/var/$APPNAME.el
        cat <<EOF
;;; Org-mode configuration

;;; Default to HTML5
(setq org-html-doctype "html5")
(setq org-html-html5-fancy t)

;;; Disable default org style (you DO want to use your own style)
(setq org-html-head-include-default-style nil)

................................................................................
        ("${APPNAME}-style"
         :base-directory "${WORKINGREP}/home/${APPNAME}/.themes"
         :recursive t
         :base-extension "css\\\|js\\\|png\\\|jpg\\\|otf"
         :publishing-function org-publish-attachment
         :publishing-directory "${WORKINGREP}/srv/${APPNAME}/.themes")
        ("$APPNAME" :components ("${APPNAME}-org" "${APPNAME}-data" "${APPNAME}-style"))))


;;; Utility functions. DO NOT MODIFY !

(defun ed/orgx-get-file-title ()
  (with-current-buffer (current-buffer)
    (save-excursion
      (goto-char (point-min))
      (if (re-search-forward "#\\+title: ?\\(.*\\)" nil t)
          (match-string 1)
        ""))))

(defun ed/orgx-get-file-name ()
  (when (string= (substring (buffer-name) 0 11) "content.org")
    (file-name-nondirectory (directory-file-name (file-name-directory buffer-file-name)))))

(defun asciify-string (string)
  "Convert STRING to ASCII string.
For example:
“passé” becomes “passe”"
  ;; Code originally by Teemu Likonen found on
  ;; http://ergoemacs.org/emacs/emacs_zap_gremlins.html
  (with-temp-buffer
    (insert string)
    (call-process-region (point-min) (point-max) "iconv" t t nil "--to-code=ASCII//TRANSLIT")
    (buffer-substring-no-properties (point-min) (point-max))))

(defun ed/orgx-get-permalink (title)
  (interactive "sTitle: ")
  (message
   (replace-regexp-in-string
    "--+" "-"
    (replace-regexp-in-string
     "^-+\\|-+$" ""
     (replace-regexp-in-string
      "[^a-z]" "-" (downcase (asciify-string title)))))))

(defun ed/orgx-parse-links ()
  (save-excursion
    (goto-char (point-min))
    (let* ((base-path (file-name-directory buffer-file-name))
           (media-folder (file-name-as-directory (concat base-path "media"))))
      (while (re-search-forward org-any-link-re nil t)
        (let* ((link-url (match-string 2))
               (file-path (when (and (stringp link-url)
                                     (string= (substring link-url 0 5) "file:"))
                            (substring link-url 5)))
               (file-name (when (and (stringp file-path)
                                     (file-exists-p file-path)
                                     (file-readable-p file-path))
                            (file-name-nondirectory file-path)))
               (dest-file (when (stringp file-name)
                            (concat media-folder file-name))))
          (when (and (stringp dest-file)
                     (not (file-exists-p dest-file)))
            (copy-file file-path dest-file)
            (save-excursion
              (search-backward link-url)
              (replace-match (concat media-folder file-name)))
            (message (concat file-path " copied to " dest-file))))))))

(defun ed/orgx-propagate-save ()
  (let* ((base-path (file-name-directory buffer-file-name))
         (meta-file (concat base-path "meta.conf"))
         (file-title (ed/orgx-get-file-title)))
    (when (and (string= (file-name-nondirectory buffer-file-name) "content.org")
               (file-exists-p meta-file)
               (file-writable-p meta-file))
      (ed/orgx-parse-links)
      (with-current-buffer (find-file-noselect meta-file)
        (goto-char (point-min))
        (when (re-search-forward "title=.*" nil t)
          (replace-match (concat "title=\"" file-title "\""))
          (save-buffer 0))
        (kill-buffer))
      (message (concat "Saved " (ed/orgx-get-file-name))))))
(add-hook 'after-save-hook 'ed/orgx-propagate-save)

(defun ed/orgx-create-file-structure (title destination &optional buffer)
  (unless (file-exists-p (directory-file-name destination))
    (make-directory destination t)
    (make-directory (concat destination "media"))
    (make-directory (concat destination "templates"))
    (let ((timestamp (current-time)))
      (with-current-buffer (find-file-noselect (concat destination "meta.conf"))
        (insert "author=\"" (user-full-name) "\"\ntimestamp="
                (format-time-string "%Y%m%d%H%M%S" timestamp)
                "\"\ntitle=\"" title "\"")
        (save-buffer 0)
        (kill-buffer))
      (when buffer
        (with-current-buffer buffer
          (ed/orgx-parse-links)
          (copy-file buffer-file-name
                     (concat destination "content.org"))))
      (with-current-buffer (find-file (concat destination "content.org"))
        (unless buffer
          (goto-char 1)
          (insert "#+title: " title "\n#+date: "
                  (format-time-string "<%Y-%m-%d %a %H:%M>" timestamp)
                  "\n\n"))))
    (message (concat "Opened " (ed/orgx-get-permalink title)))))

(defun ed/orgx-create-file (dir filename)
  "Creating a new orgx file and open it"
  (interactive "Ddirectory where to save your new orgx file: \nsname of your new orgx file: ")
  (let ((destination
         (file-name-as-directory
          (concat (file-name-as-directory dir)
                  (ed/orgx-get-permalink filename)))))
    (ed/orgx-create-file-structure filename destination)))

(defun ed/orgx-create-from-buffer (dir)
  "Creating a new orgx file from the current buffer"
  (interactive "Ddirectory where to save your new orgx file: ")
  (let* ((file-title (ed/orgx-get-file-title))
         (filename (if (string= file-title "")
                       (file-name-sans-extension (buffer-name))
                     (ed/orgx-get-permalink file-title)))
         (destination
          (file-name-as-directory (concat (file-name-as-directory dir) filename))))
    (ed/orgx-create-file-structure file-title destination (current-buffer))))

(defun ed/orgx-open-file (dir)
  "Open an orgx file"
  (interactive "Dorgx file to open: ")
  (let* ((file-path (file-name-as-directory dir))
         (meta-file (concat file-path "meta.conf"))
         (content-file (concat file-path "content.org")))
    (if (and (file-exists-p meta-file)
             (file-writable-p meta-file)
             (file-exists-p content-file)
             (file-writable-p content-file))
        (progn
          (find-file content-file)
          (message (concat "Opened " (ed/orgx-get-file-name))))
      (message (concat "Not a valid orgx file: " dir)))))
EOF

        exec 1>&6 6>&- # Restore stdout and close fd #6

        chmod u+x $WORKINGREP/usr/bin/$APPNAME.py

        echo "Application installation finished."

Changes to narv.py.

38
39
40
41
42
43
44

45
46

47
48
49
50
51
52
53
...
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
...
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
...
285
286
287
288
289
290
291





















292
293
294
295
296
297
298
        'css': 'text/css; charset=utf-8',
        'otf': 'application/font-sfnt',
        'woff': 'application/font-woff',
        'atom': 'application/atom+xml; charset=utf-8',
        'json': 'application/json; charset=utf-8',
        'js': 'text/javascript; charset=utf-8',
        'py': 'text/plain',

        'el': 'text/plain',
        'org': 'text/plain; charset=utf-8'

    }

    def __init__(self, request, App):

        self.routes = []
        self.App = App
        self.appname = App.appname
................................................................................

            route = 'srv/{0}/{1}'.format(self.appname, route)
            if self.test_local_file_exists(route):
                return True

        return False


    def parse_content(self, content):
        #content = re.sub(r'\s(src|href)="media/',
        #                 r' \1="{0}/media/'.format(
        #                     os.path.basename(
        #                         os.path.dirname(self.resource_path))),
        #                 content.decode('utf-8'))
        #return bytes(content, 'utf-8')
        return content


    def preprocess_content(self):
        success = True
        if self.resource_is_method:
            log("[{0}] Spawn custom content method".format(self.resource_path))
            self.content = getattr(self.App, self.resource_path)()

................................................................................

    def send_content(self):
        if self.resource_is_method:
            self.App.wfile.write(self.content)

        else:
            with open(self.resource_path, 'rb') as f:
                if self.resource_ext == 'html':
                    self.App.wfile.write(
                        self.parse_content(f.read()))

                else:
                    shutil.copyfileobj(f, self.App.wfile)



# TODO: May be usefull !!
class RedirectHandler(BaseHTTPRequestHandler):
    def do_HEAD(s):
        s.send_response(301)
        # s.send_header("Location", REDIRECTIONS.get(s.path, LAST_RESORT))
        s.end_headers()
    def do_GET(s):
        s.do_HEAD()



class IcanDoThat(BaseHTTPRequestHandler):
    """ Main HTTP handler """
    server_version = '0xGA/0.1'

................................................................................
        self.do_error_page('501', reason)


    def build_headers(self, resno, content_type = 'text/plain'):
        self.send_response(resno)
        if content_type != None:
            self.send_header('Content-Type', content_type)





















        self.end_headers()


    def do_GET(self):
        self.load_config()

        if not self.error:







>

|
>







 







<
<
<
<
<
<
<
<
<
<







 







<
<
<
<
<
|
<
<
<
<
<
<
<
<
<
<
<







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
...
146
147
148
149
150
151
152










153
154
155
156
157
158
159
...
166
167
168
169
170
171
172





173











174
175
176
177
178
179
180
...
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
        'css': 'text/css; charset=utf-8',
        'otf': 'application/font-sfnt',
        'woff': 'application/font-woff',
        'atom': 'application/atom+xml; charset=utf-8',
        'json': 'application/json; charset=utf-8',
        'js': 'text/javascript; charset=utf-8',
        'py': 'text/plain',
        'gpg': 'text/plain',
        'el': 'text/plain',
        'org': 'text/plain; charset=utf-8',
        'pdf': 'application/pdf'
    }

    def __init__(self, request, App):

        self.routes = []
        self.App = App
        self.appname = App.appname
................................................................................

            route = 'srv/{0}/{1}'.format(self.appname, route)
            if self.test_local_file_exists(route):
                return True

        return False












    def preprocess_content(self):
        success = True
        if self.resource_is_method:
            log("[{0}] Spawn custom content method".format(self.resource_path))
            self.content = getattr(self.App, self.resource_path)()

................................................................................

    def send_content(self):
        if self.resource_is_method:
            self.App.wfile.write(self.content)

        else:
            with open(self.resource_path, 'rb') as f:





                shutil.copyfileobj(f, self.App.wfile)














class IcanDoThat(BaseHTTPRequestHandler):
    """ Main HTTP handler """
    server_version = '0xGA/0.1'

................................................................................
        self.do_error_page('501', reason)


    def build_headers(self, resno, content_type = 'text/plain'):
        self.send_response(resno)
        if content_type != None:
            self.send_header('Content-Type', content_type)
        self.end_headers()


    def do_PUT(self):
        self.send_response(403)
        self.end_headers()


    def do_HEAD(self):
        self.load_config()

        if not self.error:
            rh = ResourceHelper(self.path, self)
            if rh.find_route() and rh.preprocess_content():
                self.send_response(200)
            else:
                self.send_response(404)

        else:
            self.send_response(501)

        self.end_headers()


    def do_GET(self):
        self.load_config()

        if not self.error:

Changes to narv_install.sh.

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
#!/usr/bin/env bash

PAYLOAD="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
8ddff/31119//fXXX3/99/QfYZqsDgAoAAA="

























WORKINGREP=`realpath ./narvroot`

echo "$PAYLOAD" | base64 -d > narv.tar.gz
tar xzf narv.tar.gz
rm narv.tar.gz
gzip -d narv.gz narv.py.gz


|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







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
#!/usr/bin/env bash

PAYLOAD="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
AAA="

WORKINGREP=`realpath ./narvroot`

echo "$PAYLOAD" | base64 -d > narv.tar.gz
tar xzf narv.tar.gz
rm narv.tar.gz
gzip -d narv.gz narv.py.gz