~luxferre/Bopher-NG

aa3a2522037842c627b4e994fb8c42b549b37b72 — Luxferre 1 year, 8 months ago f9a9be1
Added list2map.sh tool
2 files changed, 62 insertions(+), 1 deletions(-)

M tools/README-tools.md
A tools/list2map.sh
M tools/README-tools.md => tools/README-tools.md +27 -1
@@ 2,7 2,7 @@

Bopher Tools is a small collection of simple shell scripts that:

- are written in pure Bash with no external dependencies;
- are written in pure Bash with no external dependencies (unless explicitly stated otherwise);
- are totally independent from each other (but can be combined in the true spirit of Unix philosophy);
- only accept input from stdin and only output their results into stdout;
- aim to ease your life when it comes to creating and publishing your own content in Gopherspace.


@@ 133,3 133,29 @@ When running `cat example.gmi | bash gmi2txt.sh 67 5`, this file translates to t
                                                                        
     See ya!                                                            
```

## `list2map.sh`

This tool, which probably is the smallest but the most sophisticated one in the entire collection, accepts the list of files and directories (possibly generated with `find` command) and generates, line by line, a portion of Gophermap based on their type (for this, it requires the external `file` command dependency), root directory name and hostname/port number optionally passed to the script on invocation. The tool automatically applies the following rules:

- only the basename part of the file/directory is used as the entry name/description;
- if the file is a directory (MIME type `inode/directory`), the generated selector will actually refer to the `index.map` file in that directory and the entry type will be 1;
- files (or directories) named `index.map` are not themselves included in the output;
- if the file's MIME type starts with `text`, the entry type will be set to 0, otherwise it will be set to 9.

Note that the tool itself doesn't do any filtering on input names or how they are presented. All filtering, if necessary, should be done on the `find` invocation step.

Example - build a Gophermap fragment from this repo's starting directory, excluding all dotfiles, using `.` as root and assuming we'll serve this map from `example.com:777`:
```
$ find . ! -path '.' ! -path '*/.*' | bash tools/list2map.sh . example.com 777
0COPYING        /COPYING        example.com     777
1tools  /tools/index.map        example.com     777
0gopherinfo.sh  /tools/gopherinfo.sh    example.com     777
0phlow.sh       /tools/phlow.sh example.com     777
0gmi2map.sh     /tools/gmi2map.sh       example.com     777
0gmi2txt.sh     /tools/gmi2txt.sh       example.com     777
0README-tools.md        /tools/README-tools.md  example.com     777
0list2map.sh    /tools/list2map.sh      example.com     777
0bopher-ng.sh   /bopher-ng.sh   example.com     777
0README.md      /README.md      example.com     777
```

A tools/list2map.sh => tools/list2map.sh +35 -0
@@ 0,0 1,35 @@
#!/bin/bash
# A simple tool for Gophermap fragment generation from existing file/directory lists
# Depends on file external command to determine the type
#
# Usage: find [root] [params] | list2map.sh 
#
# Created by Luxferre in 2023, released into public domain

shopt -s extglob # enable extended pattern matching (just to be sure)

RDIR="$1" # root directory, no substitution if empty
THOST="$2" # can be empty per spec
TPORT="$3" # can be empty too
INDEXFILE='index.map' # the basename to consider an index file

typequery() { # external command wrapper to fetch the file's MIME type
  local res="$(file -Nn --mime-type "$1")"
  printf '%s' "${res##*: }"
}

while read -rs fpath; do # fully line-based operation
  ftype="$(typequery "$fpath")" # MIME type here
  bname="${fpath##*/}" # basename here
  [[ "$bname" == "$INDEXFILE" ]] && continue # skip index map
  etype=9 # default map entry type is binary until proven otherwise
  esel="${fpath##$RDIR}" # if RDIR is empty, they are the same
  if [[ "$ftype" == 'inode/directory' ]]; then # it's a directory
    etype=1
    esel="${esel}/${INDEXFILE}" # update the selector
  elif [[ "${ftype%%/*}" == 'text' ]]; then # update etype for text files
    etype=0
  fi
  # output the RFC-compliant Gophermap line
  printf '%s%s\t%s\t%s\t%s\r\n' "$etype" "$bname" "$esel" "$THOST" "$TPORT" 
done