[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[gnunet-scheme] 67/324: scripts: Don't flatten the FS tree and use SXML
From: |
gnunet |
Subject: |
[gnunet-scheme] 67/324: scripts: Don't flatten the FS tree and use SXML instead of JSON |
Date: |
Tue, 21 Sep 2021 13:21:47 +0200 |
This is an automated email from the git hooks/post-receive script.
maxime-devos pushed a commit to branch master
in repository gnunet-scheme.
commit 9befd560c5eccc4fdc5f5ded588167cf9fd73b68
Author: Maxime Devos <maximedevos@telenet.be>
AuthorDate: Sat Jan 30 21:02:07 2021 +0100
scripts: Don't flatten the FS tree and use SXML instead of JSON
* gnu/gnunet/scripts/download-store.scm: use a SXML tree instead
of JSON.
* gnu/gnunet/scripts/publish-store.scm: likewise.
---
gnu/gnunet/scripts/download-store.scm | 214 +++++++++++++++-------------------
gnu/gnunet/scripts/publish-store.scm | 107 ++++++++---------
2 files changed, 147 insertions(+), 174 deletions(-)
diff --git a/gnu/gnunet/scripts/download-store.scm
b/gnu/gnunet/scripts/download-store.scm
index d3c9e15..d52ed28 100644
--- a/gnu/gnunet/scripts/download-store.scm
+++ b/gnu/gnunet/scripts/download-store.scm
@@ -25,6 +25,7 @@
(rnrs io simple)
(rnrs io ports)
(rnrs bytevectors)
+ (only (ice-9 match) match)
(only (rnrs control) when unless)
(only (rnrs programs) exit)
(only (guile)
@@ -35,7 +36,6 @@
throw
file-exists? symlink stat mkdir umask
chmod stat:mode logior logand lognot getenv)
- (json)
(srfi srfi-1)
(srfi srfi-1)
(srfi srfi-26)
@@ -43,7 +43,7 @@
(srfi srfi-41))
(begin
(define %supported-formats
- '("any" "gnunet-nix-archive-json/0"))
+ '("gnunet-nar-sxml/0"))
(define (gnunet-fs-uri? str)
(or (string-prefix? "gnunet://fs/chk" str)
@@ -103,7 +103,7 @@ the options @var{options} are applied."
"scheme-gnunet download-store v0.0")
(define %help
- "Usage: download-store [OPTIONS] -i URI -o DIRECTORY
+ "Usage: download-store [OPTIONS] -i URI -o FILENAME
Download store items from GNUnet using a GNUnet CHK or LOC URI
(gnunet://fs/chk/...).
@@ -117,7 +117,7 @@ Download resumption is currently unsupported.
-f, --format Representation of store items to use,
'any' by default.
-i, --input URI to download
- -o, --output Directory to save store items in.
+ -o, --output Filename to save store item at.
--nar Location to write the nar to.
GNUnet options
@@ -138,8 +138,8 @@ GNUnet options
((option-ref options 'help #f)
(display %help)
(newline))
- ((member (option-ref options 'format "gnunet-nix-archive-json/0")
- '("gnunet-nix-archive-json/0" "any"))
+ ((equal? (option-ref options 'format "gnunet-nar-sxml/0")
+ "gnunet-nar-sxml/0")
;; TODO should multiple outputs be allowed?
(when (option-ref options 'output #f)
(download:gnunet-nar/0-to-fs
@@ -187,126 +187,104 @@ instead of writing to a file."
(define (download:gnunet-nar/0-to-fs uri output)
"Download the normalised archive in @var{gnunet-nix-archive-json/0}
format from @var{uri} to the directory @var{output}."
+ (when (file-exists? output)
+ (throw 'xxx-already-exists))
+ (download-sxml/root! (download->sxml uri) output))
+
+ (define (download->sxml uri)
(let* ((container/bv (gnunet-download/bytevector uri))
- (container/json (utf8->string container/bv))
- (container/scm (json-string->scm container/json)))
- (unless (equal? (assoc "version" container/scm)
- '("version" . "gnunet-nix-archive-json/0"))
- (throw 'download-eep 'xxx-proper-error-message))
- (let ((sorted (sort-entries (cdr (assoc "entries" container/scm)))))
- (verify-entries sorted)
- (download-entries! sorted output))))
+ ;; XXX don't allow hash-comma and other read constructs
+ ;; XXX check locale, character encoding, etc. things
+ (container/sxml
+ (read (open-bytevector-input-port container/bv))))
+ container/sxml))
(define (download:gnunet-nar/0-to-nar uri output)
"Download the normalised archive in @var{gnunet-nix-archive-json/0}
format from @var{uri} to the file @var{output}."
(throw 'todo 'implement-me 'please))
- (define (download-entries! entries output)
- (define (prefix name)
- (string-append output "/" name))
- (define (download-entry! entry)
- (let* ((type (cdr (assoc "type" entry)))
- (name (cdr (assoc "name" entry)))
- (output (prefix name)))
- (cond ((string=? type "directory")
- (mkdir output))
- ((or (string=? type "regular")
- (string=? type "executable"))
- (gnunet-download (cdr (assoc "hash" entry)) output)
- (when (string=? type "executable")
- (chmod output
- (logior (stat:mode (stat output))
- (logand #o111 (lognot (umask)))))))
- ((string=? type "symlink")
- ;; FIXME check whether guile rejects
- ;; \0, or silently trims them off
- (symlink (cdr (assoc "target" entry)) output))
- (else ???))))
- (unless (file-exists? output)
- (mkdir output))
- (vector-for-each download-entry! entries))
+ (define (create:regular hash output executable?)
+ (gnunet-download hash output)
+ (when executable?
+ (chmod output
+ (logior (stat:mode (stat output))
+ (logand #o111 (lognot (umask)))))))
- (define (sort-entries entries)
- "Sort ENTRIES, a list or vector of nar entries,
-in an order they should be created (parent directories should
-be created before children, for example"
- (define (list<? component<? x y)
- (cond ((and (eq? x '()) (eq? y '())) #f)
- ((eq? x '()) #t)
- ((eq? y '()) #f)
- ((component<? (car x) (car y)) #t)
- ((component<? (car y) (car x)) #f)
- (else (list<? component<? (cdr x) (cdr y)))))
- (define (entry<? x y)
- (list<? string<?
- (string-split (cdr (assoc "name" x)) #\/)
- (string-split (cdr (assoc "name" y)) #\/)))
- (sort entries entry<?))
+ (define (create:symlink target output)
+ (when (string-any #\nul target)
+ ;; Probably unsupported by the kernel,
+ ;; and various applications.
+ (throw 'XXX-no-nul-bytes-in-symlinks))
+ (symlink target output))
- (define (vector->stream s)
- (stream-map (cute vector-ref s <>)
- (stream-take (vector-length s)
- (stream-from 0))))
+ (define (download-sxml/root! sxml output)
+ "Download the structure described by SXML to OUTPUT.
+OUTPUT may not already exists, and the file described by
+SXML may not have a name."
+ (match sxml
+ (`(regular (@ (executable? ,executable?)
+ (hash ,hash)))
+ (create:regular hash output executable?))
+ (`(symlink (@ (target ,target)))
+ (create:symlink target output))
+ ;; XXX I thought I never created a
+ ;; node (directory (@) . stuff)?
+ ;; Where did the (@) appear?
+ (`(directory (@) . ,files)
+ (mkdir output)
+ (verify-directory-entries! files)
+ (for-each (cute download-sxml/entry! <> output) files))))
- (define (store-name? x)
- 'xxx 'todo 'for-example-no-nul-bytes
- #t)
+ (define (download-sxml/entry! sxml parent-output)
+ "Download the structure described by SXML to OUTPUT/NAME,
+where NAME is the name of the file described by SXML.
+OUTPUT/NAME may not already exist."
+ (define (prefix name)
+ (string-append parent-output "/" name))
+ (match sxml
+ (`(regular (@ (name ,name)
+ (executable? ,executable?)
+ (hash ,hash)))
+ (create:regular hash (prefix name) executable?))
+ (`(symlink (@ (target ,target)
+ (name ,target)))
+ (create:symlink target (prefix name)))
+ (`(directory (@ (name ,name)) . ,files)
+ (mkdir (prefix name))
+ (verify-directory-entries! files)
+ (for-each (cute download-sxml/entry! <> (prefix name)) files))))
- (define (verify-entries sorted)
- "Make sure there are no inconsistencies in SORTED"
- (define sorted-stream (vector->stream sorted))
- (define (name x)
- (cdr (assoc "name" x)))
- (define (duplicate? l)
- (apply (lambda (x y)
- (string=? (name x) (name y)))
- l))
- (define sorted-2à2
- (stream-zip sorted-stream
- (stream-cdr sorted-stream)))
- (define duplicates
- (stream-filter duplicate? sorted-2à2))
- (define bad-characters
- (stream-filter (negate store-name?) sorted-stream))
- (define (bad-name? x)
- (or (= 0 (string-length x))
- (any (lambda (x)
- (or (= 0 (string-length x))
- (string=? x ".")
- (string=? x "..")))
- (string-split x #\/))))
- (define bad-name
- (stream-filter (compose bad-name? name) sorted-stream))
- (define (directory-exists? latest next)
- (let ((type-latest (cdr (assoc "type" latest)))
- (type-next (cdr (assoc "type" next))))
- ;; entry in directory
- (or (and (equal? type-latest "directory")
- (string-prefix?
- (string-append (name latest) "/")
- (name next)))
- ;; two entries in same directory,
- ;; or next entry is in some (grand...)parent of
- ;; type-latest, or it is a top-level file
- (let ((d (dirname (name next))))
- (or (string=? d ".")
- (string-prefix? (string-append d "/") (name latest)))))))
- (define missing-dir
- (stream-filter (lambda (args)
- (not (apply directory-exists? args)))
- sorted-2à2))
- (define first-entry-not-root
- (stream-filter
- (negate (lambda (x) (string=? "." (dirname (name x)))))
- (stream-take 1 sorted-stream)))
- (define bad
- (stream-append
- (stream-map (cute cons 'first-entry-not-root <>)
- first-entry-not-root)
- (stream-map (cute cons 'duplicate <>) duplicates)
- (stream-map (cute cons 'bad-characters <>) bad-characters)
- (stream-map (cute cons 'bad-name <>) bad-name)
- (stream-map (cute cons 'missing-dir <>) missing-dir)))
- (stream-for-each (lambda (z) (throw '??? z))
- bad))))
+ (define (verify-directory-entries! entries)
+ "Verify whether the names of the entries in ENTRIES
+are unique, and whether they are reasonable (no #\nul bytes,
+not . or ..)."
+ (define (entry-name sxml)
+ (match sxml
+ (`(regular (@ (name ,name) . ,_))
+ name)
+ (`(symlink (@ (name ,name) . ,_))
+ name)
+ (`(directory (@ (name ,name) . ,_) . ,_)
+ name)))
+ (define names (map entry-name entries))
+ ;; Detect troublesome names
+ (for-each (lambda (name)
+ (cond ((not (string=? name))
+ (throw 'XXX-is-not-a-string))
+ ((or (string=? name ".")
+ (string=? name ".."))
+ (throw 'XXX-no-dotdot-allowed))
+ ((string-any #\nul name)
+ (throw 'XXX-no-nul-allowed))
+ ((> (string-length name) 255)
+ (throw 'XXX-way-to-long-filename))))
+ names)
+ ;; Detect duplicates
+ (let loop ((previous #f) (next-names (sort names string<?)))
+ (if (null? next-names)
+ 'ok
+ (let ((next (car next-names)))
+ (if (equal? previous next)
+ (throw 'duplicate-name)
+ (loop next (cdr next-names)))))))))
diff --git a/gnu/gnunet/scripts/publish-store.scm
b/gnu/gnunet/scripts/publish-store.scm
index ca5c2af..a41a6c4 100644
--- a/gnu/gnunet/scripts/publish-store.scm
+++ b/gnu/gnunet/scripts/publish-store.scm
@@ -17,21 +17,26 @@
;; SPDX-License-Identifier: AGPL-3.0-or-later
;; Brief: publish an item of the store (GNU Guix) to GNUnet
-;; A quirk of the directory format to keep in mind:
+;;
+;; A quirk of the GNUnet's directory format to keep in mind:
;; * the basename of the directory is saved in the .gnd
;; * the basename of regular files that are published
;; as-is isn't saved (but is included in the surrounding
;; .gnd)
+;;
+;; The format used here is a SXML tree, as that seems most
+;; simple to use with Guix' @code{write-file-tree}.
(library (gnu gnunet scripts publish-store)
+ ;; XXX check exports
(export main
store-item->sxml
directory->sxmls
publish-object
- publish-sxml->json
gnunet-publish)
(import (rnrs base)
(rnrs io simple)
+ (ice-9 optargs)
(ice-9 getopt-long)
(gnu gnunet scripts guix-stuff)
(only (ice-9 ftw) scandir)
@@ -55,7 +60,6 @@
(ice-9 regex)
(ice-9 popen)
(ice-9 rdelim)
- (json)
(sxml match)
(only (ice-9 optargs)
define*))
@@ -65,12 +69,13 @@
(help (single-char #\h))
(format (single-char #\f)
(value #t)
- (predicate ,(cute member <> '("gnunet-nix-archive-json/0"))))
+ (predicate ,(cute member <> '("gnunet-nar-sxml/0"))))
(input (single-char #\i)
(value #t))
+ (nar (value #t))
(simulate (single-char #\s))
;; Debugging options
- (display-json)
+ (display-sxml)
;; GNUnet options
(config (single-char #\c)
(value #t))
@@ -83,7 +88,7 @@
(value #t))))
(define *simulate* (make-parameter #f))
- (define *display-json* (make-parameter #f))
+ (define *display-sxml* (make-parameter #f))
(define *config*
(make-parameter (string-append (getenv "HOME")
"/.config/gnunet.conf")))
@@ -102,7 +107,7 @@ the options @var{options} are applied."
(string->number value/str)
default)))
(parameterize ((*simulate* (opt 'simulate (*simulate*)))
- (*display-json* (opt 'display-json (*display-json*)))
+ (*display-sxml* (opt 'display-sxml (*display-sxml*)))
(*config* (opt 'config (*config*)))
(*anonymity* (num 'anonymity (*anonymity*)))
(*priority* (num 'priority (*priority*)))
@@ -119,11 +124,12 @@ Publish a (GNU Guix, or Nix) store item INPUT into GNUnet.
-s, --simulate Do not actually publish INPUT, only print the
computed URI
-f, --format Format for representing a store item,
- currently gnunet-nix-archive-json/0
+ currently gnunet-nar-sxml/0
-i, --input Store item to publish
+ --nar Publish a nar instead
Debugging options
- --display-json Display generated JSON to stdout
+ --display-sxml Display generated SXML to stdout
GNUnet options
-c, --config GNUnet configuration for publishing
@@ -145,23 +151,25 @@ GNUnet options
((option-ref options 'help #f)
(display %help (current-output-port))
(newline (current-output-port)))
- ((equal? (option-ref options 'format "gnunet-nix-archive-json/0")
- "gnunet-nix-archive-json/0")
+ ((equal? (option-ref options 'format "gnunet-nar-sxml/0")
+ "gnunet-nar-sxml/0")
(let ((result
(call-with-options
- options (cute publish-nar
- #:input (option-ref options 'input #f)))))
+ options
+ (lambda ()
+ (publish-nar/sxml/1
+ #:input (option-ref options 'input #f))))))
(format (current-output-port)
"Published at ~a in ~a format~%"
- result "gnunet-nix-archive-json/0")))
+ result "gnunet-nar-sxml/0")))
(else ???))))
- (define* (publish-nar #:key input)
+ (define* (publish-nar/sxml/1 #:key input)
(let* ((sxml (store-item->sxml input))
- (json (publish-sxml->json sxml)))
- (when (*display-json*)
- (display (current-output-port) json))
- (publish-object (string->utf8 json))))
+ (sxml/hashed (sxml-publish-leaves! sxml #:include-name? #f)))
+ (when (*display-sxml*)
+ (write (current-output-port) sxml/hashed))
+ (publish-object (string->utf8 (object->string sxml/hashed)))))
(define gnunet-publish-uri-regexp
(make-regexp "\\b(gnunet://fs/chk/([A-Z0-9]+).([A-Z0-9]+).[0-9]+)\\b"))
@@ -204,44 +212,31 @@ as a string."
(throw 'gnunet-publish-eep 'gnunet-publish-???))
(extract-uri text-1)))
- (define (publish-sxml->json sxml)
+ (define* (sxml-publish-leaves! sxml #:key (include-name? #t))
"Publish SXML, an SXML as returned by store-item->sxml,
-and return a JSON string representing it, with individual files
-referred to by their hash."
- (define (path-append left right)
- (cond ((or (string=? left "") (string=? left "/"))
- right)
- (else (string-append left "/" right))))
- (define (flatten-sxml prefix sxml)
- (sxml-match sxml
- ((regular (@ (name ,name)
- (executable? ,executable?)
- (data-from-file ,filename)))
- `(((name . ,(path-append prefix name))
- (type . ,(if executable?
- "executable"
- "regular"))
- (hash . ,(publish-object filename)))))
- ((symlink (@ (name ,name)
- (target ,target)))
- `(((name . ,(path-append prefix name))
- (type . "symlink")
- (target . ,target))))
- ((directory (@ (name ,name))
- . ,rest)
- `(((name . ,(path-append prefix name))
- (type . "directory"))
- . ,(concatenate
- (map (let ((prefix (path-append prefix name)))
- (lambda (e)
- (flatten-sxml prefix e)))
- rest))))))
- (let* ((flattened (flatten-sxml "" sxml))
- (flattened/vector (list->vector flattened))
- (wrapped `((version . "gnunet-nix-archive-json/0")
- (entries . ,flattened/vector)))
- (wrapped/string (scm->json-string wrapped)))
- wrapped/string))
+and return a SXML where the on-disk filenames are replaced
+by the corresponding GNUnet URIs. If INCLUDE-NAME? is false,
+the name of the top-level entry is not included in the returned
+SXML."
+ (define (maybe-name name)
+ (if include-name?
+ `((name ,name))
+ '()))
+ (sxml-match sxml
+ ((regular (@ (name ,name)
+ (executable? ,executable?)
+ (data-from-file ,filename)))
+ `(regular (@ ,@(maybe-name name)
+ (executable? ,executable?)
+ (hash ,(publish-object filename)))))
+ ((symlink (@ (name ,name)
+ (target ,target)))
+ `(symlink (@ ,@(maybe-name name)
+ (target ,target))))
+ ((directory (@ (name ,name))
+ . ,rest)
+ `(directory (@ ,@(maybe-name name))
+ . ,(map sxml-publish-leaves! rest)))))
(define (publish-object data)
"Publish DATA, a bytevector or filename, and return
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.
- [gnunet-scheme] 55/324: enum: implement docstrings and general niceness, (continued)
- [gnunet-scheme] 55/324: enum: implement docstrings and general niceness, gnunet, 2021/09/21
- [gnunet-scheme] 56/324: Define many GNUnet message types., gnunet, 2021/09/21
- [gnunet-scheme] 69/324: doc: Update ROADMAP with steps to do, gnunet, 2021/09/21
- [gnunet-scheme] 63/324: Define message envelope type and procedures., gnunet, 2021/09/21
- [gnunet-scheme] 73/324: concurrency: implement an ‘update stream’, gnunet, 2021/09/21
- [gnunet-scheme] 81/324: nse: define network structures., gnunet, 2021/09/21
- [gnunet-scheme] 74/324: build: add autotools scripts, gnunet, 2021/09/21
- [gnunet-scheme] 78/324: scripts: download-store: remove debugging, gnunet, 2021/09/21
- [gnunet-scheme] 60/324: Allow using integer->value on maximal value, gnunet, 2021/09/21
- [gnunet-scheme] 68/324: scripts: download-store: allow downloads in nar format, gnunet, 2021/09/21
- [gnunet-scheme] 67/324: scripts: Don't flatten the FS tree and use SXML instead of JSON,
gnunet <=
- [gnunet-scheme] 66/324: Document how to use GNUnet FS without networking., gnunet, 2021/09/21
- [gnunet-scheme] 70/324: doc: Progress update in README.org, gnunet, 2021/09/21
- [gnunet-scheme] 72/324: mq: fix make-envelope/dll constructor., gnunet, 2021/09/21
- [gnunet-scheme] 65/324: download-store: prepare supporting the nar output format, gnunet, 2021/09/21
- [gnunet-scheme] 64/324: scripts: download-store: use SRFI-39 parameters for configuration, gnunet, 2021/09/21
- [gnunet-scheme] 75/324: build: correct propagated-inputs fields, gnunet, 2021/09/21
- [gnunet-scheme] 79/324: vc: add most build artifacts to .gitignore, gnunet, 2021/09/21
- [gnunet-scheme] 80/324: Define various common network structures, gnunet, 2021/09/21
- [gnunet-scheme] 86/324: doc: Update the roadmap on Guix + GNUnet., gnunet, 2021/09/21
- [gnunet-scheme] 84/324: utils: correct definition of unsigned integers, gnunet, 2021/09/21