Add basic documentation parser

This commit is contained in:
Nicolas Mattia 2019-12-01 23:25:35 +01:00
parent 2c6c9ddc46
commit cd6d9bcec3
6 changed files with 269 additions and 18 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
docparse/target

View file

@ -1,5 +1,56 @@
{ lib, libb, builtinz, arg }:
let
mkAttrs = attrs0:
{ # foo bar< baz
# baz? foooo
# one
# two
# three
# four
root = attrs0.root or null;
# hello src
# hello world
src = attrs0.src or null;
# hello src
usePureFromTOML = attrs0.usePureFromTOML or true;
# hello src
compressTarget = attrs0.compressTarget or true;
# hello src
doCheck = attrs0.doCheck or true;
# hello src
buildInputs = attrs0.buildInputs or [];
# hello src
removeReferencesToSrcFromDocs = attrs0.removeReferencesToSrcFromDocs or true;
# hello src
doDoc = attrs0.doDoc or true;
# hello src
doDocFail = attrs0.doDocFail or false;
# hello src
release = attrs0.release or true;
# hello src
override = attrs0.override or (x: x);
# hello src
cargoBuild = attrs0.cargoBuild or
''cargo build "''${cargo_release}" -j $NIX_BUILD_CORES -Z unstable-options --out-dir out'';
# hello src
singleStep = attrs0.singleStep or false;
# hello src
targets = attrs0.targets or null;
# hello src
name = attrs0.name or null;
# hello src
version = attrs0.version or null;
# hello src
cargoTestCommands = attrs0.cargoTestCommands or
[ ''cargo test "''${cargo_release}" -j $NIX_BUILD_CORES'' ];
# hello src
copyTarget = attrs0.copyTarget or false;
# hello src
copyBins = attrs0.copyBins or true;
# hello src
copyDocsToSeparateOutput = attrs0.copyDocsToSeparateOutput or true;
};
argIsAttrs =
if lib.isDerivation arg then false
else if lib.isString arg then false
@ -8,7 +59,11 @@ let
else true;
# if the argument is not an attribute set, then assume it's the 'root'.
attrs = if argIsAttrs then arg else { root = arg; };
attrs =
if argIsAttrs
then mkAttrs arg
else mkAttrs { root = arg; };
# we differentiate 'src' and 'root'. 'src' is used as source for the build;
# 'root' is used to find files like 'Cargo.toml'. As often as possible 'root'
@ -17,8 +72,8 @@ let
# not defined.
sr =
let
hasRoot = builtins.hasAttr "root" attrs;
hasSrc = builtins.hasAttr "src" attrs;
hasRoot = ! isNull attrs.root;
hasSrc = ! isNull attrs.src;
isPath = x: builtins.typeOf x == "path";
root = attrs.root;
src = attrs.src;
@ -40,18 +95,18 @@ let
# src: no, root: yes
else throw "please specify either 'src' or 'root'";
usePureFromTOML = attrs.usePureFromTOML or true;
usePureFromTOML = attrs.usePureFromTOML;
readTOML = builtinz.readTOML usePureFromTOML;
# config used during build the prebuild and the final build
buildConfig = {
compressTarget = attrs.compressTarget or true;
doCheck = attrs.doCheck or true;
buildInputs = attrs.buildInputs or [];
removeReferencesToSrcFromDocs = attrs.removeReferencesToSrcFromDocs or true;
doDoc = attrs.doDoc or true;
compressTarget = attrs.compressTarget;
doCheck = attrs.doCheck;
buildInputs = attrs.buildInputs;
removeReferencesToSrcFromDocs = attrs.removeReferencesToSrcFromDocs;
doDoc = attrs.doDoc;
#| Whether or not the rustdoc can fail the build
doDocFail = attrs.doDocFail or false;
doDocFail = attrs.doDocFail;
release = attrs.release or true;
@ -87,7 +142,7 @@ let
if ! isWorkspace
then (_member: _cargotoml: true)
else
if builtins.hasAttr "targets" attrs
if ! isNull attrs.targets
then (_member: cargotoml: lib.elem cargotoml.package.name attrs.targets)
else (member: _cargotoml: member != ".");
in
@ -140,15 +195,18 @@ let
# The cargo lock
cargolock = readTOML (root + "/Cargo.lock");
packageName = attrs.name or toplevelCargotoml.package.name or
(if isWorkspace then "rust-workspace" else "rust-package");
packageName =
if ! isNull attrs.name
then attrs.name
else toplevelCargotoml.package.name or
(if isWorkspace then "rust-workspace" else "rust-package");
packageVersion = attrs.version or toplevelCargotoml.package.version or
"unknown";
packageVersion =
if ! isNull attrs.version
then attrs.version
else toplevelCargotoml.package.version or "unknown";
cargoTestCommands = attrs.cargoTestCommands or [
''cargo test "''${cargo_release}" -j $NIX_BUILD_CORES''
];
cargoTestCommands = attrs.cargoTestCommands;
#| Whether or not to forward intermediate build artifacts to $out
copyTarget = attrs.copyTarget or false;

82
docparse/Cargo.lock generated Normal file
View file

@ -0,0 +1,82 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "autocfg"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "byteorder"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cbitset"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "docparse"
version = "0.1.0"
dependencies = [
"rnix 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-traits"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rnix"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cbitset 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rowan 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rowan"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"smol_str 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
"text_unit 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-hash"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "smol_str"
version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "text_unit"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
"checksum cbitset 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29b6ad25ae296159fb0da12b970b2fe179b234584d7cd294c891e2bbb284466b"
"checksum num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c81ffc11c212fa327657cb19dd85eb7419e163b5b076bede2bdb5c974c07e4"
"checksum rnix 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab1d6816b24e552bd47a4bed172dff60c67ca7a0b073211e6d3799298d30002c"
"checksum rowan 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fc3a6fb2a35518af7cab43ec4e21ca82eb086a8b3bb1739e426dc3923d459607"
"checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8"
"checksum smol_str 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "34836c9a295c62c2ce3514471117c5cb269891e8421b2aafdd910050576c4d8b"
"checksum text_unit 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e08bbcb7a3adbda0eb23431206b653bdad3d8dea311e72d36bf2215e27a42579"

8
docparse/Cargo.toml Normal file
View file

@ -0,0 +1,8 @@
[package]
name = "docparse"
version = "0.1.0"
authors = ["Nicolas Mattia <nicolas@nmattia.com>"]
edition = "2018"
[dependencies]
rnix = "0.7"

4
docparse/shell.nix Normal file
View file

@ -0,0 +1,4 @@
let
pkgs = import ../nix {};
in pkgs.mkShell
{ nativeBuildInputs = [ pkgs.cargo pkgs.rustfmt ]; }

98
docparse/src/main.rs Normal file
View file

@ -0,0 +1,98 @@
use std::{env, fs};
use rnix::{types::*, NodeOrToken, SyntaxKind::*, SyntaxNode};
fn main() {
let file = match env::args().skip(1).next() {
Some(file) => file,
None => {
panic!("No file given");
}
};
let content = fs::read_to_string(&file).expect("Couldn't read content");
let ast = rnix::parse(&content).as_result().expect("Couldn't parse");
let lambda = ast
.root()
.inner()
.and_then(Lambda::cast)
.ok_or("root isn't a lambda")
.expect("Something bad happened");
let args = lambda.body().and_then(LetIn::cast).unwrap();
for kv in args.entries() {
if let Some(key) = kv.key() {
if format!("{}", key.path().next().unwrap()) == "mkAttrs" {
if let Some(val) = kv.value() {
print_mk_attrs(val);
}
}
}
}
}
fn print_mk_attrs(mk_attrs: SyntaxNode) {
let body = Lambda::cast(mk_attrs)
.unwrap()
.body()
.and_then(AttrSet::cast)
.expect("Not a pattern");
for e in body.entries() {
let k = e.key().expect("No key").path().next().unwrap();
let mshown = e
.value()
.and_then(OrDefault::cast)
.expect("Is not OrDefault")
.default().and_then(|def|
{
let shown = format!("{}", def);
if shown != "null" {
Some(shown)
} else {
None
}
});
let e = e.node().clone();
let c = find_comment(e).expect("No comment");
println!("### {} \n", k);
println!("{}", c);
if let Some(shown) = mshown {
println!("");
println!("_default value:_");
println!("``` nix");
println!("{}", shown);
println!("```");
}
println!("");
}
}
fn find_comment(node: SyntaxNode) -> Option<String> {
let mut node = NodeOrToken::Node(node);
let mut comments = Vec::new();
loop {
loop {
if let Some(new) = node.prev_sibling_or_token() {
node = new;
break;
} else {
node = NodeOrToken::Node(node.parent()?);
}
}
match node.kind() {
TOKEN_COMMENT => match &node {
NodeOrToken::Token(token) => comments.push(token.text().clone()),
NodeOrToken::Node(_) => unreachable!(),
},
t if t.is_trivia() => (),
_ => break,
}
}
let doc = comments
.iter()
.map(|it| it.trim_start_matches('#').trim())
.collect::<Vec<_>>()
.join("\n ");
return Some(doc).filter(|it| !it.is_empty());
}