Compare commits

...
Author SHA1 Message Date
William Langford 51fc9e02a5 fixup! Configure appveyor build to use python 2019-02-22 20:05:09 -05:00
William Langford 0d31bdc4cf fixup! Configure appveyor build to use python 2019-02-22 20:02:44 -05:00
William Langford 0960bfc06d fixup! Configure appveyor build to use python 2019-02-22 19:53:14 -05:00
William Langford 22e6f9e966 Change contains to return true for empty string needles
The behavior of memmem for an empty needle is inconsistent between
implementations of libc.
Our tests imply that we want an empty string needle to be true,
so check for an empty needle before calling memmem.
2019-02-22 19:50:26 -05:00
William Langford df8346a935 Configure appveyor build to use python 2019-02-22 19:50:26 -05:00
William Langford e1fb525796 Cleanup leftover references to ruby 2019-02-22 19:32:31 -05:00
William Langford da170faafe Configure travis build to use python 2019-02-22 19:32:31 -05:00
William Langford 03f746bf24 Remove ruby dependency from mantests 2019-02-22 19:32:31 -05:00
William Langford 5989388c9c Remove ruby dependency from manpage build 2019-02-22 19:32:31 -05:00
William Langford 208c668818 Remove ruby dependency from website build 2019-02-22 19:32:31 -05:00
35 changed files with 772 additions and 378 deletions

No files matched your search

+12 -8
View File
@@ -17,6 +17,7 @@ jobs:
stage: test
os: linux
compiler: gcc
python: 3.6
addons:
apt:
@@ -27,13 +28,13 @@ jobs:
before_install:
- uname -s
- rvm install ruby-1.9.3-p551
- rvm use 1.9.3
- rm src/{lexer,parser}.{c,h}
- sed -i.bak '/^AM_INIT_AUTOMAKE(\[-Wno-portability 1\.14\])$/s/14/11/' modules/oniguruma/configure.ac
install:
- bundle install --gemfile=docs/Gemfile
- pyenv global 3.6
- pip3 install pipenv
- pushd docs && pipenv sync && popd
- wget http://ftp.debian.org/debian/pool/main/b/bison/bison_3.0.2.dfsg-2_amd64.deb
- ar p bison_3.0.2.dfsg-2_amd64.deb data.tar.xz | tar xJ
- if [ -n "$COVERAGE" ]; then pip install --user cpp-coveralls; fi
@@ -104,14 +105,12 @@ jobs:
- uname -s
- brew update
- brew install flex bison
- rvm install ruby-1.9.3-p551
- rvm use 1.9.3
- gem install bundler
- rm src/{lexer,parser}.{c,h}
- sed -i.bak '/^AM_INIT_AUTOMAKE(\[-Wno-portability 1\.14\])$/s/14/11/' modules/oniguruma/configure.ac
install:
- bundle install --gemfile=docs/Gemfile
- pip3 install pipenv
- pushd docs && pipenv sync && popd
- if [ -n "$COVERAGE" ]; then pip install --user cpp-coveralls; fi
@@ -136,7 +135,9 @@ jobs:
install:
- sudo sh alpine-chroot-install -b v3.7 -a "$ARCH"
-p 'build-base automake autoconf bison libtool oniguruma-dev'
-p 'build-base automake autoconf bison git libtool oniguruma-dev python3 python3-dev libxml2-dev libxslt-dev'
- /alpine/enter-chroot pip3 install pipenv
- alpine sh -c 'cd docs && pipenv sync'
before_script:
- autoreconf -if
@@ -146,6 +147,9 @@ jobs:
- alpine make
- alpine make check
after_failure:
- cat test-suite.log
- cat tests/*.log
# Build release binary statically linked with musl libc on Alpine Linux
# (inside chroot). If building a tagged commit, then deploy release
+5 -7
View File
@@ -13,9 +13,8 @@ RUN apt-get update && \
git \
bison \
flex \
ruby \
wget \
ruby-dev && \
python3 \
wget && \
wget https://github.com/kkos/oniguruma/archive/v5.9.6.tar.gz -O onig-5.9.6.tar.gz && \
sha512sum onig-5.9.6.tar.gz | grep 6b048d345e148c9da38af7a8df76d4a358eb3d4db91fa7834076e511f526a63544284f212b0d56badbbd33112c8b458a5fff02bfbbda012ecfe478bc436ea679 && \
tar zxvf onig-5.9.6.tar.gz && \
@@ -25,8 +24,8 @@ RUN apt-get update && \
./configure --prefix=/usr/local && \
make && \
make install ) && \
gem install bundler && \
(cd /app/docs && bundle install) && \
pip3 install pipenv && \
(cd /app/docs && pipenv sync) && \
(cd /app && \
autoreconf -i && \
./configure --disable-valgrind --enable-all-static --prefix=/usr/local && \
@@ -43,8 +42,7 @@ RUN apt-get update && \
bison \
git \
flex \
ruby \
ruby-dev && \
python3 && \
apt-get autoremove -y && \
rm -rf oniguruma-5.9.6 && \
rm -rf /var/lib/apt/lists/* /var/lib/gems
+9 -9
View File
@@ -136,8 +136,8 @@ TESTS_ENVIRONMENT = NO_VALGRIND=$(NO_VALGRIND)
man_MANS = jq.1
if ENABLE_DOCS
jq.1: $(srcdir)/docs/content/3.manual/manual.yml
$(AM_V_GEN) ( cd ${abs_srcdir}/docs; '$(BUNDLER)' exec rake manpage ) > $@ || { rm -f $@; false; }
jq.1: $(srcdir)/docs/content/manual/manual.yml
$(AM_V_GEN) ( cd ${abs_srcdir}/docs; pipenv run python build_manpage.py ) > $@ || { rm -f $@; false; }
jq.1.prebuilt: jq.1
$(AM_V_GEN) cp jq.1 $@ || { rm -f $@; false; }
else
@@ -165,8 +165,8 @@ install-binaries: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) install-exec
DOC_FILES = docs/content docs/public docs/templates docs/site.yml \
docs/Gemfile docs/Gemfile.lock docs/Rakefile docs/README.md \
jq.1.prebuilt
docs/Pipfile docs/Pipfile.lock docs/build_manpage.py \
docs/build_manpage.py docs/README.md jq.1.prebuilt
EXTRA_DIST = $(DOC_FILES) $(man_MANS) $(TESTS) $(TEST_LOG_COMPILER) \
jq.1.prebuilt jq.spec src/lexer.c src/lexer.h src/parser.c \
@@ -180,11 +180,11 @@ EXTRA_DIST = $(DOC_FILES) $(man_MANS) $(TESTS) $(TEST_LOG_COMPILER) \
tests/modules/test_bind_order0.jq \
tests/modules/test_bind_order1.jq \
tests/modules/test_bind_order2.jq tests/onig.supp \
tests/onig.test tests/setup tests/torture/input0.json \
tests/optional.test tests/optionaltest \
tests/utf8-truncate.jq tests/utf8test \
tests/base64.test tests/base64test \
tests/jq-f-test.sh tests/shtest
tests/onig.test tests/setup tests/torture/input0.json \
tests/optional.test tests/optionaltest \
tests/utf8-truncate.jq tests/utf8test \
tests/base64.test tests/base64test \
tests/jq-f-test.sh tests/shtest
+11 -9
View File
@@ -1,26 +1,28 @@
environment:
matrix:
- MSYSTEM: MINGW64
PATH: C:\msys64\usr\bin;C:\msys64\mingw64\bin;C:\Windows\System32;C:\Windows;%PATH%
PATH: C:\Python36;C:\Python36\Scripts;C:\msys64\usr\bin;C:\msys64\mingw64\bin;C:\Windows\System32;C:\Windows;%PATH%
- MSYSTEM: MINGW32
PATH: C:\msys64\usr\bin;C:\msys64\mingw32\bin;C:\Windows\System32;C:\Windows;%PATH%
PATH: C:\Python36;C:\Python36\Scripts;C:\msys64\usr\bin;C:\msys64\mingw32\bin;C:\Windows\System32;C:\Windows;%PATH%
clone_script:
- bash -lc "git clone -q --branch=$APPVEYOR_REPO_BRANCH https://github.com/${APPVEYOR_REPO_NAME}.git $APPVEYOR_BUILD_FOLDER"
- bash -lc "cd $APPVEYOR_BUILD_FOLDER && git checkout -qf $APPVEYOR_REPO_BRANCH"
- bash -lc "echo $APPVEYOR_PULL_REQUEST_HEAD_REPO_NAME - $APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH"
- bash -lc "git clone -q --branch=${APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH:-$APPVEYOR_REPO_BRANCH} https://github.com/${APPVEYOR_PULL_REQUEST_HEAD_REPO_NAME:-$APPVEYOR_REPO_NAME}.git $APPVEYOR_BUILD_FOLDER"
- bash -lc "cd $APPVEYOR_BUILD_FOLDER && git checkout -qf ${APPVEYOR_PULL_REQUEST_HEAD_REPO_BRANCH:APPVEYOR_REPO_BRANCH}"
- bash -lc "cd $APPVEYOR_BUILD_FOLDER && git submodule update --init --recursive"
install:
# update mysy2
# update msys2
- C:\msys64\usr\bin\bash -lc "pacman --needed --noconfirm -Sy pacman-mirrors"
- C:\msys64\usr\bin\bash -lc "pacman --noconfirm -Sy"
- C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S autoconf automake bison flex"
- C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S git"
- C:\msys64\usr\bin\bash -lc "pacman --noconfirm -Su"
- C:\msys64\usr\bin\bash -lc "pacman --noconfirm -S autoconf automake bison flex git"
- C:\msys64\usr\bin\bash -lc "pip3 install --upgrade pipenv"
- C:\msys64\usr\bin\bash -lc "cd $APPVEYOR_BUILD_FOLDER/docs && ls && pipenv sync"
build_script:
- bash -lc "exec 0</dev/null && cd $APPVEYOR_BUILD_FOLDER && autoreconf -i"
- bash -lc "exec 0</dev/null && cd $APPVEYOR_BUILD_FOLDER && ./configure --with-oniguruma=builtin --disable-shared --enable-static --enable-all-static"
- bash -lc "exec 0</dev/null && cd $APPVEYOR_BUILD_FOLDER && make -j8"
- bash -lc "exec 0</dev/null && cd $APPVEYOR_BUILD_FOLDER && make"
- bash -lc "exec 0</dev/null && cd $APPVEYOR_BUILD_FOLDER && cat jq.1 | groff -mandoc -Thtml > jq.html"
- 7z a jq-package.zip jq.1 jq.html jq.exe
- bash -lc "exec 0</dev/null && cd $APPVEYOR_BUILD_FOLDER && pwd && ls -la"
+10 -10
View File
@@ -74,7 +74,7 @@ dnl Code coverage
AC_ARG_ENABLE([gcov],
AC_HELP_STRING([--enable-gcov], [enable gcov code coverage tool]))
dnl Don't attempt to build docs if there's no Ruby lying around
dnl Don't attempt to build docs if python deps aren't installed
AC_ARG_ENABLE([docs],
AC_HELP_STRING([--disable-docs], [don't build docs]))
@@ -87,25 +87,25 @@ AC_ARG_ENABLE([all-static],
AC_HELP_STRING([--enable-all-static], [link jq with static libraries only]))
AS_IF([test "x$enable_docs" != "xno"],[
AC_CHECK_PROGS(bundle_cmd, bundle)
AC_CHECK_PROGS(pipenv_cmd, pipenv)
AC_CACHE_CHECK([for Ruby dependencies], [jq_cv_ruby_deps],
[jq_cv_ruby_deps=yes;
AS_IF([test "x$bundle_cmd" = "x" || \
! bmsg="`cd ${srcdir}/docs; "$bundle_cmd" check 2>/dev/null`"],[
AC_MSG_WARN([$bmsg])
AC_CACHE_CHECK([for Python dependencies], [jq_cv_python_deps],
[jq_cv_python_deps=yes;
AS_IF([test "x$pipenv_cmd" = "x" || \
! bmsg="`cd ${srcdir}/docs; LC_ALL=$LANG "$pipenv_cmd" check`"],[
AC_MSG_ERROR([$bmsg])
cat <<EOF
*****************************************************************
* Ruby dependencies for building jq documentation not found. *
* Python dependencies for building jq documentation not found. *
* You can still build, install and hack on jq, but the manpage *
* will not be rebuilt and some of the tests will not run. *
* See docs/README.md for how to install the docs dependencies. *
*****************************************************************
EOF
jq_cv_ruby_deps=no
jq_cv_python_deps=no
])])
if test "x$jq_cv_ruby_deps" != "xyes"; then
if test "x$jq_cv_python_deps" != "xyes"; then
enable_docs=no
fi
])
-3
View File
@@ -1,6 +1,3 @@
.DS_Store
.sass-cache
output/*
# Autogenerated from public/css/base.scss
public/css/base.css
-7
View File
@@ -1,7 +0,0 @@
source "https://rubygems.org"
gem "rake"
gem "bonsai"
gem "maruku"
gem "ronn"
gem "mustache", "<1.0" # to support ruby <2.0
-63
View File
@@ -1,63 +0,0 @@
GEM
remote: https://rubygems.org/
specs:
activesupport (4.2.3)
i18n (~> 0.7)
json (~> 1.7, >= 1.7.7)
minitest (~> 5.1)
thread_safe (~> 0.3, >= 0.3.4)
tzinfo (~> 1.1)
addressable (2.3.8)
bonsai (1.4.9)
activesupport (>= 3.0.3)
builder (>= 3.0.0)
i18n (>= 0.5.0)
launchy (>= 0.3.7)
liquid (>= 2.2.2)
maruku (>= 0.6.0)
rack
sass
sinatra (>= 1.0)
tilt (>= 1.3)
watch (>= 0.1.0)
yui-compressor
builder (3.2.2)
hpricot (0.8.6)
i18n (0.7.0)
json (1.8.3)
launchy (2.4.3)
addressable (~> 2.3)
liquid (3.0.6)
maruku (0.7.2)
minitest (5.8.0)
mustache (0.99.8)
rack (1.6.4)
rack-protection (1.5.3)
rack
rake (10.4.2)
rdiscount (2.1.8)
ronn (0.7.3)
hpricot (>= 0.8.2)
mustache (>= 0.7.0)
rdiscount (>= 1.5.8)
sass (3.4.16)
sinatra (1.4.6)
rack (~> 1.4)
rack-protection (~> 1.4)
tilt (>= 1.3, < 3)
thread_safe (0.3.5)
tilt (2.0.1)
tzinfo (1.2.2)
thread_safe (~> 0.1)
watch (0.1.0)
yui-compressor (0.12.0)
PLATFORMS
ruby
DEPENDENCIES
bonsai
maruku
mustache (< 1.0)
rake
ronn
+12
View File
@@ -0,0 +1,12 @@
[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true
[dev-packages]
[packages]
jinja2 = "*"
pyyaml = "*"
markdown = "*"
lxml = "*"
+117
View File
@@ -0,0 +1,117 @@
{
"_meta": {
"hash": {
"sha256": "16a9ef323592a417142c30be17e58c3cf36dc2bfdbf4757106a796b22262a1ce"
},
"pipfile-spec": 6,
"requires": {},
"sources": [
{
"name": "pypi",
"url": "https://pypi.org/simple",
"verify_ssl": true
}
]
},
"default": {
"jinja2": {
"hashes": [
"sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd",
"sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4"
],
"index": "pypi",
"version": "==2.10"
},
"lxml": {
"hashes": [
"sha256:0537eee4902e8bf4f41bfee8133f7edf96533dd175930a12086d6a40d62376b2",
"sha256:0562ec748abd230ab87d73384e08fa784f9b9cee89e28696087d2d22c052cc27",
"sha256:09e91831e749fbf0f24608694e4573be0ef51430229450c39c83176cc2e2d353",
"sha256:1ae4c0722fc70c0d4fba43ae33c2885f705e96dce1db41f75ae14a2d2749b428",
"sha256:1c630c083d782cbaf1f7f37f6cac87bda9cff643cf2803a5f180f30d97955cef",
"sha256:2fe74e3836bd8c0fa7467ffae05545233c7f37de1eb765cacfda15ad20c6574a",
"sha256:37af783c2667ead34a811037bda56a0b142ac8438f7ed29ae93f82ddb812fbd6",
"sha256:3f2d9eafbb0b24a33f56acd16f39fc935756524dcb3172892721c54713964c70",
"sha256:47d8365a8ef14097aa4c65730689be51851b4ade677285a3b2daa03b37893e26",
"sha256:510e904079bc56ea784677348e151e1156040dbfb736f1d8ea4b9e6d0ab2d9f4",
"sha256:58d0851da422bba31c7f652a7e9335313cf94a641aa6d73b8f3c67602f75b593",
"sha256:7940d5c2185ffb989203dacbb28e6ae88b4f1bb25d04e17f94b0edd82232bcbd",
"sha256:7cf39bb3a905579836f7a8f3a45320d9eb22f16ab0c1e112efb940ced4d057a5",
"sha256:9563a23c1456c0ab550c087833bc13fcc61013a66c6420921d5b70550ea312bf",
"sha256:95b392952935947e0786a90b75cc33388549dcb19af716b525dae65b186138fc",
"sha256:983129f3fd3cef5c3cf067adcca56e30a169656c00fcc6c648629dbb850b27fa",
"sha256:a0b75b1f1854771844c647c464533def3e0a899dd094a85d1d4ed72ecaaee93d",
"sha256:b5db89cc0ef624f3a81214b7961a99f443b8c91e88188376b6b322fd10d5b118",
"sha256:c0a7751ba1a4bfbe7831920d98cee3ce748007eab8dfda74593d44079568219a",
"sha256:c0c5a7d4aafcc30c9b6d8613a362567e32e5f5b708dc41bc3a81dac56f8af8bb",
"sha256:d4d63d85eacc6cb37b459b16061e1f100d154bee89dc8d8f9a6128a5a538e92e",
"sha256:da5e7e941d6e71c9c9a717c93725cda0708c2474f532e3680ac5e39ec57d224d",
"sha256:dccad2b3c583f036f43f80ac99ee212c2fa9a45151358d55f13004d095e683b2",
"sha256:df46307d39f2aeaafa1d25309b8a8d11738b73e9861f72d4d0a092528f498baa",
"sha256:e70b5e1cb48828ddd2818f99b1662cb9226dc6f57d07fc75485405c77da17436",
"sha256:ea825562b8cd057cbc9810d496b8b5dec37a1e2fc7b27bc7c1e72ce94462a09a"
],
"index": "pypi",
"version": "==4.3.1"
},
"markdown": {
"hashes": [
"sha256:c00429bd503a47ec88d5e30a751e147dcb4c6889663cd3e2ba0afe858e009baa",
"sha256:d02e0f9b04c500cde6637c11ad7c72671f359b87b9fe924b2383649d8841db7c"
],
"index": "pypi",
"version": "==3.0.1"
},
"markupsafe": {
"hashes": [
"sha256:048ef924c1623740e70204aa7143ec592504045ae4429b59c30054cb31e3c432",
"sha256:130f844e7f5bdd8e9f3f42e7102ef1d49b2e6fdf0d7526df3f87281a532d8c8b",
"sha256:19f637c2ac5ae9da8bfd98cef74d64b7e1bb8a63038a3505cd182c3fac5eb4d9",
"sha256:1b8a7a87ad1b92bd887568ce54b23565f3fd7018c4180136e1cf412b405a47af",
"sha256:1c25694ca680b6919de53a4bb3bdd0602beafc63ff001fea2f2fc16ec3a11834",
"sha256:1f19ef5d3908110e1e891deefb5586aae1b49a7440db952454b4e281b41620cd",
"sha256:1fa6058938190ebe8290e5cae6c351e14e7bb44505c4a7624555ce57fbbeba0d",
"sha256:31cbb1359e8c25f9f48e156e59e2eaad51cd5242c05ed18a8de6dbe85184e4b7",
"sha256:3e835d8841ae7863f64e40e19477f7eb398674da6a47f09871673742531e6f4b",
"sha256:4e97332c9ce444b0c2c38dd22ddc61c743eb208d916e4265a2a3b575bdccb1d3",
"sha256:525396ee324ee2da82919f2ee9c9e73b012f23e7640131dd1b53a90206a0f09c",
"sha256:52b07fbc32032c21ad4ab060fec137b76eb804c4b9a1c7c7dc562549306afad2",
"sha256:52ccb45e77a1085ec5461cde794e1aa037df79f473cbc69b974e73940655c8d7",
"sha256:5c3fbebd7de20ce93103cb3183b47671f2885307df4a17a0ad56a1dd51273d36",
"sha256:5e5851969aea17660e55f6a3be00037a25b96a9b44d2083651812c99d53b14d1",
"sha256:5edfa27b2d3eefa2210fb2f5d539fbed81722b49f083b2c6566455eb7422fd7e",
"sha256:7d263e5770efddf465a9e31b78362d84d015cc894ca2c131901a4445eaa61ee1",
"sha256:83381342bfc22b3c8c06f2dd93a505413888694302de25add756254beee8449c",
"sha256:857eebb2c1dc60e4219ec8e98dfa19553dae33608237e107db9c6078b1167856",
"sha256:98e439297f78fca3a6169fd330fbe88d78b3bb72f967ad9961bcac0d7fdd1550",
"sha256:bf54103892a83c64db58125b3f2a43df6d2cb2d28889f14c78519394feb41492",
"sha256:d9ac82be533394d341b41d78aca7ed0e0f4ba5a2231602e2f05aa87f25c51672",
"sha256:e982fe07ede9fada6ff6705af70514a52beb1b2c3d25d4e873e82114cf3c5401",
"sha256:edce2ea7f3dfc981c4ddc97add8a61381d9642dc3273737e756517cc03e84dd6",
"sha256:efdc45ef1afc238db84cb4963aa689c0408912a0239b0721cb172b4016eb31d6",
"sha256:f137c02498f8b935892d5c0172560d7ab54bc45039de8805075e19079c639a9c",
"sha256:f82e347a72f955b7017a39708a3667f106e6ad4d10b25f237396a7115d8ed5fd",
"sha256:fb7c206e01ad85ce57feeaaa0bf784b97fa3cad0d4a5737bc5295785f5c613a1"
],
"version": "==1.1.0"
},
"pyyaml": {
"hashes": [
"sha256:3d7da3009c0f3e783b2c873687652d83b1bbfd5c88e9813fb7e5b03c0dd3108b",
"sha256:3ef3092145e9b70e3ddd2c7ad59bdd0252a94dfe3949721633e41344de00a6bf",
"sha256:40c71b8e076d0550b2e6380bada1f1cd1017b882f7e16f09a65be98e017f211a",
"sha256:558dd60b890ba8fd982e05941927a3911dc409a63dcb8b634feaa0cda69330d3",
"sha256:a7c28b45d9f99102fa092bb213aa12e0aaf9a6a1f5e395d36166639c1f96c3a1",
"sha256:aa7dd4a6a427aed7df6fb7f08a580d68d9b118d90310374716ae90b710280af1",
"sha256:bc558586e6045763782014934bfaf39d48b8ae85a2713117d16c39864085c613",
"sha256:d46d7982b62e0729ad0175a9bc7e10a566fc07b224d2c79fafb5e032727eaa04",
"sha256:d5eef459e30b09f5a098b9cea68bebfeb268697f78d647bd255a085371ac7f3f",
"sha256:e01d3203230e1786cd91ccfdc8f8454c8069c91bee3962ad93b87a4b2860f537",
"sha256:e170a9e6fcfd19021dd29845af83bb79236068bf5fd4df3327c1be18182b2531"
],
"index": "pypi",
"version": "==3.13"
}
},
"develop": {}
}
+10 -15
View File
@@ -2,24 +2,19 @@ Documentation
=============
The jq website, manpages and some of the tests are generated from this
directory. The directory holds a [Bonsai](http://tinytree.info)
website, and the manual is a YAML file in `content/3.manual`.
directory. The manual is a YAML file in `content/manual`.
To build the documentation (including building the jq manpage), you'll
need a working Ruby setup. The easiest way to get one is to install
RVM and Ruby 1.9.3 like so:
need python3 and pipenv. You can install pipenv like so:
\curl -L https://get.rvm.io | bash -s stable --ruby=1.9.3
pip install pipenv
After that finishes installing, you'll need to make sure RVM is on
your path by doing `source $HOME/.rvm/scripts/rvm`, or just opening a
new shell. See <https://rvm.io> for more info on RVM.
Though, you may need to say pip3 instead, depending on your system. Once
you have pipenv installed, you can install the dependencies by running
`pipenv install` from the `docs` directory.
Once RVM is installed, you can install all the dependencies for jq's
documentation build by running this from the `docs` directory:
Once this is done, rerun `./configure` in the jq root directory and then
the Makefile will be able to generate the jq manpage.
bundle install
When bundle manages to install the dependencies, rerun `./configure`
in the jq root directory and then the Makefile will be able to
generate the jq manpage.
To build the website, run `pipenv run ./build_website.py` from inside
the `docs` directory.
-24
View File
@@ -1,24 +0,0 @@
current_dir = File.dirname(__FILE__)
rakefile_manual = File.expand_path(File.join(current_dir, "Rakefile.manual"))
rakefile_website = File.expand_path(File.join(current_dir, "Rakefile.website"))
desc "Build the manpage from the bonsai source of the manual"
task :manpage do
system %(#{$0} -f #{rakefile_manual} manpage)
end
desc "Collect jq unit test cases from the bonsai source of the manual"
task :mantests do
system %(#{$0} -f #{rakefile_manual} mantests)
end
desc "Build the website from the bonsai sources"
task :build do
system %(#{$0} -f #{rakefile_website} build)
end
desc "Serve a live view of the website on http://localhost:5000/jq/"
task :serve do
system %(#{$0} -f #{rakefile_website} serve)
end
-49
View File
@@ -1,49 +0,0 @@
require 'ronn'
require 'tempfile'
require 'yaml'
def load_manual
YAML::load(File.open("content/3.manual/manual.yml"))
end
task :manpage do
Tempfile.open "manpage" do |f|
manual = load_manual
f.puts manual['manpage_intro']
f.puts manual['body']
manual['sections'].each do |section|
f.puts "## #{section['title'].upcase}\n"
f.puts section['body']
f.puts ""
(section['entries'] || []).each do |entry|
f.puts "### #{entry['title']}\n"
f.puts entry['body']
f.puts ""
(entry['examples'] || []).each do |example|
f.puts " jq '#{example['program']}'"
f.puts " #{example['input']}"
f.puts " => #{example['output'].join(", ")}"
f.puts
end
end
f.puts ""
end
f.puts manual['manpage_epilogue']
f.close
puts Ronn::Document.new(f.path).convert('roff').gsub(/<\/?code>/,"")
end
end
task :mantests do
load_manual['sections'].each do |section|
(section['entries'] || []).each do |entry|
(entry['examples'] || []).each do |example|
puts example['program'].gsub("\n", " ")
puts example['input']
example['output'].each do |s| puts s end
puts
end
end
end
end
-76
View File
@@ -1,76 +0,0 @@
require 'bonsai'
require 'json'
require 'liquid'
require 'maruku'
module ExtraFilters
def markdownify(input)
Maruku.new(input).to_html
end
def search_id(input)
input.gsub(/`/, '')
end
def section_id(input)
input.gsub(/[^a-zA-Z0-9_]/, '')
end
def entry_id(input)
input.gsub(/[ `]/, '')
end
def no_paragraph(input)
input.gsub('<p>', '').gsub('</p>', '')
end
def json(input)
input.to_json
end
def unique(input)
@n = (@n || 0) + 1
input + @n.to_s
end
end
Liquid::Template.register_filter(ExtraFilters)
begin
`java 2>&1`
rescue
class Bonsai::Exporter
def self.compress_assets
Bonsai.log "java not found! Not compressing javascript or stylesheets"
end
end
end
task :build do
Bonsai.root_dir = Dir.pwd
Bonsai::Exporter.publish!
end
task :serve do
begin
Bonsai.log "Press Control+C to quit"
require 'rack'
require 'sinatra'
require 'watch'
require 'launchy'
Bonsai.root_dir = Dir.pwd
server = fork {
app = Rack::Builder.app {
map "/jq" do
use Bonsai::StaticPassThrough, :root => Bonsai.root_dir + "/output", :urls => ["/"]
end
run Bonsai::DevelopmentServer
}
Rack::Handler.default.run(app, :Port => 5000) do
Launchy.open("http://localhost:5000/jq/")
end
}
Watch.new("{content,templates,public}/**/*") { Bonsai::Exporter.process! }
rescue Interrupt
Process.kill("QUIT", server)
Process.wait(server)
exit
end
end
+235
View File
@@ -0,0 +1,235 @@
#!/usr/bin/env python3
from datetime import date
from io import StringIO
from lxml import etree
import markdown
from markdown.extensions import Extension
import re
import sys
import yaml
# Prevent our markdown parser from trying to help by interpreting things in angle brackets as HTML tags.
class EscapeHtml(Extension):
def extendMarkdown(self, md, md_globals):
del md.preprocessors['html_block']
del md.inlinePatterns['html']
class RoffWalker(object):
def __init__(self, tree, output=sys.stdout):
self.tree = tree
self.target = output
self.f = StringIO()
def walk(self):
self._walk(self.tree, parent_tag=None)
# We don't want to start lines with \. because that can confuse man
# For lines that start with \., we need to prefix them with \& so it
# knows not to treat that line as a directive
data = re.sub(r'^\\\.', r'\&.', self.f.getvalue(), flags=re.MULTILINE)
self.target.write(data)
def _ul_is_special(self, root):
if len(root) != 1:
return False
child = root[0]
if child.tag != 'li':
return False
msg = ''.join(child.itertext()).strip()
return msg.endswith(':')
def _walk_child(self, root):
if len(root) > 0:
self._walk(root[0], parent_tag=root.tag)
def _write_element(self, root, ensure_newline=True):
if root.text is not None:
text = self._sanitize(root.text)
self.__write_raw(text)
self._walk_child(root)
self._write_tail(root, ensure_newline=ensure_newline)
def _write_tail(self, root, ensure_newline=False, inline=False):
if root.tail is not None:
if inline or root.tail != '\n':
text = self._sanitize(root.tail)
if text.endswith('\n'):
ensure_newline = False
self.__write_raw(text)
if ensure_newline:
self.__write_raw('\n')
def _walk(self, root, parent_tag=None):
last_tag = None
while root is not None:
if root.tag == 'h1':
self.__write_cmd('.TH "JQ" "1" "{}" "" ""'.format(date.today().strftime('%B %Y')))
self.__write_cmd('.SH "NAME"')
# TODO: properly parse this
self.__write_raw(r'\fBjq\fR \- Command\-line JSON processor' + "\n")
elif root.tag == 'h2':
self.__write_cmd('.SH "{}"'.format(''.join(root.itertext()).strip()))
elif root.tag == 'h3':
text = ''.join(root.itertext()).strip()
self.__write_cmd('.SS "{}"'.format(self._h3_sanitize(text)))
elif root.tag == 'p':
if last_tag not in ['h2', 'h3'] and parent_tag not in ['li']:
self.__write_cmd('.P')
self._write_element(root, ensure_newline=(parent_tag != 'li'))
elif root.tag == 'ul':
if self._ul_is_special(root):
li = root[0]
self.__write_cmd('.TP')
self._write_element(li)
next = root.getnext()
while next is not None and next.tag == 'p':
if next.getnext() is not None and next.getnext().tag == 'pre':
# we don't want to .IP these, because it'll look funny with the code indent
break
self.__write_cmd('.IP')
self._write_element(next)
root = next
next = root.getnext()
else:
self._walk_child(root)
self._write_tail(root)
# A pre tag after the end of a list doesn't want two of the indentation commands
if root.getnext() is None or root.getnext().tag != 'pre':
self.__write_cmd('.IP "" 0')
elif root.tag == 'li':
self.__write_cmd(r'.IP "\(bu" 4')
if root.text is not None and root.text.strip() != '':
text = self._sanitize(root.text)
self.__write_raw(text)
self._walk_child(root)
self._write_tail(root, ensure_newline=True)
elif root.tag == 'strong':
if root.text is not None:
text = self._sanitize(root.text)
self.__write_raw('\\fB{}\\fR'.format(text))
self._write_tail(root, inline=True)
elif root.tag == 'em':
if root.text is not None:
text = self._sanitize(root.text)
self.__write_raw('\\fI{}\\fR'.format(text))
self._write_tail(root, inline=True)
elif root.tag == 'code':
if root.text is not None:
text = self._code_sanitize(root.text)
self.__write_raw('\\fB{}\\fR'.format(text))
self._write_tail(root, inline=True)
elif root.tag == 'pre':
self.__write_cmd('.IP "" 4')
self.__write_cmd('.nf\n') # extra newline for spacing reasons
next = root
first = True
while next is not None and next.tag == 'pre':
if not first:
self.__write_raw('\n')
text = ''.join(next.itertext(with_tail=False))
self.__write_raw(self._pre_sanitize(text))
first = False
root = next
next = next.getnext()
self.__write_cmd('.fi')
self.__write_cmd('.IP "" 0')
else:
self._walk_child(root)
last_tag = root.tag
root = root.getnext()
def _base_sanitize(self, text):
text = re.sub(r'\\', r'\\e', text)
text = re.sub(r'\.', r'\\.', text)
text = re.sub("'", r"\'", text)
text = re.sub('-', r'\-', text)
return text
def _pre_sanitize(self, text):
return self._base_sanitize(text)
def _code_sanitize(self, text):
text = self._base_sanitize(text)
text = re.sub(r'\s', ' ', text)
return text
def _h3_sanitize(self, text):
text = self._base_sanitize(text)
text = re.sub(' \n|\n ', ' ', text)
text = re.sub('\n', ' ', text)
return text
def _sanitize(self, text):
text = self._base_sanitize(text)
text = re.sub(r'<([^>]+)>', r'\\fI\1\\fR', text)
text = re.sub(r' +', ' ', text)
text = re.sub('\n', ' ', text)
return text
def __write_cmd(self, dat):
print('.', dat, sep='\n', file=self.f)
pass
def __write_raw(self, dat):
print(dat, sep='', end='', file=self.f)
pass
def load_yml_file(fn):
with open(fn) as f:
return yaml.load(f)
def dedent_body(body):
lines = [re.sub(r'^ (\S)', r'\1', l) for l in body.split('\n')]
return '\n'.join(lines)
def convert_manual_to_markdown():
f = StringIO()
manual = load_yml_file("content/manual/manual.yml")
f.write(manual.get('manpage_intro', '\n'))
f.write(dedent_body(manual.get('body', '\n')))
for section in manual.get('sections', []):
f.write('## {}\n'.format(section.get('title', '').upper()))
f.write(dedent_body(section.get('body', '\n')))
f.write('\n')
for entry in section.get('entries', []):
f.write('### {}\n'.format(entry.get('title', '')))
f.write(dedent_body(entry.get('body', '\n')))
f.write('\n')
if entry.get('examples') is not None:
f.write("~~~~\n")
first = True
for example in entry.get('examples'):
if not first:
f.write('\n')
f.write("jq '{}'\n".format(example.get('program', '')))
f.write(" {}\n".format(example.get('input', '')))
output = [str(x) for x in example.get('output', [])]
f.write("=> {}\n".format(', '.join(output)))
first = False
f.write("~~~~\n")
f.write('\n')
f.write(manual.get('manpage_epilogue', ''))
return f.getvalue()
# Convert manual.yml to our special markdown format
markdown_data = convert_manual_to_markdown()
# Convert markdown to html
html_data = markdown.markdown(markdown_data, extensions=[EscapeHtml(), 'fenced_code'])
# Parse the html into a tree so we can walk it
tr = etree.HTML(html_data, etree.HTMLParser())
# Convert the markdown to ROFF
RoffWalker(tr).walk()
+13
View File
@@ -0,0 +1,13 @@
#!/usr/bin/env python3
import yaml
with open("content/manual/manual.yml") as f:
manual = yaml.load(f)
for section in manual.get('sections', []):
for entry in section.get('entries', []):
for example in entry.get('examples', []):
print(example.get('program', '').replace('\n', ' '))
print(example.get('input', ''))
for s in example.get('output', []):
print(s)
print('')
+62
View File
@@ -0,0 +1,62 @@
#!/usr/bin/env python3
import glob
import itertools
from jinja2 import Environment, FileSystemLoader, Markup, select_autoescape, contextfunction
from markdown import markdown
import os
import os.path
import re
import shutil
import yaml
env = Environment(
loader=FileSystemLoader('templates'),
autoescape=select_autoescape(['html.j2']),
)
def load_yml_file(fn):
with open(fn) as f:
return yaml.load(f)
env.filters['search_id'] = lambda input: input.replace(r'`', '')
env.filters['section_id'] = lambda input: re.sub(r"[^a-zA-Z0-9_]", '', input)
env.filters['entry_id'] = lambda input: re.sub(r"[ `]", '', input)
env.filters['markdownify'] = lambda input: Markup(markdown(input))
env.filters['no_paragraph'] = lambda input: Markup(re.sub(r"</?p>", '', input))
env.globals['unique_id'] = contextfunction(lambda ctx: str(next(ctx['unique_ctr'])))
env.globals.update(load_yml_file('site.yml'))
env.globals['navigation'] = ['tutorial', 'download', 'manual']
def generate_file(env, fname='content/1.tutorial/default.yml'):
path, base = os.path.split(fname)
path = os.path.relpath(path, 'content')
output_dir = os.path.join('output', path)
output_path = os.path.join(output_dir, 'index.html')
template_name = re.sub(r".yml$", '.html.j2', base)
ctx = load_yml_file(fname)
ctx.update(unique_ctr=itertools.count(1), permalink=path)
os.makedirs(output_dir, exist_ok=True)
env.get_template(template_name).stream(ctx).dump(output_path, encoding='utf-8')
def copy_public_files(root=''):
for f in os.scandir(os.path.join('public', root)):
src = os.path.join(root, f.name)
dst = os.path.join('output', src)
if f.is_dir():
os.makedirs(dst, exist_ok=True)
copy_public_files(src)
else:
shutil.copyfile(f.path, dst)
copy_public_files()
for fn in glob.glob('content/**/*.yml', recursive=True):
generate_file(env, fn)
@@ -180,14 +180,13 @@ body:
#### Building the documentation
jq's documentation is compiled into static HTML using
[Bonsai](http://www.tinytree.info). To view the documentation
locally, run `rake serve` (or `bundle exec rake serve`) from the
docs/ subdirectory. To build the docs just `rake build` from the
docs subdirectory. You'll need a few Ruby dependencies, which can
be installed by following the instructions in `docs/README.md`.
jq's documentation is compiled into static HTML using Python.
To build the docs, run `pipenv run python3 build_website.py` from
the docs/ subdirectory. To serve them locally, you can run
`python3 -m SimpleHTTPServer`. You'll need a few Python dependencies,
which can be installed by following the instructions in `docs/README.md`.
The man page is built by `make jq.1`, or just `make`, also from
the YAML docs, and you'll still need the Ruby dependencies to
the YAML docs, and you'll still need the Python dependencies to
build the manpage.
File renamed without changes.
@@ -172,7 +172,7 @@ sections:
ASCII output with every non-ASCII character replaced with the
equivalent escape sequence.
* `--unbuffered`
* `--unbuffered`:
Flush the output after each JSON object is printed (useful if
you're piping a slow data source into jq and piping jq's
@@ -658,10 +658,10 @@ sections:
- **Strings** are added by being joined into a larger string.
- **Objects** are added by merging, that is, inserting all
the key-value pairs from both objects into a single
combined object. If both objects contain a value for the
same key, the object on the right of the `+` wins. (For
recursive merge use the `*` operator.)
the key-value pairs from both objects into a single
combined object. If both objects contain a value for the
same key, the object on the right of the `+` wins. (For
recursive merge use the `*` operator.)
`null` can be added to any value, and returns the other
value unchanged.
@@ -1975,40 +1975,40 @@ sections:
jq provides a few SQL-style operators.
* INDEX(stream; index_expression):
* INDEX(stream; index_expression):
This builtin produces an object whose keys are computed by
the given index expression applied to each value from the
given stream.
This builtin produces an object whose keys are computed by
the given index expression applied to each value from the
given stream.
* JOIN($idx; stream; idx_expr; join_expr):
* JOIN($idx; stream; idx_expr; join_expr):
This builtin joins the values from the given stream to the
given index. The index's keys are computed by applying the
given index expression to each value from the given stream.
An array of the value in the stream and the corresponding
value from the index is fed to the given join expression to
produce each result.
This builtin joins the values from the given stream to the
given index. The index's keys are computed by applying the
given index expression to each value from the given stream.
An array of the value in the stream and the corresponding
value from the index is fed to the given join expression to
produce each result.
* JOIN($idx; stream; idx_expr):
* JOIN($idx; stream; idx_expr):
Same as `JOIN($idx; stream; idx_expr; .)`.
Same as `JOIN($idx; stream; idx_expr; .)`.
* JOIN($idx; idx_expr):
* JOIN($idx; idx_expr):
This builtin joins the input `.` to the given index, applying
the given index expression to `.` to compute the index key.
The join operation is as described above.
This builtin joins the input `.` to the given index, applying
the given index expression to `.` to compute the index key.
The join operation is as described above.
* IN(s):
* IN(s):
This builtin outputs `true` if `.` appears in the given
stream, otherwise it outputs `false`.
This builtin outputs `true` if `.` appears in the given
stream, otherwise it outputs `false`.
* IN(source; s):
* IN(source; s):
This builtin outputs `true` if any value in the source stream
appears in the second stream, otherwise it outputs `false`.
This builtin outputs `true` if any value in the source stream
appears in the second stream, otherwise it outputs `false`.
- title: "`builtins`"
body: |
@@ -2230,6 +2230,7 @@ sections:
STRING | FILTER( [REGEX, FLAGS] )
where:
* STRING, REGEX and FLAGS are jq strings and subject to jq string interpolation;
* REGEX, after string interpolation, should be a valid PCRE regex;
* FILTER is one of `test`, `match`, or `capture`, as described below.
@@ -2642,9 +2643,9 @@ sections:
For example, in the following expression there is a binding
which is visible "to the right" of it, `... | .*3 as
$times_three | [. + $times_three] | ...`, but not "to the
$times_three | [. + $times_three] | ...`, but not "to the
left". Consider this expression now, `... | (.*3 as
$times_three | [.+ $times_three]) | ...`: here the binding
$times_three | [. + $times_three]) | ...`: here the binding
`$times_three` is _not_ visible past the closing parenthesis.
- title: Reduce
@@ -2867,7 +2868,7 @@ sections:
Two builtins provide minimal output capabilities, `debug`, and
`stderr`. (Recall that a jq program's output values are always
output as JSON texts on `stdout`.) The `debug` builtin can have
output as JSON texts on `stdout`.) The `debug` builtin can have
application-specific behavior, such as for executables that use
the libjq C API but aren't the jq executable itself. The `stderr`
builtin outputs its input in raw mode to stder with no additional
@@ -441,7 +441,7 @@ sections:
input: 5
output: [6]
- title: `length`
- title: '`length`'
body: |
The builtin function `length` gets the length of various
@@ -462,7 +462,7 @@ sections:
input: '[[1,2], "string", {"a":2}, null]'
output: [2, 6, 1, 0]
- title: `keys`
- title: '`keys`'
body: |
The builtin function `keys`, when given an object, returns
@@ -485,7 +485,7 @@ sections:
input: '[42,3,35]'
output: ['[0,1,2]']
- title: `has`
- title: '`has`'
body: |
The builtin function `has` returns whether the input object
@@ -504,7 +504,7 @@ sections:
input: '[[0,1], ["a","b","c"]]'
output: ['[false, true]']
- title: `to_entries`, `from_entries`, `with_entries`
- title: '`to_entries`, `from_entries`, `with_entries`'
body: |
These functions convert between an object and an array of
@@ -529,14 +529,14 @@ sections:
output: ['{"KEY_a": 1, "KEY_b": 2}']
- title: `select`
- title: '`select`'
body: |
The function `select(foo)` produces its input unchanged if
`foo` returns true for that input, and produces no output
otherwise.
It's useful for filtering lists: `[1,2,3] | map(select(. >= 2))`
It's useful for filtering lists: '`[1,2,3] | map(select(. >= 2))`'
will give you `[3]`.
examples:
@@ -544,7 +544,7 @@ sections:
input: '[1,5,3,0,7]'
output: ['[5,3,7]']
- title: `empty`
- title: '`empty`'
body: |
`empty` returns no results. None at all. Not even `null`.
@@ -559,7 +559,7 @@ sections:
input: 'null'
output: ['[1,2,3]']
- title: `map(x)`
- title: '`map(x)`'
body: |
For any filter `x`, `map(x)` will run that filter for each
@@ -574,7 +574,7 @@ sections:
input: '[1,2,3]'
output: ['[2,3,4]']
- title: `add`
- title: '`add`'
body: |
The filter `add` takes as input an array, and produces as
@@ -596,7 +596,7 @@ sections:
input: '[]'
output: ["null"]
- title: `range`
- title: '`range`'
body: |
The `range` function produces a range of numbers. `range(4;10)`
@@ -612,7 +612,7 @@ sections:
input: 'null'
output: ['[2,3]']
- title: `tonumber`
- title: '`tonumber`'
body: |
The `tonumber` function parses its input as a number. It
@@ -624,7 +624,7 @@ sections:
input: '[1, "1"]'
output: [1, 1]
- title: `tostring`
- title: '`tostring`'
body: |
The `tostring` function prints its input as a
@@ -636,7 +636,7 @@ sections:
input: '[1, "1", [1]]'
output: ['"1"', '"1"', '"[1]"']
- title: `type`
- title: '`type`'
body: |
The `type` function returns the type of its argument as a
@@ -648,7 +648,7 @@ sections:
input: '[0, false, [], {}, null, "hello"]'
output: ['["number", "boolean", "array", "object", "null", "string"]']
- title: `sort, sort_by`
- title: '`sort, sort_by`'
body: |
The `sort` functions sorts its input, which must be an
@@ -680,7 +680,7 @@ sections:
input: '[{"foo":4, "bar":10}, {"foo":3, "bar":100}, {"foo":2, "bar":1}]'
output: ['[{"foo":2, "bar":1}, {"foo":3, "bar":100}, {"foo":4, "bar":10}]']
- title: `group_by`
- title: '`group_by`'
body: |
`group_by(.foo)` takes as input an array, groups the
@@ -697,7 +697,7 @@ sections:
input: '[{"foo":1, "bar":10}, {"foo":3, "bar":100}, {"foo":1, "bar":1}]'
output: ['[[{"foo":1, "bar":10}, {"foo":1, "bar":1}], [{"foo":3, "bar":100}]]']
- title: `min`, `max`, `min_by`, `max_by`
- title: '`min`, `max`, `min_by`, `max_by`'
body: |
Find the minimum or maximum element of the input array. The
@@ -713,7 +713,7 @@ sections:
input: '[{"foo":1, "bar":14}, {"foo":2, "bar":3}]'
output: ['{"foo":2, "bar":3}']
- title: `unique`
- title: '`unique`'
body: |
The `unique` function takes as input an array and produces
@@ -725,7 +725,7 @@ sections:
input: '[1,2,5,3,5,3,1,3]'
output: ['[1,2,3,5]']
- title: `reverse`
- title: '`reverse`'
body: |
This function reverses an array.
@@ -735,7 +735,7 @@ sections:
input: '[1,2,3,4]'
output: ['[4,3,2,1]']
- title: `contains`
- title: '`contains`'
body: |
The filter `contains(b)` will produce true if b is
@@ -764,7 +764,7 @@ sections:
input: '{"foo": 12, "bar":[1,2,{"barp":12, "blip":13}]}'
output: ['false']
- title: `recurse`
- title: '`recurse`'
body: |
The `recurse` function allows you to search through a
@@ -796,7 +796,7 @@ sections:
- '{"foo":[]}'
- title: "String interpolation - `\(foo)`"
- title: String interpolation - `\(foo)`
body: |
Inside a string, you can put an expression inside parens
@@ -882,7 +882,7 @@ sections:
- title: Conditionals and Comparisons
entries:
- title: `==`, `!=`
- title: '`==`, `!=`'
body: |
The expression 'a == b' will produce 'true' if the result of a and b
@@ -931,7 +931,7 @@ sections:
input: 2
output: ['"many"']
- title: `>, >=, <=, <`
- title: '`>, >=, <=, <`'
body: |
The comparison operators `>`, `>=`, `<=`, `<` return whether
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+173
View File
@@ -0,0 +1,173 @@
body {
padding-top: 80px;
}
.container {
max-width: 970px;
}
/* index.liquid *******************************************/
#blurb {
padding-top: 40px;
}
#blurb p {
font-size: 1.9em;
}
#blurb .btn-group {
margin: 4px;
}
#multiblurb {
line-height: 1.7;
text-align: center;
font-size: 12pt;
}
#multiblurb code {
border: 0;
font-size: 12pt;
}
#news {
font-size: 12pt;
}
#news .date {
font-style: italic;
}
/* default.liquid *****************************************/
.tutorial-example {
position: relative;
margin-bottom: 10px;
}
.tutorial-example pre {
margin-bottom: 0px;
}
.tutorial-example a {
position: absolute;
top: 0px;
right: 0px;
padding: 15px 8px;
color: #777777;
font-weight: bold;
line-height: 10px;
font-size: 12px;
border-left: 1px solid #DDDDDD;
display: block;
}
.tutorial-example .accordion-body pre {
margin: 0 4px;
border-top: 0;
border-top-left-radius: 0;
border-top-right-radius: 0;
}
@media print {
.tutorial-example a {
display: none;
}
}
/* manual.liquid ******************************************/
section {
padding-top: 24px;
}
h3 code {
border: 0;
font-size: 20px;
}
@media (max-width: 991px) {
#navcolumn {
/* Put nav column above manual content */
position: relative !important;
margin-bottom: 60px;
}
}
@media (min-width: 992px) {
#manualcontent {
/* Put nav column left of manual content */
padding-left: 280px;
}
}
.nav-pills {
margin-bottom: 20px;
}
.nav-pills li a {
padding: 8px 12px;
}
.manual-example table {
border-top: 1px solid #E5E5E5;
}
.manual-example table td {
white-space: pre-wrap;
font-family: Monaco, Menlo, Consolas, "Courier New", monospace;
}
.manual-example table td.jqprogram {
font-weight: bold;
}
.manual-example table th {
text-align: right;
padding-right: 10px;
}
@media print {
#navcolumn {
display: none !important;
}
.manual-example {
display: block !important;
height: auto !important;
}
.jqplay-btn {
display: none !important;
}
}
/* shared/_footer.liquid **********************************/
footer {
background-color: #F5F5F5;
padding: 20px 0;
margin-top: 40px;
color: #999999;
text-align: center;
}
footer p {
margin: 8px 0;
}
/* typeahead **********************************************/
.twitter-typeahead {
width: 100%;
}
.tt-menu {
width: 100%;
background-color: #fff;
padding: 8px 0;
border: 1px solid #ccc;
border: 1px solid rgba(0, 0, 0, 0.2);
-webkit-border-radius: 8px;
-moz-border-radius: 8px;
border-radius: 8px;
-webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
-moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
}
.tt-suggestion {
padding: 3px 20px;
}
.tt-suggestion:hover {
cursor: pointer;
color: #fff;
background-color: #446e9b;
}
.tt-suggestion.tt-cursor {
color: #fff;
background-color: #446e9b;
}
.tt-suggestion p {
margin: 0;
}
@@ -1,26 +1,26 @@
<!DOCTYPE html>
<html lang="en">
{% include "shared/head" %}
{% include "shared/_head.html.j2" %}
<body id="{{slug}}">
{% include "shared/navbar" %}
{% include "shared/_navbar.html.j2" %}
<div class="container">
<div class="row">
<h1>{{headline}}</h1>
{% for item in body %}
{% if item.text %}
{{ item.text | replace: '$JQ_VERSION', jq_version | markdownify }}
{{ item.text | replace('$JQ_VERSION', jq_version) | markdownify }}
{% endif %}
{% if item.command %}
{% capture resultID %}{{ "result" | unique}}{% endcapture %}
{% set resultID = unique_id() %}
<div class="tutorial-example">
<div class="accordion-heading">
<pre>{{item.command}}</pre>
<a data-toggle="collapse" href="#{{resultID}}">Show result</a>
<a data-toggle="collapse" href="#result{{resultID}}">Show result</a>
</div>
<div id="{{resultID}}" class="accordion-body collapse">
<div id="result{{resultID}}" class="accordion-body collapse">
<pre>{{item.result}}</pre>
</div>
</div>
@@ -29,6 +29,6 @@
</div>
</div>
{% include "shared/footer" %}
{% include "shared/_footer.html.j2" %}
</body>
</html>
@@ -1,9 +1,9 @@
<!DOCTYPE html>
<html lang="en">
{% include "shared/head" %}
{% include "shared/_head.html.j2" %}
<body id="{{slug}}">
{% include "shared/navbar" %}
<body id="{{ slug }}">
{% include "shared/_navbar.html.j2" %}
<div class="container">
<div class="row">
@@ -27,7 +27,7 @@
<li><a href="https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64">Linux (64-bit)</a></li>
<li><a href="https://github.com/stedolan/jq/releases/download/jq-1.6/jq-osx-amd64">OS X (64-bit)</a></li>
<li><a href="https://github.com/stedolan/jq/releases/download/jq-1.6/jq-win64.exe">Windows (64-bit)</a></li>
<li><a href="/jq/download/">Other platforms, older versions, and source</a></li>
<li><a href="{{root}}/download/">Other platforms, older versions, and source</a></li>
</ul>
</div>
@@ -68,6 +68,6 @@
</div>
</div>
{% include "shared/footer" %}
{% include "shared/_footer.html.j2" %}
</body>
</html>
@@ -1,9 +1,9 @@
<!DOCTYPE html>
<html lang="en">
{% include "shared/head" %}
{% include "shared/_head.html.j2" %}
<body id="{{slug}}" data-spy="scroll" data-target="#navcolumn" data-offset="100">
{% include "shared/navbar" %}
{% include "shared/_navbar.html.j2" %}
<div class="container">
<div class="row">
@@ -32,41 +32,41 @@
{% for section in sections %}
<section id="{{section.title | section_id}}">
<h2>{{section.title}}</h2>
{{section.body | markdownify}}
{{ (section.body | markdownify) if section.body }}
{% for entry in section.entries %}
<section id="{{entry.title | entry_id}}">
<h3>
{{entry.title | markdownify | no_paragraph}}
{{entry.title | markdownify | no_paragraph }}
{% if entry.subtitle %}<small>{{entry.subtitle}}</small>{% endif %}
</h3>
{{entry.body | markdownify}}
{% if entry.examples %}
<div>
{% capture exampleID %}{{ "" | unique }}{% endcapture %}
{% set exampleID = unique_id() %}
<a data-toggle="collapse" href="#example{{exampleID}}">
<i class="glyphicon glyphicon-chevron-right"></i>
{% if entry.examples[1] %}Examples{%else%}Example{%endif%}
{% if entry.examples | length > 1 %}Examples{%else%}Example{%endif%}
</a>
<div id="example{{exampleID}}" class="manual-example collapse">
{% for example in entry.examples %}
<table>
<tr><th></th><td class="jqprogram">jq '{{example.program | escape}}'</td></tr>
<tr><th>Input</th><td>{{example.input | escape}}</td></tr>
{% unless example.output[0] %}
<tr><th></th><td class="jqprogram">jq '{{ example.program }}'</td></tr>
<tr><th>Input</th><td>{{ example.input }}</td></tr>
{% if not example.output[0] %}
<tr>
<th>Output</th>
<td><i>none</i></td>
</tr>
{% endunless %}
{% endif %}
{% for output in example.output %}
<tr>
{% if forloop.index == 1 %}
{% if loop.first %}
<th>Output</th>
{% else %}
<th></th>
{% endif %}
<td>{{output | escape}}</td>
<td>{{ output }}</td>
</tr>
{% endfor %}
</table>
@@ -82,15 +82,15 @@
</div>
</div>
{% include "shared/footer" %}
{% include "shared/_footer.html.j2" %}
<script>
var section_map = {
{% for section in sections %}
{% for entry in section.entries %}
{{entry.title | search_id | json}} : {{entry.title | entry_id | json}},
{{entry.title | search_id | tojson }} : {{entry.title | entry_id | tojson }},
{% endfor %}
{{section.title | search_id | json}} : {{section.title | section_id | json}}
{% unless forloop.last %},{% endunless %}
{{section.title | search_id | tojson }} : {{section.title | section_id | tojson }}
{% if not loop.last %},{% endif %}
{% endfor %}
};
</script>
@@ -1,6 +1,6 @@
<footer>
<div class="container">
<p>This website is made with <a href="http://www.tinytree.info">Bonsai</a> and <a href="http://getbootstrap.com">Bootstrap</a>, themed with <a href="https://bootswatch.com">Bootswatch</a>.</p>
<p>This website is made with <a href="http://getbootstrap.com">Bootstrap</a>, themed with <a href="https://bootswatch.com">Bootswatch</a>.</p>
<p>jq is licensed under the MIT license (code) and the <a href="https://creativecommons.org/licenses/by/3.0/">CC-BY-3.0</a> license (docs).</p>
</div>
</footer>
@@ -7,9 +7,9 @@
<title>{{headline}}</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<link rel="canonical" href="{{url}}{{permalink | remove:'/index'}}" />
<link rel="canonical" href="{{ url }}{{ permalink | replace('/index','') }}" />
<link href="https://maxcdn.bootstrapcdn.com/bootswatch/3.3.5/spacelab/bootstrap.min.css" rel="stylesheet" integrity="sha256-j7Dtnd7ZjexEiPNbscbopFn9+Cs0b3TLipKsWAPHZIM= sha512-RFhfi6P8zWMAJrEGU+CPjuxPh3r/UUBGqQ+/o6WKPIVZmQqeOipGotH2ihRULuQ8wsMBoK15TSZqc/7VYWyuIw==" crossorigin="anonymous">
<link rel="stylesheet" href="{{root}}/css/base.css" type="text/css">
<link rel="stylesheet" href="{{ root }}/css/base.css" type="text/css">
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
@@ -13,8 +13,8 @@
<div class="navbar-collapse collapse" id="nav-collapse">
<ul class="nav navbar-nav">
{% for item in navigation %}
<li {% if item.permalink == permalink %} class="active" {% endif %}>
<a href="{{root}}{{item.permalink}}">{{item.name}}</a>
<li {% if item == permalink %} class="active" {% endif %}>
<a href="{{root}}/{{item}}">{{item | capitalize}}</a>
</li>
{% endfor %}
<li><a href="https://github.com/stedolan/jq/issues">Issues</a></li>
+1 -1
View File
@@ -11,7 +11,7 @@ set -o xtrace
scriptdir=`dirname "$0"`
cd "$scriptdir"/../docs
rm -rf output
rake build
pipenv run python3 build_website.py
cd ..
# copy to /tmp
+7 -2
View File
@@ -1344,8 +1344,13 @@ int jv_contains(jv a, jv b) {
} else if (jv_get_kind(a) == JV_KIND_ARRAY) {
r = jv_array_contains(jv_copy(a), jv_copy(b));
} else if (jv_get_kind(a) == JV_KIND_STRING) {
r = _jq_memmem(jv_string_value(a), jv_string_length_bytes(jv_copy(a)),
jv_string_value(b), jv_string_length_bytes(jv_copy(b))) != 0;
int b_len = jv_string_length_bytes(jv_copy(b));
if (b_len != 0) {
r = _jq_memmem(jv_string_value(a), jv_string_length_bytes(jv_copy(a)),
jv_string_value(b), b_len) != 0;
} else {
r = 1;
}
} else {
r = jv_equal(jv_copy(a), jv_copy(b));
}
+1 -1
View File
@@ -3,5 +3,5 @@
. "${0%/*}/setup" "$@"
# We set PAGER because there's a mantest for `env` that uses it.
(cd $JQBASEDIR/docs && rake mantests) |
(cd $JQBASEDIR/docs && pipenv run python3 build_mantests.py) |
env PAGER=less $VALGRIND $Q $JQ -L "$mods" --run-tests