feat: add full Zonemaster stack with Docker and Spanish UI
- Clone all 5 Zonemaster component repos (LDNS, Engine, CLI, Backend, GUI) - Dockerfile.backend: 8-stage multi-stage build LDNS→Engine→CLI→Backend - Dockerfile.gui: Astro static build served via nginx - docker-compose.yml: backend (internal) + frontend (port 5353) - nginx.conf: root redirects to /es/, /api/ proxied to backend - zonemaster-gui/config.ts: defaultLanguage set to 'es' (Spanish) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
15
zonemaster-cli/.github/pull_request_template.md
vendored
Normal file
15
zonemaster-cli/.github/pull_request_template.md
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
## Purpose
|
||||
|
||||
This PR...
|
||||
|
||||
## Context
|
||||
|
||||
(e.g. Fixes #9999, Follow-up to #9999, etc.)
|
||||
|
||||
## Changes
|
||||
|
||||
...
|
||||
|
||||
## How to test this PR
|
||||
|
||||
...
|
||||
112
zonemaster-cli/.github/workflows/ci.yml
vendored
Normal file
112
zonemaster-cli/.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
---
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- develop
|
||||
- master
|
||||
- 'release/**'
|
||||
pull_request:
|
||||
branches:
|
||||
- develop
|
||||
- master
|
||||
- 'release/**'
|
||||
|
||||
jobs:
|
||||
run-tests:
|
||||
strategy:
|
||||
matrix:
|
||||
compatibility:
|
||||
- develop
|
||||
# - latest
|
||||
perl:
|
||||
- '5.40'
|
||||
- '5.36'
|
||||
- '5.26'
|
||||
runner:
|
||||
- ubuntu-22.04
|
||||
|
||||
runs-on: ${{ matrix.runner }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- uses: shogo82148/actions-setup-perl@v1
|
||||
with:
|
||||
perl-version: ${{ matrix.perl }}
|
||||
|
||||
- name: Install binary dependencies
|
||||
run: |
|
||||
# * These were taken from the installation instruction.
|
||||
# * Gettext was added so we can run cpanm . on the Engine sources.
|
||||
# * The Perl modules were left out because I couldn't get all of them
|
||||
# to work with custom Perl versions.
|
||||
# * Cpanminus was left out because actions-setup-perl installs it.
|
||||
sudo apt-get install -y \
|
||||
autoconf \
|
||||
automake \
|
||||
build-essential \
|
||||
gettext \
|
||||
libidn2-dev \
|
||||
libssl-dev \
|
||||
libtool \
|
||||
m4 \
|
||||
|
||||
- name: Install Zonemaster dependencies (latest)
|
||||
if: ${{ matrix.compatibility == 'latest' }}
|
||||
run: |
|
||||
cpanm --sudo --notest \
|
||||
Module::Install \
|
||||
ExtUtils::PkgConfig \
|
||||
Zonemaster::Engine
|
||||
|
||||
- name: Install Zonemaster dependencies (develop)
|
||||
if: ${{ matrix.compatibility == 'develop' }}
|
||||
run: |
|
||||
cpanm --sudo --notest \
|
||||
Devel::CheckLib \
|
||||
Module::Install \
|
||||
ExtUtils::PkgConfig \
|
||||
Module::Install::XSUtil
|
||||
git clone --branch=develop --depth=1 \
|
||||
https://github.com/zonemaster/zonemaster-ldns.git
|
||||
perl Makefile.PL # Generate MYMETA.yml to appease cpanm .
|
||||
( cd zonemaster-ldns ; cpanm --sudo --notest . )
|
||||
rm -rf zonemaster-ldns
|
||||
git clone --branch=develop --depth=1 \
|
||||
https://github.com/zonemaster/zonemaster-engine.git
|
||||
perl Makefile.PL # Generate MYMETA.yml to appease cpanm .
|
||||
( cd zonemaster-engine ; cpanm --sudo --notest . )
|
||||
rm -rf zonemaster-engine
|
||||
|
||||
# Installing Zonemaster::Engine requires root privileges, because of a
|
||||
# bug in Mail::SPF preventing normal installation with cpanm as
|
||||
# non-root user (see link below [1]).
|
||||
#
|
||||
# The alternative, if one still wishes to install Zonemaster::Engine
|
||||
# as non-root user, is to install Mail::SPF first with a command like:
|
||||
#
|
||||
# % cpanm --notest \
|
||||
# --install-args="--install_path sbin=$HOME/.local/sbin" \
|
||||
# Mail::SPF
|
||||
#
|
||||
# For the sake of consistency, other Perl packages installed from CPAN
|
||||
# are also installed as root.
|
||||
#
|
||||
# [1]: https://rt.cpan.org/Public/Bug/Display.html?id=34768
|
||||
- name: Install remaining dependencies
|
||||
run: |
|
||||
cpanm --sudo --verbose --notest --installdeps .
|
||||
|
||||
- name: Install Zonemaster::CLI
|
||||
run: |
|
||||
cpanm --sudo --verbose --notest .
|
||||
|
||||
- name: Show content of log files
|
||||
if: ${{ failure() }}
|
||||
run: cat /home/runner/.cpanm/work/*/build.log
|
||||
|
||||
- name: Test
|
||||
run: |
|
||||
prove -lv t
|
||||
25
zonemaster-cli/.gitignore
vendored
Normal file
25
zonemaster-cli/.gitignore
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
/Makefile
|
||||
Makefile.old
|
||||
Build
|
||||
Build.bat
|
||||
META.*
|
||||
MYMETA.*
|
||||
.build/
|
||||
_build/
|
||||
cover_db/
|
||||
blib/
|
||||
inc/
|
||||
share/locale/
|
||||
share/*.mo
|
||||
.lwpcookies
|
||||
.last_cover_stats
|
||||
nytprof.out
|
||||
pod2htm*.tmp
|
||||
pm_to_blib
|
||||
Zonemaster-CLI-*
|
||||
Zonemaster-CLI-*.tar.gz
|
||||
share/Zonemaster-CLI.pot
|
||||
|
||||
# Emacs and other backup files
|
||||
*.bak
|
||||
*~
|
||||
17
zonemaster-cli/.perltidyrc
Normal file
17
zonemaster-cli/.perltidyrc
Normal file
@@ -0,0 +1,17 @@
|
||||
-ole=unix
|
||||
-se
|
||||
-bext=~
|
||||
-l=120
|
||||
-i=4
|
||||
-ci=2
|
||||
-nsbl
|
||||
-cti=0
|
||||
-pt=0
|
||||
-sbt=1
|
||||
-bt=1
|
||||
-bbt=0
|
||||
-sfs
|
||||
-tso
|
||||
-csc
|
||||
-csci=20
|
||||
-nbbc
|
||||
30
zonemaster-cli/CONTRIBUTING.md
Normal file
30
zonemaster-cli/CONTRIBUTING.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# Contributing to Zonemaster::CLI
|
||||
|
||||
Contribution to this repository is welcome. Contribution can be either an issue
|
||||
report or a code or a documentation update. Also see the information in the
|
||||
[main README][Zonemaster/Zonemaster README] in the main Zonemaster respository.
|
||||
|
||||
## Issue
|
||||
|
||||
First search for a similar issue in the [issues list]. If a relevant issue is
|
||||
found, add your information as a comment. If no relevant issue is found, create
|
||||
[a new issue][create issue]. Give as many details as you have and describe, if
|
||||
possible, how the issue can be reproduced.
|
||||
|
||||
## Pull request
|
||||
|
||||
If you would like to contribute an update, first please look for issues and open
|
||||
[pull requests] that are about the same thing. If nothing relevant is found or
|
||||
you have a different solution, create [a new pull request][create pull request].
|
||||
Creating a pull request assumes that you have your proposal in a fork repository.
|
||||
|
||||
When you create a pull request, please always start with the `develop` branch
|
||||
and create the pull request against the same branch.
|
||||
|
||||
|
||||
[issues list]: https://github.com/zonemaster/zonemaster-cli/issues
|
||||
[create issue]: https://github.com/zonemaster/zonemaster-cli/issues/new
|
||||
[pull requests]: https://github.com/zonemaster/zonemaster-cli/pulls
|
||||
[create pull request]: https://github.com/zonemaster/zonemaster-cli/compare
|
||||
[Zonemaster/Zonemaster README]: https://github.com/zonemaster/zonemaster#readme
|
||||
|
||||
431
zonemaster-cli/Changes
Normal file
431
zonemaster-cli/Changes
Normal file
@@ -0,0 +1,431 @@
|
||||
Release history for Zonemaster component Zonemaster-CLI
|
||||
|
||||
|
||||
v8.0.1 2025-12-17 (part of Zonemaster v2025.2 release)
|
||||
|
||||
[Fixes]
|
||||
- This version has no changes besides requiring updated
|
||||
Zonemaster-LDNS and Zonemaster-Engine.
|
||||
|
||||
|
||||
v8.0.0 2025-06-26 (part of Zonemaster v2025.1 release)
|
||||
|
||||
[Breaking changes]
|
||||
- Makes the --test option more flexible #359
|
||||
|
||||
[Features]
|
||||
- Expands the --nstimes option #421
|
||||
- Expands the --count option #424
|
||||
|
||||
[Fixes]
|
||||
- Updates translations #444, #445
|
||||
- Slows down the spinner a bit #419
|
||||
|
||||
|
||||
v7.2.0 2025-03-04 (part of Zonemaster v2024.2.1 release)
|
||||
|
||||
[Release information]
|
||||
- Translations have not been fully updated in this release. They will
|
||||
be updated in an upcoming extra release.
|
||||
|
||||
[Features]
|
||||
- Adds translation to Slovenian language (#384)
|
||||
|
||||
[Fixes]
|
||||
- Updates translations (#418, #425, #415, #422, #414)
|
||||
- Minor code cleanup (#420)
|
||||
- Fixes to make early messages not to be lost (#416)
|
||||
|
||||
|
||||
v7.1.0 2024-12-09 (part of Zonemaster v2024.2 release)
|
||||
|
||||
[Release information]
|
||||
- Translations have not been fully updated in this release. They will
|
||||
be updated in an upcoming extra release.
|
||||
|
||||
[Features]
|
||||
- Corrects display when running 'zonemaster-cli' with '--ns' or '--ds'
|
||||
(#382)
|
||||
- Allows explicitly setting '--stop-level' to empty string (#395)
|
||||
|
||||
[Fixes]
|
||||
- Provides a useful link in man page (#401)
|
||||
- Write “AS” in uppercase in Dockerfile (#400)
|
||||
- Corrects gettext code (#398)
|
||||
- Organizes "zonemaster-cli --help" text (#389)
|
||||
- Make "zonemaster-cli" usage documentation consistent and also remove
|
||||
dependency on the Moose library (#371)
|
||||
- Fixes the handling of invalid --hints argument (#386)
|
||||
- Moves the "zonemaster-info" utility from this repository (#385)
|
||||
- Clean-up exit statuses (#381)
|
||||
|
||||
|
||||
v7.0.0 2024-07-01 (part of Zonemaster v2024.1 release)
|
||||
|
||||
[Release information]
|
||||
- Translations have not been fully updated in this release. They will
|
||||
be updated in an upcoming release.
|
||||
|
||||
[Breaking change]
|
||||
- Removes deprecated '--sourceaddr' option. Breaks custom 'cli.args'
|
||||
using this option. Use '--sourceaddr4' and '--sourceaddr6'
|
||||
instead. (#370)
|
||||
|
||||
[Fixes]
|
||||
- Fixes command line argument handling of domain names (#365)
|
||||
- Speeds up Docker build (#374)
|
||||
|
||||
|
||||
v6.1.0 2024-03-18 (public release version)
|
||||
|
||||
[Features]
|
||||
- Extends "--test" option to allow passing of test case only (#333)
|
||||
- Updates "--list_tests" option (#354)
|
||||
- Adds input name normalization (#357)
|
||||
|
||||
[Fixes]
|
||||
- Fixes the "--raw" output (#360)
|
||||
|
||||
|
||||
v6.0.3 2023-09-08 (public fix version)
|
||||
|
||||
[Fixes]
|
||||
- Fixes a spelling error (text) in the zonemaster-cli script (#351).
|
||||
- This version contains no real code changes, but it requires a higher
|
||||
(fixed) version of Zonemaster-Engine.
|
||||
|
||||
v6.0.2 2023-08-07 (public fix version)
|
||||
|
||||
[Fixes]
|
||||
- This version contains no real changes. It has been created to
|
||||
require a higher (fixed) version of Zonemaster-Engine.
|
||||
|
||||
|
||||
v6.0.1 2023-07-24 (public fix version)
|
||||
|
||||
[Fixes]
|
||||
- Updates the translation to Norwegian (#342)
|
||||
|
||||
|
||||
v6.0.0 2023-06-21 (public release version)
|
||||
|
||||
[Breaking changes]
|
||||
- Adds display of Zonemaster::LDNS and libldns versions
|
||||
when --version has been selected (#306)
|
||||
|
||||
[Features]
|
||||
- Updates various report options to zonemaster-cli script
|
||||
(#318, #337, #309, #308)
|
||||
- Adds options "--sourceaddr4" and "--sourceaddr6" to
|
||||
zonemaster-cli script (#317)
|
||||
|
||||
[Fixes]
|
||||
- Updates translations (#338, #328, #329, #331, #327, #322)
|
||||
- Updates documentation in zonemaster-cli script (#336)
|
||||
- Fixes table layout in zonemaster-cli output (#335)
|
||||
- Removes documentation moved to the zonemaster/zonemaster
|
||||
repository (#332)
|
||||
- Removes some untranslatable characters from msgids (#307)
|
||||
|
||||
|
||||
v5.0.2 2023-03-01 (public fix version)
|
||||
|
||||
[Fixes]
|
||||
- Updates translations (#303)
|
||||
|
||||
|
||||
v5.0.1 2023-01-31 (public fix version)
|
||||
|
||||
[Fixes]
|
||||
- Updates translations (#298, #297)
|
||||
|
||||
|
||||
v5.0.0 2022-12-19 (public release version)
|
||||
|
||||
[Breaking changes]
|
||||
- Makes zonemaster-cli fail if there are multiple domain
|
||||
names in entry (#287, #286)
|
||||
|
||||
[Features]
|
||||
- Adds --hints option (#284, #293, #292)
|
||||
|
||||
[Fixes]
|
||||
- Updates installation instruction (#291, #289)
|
||||
- Corrects the license statement in CLI.pm (#288)
|
||||
- Sets lowercase fragments to refer to internal headings in
|
||||
markdown documents (#282)
|
||||
- Cleans-up unused import (#283)
|
||||
- Adds Mac note on USING.md when it comes to Docker (#281)
|
||||
|
||||
|
||||
v4.0.1 2022-07-08 (public fix version)
|
||||
|
||||
[Fixes]
|
||||
- Adds missing installation instructions for CentOS Linux 7
|
||||
(#275)
|
||||
- Updates translation to Danish (#271)
|
||||
|
||||
|
||||
v4.0.0 2022-06-09 (public release version)
|
||||
|
||||
[Breaking changes]
|
||||
- Updates how trailing dots of domain name or name
|
||||
server name is handled. Trailing double dot is now
|
||||
always an error. (#253)
|
||||
|
||||
[Features]
|
||||
- Uses pre-built packages for ubuntu (#268)
|
||||
- Adds support for global configuration file (#260, #252)
|
||||
|
||||
[Fixes]
|
||||
- Updates translation (#263, #267, #266, #265, #269, #264, #261)
|
||||
- Fixes a bug where a trailing dot on name server name
|
||||
gives a crash (#253)
|
||||
- Fixes warning message (#255)
|
||||
- Uses libidn2 instead of libidn (#254)
|
||||
- Updates documentation for users (#241, #244)
|
||||
- Updates installation document (#243)
|
||||
|
||||
|
||||
v3.2.0 2021-12-20 (public fix version)
|
||||
|
||||
[Features]
|
||||
- Adds translation to Spanish language (#219)
|
||||
|
||||
[Fixes]
|
||||
- Clarifies IPv6 limitations in Docker (#238)
|
||||
- Updates Danish translation (#236, #233)
|
||||
- Updates French translation (#237, #225)
|
||||
|
||||
|
||||
v3.1.1 2021-12-03 (public release version)
|
||||
|
||||
[Features]
|
||||
- Deb packages are available for Debian (#233)
|
||||
- Adds support for Docker (#221, #218, #216)
|
||||
- Replaces CentOS with Rocky Linux (#220)
|
||||
|
||||
[Fixes]
|
||||
- Updates Finnish translation (#230, #224)
|
||||
- Updates Norwegian translation (#228, #226)
|
||||
- Updates Swedish translation (#227)
|
||||
- Updates dependencies (#217)
|
||||
- Improves DEBUG3 output (#215, #111)
|
||||
- Improves output when option is incorrect (#214, #160)
|
||||
- Clean-up removing unused options (#213, #145)
|
||||
- More user-friendly options (#212, #159)
|
||||
|
||||
|
||||
v3.1.0 2021-05-28 (public release version)
|
||||
|
||||
[Features]
|
||||
- Adds Finnish translation (PO file) (#192, #191)
|
||||
|
||||
[Fixes]
|
||||
- Updates the installation instructions (#193, #191)
|
||||
- Updates translations (#204, #201, #205, #200,
|
||||
#207, #202)
|
||||
|
||||
|
||||
v3.0.4 2021-02-10 (public release version)
|
||||
|
||||
[Features]
|
||||
- Updates --raw mode output in debug level (#113)
|
||||
|
||||
[Fixes]
|
||||
- Updates the installation instructions (#188)
|
||||
- Prevents PO files to be updated unintentionally (#186)
|
||||
- Fixes how command line options of profile and IP
|
||||
interact (#185, #183, #182)
|
||||
- Makes --sourceaddr behavior more reasonable when
|
||||
selected address is not reasonable (#110, #38)
|
||||
|
||||
v3.0.3 (never released)
|
||||
|
||||
v3.0.2 (never released)
|
||||
|
||||
v3.0.1 2020-11-09 (public release version)
|
||||
|
||||
[Fixes]
|
||||
- Fixed an version specification error in Makefile.PL
|
||||
(#178)
|
||||
|
||||
v3.0.0 2020-11-06 (public release version)
|
||||
|
||||
[Breaking changes]
|
||||
- Added "--show_testcase" and changed format when "--raw"
|
||||
is selected (#157)
|
||||
|
||||
[Features]
|
||||
- Added Norwegian language support to match added
|
||||
translation to Norwegian in Zonemaster-Engine (#164, #155,
|
||||
#161)
|
||||
|
||||
[Fixes]
|
||||
- Updated/corrected translations/PO files (#174, #173)
|
||||
- Corrected documentation (#172)
|
||||
- Rename share/Makefile to share/GNUmakefile and
|
||||
create wrapper for FreeBSD. Make FreeBSD use gmake
|
||||
for share/GNUmakefile (#169)
|
||||
- Corrected MANIFEST (#168)
|
||||
- Updated share/Makefile (#167)
|
||||
- Clean-up (#166, #158)
|
||||
- Correcting --nstimes option (#163, #148)
|
||||
- Updated translation/PO files handling (#151, #132, #147,
|
||||
#150, #149)
|
||||
|
||||
|
||||
v2.0.4 2020-05-22
|
||||
|
||||
[Fixes]
|
||||
- Bumping the version of Zonemaster::CLI to be able to
|
||||
upload a new package to CPAN to avoid the confusion
|
||||
that the version v2.0.3.1 created. There are no
|
||||
changes compared to v2.0.3.
|
||||
|
||||
|
||||
v2.0.3.1 2020-05-15
|
||||
|
||||
[Fixes]
|
||||
- This release fixes inconsitency between the branches in the
|
||||
repository. See the release notes for v2.0.3 for the real
|
||||
changes.
|
||||
- There is no change in data so this release has not been
|
||||
published on CPAN.
|
||||
|
||||
|
||||
v2.0.3 2020-04-30
|
||||
|
||||
[Features]
|
||||
- (none)
|
||||
|
||||
[Fixes]
|
||||
- Update installation instructions (#119, #117, #137)
|
||||
- Translation into Danish (#109, #61)
|
||||
|
||||
|
||||
v2.0.2 2019-05-31 (public fix version)
|
||||
|
||||
[Fixes]
|
||||
- Corrects in Makefile.PL the versions of Zonemaster::Engine
|
||||
and Zonemaster::LDNS that this version of Zonemaster::CLI
|
||||
depends on (#105)
|
||||
|
||||
|
||||
v2.0.1 2019-05-22 (public release version)
|
||||
|
||||
[Status]
|
||||
- This a public release fully tested before release. This version
|
||||
will be available on CPAN.
|
||||
|
||||
[Fixes]
|
||||
- Updated installation instructions for FreeBSD (#101)
|
||||
- Dropped support for Ubuntu 14.04 (#99)
|
||||
- Made Travis use the equivalent branch in Zonemaster-Engine (#98)
|
||||
|
||||
|
||||
v2.0.0 2019-01-25 (pre-release version)
|
||||
|
||||
- Status
|
||||
- This is a pre-release version not fully tested on all supported
|
||||
OS's and Perl versions. This version will not be available on
|
||||
CPAN.
|
||||
- API change
|
||||
- Replaced separate config and policy with a unified profile
|
||||
(see below)
|
||||
- Some changes in printout that can affect scripts using
|
||||
zonemaster-cli (see below)
|
||||
- Features
|
||||
- Changes in printout
|
||||
- Print information on STDERR if --json has been selected #84
|
||||
- Diagnostics #85
|
||||
- Only show spinner in human readable output mode #86
|
||||
- Make --level and --stop_level case-insensitive #87
|
||||
- Replaced separate config and policy with a unified profile
|
||||
- Removed config and policy and added profile #70, #93
|
||||
- Fixes
|
||||
- All link references on Github now to zonemaster/zonemaster instead
|
||||
of old dotse/zonemaster #81
|
||||
- Clarify documentation of --progress option #88
|
||||
- Travis tests against develop branch of Zonemaster-Engine instead
|
||||
of fetching from CPAN #92
|
||||
- Update travis configuration when it comes to Perl versions. #95
|
||||
|
||||
|
||||
v1.1.3 2018-06-25
|
||||
|
||||
Fixed:
|
||||
- Move license from Makefile.PL to main module (#67)
|
||||
- Initialize gettext according to gettext documentation (#71), which
|
||||
solves issues with translations in Linux (#46) and FreeBSD (#64)
|
||||
- Updated the install instructions for debian and centos (#75)
|
||||
- Update Installation.md for FreeBSD (uses cpan instead of cpanm) (#78)
|
||||
|
||||
v1.1.2 2018-01-12
|
||||
|
||||
Natural Language support:
|
||||
- Adding support for Danish translation. (#62)
|
||||
|
||||
Fixed:
|
||||
- Fixes issues with pre-delegation testing ("fake delegation") (#63)
|
||||
|
||||
|
||||
v1.1.1 2017-11-02 Public release
|
||||
|
||||
Fixed:
|
||||
- Update licensing (#58)
|
||||
- Specify smallest version of Locale::TextDomain i Makefile.PL. (#57)
|
||||
- Updated installation instruction (#53)
|
||||
- Changed dependency from Net::LDNS to Zonemaster::LDNS due to
|
||||
name space change (#51)
|
||||
- Various updates to packaging (#52)
|
||||
- Fix Commonmark rendering on Github. Replace NBSP with SPACE. (#49)
|
||||
- Changed dependency from Zonemaster to Zonemaster::Engine due
|
||||
to name space change (#43)
|
||||
|
||||
|
||||
v1.1.0 2017-04-04 Public pre-release
|
||||
- This release will not be published on CPAN since it contains updates that have
|
||||
not been fully tested. Do not update production systems without verification.
|
||||
- Update install instructions (#34)
|
||||
- Fixes packaging issue with version numbering (#35)
|
||||
- Solved --sourceaddr is not correctly implemented (#36)
|
||||
- Updates so that "fake delegation" is tested correctly (#42)
|
||||
|
||||
1.0.5 2016-10-14
|
||||
- Correcting version in CLI.pm. Update missing in 1.0.4.
|
||||
|
||||
1.0.4 2016-10-14
|
||||
- Updating README.md and USING.md
|
||||
- Better way to check ExtUtils::MakeMaker version
|
||||
- Introduced MANIFEST.SKIP
|
||||
|
||||
|
||||
1.0.3 2015-12-22
|
||||
- Added JSON streaming
|
||||
- Changed all instances from .SE to IIS
|
||||
|
||||
1.0.2 2015-06-25
|
||||
- Allow lookup of nameservers for undelegated tests
|
||||
- Net::LDNS::to_idn() takes Perl characters, not octets with utf-8 data
|
||||
- Fixed display bug when using --nstimes with --no-ipv6 or --no-ipv4
|
||||
|
||||
1.0.1 2015-04-07
|
||||
- State clearly that a given name is not a domain when it is not a domain
|
||||
- Send "Net::LDNS not compiled with libidn" to STDERR, not STDOUT
|
||||
|
||||
1.0.0 2014-12-11 Release version
|
||||
|
||||
1.000000 2014-12-11 Public beta release.
|
||||
|
||||
0.001002 2014-11-26
|
||||
|
||||
0.001001 2014-11-19
|
||||
|
||||
0.001000 2014-11-17
|
||||
|
||||
0.03 2014-10-30
|
||||
|
||||
0.01 2014-05-25
|
||||
|
||||
- initial CPAN release
|
||||
37
zonemaster-cli/Dockerfile
Normal file
37
zonemaster-cli/Dockerfile
Normal file
@@ -0,0 +1,37 @@
|
||||
FROM zonemaster/engine:local AS build
|
||||
|
||||
RUN apk add --no-cache \
|
||||
make \
|
||||
perl-app-cpanminus \
|
||||
perl-json-xs \
|
||||
perl-lwp-protocol-https \
|
||||
perl-mojolicious \
|
||||
perl-test-deep \
|
||||
perl-test-differences \
|
||||
perl-try-tiny \
|
||||
&& cpanm --notest --no-wget --from https://cpan.metacpan.org/ \
|
||||
JSON::Validator
|
||||
|
||||
ARG version
|
||||
|
||||
COPY ./Zonemaster-CLI-${version}.tar.gz ./Zonemaster-CLI-${version}.tar.gz
|
||||
|
||||
RUN cpanm --notest --no-wget \
|
||||
./Zonemaster-CLI-${version}.tar.gz
|
||||
|
||||
FROM zonemaster/engine:local
|
||||
|
||||
RUN apk add --no-cache \
|
||||
perl-json-xs \
|
||||
perl-try-tiny
|
||||
|
||||
COPY --from=build /usr/local/bin/zonemaster-cli /usr/local/bin/zonemaster-cli
|
||||
# Include all the Perl modules we built
|
||||
COPY --from=build /usr/local/lib/perl5/site_perl /usr/local/lib/perl5/site_perl
|
||||
COPY --from=build /usr/local/share/perl5/site_perl /usr/local/share/perl5/site_perl
|
||||
|
||||
USER nobody:nogroup
|
||||
|
||||
ENTRYPOINT [ "zonemaster-cli" ]
|
||||
|
||||
CMD [ "--help" ]
|
||||
42
zonemaster-cli/LICENSE
Normal file
42
zonemaster-cli/LICENSE
Normal file
@@ -0,0 +1,42 @@
|
||||
### Code license
|
||||
|
||||
Copyright (c) The Swedish Internet Foundation (<https://internetstiftelsen.se/en/>)
|
||||
Copyright (c) AFNIC (<https://www.afnic.fr/en/>)
|
||||
All rights reserved.
|
||||
|
||||
Copyright belongs to external contributor where applicable.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
### Documentation license
|
||||
|
||||
Copyright (c) The Swedish Internet Foundation (<https://internetstiftelsen.se/en/>)
|
||||
Copyright (c) AFNIC (<https://www.afnic.fr/en/>)
|
||||
All rights reserved.
|
||||
|
||||
Copyright belongs to external contributor where applicable.
|
||||
|
||||
Creative Commons Attribution 4.0 International License
|
||||
|
||||
You should have received a copy of the license along with this
|
||||
work. If not, see <https://creativecommons.org/licenses/by/4.0/>.
|
||||
40
zonemaster-cli/MANIFEST
Normal file
40
zonemaster-cli/MANIFEST
Normal file
@@ -0,0 +1,40 @@
|
||||
Changes
|
||||
CONTRIBUTING.md
|
||||
inc/Module/Install.pm
|
||||
inc/Module/Install/Base.pm
|
||||
inc/Module/Install/Can.pm
|
||||
inc/Module/Install/External.pm
|
||||
inc/Module/Install/Fetch.pm
|
||||
inc/Module/Install/Makefile.pm
|
||||
inc/Module/Install/Metadata.pm
|
||||
inc/Module/Install/Scripts.pm
|
||||
inc/Module/Install/Share.pm
|
||||
inc/Module/Install/Win32.pm
|
||||
inc/Module/Install/WriteAll.pm
|
||||
lib/Zonemaster/CLI.pm
|
||||
lib/Zonemaster/CLI/TestCaseSet.pm
|
||||
LICENSE
|
||||
Makefile.PL
|
||||
MANIFEST This list of files
|
||||
META.yml
|
||||
README.md
|
||||
script/zonemaster-cli
|
||||
share/GNUmakefile
|
||||
share/Makefile
|
||||
share/locale/da/LC_MESSAGES/Zonemaster-CLI.mo
|
||||
share/locale/es/LC_MESSAGES/Zonemaster-CLI.mo
|
||||
share/locale/fi/LC_MESSAGES/Zonemaster-CLI.mo
|
||||
share/locale/fr/LC_MESSAGES/Zonemaster-CLI.mo
|
||||
share/locale/nb/LC_MESSAGES/Zonemaster-CLI.mo
|
||||
share/locale/sl/LC_MESSAGES/Zonemaster-CLI.mo
|
||||
share/locale/sv/LC_MESSAGES/Zonemaster-CLI.mo
|
||||
t/00-load.t
|
||||
t/pod.t
|
||||
t/test_case_set.t
|
||||
t/usage.fake-data.data
|
||||
t/usage.fake-root.data
|
||||
t/usage.hints
|
||||
t/usage.normal.data
|
||||
t/usage.profile
|
||||
t/usage.t
|
||||
t/usage.wrapper.pl
|
||||
83
zonemaster-cli/MANIFEST.SKIP
Normal file
83
zonemaster-cli/MANIFEST.SKIP
Normal file
@@ -0,0 +1,83 @@
|
||||
^\.perltidyrc$
|
||||
^\.perlcriticrc$
|
||||
^\.travis\.yml$
|
||||
^MANIFEST\.SKIP$
|
||||
^Dockerfile$
|
||||
|
||||
# PO files are not present in the distribution package, tests of those are irrelevant there.
|
||||
t/po-files.t
|
||||
|
||||
\.tar\.gz$
|
||||
\.bak$
|
||||
\.po$
|
||||
# Skip MO files directly under share
|
||||
^share/[^/]*\.mo$
|
||||
^share/Zonemaster-CLI.pot$
|
||||
^share/update-po$ # PO files are exluded from dist, which makes this script meaningless in dist
|
||||
|
||||
# Exclude Github control files
|
||||
^\.github/
|
||||
|
||||
#!start included /usr/share/perl/5.20/ExtUtils/MANIFEST.SKIP
|
||||
# Avoid version control files.
|
||||
\bRCS\b
|
||||
\bCVS\b
|
||||
\bSCCS\b
|
||||
,v$
|
||||
\B\.svn\b
|
||||
\B\.git\b
|
||||
\B\.gitignore\b
|
||||
\b_darcs\b
|
||||
\B\.cvsignore$
|
||||
|
||||
# Avoid VMS specific MakeMaker generated files
|
||||
\bDescrip.MMS$
|
||||
\bDESCRIP.MMS$
|
||||
\bdescrip.mms$
|
||||
|
||||
# Avoid Makemaker generated and utility files.
|
||||
\bMANIFEST\.bak
|
||||
\bMakefile$
|
||||
\bblib/
|
||||
\bMakeMaker-\d
|
||||
\bpm_to_blib\.ts$
|
||||
\bpm_to_blib$
|
||||
\bblibdirs\.ts$ # 6.18 through 6.25 generated this
|
||||
|
||||
# Avoid Module::Build generated and utility files.
|
||||
\bBuild$
|
||||
\b_build/
|
||||
\bBuild.bat$
|
||||
\bBuild.COM$
|
||||
\bBUILD.COM$
|
||||
\bbuild.com$
|
||||
|
||||
# Avoid temp and backup files.
|
||||
~$
|
||||
\.old$
|
||||
\#$
|
||||
\b\.#
|
||||
\.bak$
|
||||
\.tmp$
|
||||
\.#
|
||||
\.rej$
|
||||
|
||||
# Avoid OS-specific files/dirs
|
||||
# Mac OSX metadata
|
||||
\B\.DS_Store
|
||||
# Mac OSX SMB mount metadata files
|
||||
\B\._
|
||||
|
||||
# Avoid Devel::Cover and Devel::CoverX::Covered files.
|
||||
\bcover_db\b
|
||||
\bcovered\b
|
||||
|
||||
# Avoid MYMETA files
|
||||
^MYMETA\.
|
||||
#!end included /usr/share/perl/5.20/ExtUtils/MANIFEST.SKIP
|
||||
|
||||
# Development mode aid for File::ShareDir
|
||||
^lib/auto/share/dist/Zonemaster-CLI
|
||||
|
||||
# Avoid MANIFEST test
|
||||
t/manifest.t
|
||||
76
zonemaster-cli/Makefile.PL
Normal file
76
zonemaster-cli/Makefile.PL
Normal file
@@ -0,0 +1,76 @@
|
||||
use 5.014002;
|
||||
use strict;
|
||||
use warnings FATAL => 'all';
|
||||
use inc::Module::Install;
|
||||
|
||||
use ExtUtils::MakeMaker ();
|
||||
|
||||
name 'Zonemaster-CLI';
|
||||
all_from 'lib/Zonemaster/CLI.pm';
|
||||
resources(
|
||||
repository => 'https://github.com/zonemaster/zonemaster-cli',
|
||||
bugtracker => 'https://github.com/zonemaster/zonemaster-cli/issues',
|
||||
);
|
||||
|
||||
tests_recursive( 't' );
|
||||
|
||||
# "2.1.0" could be declared as "2.001" but not as "2.1"
|
||||
# (see Zonemaster::LDNS below)
|
||||
|
||||
requires(
|
||||
'Readonly' => 0,
|
||||
'Net::IP::XS' => 0,
|
||||
'JSON::XS' => 0,
|
||||
'Locale::TextDomain' => 1.23,
|
||||
'Try::Tiny' => 0,
|
||||
'Zonemaster::LDNS' => 5.000001, # v5.0.1
|
||||
'Zonemaster::Engine' => 8.001000, # v8.1.0
|
||||
);
|
||||
|
||||
test_requires(
|
||||
'JSON::Validator' => 0,
|
||||
'Test::Differences' => 0,
|
||||
);
|
||||
|
||||
# Make all platforms include inc/Module/Install/External.pm
|
||||
requires_external_bin 'find';
|
||||
if ($^O eq "freebsd") {
|
||||
requires_external_bin 'gmake';
|
||||
};
|
||||
|
||||
sub MY::postamble {
|
||||
my $pure_all;
|
||||
my $sharemakefile = 'share/GNUmakefile';
|
||||
if ($^O eq "freebsd") {
|
||||
# Make FreeBSD use gmake for share
|
||||
$pure_all = "GMAKE ?= \"gmake\"\n"
|
||||
. "pure_all :: $sharemakefile\n"
|
||||
. "\tcd share && \$(GMAKE) all\n";
|
||||
} else {
|
||||
# Here Linux and GNU Make is assumed
|
||||
$pure_all = "pure_all :: $sharemakefile\n"
|
||||
. "\tcd share && \$(MAKE) all\n";
|
||||
};
|
||||
|
||||
my $docker = <<'END_DOCKER';
|
||||
|
||||
docker-build:
|
||||
docker build --tag zonemaster/cli:local --build-arg version=$(VERSION) .
|
||||
|
||||
docker-tag-version:
|
||||
docker tag zonemaster/cli:local zonemaster/cli:$(VERSION)
|
||||
|
||||
docker-tag-latest:
|
||||
docker tag zonemaster/cli:local zonemaster/cli:latest
|
||||
|
||||
END_DOCKER
|
||||
|
||||
return $pure_all . $docker;
|
||||
};
|
||||
|
||||
|
||||
|
||||
install_script 'zonemaster-cli';
|
||||
install_share;
|
||||
|
||||
WriteAll;
|
||||
70
zonemaster-cli/README.md
Normal file
70
zonemaster-cli/README.md
Normal file
@@ -0,0 +1,70 @@
|
||||
# Zonemaster-CLI
|
||||
|
||||
|
||||
## Purpose
|
||||
|
||||
This Git repository is one of the components of the Zonemaster software and
|
||||
contains the source for the Zonemaster-CLI utility.
|
||||
|
||||
For an overview of the Zonemaster software, please see the
|
||||
[Zonemaster repository].
|
||||
|
||||
|
||||
## Prerequisite
|
||||
|
||||
Before you install the Zonemaster-CLI utility, you need the Zonemaster-Engine
|
||||
test framework installed. Please see the [Zonemaster Engine installation
|
||||
instructions][Zonemaster-Engine installation].
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
For installation, see the [installation] document.
|
||||
|
||||
|
||||
## Configuration
|
||||
|
||||
This repository does not need any specific configuration.
|
||||
|
||||
|
||||
## Docker
|
||||
|
||||
Zonemaster-CLI is available on [Docker Hub], and can be conveniently downloaded
|
||||
and run without any installation. See [USING] Zonemaster-CLI for how to run
|
||||
Zonemaster-CLI on Docker.
|
||||
|
||||
To build your own Docker image, see the [Docker Image Creation] documentation.
|
||||
|
||||
|
||||
## Documentation
|
||||
|
||||
Run `zonemaster-cli --help` to get brief descriptions of a selection of the most
|
||||
important command line options.
|
||||
For complete reference documentation, see the manual page by running `man
|
||||
zonemaster-cli`.
|
||||
Additional end-user documentation is available in the [USING] document.
|
||||
|
||||
When developing Zonemaster-CLI, refer to the [development documentation].
|
||||
|
||||
|
||||
## Participation, Contact and Bug reporting
|
||||
|
||||
For participation, contact and bug reporting, please see the main
|
||||
[Zonemaster README].
|
||||
|
||||
|
||||
## License
|
||||
|
||||
This is free software under a 2-clause BSD license. The full text of the license can
|
||||
be found in the [LICENSE](LICENSE) file included in this respository.
|
||||
|
||||
|
||||
[Development documentation]: https://github.com/zonemaster/zonemaster/blob/master/docs/public/development/cli.md
|
||||
[Docker Image Creation]: https://github.com/zonemaster/zonemaster/blob/master/docs/internal/maintenance/ReleaseProcess-create-docker-image.md
|
||||
[Docker Hub]: https://hub.docker.com/u/zonemaster
|
||||
[Installation]: https://github.com/zonemaster/zonemaster/blob/master/docs/public/installation/zonemaster-cli.md
|
||||
[USING]: https://github.com/zonemaster/zonemaster/blob/master/docs/public/using/cli.md
|
||||
[Zonemaster-Engine installation]: https://github.com/zonemaster/zonemaster/blob/master/docs/public/installation/zonemaster-engine.md
|
||||
[Zonemaster README]: https://github.com/zonemaster/zonemaster/blob/master/README.md
|
||||
[Zonemaster repository]: https://github.com/zonemaster/zonemaster
|
||||
|
||||
973
zonemaster-cli/lib/Zonemaster/CLI.pm
Normal file
973
zonemaster-cli/lib/Zonemaster/CLI.pm
Normal file
@@ -0,0 +1,973 @@
|
||||
# Brief help module to define the exception we use for early exits.
|
||||
package Zonemaster::Engine::Exception::NormalExit;
|
||||
use v5.26;
|
||||
use warnings;
|
||||
use parent 'Zonemaster::Engine::Exception';
|
||||
|
||||
# The actual interesting module.
|
||||
package Zonemaster::CLI;
|
||||
|
||||
use v5.26;
|
||||
|
||||
use warnings;
|
||||
|
||||
use version; our $VERSION = version->declare( "v8.0.1" );
|
||||
|
||||
use Locale::TextDomain 'Zonemaster-CLI';
|
||||
|
||||
use Encode;
|
||||
use File::Slurp;
|
||||
use Getopt::Long qw[GetOptionsFromArray :config gnu_compat bundling no_auto_abbrev];
|
||||
use JSON::XS;
|
||||
use List::Util qw[max uniq];
|
||||
use Net::IP::XS;
|
||||
use Pod::Usage;
|
||||
use POSIX qw[setlocale LC_MESSAGES LC_CTYPE];
|
||||
use Readonly;
|
||||
use Scalar::Util qw[blessed];
|
||||
use Time::HiRes;
|
||||
use Try::Tiny;
|
||||
use Zonemaster::CLI::TestCaseSet;
|
||||
use Zonemaster::Engine::Exception;
|
||||
use Zonemaster::Engine::Logger::Entry;
|
||||
use Zonemaster::Engine::Normalization qw[normalize_name];
|
||||
use Zonemaster::Engine::Translator;
|
||||
use Zonemaster::Engine::Util qw[parse_hints];
|
||||
use Zonemaster::Engine::Validation qw[validate_ipv4 validate_ipv6];
|
||||
use Zonemaster::Engine;
|
||||
use Zonemaster::LDNS;
|
||||
|
||||
our %numeric = Zonemaster::Engine::Logger::Entry->levels;
|
||||
our $JSON = JSON::XS->new->allow_blessed->convert_blessed->canonical;
|
||||
our $SCRIPT = $0;
|
||||
|
||||
Readonly our $EXIT_SUCCESS => 0;
|
||||
Readonly our $EXIT_GENERIC_ERROR => 1;
|
||||
Readonly our $EXIT_USAGE_ERROR => 2;
|
||||
|
||||
Readonly our $DS_RE => qr/^(?:[[:digit:]]+,){3}[[:xdigit:]]+$/;
|
||||
|
||||
STDOUT->autoflush( 1 );
|
||||
|
||||
sub my_pod2usage {
|
||||
my ( %opts ) = @_;
|
||||
|
||||
pod2usage(
|
||||
-input => $SCRIPT,
|
||||
-output => $opts{output},
|
||||
-verbose => $opts{verbosity},
|
||||
-exitcode => 'NOEXIT',
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
# Returns an integer representing an OS exit status.
|
||||
sub run {
|
||||
my ( $class, @argv ) = @_;
|
||||
|
||||
my $opt_count = 0;
|
||||
my @opt_ds = ();
|
||||
my $opt_dump_profile = 0;
|
||||
my $opt_elapsed = 0;
|
||||
my $opt_encoding = undef;
|
||||
my $opt_help = 0;
|
||||
my $opt_hints;
|
||||
my $opt_ipv4 = undef;
|
||||
my $opt_ipv6 = undef;
|
||||
my $opt_json = undef;
|
||||
my $opt_json_stream = 0;
|
||||
my $opt_json_translate = undef;
|
||||
my $opt_level = 'NOTICE';
|
||||
my $opt_list_tests = 0;
|
||||
my $opt_locale = undef;
|
||||
my @opt_ns = ();
|
||||
my $opt_nstimes = 0;
|
||||
my $opt_profile;
|
||||
my $opt_progress = undef;
|
||||
my $opt_raw;
|
||||
my $opt_restore;
|
||||
my $opt_save;
|
||||
my $opt_show_level = 1;
|
||||
my $opt_show_module = 0;
|
||||
my $opt_show_testcase = 0;
|
||||
my $opt_sourceaddr4;
|
||||
my $opt_sourceaddr6;
|
||||
my $opt_stop_level = '';
|
||||
my @opt_test = ();
|
||||
my $opt_time = 1;
|
||||
my $opt_version = 0;
|
||||
|
||||
{
|
||||
local $SIG{__WARN__} = sub { print STDERR $_[0] };
|
||||
|
||||
GetOptionsFromArray(
|
||||
\@argv,
|
||||
'count!' => \$opt_count,
|
||||
'ds=s' => \@opt_ds,
|
||||
'dump-profile!' => \$opt_dump_profile,
|
||||
'dump_profile!' => \$opt_dump_profile,
|
||||
'elapsed!' => \$opt_elapsed,
|
||||
'encoding=s' => \$opt_encoding,
|
||||
'hints=s' => \$opt_hints,
|
||||
'help|h|usage|?!' => \$opt_help,
|
||||
'ipv4!' => \$opt_ipv4,
|
||||
'ipv6!' => \$opt_ipv6,
|
||||
'json!' => \$opt_json,
|
||||
'json-stream!' => \$opt_json_stream,
|
||||
'json_stream!' => \$opt_json_stream,
|
||||
'json-translate!' => \$opt_json_translate,
|
||||
'json_translate!' => \$opt_json_translate,
|
||||
'level=s' => \$opt_level,
|
||||
'list-tests!' => \$opt_list_tests,
|
||||
'list_tests!' => \$opt_list_tests,
|
||||
'locale=s' => \$opt_locale,
|
||||
'ns=s' => \@opt_ns,
|
||||
'nstimes!' => \$opt_nstimes,
|
||||
'profile=s' => \$opt_profile,
|
||||
'progress!' => \$opt_progress,
|
||||
'raw!' => \$opt_raw,
|
||||
'restore=s' => \$opt_restore,
|
||||
'save=s' => \$opt_save,
|
||||
'show-level!' => \$opt_show_level,
|
||||
'show_level!' => \$opt_show_level,
|
||||
'show-module!' => \$opt_show_module,
|
||||
'show_module!' => \$opt_show_module,
|
||||
'show-testcase!' => \$opt_show_testcase,
|
||||
'show_testcase!' => \$opt_show_testcase,
|
||||
'sourceaddr4=s' => \$opt_sourceaddr4,
|
||||
'sourceaddr6=s' => \$opt_sourceaddr6,
|
||||
'stop-level=s' => \$opt_stop_level,
|
||||
'stop_level=s' => \$opt_stop_level,
|
||||
'test=s' => \@opt_test,
|
||||
'time!' => \$opt_time,
|
||||
'version!' => \$opt_version,
|
||||
)
|
||||
or do {
|
||||
my_pod2usage( verbosity => 0, output => \*STDERR );
|
||||
return 2;
|
||||
};
|
||||
}
|
||||
|
||||
if ( $opt_help ) {
|
||||
my_pod2usage( verbosity => 1, output => \*STDOUT );
|
||||
say "Severity levels from highest to lowest:";
|
||||
say " CRITICAL, ERROR, WARNING, NOTICE, INFO, DEBUG, DEBUG2, DEBUG3";
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
$opt_level = uc $opt_level;
|
||||
$opt_stop_level = uc $opt_stop_level;
|
||||
|
||||
my @accumulator;
|
||||
my %counter;
|
||||
my $printed_something;
|
||||
|
||||
if ( $opt_locale ) {
|
||||
undef $ENV{LANGUAGE};
|
||||
$ENV{LC_ALL} = $opt_locale;
|
||||
}
|
||||
|
||||
# Set LC_MESSAGES and LC_CTYPE separately
|
||||
# (https://www.gnu.org/software/gettext/manual/html_node/Triggering.html#Triggering)
|
||||
if ( not defined setlocale( LC_MESSAGES, "" ) ) {
|
||||
my $locale = ( $ENV{LANGUAGE} || $ENV{LC_ALL} || $ENV{LC_MESSAGES} );
|
||||
say STDERR __x(
|
||||
"Warning: setting locale category LC_MESSAGES to {locale} failed -- is it installed on this system?",
|
||||
locale => $locale ) . "\n\n";
|
||||
}
|
||||
|
||||
if ( not defined setlocale( LC_CTYPE, "" ) ) {
|
||||
my $locale = ( $ENV{LC_ALL} || $ENV{LC_CTYPE} );
|
||||
say STDERR __x(
|
||||
"Warning: setting locale category LC_CTYPE to {locale} failed -- is it installed on this system?",
|
||||
locale => $locale ) . "\n\n";
|
||||
}
|
||||
|
||||
if ( $opt_version ) {
|
||||
print_versions();
|
||||
return $EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
if ( $opt_list_tests ) {
|
||||
print_test_list();
|
||||
return $EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
# errors and warnings
|
||||
if ( defined $opt_encoding ) {
|
||||
say STDERR __( "Warning: deprecated --encoding, simply remove it from your usage." );
|
||||
}
|
||||
|
||||
if ( $opt_json_stream and defined $opt_json and not $opt_json ) {
|
||||
say STDERR __( "Error: --json-stream and --no-json cannot be used together." );
|
||||
return $EXIT_USAGE_ERROR;
|
||||
}
|
||||
|
||||
if ( defined $opt_json_translate ) {
|
||||
unless ( $opt_json or $opt_json_stream ) {
|
||||
printf STDERR __( "Warning: --json-translate has no effect without either --json or --json-stream." )
|
||||
. "\n";
|
||||
}
|
||||
if ( $opt_json_translate ) {
|
||||
printf STDERR __( "Warning: deprecated --json-translate, use --no-raw instead." ) . "\n";
|
||||
}
|
||||
else {
|
||||
printf STDERR __( "Warning: deprecated --no-json-translate, use --raw instead." ) . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
# align values
|
||||
$opt_json = 1 if $opt_json_stream;
|
||||
$opt_raw //= defined $opt_json_translate ? !$opt_json_translate : 0;
|
||||
|
||||
# Filehandle for diagnostics output
|
||||
my $fh_diag = ( $opt_json or $opt_raw or $opt_dump_profile )
|
||||
? *STDERR # Structured output mode (e.g. JSON)
|
||||
: *STDOUT; # Human readable output mode
|
||||
|
||||
my $show_progress = $opt_progress // !!-t STDOUT && !$opt_json && !$opt_raw;
|
||||
|
||||
if ( $opt_profile ) {
|
||||
say $fh_diag __x( "Loading profile from {path}.", path => $opt_profile );
|
||||
my $json = read_file( $opt_profile );
|
||||
my $foo = Zonemaster::Engine::Profile->from_json( $json );
|
||||
my $profile = Zonemaster::Engine::Profile->default;
|
||||
$profile->merge( $foo );
|
||||
Zonemaster::Engine::Profile->effective->merge( $profile );
|
||||
}
|
||||
|
||||
if ( defined $opt_sourceaddr4 ) {
|
||||
local $@;
|
||||
eval {
|
||||
Zonemaster::Engine::Profile->effective->set( q{resolver.source4}, $opt_sourceaddr4 );
|
||||
1;
|
||||
} or do {
|
||||
say STDERR __x( "Error: invalid value for --sourceaddr4: {reason}", reason => $@ );
|
||||
return $EXIT_USAGE_ERROR;
|
||||
};
|
||||
}
|
||||
|
||||
if ( defined $opt_sourceaddr6 ) {
|
||||
local $@;
|
||||
eval {
|
||||
Zonemaster::Engine::Profile->effective->set( q{resolver.source6}, $opt_sourceaddr6 );
|
||||
1;
|
||||
} or do {
|
||||
say STDERR __x( "Error: invalid value for --sourceaddr6: {reason}", reason => $@ );
|
||||
return $EXIT_USAGE_ERROR;
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
my %all_methods = Zonemaster::Engine->all_methods;
|
||||
my $cases = Zonemaster::CLI::TestCaseSet->new( #
|
||||
Zonemaster::Engine::Profile->effective->get( q{test_cases} ),
|
||||
\%all_methods,
|
||||
);
|
||||
|
||||
for my $test ( @opt_test ) {
|
||||
my @modifiers = Zonemaster::CLI::TestCaseSet->parse_modifier_expr( $test );
|
||||
while ( @modifiers ) {
|
||||
my $op = shift @modifiers;
|
||||
my $term = shift @modifiers;
|
||||
|
||||
if ( !$cases->apply_modifier( $op, $term ) ) {
|
||||
say STDERR __x( "Error: unrecognized term '{term}' in --test.", term => $term ) . "\n";
|
||||
return $EXIT_USAGE_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Zonemaster::Engine::Profile->effective->set( q{test_cases}, [ $cases->to_list ] ),
|
||||
}
|
||||
|
||||
# These two must come after any profile from command line has been loaded
|
||||
# to make any IPv4/IPv6 option override the profile setting.
|
||||
if ( defined( $opt_ipv4 ) ) {
|
||||
Zonemaster::Engine::Profile->effective->set( q{net.ipv4}, $opt_ipv4 );
|
||||
}
|
||||
if ( defined( $opt_ipv6 ) ) {
|
||||
Zonemaster::Engine::Profile->effective->set( q{net.ipv6}, $opt_ipv6 );
|
||||
}
|
||||
|
||||
if ( $opt_dump_profile ) {
|
||||
do_dump_profile();
|
||||
return $EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
if ( $opt_stop_level and not defined( $numeric{$opt_stop_level} ) ) {
|
||||
say STDERR __x( "Failed to recognize stop level '{level}'.", level => $opt_stop_level );
|
||||
return $EXIT_USAGE_ERROR;
|
||||
}
|
||||
|
||||
if ( not defined $numeric{$opt_level} ) {
|
||||
say STDERR __( "--level must be one of CRITICAL, ERROR, WARNING, NOTICE, INFO, DEBUG, DEBUG2 or DEBUG3." );
|
||||
return $EXIT_USAGE_ERROR;
|
||||
}
|
||||
|
||||
if ( $opt_restore ) {
|
||||
Zonemaster::Engine->preload_cache( $opt_restore );
|
||||
}
|
||||
|
||||
my $level_width = 0;
|
||||
foreach ( keys %numeric ) {
|
||||
if ( $numeric{$opt_level} <= $numeric{$_} ) {
|
||||
my $width_l10n = length( decode_utf8( translate_severity( $_ ) ) );
|
||||
$level_width = $width_l10n if $width_l10n > $level_width;
|
||||
}
|
||||
}
|
||||
|
||||
my $translator;
|
||||
my %field_width = (
|
||||
seconds => 7,
|
||||
level => $level_width,
|
||||
module => 12,
|
||||
testcase => 14
|
||||
);
|
||||
my %header_names = ();
|
||||
my %remaining_space = ();
|
||||
|
||||
# Callback defined here so it closes over the setup above.
|
||||
# But we can’t use it right now because the translator isn’t initialized.
|
||||
my $message_printer = sub {
|
||||
my ( $entry ) = @_;
|
||||
|
||||
print_spinner() if $show_progress;
|
||||
|
||||
my $entry_level = $entry->level;
|
||||
|
||||
$counter{ uc $entry_level } += 1;
|
||||
|
||||
if ( $numeric{ uc $entry_level } >= $numeric{$opt_level} ) {
|
||||
$printed_something = 1;
|
||||
|
||||
if ( $opt_json and $opt_json_stream ) {
|
||||
my %r;
|
||||
|
||||
$r{timestamp} = $entry->timestamp if $opt_time;
|
||||
$r{module} = $entry->module if $opt_show_module;
|
||||
$r{testcase} = $entry->testcase if $opt_show_testcase;
|
||||
$r{tag} = $entry->tag;
|
||||
$r{level} = $entry_level if $opt_show_level;
|
||||
$r{args} = $entry->args if $entry->args;
|
||||
$r{message} = $translator->translate_tag( $entry ) unless $opt_raw;
|
||||
|
||||
say $JSON->encode( \%r );
|
||||
}
|
||||
elsif ( $opt_json and not $opt_json_stream ) {
|
||||
# Don't do anything
|
||||
}
|
||||
else {
|
||||
my $prefix = q{};
|
||||
if ( $opt_time ) {
|
||||
$prefix .= sprintf "%*.2f ", ${ field_width { seconds } }, $entry->timestamp;
|
||||
}
|
||||
|
||||
if ( $opt_show_level ) {
|
||||
$prefix .= $opt_raw ? $entry->level : translate_severity( $entry->level );
|
||||
my $space_l10n =
|
||||
${ field_width { level } } - length( decode_utf8( translate_severity( $entry_level ) ) ) + 1;
|
||||
$prefix .= ' ' x $space_l10n;
|
||||
}
|
||||
|
||||
if ( $opt_show_module ) {
|
||||
$prefix .= sprintf "%-*s ", ${ field_width { module } }, $entry->module;
|
||||
}
|
||||
|
||||
if ( $opt_show_testcase ) {
|
||||
$prefix .= sprintf "%-*s ", ${ field_width { testcase } }, $entry->testcase;
|
||||
}
|
||||
|
||||
if ( $opt_raw ) {
|
||||
$prefix .= $entry->tag;
|
||||
|
||||
my $message = $entry->argstr;
|
||||
my @lines = split /\n/, $message;
|
||||
|
||||
printf "%s%s %s\n", $prefix, ' ', @lines ? shift @lines : '';
|
||||
for my $line ( @lines ) {
|
||||
printf "%s%s %s\n", $prefix, '>', $line;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( $entry_level eq q{DEBUG3}
|
||||
and scalar( keys %{ $entry->args } ) == 1
|
||||
and defined $entry->args->{packet} )
|
||||
{
|
||||
my $packet = $entry->args->{packet};
|
||||
my $padding = q{ } x length $prefix;
|
||||
$entry->args->{packet} = q{};
|
||||
printf "%s%s\n", $prefix, $translator->translate_tag( $entry );
|
||||
foreach my $line ( split /\n/, $packet ) {
|
||||
printf "%s%s\n", $padding, $line;
|
||||
}
|
||||
}
|
||||
else {
|
||||
printf "%s%s\n", $prefix, $translator->translate_tag( $entry );
|
||||
}
|
||||
}
|
||||
} ## end else [ if ( $opt_json and $opt_json_stream)]
|
||||
} ## end if ( $numeric{ uc $entry_level...})
|
||||
if ( $opt_stop_level and $numeric{ uc $entry->level } >= $numeric{$opt_stop_level} ) {
|
||||
die(
|
||||
Zonemaster::Engine::Exception::NormalExit->new(
|
||||
{ message => "Saw message at level " . $entry->level }
|
||||
)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
# Instead, hold early messages in a temporary queue and switch to the
|
||||
# actual callback when we are ready.
|
||||
my @held_messages;
|
||||
Zonemaster::Engine->logger->callback(
|
||||
sub {
|
||||
my ( $entry ) = @_;
|
||||
push @held_messages, @_;
|
||||
}
|
||||
);
|
||||
|
||||
if ( @argv > 1 ) {
|
||||
say STDERR __(
|
||||
"Only one domain can be given for testing. Did you forget to prepend an option with '--<OPTION>'?" );
|
||||
return $EXIT_USAGE_ERROR;
|
||||
}
|
||||
elsif ( @argv < 1 ) {
|
||||
say STDERR __( "Must give the name of a domain to test." );
|
||||
return $EXIT_USAGE_ERROR;
|
||||
}
|
||||
|
||||
my ( $domain ) = @argv;
|
||||
|
||||
( my $errors, $domain ) = normalize_name( decode( 'utf8', $domain ) );
|
||||
|
||||
if ( @opt_ns ) {
|
||||
local $@;
|
||||
eval {
|
||||
check_fake_delegation( $domain, @opt_ns );
|
||||
1;
|
||||
} or do {
|
||||
print STDERR $@;
|
||||
return $EXIT_USAGE_ERROR;
|
||||
};
|
||||
}
|
||||
|
||||
if ( @opt_ds ) {
|
||||
check_fake_ds( @opt_ds );
|
||||
}
|
||||
|
||||
if ( scalar @$errors > 0 ) {
|
||||
my $error_message;
|
||||
foreach my $err ( @$errors ) {
|
||||
$error_message .= $err->string . "\n";
|
||||
}
|
||||
print STDERR $error_message;
|
||||
return $EXIT_USAGE_ERROR;
|
||||
}
|
||||
|
||||
if ( defined $opt_hints ) {
|
||||
my $hints_data;
|
||||
my $error = undef;
|
||||
try {
|
||||
my $hints_text = read_file( $opt_hints ) // die "read_file failed\n";
|
||||
local $SIG{__WARN__} = \¨
|
||||
$hints_data = parse_hints( $hints_text )
|
||||
}
|
||||
catch {
|
||||
$error = $_;
|
||||
};
|
||||
|
||||
if ( defined $error ) {
|
||||
print STDERR __x( "Error loading hints file: {message}", message => $error );
|
||||
return $EXIT_USAGE_ERROR;
|
||||
}
|
||||
|
||||
Zonemaster::Engine::Recursor->remove_fake_addresses( '.' );
|
||||
Zonemaster::Engine::Recursor->add_fake_addresses( '.', $hints_data );
|
||||
} ## end if ( defined $opt_hints)
|
||||
|
||||
# This can generate early log messages.
|
||||
if ( @opt_ns ) {
|
||||
local $@;
|
||||
eval {
|
||||
add_fake_delegation( $domain, @opt_ns );
|
||||
1;
|
||||
} or do {
|
||||
print STDERR $@;
|
||||
return $EXIT_USAGE_ERROR;
|
||||
};
|
||||
}
|
||||
|
||||
if ( @opt_ds ) {
|
||||
add_fake_ds( $domain, @opt_ds );
|
||||
}
|
||||
|
||||
if ( not $opt_raw ) {
|
||||
$translator = Zonemaster::Engine::Translator->new;
|
||||
$translator->locale( $opt_locale )
|
||||
if $opt_locale;
|
||||
|
||||
%header_names = (
|
||||
seconds => __( 'Seconds' ),
|
||||
level => __( 'Level' ),
|
||||
module => __( 'Module' ),
|
||||
testcase => __( 'Testcase' ),
|
||||
message => __( 'Message' )
|
||||
);
|
||||
foreach ( keys %header_names ) {
|
||||
$field_width{$_} = _max( $field_width{$_}, length( decode_utf8( $header_names{$_} ) ) );
|
||||
$remaining_space{$_} = $field_width{$_} - length( decode_utf8( $header_names{$_} ) );
|
||||
}
|
||||
}
|
||||
|
||||
if ( $opt_profile or @opt_test ) {
|
||||
# Separate initialization from main output in human readable output mode
|
||||
print "\n" if $fh_diag eq *STDOUT;
|
||||
}
|
||||
|
||||
if ( not $opt_raw and not $opt_json ) {
|
||||
my $header = q{};
|
||||
|
||||
if ( $opt_time ) {
|
||||
$header .= sprintf "%s%s ", $header_names{seconds}, " " x $remaining_space{seconds};
|
||||
}
|
||||
if ( $opt_show_level ) {
|
||||
$header .= sprintf "%s%s ", $header_names{level}, " " x $remaining_space{level};
|
||||
}
|
||||
if ( $opt_show_module ) {
|
||||
$header .= sprintf "%s%s ", $header_names{module}, " " x $remaining_space{module};
|
||||
}
|
||||
if ( $opt_show_testcase ) {
|
||||
$header .= sprintf "%s%s ", $header_names{testcase}, " " x $remaining_space{testcase};
|
||||
}
|
||||
$header .= sprintf "%s\n", $header_names{message};
|
||||
|
||||
if ( $opt_time ) {
|
||||
$header .= sprintf "%s ", "=" x $field_width{seconds};
|
||||
}
|
||||
if ( $opt_show_level ) {
|
||||
$header .= sprintf "%s ", "=" x $field_width{level};
|
||||
}
|
||||
if ( $opt_show_module ) {
|
||||
$header .= sprintf "%s ", "=" x $field_width{module};
|
||||
}
|
||||
if ( $opt_show_testcase ) {
|
||||
$header .= sprintf "%s ", "=" x $field_width{testcase};
|
||||
}
|
||||
$header .= sprintf "%s\n", "=" x $field_width{message};
|
||||
|
||||
print $header;
|
||||
} ## end if ( not $opt_raw and ...)
|
||||
|
||||
# Now we are ready to actually print messages, including those that are
|
||||
# currently in the hold queue.
|
||||
while ( my $entry = pop @held_messages ) {
|
||||
$message_printer->( $entry );
|
||||
}
|
||||
Zonemaster::Engine->logger->callback( $message_printer );
|
||||
|
||||
# Actually run tests!
|
||||
eval { Zonemaster::Engine->test_zone( $domain ); };
|
||||
|
||||
if ( $@ ) {
|
||||
my $err = $@;
|
||||
if ( blessed $err and $err->isa( "Zonemaster::Engine::Exception::NormalExit" ) ) {
|
||||
say STDERR "Exited early: " . $err->message;
|
||||
}
|
||||
else {
|
||||
die $err; # Don't know what it is, rethrow
|
||||
}
|
||||
}
|
||||
|
||||
if ( not $opt_raw and not $opt_json ) {
|
||||
if ( not $printed_something ) {
|
||||
say __( "Looks OK." );
|
||||
}
|
||||
}
|
||||
|
||||
my $json_output = {};
|
||||
|
||||
if ( $opt_count ) {
|
||||
my %entries;
|
||||
foreach my $e ( @{ Zonemaster::Engine->logger->entries } ) {
|
||||
$entries{$e->level}{$e->tag} += 1;
|
||||
}
|
||||
|
||||
if ( $opt_json ) {
|
||||
$json_output->{count} = {};
|
||||
foreach my $level ( sort { $numeric{$b} <=> $numeric{$a} } keys %counter ) {
|
||||
$json_output->{count}{by_level}{$level} = $counter{$level};
|
||||
}
|
||||
|
||||
foreach my $level ( sort { $numeric{$b} <=> $numeric{$a} } keys %entries ) {
|
||||
foreach my $tag ( sort keys %{ $entries{$level} } ) {
|
||||
$json_output->{count}{by_message_tag}{$level}{$tag} = $entries{$level}{$tag};
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
my $header1 = __( 'Level' );
|
||||
my $max1 = length $header1;
|
||||
my $header2 = __( 'Number of log entries' );
|
||||
my $max2 = length $header2;
|
||||
|
||||
foreach my $level ( sort { $numeric{$b} <=> $numeric{$a} } keys %counter ) {
|
||||
my $len = length translate_severity( $level );
|
||||
$max1 = $len if $len > $max1;
|
||||
}
|
||||
|
||||
printf "\n\n%${max1}s\t%${max2}s", $header1, $header2;
|
||||
printf "\n%s\t%s\n", '=' x $max1, '=' x $max2;
|
||||
|
||||
foreach my $level ( sort { $numeric{$b} <=> $numeric{$a} } keys %counter ) {
|
||||
printf "%${max1}s\t%${max2}d\n", translate_severity( $level ), $counter{$level};
|
||||
}
|
||||
|
||||
my $header3 = __( 'Message tag' );
|
||||
my $max3 = max map { length "$_" } ( ( map { keys %{ $_ } } ( values %entries ) ), $header3 );
|
||||
my $header4 = __( 'Count' );
|
||||
my $max4 = max map { length "$_" } ( ( map { values %{ $_ } } ( values %entries ) ), $header4 );
|
||||
|
||||
printf "\n%${max1}s\t%${max3}s\t%${max4}s", $header1, $header3, $header4;
|
||||
printf "\n%${max1}s\t%${max3}s\t%${max4}s\n", '=' x $max1, '=' x $max3, '=' x $max4;
|
||||
foreach my $level ( sort { $numeric{$b} <=> $numeric{$a} } keys %entries ) {
|
||||
foreach my $tag ( sort keys %{ $entries{$level} } ) {
|
||||
printf "%${max1}s\t%${max3}s\t%${max4}s\n", $level, $tag, $entries{$level}{$tag};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( $opt_nstimes ) {
|
||||
my $zone = Zonemaster::Engine->zone( $domain );
|
||||
my %all_nss = %{ Zonemaster::Engine::Nameserver::object_cache };
|
||||
my @child_nss = @{ $zone->ns };
|
||||
my @parent_nss = @{ $zone->parent->ns };
|
||||
my @all_responded_nss;
|
||||
|
||||
foreach my $ns_name ( keys %all_nss ) {
|
||||
foreach my $ns ( values %{ $all_nss{$ns_name} } ) {
|
||||
push @all_responded_nss, $ns if scalar @{ $ns->times } > 0;
|
||||
}
|
||||
}
|
||||
|
||||
my %nss_filter = map { $_ => undef } ( @child_nss, @parent_nss );
|
||||
my @other_nss = grep { ! exists $nss_filter{$_} } @all_responded_nss;
|
||||
|
||||
if ( $opt_json ) {
|
||||
my @times;
|
||||
|
||||
my sub json_nstimes {
|
||||
my ( $ns ) = @_;
|
||||
return {
|
||||
'ns' => $ns->string,
|
||||
'max' => 1000 * $ns->max_time,
|
||||
'min' => 1000 * $ns->min_time,
|
||||
'avg' => 1000 * $ns->average_time,
|
||||
'stddev' => 1000 * $ns->stddev_time,
|
||||
'median' => 1000 * $ns->median_time,
|
||||
'total' => 1000 * $ns->sum_time,
|
||||
'count' => scalar @{ $ns->times }
|
||||
};
|
||||
}
|
||||
|
||||
my %section_mapping = (
|
||||
'child' => \@child_nss,
|
||||
'parent' => \@parent_nss,
|
||||
'other' => \@other_nss
|
||||
);
|
||||
|
||||
foreach my $section_name ( sort keys %section_mapping ) {
|
||||
my @entries = map { json_nstimes( $_ ) } sort @{ $section_mapping{$section_name} };
|
||||
push @times, { $section_name => \@entries };
|
||||
}
|
||||
|
||||
$json_output->{nstimes} = \@times;
|
||||
}
|
||||
else {
|
||||
my $header = __( 'Name servers' );
|
||||
my $max = max map { length( "$_" ) } ( ( @child_nss, @parent_nss, @all_responded_nss ), $header );
|
||||
printf "\n%${max}s %s\n", $header, ' Max Min Avg Stddev Median Total Count';
|
||||
printf "%${max}s %s\n", '=' x $max, ' ========== ========== ========== ========== ========== =========== ===========';
|
||||
|
||||
my $total_queries_count = 0;
|
||||
my $total_queries_times = 0;
|
||||
my %nss_already_processed;
|
||||
|
||||
my sub print_nstimes {
|
||||
my ( $ns, $max, $total_queries_count, $total_queries_times, $nss_already_processed_ref ) = @_;
|
||||
my %nss_already_processed = %{ $nss_already_processed_ref };
|
||||
|
||||
printf "%${max}s ", $ns->string;
|
||||
printf "%11.2f ", 1000 * $ns->max_time;
|
||||
printf "%10.2f ", 1000 * $ns->min_time;
|
||||
printf "%10.2f ", 1000 * $ns->average_time;
|
||||
printf "%10.2f ", 1000 * $ns->stddev_time;
|
||||
printf "%10.2f ", 1000 * $ns->median_time;
|
||||
printf "%11.2f ", 1000 * $ns->sum_time;
|
||||
printf "%11d\n", scalar @{ $ns->times };
|
||||
$total_queries_count += scalar @{ $ns->times } unless $nss_already_processed{$ns};
|
||||
$total_queries_times += ( 1000 * $ns->sum_time ) unless $nss_already_processed{$ns};
|
||||
|
||||
return $total_queries_count, $total_queries_times;
|
||||
}
|
||||
|
||||
my %section_mapping = (
|
||||
1 => { __( 'Child zone' ) => \@child_nss },
|
||||
2 => { __( 'Parent zone' ) => \@parent_nss },
|
||||
3 => { __( 'Other' ) => \@other_nss }
|
||||
);
|
||||
|
||||
foreach my $section_order ( sort keys %section_mapping ) {
|
||||
foreach my $section_header ( keys % { $section_mapping{$section_order} } ) {
|
||||
printf "%s %s\n", $section_header, '-' x ( ( $max - length $section_header ) - 1 );
|
||||
|
||||
foreach my $section_nss ( sort @{ $section_mapping{$section_order}{$section_header} } ) {
|
||||
( $total_queries_count, $total_queries_times ) =
|
||||
print_nstimes( $section_nss, $max, $total_queries_count, $total_queries_times, \%nss_already_processed );
|
||||
$nss_already_processed{$section_nss} = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf "%${max}s %s\n", '=' x $max, ' ========== ========== ========== ========== ========== =========== ===========';
|
||||
printf "%${max}s %67.2f %11s\n", __( 'Grand total' ), $total_queries_times, $total_queries_count;
|
||||
}
|
||||
} ## end if ( $opt_nstimes )
|
||||
|
||||
if ( $opt_elapsed ) {
|
||||
my $last = Zonemaster::Engine->logger->entries->[-1];
|
||||
|
||||
if ( $opt_json ) {
|
||||
$json_output->{elapsed} = $last->timestamp;
|
||||
}
|
||||
else {
|
||||
printf "\nTotal test run time: %0.1f seconds.\n", $last->timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $opt_json and not $opt_json_stream ) {
|
||||
my $res = Zonemaster::Engine->logger->json( $opt_level );
|
||||
$res = $JSON->decode( $res );
|
||||
foreach ( @$res ) {
|
||||
unless ( $opt_raw ) {
|
||||
my %e = %$_;
|
||||
my $entry = Zonemaster::Engine::Logger::Entry->new( \%e );
|
||||
$_->{message} = $translator->translate_tag( $entry );
|
||||
}
|
||||
delete $_->{timestamp} unless $opt_time;
|
||||
delete $_->{level} unless $opt_show_level;
|
||||
delete $_->{module} unless $opt_show_module;
|
||||
delete $_->{testcase} unless $opt_show_testcase;
|
||||
}
|
||||
$json_output->{results} = $res;
|
||||
}
|
||||
|
||||
if ( scalar keys %$json_output ) {
|
||||
say $JSON->encode( $json_output );
|
||||
}
|
||||
|
||||
if ( $opt_save ) {
|
||||
Zonemaster::Engine->save_cache( $opt_save );
|
||||
}
|
||||
|
||||
return $EXIT_SUCCESS;
|
||||
} ## end sub run
|
||||
|
||||
sub check_fake_delegation {
|
||||
my ( $domain, @ns ) = @_;
|
||||
|
||||
foreach my $pair ( @ns ) {
|
||||
my ( $name, $ip ) = split( '/', $pair, 2 );
|
||||
|
||||
if ( $pair =~ tr/\/// > 1 or not $name ) {
|
||||
die __( "--ns must be a name or a name/ip pair." ) . "\n";
|
||||
}
|
||||
|
||||
( my $errors, $name ) = normalize_name( decode( 'utf8', $name ) );
|
||||
|
||||
if ( scalar @$errors > 0 ) {
|
||||
my $error_message = "Invalid name in --ns argument:\n";
|
||||
foreach my $err ( @$errors ) {
|
||||
$error_message .= "\t" . $err->string . "\n";
|
||||
}
|
||||
die $error_message;
|
||||
}
|
||||
|
||||
if ( $ip ) {
|
||||
my $net_ip = Net::IP::XS->new( $ip );
|
||||
unless ( validate_ipv4( $ip ) or validate_ipv6( $ip ) ) {
|
||||
die Net::IP::XS::Error()
|
||||
? "Invalid IP address in --ns argument:\n\t" . Net::IP::XS::Error() . "\n"
|
||||
: "Invalid IP address in --ns argument.\n";
|
||||
}
|
||||
}
|
||||
} ## end foreach my $pair ( @ns )
|
||||
|
||||
return;
|
||||
} ## end sub check_fake_delegation
|
||||
|
||||
sub check_fake_ds {
|
||||
my ( @ds ) = @_;
|
||||
|
||||
foreach my $str ( @ds ) {
|
||||
unless ( $str =~ /$DS_RE/ ) {
|
||||
say STDERR __(
|
||||
"--ds ds data must be in the form \"keytag,algorithm,type,digest\". E.g. space is not permitted anywhere in the string."
|
||||
);
|
||||
exit( 1 );
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sub add_fake_delegation {
|
||||
my ( $domain, @ns ) = @_;
|
||||
my @ns_with_no_ip;
|
||||
my %data;
|
||||
|
||||
foreach my $pair ( @ns ) {
|
||||
my ( $name, $ip ) = split( '/', $pair, 2 );
|
||||
|
||||
( my $errors, $name ) = normalize_name( decode( 'utf8', $name ) );
|
||||
|
||||
if ( $ip ) {
|
||||
push @{ $data{$name} }, $ip;
|
||||
}
|
||||
else {
|
||||
push @ns_with_no_ip, $name;
|
||||
}
|
||||
}
|
||||
|
||||
foreach my $ns ( @ns_with_no_ip ) {
|
||||
if ( not exists $data{$ns} ) {
|
||||
$data{$ns} = undef;
|
||||
}
|
||||
}
|
||||
|
||||
return Zonemaster::Engine->add_fake_delegation( $domain => \%data );
|
||||
|
||||
} ## end sub add_fake_delegation
|
||||
|
||||
sub add_fake_ds {
|
||||
my ( $domain, @ds ) = @_;
|
||||
my @data;
|
||||
|
||||
foreach my $str ( @ds ) {
|
||||
my ( $tag, $algo, $type, $digest ) = split( /,/, $str );
|
||||
push @data, { keytag => $tag, algorithm => $algo, type => $type, digest => $digest };
|
||||
}
|
||||
|
||||
Zonemaster::Engine->add_fake_ds( $domain => \@data );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sub print_versions {
|
||||
say 'Zonemaster-CLI version ' . __PACKAGE__->VERSION;
|
||||
say 'Zonemaster-Engine version ' . $Zonemaster::Engine::VERSION;
|
||||
say 'Zonemaster-LDNS version ' . $Zonemaster::LDNS::VERSION;
|
||||
say 'NL NetLabs LDNS version ' . Zonemaster::LDNS::lib_version();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
my @spinner_strings = ( ' | ', ' / ', ' - ', ' \\ ' );
|
||||
|
||||
sub print_spinner {
|
||||
state $counter = 0;
|
||||
state $last_spin = [ 0, 0 ];
|
||||
|
||||
my $time = [ Time::HiRes::gettimeofday() ];
|
||||
if ( Time::HiRes::tv_interval( $last_spin, $time ) > 0.1 ) {
|
||||
$last_spin = $time;
|
||||
printf "%s\r", $spinner_strings[ $counter++ % 4 ];
|
||||
}
|
||||
}
|
||||
|
||||
sub print_test_list {
|
||||
my %methods = Zonemaster::Engine->all_methods;
|
||||
my $maxlen = max map {
|
||||
map { length( $_ ) }
|
||||
@$_
|
||||
} values %methods;
|
||||
|
||||
foreach my $module ( sort keys %methods ) {
|
||||
say $module;
|
||||
foreach my $method ( sort @{ $methods{$module} } ) {
|
||||
printf " %${maxlen}s\n", $method;
|
||||
}
|
||||
print "\n";
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sub do_dump_profile {
|
||||
my $json = JSON::XS->new->canonical->pretty;
|
||||
|
||||
print $json->encode( Zonemaster::Engine::Profile->effective->{q{profile}} );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sub translate_severity {
|
||||
my $severity = shift;
|
||||
if ( $severity eq "DEBUG" ) {
|
||||
return __( "DEBUG" );
|
||||
}
|
||||
elsif ( $severity eq "INFO" ) {
|
||||
return __( "INFO" );
|
||||
}
|
||||
elsif ( $severity eq "NOTICE" ) {
|
||||
return __( "NOTICE" );
|
||||
}
|
||||
elsif ( $severity eq "WARNING" ) {
|
||||
return __( "WARNING" );
|
||||
}
|
||||
elsif ( $severity eq "ERROR" ) {
|
||||
return __( "ERROR" );
|
||||
}
|
||||
elsif ( $severity eq "CRITICAL" ) {
|
||||
return __( "CRITICAL" );
|
||||
}
|
||||
else {
|
||||
return $severity;
|
||||
}
|
||||
} ## end sub translate_severity
|
||||
|
||||
sub _max {
|
||||
my ( $a, $b ) = @_;
|
||||
$a //= 0;
|
||||
$b //= 0;
|
||||
return ( $a > $b ? $a : $b );
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Zonemaster::CLI - run Zonemaster tests from the command line
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
Vincent Levigneron <vincent.levigneron at nic.fr>
|
||||
- Current maintainer
|
||||
|
||||
Calle Dybedahl <calle at init.se>
|
||||
- Original author
|
||||
|
||||
=head1 LICENSE
|
||||
|
||||
This is free software under a 2-clause BSD license. The full text of the license can
|
||||
be found in the F<LICENSE> file included with this distribution.
|
||||
|
||||
=cut
|
||||
271
zonemaster-cli/lib/Zonemaster/CLI/TestCaseSet.pm
Normal file
271
zonemaster-cli/lib/Zonemaster/CLI/TestCaseSet.pm
Normal file
@@ -0,0 +1,271 @@
|
||||
package Zonemaster::CLI::TestCaseSet;
|
||||
use 5.014;
|
||||
use warnings;
|
||||
use utf8;
|
||||
|
||||
use Carp qw( croak );
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Zonemaster::CLI::TestCaseSet - Manage and modify Zonemaster test case selections
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use Zonemaster::CLI::TestCaseSet;
|
||||
|
||||
# Define the names of the available test modules and their test cases
|
||||
my $schema = {
|
||||
alpha => [qw( alpha01 alpha02 alpha03 )],
|
||||
beta => [qw( beta01 beta02 )],
|
||||
};
|
||||
|
||||
# Construct an initial selection of test cases
|
||||
my $selection = Zonemaster::CLI::TestCaseSet->new(
|
||||
[qw( alpha01 alpha02 alpha03 beta01 )],
|
||||
$schema,
|
||||
);
|
||||
|
||||
# Parse and apply a modifier expression
|
||||
my @modifiers = Zonemaster::CLI::TestCaseSet->parse_modifier_expr( '-alpha+alpha02' );
|
||||
while ( @modifiers ) {
|
||||
my ( $op, $term ) = splice @modifiers, 0, 2;
|
||||
$selection->apply_modifier( $op, $term )
|
||||
or die "Error: Unrecognized term '$term'.\n";
|
||||
}
|
||||
|
||||
# Output final test case selection
|
||||
print join( ' ', $selection->to_list ); # alpha02 beta01
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Zonemaster::CLI::TestCaseSet represents a mutable selection of test cases,
|
||||
together with an immutable schema defining available test modules and their
|
||||
associated test cases.
|
||||
|
||||
The schema is defined as a mapping of test module names to their associated test
|
||||
case names.
|
||||
|
||||
The selection can be adjusted using modifier expressions.
|
||||
|
||||
=head2 MODIFIER EXPRESSIONS
|
||||
|
||||
A modifier expression describes a change to the current selection.
|
||||
Expressions combine terms using operators, e.g., C<'-alpha+alpha02'>.
|
||||
|
||||
These operators are supported:
|
||||
|
||||
=over 4
|
||||
|
||||
=item C<'+'> (union)
|
||||
|
||||
Add test cases to the current selection.
|
||||
The set of test cases to add is the expansion of C<$term>.
|
||||
|
||||
=item C<'-'> (difference)
|
||||
|
||||
Remove test cases from the current selection.
|
||||
The set of test cases to remove is the expansion of C<$term>.
|
||||
|
||||
=item C<''> (replace)
|
||||
|
||||
Replace the current selection.
|
||||
The new selection is the set of test cases expanded from C<$term>.
|
||||
|
||||
=back
|
||||
|
||||
Terms expand into sets of test cases in one of three ways:
|
||||
|
||||
=over 4
|
||||
|
||||
=item C<all>
|
||||
|
||||
Expands to all available test cases defined by the schema.
|
||||
|
||||
=item Test module name
|
||||
|
||||
Expands to all test cases associated with the test module.
|
||||
|
||||
=item Test case name
|
||||
|
||||
Expands directly to the specified test case itself.
|
||||
Test cases may be specified plainly (e.g., C<Case10>) or fully qualified
|
||||
(module/testcase, e.g., C<Case/Case10>).
|
||||
|
||||
=back
|
||||
|
||||
Term matching is case-insensitive.
|
||||
|
||||
=cut
|
||||
|
||||
=head1 CONSTRUCTORS
|
||||
|
||||
=head2 new( $selection, $schema )
|
||||
|
||||
Construct a new TestCaseSet object.
|
||||
|
||||
=over 4
|
||||
|
||||
=item C<$selection> (arrayref)
|
||||
|
||||
Initial selection of test case names.
|
||||
|
||||
=item C<$schema> (hashref)
|
||||
|
||||
A hash mapping test module names to arrays of their associated test case names.
|
||||
|
||||
=back
|
||||
|
||||
Dies if:
|
||||
- Any test case name in C<$schema> is repeated.
|
||||
- C<$selection> contains names not found in C<$schema>.
|
||||
|
||||
=cut
|
||||
|
||||
sub new {
|
||||
my ( $class, $selection, $schema ) = @_;
|
||||
|
||||
my %cases = map { lc $_ => 1 } map { @{$_} } values %$schema;
|
||||
for my $case ( @$selection ) {
|
||||
if ( !exists $cases{ lc $case } ) {
|
||||
croak "Unrecognized initial test case '$case'";
|
||||
}
|
||||
}
|
||||
|
||||
my $obj = {
|
||||
_selection => { map { lc $_ => 1 } @$selection },
|
||||
_terms => _get_schema_terms( $schema ),
|
||||
};
|
||||
|
||||
bless $obj, $class;
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
=head1 CLASS METHODS
|
||||
|
||||
parse_modifier_expr( $modifier_expr )
|
||||
|
||||
Parse a string containing a modifier expression and returns a list of
|
||||
alternating operators and terms.
|
||||
|
||||
The returned list always starts with an operator.
|
||||
|
||||
For example, parsing C<'-alpha+beta02'> returns:
|
||||
|
||||
('-', 'alpha', '+', 'beta02')
|
||||
|
||||
=cut
|
||||
|
||||
sub parse_modifier_expr {
|
||||
my ( $class, $modifier_expr ) = @_;
|
||||
|
||||
my @modifiers;
|
||||
for my $op_and_term ( split /(?=[+-])/, $modifier_expr ) {
|
||||
$op_and_term =~ /([+-]?)(.*)/;
|
||||
my ( $op, $term ) = ( $1, $2 );
|
||||
|
||||
push @modifiers, ( $op, $term );
|
||||
}
|
||||
|
||||
return @modifiers;
|
||||
}
|
||||
|
||||
=head1 INSTANCE METHODS
|
||||
|
||||
=head2 apply_modifier( $operator, $term )
|
||||
|
||||
Update the selection using the given operator and term.
|
||||
|
||||
Returns true if successful, or false if the term could not be expanded based on
|
||||
the schema.
|
||||
|
||||
Dies if the operator is invalid.
|
||||
|
||||
=head3 Example:
|
||||
|
||||
$selection->apply_modifier('+', 'beta')
|
||||
or die "Unrecognized term";
|
||||
|
||||
=cut
|
||||
|
||||
sub apply_modifier {
|
||||
my ( $self, $op, $term ) = @_;
|
||||
|
||||
my $cases_ref = $self->{_terms}{ lc $term };
|
||||
|
||||
if ( !defined $cases_ref ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( $op eq '' ) {
|
||||
$self->{_selection} = {};
|
||||
$op = '+';
|
||||
}
|
||||
|
||||
if ( $op eq '-' ) {
|
||||
for my $case ( @$cases_ref ) {
|
||||
delete $self->{_selection}{$case};
|
||||
}
|
||||
}
|
||||
elsif ( $op eq '+' ) {
|
||||
for my $case ( @$cases_ref ) {
|
||||
$self->{_selection}{$case} = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
croak "Unrecognized operator '$op'";
|
||||
}
|
||||
|
||||
return 1;
|
||||
} ## end sub apply_modifier
|
||||
|
||||
=head2 to_list
|
||||
|
||||
Return a lowercase list of the currently selected test case names.
|
||||
|
||||
=cut
|
||||
|
||||
sub to_list {
|
||||
my ( $self ) = @_;
|
||||
|
||||
return sort keys %{ $self->{_selection} };
|
||||
}
|
||||
|
||||
sub _get_schema_terms {
|
||||
my ( $schema ) = @_;
|
||||
|
||||
my $terms = {};
|
||||
$terms->{all} = [];
|
||||
|
||||
for my $module ( keys %$schema ) {
|
||||
if ( lc $module eq 'all' ) {
|
||||
croak "test module name must not be 'all'";
|
||||
}
|
||||
if ( $module =~ qr{/} ) {
|
||||
croak "test module name contains forbidden character '/': '$module'";
|
||||
}
|
||||
if ( exists $terms->{ lc $module } ) {
|
||||
croak "found test module with same name as another test case or test module: '$module'";
|
||||
}
|
||||
$terms->{ lc $module } = [];
|
||||
for my $case ( @{ $schema->{$module} } ) {
|
||||
if ( lc $case eq 'all' ) {
|
||||
croak "test case name must not be 'all'";
|
||||
}
|
||||
if ( $case =~ qr{/} ) {
|
||||
croak "test case name contains forbidden character '/': '$case'";
|
||||
}
|
||||
if ( exists $terms->{ lc $case } ) {
|
||||
croak "found test case with same name as another test case or test module: '$case'";
|
||||
}
|
||||
$terms->{ lc $case } = [$case];
|
||||
$terms->{ lc "$module/$case" } = [$case];
|
||||
push @{ $terms->{ lc $module } }, $case;
|
||||
push @{ $terms->{all} }, $case;
|
||||
}
|
||||
} ## end for my $module ( keys %$schema)
|
||||
|
||||
return $terms;
|
||||
} ## end sub _get_schema_terms
|
||||
|
||||
1;
|
||||
1
zonemaster-cli/lib/auto/share/dist/Zonemaster-CLI
vendored
Symbolic link
1
zonemaster-cli/lib/auto/share/dist/Zonemaster-CLI
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../../share/
|
||||
472
zonemaster-cli/script/zonemaster-cli
Executable file
472
zonemaster-cli/script/zonemaster-cli
Executable file
@@ -0,0 +1,472 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
use 5.14.2;
|
||||
use warnings;
|
||||
|
||||
use Zonemaster::CLI;
|
||||
use File::Spec;
|
||||
use autodie;
|
||||
|
||||
sub read_conf_file {
|
||||
# Returns list of command line parameters. List can be empty.
|
||||
my ( $conf_file ) = @_;
|
||||
my @lines;
|
||||
open my $fh, '<', $conf_file;
|
||||
while ( <$fh> ) {
|
||||
chomp;
|
||||
next if /^\s*$/;
|
||||
next if /^\s*#/;
|
||||
push @lines, $_;
|
||||
}
|
||||
return @lines;
|
||||
}
|
||||
|
||||
# Load default arguments from file in home directory, if any
|
||||
# This must be loaded before any global file to make the local
|
||||
# file take precedence
|
||||
my $home_dir = ( ( getpwuid( $< ) )[7] ) || $ENV{HOME};
|
||||
my $home_conf_file = File::Spec->catfile( $home_dir, '.zonemaster', 'cli.args' );
|
||||
|
||||
if ( -r $home_conf_file ) {
|
||||
my @lines = read_conf_file( $home_conf_file );
|
||||
unshift @ARGV, @lines;
|
||||
}
|
||||
|
||||
# Load default arguments from global file, if any
|
||||
my @global_conf = ( '/etc/zonemaster/cli.args', '/usr/local/etc/zonemaster/cli.args' ); # Order is significant.
|
||||
my $global_conf_file;
|
||||
|
||||
for my $p ( @global_conf ) {
|
||||
if ( -e $p and -r $p ) {
|
||||
$global_conf_file = $p;
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
if ( defined $global_conf_file ) {
|
||||
my @lines = read_conf_file( $global_conf_file );
|
||||
unshift @ARGV, @lines;
|
||||
|
||||
}
|
||||
|
||||
eval {
|
||||
my $exitstatus = Zonemaster::CLI->run( @ARGV );
|
||||
exit $exitstatus;
|
||||
};
|
||||
|
||||
print STDERR $@;
|
||||
exit $Zonemaster::CLI::EXIT_GENERIC_ERROR;
|
||||
|
||||
=head1 NAME
|
||||
|
||||
zonemaster-cli - run Zonemaster tests from the command line
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
zonemaster-cli [--help | --version | --list-tests]
|
||||
zonemaster-cli [OPTIONS] --dump-profile
|
||||
zonemaster-cli [OPTIONS] DOMAINNAME
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
L<zonemaster-cli> is a command-line interface to the Zonemaster test engine.
|
||||
It takes instructions the user provides as command line arguments, transforms
|
||||
them into suitable API calls to the engine, runs the test suite and prints the
|
||||
resulting messages. By default, the messages will be translated by the engine's
|
||||
translation module, with the corresponding timestamp and logging level when
|
||||
printed. See the available options below.
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
=head2 Special Options
|
||||
|
||||
=over 4
|
||||
|
||||
=item B<-h>, B<--help>
|
||||
|
||||
Print brief usage information and exit.
|
||||
(run `man zonemaster-cli` for the full manual page)
|
||||
|
||||
=item B<--version>
|
||||
|
||||
Print version information and exit.
|
||||
|
||||
=for :man The printed version numbers are the versions of this program as well as the ones from the underlying
|
||||
Zonemaster test engine.
|
||||
|
||||
=item B<--list-tests>
|
||||
|
||||
Print all test cases listed in the test modules, then exit.
|
||||
|
||||
=item B<--dump-profile>
|
||||
|
||||
Print the effective profile used in JSON format, then exit.
|
||||
|
||||
=back
|
||||
|
||||
=head2 Testing Options
|
||||
|
||||
=over 4
|
||||
|
||||
=item B<--test>=EXPR
|
||||
|
||||
Specify which test cases to run by setting the C<test_cases> property in the profile.
|
||||
The EXPR is a flexible expression consisting of terms (individual test cases, test
|
||||
modules, or all) and operators (C<+> to add, C<-> to remove).
|
||||
For details, see C<man zonemaster-cli>.
|
||||
|
||||
=begin :man
|
||||
|
||||
An EXPR starting with a term (e.g., C<all>, C<nameserver01>) I<replaces>
|
||||
the current selection.
|
||||
An EXPR starting with an operator (C<+> or C<->) I<modifies> the current selection.
|
||||
An empty EXPR (C<--test=>) does not modify the selection (i.e., it is a no-op).
|
||||
|
||||
Multiple C<--test> options may be specified; they are applied in the order they are given.
|
||||
When used together with the C<--profile>, the profile option is applied first.
|
||||
|
||||
Use C<--list-tests> to list all test cases and test modules in the default profile.
|
||||
|
||||
Examples:
|
||||
|
||||
=over 4
|
||||
|
||||
=item --test=B<all>
|
||||
|
||||
selects all test cases in the default profile, i.e. overrides any custom profile.
|
||||
|
||||
=item --test=B<nameserver>
|
||||
|
||||
selects all test cases in the Nameserver test module in the default profile.
|
||||
|
||||
=item --test=B<nameserver01>
|
||||
|
||||
selects only the Nameserver01 test case.
|
||||
|
||||
=item --test=B<dnssec-dnssec05>
|
||||
|
||||
selects all DNSSEC test cases except DNSSEC05.
|
||||
|
||||
=item --test=B<all-nameserver+nameserver03>
|
||||
|
||||
selects all test cases, excludes the Nameserver test cases, and adds back
|
||||
Nameserver03.
|
||||
|
||||
=item --test=B<-dnssec>
|
||||
|
||||
removes all DNSSEC test cases from the selection.
|
||||
|
||||
=item --test=B<+syntax01+syntax02>
|
||||
|
||||
adds the Syntax01 and Syntax02 test cases to the selection.
|
||||
|
||||
=item --test=
|
||||
|
||||
empty value is valid, but does not change the selection of test cases
|
||||
Specifying C<--test=> without an argument is a no-op.
|
||||
Having this possibility may come in handy when invoking zonemaster-cli from scripts.
|
||||
|
||||
=back
|
||||
|
||||
=end :man
|
||||
|
||||
=item B<--level>=LEVEL
|
||||
|
||||
Specify the minimum level of a message to be printed.
|
||||
(default: NOTICE)
|
||||
|
||||
=for :man Messages with this level
|
||||
(or higher) will be printed. The levels are, from highest to lowest:
|
||||
CRITICAL, ERROR, WARNING, NOTICE, INFO, DEBUG, DEBUG2 and DEBUG3.
|
||||
The lowest three levels (DEBUG) add a significant amount of messages to be shown.
|
||||
They reveal some of the internal workings of the test engine, and are probably
|
||||
not useful for most users.
|
||||
|
||||
=begin :man
|
||||
|
||||
=item B<--stop-level>=LEVEL
|
||||
|
||||
Specify the minimum severity level after which the testing suite is terminated.
|
||||
(default: the empty string)
|
||||
|
||||
=for :man When set to the empty string, testing is allowed to complete normally
|
||||
no matter what messages are emitted.
|
||||
|
||||
=for :man The levels are, from highest to lowest: CRITICAL, ERROR, WARNING, NOTICE,
|
||||
INFO, DEBUG, DEBUG2 and DEBUG3.
|
||||
|
||||
=end :man
|
||||
|
||||
=item B<--[no-]progress>
|
||||
|
||||
Print an activity indicator ("spinner").
|
||||
(default: enabled if the process' standard output is a TTY)
|
||||
|
||||
=for :man Useful to know that something is happening during a run.
|
||||
|
||||
=item B<--[no-]ipv4>, B<--[no-]ipv6>
|
||||
|
||||
Enable or disable queries over IPv4 or IPv6.
|
||||
(default: both enabled)
|
||||
|
||||
=begin :man
|
||||
|
||||
=item B<--sourceaddr4>=IPADDR, B<--sourceaddr6>=IPADDR
|
||||
|
||||
Set IPv4 or IPv6 source address for DNS queries.
|
||||
|
||||
=for :man Setting an address not correctly configured on a local network interface
|
||||
fails silently.
|
||||
|
||||
=end :man
|
||||
|
||||
=item B<--profile>=FILE
|
||||
|
||||
Override the Zonemaster Engine default profile data with values from
|
||||
the given profile JSON file.
|
||||
|
||||
=back
|
||||
|
||||
=head2 Formatting Options
|
||||
|
||||
=over 4
|
||||
|
||||
=item B<--[no-]json>
|
||||
|
||||
Print results as JSON instead of human language.
|
||||
(default: disabled)
|
||||
|
||||
=begin :man
|
||||
|
||||
=item B<--[no-]json-stream>
|
||||
|
||||
Stream the results as JSON.
|
||||
(default: disabled)
|
||||
|
||||
=for :man Useful to follow the progress in a machine-readable way.
|
||||
|
||||
=item B<--[no-]raw>
|
||||
|
||||
Print messages as raw dumps (message identifiers) instead of translating them
|
||||
to human language.
|
||||
|
||||
=end :man
|
||||
|
||||
=item B<--locale>=LOCALE
|
||||
|
||||
Specify which locale to be used by the translation system.
|
||||
(default: system locale or English)
|
||||
|
||||
=for :man If not given, the
|
||||
translation system itself will look at environment variables to try and guess.
|
||||
If the requested translation does not exist, it will fall back to the local
|
||||
locale, and if that does not exist either, to English.
|
||||
|
||||
=begin :man
|
||||
|
||||
=item B<--[no-]time>
|
||||
|
||||
Print the timestamp for each message.
|
||||
(default: enabled)
|
||||
|
||||
=item B<--[no-]show-level>
|
||||
|
||||
Print the severity level for each message.
|
||||
(default: enabled)
|
||||
|
||||
=item B<--[no-]show-module>
|
||||
|
||||
Print the name of the module which produced the message.
|
||||
(default: disabled)
|
||||
|
||||
=item B<--[no-]show-testcase>
|
||||
|
||||
Print the name of the test case (test case identifier) which produced the message.
|
||||
(default: disabled)
|
||||
|
||||
=end :man
|
||||
|
||||
=back
|
||||
|
||||
=begin :man
|
||||
|
||||
=head2 Summary Options
|
||||
|
||||
=over 4
|
||||
|
||||
=item B<--[no-]count>
|
||||
|
||||
Print a summary, at the end of a run, of the numbers of messages for each severity
|
||||
level that were logged during the run, as well as a count of each message tag.
|
||||
(default: disabled)
|
||||
|
||||
=item B<--[no-]nstimes>
|
||||
|
||||
Print a summary, at the end of a run, of various metrics related to the times
|
||||
(in milliseconds) each name server took to answer, as well as a count of the
|
||||
number of sent queries per name server.
|
||||
(default: disabled)
|
||||
|
||||
=item B<--[no-]elapsed>
|
||||
|
||||
Print elapsed time (in seconds) at end of a run.
|
||||
(default: disabled)
|
||||
|
||||
=back
|
||||
|
||||
=head2 Undelegated Test Options
|
||||
|
||||
=over 4
|
||||
|
||||
=item B<--ns>=DOMAINNAME, B<--ns>=DOMAINNAME/IPADDR
|
||||
|
||||
Provide information about a nameserver, for undelegated tests.
|
||||
|
||||
=for :man The argument
|
||||
must be either: (i) a domain name and an IP address, separated by a single
|
||||
slash character (/), or (ii) only a domain name, in which case a A and AAAA
|
||||
records lookup for that name is done in the live global DNS tree (unless
|
||||
overridden by --hints) and from which the results of that lookup will be used.
|
||||
|
||||
=for :man This switch can be given multiple times. As long as any of these switches
|
||||
are present, their aggregated content will be used as the
|
||||
entirety of the parent-side delegation information.
|
||||
|
||||
=item B<--ds>=KEYTAG,ALGORITHM,TYPE,DIGEST
|
||||
|
||||
Provide a DS record for undelegated testing (that is, a test where the
|
||||
delegating nameserver information is given via --ns switches).
|
||||
|
||||
=for :man The four pieces
|
||||
of data (keytag, algorithm, type, digest) should be in the same format they would
|
||||
have in a zone file.
|
||||
|
||||
=item B<--hints>=FILE
|
||||
|
||||
Name of a root hints file to override the defaults.
|
||||
|
||||
=back
|
||||
|
||||
=head2 Cache Options
|
||||
|
||||
=over 4
|
||||
|
||||
=item B<--save>=FILE
|
||||
|
||||
Write the contents of the accumulated DNS packet cache to a file with the given name
|
||||
after the testing suite has finished running.
|
||||
|
||||
=item B<--restore>=FILE
|
||||
|
||||
Prime the DNS packet cache with the contents from the file with the given name
|
||||
before starting the testing suite.
|
||||
|
||||
=for :man The format of the file should be from one produced by the --save
|
||||
switch.
|
||||
|
||||
=back
|
||||
|
||||
=head2 Deprecated Options
|
||||
|
||||
=over 4
|
||||
|
||||
=item B<--encoding>=ENCODING
|
||||
|
||||
Deprecated: Simply remove it from your usage. It is ignored.
|
||||
|
||||
=item B<--[no-]json-translate>
|
||||
|
||||
Deprecated since v2023.1, use --no-raw instead.
|
||||
|
||||
=for :man For streaming JSON output, include the translated message of the tag.
|
||||
|
||||
=back
|
||||
|
||||
=head2 Option Aliases
|
||||
|
||||
These options are provided for compatibility with older scripts.
|
||||
The first two are aliases for C<--help>.
|
||||
The rest are aliases for their namesakes spelled with dash C<-> instead of
|
||||
underscore C<_>.
|
||||
|
||||
=over 4
|
||||
|
||||
=item B<-?>
|
||||
|
||||
=item B<--usage>
|
||||
|
||||
=item B<--dump_profile>
|
||||
|
||||
=item B<--[no-]json_stream>
|
||||
|
||||
=item B<--[no-]json_translate>
|
||||
|
||||
=item B<--list_tests>
|
||||
|
||||
=item B<--[no-]show_level>
|
||||
|
||||
=item B<--[no-]show_module>
|
||||
|
||||
=item B<--[no-]show_testcase>
|
||||
|
||||
=item B<--stop_level>=LEVEL
|
||||
|
||||
=back
|
||||
|
||||
=end :man
|
||||
|
||||
=head1 EXAMPLES
|
||||
|
||||
zonemaster-cli zonemaster.net
|
||||
|
||||
zonemaster-cli --test=delegation --level=info --no-time zonemaster.net
|
||||
|
||||
zonemaster-cli --test=delegation01 --level=debug zonemaster.net
|
||||
|
||||
zonemaster-cli --list-tests
|
||||
|
||||
=head1 PROFILES
|
||||
|
||||
The testing and result analysis performed by Zonemaster Engine is always
|
||||
guided by a profile.
|
||||
Zonemaster Engine has a default profile with sensible defaults.
|
||||
Zonemaster CLI allows users to override the default profile data with
|
||||
values from a profile JSON file with the C<--profile> option.
|
||||
For details on profiles and how they are represented in files, see
|
||||
L<Zonemaster::Engine::Profile>.
|
||||
|
||||
=head1 CONFIGURATION
|
||||
|
||||
If there is a readable file F</etc/zonemaster/cli.args> (Linux style), each line
|
||||
in that file will be prepended as an argument on the command line. If no
|
||||
F</etc/zonemaster/cli.args> is found (or is not readable) but
|
||||
F</usr/local/etc/zonemaster/cli.args> (FreeBSD style) is found and readable then
|
||||
that file will be used instead. Only one global file is loaded.
|
||||
|
||||
If there is a readable file F<.zonemaster/cli.args> in the user's home
|
||||
directory, it will be used in the same way even when a global file has been
|
||||
loaded. Any argument in user's F<cli.args> will override the same argument in the
|
||||
global config file.
|
||||
|
||||
For example, if one would like to by default run with the log
|
||||
level set to DEBUG and with translation to human-readable messages turned off,
|
||||
one could put this in the config file:
|
||||
|
||||
--raw
|
||||
--level=DEBUG
|
||||
|
||||
Only one argument per line. If the argument has a value there must be a "="
|
||||
between argument and value. A line starting with "#" is a comment. Comments
|
||||
cannot be added on lines with arguments.
|
||||
|
||||
Any arguments actually given on the command line will override what is in any of
|
||||
the loaded config files.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
More complete documentation on Zonemaster and its tests can be found on
|
||||
L<https://doc.zonemaster.net>.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Calle Dybedahl <calle@init.se> and others from the Zonemaster project
|
||||
52
zonemaster-cli/share/GNUmakefile
Normal file
52
zonemaster-cli/share/GNUmakefile
Normal file
@@ -0,0 +1,52 @@
|
||||
.POSIX:
|
||||
.SUFFIXES: .po .mo
|
||||
.PHONY: all check-msg-args dist extract-pot tidy-po show-fuzzy update-po new-po check-po
|
||||
|
||||
POFILES := $(shell find . -maxdepth 1 -type f -name '*.po' -exec basename {} \;)
|
||||
MOFILES := $(POFILES:%.po=%.mo)
|
||||
POTFILE = Zonemaster-CLI.pot
|
||||
PMFILES := $(shell find ../lib -type f -name '*.pm' | sort)
|
||||
|
||||
all: $(MOFILES)
|
||||
|
||||
# Tidy the formatting of all PO files
|
||||
tidy-po:
|
||||
@tmpdir="`mktemp -d tidy-po.XXXXXXXX`" ;\
|
||||
trap 'rm -rf "$$tmpdir"' EXIT ;\
|
||||
for f in $(POFILES) ; do msgcat $$f -o $$tmpdir/$$f && mv -f $$tmpdir/$$f $$f ; done
|
||||
|
||||
update-po: extract-pot
|
||||
@for f in $(POFILES) ; do msgmerge --update --backup=none --quiet --no-location $(MSGMERGE_OPTS) $$f $(POTFILE) ; done
|
||||
|
||||
# Create a new empty PO file with basename provided with the POLANG variable
|
||||
# Update the Language field in the header
|
||||
new-po: extract-pot
|
||||
@[ -n "$(POLANG)" ] || ( echo "Usage: make POLANG=xx new-po" && exit 1 )
|
||||
@cp $(POTFILE) $(POLANG).po
|
||||
@perl -pi -e 's/^("Project-Id-Version:) .+(\\n)/$$1 1.0.0$$2/;' \
|
||||
-e 's/^("Language-Team:) .+(\\n)/$$1 Zonemaster Team$$2/;' \
|
||||
-e 's/^"Language: /$$&$(POLANG)/;' \
|
||||
-e 's/^("Content-Type:.+charset=)CHARSET/$${1}UTF-8/;' $(POLANG).po
|
||||
@perl -ni -e 'print unless /^#( |$$)/' $(POLANG).po
|
||||
|
||||
# Check the msgid/msgstr pair for some inconsistencies between them in the
|
||||
# selected PO file and report on standard error any errors found. The PO file
|
||||
# is not updated.
|
||||
check-po:
|
||||
@for f in $(POFILES) ; do msgfmt -c $$f ; done
|
||||
|
||||
extract-pot:
|
||||
@xgettext --output $(POTFILE) --sort-by-file --add-comments --language=Perl --from-code=UTF-8 -k__ -k\$$__ -k%__ -k__x -k__n:1,2 -k__nx:1,2 -k__xn:1,2 -kN__ -kN__n:1,2 -k__p:1c,2 -k__np:1c,2,3 -kN__p:1c,2 -kN__np:1c,2,3 $(PMFILES)
|
||||
|
||||
$(POTFILE): extract-pot
|
||||
|
||||
.po.mo:
|
||||
@msgfmt -o $@ $<
|
||||
@mkdir -p locale/`basename $@ .mo`/LC_MESSAGES
|
||||
@ln -vf $@ locale/`basename $@ .mo`/LC_MESSAGES/Zonemaster-CLI.mo
|
||||
|
||||
show-fuzzy:
|
||||
@for f in $(POFILES) ; do msgattrib --only-fuzzy $$f ; done
|
||||
|
||||
check-msg-args:
|
||||
@for f in $(POFILES) ; do ../util/check-msg-args $$f ; done
|
||||
15
zonemaster-cli/share/Makefile
Normal file
15
zonemaster-cli/share/Makefile
Normal file
@@ -0,0 +1,15 @@
|
||||
# This is a wrapper for BSD Make (FreeBSD) to execute
|
||||
# GNU Make (gmake) and the primary makefile GNUmakefile.
|
||||
|
||||
GNUMAKE?= gmake
|
||||
FILES != ls *
|
||||
|
||||
# File targets should be evaluated by gmake.
|
||||
.PHONY: all $(FILES)
|
||||
|
||||
all:
|
||||
@${GNUMAKE} $@
|
||||
|
||||
.DEFAULT:
|
||||
@${GNUMAKE} $@
|
||||
|
||||
180
zonemaster-cli/share/da.po
Normal file
180
zonemaster-cli/share/da.po
Normal file
@@ -0,0 +1,180 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: 0.0.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-02-26 17:21+0100\n"
|
||||
"PO-Revision-Date: 2023-06-02 11:12+0200\n"
|
||||
"Last-Translator: haarbo@dk-hostmaster.dk\n"
|
||||
"Language-Team: Zonemaster Team\n"
|
||||
"Language: da\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: Poedit 3.3.1\n"
|
||||
|
||||
#, perl-brace-format
|
||||
msgid ""
|
||||
"Warning: setting locale category LC_MESSAGES to {locale} failed -- is it "
|
||||
"installed on this system?"
|
||||
msgstr ""
|
||||
"Advarsel: Kunne ikke sætte locale kategori LC_MESSAGES til {locale} (er det "
|
||||
"installeret på dette system?)."
|
||||
|
||||
#, perl-brace-format
|
||||
msgid ""
|
||||
"Warning: setting locale category LC_CTYPE to {locale} failed -- is it "
|
||||
"installed on this system?"
|
||||
msgstr ""
|
||||
"Advarsel: Kunne ikke sætte locale kategori LC_CTYPE til {locale} (er det "
|
||||
"installeret på dette system?)."
|
||||
|
||||
msgid "Warning: deprecated --encoding, simply remove it from your usage."
|
||||
msgstr "Advarsel: --encoding er forældet, fjern det blot fra din brug."
|
||||
|
||||
msgid "Error: --json-stream and --no-json cannot be used together."
|
||||
msgstr "Fejl: --json-stream og --no-json kan ikke bruges samtidigt."
|
||||
|
||||
msgid ""
|
||||
"Warning: --json-translate has no effect without either --json or --json-"
|
||||
"stream."
|
||||
msgstr ""
|
||||
"Advarsel: --json-translate har ingen virkning uden enten --json eller --json-"
|
||||
"stream."
|
||||
|
||||
msgid "Warning: deprecated --json-translate, use --no-raw instead."
|
||||
msgstr "Advarsel: --json-translate er forældet, brug --no-raw i stedet."
|
||||
|
||||
msgid "Warning: deprecated --no-json-translate, use --raw instead."
|
||||
msgstr "Advarsel: --no-json-translate er forældet, brug --raw i stedet."
|
||||
|
||||
#, perl-brace-format
|
||||
msgid "Loading profile from {path}."
|
||||
msgstr "Indlæser profil fra {path}."
|
||||
|
||||
#, perl-brace-format
|
||||
msgid "Error: invalid value for --sourceaddr4: {reason}"
|
||||
msgstr "Fejl: ugyldig værdi for --sourceaddr4: {reason}"
|
||||
|
||||
#, perl-brace-format
|
||||
msgid "Error: invalid value for --sourceaddr6: {reason}"
|
||||
msgstr "Fejl: ugyldig værdi for --sourceaddr6: {reason}"
|
||||
|
||||
#, perl-brace-format
|
||||
msgid ""
|
||||
"Error: Invalid input '{cli_arg}' in --test. There must be at most one slash "
|
||||
"('/') character."
|
||||
msgstr ""
|
||||
"Fejl: Ugyldigt input '{cli_arg}' i --test. Der må højst være ét skråstreg "
|
||||
"('/') tegn."
|
||||
|
||||
#, perl-brace-format
|
||||
msgid ""
|
||||
"Error: Unrecognized test case '{testcase}' in --test. Use --list-tests for a "
|
||||
"list of valid choices."
|
||||
msgstr ""
|
||||
"Fejl: Ugenkendt test-case '{testcase}' i --test. Brug --list-tests for en "
|
||||
"liste over gyldige valg."
|
||||
|
||||
#, perl-brace-format
|
||||
msgid ""
|
||||
"Error: Unrecognized test module '{module}' in --test. Use --list-tests for a "
|
||||
"list of valid choices."
|
||||
msgstr ""
|
||||
"Fejl: Ugenkendt testmodul '{module}' i --test. Brug --list-tests for en "
|
||||
"liste over gyldige valg."
|
||||
|
||||
#, perl-brace-format
|
||||
msgid "Error: Invalid input '{cli_arg}' in --test."
|
||||
msgstr "Fejl: Ugyldigt input '{cli_arg}' i --test."
|
||||
|
||||
#, perl-brace-format
|
||||
msgid ""
|
||||
"Notice: Engine does not have test case '{testcase}' enabled in the profile. "
|
||||
"Forcing..."
|
||||
msgstr ""
|
||||
"Bemærk: Motoren har ikke test-case '{testcase}' aktiveret i profilen. "
|
||||
"Tvinger..."
|
||||
|
||||
#, perl-brace-format
|
||||
msgid "Failed to recognize stop level '{level}'."
|
||||
msgstr "Kunne ikke genkende stopniveau '{level}'."
|
||||
|
||||
msgid ""
|
||||
"--level must be one of CRITICAL, ERROR, WARNING, NOTICE, INFO, DEBUG, DEBUG2 "
|
||||
"or DEBUG3."
|
||||
msgstr ""
|
||||
"--level skal være enten CRITICAL, ERROR, WARNING, NOTICE, INFO, DEBUG, "
|
||||
"DEBUG2 eller DEBUG3."
|
||||
|
||||
msgid ""
|
||||
"Only one domain can be given for testing. Did you forget to prepend an "
|
||||
"option with '--<OPTION>'?"
|
||||
msgstr ""
|
||||
"Der kan kun angives ét domæne til test. Har du glemt at sætte '--<OPTION>' "
|
||||
"foran en indstilling?"
|
||||
|
||||
msgid "Must give the name of a domain to test."
|
||||
msgstr "Domænenavn, der skal testes, skal angives."
|
||||
|
||||
#, perl-brace-format
|
||||
msgid "Error loading hints file: {message}"
|
||||
msgstr "Fejl ved indlæsning af hints-fil: {message}"
|
||||
|
||||
msgid "Seconds"
|
||||
msgstr "Sekunder"
|
||||
|
||||
msgid "Level"
|
||||
msgstr "Niveau"
|
||||
|
||||
msgid "Module"
|
||||
msgstr "Modul"
|
||||
|
||||
msgid "Testcase"
|
||||
msgstr "Testcase"
|
||||
|
||||
msgid "Message"
|
||||
msgstr "Besked"
|
||||
|
||||
msgid "Looks OK."
|
||||
msgstr "Ser OK ud."
|
||||
|
||||
msgid ""
|
||||
"\n"
|
||||
"\n"
|
||||
" Level\tNumber of log entries"
|
||||
msgstr ""
|
||||
"\n"
|
||||
"\n"
|
||||
" Niveau\tAntal logbeskeder"
|
||||
|
||||
#, perl-format
|
||||
msgid "%8s\t%5d entries.\n"
|
||||
msgstr "%8s\t%5d beskeder.\n"
|
||||
|
||||
msgid "--ns must be a name or a name/ip pair."
|
||||
msgstr "--ns skal være et navn eller et navn/IP-adresse par."
|
||||
|
||||
msgid ""
|
||||
"--ds ds data must be in the form \"keytag,algorithm,type,digest\". E.g. "
|
||||
"space is not permitted anywhere in the string."
|
||||
msgstr ""
|
||||
"--ds ds-data skal være i formatet \"keytag,algorithm,type,digest\". F.eks. "
|
||||
"er mellemrum ikke tilladt noget sted i strengen."
|
||||
|
||||
msgid "DEBUG"
|
||||
msgstr "FEJLSØG"
|
||||
|
||||
msgid "INFO"
|
||||
msgstr "INFO"
|
||||
|
||||
msgid "NOTICE"
|
||||
msgstr "NOTER"
|
||||
|
||||
msgid "WARNING"
|
||||
msgstr "ADVARSEL"
|
||||
|
||||
msgid "ERROR"
|
||||
msgstr "FEJL"
|
||||
|
||||
msgid "CRITICAL"
|
||||
msgstr "KRITISK"
|
||||
387
zonemaster-cli/share/es.po
Normal file
387
zonemaster-cli/share/es.po
Normal file
@@ -0,0 +1,387 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: 0.0.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-12-16 19:52-0300\n"
|
||||
"PO-Revision-Date: 2024-12-16 20:05-0300\n"
|
||||
"Last-Translator: hsalgado@vulcano.cl\n"
|
||||
"Language-Team: Zonemaster Team\n"
|
||||
"Language: es\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: Poedit 3.2.2\n"
|
||||
|
||||
#, perl-brace-format
|
||||
msgid ""
|
||||
"Warning: setting locale category LC_MESSAGES to {locale} failed -- is it "
|
||||
"installed on this system?"
|
||||
msgstr ""
|
||||
"Advertencia: fallo en definir la categoría de localización LC_MESSAGES como "
|
||||
"{locale} (¿está instalada en este sistema?)"
|
||||
|
||||
#, perl-brace-format
|
||||
msgid ""
|
||||
"Warning: setting locale category LC_CTYPE to {locale} failed -- is it "
|
||||
"installed on this system?"
|
||||
msgstr ""
|
||||
"Advertencia: fallo en definir la categoría de localización LC_CTYPE como "
|
||||
"{locale} (¿está instalada en este sistema?)"
|
||||
|
||||
msgid "Warning: deprecated --encoding, simply remove it from your usage."
|
||||
msgstr ""
|
||||
"Advertencia: --encoding está obsoleto, puede eliminarlo de las opciones."
|
||||
|
||||
msgid "Error: --json-stream and --no-json cannot be used together."
|
||||
msgstr "Error: --json-stream y --no-json no pueden usarse juntas."
|
||||
|
||||
msgid ""
|
||||
"Warning: --json-translate has no effect without either --json or --json-"
|
||||
"stream."
|
||||
msgstr ""
|
||||
"Advertencia: --json-translate no tiene ningún efecto sin tener además --json "
|
||||
"o --json-stream."
|
||||
|
||||
msgid "Warning: deprecated --json-translate, use --no-raw instead."
|
||||
msgstr "Advertencia: --json-translate está obsoleta, utilice mejor --no-raw."
|
||||
|
||||
msgid "Warning: deprecated --no-json-translate, use --raw instead."
|
||||
msgstr "Advertencia: --no-json-translate está obsoleta, utilice mejor --raw."
|
||||
|
||||
#, perl-brace-format
|
||||
msgid "Loading profile from {path}."
|
||||
msgstr "Cargando perfil desde {path}."
|
||||
|
||||
#, perl-brace-format
|
||||
msgid "Error: invalid value for --sourceaddr4: {reason}"
|
||||
msgstr "Error: valor inválido para --sourceaddr4: {reason}"
|
||||
|
||||
#, perl-brace-format
|
||||
msgid "Error: invalid value for --sourceaddr6: {reason}"
|
||||
msgstr "Error: valor inválido para --sourceaddr6: {reason}"
|
||||
|
||||
#, perl-brace-format
|
||||
msgid ""
|
||||
"Error: Invalid input '{cli_arg}' in --test. There must be at most one slash "
|
||||
"('/') character."
|
||||
msgstr ""
|
||||
"Error: entrada inválida '{cli_arg}' en --test. Debe haber al menos una barra "
|
||||
"diagonal ('/')."
|
||||
|
||||
#, perl-brace-format
|
||||
msgid ""
|
||||
"Error: Unrecognized test case '{testcase}' in --test. Use --list-tests for a "
|
||||
"list of valid choices."
|
||||
msgstr ""
|
||||
"Error: caso de prueba no reconocido '{testcase}' en --test. Use --list-tests "
|
||||
"para una lista de las alternativas válidas."
|
||||
|
||||
#, perl-brace-format
|
||||
msgid ""
|
||||
"Error: Unrecognized test module '{module}' in --test. Use --list-tests for a "
|
||||
"list of valid choices."
|
||||
msgstr ""
|
||||
"Error: módulo de prueba no reconocido '{module}' en --test. Use --list-tests "
|
||||
"para una lista de las alternativas válidas."
|
||||
|
||||
#, perl-brace-format
|
||||
msgid "Error: Invalid input '{cli_arg}' in --test."
|
||||
msgstr "Error: entrada inválida '{cli_arg}' en --test."
|
||||
|
||||
#, perl-brace-format
|
||||
msgid ""
|
||||
"Notice: Engine does not have test case '{testcase}' enabled in the profile. "
|
||||
"Forcing..."
|
||||
msgstr ""
|
||||
"Aviso: El motor no tiene el caso de prueba '{testcase}' habilitado en el "
|
||||
"perfil. Forzando..."
|
||||
|
||||
#, perl-brace-format
|
||||
msgid "Failed to recognize stop level '{level}'."
|
||||
msgstr "Fallo en identificar el nivel de detención '{level}'."
|
||||
|
||||
msgid ""
|
||||
"--level must be one of CRITICAL, ERROR, WARNING, NOTICE, INFO, DEBUG, DEBUG2 "
|
||||
"or DEBUG3."
|
||||
msgstr ""
|
||||
"--level debe ser alguno entre CRITICAL, ERROR, WARNING, NOTICE, INFO, DEBUG, "
|
||||
"DEBUG2 o DEBUG3."
|
||||
|
||||
msgid ""
|
||||
"Only one domain can be given for testing. Did you forget to prepend an "
|
||||
"option with '--<OPTION>'?"
|
||||
msgstr ""
|
||||
"Solo puede indicarse 1 dominio para las pruebas. ¿Quizás incluyó una opción "
|
||||
"y olvidó el prefijo '--<OPCIÓN>'?"
|
||||
|
||||
msgid "Must give the name of a domain to test."
|
||||
msgstr "Debe indicar el nombre de un dominio a probar."
|
||||
|
||||
#, perl-brace-format
|
||||
msgid "Error loading hints file: {message}"
|
||||
msgstr "Error al cargar el archivo 'hints': {message}"
|
||||
|
||||
msgid "Seconds"
|
||||
msgstr "Segundos"
|
||||
|
||||
msgid "Level"
|
||||
msgstr "Nivel"
|
||||
|
||||
msgid "Module"
|
||||
msgstr "Módulo"
|
||||
|
||||
msgid "Testcase"
|
||||
msgstr "Caso de prueba"
|
||||
|
||||
msgid "Message"
|
||||
msgstr "Mensaje"
|
||||
|
||||
msgid "Looks OK."
|
||||
msgstr "Se ve bien."
|
||||
|
||||
msgid ""
|
||||
"\n"
|
||||
"\n"
|
||||
" Level\tNumber of log entries"
|
||||
msgstr ""
|
||||
"\n"
|
||||
"\n"
|
||||
" Nivel\tNúmero de registros"
|
||||
|
||||
#, perl-format
|
||||
msgid "%8s\t%5d entries.\n"
|
||||
msgstr "%8s\t%5d registros.\n"
|
||||
|
||||
msgid "--ns must be a name or a name/ip pair."
|
||||
msgstr "--ns debe ser un nombre o un par nombre/ip."
|
||||
|
||||
msgid ""
|
||||
"--ds ds data must be in the form \"keytag,algorithm,type,digest\". E.g. "
|
||||
"space is not permitted anywhere in the string."
|
||||
msgstr ""
|
||||
"--ds los datos para DS deben estar en el formato \"keytag,algoritmo,tipo,"
|
||||
"digest\". No se permiten espacios dentro del valor."
|
||||
|
||||
msgid "DEBUG"
|
||||
msgstr "DEPURACIÓN"
|
||||
|
||||
msgid "INFO"
|
||||
msgstr "INFO"
|
||||
|
||||
msgid "NOTICE"
|
||||
msgstr "AVISO"
|
||||
|
||||
msgid "WARNING"
|
||||
msgstr "ADVERTENCIA"
|
||||
|
||||
msgid "ERROR"
|
||||
msgstr "ERROR"
|
||||
|
||||
msgid "CRITICAL"
|
||||
msgstr "CRÍTICO"
|
||||
|
||||
#~ msgid "Print version information and exit."
|
||||
#~ msgstr "Despliega información de la versión y termina."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "The minimum severity level to display. Must be one of CRITICAL, ERROR, "
|
||||
#~ "WARNING, NOTICE, INFO or DEBUG."
|
||||
#~ msgstr ""
|
||||
#~ "El nivel de severidad mínimo para mostrar. Debe ser alguno entre "
|
||||
#~ "CRITICAL, ERROR, WARNING, NOTICE, INFO o DEBUG."
|
||||
|
||||
#~ msgid "The locale to use for messages translation."
|
||||
#~ msgstr "Localización (locale) para la traducción de los mensajes."
|
||||
|
||||
#~ msgid "Flag indicating if output should be in JSON or not."
|
||||
#~ msgstr "Opción que indica si la salida será en JSON o no."
|
||||
|
||||
#~ msgid "Flag indicating if output should be streaming JSON or not."
|
||||
#~ msgstr ""
|
||||
#~ "Opción que indica si la salida debiera ser transmisión de JSON o no."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Deprecated. Flag indicating if JSON output should include the translated "
|
||||
#~ "message of the tag or not."
|
||||
#~ msgstr ""
|
||||
#~ "Obsoleta. Opción que indica si la salida de transmisión de JSON debiera "
|
||||
#~ "incluir el mensaje traducido del tag o no."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Flag indicating if output should be translated to human language or "
|
||||
#~ "dumped raw."
|
||||
#~ msgstr ""
|
||||
#~ "Opción que indica si la salida se traducirá a idioma humano o en formato "
|
||||
#~ "crudo."
|
||||
|
||||
#~ msgid "Print timestamp on entries."
|
||||
#~ msgstr "Despliega marcas de tiempo en los registros."
|
||||
|
||||
#~ msgid "Print level on entries."
|
||||
#~ msgstr "Despliega el nivel en los registros."
|
||||
|
||||
#~ msgid "Print the name of the module on entries."
|
||||
#~ msgstr "Despliega el nombre del módulo en los registros."
|
||||
|
||||
#~ msgid "Print the name of the test case on entries."
|
||||
#~ msgstr "Despliega el nombre del caso de prueba en los registros."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "A name/ip string giving a nameserver for undelegated tests, or just a "
|
||||
#~ "name which will be looked up for IP addresses. Can be given multiple "
|
||||
#~ "times."
|
||||
#~ msgstr ""
|
||||
#~ "Una etiqueta nombre/IP para el servidor de nombres en las pruebas no-"
|
||||
#~ "delegadas, o solo un nombre que será resuelto para buscar la dirección "
|
||||
#~ "IP. Puede repetirse varias veces."
|
||||
|
||||
#~ msgid "Name of a root hints file to override the defaults."
|
||||
#~ msgstr ""
|
||||
#~ "Nombre del archivo 'root hints' para reemplazar los valores por defecto."
|
||||
|
||||
#~ msgid "Name of a file to save DNS data to after running tests."
|
||||
#~ msgstr ""
|
||||
#~ "Nombre de un archivo para guardar los datos DNS después de ejecutar las "
|
||||
#~ "pruebas."
|
||||
|
||||
#~ msgid "Name of a file to restore DNS data from before running test."
|
||||
#~ msgstr ""
|
||||
#~ "Nombre de un archivo para recuperar los datos DNS antes de ejecutar la "
|
||||
#~ "prueba."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Flag to permit or deny queries being sent via IPv4. --ipv4 permits IPv4 "
|
||||
#~ "traffic, --no-ipv4 forbids it."
|
||||
#~ msgstr ""
|
||||
#~ "Opción para permitir o prohibir el envío de consultas vía IPv4. --ipv4 "
|
||||
#~ "autoriza el tráfico IPv4, --no-ipv4 lo prohíbe."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Flag to permit or deny queries being sent via IPv6. --ipv6 permits IPv6 "
|
||||
#~ "traffic, --no-ipv6 forbids it."
|
||||
#~ msgstr ""
|
||||
#~ "Opción para permitir o prohibir el envío de consultas vía IPv6. --ipv6 "
|
||||
#~ "autoriza el tráfico IPv6, --no-ipv6 lo prohíbe."
|
||||
|
||||
#~ msgid "Instead of running a test, list all available tests."
|
||||
#~ msgstr ""
|
||||
#~ "En vez de ejecutar una prueba, despliega todas las pruebas disponibles."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Specify test to run. Should be either the name of a module, or the name "
|
||||
#~ "of a module and the name of a method in that module separated by a \"/\" "
|
||||
#~ "character (Example: \"Basic/basic1\"). The method specified must be one "
|
||||
#~ "that takes a zone object as its single argument. This switch can be "
|
||||
#~ "repeated."
|
||||
#~ msgstr ""
|
||||
#~ "Indica la prueba a ejecutar. Debe ser el nombre de un módulo, o el nombre "
|
||||
#~ "de un módulo y el nombre de un método de ese módulo separado por el "
|
||||
#~ "caracter \"/\" (por ejemplo: \"Basic/basic1\"). El método especificado "
|
||||
#~ "debe ser uno que recibe un objecto de zona como su único argumento. Esta "
|
||||
#~ "opción puede repetirse."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "As soon as a message at this level or higher is logged, execution will "
|
||||
#~ "stop. Must be one of CRITICAL, ERROR, WARNING, NOTICE, INFO or DEBUG."
|
||||
#~ msgstr ""
|
||||
#~ "Tan pronto como se registra un mensaje en este nivel o uno superior, la "
|
||||
#~ "ejecución se detendrá. Debe ser alguno entre CRITICAL, ERROR, WARNING, "
|
||||
#~ "NOTICE, INFO o DEBUG."
|
||||
|
||||
#~ msgid "Name of profile file to load. (DEFAULT)"
|
||||
#~ msgstr "Nombre del archivo de perfiles a cargar. (DEFAULT)"
|
||||
|
||||
#~ msgid "Strings with DS data on the form \"keytag,algorithm,type,digest\""
|
||||
#~ msgstr ""
|
||||
#~ "Etiquetas con los datos DS en la forma \"tag,algoritmo,tipo,"
|
||||
#~ "resumen\" (\"keytag,algorithm,type,digest\")"
|
||||
|
||||
#~ msgid "Print a count of the number of messages at each level"
|
||||
#~ msgstr "Despliega un contador de la cantidad de mensajes en cada nivel"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Boolean flag for activity indicator. Defaults to on if STDOUT is a tty, "
|
||||
#~ "off if it is not. Disable with --no-progress."
|
||||
#~ msgstr ""
|
||||
#~ "Opción booleana para el indicador de actividad. El predeterminado es "
|
||||
#~ "encendido si la salida estándar (STDOUT) es un terminal, apagado si no lo "
|
||||
#~ "es. Se puede deshabilitar con --no-progress."
|
||||
|
||||
#~ msgid "Name of the character encoding used for command line arguments"
|
||||
#~ msgstr ""
|
||||
#~ "Nombre de la codificación de caracteres (\"encoding\") que se usa para "
|
||||
#~ "los argumentos en la línea de comandos"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "At the end of a run, print a summary of the times (in milliseconds) the "
|
||||
#~ "zone's name servers took to answer."
|
||||
#~ msgstr ""
|
||||
#~ "Al finalizar una ejecución, despliega un resumen del tiempo (en "
|
||||
#~ "milisegundos) que le tomó responder a los servidores de nombre de la zona."
|
||||
|
||||
#~ msgid "Print the effective profile used in JSON format, then exit."
|
||||
#~ msgstr ""
|
||||
#~ "Despliega el perfil definitivo usado en formato JSON, luego termina."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Deprecated (planned removal: v2024.1). Use --sourceaddr4 and/or --"
|
||||
#~ "sourceaddr6. Source IP address used to send queries. Setting an IP "
|
||||
#~ "address not correctly configured on a local network interface causes "
|
||||
#~ "cryptic error messages."
|
||||
#~ msgstr ""
|
||||
#~ "Obsoleta (eliminación planificada para v2024.1). Use --sourceaddr4 y/o .."
|
||||
#~ "sourceaddr6. Dirección IP de origen usada para enviar las consultas. "
|
||||
#~ "Indicar una dirección IP que no esté correctamente configurada en una "
|
||||
#~ "interfaz de red local puede causar mensajes de error confusos."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Source IPv4 address used to send queries. Setting an IPv4 address not "
|
||||
#~ "correctly configured on a local network interface fails silently. Can not "
|
||||
#~ "be combined with --sourceaddr."
|
||||
#~ msgstr ""
|
||||
#~ "Dirección IPv4 de origen usada para enviar las consultas. Indicar una "
|
||||
#~ "dirección IPv4 que no esté correctamente configurada en una interfaz de "
|
||||
#~ "red local fallará silenciosamente. No puede usarse en combinación con --"
|
||||
#~ "sourceaddr."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Source IPv6 address used to send queries. Setting an IPv6 address not "
|
||||
#~ "correctly configured on a local network interface fails silently. Can not "
|
||||
#~ "be combined with --sourceaddr."
|
||||
#~ msgstr ""
|
||||
#~ "Dirección IPv6 de origen usada para enviar las consultas. Indicar una "
|
||||
#~ "dirección IPv6 que no esté correctamente configurada en una interfaz de "
|
||||
#~ "red local fallará silenciosamente. No puede usarse en combinación con --"
|
||||
#~ "sourceaddr."
|
||||
|
||||
#~ msgid "Print elapsed time (in seconds) at end of run."
|
||||
#~ msgstr ""
|
||||
#~ "Imprime el tiempo transcurrido (en segundos) al finalizar la ejecución."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Error: --sourceaddr can't be combined with --sourceaddr4 or --sourceaddr6."
|
||||
#~ msgstr ""
|
||||
#~ "Error: --sourceaddr no puede usarse al mismo tiempo que --sourceaddr4 o --"
|
||||
#~ "sourceaddr6."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Warning: --sourceaddr is deprecated (planned removal: v2024.1). Use --"
|
||||
#~ "sourceaddr4 and/or --sourceaddr6 instead."
|
||||
#~ msgstr ""
|
||||
#~ "Advertencia: --sourceaddr está obsoleta (eliminación planificada para "
|
||||
#~ "v2024.1). Utilice mejor --sourceaddr4 y/o --sourceaddr6."
|
||||
|
||||
#~ msgid "The domain name contains consecutive dots.\n"
|
||||
#~ msgstr "El nombre de dominio contiene puntos consecutivos.\n"
|
||||
|
||||
#, perl-brace-format
|
||||
#~ msgid "The name of the nameserver '{nsname}' contains consecutive dots."
|
||||
#~ msgstr ""
|
||||
#~ "El nombre del servidor de nombres '{nsname}' contiene puntos consecutivos."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Warning: Zonemaster::LDNS not compiled with IDN support, cannot handle "
|
||||
#~ "non-ASCII names correctly."
|
||||
#~ msgstr ""
|
||||
#~ "Advertencia: Zonemaster::LDNS no fue compilado con soporte IDN, no puede "
|
||||
#~ "manejar correctamente nombres no-ASCII."
|
||||
316
zonemaster-cli/share/fi.po
Normal file
316
zonemaster-cli/share/fi.po
Normal file
@@ -0,0 +1,316 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: 0.0.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2023-05-23 13:09+0000\n"
|
||||
"PO-Revision-Date: 2023-05-22 16:12+0300\n"
|
||||
"Last-Translator: sami.salmensuo@traficom.fi\n"
|
||||
"Language-Team: Traficom domain team\n"
|
||||
"Language: fi\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: Poedit 3.2.2\n"
|
||||
|
||||
msgid "Print version information and exit."
|
||||
msgstr "Tulosta versiotiedot ja poistu."
|
||||
|
||||
msgid ""
|
||||
"The minimum severity level to display. Must be one of CRITICAL, ERROR, "
|
||||
"WARNING, NOTICE, INFO or DEBUG."
|
||||
msgstr ""
|
||||
"Näytettävä minimivakavuusaste. Sen on oltava yksi näistä: CRITICAL "
|
||||
"(kriittinen), ERROR (virhe), WARNING (varoitus), NOTICE (huomio), INFO "
|
||||
"(info) tai DEBUG (virheenkorjaus)."
|
||||
|
||||
msgid "The locale to use for messages translation."
|
||||
msgstr "Viestien kääntämisessä käytettävä lokaali."
|
||||
|
||||
msgid "Flag indicating if output should be in JSON or not."
|
||||
msgstr "Lippu, joka ilmoittaa pitääkö tulosteen olla JSON-muodossa vai ei."
|
||||
|
||||
msgid "Flag indicating if output should be streaming JSON or not."
|
||||
msgstr ""
|
||||
"Lippu, joka ilmoittaa pitääkö tulosteen olla suoratoistettavassa JSON-"
|
||||
"muodossa vai ei."
|
||||
|
||||
msgid ""
|
||||
"Deprecated. Flag indicating if JSON output should include the translated "
|
||||
"message of the tag or not."
|
||||
msgstr ""
|
||||
"Käytöstä poistettu. Lippu joka ilmaisee pitäisikö JSON-tulostuksen sisältää "
|
||||
"tagin käännetty viesti vai ei."
|
||||
|
||||
msgid ""
|
||||
"Flag indicating if output should be translated to human language or dumped "
|
||||
"raw."
|
||||
msgstr ""
|
||||
"Lippu, joka ilmoittaa pitääkö tuloste kääntää ihmiskielelle vai annetaanko "
|
||||
"se raakamuodossa."
|
||||
|
||||
msgid "Print timestamp on entries."
|
||||
msgstr "Tulosta merkintöihin aikaleima."
|
||||
|
||||
msgid "Print level on entries."
|
||||
msgstr "Tulosta merkintöihin taso."
|
||||
|
||||
msgid "Print the name of the module on entries."
|
||||
msgstr "Tulosta merkintöihin moduulin nimi."
|
||||
|
||||
msgid "Print the name of the test case on entries."
|
||||
msgstr "Tulosta merkintöihin testitapauksen nimi."
|
||||
|
||||
msgid ""
|
||||
"A name/ip string giving a nameserver for undelegated tests, or just a name "
|
||||
"which will be looked up for IP addresses. Can be given multiple times."
|
||||
msgstr ""
|
||||
"Nimi/IP-merkkijono, joka antaa nimipalvelimen testeille, joita ei ole "
|
||||
"delegoitu, tai pelkkä nimi, jolla haetaan IP-osoitteita. Voidaan antaa "
|
||||
"useita kertoja."
|
||||
|
||||
msgid "Name of a root hints file to override the defaults."
|
||||
msgstr "'Root hints' tiedoston nimi jolla ohitetaan oletusasetukset."
|
||||
|
||||
msgid "Name of a file to save DNS data to after running tests."
|
||||
msgstr ""
|
||||
"Sen tiedoston nimi, johon DNS-tiedot tallennetaan testien ajamisen jälkeen."
|
||||
|
||||
msgid "Name of a file to restore DNS data from before running test."
|
||||
msgstr ""
|
||||
"Sen tiedoston nimi, josta testiä edeltävät DNS-tiedot voidaan palauttaa."
|
||||
|
||||
msgid ""
|
||||
"Flag to permit or deny queries being sent via IPv4. --ipv4 permits IPv4 "
|
||||
"traffic, --no-ipv4 forbids it."
|
||||
msgstr ""
|
||||
"Lippu, joka sallii tai kieltää IPv4:n kautta lähetetyt kyselyt. --ipv4 "
|
||||
"sallii IPv4-liikenteen, --no-ipv4 kieltää sen."
|
||||
|
||||
msgid ""
|
||||
"Flag to permit or deny queries being sent via IPv6. --ipv6 permits IPv6 "
|
||||
"traffic, --no-ipv6 forbids it."
|
||||
msgstr ""
|
||||
"Lippu, joka sallii tai kieltää IPv6:n kautta lähetetyt kyselyt. --ipv6 "
|
||||
"sallii IPv6-liikenteen, --no-ipv6 kieltää sen."
|
||||
|
||||
msgid "Instead of running a test, list all available tests."
|
||||
msgstr "Listaa kaikki käytettävissä olevat testit testin ajamisen sijasta."
|
||||
|
||||
msgid ""
|
||||
"Specify test to run. Should be either the name of a module, or the name of a "
|
||||
"module and the name of a method in that module separated by a \"/\" "
|
||||
"character (Example: \"Basic/basic1\"). The method specified must be one that "
|
||||
"takes a zone object as its single argument. This switch can be repeated."
|
||||
msgstr ""
|
||||
"Määritä ajettava testi. Sen tulisi olla joko moduulin nimi tai moduulin nimi "
|
||||
"ja moduulissa olevan metodin nimi erotettuna ”/”-merkillä (esimerkki: "
|
||||
"\"Basic/basic1\"). Määritetyn metodin on otettava ainoaksi parametrikseen "
|
||||
"vyöhykeobjekti. Tämä vaihto voidaan toistaa."
|
||||
|
||||
msgid ""
|
||||
"As soon as a message at this level or higher is logged, execution will stop. "
|
||||
"Must be one of CRITICAL, ERROR, WARNING, NOTICE, INFO or DEBUG."
|
||||
msgstr ""
|
||||
"Heti kun lokiin kirjataan tämän tasoinen tai tätä korkeamman tasoinen "
|
||||
"viesti, suoritus lakkaa. Sen on oltava yksi näistä: CRITICAL (kriittinen), "
|
||||
"ERROR (virhe), WARNING (varoitus), NOTICE (huomio), INFO (info) tai DEBUG "
|
||||
"(virheenkorjaus)."
|
||||
|
||||
msgid "Name of profile file to load. (DEFAULT)"
|
||||
msgstr "Ladattavan profiilitiedoston nimi. (DEFAULT (oletus))"
|
||||
|
||||
msgid "Strings with DS data on the form \"keytag,algorithm,type,digest\""
|
||||
msgstr ""
|
||||
"Merkkijonot, jotka sisältävät DS-tietoja muodossa \"keytag,algorithm,type,"
|
||||
"digest” (avaintunniste, algoritmi, tyyppi, tiiviste)"
|
||||
|
||||
msgid "Print a count of the number of messages at each level"
|
||||
msgstr "Tulosta viestien lukumäärä kullakin tasolla"
|
||||
|
||||
msgid ""
|
||||
"Boolean flag for activity indicator. Defaults to on if STDOUT is a tty, off "
|
||||
"if it is not. Disable with --no-progress."
|
||||
msgstr ""
|
||||
"Looginen lippu toiminnan merkitsemiseen. Oletusarvoisesti päällä, jos STDOUT "
|
||||
"on tty, muussa tapauksessa poissa päältä. Poistetaan käytöstä parametrilla --"
|
||||
"no-progress."
|
||||
|
||||
msgid "Name of the character encoding used for command line arguments"
|
||||
msgstr "Komentorivin parametreissä käytetty merkistökoodaus"
|
||||
|
||||
msgid ""
|
||||
"At the end of a run, print a summary of the times (in milliseconds) the "
|
||||
"zone's name servers took to answer."
|
||||
msgstr ""
|
||||
"Tulosta ajon lopussa yhteenveto ajasta (millisekunteina), joka vyöhykkeen "
|
||||
"nimipalvelimilla kesti vastata."
|
||||
|
||||
msgid "Print the effective profile used in JSON format, then exit."
|
||||
msgstr "Tulosta käytössä oleva profiili JSON-muodossa ja poistu."
|
||||
|
||||
msgid ""
|
||||
"Deprecated (planned removal: v2024.1). Use --sourceaddr4 and/or --"
|
||||
"sourceaddr6. Source IP address used to send queries. Setting an IP address "
|
||||
"not correctly configured on a local network interface causes cryptic error "
|
||||
"messages."
|
||||
msgstr ""
|
||||
"Käytöstä poistettu (suunniteltu poisto v2024.1) Kyselyjen lähettämiseen "
|
||||
"käytetty IP-lähdeosoite. IP-osoitetta ei ole määritetty oikein määriteltynä "
|
||||
"paikalliseen verkkoliitäntään aiheuttaa poikkeuksellisia virheitä."
|
||||
|
||||
msgid ""
|
||||
"Source IPv4 address used to send queries. Setting an IPv4 address not "
|
||||
"correctly configured on a local network interface fails silently. Can not be "
|
||||
"combined with --sourceaddr."
|
||||
msgstr ""
|
||||
"Lähde IPv4-osoite jota käytetään kyselyjen lähettämiseen. IPv4-osoitteen "
|
||||
"määrittäminen jota ei ole määritetty oikein paikalliseen verkkoliitäntään, "
|
||||
"epäonnistuu äänettömästi. Ei voida yhdistää --sourceaddr kanssa."
|
||||
|
||||
msgid ""
|
||||
"Source IPv6 address used to send queries. Setting an IPv6 address not "
|
||||
"correctly configured on a local network interface fails silently. Can not be "
|
||||
"combined with --sourceaddr."
|
||||
msgstr ""
|
||||
"Lähde IPv6-osoite, jota käytetään kyselyjen lähettämiseen. IPv6-osoitteen "
|
||||
"määrittäminen, jota ei ole määritetty oikein paikalliseen verkkoliitäntään, "
|
||||
"epäonnistuu äänettömästi. Ei voida yhdistää --sourceaddr kanssa ."
|
||||
|
||||
msgid "Print elapsed time (in seconds) at end of run."
|
||||
msgstr "Tulosta kulunut aika (sekunteina) ajon lopussa."
|
||||
|
||||
#, perl-format
|
||||
msgid ""
|
||||
"Warning: setting locale category LC_MESSAGES to %s failed (is it installed "
|
||||
"on this system?)."
|
||||
msgstr ""
|
||||
"Varoitus: arvoa %s ei voitu asettaa lokaalikategorian LC_MESSAGES arvoksi "
|
||||
"(onko sitä asennettu tähän järjestelmään?)."
|
||||
|
||||
#, perl-format
|
||||
msgid ""
|
||||
"Warning: setting locale category LC_CTYPE to %s failed (is it installed on "
|
||||
"this system?)."
|
||||
msgstr ""
|
||||
"Varoitus: arvoa %s ei voitu asettaa lokaalikategorian LC_CTYPE arvoksi (onko "
|
||||
"sitä asennettu tähän järjestelmään?)."
|
||||
|
||||
msgid ""
|
||||
"Error: --sourceaddr can't be combined with --sourceaddr4 or --sourceaddr6."
|
||||
msgstr ""
|
||||
"Virhe: --sourceaddr ei voi yhdistää --sourceaddr4:n tai --sourceaddr6:n "
|
||||
"kanssa."
|
||||
|
||||
msgid ""
|
||||
"Warning: --sourceaddr is deprecated (planned removal: v2024.1). Use --"
|
||||
"sourceaddr4 and/or --sourceaddr6 instead."
|
||||
msgstr ""
|
||||
"Varoitus: --sourceaddr on vanhentunut (suunniteltu poisto: v2024.1). Käytä "
|
||||
"sen sijaan --sourceaddr4 ja/tai --sourceaddr6."
|
||||
|
||||
msgid "Error: --json-stream and --no-json can't be used together."
|
||||
msgstr "Virhe: --json-streamia ja --no-jsonia ei voida käyttää yhdessä."
|
||||
|
||||
msgid ""
|
||||
"Warning: --json-translate has no effect without either --json or --json-"
|
||||
"stream."
|
||||
msgstr ""
|
||||
"Varoitus: --json-translatella ei ole vaikutusta ilman --json- tai --json-"
|
||||
"streamia."
|
||||
|
||||
msgid "Warning: deprecated --json-translate, use --no-raw instead."
|
||||
msgstr "Varoitus: vanhentunut --json-translate, käytä sen sijaan --no-raw."
|
||||
|
||||
msgid "Warning: deprecated --no-json-translate, use --raw instead."
|
||||
msgstr "Varoitus: vanhentunut --no-json-translate, käytä sen sijaan --raw:ta."
|
||||
|
||||
#, perl-brace-format
|
||||
msgid "Loading profile from {path}."
|
||||
msgstr "Ladataan profiili kohteesta {path}."
|
||||
|
||||
msgid "Failed to recognize stop level '"
|
||||
msgstr "Ei tunnistettu lopetustasoa '"
|
||||
|
||||
msgid ""
|
||||
"--level must be one of CRITICAL, ERROR, WARNING, NOTICE, INFO, DEBUG, DEBUG2 "
|
||||
"or DEBUG3.\n"
|
||||
msgstr ""
|
||||
"--level (taso) täytyy olla yksi seuraavista: CRITICAL (kriittinen), ERROR "
|
||||
"(virhe), WARNING (varoitus), NOTICE (huomautus), INFO (tiedotus), DEBUG "
|
||||
"(virheenkorjaus), DEBUG2 (virheenkorjaus2) tai DEBUG3 (virheenkorjaus3).\n"
|
||||
|
||||
msgid "Seconds"
|
||||
msgstr "Sekuntia"
|
||||
|
||||
msgid "Level"
|
||||
msgstr "Taso"
|
||||
|
||||
msgid "Module"
|
||||
msgstr "Moduuli"
|
||||
|
||||
msgid "Testcase"
|
||||
msgstr "Testitapaus"
|
||||
|
||||
msgid "Message"
|
||||
msgstr "Viesti"
|
||||
|
||||
msgid ""
|
||||
"Only one domain can be given for testing. Did you forget to prepend an "
|
||||
"option with '--<OPTION>'?\n"
|
||||
msgstr ""
|
||||
"Vain yksi verkkotunnus voidaan antaa testattavaksi kerrallaan. Unohditko "
|
||||
"lisätä määrityksen eteen '--<OPTION>'?\n"
|
||||
|
||||
msgid "Must give the name of a domain to test.\n"
|
||||
msgstr "Testattavan verkkoalueen nimi on annettava.\n"
|
||||
|
||||
msgid "The domain name contains consecutive dots.\n"
|
||||
msgstr "Verkkotunnus sisältää peräkkäisiä pisteitä.\n"
|
||||
|
||||
msgid "Looks OK."
|
||||
msgstr "Näyttää olevan OK."
|
||||
|
||||
msgid ""
|
||||
"\n"
|
||||
"\n"
|
||||
" Level\tNumber of log entries"
|
||||
msgstr ""
|
||||
"\n"
|
||||
"\n"
|
||||
" Taso\tLokimerkintöjen lukumäärä"
|
||||
|
||||
#, perl-format
|
||||
msgid "%8s\t%5d entries.\n"
|
||||
msgstr "%8s\t%5d merkintää.\n"
|
||||
|
||||
msgid "--ns must be a name or a name/ip pair."
|
||||
msgstr "--ns:n on oltava nimi tai nimi/ip-pari."
|
||||
|
||||
#, perl-brace-format
|
||||
msgid "The name of the nameserver '{nsname}' contains consecutive dots."
|
||||
msgstr "Nimipalvelimen nimi \"{nsname}\" sisältää peräkkäisiä pisteitä."
|
||||
|
||||
msgid ""
|
||||
"Warning: Zonemaster::LDNS not compiled with IDN support, cannot handle non-"
|
||||
"ASCII names correctly."
|
||||
msgstr ""
|
||||
"Varoitus: Zonemaster::LDNS ei ole käännetty IDN tuella, joten se ei pysty "
|
||||
"käsittelemään Ei ASCII-muodossa olevia nimiä oikein."
|
||||
|
||||
msgid "DEBUG"
|
||||
msgstr "DEBUG"
|
||||
|
||||
msgid "INFO"
|
||||
msgstr "INFO"
|
||||
|
||||
msgid "NOTICE"
|
||||
msgstr "NOTICE"
|
||||
|
||||
msgid "WARNING"
|
||||
msgstr "WARNING"
|
||||
|
||||
msgid "ERROR"
|
||||
msgstr "ERROR"
|
||||
|
||||
msgid "CRITICAL"
|
||||
msgstr "CRITICAL"
|
||||
165
zonemaster-cli/share/fr.po
Normal file
165
zonemaster-cli/share/fr.po
Normal file
@@ -0,0 +1,165 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: 0.0.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-06-24 13:54+0200\n"
|
||||
"PO-Revision-Date: 2025-06-24 14:00+0200\n"
|
||||
"Last-Translator: thomas.green@afnic.fr\n"
|
||||
"Language-Team: Zonemaster Team\n"
|
||||
"Language: fr\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: Poedit 3.6\n"
|
||||
|
||||
#, perl-brace-format
|
||||
msgid ""
|
||||
"Warning: setting locale category LC_MESSAGES to {locale} failed -- is it "
|
||||
"installed on this system?"
|
||||
msgstr ""
|
||||
"Attention : positionner la catégorie de localisation LC_MESSAGES pour "
|
||||
"{locale} a échoué -- est-elle installée sur ce système ?"
|
||||
|
||||
#, perl-brace-format
|
||||
msgid ""
|
||||
"Warning: setting locale category LC_CTYPE to {locale} failed -- is it "
|
||||
"installed on this system?"
|
||||
msgstr ""
|
||||
"Attention : positionner la catégorie de localisation LC_TYPE pour {locale} a "
|
||||
"échoué -- est-elle installée sur ce système ?"
|
||||
|
||||
msgid "Warning: deprecated --encoding, simply remove it from your usage."
|
||||
msgstr ""
|
||||
"Attention : --encoding est dépréciée, retirez-le simplement de votre ligne "
|
||||
"de commande."
|
||||
|
||||
msgid "Error: --json-stream and --no-json cannot be used together."
|
||||
msgstr ""
|
||||
"Erreur : --json-stream et --no-json ne peuvent pas être utilisés "
|
||||
"simultanément."
|
||||
|
||||
msgid ""
|
||||
"Warning: --json-translate has no effect without either --json or --json-"
|
||||
"stream."
|
||||
msgstr ""
|
||||
"Avertissement : --json-translate n'a pas d'effet sans --json ou --json-"
|
||||
"stream."
|
||||
|
||||
msgid "Warning: deprecated --json-translate, use --no-raw instead."
|
||||
msgstr ""
|
||||
"Avertissement : --json-translate est dépréciée, utilisez plutôt --no-raw."
|
||||
|
||||
msgid "Warning: deprecated --no-json-translate, use --raw instead."
|
||||
msgstr ""
|
||||
"Avertissement : --no-json-translate est dépréciée, utilisez plutôt --raw."
|
||||
|
||||
#, perl-brace-format
|
||||
msgid "Loading profile from {path}."
|
||||
msgstr "Chargement du profil depuis le fichier {path}."
|
||||
|
||||
#, perl-brace-format
|
||||
msgid "Error: invalid value for --sourceaddr4: {reason}"
|
||||
msgstr "Erreur : valeur incorrecte pour --sourceaddr4: {reason}"
|
||||
|
||||
#, perl-brace-format
|
||||
msgid "Error: invalid value for --sourceaddr6: {reason}"
|
||||
msgstr "Erreur : valeur incorrecte pour --sourceaddr6: {reason}"
|
||||
|
||||
#, perl-brace-format
|
||||
msgid "Error: unrecognized term '{term}' in --test."
|
||||
msgstr "Erreur : terme non reconnu '{term}' pour --test."
|
||||
|
||||
#, perl-brace-format
|
||||
msgid "Failed to recognize stop level '{level}'."
|
||||
msgstr "Impossible de reconnaître le niveau de gravité d'arrêt '{level}'."
|
||||
|
||||
msgid ""
|
||||
"--level must be one of CRITICAL, ERROR, WARNING, NOTICE, INFO, DEBUG, DEBUG2 "
|
||||
"or DEBUG3."
|
||||
msgstr ""
|
||||
"--level doit avoir pour valeur CRITICAL, ERROR, WARNING, NOTICE, INFO, "
|
||||
"DEBUG, DEBUG2 ou DEBUG3."
|
||||
|
||||
msgid ""
|
||||
"Only one domain can be given for testing. Did you forget to prepend an "
|
||||
"option with '--<OPTION>'?"
|
||||
msgstr ""
|
||||
"Seul un domaine peut être soumis à un test. Auriez-vous oublié de préfixer "
|
||||
"une option avec '--<OPTION>'?"
|
||||
|
||||
msgid "Must give the name of a domain to test."
|
||||
msgstr "Il est nécessaire d'indiquer un nom de domaine à tester."
|
||||
|
||||
#, perl-brace-format
|
||||
msgid "Error loading hints file: {message}"
|
||||
msgstr "Erreur de chargement du fichier d'indication de la racine : {message}"
|
||||
|
||||
msgid "Seconds"
|
||||
msgstr "Durée"
|
||||
|
||||
msgid "Level"
|
||||
msgstr "Niveau"
|
||||
|
||||
msgid "Module"
|
||||
msgstr "Module"
|
||||
|
||||
msgid "Testcase"
|
||||
msgstr "Cas de test"
|
||||
|
||||
msgid "Message"
|
||||
msgstr "Message"
|
||||
|
||||
msgid "Looks OK."
|
||||
msgstr "Rien de particulier à signaler."
|
||||
|
||||
msgid "Number of log entries"
|
||||
msgstr "Nombre d'entrées journal"
|
||||
|
||||
msgid "Message tag"
|
||||
msgstr "Message"
|
||||
|
||||
msgid "Count"
|
||||
msgstr "Compte"
|
||||
|
||||
msgid "Name servers"
|
||||
msgstr "Serveurs de nom"
|
||||
|
||||
msgid "Child zone"
|
||||
msgstr "Zone fille"
|
||||
|
||||
msgid "Parent zone"
|
||||
msgstr "Zone parente"
|
||||
|
||||
msgid "Other"
|
||||
msgstr "Autre"
|
||||
|
||||
msgid "Grand total"
|
||||
msgstr "Grand total"
|
||||
|
||||
msgid "--ns must be a name or a name/ip pair."
|
||||
msgstr "--ns doit être un nom ou un couple nom/ip."
|
||||
|
||||
msgid ""
|
||||
"--ds ds data must be in the form \"keytag,algorithm,type,digest\". E.g. "
|
||||
"space is not permitted anywhere in the string."
|
||||
msgstr ""
|
||||
"Les données passées à --ds doivent être de la forme \"keytag,algorithme,type,"
|
||||
"condensat\". Par exemple, un espace n'est pas permis dans cette chaîne."
|
||||
|
||||
msgid "DEBUG"
|
||||
msgstr "DEBOGUE"
|
||||
|
||||
msgid "INFO"
|
||||
msgstr "INFO"
|
||||
|
||||
msgid "NOTICE"
|
||||
msgstr "NOTE"
|
||||
|
||||
msgid "WARNING"
|
||||
msgstr "AVERTISSEMENT"
|
||||
|
||||
msgid "ERROR"
|
||||
msgstr "ERREUR"
|
||||
|
||||
msgid "CRITICAL"
|
||||
msgstr "CRITIQUE"
|
||||
303
zonemaster-cli/share/nb.po
Normal file
303
zonemaster-cli/share/nb.po
Normal file
@@ -0,0 +1,303 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: 0.0.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2023-06-27 14:38+0200\n"
|
||||
"PO-Revision-Date: 2023-06-27 14:54+0200\n"
|
||||
"Last-Translator: Richard Persson <richard.persson@norid.no>\n"
|
||||
"Language-Team: Zonemaster Team\n"
|
||||
"Language: nb\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: Poedit 3.3.2\n"
|
||||
|
||||
msgid "Print version information and exit."
|
||||
msgstr "Vis versjonsinformasjon og avslutt."
|
||||
|
||||
msgid ""
|
||||
"The minimum severity level to display. Must be one of CRITICAL, ERROR, "
|
||||
"WARNING, NOTICE, INFO or DEBUG."
|
||||
msgstr ""
|
||||
"Minimumsnivå på feilmeldinger. Må være satt til en av CRITICAL, ERROR, "
|
||||
"WARNING, NOTICE, INFO eller DEBUG."
|
||||
|
||||
msgid "The locale to use for messages translation."
|
||||
msgstr "Språk for oversetting av meldinger."
|
||||
|
||||
msgid "Flag indicating if output should be in JSON or not."
|
||||
msgstr "Flagg som indikerer om output skal være formattert som JSON."
|
||||
|
||||
msgid "Flag indicating if output should be streaming JSON or not."
|
||||
msgstr "Flagg som indikerer om output skal strømme JSON."
|
||||
|
||||
msgid ""
|
||||
"Deprecated. Flag indicating if JSON output should include the translated "
|
||||
"message of the tag or not."
|
||||
msgstr ""
|
||||
"Foreldet. Flag som indikerer om JSON-output skal inneholde den oversatte "
|
||||
"meldingen."
|
||||
|
||||
msgid ""
|
||||
"Flag indicating if output should be translated to human language or dumped "
|
||||
"raw."
|
||||
msgstr "Flagg som indikerer om output skal oversettes til vanlig språk."
|
||||
|
||||
msgid "Print timestamp on entries."
|
||||
msgstr "Skriv tidsstempel på innslag."
|
||||
|
||||
msgid "Print level on entries."
|
||||
msgstr "Skriv nivå på innslag."
|
||||
|
||||
msgid "Print the name of the module on entries."
|
||||
msgstr "Skriv modulnavn på innslag."
|
||||
|
||||
msgid "Print the name of the test case on entries."
|
||||
msgstr "Skriv testnavn på innslag."
|
||||
|
||||
msgid ""
|
||||
"A name/ip string giving a nameserver for undelegated tests, or just a name "
|
||||
"which will be looked up for IP addresses. Can be given multiple times."
|
||||
msgstr ""
|
||||
"Et navn/IP-nummer for en navnetjener for udelegerte tester eller bare et "
|
||||
"navn som blir slått opp i DNS. Kan angis flere ganger."
|
||||
|
||||
msgid "Name of a root hints file to override the defaults."
|
||||
msgstr "Navn på en 'root hints'-fil for å overstyre standardinnstillingene."
|
||||
|
||||
msgid "Name of a file to save DNS data to after running tests."
|
||||
msgstr "Filnavn på fil der DNS-data blir lagret etter at testene er kjørt."
|
||||
|
||||
msgid "Name of a file to restore DNS data from before running test."
|
||||
msgstr "Filnavn på fil med DNS-data som leses inn innen testene startes."
|
||||
|
||||
msgid ""
|
||||
"Flag to permit or deny queries being sent via IPv4. --ipv4 permits IPv4 "
|
||||
"traffic, --no-ipv4 forbids it."
|
||||
msgstr ""
|
||||
"Flagg som angir om spørringer skal sendes vha. IPv4. \"--ipv4\" slår på og "
|
||||
"\"--no-ipv4\" slår av."
|
||||
|
||||
msgid ""
|
||||
"Flag to permit or deny queries being sent via IPv6. --ipv6 permits IPv6 "
|
||||
"traffic, --no-ipv6 forbids it."
|
||||
msgstr ""
|
||||
"Flagg som angir om spørringer skal sendes vha. IPv6. \"--ipv6\" slår på og "
|
||||
"\"--no-ipv6\" slår av."
|
||||
|
||||
msgid "Instead of running a test, list all available tests."
|
||||
msgstr "Liste tilgjengelige tester."
|
||||
|
||||
msgid ""
|
||||
"Specify test to run. Should be either the name of a module, or the name of a "
|
||||
"module and the name of a method in that module separated by a \"/\" "
|
||||
"character (Example: \"Basic/basic1\"). The method specified must be one that "
|
||||
"takes a zone object as its single argument. This switch can be repeated."
|
||||
msgstr ""
|
||||
"Angi test som skal kjøres. Kan angis som \"modulnavn\" eller \"modulnavn/"
|
||||
"metode\". Eksempel: \"Basic/basic1\". Den angitte metoden må være en som "
|
||||
"bare tar et sone-objekt som argument. Denne parameteren kan angis flere "
|
||||
"ganger."
|
||||
|
||||
msgid ""
|
||||
"As soon as a message at this level or higher is logged, execution will stop. "
|
||||
"Must be one of CRITICAL, ERROR, WARNING, NOTICE, INFO or DEBUG."
|
||||
msgstr ""
|
||||
"Avslutt testkjørningen når en melding med denna nivå eller høyere "
|
||||
"registreres."
|
||||
|
||||
msgid "Name of profile file to load. (DEFAULT)"
|
||||
msgstr "Filnavn på fil med profildata som skal leses. (DEFAULT)"
|
||||
|
||||
msgid "Strings with DS data on the form \"keytag,algorithm,type,digest\""
|
||||
msgstr ""
|
||||
"En tekststreng med DS-data på formatet: \"keytag,algorithm,type,digest\""
|
||||
|
||||
msgid "Print a count of the number of messages at each level"
|
||||
msgstr "Skriv en summering av antall meldinger på hvert nivå"
|
||||
|
||||
msgid ""
|
||||
"Boolean flag for activity indicator. Defaults to on if STDOUT is a tty, off "
|
||||
"if it is not. Disable with --no-progress."
|
||||
msgstr ""
|
||||
"Flagg som angir om fremdriftsindikator skal vises. Normalt på dersom STDOUT "
|
||||
"er en TTY, ellers av. Slå av med --no-progress."
|
||||
|
||||
msgid "Name of the character encoding used for command line arguments"
|
||||
msgstr "Navn på tegnsett som er brukt for kommandolinjeargumenter"
|
||||
|
||||
msgid ""
|
||||
"At the end of a run, print a summary of the times (in milliseconds) the "
|
||||
"zone's name servers took to answer."
|
||||
msgstr ""
|
||||
"Etter kjøring, skriv ut en oppsummering av svarstider (i millisekunder) fra "
|
||||
"sonens navnetjenere."
|
||||
|
||||
msgid "Print the effective profile used in JSON format, then exit."
|
||||
msgstr "Skriv ut profilen som er brukt i JSON-format."
|
||||
|
||||
msgid ""
|
||||
"Deprecated (planned removal: v2024.1). Use --sourceaddr4 and/or --"
|
||||
"sourceaddr6. Source IP address used to send queries. Setting an IP address "
|
||||
"not correctly configured on a local network interface causes cryptic error "
|
||||
"messages."
|
||||
msgstr ""
|
||||
"Foreldet (planlagt fjerning: v2024.1). Bruk --sourceaddr4 og/eller --"
|
||||
"sourceaddr6. Fra-IP-adresse brukt til å sende spørringer. Ved å bruke en IP-"
|
||||
"adresse som ikke er korrekt satt opp på et lokalt nett forårsakes kryptiske "
|
||||
"feilmeldinger."
|
||||
|
||||
msgid ""
|
||||
"Source IPv4 address used to send queries. Setting an IPv4 address not "
|
||||
"correctly configured on a local network interface fails silently. Can not be "
|
||||
"combined with --sourceaddr."
|
||||
msgstr ""
|
||||
"Fra-IPv4-adresse brukt til å sende spørringer. Hvis en bruker en IPv4-"
|
||||
"adresse som ikke er korrekt satt opp på et lokalt nett feiler testen uten "
|
||||
"meldinger. Kan ikke kombineres med --sourceaddr."
|
||||
|
||||
msgid ""
|
||||
"Source IPv6 address used to send queries. Setting an IPv6 address not "
|
||||
"correctly configured on a local network interface fails silently. Can not be "
|
||||
"combined with --sourceaddr."
|
||||
msgstr ""
|
||||
"Fra-IPv6-adresse brukt til å sende spørringer. Hvis en bruker en IPv6-"
|
||||
"adresse som ikke er korrekt satt opp på et lokalt nett feiler testen uten "
|
||||
"meldinger. Kan ikke kombineres med --sourceaddr."
|
||||
|
||||
msgid "Print elapsed time (in seconds) at end of run."
|
||||
msgstr "Skriv ut medgått tid (i sekunder) ved slutten av kjøringen."
|
||||
|
||||
#, perl-format
|
||||
msgid ""
|
||||
"Warning: setting locale category LC_MESSAGES to %s failed (is it installed "
|
||||
"on this system?)."
|
||||
msgstr ""
|
||||
"Advarsel: misslyktes med at sette locale category LC_MESSAGES til %s. Er den "
|
||||
"installert på dette system?"
|
||||
|
||||
#, perl-format
|
||||
msgid ""
|
||||
"Warning: setting locale category LC_CTYPE to %s failed (is it installed on "
|
||||
"this system?)."
|
||||
msgstr ""
|
||||
"Advarsel: misslyktes med at sette locale category LC_CTYPE til %s. Er den "
|
||||
"installert på dette system?"
|
||||
|
||||
msgid ""
|
||||
"Error: --sourceaddr can't be combined with --sourceaddr4 or --sourceaddr6."
|
||||
msgstr ""
|
||||
"Feil: --sourceaddr kan ikke kombineres med --sourceaddr4 eller --sourceaddr6."
|
||||
|
||||
msgid ""
|
||||
"Warning: --sourceaddr is deprecated (planned removal: v2024.1). Use --"
|
||||
"sourceaddr4 and/or --sourceaddr6 instead."
|
||||
msgstr ""
|
||||
"Advarsel: --sourceaddr er foreldet (planlagt fjerning: v2024.1). Bruk --"
|
||||
"sourceaddr4 og/eller --sourceaddr6 i stedet."
|
||||
|
||||
msgid "Error: --json-stream and --no-json can't be used together."
|
||||
msgstr "Feil: --json-stream og --no-json kan ikke brukes sammen."
|
||||
|
||||
msgid ""
|
||||
"Warning: --json-translate has no effect without either --json or --json-"
|
||||
"stream."
|
||||
msgstr ""
|
||||
"Advarsel: --json-translate har ingen effekt uten verken --json eller --json-"
|
||||
"stream."
|
||||
|
||||
msgid "Warning: deprecated --json-translate, use --no-raw instead."
|
||||
msgstr "Advarsel: foreldet --json-translate, bruk --no-raw i stedet."
|
||||
|
||||
msgid "Warning: deprecated --no-json-translate, use --raw instead."
|
||||
msgstr "Advarsel: utdatert --no-json-translate, bruk --raw i stedet."
|
||||
|
||||
#, perl-brace-format
|
||||
msgid "Loading profile from {path}."
|
||||
msgstr "Laster profil fra {path}."
|
||||
|
||||
msgid "Failed to recognize stop level '"
|
||||
msgstr "Kunne ikke gjenkjenne stop-nivå '"
|
||||
|
||||
msgid ""
|
||||
"--level must be one of CRITICAL, ERROR, WARNING, NOTICE, INFO, DEBUG, DEBUG2 "
|
||||
"or DEBUG3.\n"
|
||||
msgstr ""
|
||||
"--level må være en av CRITICAL, ERROR, WARNING, NOTICE, INFO, DEBUG, DEBUG2 "
|
||||
"eller DEBUG3.\n"
|
||||
|
||||
msgid "Seconds"
|
||||
msgstr "Sekunder"
|
||||
|
||||
msgid "Level"
|
||||
msgstr "Nivå"
|
||||
|
||||
msgid "Module"
|
||||
msgstr "Modul"
|
||||
|
||||
msgid "Testcase"
|
||||
msgstr "Test"
|
||||
|
||||
msgid "Message"
|
||||
msgstr "Melding"
|
||||
|
||||
msgid ""
|
||||
"Only one domain can be given for testing. Did you forget to prepend an "
|
||||
"option with '--<OPTION>'?\n"
|
||||
msgstr ""
|
||||
"Bare ett domene kan gis for testing. Glemte du å sette '--<OPTION>' foran en "
|
||||
"opsjon?\n"
|
||||
|
||||
msgid "Must give the name of a domain to test.\n"
|
||||
msgstr "Må angi navnet på domenet som skal testes.\n"
|
||||
|
||||
msgid "The domain name contains consecutive dots.\n"
|
||||
msgstr "Domenenavnet inneholder flere punkter på rad.\n"
|
||||
|
||||
msgid "Looks OK."
|
||||
msgstr "Ser OK ut."
|
||||
|
||||
msgid ""
|
||||
"\n"
|
||||
"\n"
|
||||
" Level\tNumber of log entries"
|
||||
msgstr ""
|
||||
"\n"
|
||||
"\n"
|
||||
" Nivå Antall loggmeldinger"
|
||||
|
||||
#, perl-format
|
||||
msgid "%8s\t%5d entries.\n"
|
||||
msgstr "%8s\t%5d meldinger.\n"
|
||||
|
||||
msgid "--ns must be a name or a name/ip pair."
|
||||
msgstr "--ns må være et navn eller et navn/ip par."
|
||||
|
||||
#, perl-brace-format
|
||||
msgid "The name of the nameserver '{nsname}' contains consecutive dots."
|
||||
msgstr "Navnet til navnetjeneren '{nsname}' inneholder flere punkter på rad."
|
||||
|
||||
msgid ""
|
||||
"Warning: Zonemaster::LDNS not compiled with IDN support, cannot handle non-"
|
||||
"ASCII names correctly."
|
||||
msgstr ""
|
||||
"Advarsel: Zonemaster::LDNS er ikke kompilert med IDN-støtte. Kan bare "
|
||||
"håndtere ASCII-navn."
|
||||
|
||||
msgid "DEBUG"
|
||||
msgstr "DEBUG"
|
||||
|
||||
msgid "INFO"
|
||||
msgstr "INFO"
|
||||
|
||||
msgid "NOTICE"
|
||||
msgstr "NOTIS"
|
||||
|
||||
msgid "WARNING"
|
||||
msgstr "ADVARSEL"
|
||||
|
||||
msgid "ERROR"
|
||||
msgstr "FEIL"
|
||||
|
||||
msgid "CRITICAL"
|
||||
msgstr "KRITISK"
|
||||
176
zonemaster-cli/share/sl.po
Normal file
176
zonemaster-cli/share/sl.po
Normal file
@@ -0,0 +1,176 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: 0.0.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-02-26 15:58+0100\n"
|
||||
"PO-Revision-Date: 2025-02-26 14:58+0200\n"
|
||||
"Last-Translator: milijan@arnes.si\n"
|
||||
"Language-Team: register.si\n"
|
||||
"Language: sl\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: Poedit 3.5\n"
|
||||
|
||||
#, perl-brace-format
|
||||
msgid ""
|
||||
"Warning: setting locale category LC_MESSAGES to {locale} failed -- is it "
|
||||
"installed on this system?"
|
||||
msgstr ""
|
||||
"Opozorilo: Neuspešno nastavljanje jezika {locale} za LC_MESSAGES(Je jezik "
|
||||
"nameščen na sistemu?)."
|
||||
|
||||
#, perl-brace-format
|
||||
msgid ""
|
||||
"Warning: setting locale category LC_CTYPE to {locale} failed -- is it "
|
||||
"installed on this system?"
|
||||
msgstr ""
|
||||
"Opozorilo: Neuspešno nastavljanje jezika {locale} za LC_CTYPE (Je jezik "
|
||||
"nameščen na sistemu?)."
|
||||
|
||||
msgid "Warning: deprecated --encoding, simply remove it from your usage."
|
||||
msgstr ""
|
||||
|
||||
msgid "Error: --json-stream and --no-json cannot be used together."
|
||||
msgstr "Napaka : --json-stream in --no-json ne možno uporabiti hkrati."
|
||||
|
||||
msgid ""
|
||||
"Warning: --json-translate has no effect without either --json or --json-"
|
||||
"stream."
|
||||
msgstr "Opozorilo: --json-translate nima učinka brez --json ali --json-stream."
|
||||
|
||||
msgid "Warning: deprecated --json-translate, use --no-raw instead."
|
||||
msgstr "Opozorilo: --json-translate je zastarelo, uporabi --no-raw."
|
||||
|
||||
msgid "Warning: deprecated --no-json-translate, use --raw instead."
|
||||
msgstr "Opozorilo: --no-json-translate je zastarelo, uporabi --raw."
|
||||
|
||||
#, perl-brace-format
|
||||
msgid "Loading profile from {path}."
|
||||
msgstr "Nalagam profil iz {path}."
|
||||
|
||||
#, perl-brace-format
|
||||
msgid "Error: invalid value for --sourceaddr4: {reason}"
|
||||
msgstr "Napačna vrednost za --sourceaddr4: {reason}"
|
||||
|
||||
#, perl-brace-format
|
||||
msgid "Error: invalid value for --sourceaddr6: {reason}"
|
||||
msgstr "Napačna vrednost za --sourceaddr6: {reason}"
|
||||
|
||||
#, perl-brace-format
|
||||
msgid ""
|
||||
"Error: Invalid input '{cli_arg}' in --test. There must be at most one slash "
|
||||
"('/') character."
|
||||
msgstr ""
|
||||
"Napaka: Napačen vnos '{cli_arg}' v --test. Zahtevana je najmanj ena "
|
||||
"poševnica znak ('/')."
|
||||
|
||||
#, perl-brace-format
|
||||
msgid ""
|
||||
"Error: Unrecognized test case '{testcase}' in --test. Use --list-tests for a "
|
||||
"list of valid choices."
|
||||
msgstr ""
|
||||
"Napaka: Test '{testcase}' v --test ni prepoznan, Uporabite --list-tests za "
|
||||
"spisek veljavnih izbir."
|
||||
|
||||
#, perl-brace-format
|
||||
msgid ""
|
||||
"Error: Unrecognized test module '{module}' in --test. Use --list-tests for a "
|
||||
"list of valid choices."
|
||||
msgstr ""
|
||||
"Napaka: Modul '{module}' v --test ni prepoznan. Uporabite --list-tests za "
|
||||
"spisek veljavnih izbir."
|
||||
|
||||
#, perl-brace-format
|
||||
msgid "Error: Invalid input '{cli_arg}' in --test."
|
||||
msgstr "Napaka: Napačen vnos '{cli_arg}' v --test."
|
||||
|
||||
#, perl-brace-format
|
||||
msgid ""
|
||||
"Notice: Engine does not have test case '{testcase}' enabled in the profile. "
|
||||
"Forcing..."
|
||||
msgstr ""
|
||||
"Pozor: Orodje ne podpira testa '{testcase}', ki je omogočeno v profilu. "
|
||||
"Vklopljen..."
|
||||
|
||||
#, perl-brace-format
|
||||
msgid "Failed to recognize stop level '{level}'."
|
||||
msgstr "Ni mogoče prepoznati stopnjo resnosti {level}, ki povzroči ustavitev '"
|
||||
|
||||
msgid ""
|
||||
"--level must be one of CRITICAL, ERROR, WARNING, NOTICE, INFO, DEBUG, DEBUG2 "
|
||||
"or DEBUG3."
|
||||
msgstr ""
|
||||
"--level mora biti eden izmed KRITIČNO, NAPAKA, OPOZORILO, OBVESTILO, INFO, "
|
||||
"DEBUG, DEBUG2 ali DEBUG3."
|
||||
|
||||
msgid ""
|
||||
"Only one domain can be given for testing. Did you forget to prepend an "
|
||||
"option with '--<OPTION>'?"
|
||||
msgstr "Lahko se preverja le ena domena. Ste pozabili dodati '--<OPTION>'?"
|
||||
|
||||
msgid "Must give the name of a domain to test."
|
||||
msgstr "Vnesite ime domene za preverjanje."
|
||||
|
||||
#, perl-brace-format
|
||||
msgid "Error loading hints file: {message}"
|
||||
msgstr "Napaka pri nalaganju hint datoteke: {message}"
|
||||
|
||||
msgid "Seconds"
|
||||
msgstr "Sekund"
|
||||
|
||||
msgid "Level"
|
||||
msgstr "Stopnja"
|
||||
|
||||
msgid "Module"
|
||||
msgstr "Modul"
|
||||
|
||||
msgid "Testcase"
|
||||
msgstr "Vrsta testa"
|
||||
|
||||
msgid "Message"
|
||||
msgstr "Sporočilo"
|
||||
|
||||
msgid "Looks OK."
|
||||
msgstr "Videti je v redu."
|
||||
|
||||
msgid ""
|
||||
"\n"
|
||||
"\n"
|
||||
" Level\tNumber of log entries"
|
||||
msgstr ""
|
||||
"\n"
|
||||
"\n"
|
||||
" Stopnja\tŠtevilo dnevniških vnosov"
|
||||
|
||||
#, perl-format
|
||||
msgid "%8s\t%5d entries.\n"
|
||||
msgstr "%8s\t%5d vnosov.\n"
|
||||
|
||||
msgid "--ns must be a name or a name/ip pair."
|
||||
msgstr "--ns mora biti ime ali ime/IP."
|
||||
|
||||
msgid ""
|
||||
"--ds ds data must be in the form \"keytag,algorithm,type,digest\". E.g. "
|
||||
"space is not permitted anywhere in the string."
|
||||
msgstr ""
|
||||
"--ds ds mora biti v formatu \"keytag,algorithm,type,digest\". Npr. presledek "
|
||||
"ni dovoljen nikjer v nizu."
|
||||
|
||||
msgid "DEBUG"
|
||||
msgstr "DEBUG"
|
||||
|
||||
msgid "INFO"
|
||||
msgstr "INFO"
|
||||
|
||||
msgid "NOTICE"
|
||||
msgstr "OBVESTILO"
|
||||
|
||||
msgid "WARNING"
|
||||
msgstr "OPOZORILO"
|
||||
|
||||
msgid "ERROR"
|
||||
msgstr "NAPAKA"
|
||||
|
||||
msgid "CRITICAL"
|
||||
msgstr "KRITIČNO"
|
||||
171
zonemaster-cli/share/sv.po
Normal file
171
zonemaster-cli/share/sv.po
Normal file
@@ -0,0 +1,171 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: 0.0.5\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-12-12 10:17+0100\n"
|
||||
"PO-Revision-Date: 2023-05-31 08:42+0000\n"
|
||||
"Last-Translator: mattias.paivarinta@iis.se\n"
|
||||
"Language-Team: Zonemaster Team\n"
|
||||
"Language: sv\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#, perl-brace-format
|
||||
msgid ""
|
||||
"Warning: setting locale category LC_MESSAGES to {locale} failed -- is it "
|
||||
"installed on this system?"
|
||||
msgstr ""
|
||||
"Varning: misslyckades med att sätta locale kategori LC_MESSAGES till "
|
||||
"'{locale}' – finns den installerad på det här systemet?"
|
||||
|
||||
#, perl-brace-format
|
||||
msgid ""
|
||||
"Warning: setting locale category LC_CTYPE to {locale} failed -- is it "
|
||||
"installed on this system?"
|
||||
msgstr ""
|
||||
"Varning: misslyckades med att sätta locale kategori LC_CTYPE till '{locale}' "
|
||||
"– finns den installerad på det här systemet?"
|
||||
|
||||
msgid "Warning: deprecated --encoding, simply remove it from your usage."
|
||||
msgstr ""
|
||||
|
||||
msgid "Error: --json-stream and --no-json cannot be used together."
|
||||
msgstr "Fel: --json-stream och --no-json kan inte användas tillsammans."
|
||||
|
||||
msgid ""
|
||||
"Warning: --json-translate has no effect without either --json or --json-"
|
||||
"stream."
|
||||
msgstr ""
|
||||
"Varning: --json-translate är verkningslös utan samtidig --json eller --json-"
|
||||
"stream."
|
||||
|
||||
msgid "Warning: deprecated --json-translate, use --no-raw instead."
|
||||
msgstr ""
|
||||
"Varning: --json-translate är under utfasning. Använd --no-raw instället."
|
||||
|
||||
msgid "Warning: deprecated --no-json-translate, use --raw instead."
|
||||
msgstr ""
|
||||
"Varning: --no-json-translate är under utfasning. Använd --raw instället."
|
||||
|
||||
#, perl-brace-format
|
||||
msgid "Loading profile from {path}."
|
||||
msgstr "Laddar profil från {path}."
|
||||
|
||||
#, perl-brace-format
|
||||
msgid "Error: invalid value for --sourceaddr4: {reason}"
|
||||
msgstr ""
|
||||
|
||||
#, perl-brace-format
|
||||
msgid "Error: invalid value for --sourceaddr6: {reason}"
|
||||
msgstr ""
|
||||
|
||||
#, perl-brace-format
|
||||
msgid ""
|
||||
"Error: Invalid input '{cli_arg}' in --test. There must be at most one slash "
|
||||
"('/') character."
|
||||
msgstr ""
|
||||
|
||||
#, perl-brace-format
|
||||
msgid ""
|
||||
"Error: Unrecognized test case '{testcase}' in --test. Use --list-tests for a "
|
||||
"list of valid choices."
|
||||
msgstr ""
|
||||
|
||||
#, perl-brace-format
|
||||
msgid ""
|
||||
"Error: Unrecognized test module '{module}' in --test. Use --list-tests for a "
|
||||
"list of valid choices."
|
||||
msgstr ""
|
||||
|
||||
#, perl-brace-format
|
||||
msgid "Error: Invalid input '{cli_arg}' in --test."
|
||||
msgstr ""
|
||||
|
||||
#, perl-brace-format
|
||||
msgid ""
|
||||
"Notice: Engine does not have test case '{testcase}' enabled in the profile. "
|
||||
"Forcing..."
|
||||
msgstr ""
|
||||
|
||||
#, perl-brace-format
|
||||
msgid "Failed to recognize stop level '{level}'."
|
||||
msgstr "Kände inte igen avslutsnivån '{level}'."
|
||||
|
||||
msgid ""
|
||||
"--level must be one of CRITICAL, ERROR, WARNING, NOTICE, INFO, DEBUG, DEBUG2 "
|
||||
"or DEBUG3."
|
||||
msgstr ""
|
||||
"--level måste vara en av CRITICAL, ERROR, WARNING, NOTICE, INFO, DEBUG, "
|
||||
"DEBUG2 eller DEBUG3."
|
||||
|
||||
msgid ""
|
||||
"Only one domain can be given for testing. Did you forget to prepend an "
|
||||
"option with '--<OPTION>'?"
|
||||
msgstr ""
|
||||
"Endast ett domännamn kan anges för testning. Missade du att sätta '--"
|
||||
"<OPTION>' före en optionsparameter?"
|
||||
|
||||
msgid "Must give the name of a domain to test."
|
||||
msgstr "Namnet på en domän att testa måste anges."
|
||||
|
||||
#, perl-brace-format
|
||||
msgid "Error loading hints file: {message}"
|
||||
msgstr ""
|
||||
|
||||
msgid "Seconds"
|
||||
msgstr "Sekund"
|
||||
|
||||
msgid "Level"
|
||||
msgstr "Nivå"
|
||||
|
||||
msgid "Module"
|
||||
msgstr "Modul"
|
||||
|
||||
msgid "Testcase"
|
||||
msgstr "Testfall"
|
||||
|
||||
msgid "Message"
|
||||
msgstr "Meddelande"
|
||||
|
||||
msgid "Looks OK."
|
||||
msgstr "Ser OK ut."
|
||||
|
||||
msgid ""
|
||||
"\n"
|
||||
"\n"
|
||||
" Level\tNumber of log entries"
|
||||
msgstr ""
|
||||
"\n"
|
||||
"\n"
|
||||
" Nivå \tAntal loggmeddelanden"
|
||||
|
||||
#, perl-format
|
||||
msgid "%8s\t%5d entries.\n"
|
||||
msgstr "%8s\t%5d meddelanden.\n"
|
||||
|
||||
msgid "--ns must be a name or a name/ip pair."
|
||||
msgstr "--ns måste vara ett namn eller namn/ip i det formatet.\""
|
||||
|
||||
msgid ""
|
||||
"--ds ds data must be in the form \"keytag,algorithm,type,digest\". E.g. "
|
||||
"space is not permitted anywhere in the string."
|
||||
msgstr ""
|
||||
|
||||
msgid "DEBUG"
|
||||
msgstr "DEBUG"
|
||||
|
||||
msgid "INFO"
|
||||
msgstr "INFO"
|
||||
|
||||
msgid "NOTICE"
|
||||
msgstr "NOTIS"
|
||||
|
||||
msgid "WARNING"
|
||||
msgstr "VARNING"
|
||||
|
||||
msgid "ERROR"
|
||||
msgstr "FEL"
|
||||
|
||||
msgid "CRITICAL"
|
||||
msgstr "KRITISKT"
|
||||
9
zonemaster-cli/share/update-po
Executable file
9
zonemaster-cli/share/update-po
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ -z "$1" ] ; then
|
||||
echo "error: No PO file specified." >&2
|
||||
exit 2
|
||||
fi
|
||||
po_file="$1" ; shift
|
||||
|
||||
make update-po POFILES="$po_file"
|
||||
12
zonemaster-cli/t/00-load.t
Normal file
12
zonemaster-cli/t/00-load.t
Normal file
@@ -0,0 +1,12 @@
|
||||
use 5.014002;
|
||||
use strict;
|
||||
use warnings FATAL => 'all';
|
||||
use Test::More;
|
||||
|
||||
plan tests => 1;
|
||||
|
||||
BEGIN {
|
||||
use_ok( 'Zonemaster::CLI' ) || print "Bail out!\n";
|
||||
}
|
||||
|
||||
diag( "Testing Zonemaster::CLI $Zonemaster::CLI::VERSION, Perl $], $^X" );
|
||||
37
zonemaster-cli/t/manifest.t
Normal file
37
zonemaster-cli/t/manifest.t
Normal file
@@ -0,0 +1,37 @@
|
||||
#!perl
|
||||
use v5.14.2;
|
||||
use strict;
|
||||
use warnings;
|
||||
use utf8;
|
||||
use Test::More tests => 2;
|
||||
use Test::NoWarnings;
|
||||
|
||||
use File::Basename qw( dirname );
|
||||
|
||||
chdir dirname( dirname( __FILE__ ) ) or BAIL_OUT( "chdir: $!" );
|
||||
|
||||
my $makebin = 'make';
|
||||
|
||||
sub make {
|
||||
my @make_args = @_;
|
||||
|
||||
undef $ENV{MAKEFLAGS};
|
||||
|
||||
my $command = join( ' ', $makebin, '-s', @make_args );
|
||||
my $output = `$command 2>&1`;
|
||||
|
||||
if ( $? == -1 ) {
|
||||
BAIL_OUT( "failed to execute: $!" );
|
||||
}
|
||||
elsif ( $? & 127 ) {
|
||||
BAIL_OUT( "child died with signal %d, %s coredump\n", ( $? & 127 ), ( $? & 128 ) ? 'with' : 'without' );
|
||||
}
|
||||
|
||||
return $output, $? >> 8;
|
||||
}
|
||||
|
||||
subtest "distcheck" => sub {
|
||||
my ( $output, $status ) = make "distcheck";
|
||||
is $status, 0, $makebin . ' distcheck exits with value 0';
|
||||
is $output, "", $makebin . ' distcheck gives empty output';
|
||||
};
|
||||
64
zonemaster-cli/t/po-files.t
Normal file
64
zonemaster-cli/t/po-files.t
Normal file
@@ -0,0 +1,64 @@
|
||||
#!perl
|
||||
use v5.14.2;
|
||||
use strict;
|
||||
use warnings;
|
||||
use utf8;
|
||||
use Test::More; # see done_testing()
|
||||
|
||||
use File::Basename qw( dirname );
|
||||
|
||||
chdir dirname( dirname( __FILE__ ) ) or BAIL_OUT( "chdir: $!" );
|
||||
chdir 'share' or BAIL_OUT( "chdir: $!" );
|
||||
|
||||
my $makebin = 'make';
|
||||
|
||||
sub make {
|
||||
my @make_args = @_;
|
||||
|
||||
undef $ENV{MAKEFLAGS};
|
||||
|
||||
my $command = join( ' ', $makebin, '--silent', '--no-print-directory', @make_args );
|
||||
my $output = `$command`;
|
||||
|
||||
if ( $? == -1 ) {
|
||||
BAIL_OUT( "failed to execute: $!" );
|
||||
}
|
||||
elsif ( $? & 127 ) {
|
||||
BAIL_OUT( "child died with signal %d, %s coredump\n", ( $? & 127 ), ( $? & 128 ) ? 'with' : 'without' );
|
||||
}
|
||||
|
||||
return $output, $? >> 8;
|
||||
}
|
||||
|
||||
subtest "no fuzzy marks" => sub {
|
||||
my ( $output, $status ) = make "show-fuzzy";
|
||||
is $status, 0, $makebin . ' show-fuzzy exits with value 0';
|
||||
is $output, "", $makebin . ' show-fuzzy gives empty output';
|
||||
};
|
||||
|
||||
subtest "check po files" => sub {
|
||||
my ( $output, $status ) = make "check-po";
|
||||
is $status, 0, $makebin . ' check-po exits with value 0';
|
||||
is $output, "", $makebin . ' check-po gives empty output';
|
||||
};
|
||||
|
||||
subtest "tidy po files" => sub {
|
||||
SKIP: {
|
||||
my ( $output, $status );
|
||||
|
||||
$output = `git diff --numstat`;
|
||||
|
||||
skip 'git repo should be clean to run this test', 3 if $output ne '';
|
||||
|
||||
diag "Using msgcat version: " . `msgcat --version | head -n1`;
|
||||
|
||||
( $output, $status ) = make "tidy-po";
|
||||
is $status, 0, $makebin . ' tidy-po exits with value 0';
|
||||
is $output, "", $makebin . ' tidy-po gives empty output';
|
||||
|
||||
$output = `git diff --numstat`;
|
||||
is $output, "", 'all files are tidied (if not run "make tidy-po")';
|
||||
}
|
||||
};
|
||||
|
||||
done_testing();
|
||||
18
zonemaster-cli/t/pod.t
Normal file
18
zonemaster-cli/t/pod.t
Normal file
@@ -0,0 +1,18 @@
|
||||
#!perl -T
|
||||
use 5.006;
|
||||
use strict;
|
||||
use warnings FATAL => 'all';
|
||||
use Test::More;
|
||||
|
||||
# Ensure a recent version of Test::Pod
|
||||
my $min_tp = 1.22;
|
||||
eval "use Test::Pod $min_tp";
|
||||
plan skip_all => "Test::Pod $min_tp required for testing POD" if $@;
|
||||
|
||||
my @poddirs;
|
||||
push @poddirs, ( -e 'lib' ? 'lib' : 'blib' );
|
||||
push @poddirs, 'script';
|
||||
|
||||
all_pod_files_ok( all_pod_files( @poddirs ) );
|
||||
|
||||
done_testing;
|
||||
320
zonemaster-cli/t/test_case_set.t
Normal file
320
zonemaster-cli/t/test_case_set.t
Normal file
@@ -0,0 +1,320 @@
|
||||
#!perl
|
||||
use 5.14.2;
|
||||
use utf8;
|
||||
use warnings;
|
||||
use Test::More;
|
||||
|
||||
use Log::Any::Test;
|
||||
use Log::Any qw( $log );
|
||||
use Test::Differences;
|
||||
use Test::Exception;
|
||||
use Zonemaster::Engine;
|
||||
use Zonemaster::Engine::Profile;
|
||||
|
||||
use Zonemaster::CLI::TestCaseSet;
|
||||
|
||||
require Test::NoWarnings;
|
||||
|
||||
lives_ok { # Make sure we get to print log messages in case of errors.
|
||||
subtest 'parse_modifier_expr' => sub {
|
||||
my @cases = (
|
||||
{
|
||||
name => 'empty',
|
||||
expr => '',
|
||||
expected => [],
|
||||
},
|
||||
{
|
||||
name => 'absolute term',
|
||||
expr => 'term',
|
||||
expected => [ '', 'term' ],
|
||||
},
|
||||
{
|
||||
name => 'absolute additive',
|
||||
expr => 'term',
|
||||
expected => [ '', 'term' ],
|
||||
},
|
||||
{
|
||||
name => 'absolute subtractive',
|
||||
expr => 'term',
|
||||
expected => [ '', 'term' ],
|
||||
},
|
||||
{
|
||||
name => 'absolute multiple modifiers',
|
||||
expr => 'term1+term2',
|
||||
expected => [ '', 'term1', '+', 'term2' ],
|
||||
},
|
||||
{
|
||||
name => 'relative multiple modifiers',
|
||||
expr => '-term1+term2',
|
||||
expected => [ '-', 'term1', '+', 'term2' ],
|
||||
},
|
||||
);
|
||||
for my $case ( @cases ) {
|
||||
subtest $case->{name} => sub {
|
||||
my @actual = Zonemaster::CLI::TestCaseSet->parse_modifier_expr( $case->{expr} );
|
||||
eq_or_diff \@actual, $case->{expected};
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
subtest 'new' => sub {
|
||||
my @cases = (
|
||||
{
|
||||
name => 'empty',
|
||||
schema => {},
|
||||
selection => [],
|
||||
expect_ok => {
|
||||
terms => ['all'],
|
||||
methods => [],
|
||||
},
|
||||
},
|
||||
{
|
||||
name => 'multiple test modules and test cases',
|
||||
schema => { 'alpha' => [ 'bravo', 'charlie' ], 'delta' => ['echo'] },
|
||||
selection => [ 'bravo', 'echo' ],
|
||||
expect_ok => {
|
||||
terms => [
|
||||
'all', 'alpha', 'alpha/bravo', 'alpha/charlie',
|
||||
'bravo', 'charlie', 'delta', 'delta/echo',
|
||||
'echo'
|
||||
],
|
||||
methods => [ 'bravo', 'echo' ],
|
||||
},
|
||||
},
|
||||
{
|
||||
name => 'mixed cases',
|
||||
schema => { 'alpha' => [ 'BRAVO', 'charlie' ] },
|
||||
selection => [ 'bravo', 'CHARLIE' ],
|
||||
expect_ok => {
|
||||
terms => [ 'all', 'alpha', 'alpha/bravo', 'alpha/charlie', 'bravo', 'charlie' ],
|
||||
methods => [ 'bravo', 'charlie' ],
|
||||
},
|
||||
},
|
||||
{
|
||||
name => 'illegal test module name 1',
|
||||
schema => { 'all' => [] },
|
||||
selection => [],
|
||||
expect_err => qr/must not be 'all'/i,
|
||||
},
|
||||
{
|
||||
name => 'illegal test module name 2',
|
||||
schema => { 'ALL' => [] },
|
||||
selection => [],
|
||||
expect_err => qr/must not be 'all'/i,
|
||||
},
|
||||
{
|
||||
name => 'illegal test module name 3',
|
||||
schema => { 'alpha/bravo' => [] },
|
||||
selection => [],
|
||||
expect_err => qr{contains forbidden character '/'}i,
|
||||
},
|
||||
{
|
||||
name => 'illegal test case name 1',
|
||||
schema => { 'alpha' => ['all'] },
|
||||
selection => [],
|
||||
expect_err => qr/must not be 'all'/i,
|
||||
},
|
||||
{
|
||||
name => 'illegal test case name 2',
|
||||
schema => { 'alpha' => ['ALL'] },
|
||||
selection => [],
|
||||
expect_err => qr/must not be 'all'/i,
|
||||
},
|
||||
{
|
||||
name => 'illegal test case name 3',
|
||||
schema => { 'alpha' => ['bravo/charlie'] },
|
||||
selection => [],
|
||||
expect_err => qr{contains forbidden character '/'}i,
|
||||
},
|
||||
{
|
||||
name => 'duplicate term 1',
|
||||
schema => { 'alpha' => ['alpha'] },
|
||||
selection => [],
|
||||
expect_err => qr/same name/i,
|
||||
},
|
||||
{
|
||||
name => 'duplicate term 2',
|
||||
schema => { 'alpha' => ['ALPHA'] },
|
||||
selection => [],
|
||||
expect_err => qr/same name/i,
|
||||
},
|
||||
{
|
||||
name => 'duplicate term 3',
|
||||
schema => { 'ALPHA' => ['alpha'] },
|
||||
selection => [],
|
||||
expect_err => qr/same name/i,
|
||||
},
|
||||
{
|
||||
name => 'duplicate term 4',
|
||||
schema => { 'alpha' => [], 'bravo' => ['alpha'] },
|
||||
selection => [],
|
||||
expect_err => qr/same name/i,
|
||||
},
|
||||
{
|
||||
name => 'duplicate term 5',
|
||||
schema => { 'alpha' => [ 'bravo', 'bravo' ] },
|
||||
selection => [],
|
||||
expect_err => qr/same name/i,
|
||||
},
|
||||
{
|
||||
name => 'duplicate term 6',
|
||||
schema => { 'alpha' => ['bravo'], 'charlie' => ['bravo'] },
|
||||
selection => [],
|
||||
expect_err => qr/same name/i,
|
||||
},
|
||||
{
|
||||
name => 'unrecognized test case 1',
|
||||
schema => { 'alpha' => [] },
|
||||
selection => ['all'],
|
||||
expect_err => qr/unrecognized/i,
|
||||
},
|
||||
{
|
||||
name => 'unrecognized test case 2',
|
||||
schema => { 'alpha' => [] },
|
||||
selection => ['alpha'],
|
||||
expect_err => qr/unrecognized/i,
|
||||
},
|
||||
);
|
||||
for my $case ( @cases ) {
|
||||
subtest $case->{name} => sub {
|
||||
my $test_case_set;
|
||||
local $@;
|
||||
eval {
|
||||
$test_case_set = Zonemaster::CLI::TestCaseSet->new( #
|
||||
$case->{selection},
|
||||
$case->{schema},
|
||||
);
|
||||
};
|
||||
|
||||
my $err = $@;
|
||||
my $actual;
|
||||
if ( !$err ) {
|
||||
$actual = {
|
||||
terms => [ sort keys %{ $test_case_set->{_terms} } ],
|
||||
methods => [ $test_case_set->to_list ],
|
||||
};
|
||||
}
|
||||
|
||||
if ( defined $case->{expect_err} ) {
|
||||
like $err, $case->{expect_err}, "error";
|
||||
}
|
||||
else {
|
||||
is $err, "", "no error";
|
||||
}
|
||||
if ( defined $case->{expect_ok} ) {
|
||||
eq_or_diff $actual, $case->{expect_ok}, "result";
|
||||
}
|
||||
else {
|
||||
eq_or_diff $actual, undef, "no result";
|
||||
}
|
||||
}; ## end sub
|
||||
} ## end for my $case ( @cases )
|
||||
}; ## end 'new' => sub
|
||||
|
||||
subtest 'apply_modifier' => sub {
|
||||
my @cases = (
|
||||
{
|
||||
name => 'empty',
|
||||
schema => {},
|
||||
selection => [],
|
||||
modifiers => [],
|
||||
expected => [],
|
||||
},
|
||||
{
|
||||
name => 'no modifiers',
|
||||
schema => { basic => [ 'basic01', 'basic02' ] },
|
||||
selection => ['basic01'],
|
||||
modifiers => [],
|
||||
expected => ['basic01'],
|
||||
},
|
||||
{
|
||||
name => 'add a new case',
|
||||
schema => { basic => [ 'basic01', 'basic02' ] },
|
||||
selection => ['basic01'],
|
||||
modifiers => [ '+', 'basic02' ],
|
||||
expected => [ 'basic01', 'basic02' ],
|
||||
},
|
||||
{
|
||||
name => 'add the same case',
|
||||
schema => { basic => [ 'basic01', 'basic02' ] },
|
||||
selection => ['basic01'],
|
||||
modifiers => [ '+', 'basic01' ],
|
||||
expected => ['basic01'],
|
||||
},
|
||||
{
|
||||
name => 'replace',
|
||||
schema => { basic => [ 'basic01', 'basic02' ] },
|
||||
selection => ['basic01'],
|
||||
modifiers => [ '', 'basic02' ],
|
||||
expected => ['basic02'],
|
||||
},
|
||||
{
|
||||
name => 'module expansion',
|
||||
schema => { basic => ['basic01'], extra => [ 'extra01', 'extra02' ] },
|
||||
selection => ['basic01'],
|
||||
modifiers => [ '', 'extra' ],
|
||||
expected => [ 'extra01', 'extra02' ],
|
||||
},
|
||||
{
|
||||
name => 'all',
|
||||
schema => { basic => ['basic01'], extra => [ 'extra01', 'extra02' ] },
|
||||
selection => ['basic01'],
|
||||
modifiers => [ '', 'all' ],
|
||||
expected => [ 'basic01', 'extra01', 'extra02' ],
|
||||
},
|
||||
{
|
||||
name => 'multiple modifiers',
|
||||
schema => { basic => ['basic01'], extra => [ 'extra01', 'extra02' ] },
|
||||
selection => ['basic01'],
|
||||
modifiers => [ '', 'all', '-', 'basic' ],
|
||||
expected => [ 'extra01', 'extra02' ],
|
||||
},
|
||||
{
|
||||
name => 'invalid operator',
|
||||
schema => { basic => [ 'basic01', 'basic02' ] },
|
||||
selection => ['basic01'],
|
||||
modifiers => [ '*', 'basic02' ],
|
||||
error => qr{unrecognized operator}i,
|
||||
},
|
||||
);
|
||||
for my $case ( @cases ) {
|
||||
subtest $case->{name} => sub {
|
||||
my $test_case_set = Zonemaster::CLI::TestCaseSet->new( #
|
||||
$case->{selection},
|
||||
$case->{schema},
|
||||
);
|
||||
|
||||
local $@ = '';
|
||||
eval {
|
||||
while ( @{ $case->{modifiers} } ) {
|
||||
my $op = shift @{ $case->{modifiers} };
|
||||
my $term = shift @{ $case->{modifiers} };
|
||||
$test_case_set->apply_modifier( $op, $term );
|
||||
}
|
||||
};
|
||||
my $error = $@;
|
||||
|
||||
if ( exists $case->{expected} ) {
|
||||
is $error, '';
|
||||
eq_or_diff [ $test_case_set->to_list ], $case->{expected};
|
||||
}
|
||||
else {
|
||||
like $error, $case->{error};
|
||||
}
|
||||
};
|
||||
} ## end for my $case ( @cases )
|
||||
};
|
||||
};
|
||||
|
||||
for my $msg ( @{ $log->msgs } ) {
|
||||
my $text = sprintf( "%s: %s", $msg->{level}, $msg->{message} );
|
||||
if ( $msg->{level} =~ /trace|debug|info|notice/ ) {
|
||||
note $text;
|
||||
}
|
||||
else {
|
||||
diag $text;
|
||||
}
|
||||
}
|
||||
|
||||
Test::NoWarnings::had_no_warnings();
|
||||
done_testing;
|
||||
138
zonemaster-cli/t/usage.fake-data.data
Normal file
138
zonemaster-cli/t/usage.fake-data.data
Normal file
File diff suppressed because one or more lines are too long
1
zonemaster-cli/t/usage.fake-root.data
Normal file
1
zonemaster-cli/t/usage.fake-root.data
Normal file
@@ -0,0 +1 @@
|
||||
ns1.test 192.0.2.1 {"9kfShNTLVy4wDehBPdpCXg":null}
|
||||
2
zonemaster-cli/t/usage.hints
Normal file
2
zonemaster-cli/t/usage.hints
Normal file
@@ -0,0 +1,2 @@
|
||||
. NS ns1.test
|
||||
ns1.test A 192.0.2.1
|
||||
26
zonemaster-cli/t/usage.normal.data
Normal file
26
zonemaster-cli/t/usage.normal.data
Normal file
@@ -0,0 +1,26 @@
|
||||
b.root-servers.net 2001:0500:0200:0000:0000:0000:0000:000b {}
|
||||
b.root-servers.net 199.9.14.201 {"9kfShNTLVy4wDehBPdpCXg":{"Zonemaster::Engine::Packet":{"Zonemaster::LDNS::Packet":{"data":"Q/iEAAABAAEAAAABAAAGAAEAAAYAAQABUYAAQAFhDHJvb3Qtc2VydmVycwNuZXQABW5zdGxkDHZlcmlzaWduLWdycwNjb20AeKV9KAAABwgAAAOEAAk6gAABUYAAACkE0AAAAAAAAA==","timestamp":1731580714.30933,"answerfrom":"199.9.14.201","querytime":0}}}}
|
||||
l.root-servers.net 2001:0500:009f:0000:0000:0000:0000:0042 {}
|
||||
l.root-servers.net 199.7.83.42 {"9kfShNTLVy4wDehBPdpCXg":{"Zonemaster::Engine::Packet":{"Zonemaster::LDNS::Packet":{"data":"72GEAAABAAEADQAOAAAGAAEAAAYAAQABUYAAQAFhDHJvb3Qtc2VydmVycwNuZXQABW5zdGxkDHZlcmlzaWduLWdycwNjb20AeKV9KAAABwgAAAOEAAk6gAABUYAAAAIAAQAH6QAAAsAcAAACAAEAB+kAAAQBYsAeAAACAAEAB+kAAAQBY8AeAAACAAEAB+kAAAQBZMAeAAACAAEAB+kAAAQBZcAeAAACAAEAB+kAAAQBZsAeAAACAAEAB+kAAAQBZ8AeAAACAAEAB+kAAAQBaMAeAAACAAEAB+kAAAQBacAeAAACAAEAB+kAAAQBasAeAAACAAEAB+kAAAQBa8AeAAACAAEAB+kAAAQBbMAeAAACAAEAB+kAAAQBbcAewBwAAQABAAfpAAAExikABMB0AAEAAQAH6QAABKr3qgLAgwABAAEAB+kAAATAIQQMwJIAAQABAAfpAAAExwdbDcChAAEAAQAH6QAABMDL5grAsAABAAEAB+kAAATABQXxwL8AAQABAAfpAAAEwHAkBMDOAAEAAQAH6QAABMZhvjXA3QABAAEAB+kAAATAJJQRwOwAAQABAAfpAAAEwDqAHsD7AAEAAQAH6QAABMEADoHBCgABAAEAB+kAAATHB1MqwRkAAQABAAfpAAAEygwbIQAAKRAAAAAAAAAA","querytime":0,"answerfrom":"199.7.83.42","timestamp":1731580714.6482}}}}
|
||||
h.root-servers.net 198.97.190.53 {"9kfShNTLVy4wDehBPdpCXg":{"Zonemaster::Engine::Packet":{"Zonemaster::LDNS::Packet":{"querytime":0,"timestamp":1731580714.53711,"answerfrom":"198.97.190.53","data":"jU+EAAABAAEADQAOAAAGAAEAAAYAAQABUYAAQAFhDHJvb3Qtc2VydmVycwNuZXQABW5zdGxkDHZlcmlzaWduLWdycwNjb20AeKV9KAAABwgAAAOEAAk6gAABUYAAAAIAAQAH6QAAAsAcAAACAAEAB+kAAAQBYsAeAAACAAEAB+kAAAQBY8AeAAACAAEAB+kAAAQBZMAeAAACAAEAB+kAAAQBZcAeAAACAAEAB+kAAAQBZsAeAAACAAEAB+kAAAQBZ8AeAAACAAEAB+kAAAQBaMAeAAACAAEAB+kAAAQBacAeAAACAAEAB+kAAAQBasAeAAACAAEAB+kAAAQBa8AeAAACAAEAB+kAAAQBbMAeAAACAAEAB+kAAAQBbcAewBwAAQABAAfpAAAExikABMB0AAEAAQAH6QAABKr3qgLAgwABAAEAB+kAAATAIQQMwJIAAQABAAfpAAAExwdbDcChAAEAAQAH6QAABMDL5grAsAABAAEAB+kAAATABQXxwL8AAQABAAfpAAAEwHAkBMDOAAEAAQAH6QAABMZhvjXA3QABAAEAB+kAAATAJJQRwOwAAQABAAfpAAAEwDqAHsD7AAEAAQAH6QAABMEADoHBCgABAAEAB+kAAATHB1MqwRkAAQABAAfpAAAEygwbIQAAKQTQAAAAAAAA"}}}}
|
||||
h.root-servers.net 2001:0500:0001:0000:0000:0000:0000:0053 {}
|
||||
j.root-servers.net 2001:0503:0c27:0000:0000:0000:0002:0030 {}
|
||||
j.root-servers.net 192.58.128.30 {"9kfShNTLVy4wDehBPdpCXg":{"Zonemaster::Engine::Packet":{"Zonemaster::LDNS::Packet":{"querytime":0,"answerfrom":"192.58.128.30","timestamp":1731580714.58295,"data":"R7KEAAABAAEADQAOAAAGAAEAAAYAAQABUYAAQAFhDHJvb3Qtc2VydmVycwNuZXQABW5zdGxkDHZlcmlzaWduLWdycwNjb20AeKV9KAAABwgAAAOEAAk6gAABUYAAAAIAAQAH6QAAAsAcAAACAAEAB+kAAAQBYsAeAAACAAEAB+kAAAQBY8AeAAACAAEAB+kAAAQBZMAeAAACAAEAB+kAAAQBZcAeAAACAAEAB+kAAAQBZsAeAAACAAEAB+kAAAQBZ8AeAAACAAEAB+kAAAQBaMAeAAACAAEAB+kAAAQBacAeAAACAAEAB+kAAAQBasAeAAACAAEAB+kAAAQBa8AeAAACAAEAB+kAAAQBbMAeAAACAAEAB+kAAAQBbcAewBwAAQABAAfpAAAExikABMB0AAEAAQAH6QAABKr3qgLAgwABAAEAB+kAAATAIQQMwJIAAQABAAfpAAAExwdbDcChAAEAAQAH6QAABMDL5grAsAABAAEAB+kAAATABQXxwL8AAQABAAfpAAAEwHAkBMDOAAEAAQAH6QAABMZhvjXA3QABAAEAB+kAAATAJJQRwOwAAQABAAfpAAAEwDqAHsD7AAEAAQAH6QAABMEADoHBCgABAAEAB+kAAATHB1MqwRkAAQABAAfpAAAEygwbIQAAKQXAAAAAAAAA"}}}}
|
||||
f.root-servers.net 192.5.5.241 {"9kfShNTLVy4wDehBPdpCXg":{"Zonemaster::Engine::Packet":{"Zonemaster::LDNS::Packet":{"querytime":0,"timestamp":1731580714.41004,"answerfrom":"192.5.5.241","data":"1CWEAAABAAEADQAbAAAGAAEAAAYAAQABUYAAQAFhDHJvb3Qtc2VydmVycwNuZXQABW5zdGxkDHZlcmlzaWduLWdycwNjb20AeKV9KAAABwgAAAOEAAk6gAABUYAAAAIAAQAH6QAABAFjwB4AAAIAAQAH6QAABAFlwB4AAAIAAQAH6QAABAFrwB4AAAIAAQAH6QAABAFswB4AAAIAAQAH6QAABAFkwB4AAAIAAQAH6QAAAsAcAAACAAEAB+kAAAQBYsAeAAACAAEAB+kAAAQBacAeAAACAAEAB+kAAAQBZsAeAAACAAEAB+kAAAQBaMAeAAACAAEAB+kAAAQBZ8AeAAACAAEAB+kAAAQBasAeAAACAAEAB+kAAAQBbcAewGcAAQABAAfpAAAEwCEEDMBnABwAAQAH6QAAECABBQAAAgAAAAAAAAAAAAzAdgABAAEAB+kAAATAy+YKwHYAHAABAAfpAAAQIAEFAACoAAAAAAAAAAAADsCFAAEAAQAH6QAABMEADoHAhQAcAAEAB+kAABAgAQf9AAAAAAAAAAAAAAABwJQAAQABAAfpAAAExwdTKsCUABwAAQAH6QAAECABBQAAnwAAAAAAAAAAAELAowABAAEAB+kAAATHB1sNwKMAHAABAAfpAAAQIAEFAAAtAAAAAAAAAAAADcAcAAEAAQAH6QAABMYpAATAHAAcAAEAB+kAABAgAQUDuj4AAAAAAAAAAgAwwL8AAQABAAfpAAAEqveqAsC/ABwAAQAH6QAAECgBAbgAEAAAAAAAAAAAAAvAzgABAAEAB+kAAATAJJQRwM4AHAABAAfpAAAQIAEH/gAAAAAAAAAAAAAAU8DdAAEAAQAH6QAABMAFBfHA3QAcAAEAB+kAABAgAQUAAC8AAAAAAAAAAAAPwOwAAQABAAfpAAAExmG+NcDsABwAAQAH6QAAECABBQAAAQAAAAAAAAAAAFPA+wABAAEAB+kAAATAcCQEwPsAHAABAAfpAAAQIAEFAAASAAAAAAAAAAANDcEKAAEAAQAH6QAABMA6gB7BCgAcAAEAB+kAABAgAQUDDCcAAAAAAAAAAgAwwRkAAQABAAfpAAAEygwbIcEZABwAAQAH6QAAECABDcMAAAAAAAAAAAAAADUAACn//wAAAAAAAA=="}}}}
|
||||
f.root-servers.net 2001:0500:002f:0000:0000:0000:0000:000f {}
|
||||
k.root-servers.net 193.0.14.129 {"9kfShNTLVy4wDehBPdpCXg":{"Zonemaster::Engine::Packet":{"Zonemaster::LDNS::Packet":{"data":"EJGEAAABAAEAAAABAAAGAAEAAAYAAQABUYAAQAFhDHJvb3Qtc2VydmVycwNuZXQABW5zdGxkDHZlcmlzaWduLWdycwNjb20AeKV9KAAABwgAAAOEAAk6gAABUYAAACkE0AAAAAAAAA==","timestamp":1731580714.61398,"answerfrom":"193.0.14.129","querytime":0}}}}
|
||||
k.root-servers.net 2001:07fd:0000:0000:0000:0000:0000:0001 {}
|
||||
e.root-servers.net 192.203.230.10 {"9kfShNTLVy4wDehBPdpCXg":{"Zonemaster::Engine::Packet":{"Zonemaster::LDNS::Packet":{"data":"mDyEAAABAAEADQAOAAAGAAEAAAYAAQABUYAAQAFhDHJvb3Qtc2VydmVycwNuZXQABW5zdGxkDHZlcmlzaWduLWdycwNjb20AeKV9KAAABwgAAAOEAAk6gAABUYAAAAIAAQAH6QAAAsAcAAACAAEAB+kAAAQBYsAeAAACAAEAB+kAAAQBY8AeAAACAAEAB+kAAAQBZMAeAAACAAEAB+kAAAQBZcAeAAACAAEAB+kAAAQBZsAeAAACAAEAB+kAAAQBZ8AeAAACAAEAB+kAAAQBaMAeAAACAAEAB+kAAAQBacAeAAACAAEAB+kAAAQBasAeAAACAAEAB+kAAAQBa8AeAAACAAEAB+kAAAQBbMAeAAACAAEAB+kAAAQBbcAewBwAAQABAAfpAAAExikABMB0AAEAAQAH6QAABKr3qgLAgwABAAEAB+kAAATAIQQMwJIAAQABAAfpAAAExwdbDcChAAEAAQAH6QAABMDL5grAsAABAAEAB+kAAATABQXxwL8AAQABAAfpAAAEwHAkBMDOAAEAAQAH6QAABMZhvjXA3QABAAEAB+kAAATAJJQRwOwAAQABAAfpAAAEwDqAHsD7AAEAAQAH6QAABMEADoHBCgABAAEAB+kAAATHB1MqwRkAAQABAAfpAAAEygwbIQAAKRAAAAAAAAAA","querytime":0,"timestamp":1731580714.3888,"answerfrom":"192.203.230.10"}}}}
|
||||
e.root-servers.net 2001:0500:00a8:0000:0000:0000:0000:000e {}
|
||||
d.root-servers.net 199.7.91.13 {"9kfShNTLVy4wDehBPdpCXg":{"Zonemaster::Engine::Packet":{"Zonemaster::LDNS::Packet":{"answerfrom":"199.7.91.13","timestamp":1731580714.37701,"querytime":0,"data":"ZOyEAAABAAEADQAOAAAGAAEAAAYAAQABUYAAQAFhDHJvb3Qtc2VydmVycwNuZXQABW5zdGxkDHZlcmlzaWduLWdycwNjb20AeKV9KAAABwgAAAOEAAk6gAABUYAAAAIAAQAH6QAAAsAcAAACAAEAB+kAAAQBYsAeAAACAAEAB+kAAAQBY8AeAAACAAEAB+kAAAQBZMAeAAACAAEAB+kAAAQBZcAeAAACAAEAB+kAAAQBZsAeAAACAAEAB+kAAAQBZ8AeAAACAAEAB+kAAAQBaMAeAAACAAEAB+kAAAQBacAeAAACAAEAB+kAAAQBasAeAAACAAEAB+kAAAQBa8AeAAACAAEAB+kAAAQBbMAeAAACAAEAB+kAAAQBbcAewBwAAQABAAfpAAAExikABMB0AAEAAQAH6QAABKr3qgLAgwABAAEAB+kAAATAIQQMwJIAAQABAAfpAAAExwdbDcChAAEAAQAH6QAABMDL5grAsAABAAEAB+kAAATABQXxwL8AAQABAAfpAAAEwHAkBMDOAAEAAQAH6QAABMZhvjXA3QABAAEAB+kAAATAJJQRwOwAAQABAAfpAAAEwDqAHsD7AAEAAQAH6QAABMEADoHBCgABAAEAB+kAAATHB1MqwRkAAQABAAfpAAAEygwbIQAAKQWqAAAAAAAA"}}}}
|
||||
d.root-servers.net 2001:0500:002d:0000:0000:0000:0000:000d {}
|
||||
g.root-servers.net 2001:0500:0012:0000:0000:0000:0000:0d0d {}
|
||||
g.root-servers.net 192.112.36.4 {"9kfShNTLVy4wDehBPdpCXg":{"Zonemaster::Engine::Packet":{"Zonemaster::LDNS::Packet":{"querytime":0,"timestamp":1731580714.42995,"answerfrom":"192.112.36.4","data":"8aWEAAABAAEAAAABAAAGAAEAAAYAAQABUYAAQAFhDHJvb3Qtc2VydmVycwNuZXQABW5zdGxkDHZlcmlzaWduLWdycwNjb20AeKV9KAAABwgAAAOEAAk6gAABUYAAACkE0AAAAAAAAA=="}}}}
|
||||
m.root-servers.net 2001:0dc3:0000:0000:0000:0000:0000:0035 {}
|
||||
m.root-servers.net 202.12.27.33 {"9kfShNTLVy4wDehBPdpCXg":{"Zonemaster::Engine::Packet":{"Zonemaster::LDNS::Packet":{"timestamp":1731580714.65964,"answerfrom":"202.12.27.33","querytime":0,"data":"reuEAAABAAEAAAABAAAGAAEAAAYAAQABUYAAQAFhDHJvb3Qtc2VydmVycwNuZXQABW5zdGxkDHZlcmlzaWduLWdycwNjb20AeKV9KAAABwgAAAOEAAk6gAABUYAAACkE0AAAAAAAAA=="}}}}
|
||||
a.root-servers.net 198.41.0.4 {"9kfShNTLVy4wDehBPdpCXg":{"Zonemaster::Engine::Packet":{"Zonemaster::LDNS::Packet":{"answerfrom":"198.41.0.4","timestamp":1731580714.27699,"querytime":0,"data":"9WaEAAABAAEADQALAAAGAAEAAAYAAQABUYAAQAFhDHJvb3Qtc2VydmVycwNuZXQABW5zdGxkDHZlcmlzaWduLWdycwNjb20AeKV9KAAABwgAAAOEAAk6gAABUYAAAAIAAQAH6QAABAFswB4AAAIAAQAH6QAABAFqwB4AAAIAAQAH6QAABAFmwB4AAAIAAQAH6QAABAFowB4AAAIAAQAH6QAABAFkwB4AAAIAAQAH6QAABAFiwB4AAAIAAQAH6QAABAFrwB4AAAIAAQAH6QAABAFpwB4AAAIAAQAH6QAABAFtwB4AAAIAAQAH6QAABAFlwB4AAAIAAQAH6QAABAFnwB4AAAIAAQAH6QAABAFjwB4AAAIAAQAH6QAAAsAcwGcAAQABAAfpAAAExwdTKsBnABwAAQAH6QAAECABBQAAnwAAAAAAAAAAAELAdgABAAEAB+kAAATAOoAewHYAHAABAAfpAAAQIAEFAwwnAAAAAAAAAAIAMMCFAAEAAQAH6QAABMAFBfHAhQAcAAEAB+kAABAgAQUAAC8AAAAAAAAAAAAPwJQAAQABAAfpAAAExmG+NcCUABwAAQAH6QAAECABBQAAAQAAAAAAAAAAAFPAowABAAEAB+kAAATHB1sNwLIAAQABAAfpAAAEqveqAgAAKRAAAAAAAAAA"}}},"UzfnoYKACE71u6V/QQ17nw":{"Zonemaster::Engine::Packet":{"Zonemaster::LDNS::Packet":{"data":"UCOEAAABAA0AAAANAAACAAEAAAIAAQAH6QAAFAFsDHJvb3Qtc2VydmVycwNuZXQAAAACAAEAB+kAAAQBasAeAAACAAEAB+kAAAQBZsAeAAACAAEAB+kAAAQBaMAeAAACAAEAB+kAAAQBZMAeAAACAAEAB+kAAAQBYsAeAAACAAEAB+kAAAQBa8AeAAACAAEAB+kAAAQBacAeAAACAAEAB+kAAAQBbcAeAAACAAEAB+kAAAQBZcAeAAACAAEAB+kAAAQBZ8AeAAACAAEAB+kAAAQBY8AeAAACAAEAB+kAAAQBYcAewBwAAQABAAfpAAAExwdTKsAcABwAAQAH6QAAECABBQAAnwAAAAAAAAAAAELAOwABAAEAB+kAAATAOoAewDsAHAABAAfpAAAQIAEFAwwnAAAAAAAAAAIAMMBKAAEAAQAH6QAABMAFBfHASgAcAAEAB+kAABAgAQUAAC8AAAAAAAAAAAAPwFkAAQABAAfpAAAExmG+NcBZABwAAQAH6QAAECABBQAAAQAAAAAAAAAAAFPAaAABAAEAB+kAAATHB1sNwGgAHAABAAfpAAAQIAEFAAAtAAAAAAAAAAAADcB3AAEAAQAH6QAABKr3qgLAdwAcAAEAB+kAABAoAQG4ABAAAAAAAAAAAAALAAApEAAAAAAAAAA=","timestamp":1731580714.23954,"answerfrom":"198.41.0.4","querytime":0}}}}
|
||||
a.root-servers.net 2001:0503:ba3e:0000:0000:0000:0002:0030 {}
|
||||
i.root-servers.net 2001:07fe:0000:0000:0000:0000:0000:0053 {}
|
||||
i.root-servers.net 192.36.148.17 {"9kfShNTLVy4wDehBPdpCXg":{"Zonemaster::Engine::Packet":{"Zonemaster::LDNS::Packet":{"data":"tQyEAAABAAEAAAABAAAGAAEAAAYAAQABUYAAQAFhDHJvb3Qtc2VydmVycwNuZXQABW5zdGxkDHZlcmlzaWduLWdycwNjb20AeKV9KAAABwgAAAOEAAk6gAABUYAAACkE0AAAAAAAAA==","querytime":0,"timestamp":1731580714.57324,"answerfrom":"192.36.148.17"}}}}
|
||||
c.root-servers.net 192.33.4.12 {"9kfShNTLVy4wDehBPdpCXg":{"Zonemaster::Engine::Packet":{"Zonemaster::LDNS::Packet":{"data":"b2iEAAABAAEAAAABAAAGAAEAAAYAAQABUYAAQAFhDHJvb3Qtc2VydmVycwNuZXQABW5zdGxkDHZlcmlzaWduLWdycwNjb20AeKV9KAAABwgAAAOEAAk6gAABUYAAACkE0AAAAAAAAA==","querytime":0,"answerfrom":"192.33.4.12","timestamp":1731580714.34358}}}}
|
||||
c.root-servers.net 2001:0500:0002:0000:0000:0000:0000:000c {}
|
||||
20
zonemaster-cli/t/usage.profile
Normal file
20
zonemaster-cli/t/usage.profile
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"net":{
|
||||
"ipv4": false,
|
||||
"ipv6": false
|
||||
},
|
||||
"resolver":{
|
||||
"source4": "192.0.2.1",
|
||||
"source6": "2001:db8::1"
|
||||
},
|
||||
"test_levels" : {
|
||||
"BASIC" : {
|
||||
"B01_CHILD_FOUND" : "NOTICE",
|
||||
"B01_ROOT_HAS_NO_PARENT" : "WARNING",
|
||||
"B02_AUTH_RESPONSE_SOA" : "ERROR"
|
||||
},
|
||||
"SYSTEM" : {
|
||||
"GLOBAL_VERSION" : "INFO"
|
||||
}
|
||||
}
|
||||
}
|
||||
712
zonemaster-cli/t/usage.t
Normal file
712
zonemaster-cli/t/usage.t
Normal file
@@ -0,0 +1,712 @@
|
||||
#!perl
|
||||
use 5.16.0;
|
||||
use warnings;
|
||||
use utf8;
|
||||
use Test::More;
|
||||
|
||||
use Config '%Config';
|
||||
use Encode qw( decode_utf8 );
|
||||
use File::Basename qw( dirname );
|
||||
use File::Slurp qw( read_file write_file );
|
||||
use File::Spec::Functions qw( catfile );
|
||||
use File::Temp qw( tempdir );
|
||||
use IPC::Open3;
|
||||
use JSON::XS;
|
||||
use POSIX;
|
||||
use Readonly;
|
||||
use Symbol qw( gensym );
|
||||
use Test::Differences;
|
||||
use Zonemaster::CLI;
|
||||
use JSON::Validator;
|
||||
|
||||
# Force locale C for these unit tests. They depend on the print outs not being
|
||||
# translated. See zonemaster/zonemaster-cli/issues/438 and
|
||||
# https://github.com/zonemaster/zonemaster-cli/issues/438#issuecomment-2996235684
|
||||
$ENV{LC_ALL} = "C.UTF-8";
|
||||
delete $ENV{LANG};
|
||||
delete $ENV{LANGUAGE};
|
||||
|
||||
|
||||
# CONSTANTS
|
||||
|
||||
Readonly::Array my @SIG_NAMES => do {
|
||||
my @sig_names;
|
||||
@sig_names[ split ' ', $Config{sig_num} ] = split ' ', $Config{sig_name};
|
||||
@sig_names;
|
||||
};
|
||||
|
||||
Readonly::Scalar my $PATH_WRAPPER => catfile( dirname( __FILE__ ), 'usage.wrapper.pl' );
|
||||
Readonly::Scalar my $PATH_NORMAL_DATAFILE => catfile( dirname( __FILE__ ), 'usage.normal.data' );
|
||||
Readonly::Scalar my $PATH_FAKE_DATA_DATAFILE => catfile( dirname( __FILE__ ), 'usage.fake-data.data' );
|
||||
Readonly::Scalar my $PATH_FAKE_ROOT_DATAFILE => catfile( dirname( __FILE__ ), 'usage.fake-root.data' );
|
||||
Readonly::Array my @PERL => do {
|
||||
# Detect whether Devel::Cover is running
|
||||
my $is_covering = !!( eval 'Devel::Cover::get_coverage()' );
|
||||
note $is_covering ? 'Devel::Cover running' : 'Devel::Cover not covering';
|
||||
( $^X, $is_covering ? ( '-MDevel::Cover=-silent,1' ) : () )
|
||||
};
|
||||
|
||||
# MUTABLE GLOBAL VARIABLES
|
||||
|
||||
our $test_datafile;
|
||||
|
||||
# SETUP
|
||||
|
||||
if ( $ENV{ZONEMASTER_RECORD} ) {
|
||||
write_file $PATH_NORMAL_DATAFILE, '';
|
||||
write_file $PATH_FAKE_DATA_DATAFILE, '';
|
||||
write_file $PATH_FAKE_ROOT_DATAFILE, '';
|
||||
}
|
||||
|
||||
# HELPERS
|
||||
|
||||
sub json_schema {
|
||||
my ( $schema ) = @_;
|
||||
my $validator = JSON::Validator->new;
|
||||
$validator->schema( $schema );
|
||||
return $validator;
|
||||
}
|
||||
|
||||
sub check_success {
|
||||
my ( $name, $args, $predicate ) = @_;
|
||||
|
||||
subtest $name => sub {
|
||||
my $result = _run_zonemaster_cli( $test_datafile, @$args );
|
||||
|
||||
my $stdout = delete $result->{stdout};
|
||||
my $stderr = delete $result->{stderr};
|
||||
my $exitstatus = delete $result->{exitstatus};
|
||||
|
||||
if ( $stderr ne '' ) {
|
||||
note "stderr:\n$stderr" =~ s/\n/\n /gr;
|
||||
}
|
||||
|
||||
if ( ref $predicate eq 'CODE' ) {
|
||||
if ( $predicate->( $stdout ) ) {
|
||||
pass 'expected stdout (sub)';
|
||||
}
|
||||
else {
|
||||
fail 'expected stdout (sub)';
|
||||
diag "actual stdout:\n$stdout" =~ s/\n/\n /gr;
|
||||
}
|
||||
}
|
||||
elsif ( ref $predicate eq 'Regexp' ) {
|
||||
like $stdout, $predicate, 'expected stdout (regex)';
|
||||
}
|
||||
elsif ( blessed $predicate && blessed $predicate eq 'JSON::Validator' ) {
|
||||
my @items = parse_json_stream( $stdout );
|
||||
my @errors = $predicate->validate( [@items] );
|
||||
if ( !eq_or_diff \@errors, [], "schema validation" ) {
|
||||
diag "actual stdout:\n$stdout" =~ s/\n/\n /gr;
|
||||
}
|
||||
}
|
||||
else {
|
||||
BAIL_OUT( "unrecognized predicate type" );
|
||||
}
|
||||
|
||||
is $exitstatus, $Zonemaster::CLI::EXIT_SUCCESS, 'success exit status';
|
||||
}; ## end sub
|
||||
} ## end sub check_success
|
||||
|
||||
sub check_success_report {
|
||||
my ( $name, $args, $predicates ) = @_;
|
||||
|
||||
subtest $name => sub {
|
||||
check_success 'normal mode', $args, $predicates->{text};
|
||||
|
||||
check_success 'raw mode', $args, $predicates->{text};
|
||||
|
||||
check_success 'json mode', [ '--json', @$args ],
|
||||
json_schema(
|
||||
{
|
||||
type => "array",
|
||||
items => $predicates->{json},
|
||||
}
|
||||
);
|
||||
|
||||
check_success 'json-stream mode', [ '--json-stream', @$args ],
|
||||
json_schema(
|
||||
{
|
||||
type => "array",
|
||||
contains => $predicates->{json},
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
sub check_usage_error {
|
||||
my ( $name, $args, $error_pattern ) = @_;
|
||||
|
||||
subtest $name => sub {
|
||||
my $result = _run_zonemaster_cli( undef, @$args );
|
||||
|
||||
my $stderr = delete $result->{stderr};
|
||||
like $stderr, $error_pattern, 'expected error message';
|
||||
|
||||
eq_or_diff(
|
||||
$result,
|
||||
{
|
||||
stdout => '',
|
||||
exitstatus => $Zonemaster::CLI::EXIT_USAGE_ERROR,
|
||||
},
|
||||
'no stdout and usage error exit code'
|
||||
) or diag "stderr:\n$stderr" =~ s/\n/\n /gr;
|
||||
};
|
||||
}
|
||||
|
||||
sub parse_json_stream {
|
||||
my ( $text ) = @_;
|
||||
|
||||
my $decoder = JSON::XS->new;
|
||||
|
||||
my @items;
|
||||
while ( 1 ) {
|
||||
$text =~ s/^\s+//;
|
||||
if ( $text eq '' ) {
|
||||
last;
|
||||
}
|
||||
|
||||
my ( $item, $len ) = $decoder->decode_prefix( $text );
|
||||
|
||||
push @items, $item;
|
||||
$text = substr $text, $len;
|
||||
$text =~ s/^\s+//;
|
||||
}
|
||||
return @items;
|
||||
} ## end sub parse_json_stream
|
||||
|
||||
sub has_locale {
|
||||
my ( $locale ) = @_;
|
||||
my $old_locale = setlocale( LC_CTYPE );
|
||||
my $success = defined setlocale( LC_CTYPE, $locale );
|
||||
setlocale( LC_CTYPE, $old_locale );
|
||||
return $success;
|
||||
}
|
||||
|
||||
sub _run_zonemaster_cli {
|
||||
my ( $datafile, @args ) = @_;
|
||||
|
||||
my @cmd = ( @PERL, $PATH_WRAPPER );
|
||||
if ( defined $datafile ) {
|
||||
if ( $ENV{ZONEMASTER_RECORD} ) {
|
||||
push @cmd, '--record';
|
||||
}
|
||||
push @cmd, $datafile;
|
||||
}
|
||||
push @cmd, '--', @args;
|
||||
|
||||
my $pid = open3( my $stdin, my $stdout, my $stderr = gensym, @cmd );
|
||||
waitpid( $pid, 0 );
|
||||
my $exitcode = $?;
|
||||
|
||||
if ( POSIX::WIFEXITED( $exitcode ) ) {
|
||||
local $/ = undef;
|
||||
return {
|
||||
stdout => scalar <$stdout>,
|
||||
stderr => scalar <$stderr>,
|
||||
exitstatus => POSIX::WEXITSTATUS( $exitcode ),
|
||||
};
|
||||
}
|
||||
elsif ( POSIX::WIFSIGNALED( $exitcode ) ) {
|
||||
die "child process terminated by signal: " . $SIG_NAMES[ POSIX::WTERMSIG( $exitcode ) ];
|
||||
}
|
||||
elsif ( POSIX::WIFSTOPPED( $exitcode ) ) {
|
||||
die "child process stopped by signal: " . $SIG_NAMES[ POSIX::WSTOPSIG( $exitcode ) ];
|
||||
}
|
||||
else {
|
||||
die "unrecognized exit code $exitcode";
|
||||
}
|
||||
} ## end sub _run_zonemaster_cli
|
||||
|
||||
# TESTS
|
||||
|
||||
do {
|
||||
local $test_datafile = $PATH_NORMAL_DATAFILE;
|
||||
note "TESTS USING $test_datafile FOR RECORDED DATA:";
|
||||
|
||||
check_success 'normal table output', [ '--test=basic01', '--level=INFO', '.' ], qr{
|
||||
^
|
||||
Seconds \s+ Level \s+ Message \n
|
||||
=+ \s =+ \s =+ \n
|
||||
\s* \Q0.00\E \s+ INFO \s+ .* \s [v0-9.]+ \s .* \n
|
||||
}msx;
|
||||
|
||||
check_success 'normal table output, no optional fields',
|
||||
[ '--test=basic01', '--level=INFO', '--no-time', '--no-show-level', '.' ], qr{
|
||||
^
|
||||
Message \n
|
||||
=+ \n
|
||||
Using .* \n
|
||||
}msx;
|
||||
|
||||
check_success 'normal table output, no optional fields, using underscore alias',
|
||||
[ '--test=basic01', '--level=INFO', '--no-time', '--no-show_level', '.' ], qr{
|
||||
^
|
||||
Message \n
|
||||
=+ \n
|
||||
Using .* \n
|
||||
}msx;
|
||||
|
||||
check_success 'normal table output, all fields',
|
||||
[ '--test=basic01', '--level=INFO', '--show-module', '--show-testcase', '.' ], qr{
|
||||
^
|
||||
Seconds \s+ Level \s+ Module \s+ Testcase \s+ Message \n
|
||||
=+ \s =+ \s =+ \s =+ \s =+ \n
|
||||
\s* \Q0.00\E \s+ INFO \s+ System \s+ Unspecified \s+ Using .* \n
|
||||
}msx;
|
||||
|
||||
check_success 'normal table output, all fields, using underscore aliases',
|
||||
[ '--test=basic01', '--level=INFO', '--show_module', '--show_testcase', '.' ], qr{
|
||||
^
|
||||
Seconds \s+ Level \s+ Module \s+ Testcase \s+ Message \n
|
||||
=+ \s =+ \s =+ \s =+ \s =+ \n
|
||||
\s* \Q0.00\E \s+ INFO \s+ System \s+ Unspecified \s+ Using .* \n
|
||||
}msx;
|
||||
|
||||
check_success '--encoding', [ '--test=basic01', '--json', '--encoding', 'foobar', '.' ], qr{
|
||||
\Q{"results":[]}\E
|
||||
}msx;
|
||||
|
||||
check_success '--json', [ '--test=basic01', '--json', '.' ], qr{
|
||||
\Q{"results":[]}\E
|
||||
}msx;
|
||||
|
||||
check_success '--json-stream', [ '--test=basic01', '--json-stream', '--level=INFO', '.' ], sub {
|
||||
my $found = 0;
|
||||
for my $item ( parse_json_stream( $_[0] ) ) {
|
||||
if ( $item->{tag} eq 'GLOBAL_VERSION' ) {
|
||||
if ( $item->{message} !~ /^Using / ) {
|
||||
return 0;
|
||||
}
|
||||
$found = 1;
|
||||
}
|
||||
}
|
||||
return $found;
|
||||
};
|
||||
|
||||
check_success '--json_stream', [ '--test=basic01', '--json_stream', '--level=INFO', '.' ], sub {
|
||||
my $found = 0;
|
||||
for my $item ( parse_json_stream( $_[0] ) ) {
|
||||
if ( $item->{tag} eq 'GLOBAL_VERSION' ) {
|
||||
if ( $item->{message} !~ /^Using / ) {
|
||||
return 0;
|
||||
}
|
||||
$found = 1;
|
||||
}
|
||||
}
|
||||
return $found;
|
||||
};
|
||||
|
||||
check_success '--raw', [ '--test=basic01', '--level=INFO', '--raw', '.' ], qr{
|
||||
^
|
||||
\s* \Q0.00\E \s+ INFO \s+ GLOBAL_VERSION \s+ version= [v0-9.]+ \n
|
||||
}msx;
|
||||
|
||||
SKIP: {
|
||||
skip 'sv_SE.UTF-8 locale is unavailable', 5
|
||||
if !has_locale( 'sv_SE.UTF-8' );
|
||||
|
||||
check_success '--json-stream --no-raw',
|
||||
[ '--test=basic01', '--json-stream', '--no-raw', '--locale=sv_SE.UTF-8', '--level=INFO', '.' ], sub {
|
||||
my $found = 0;
|
||||
for my $item ( parse_json_stream( decode_utf8( $_[0] ) ) ) {
|
||||
if ( $item->{tag} eq 'GLOBAL_VERSION' ) {
|
||||
if ( $item->{message} !~ qr{^Använder } ) {
|
||||
return 0;
|
||||
}
|
||||
$found = 1;
|
||||
}
|
||||
}
|
||||
return $found;
|
||||
};
|
||||
|
||||
check_success '--json-stream --json-translate',
|
||||
[ '--test=basic01', '--json-stream', '--json-translate', '--locale=sv_SE.UTF-8', '--level=INFO', '.' ], sub {
|
||||
my $found = 0;
|
||||
for my $item ( parse_json_stream( decode_utf8( $_[0] ) ) ) {
|
||||
if ( $item->{tag} eq 'GLOBAL_VERSION' ) {
|
||||
if ( $item->{message} !~ qr{^Använder } ) {
|
||||
return 0;
|
||||
}
|
||||
$found = 1;
|
||||
}
|
||||
}
|
||||
return $found;
|
||||
};
|
||||
|
||||
check_success '--json-stream --no-raw --locale',
|
||||
[ '--test=basic01', '--json-stream', '--no-raw', '--locale=sv_SE.UTF-8', '--level=INFO', '.' ], sub {
|
||||
my $found = 0;
|
||||
for my $item ( parse_json_stream( decode_utf8( $_[0] ) ) ) {
|
||||
if ( $item->{tag} eq 'GLOBAL_VERSION' ) {
|
||||
if ( $item->{message} !~ qr{^Använder } ) {
|
||||
return 0;
|
||||
}
|
||||
$found = 1;
|
||||
}
|
||||
}
|
||||
return $found;
|
||||
};
|
||||
|
||||
check_success '--json-stream --json-translate --locale',
|
||||
[ '--test=basic01', '--json-stream', '--no-raw', '--locale=sv_SE.UTF-8', '--level=INFO', '.' ], sub {
|
||||
my $found = 0;
|
||||
for my $item ( parse_json_stream( decode_utf8( $_[0] ) ) ) {
|
||||
if ( $item->{tag} eq 'GLOBAL_VERSION' ) {
|
||||
if ( $item->{message} !~ qr{^Använder } ) {
|
||||
return 0;
|
||||
}
|
||||
$found = 1;
|
||||
}
|
||||
}
|
||||
return $found;
|
||||
};
|
||||
|
||||
check_success '--locale', [ '--test=basic01', '--locale=sv_SE.UTF-8', '.' ], qr{
|
||||
\QSer OK ut.\E
|
||||
}msx;
|
||||
} ## end SKIP:
|
||||
|
||||
check_success_report '--count', [ '--test=basic01', '--count', '.' ], {
|
||||
text => qr{
|
||||
\QLooks OK.\E
|
||||
.*
|
||||
Level \s+ \QNumber of log entries\E
|
||||
.*
|
||||
INFO \s+ \d+
|
||||
.*
|
||||
DEBUG \s+ \d+
|
||||
.*
|
||||
Level \s+ \QMessage tag\E \s+ \QCount\E
|
||||
.*
|
||||
INFO \s+ \w+ \s+ \d+
|
||||
.*
|
||||
}msx,
|
||||
json => {
|
||||
type => "object",
|
||||
required => ["count"],
|
||||
patternProperties => {
|
||||
'^[A-Z]+[0-9]*$' => {
|
||||
type => "integer",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
check_success_report '--nstimes', [ '--test=basic01', '--nstimes', '.' ], {
|
||||
text => qr{
|
||||
\QLooks OK.\E
|
||||
.*
|
||||
\QName servers\E \s+ Max \s+ Min \s+ Avg \s+ Stddev \s+ Median \s+ Total \s+ Count
|
||||
.*
|
||||
\QChild zone\E
|
||||
.*
|
||||
\QParent zone\E
|
||||
.*
|
||||
Other
|
||||
.*
|
||||
\QGrand total\E \s+ \d+
|
||||
}msx,
|
||||
json => {
|
||||
type => "object",
|
||||
required => ["nstimes"],
|
||||
properties => {
|
||||
nstimes => {
|
||||
type => "array",
|
||||
items => {
|
||||
type => "object",
|
||||
properties => {
|
||||
child => {
|
||||
type => "array",
|
||||
items => {
|
||||
type => "object",
|
||||
required => [qw( avg max median min ns stddev total count)],
|
||||
},
|
||||
},
|
||||
parent => {
|
||||
type => "array",
|
||||
items => {
|
||||
type => "object",
|
||||
required => [qw( avg max median min ns stddev total count)],
|
||||
},
|
||||
},
|
||||
other => {
|
||||
type => "array",
|
||||
items => {
|
||||
type => "object",
|
||||
required => [qw( avg max median min ns stddev total count)],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
check_success_report '--elapsed', [ '--test=basic01', '--elapsed', '.' ], {
|
||||
text => qr{
|
||||
\QLooks OK.\E
|
||||
.*
|
||||
\QTotal test run time:\E
|
||||
}msx,
|
||||
json => {
|
||||
type => "object",
|
||||
required => ["elapsed"],
|
||||
properties => {
|
||||
elapsed => {
|
||||
type => "number",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
check_success '--level',
|
||||
[ '--profile=t/usage.profile', '--ipv4', '--sourceaddr4', '', '--test=basic', '--raw', '--level=notice', '.' ],
|
||||
sub {
|
||||
my $stdout = $_[0];
|
||||
|
||||
return ( $stdout =~ qr{NOTICE .* WARNING .* ERROR}msx )
|
||||
&& ( $stdout !~ qr{INFO}msx );
|
||||
};
|
||||
|
||||
check_success '--stop-level=', [ '--profile=t/usage.profile', '--stop-level=', '.' ], qr{Looks OK}i;
|
||||
|
||||
check_success '--stop-level=warning',
|
||||
[
|
||||
'--profile=t/usage.profile', '--ipv4', '--sourceaddr4', '',
|
||||
'--test=basic', '--raw', '--stop-level=warning', '.'
|
||||
],
|
||||
sub {
|
||||
my $stdout = $_[0];
|
||||
|
||||
return ( $stdout =~ qr{NOTICE .* WARNING}msx )
|
||||
&& ( $stdout !~ qr{ERROR}m );
|
||||
};
|
||||
|
||||
check_success '--stop_level',
|
||||
[
|
||||
'--profile=t/usage.profile', '--ipv4', '--sourceaddr4', '',
|
||||
'--test=basic', '--raw', '--stop_level=warning', '.'
|
||||
],
|
||||
sub {
|
||||
my $stdout = $_[0];
|
||||
|
||||
return ( $stdout =~ qr{NOTICE .* WARNING}msx )
|
||||
&& ( $stdout !~ qr{ERROR}m );
|
||||
};
|
||||
|
||||
my $tempdir = tempdir( CLEANUP => 1 );
|
||||
my $savefile = catfile( $tempdir, 'saved.data' );
|
||||
check_success 'run command', [ "--save=$savefile", '--test=basic01', '.' ], sub {
|
||||
my @saved_lines = read_file $savefile;
|
||||
my @expected_lines = read_file $PATH_NORMAL_DATAFILE;
|
||||
return scalar( @saved_lines ) == scalar( @expected_lines );
|
||||
};
|
||||
};
|
||||
|
||||
do {
|
||||
local $test_datafile = $PATH_FAKE_DATA_DATAFILE;
|
||||
note "TESTS USING $test_datafile FOR RECORDED DATA:";
|
||||
|
||||
SKIP: {
|
||||
skip 'crashing test that has never worked on replay (FIXME)', 2
|
||||
if not $ENV{ZONEMASTER_RECORD};
|
||||
|
||||
check_success '--ns', [ '--noipv6', '--raw', '--ns=ns1.a.example/9.9.9.9', 'a.se' ], qr{B02_NO_WORKING_NS};
|
||||
|
||||
check_success '--ds',
|
||||
[
|
||||
'--noipv6', '--raw', '--test=dnssec02',
|
||||
'--ds=0,8,2,0000000000000000000000000000000000000000000000000000000000000000',
|
||||
'zonemaster.net'
|
||||
],
|
||||
qr{DS02_NO_DNSKEY_FOR_DS};
|
||||
}
|
||||
};
|
||||
|
||||
do {
|
||||
local $test_datafile = $PATH_FAKE_ROOT_DATAFILE;
|
||||
note "TESTS USING $test_datafile FOR RECORDED DATA:";
|
||||
|
||||
check_success '--hints', [ '--noipv6', '--raw', '--hints=t/usage.hints', 'example.' ], qr{CANNOT_CONTINUE}i;
|
||||
};
|
||||
|
||||
do {
|
||||
local $test_datafile = undef;
|
||||
note "TESTS USING NO NETWORK AND NO FILE FOR RECORDED DATA:";
|
||||
|
||||
check_usage_error 'no domain', [], qr{must give the name of a domain to test}i;
|
||||
|
||||
check_usage_error 'too many domains', [ 'example.com', 'example.net' ],
|
||||
qr{only one domain can be given for testing}i;
|
||||
|
||||
check_usage_error 'invalid domain', ['!%~&'], qr{character not permitted}i;
|
||||
|
||||
check_usage_error 'unrecognized option', ['--foobar'], qr{unknown option}i;
|
||||
|
||||
check_usage_error '--test BAD_MODULE', [ '--test', '!%~&', 'example.' ], qr{unrecognized term '!%~&' in --test}i;
|
||||
|
||||
check_usage_error '--test UNKNOWN_MODULE/TESTCASE', [ '--test', 'foobar/foobar01', 'example.' ],
|
||||
qr{unrecognized term 'foobar/foobar01' in --test}i;
|
||||
|
||||
check_usage_error '--test MODULE/UNKNOWN_TESTCASE', [ '--test', 'basic/foobar01', 'example.' ],
|
||||
qr{unrecognized term 'basic/foobar01' in --test}i;
|
||||
|
||||
check_usage_error '--test MODULE//TESTCASE', [ '--test', 'basic//basic01', 'example.' ],
|
||||
qr{unrecognized term 'basic//basic01' in --test}i;
|
||||
|
||||
check_usage_error '--ns BAD_NAME', [ '--ns', '!%~&', 'example.' ], qr{invalid name}i;
|
||||
|
||||
check_usage_error '--ns NAME//IP', [ '--ns', 'ns1.example//192.0.2.1', 'example.' ], qr{--ns}i;
|
||||
|
||||
check_usage_error '--ns NAME/BAD_IP', [ '--ns', 'ns1.example/foobar', 'example.' ], qr{invalid ip address}i;
|
||||
|
||||
check_usage_error '--sourceaddr4', [ '--sourceaddr4', 'foobar', 'example.' ], qr{invalid value}i;
|
||||
|
||||
check_usage_error '--sourceaddr6', [ '--sourceaddr6', 'foobar', 'example.' ], qr{invalid value}i;
|
||||
|
||||
check_usage_error '--level BAD_LEVEL', [ '--level', 'foobar', 'example.' ], qr{--level}i;
|
||||
|
||||
check_usage_error '--stop-level BAD_LEVEL', [ '--stop-level', 'foobar', 'example.' ],
|
||||
qr{failed to recognize stop level}i;
|
||||
|
||||
check_usage_error '--json-stream and --no-json', [ '--json-stream', '--no-json', 'example.' ],
|
||||
qr{cannot be used together}i;
|
||||
|
||||
check_usage_error 'Bad --hints (directory)', [ '--hints', '/', 'example.' ],
|
||||
qr{error loading hints file}i;
|
||||
|
||||
check_usage_error 'Bad --hints (syntax)', [ '--hints', 't/usage.t', 'example.' ],
|
||||
qr{error loading hints file}i;
|
||||
|
||||
check_success '--help', ['--help'], qr{
|
||||
^Usage:$
|
||||
.*
|
||||
zonemaster-cli
|
||||
.*
|
||||
^Options:$
|
||||
.*
|
||||
--test
|
||||
}msx;
|
||||
|
||||
check_success '-h', ['-h'], qr{
|
||||
^Usage:$
|
||||
.*
|
||||
zonemaster-cli
|
||||
.*
|
||||
^Options:$
|
||||
.*
|
||||
--test
|
||||
}msx;
|
||||
|
||||
check_success 'Single-character option bundling', ['-h?'], qr{
|
||||
--test
|
||||
}msx;
|
||||
|
||||
check_success '--version', ['--version'], qr{
|
||||
^\QZonemaster-CLI version\E .*
|
||||
^\QZonemaster-Engine version\E .*
|
||||
^\QZonemaster-LDNS version\E .*
|
||||
^\QNL NetLabs LDNS version\E .*
|
||||
}msx;
|
||||
|
||||
check_success '--list-tests', ['--list-tests'], qr{
|
||||
Basic
|
||||
.*
|
||||
basic01
|
||||
}msx;
|
||||
|
||||
check_success '--list_tests', ['--list_tests'], qr{
|
||||
Basic
|
||||
.*
|
||||
basic01
|
||||
}msx;
|
||||
|
||||
SKIP: {
|
||||
skip 'test that hang on FreeBSD (FIXME, see #388)', 2;
|
||||
|
||||
check_success '--dump-profile', ['--dump-profile'], qr{
|
||||
"no_network"
|
||||
}msx;
|
||||
|
||||
check_success '--dump_profile', ['--dump_profile'], qr{
|
||||
"no_network"
|
||||
}msx;
|
||||
};
|
||||
|
||||
check_success 'override profile', [ '--dump-profile', '--profile=t/usage.profile' ], sub {
|
||||
my ( $profile ) = parse_json_stream( $_[0] );
|
||||
|
||||
my $ipv4 = exists $profile->{net}{ipv4} ? ( $profile->{net}{ipv4} ? '1' : '0' ) : '<missing>';
|
||||
my $ipv6 = exists $profile->{net}{ipv6} ? ( $profile->{net}{ipv6} ? '1' : '0' ) : '<missing>';
|
||||
my $source4 = $profile->{resolver}{source4} // '<missing>';
|
||||
my $source6 = $profile->{resolver}{source6} // '<missing>';
|
||||
|
||||
return
|
||||
( $ipv4 eq '0' )
|
||||
&& ( $ipv6 eq '0' )
|
||||
&& ( $source4 eq '192.0.2.1' )
|
||||
&& ( $source6 eq '2001:db8::1' );
|
||||
};
|
||||
|
||||
check_success 'override net.ipv4', [ '--dump-profile', '--profile=t/usage.profile', '--ipv4' ], sub {
|
||||
my ( $profile ) = parse_json_stream( $_[0] );
|
||||
|
||||
my $ipv4 = exists $profile->{net}{ipv4} ? ( $profile->{net}{ipv4} ? '1' : '0' ) : '<missing>';
|
||||
|
||||
return $ipv4 eq '1';
|
||||
};
|
||||
|
||||
check_success 'override net.ipv6', [ '--dump-profile', '--profile=t/usage.profile', '--ipv6' ], sub {
|
||||
my ( $profile ) = parse_json_stream( $_[0] );
|
||||
|
||||
my $ipv6 = exists $profile->{net}{ipv6} ? ( $profile->{net}{ipv6} ? '1' : '0' ) : '<missing>';
|
||||
|
||||
return $ipv6 eq '1';
|
||||
};
|
||||
|
||||
check_success 'override resolver.source4',
|
||||
[ '--dump-profile', '--profile=t/usage.profile', '--sourceaddr4', '192.0.2.2' ], sub {
|
||||
my ( $profile ) = parse_json_stream( $_[0] );
|
||||
|
||||
my $source4 = $profile->{resolver}{source4} // '<missing>';
|
||||
|
||||
return $source4 eq '192.0.2.2';
|
||||
};
|
||||
|
||||
check_success 'override resolver.source6',
|
||||
[ '--dump-profile', '--profile=t/usage.profile', '--sourceaddr6', '2001:db8::2' ], sub {
|
||||
my ( $profile ) = parse_json_stream( $_[0] );
|
||||
|
||||
my $source6 = $profile->{resolver}{source6} // '<missing>';
|
||||
|
||||
return $source6 eq '2001:db8::2';
|
||||
};
|
||||
|
||||
check_success 'override test_cases',
|
||||
[ '--dump-profile', '--profile=t/usage.profile', '--test=basic01' ], sub {
|
||||
my ( $profile ) = parse_json_stream( $_[0] );
|
||||
|
||||
return
|
||||
ref $profile->{test_cases} eq 'ARRAY'
|
||||
&& scalar @{ $profile->{test_cases} } == 1
|
||||
&& $profile->{test_cases}[0] eq 'basic01';
|
||||
};
|
||||
|
||||
check_success 'override test_cases twice',
|
||||
[ '--dump-profile', '--profile=t/usage.profile', '--test=-all', '--test=+basic01' ], sub {
|
||||
my ( $profile ) = parse_json_stream( $_[0] );
|
||||
|
||||
return
|
||||
ref $profile->{test_cases} eq 'ARRAY'
|
||||
&& scalar @{ $profile->{test_cases} } == 1
|
||||
&& $profile->{test_cases}[0] eq 'basic01';
|
||||
};
|
||||
|
||||
check_success '--restore', [ "--restore=$PATH_NORMAL_DATAFILE", '--test=basic01', '--level=INFO', '--raw', '.' ],
|
||||
qr{B01_CHILD_FOUND};
|
||||
};
|
||||
|
||||
done_testing;
|
||||
85
zonemaster-cli/t/usage.wrapper.pl
Executable file
85
zonemaster-cli/t/usage.wrapper.pl
Executable file
@@ -0,0 +1,85 @@
|
||||
#!/usr/bin/env perl
|
||||
use v5.16;
|
||||
use warnings;
|
||||
|
||||
use File::Basename qw( dirname );
|
||||
use File::Spec::Functions qw( catfile );
|
||||
use Zonemaster::CLI;
|
||||
use Zonemaster::Engine::Nameserver;
|
||||
use Zonemaster::Engine::Profile;
|
||||
|
||||
use lib catfile( dirname( dirname( __FILE__ ) ), 'script' );
|
||||
|
||||
# Help Zonemaster::CLI find zonemaster-cli in test context
|
||||
$Zonemaster::CLI::SCRIPT = catfile( dirname( dirname( __FILE__ ) ), 'script', 'zonemaster-cli' );
|
||||
|
||||
# Parse command line options upto and including '--'.
|
||||
|
||||
my $opt_record = 0;
|
||||
my $opt_datafile;
|
||||
while ( @ARGV ) {
|
||||
my $arg = shift @ARGV;
|
||||
if ( substr( $arg, 0, 2 ) eq '--' ) {
|
||||
if ( $arg eq '--' ) {
|
||||
last;
|
||||
}
|
||||
elsif ( $arg eq '--record' ) {
|
||||
$opt_record = 1;
|
||||
}
|
||||
else {
|
||||
die "unrecognized option '$arg'";
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( defined $opt_datafile ) {
|
||||
die "too many data files provided";
|
||||
}
|
||||
$opt_datafile = $arg;
|
||||
}
|
||||
} ## end while ( @ARGV )
|
||||
|
||||
if ( $opt_record && !defined $opt_datafile ) {
|
||||
die "must not specify --record without also specifying a data file";
|
||||
}
|
||||
|
||||
# Prime Zonemaster Engine before letting zonemaster-cli do its thing
|
||||
|
||||
if ( !$opt_record ) {
|
||||
Zonemaster::Engine::Profile->effective->set( q{no_network}, 1 );
|
||||
}
|
||||
|
||||
if ( $opt_datafile ) {
|
||||
Zonemaster::Engine::Nameserver->restore( $opt_datafile );
|
||||
}
|
||||
|
||||
our $EXIT_STATUS;
|
||||
our $EMITTED_WARNING = 0;
|
||||
do {
|
||||
# Intercept warn()
|
||||
local $SIG{__WARN__} = sub {
|
||||
print STDERR "__WARN__: " . $_[0];
|
||||
$EMITTED_WARNING = 1;
|
||||
};
|
||||
|
||||
# Run Zonemaster::CLI
|
||||
eval {
|
||||
$EXIT_STATUS = Zonemaster::CLI->run( @ARGV );
|
||||
1;
|
||||
} or do {
|
||||
print STDERR $@;
|
||||
$EXIT_STATUS = $Zonemaster::CLI::EXIT_GENERIC_ERROR;
|
||||
};
|
||||
};
|
||||
|
||||
# Wrap up and terminate
|
||||
|
||||
if ( $opt_record ) {
|
||||
Zonemaster::Engine::Nameserver->save( $opt_datafile );
|
||||
}
|
||||
|
||||
if ( $EMITTED_WARNING ) {
|
||||
say STDERR "EXIT 125: one or more warnings were emitted";
|
||||
exit 125;
|
||||
}
|
||||
|
||||
exit $EXIT_STATUS;
|
||||
Reference in New Issue
Block a user