summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLouie Shprung <lshprung@scu.edu>2022-11-24 16:32:35 -0800
committerLouie Shprung <lshprung@scu.edu>2022-11-24 19:35:00 -0800
commit60cf749e9cb8f751346db0d378ac9ed93534db4d (patch)
tree3e4875e91a0feb9e6bda7b6461ffb4577ba870a0
First commit as mandocsets; added ncurses
-rw-r--r--.gitignore7
-rw-r--r--Makefile30
-rw-r--r--README.md28
-rwxr-xr-xgetters/ncurses.sh12
-rw-r--r--mandocset.py140
5 files changed, 217 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..82f3668
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,7 @@
+*
+!.gitignore
+!getters
+!getters/*
+!Makefile
+!mandocset.py
+!README.md
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..a6fd474
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,30 @@
+all: begin $(DOCSET) $(DOCSET).docset
+
+# Check that DOCSET is set
+.PHONY: begin
+begin:
+ifndef DOCSET
+ $(error Error: DOCSET is not defined)
+endif
+
+# Get DOCSET from system files
+$(DOCSET): getters/$(DOCSET).sh
+ rm -rf $(DOCSET)
+ getters/$(DOCSET).sh
+
+# Convert to dash docset using python script
+$(DOCSET).docset: $(DOCSET) mandocset.py
+ python3 mandocset.py -o $(DOCSET) -p $(DOCSET)/
+
+# Remove generated files/directories
+.PHONY: clean
+clean: begin
+ rm -rf $(DOCSET)
+ rm -rf $(DOCSET).docset
+ rm -rf $(DOCSET).tgz
+
+# Create .tgz archive of generated docset directory
+.PHONY: tgz
+tgz: begin $(DOCSET).tgz
+$(DOCSET).tgz: $(DOCSET).docset
+ tar --exclude='.DS_Store' -cvzf $(DOCSET).tgz $(DOCSET).docset
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..74cc38a
--- /dev/null
+++ b/README.md
@@ -0,0 +1,28 @@
+# mandocset
+
+This is python script (mandocset.py) that generates Dash docset from man pages. It takes folders with man pages as it's arguments. Then in each folder it finds all folders, containing digit in their name, runs `man2html -r` for each file inside them.
+
+By default script uses man2html utility. If you prefer pandoc just use `-e "pandoc -f man -t html"`.
+
+---
+
+This is a loose fork of [Yanpas' repository](https://github.com/Yanpas/mandocset), forked to help package additional man page collections. Currently, this fork only supports Debian and Debian-based systems.
+
+### Prerequisites
+
+- `apt-file`
+- `coreutils`
+- `make`
+- `man2html`
+- `python3`
+
+```
+# apt install apt-file coreutils make man2html python3
+```
+
+### Usage
+
+Available docsets to build are listed under `getters/`. To build a docset, run `make DOCSET=[DOCSET]`, where `[DOCSET]` is the docset you wish to generate (the name of the script in `getters/` minus the extension). Additional make directives include:
+
+- `make clean` - remove the directories created when building the docset
+- `make tgz` - Create a .tgz archive for easily submitting to [Dash-User-Contributions](https://github.com/Kapeli/Dash-User-Contributions)
diff --git a/getters/ncurses.sh b/getters/ncurses.sh
new file mode 100755
index 0000000..e933896
--- /dev/null
+++ b/getters/ncurses.sh
@@ -0,0 +1,12 @@
+#!/usr/bin/env sh
+
+SOURCE="$(apt-file list ncurses-doc | grep -Eo "/usr/share/man/.*")"
+DESTINATION="$(dirname "$0")/../ncurses/"
+
+# Copy files to source
+echo "$SOURCE" | while read -r line; do
+ unset CATEGORY
+ CATEGORY="$(basename "$(dirname "$line")")"
+ mkdir -p "$DESTINATION/$CATEGORY"
+ cp "$line" "$DESTINATION/$CATEGORY"
+done
diff --git a/mandocset.py b/mandocset.py
new file mode 100644
index 0000000..277eff6
--- /dev/null
+++ b/mandocset.py
@@ -0,0 +1,140 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+'''
+Created on 19 feb 2017
+
+DocsetMaker
+
+@author: yanpas
+'''
+
+import sqlite3, argparse, os, re, subprocess, sys
+import shutil
+from typing import List
+
+def getPlist(name: str) -> str:
+ return '''<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleIdentifier</key>
+ <string>{}</string>
+ <key>CFBundleName</key>
+ <string>{}</string>
+ <key>DocSetPlatformFamily</key>
+ <string>{}</string>
+ <key>isDashDocset</key>
+ <true/>
+</dict>
+</plist>
+'''.format(name.split('_')[0],
+ name.replace('_', ' '),
+ name.split('_')[0].lower())
+
+def toHtml(executable: List[str], inf: str, outdir: str, basedir: str):
+ name = os.path.basename(inf)
+ inf_f = open(inf)
+ for suff, decoder in [('.gz', 'gzip'), ('.bz2', 'bzip2')]:
+ if inf.endswith(suff):
+ name = ''.join(name.rsplit(suff, 1))
+ inf_f = subprocess.Popen([decoder, '-d'], stdin=inf_f, stdout=subprocess.PIPE).stdout
+ break
+ subp = subprocess.Popen(executable, stdout=subprocess.PIPE, stdin=inf_f)
+ subp.stdout.readline() # skip Content-Type http header
+ outpath = os.path.join(basedir, name) + '.html'
+ with open(os.path.join(outdir, outpath), 'wb') as f:
+ f.write(subp.stdout.read())
+ if subp.wait() != 0:
+ print(executable[0], "error:", subp.returncode, file=sys.stderr)
+ return outpath
+
+def getType(n):
+ if n == 1:
+ return 'Command'
+ elif n == 2:
+ return 'Service' # Command and Callback have too similar icons
+ elif n == 3:
+ return 'Function'
+ else:
+ return 'Object'
+
+class DocsetMaker:
+ fldre = re.compile(r'\w*(\d)\w*')
+ manfre = re.compile(r'(.+)\..*?\d.*')
+
+ def __init__(self, outname, executable: str):
+ self.outname = outname
+ self.dups = set()
+ self.db = None
+ self.executable = executable.split()
+
+ def __enter__(self):
+ os.makedirs(self.outname + '.docset/Contents/Resources/Documents')
+ self.db = sqlite3.connect(self.outname + '.docset/Contents/Resources/docSet.dsidx')
+ self.db.execute('CREATE TABLE searchIndex(id INTEGER PRIMARY KEY, name TEXT, type TEXT, path TEXT);')
+ self.db.execute('CREATE UNIQUE INDEX anchor ON searchIndex (name, type, path);')
+ with open(self.outname + '.docset/Contents/Info.plist', 'w') as plist:
+ plist.write(getPlist(self.outname))
+ return self
+
+ def __exit__(self, *oth):
+ self.db.close()
+
+ def scanDirectory(self, path1, it, mannum):
+ outbase = self.outname + '.docset/Contents/Resources/Documents'
+ os.makedirs(os.path.join(outbase, it), exist_ok=True)
+ for jt in os.listdir(path1):
+ manf = os.path.join(path1, jt)
+ if os.path.isfile(manf) and re.match(DocsetMaker.manfre, jt):
+ print('\tman', jt)
+ fname = os.path.join(it, os.path.basename(manf)) + '.html'
+ name_for_db = re.match(DocsetMaker.manfre, jt).group(1)
+ dashtype = getType(mannum)
+ new_el = (mannum, name_for_db)
+ if not (new_el in self.dups):
+ outpath = toHtml(self.executable, manf, outbase, it)
+ self.db.execute('INSERT OR IGNORE INTO searchIndex(name, type, path) VALUES (?,?,?);',
+ [name_for_db, dashtype, outpath])
+ self.dups.add(new_el)
+ else:
+ print('\tduplicate skipped',fname)
+
+ def addToDocset(self, indir):
+ self.db.execute("BEGIN")
+ for it in os.listdir(indir):
+ path1 = os.path.join(indir, it)
+ if os.path.isdir(path1):
+ mo = re.match(DocsetMaker.fldre, it)
+ if mo:
+ print('dir', it)
+ self.scanDirectory(path1, it, int(mo.group(1)))
+ self.db.commit()
+
+def main():
+ argp = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+ argp.add_argument('-p', '--paths', help='paths with unpacked archive, order matters', nargs='+', required=True)
+ argp.add_argument('-o', '--out', help='new docset name', required=True)
+ argp.add_argument('-f', help='force outdir', action='store_true')
+ argp.add_argument('-i', help='x1 icon (16x16)', metavar='icon.png')
+ argp.add_argument('-I', help='x2 icon (32x32)', metavar='icon@2x.png')
+ argp.add_argument('-e', default='man2html -r',
+ help=('Executable with arguments which reads from stdin and writes to stdout.'
+ ' Alterntaively "pandoc -f man -t html" may be used'))
+ args = argp.parse_args()
+ if ' ' in args.out:
+ exit('spaces are forbidden in outname')
+ outpath = args.out + '.docset'
+ if os.path.exists(outpath):
+ if args.f:
+ shutil.rmtree(outpath)
+ else:
+ exit('path already exists, exiting (use "-f" to ignore this)')
+ with DocsetMaker(args.out, args.e) as dsm:
+ for path in args.paths:
+ dsm.addToDocset(path)
+ for name,path in [('icon.png', args.i), ('icon@2x.png', args.I)]:
+ if path:
+ shutil.copyfile(path, os.path.join(outpath, name))
+
+if __name__ == '__main__':
+ main()