Compare commits
No commits in common. 'master' and 'v0.12.0-beta2' have entirely different histories.
master
...
v0.12.0-be
@ -1,32 +0,0 @@
|
|||||||
# This config was automatically generated from your source code
|
|
||||||
# Stacks detected: cicd:github-actions:.github/workflows,deps:python:docs,deps:ruby:docs,deps:rust:src/third-party/prqlc-c
|
|
||||||
version: 2.1
|
|
||||||
orbs:
|
|
||||||
macos: circleci/macos@2.2.0
|
|
||||||
jobs:
|
|
||||||
macos-apple-clang:
|
|
||||||
macos:
|
|
||||||
xcode: 14.2.0
|
|
||||||
resource_class: macos.m1.medium.gen1
|
|
||||||
steps:
|
|
||||||
- checkout
|
|
||||||
- run: brew install pcre2 sqlite ncurses xz zstd readline libarchive curl autoconf automake
|
|
||||||
- run: ./autogen.sh
|
|
||||||
- run: >-
|
|
||||||
./configure \
|
|
||||||
--with-libcurl=$(brew --prefix curl) \
|
|
||||||
--with-pcre2=$(brew --prefix pcre2) \
|
|
||||||
--with-sqlite3=$(brew --prefix sqlite3) \
|
|
||||||
"CXXFLAGS=-I$(brew --prefix ncurses)/include -g2 -O2" \
|
|
||||||
'CFLAGS=-O2 -g2' \
|
|
||||||
"LDFLAGS=-L$(brew --prefix ncurses)/lib -L$(brew --prefix xz)/lib -L$(brew --prefix lz4)/lib -L$(brew --prefix zstd)/lib/" \
|
|
||||||
--with-readline=$(brew --prefix readline) \
|
|
||||||
--with-libarchive=$(brew --prefix libarchive) \
|
|
||||||
|| cat config.log
|
|
||||||
- run: make -j2 || true
|
|
||||||
- run: env DUMP_CRASH=1 src/lnav -V
|
|
||||||
- run: make check -j2 || (test -e test/test-suite.log && cat test/test-suite.log && false)
|
|
||||||
workflows:
|
|
||||||
build-and-test:
|
|
||||||
jobs:
|
|
||||||
- macos-apple-clang
|
|
@ -1,13 +1,142 @@
|
|||||||
{
|
{
|
||||||
"version": 2,
|
"version": 2,
|
||||||
"configurePresets": [
|
"cmakeMinimumRequired": {
|
||||||
{
|
"major": 3,
|
||||||
"name": "default",
|
"minor": 14,
|
||||||
"generator": "Ninja",
|
"patch": 0
|
||||||
"binaryDir": "${sourceDir}/build",
|
},
|
||||||
"cacheVariables": {
|
"configurePresets": [
|
||||||
"CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
|
{
|
||||||
}
|
"name": "cmake-pedantic",
|
||||||
}
|
"hidden": true,
|
||||||
]
|
"warnings": {
|
||||||
}
|
"dev": true,
|
||||||
|
"deprecated": true,
|
||||||
|
"uninitialized": true,
|
||||||
|
"unusedCli": true,
|
||||||
|
"systemVars": false
|
||||||
|
},
|
||||||
|
"errors": {
|
||||||
|
"dev": true,
|
||||||
|
"deprecated": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "dev-mode",
|
||||||
|
"hidden": true,
|
||||||
|
"inherits": "cmake-pedantic",
|
||||||
|
"cacheVariables": {
|
||||||
|
"lnav_DEVELOPER_MODE": "ON"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "conan",
|
||||||
|
"hidden": true,
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_TOOLCHAIN_FILE": "${sourceDir}/conan/conan_toolchain.cmake"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cppcheck",
|
||||||
|
"hidden": true,
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_CXX_CPPCHECK": "cppcheck;--inline-suppr"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "clang-tidy",
|
||||||
|
"hidden": true,
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_CXX_CLANG_TIDY": "clang-tidy;--header-filter=${sourceDir}/*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ci-std",
|
||||||
|
"description": "This preset makes sure the project actually builds with at least the specified standard",
|
||||||
|
"hidden": true,
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_CXX_EXTENSIONS": "OFF",
|
||||||
|
"CMAKE_CXX_STANDARD": "14",
|
||||||
|
"CMAKE_CXX_STANDARD_REQUIRED": "ON"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "flags-unix",
|
||||||
|
"hidden": true,
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_CXX_FLAGS": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "flags-windows",
|
||||||
|
"hidden": true,
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_CXX_FLAGS": "/W4 /permissive- /utf-8 /volatile:iso /EHsc /Zc:__cplusplus /Zc:throwingNew"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ci-unix",
|
||||||
|
"generator": "Unix Makefiles",
|
||||||
|
"hidden": true,
|
||||||
|
"inherits": ["flags-unix", "ci-std"],
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_BUILD_TYPE": "Release"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ci-win64",
|
||||||
|
"inherits": ["flags-windows", "ci-std"],
|
||||||
|
"generator": "Visual Studio 17 2022",
|
||||||
|
"architecture": "x64",
|
||||||
|
"hidden": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "coverage-unix",
|
||||||
|
"binaryDir": "${sourceDir}/build/coverage",
|
||||||
|
"inherits": "ci-unix",
|
||||||
|
"hidden": true,
|
||||||
|
"cacheVariables": {
|
||||||
|
"ENABLE_COVERAGE": "ON",
|
||||||
|
"CMAKE_BUILD_TYPE": "Coverage",
|
||||||
|
"CMAKE_CXX_FLAGS_COVERAGE": "-Og -g --coverage -fkeep-inline-functions -fkeep-static-functions",
|
||||||
|
"CMAKE_EXE_LINKER_FLAGS_COVERAGE": "--coverage",
|
||||||
|
"CMAKE_SHARED_LINKER_FLAGS_COVERAGE": "--coverage",
|
||||||
|
"CMAKE_MAP_IMPORTED_CONFIG_SANITIZE": "Coverage;RelWithDebInfo;Release;Debug;"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ci-coverage",
|
||||||
|
"inherits": ["coverage-unix", "dev-mode", "conan"],
|
||||||
|
"cacheVariables": {
|
||||||
|
"COVERAGE_HTML_COMMAND": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ci-sanitize",
|
||||||
|
"binaryDir": "${sourceDir}/build/sanitize",
|
||||||
|
"inherits": ["ci-unix", "dev-mode", "conan"],
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_BUILD_TYPE": "Sanitize",
|
||||||
|
"CMAKE_CXX_FLAGS_SANITIZE": "-O2 -g -fsanitize=address,undefined -fno-omit-frame-pointer -fno-common",
|
||||||
|
"CMAKE_MAP_IMPORTED_CONFIG_SANITIZE": "Sanitize;RelWithDebInfo;Release;Debug;"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ci-build",
|
||||||
|
"binaryDir": "${sourceDir}/build",
|
||||||
|
"hidden": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ci-macos",
|
||||||
|
"inherits": ["ci-build", "ci-unix", "dev-mode", "conan"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ci-ubuntu",
|
||||||
|
"inherits": ["ci-build", "ci-unix", "clang-tidy", "conan", "dev-mode"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ci-windows",
|
||||||
|
"inherits": ["ci-build", "ci-win64", "dev-mode", "conan"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
hunter_config(
|
||||||
|
libpcre
|
||||||
|
VERSION 8.41
|
||||||
|
CMAKE_ARGS
|
||||||
|
EXTRA_FLAGS=--enable-unicode-properties --enable-jit --enable-utf
|
||||||
|
)
|
||||||
|
|
||||||
|
hunter_config(
|
||||||
|
readline
|
||||||
|
VERSION 6.3
|
||||||
|
CMAKE_ARGS
|
||||||
|
EXTRA_FLAGS=CFLAGS=-Wno-implicit-function-declaration
|
||||||
|
)
|
@ -0,0 +1,528 @@
|
|||||||
|
# Copyright (c) 2013-2019, Ruslan Baratov
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
# This is a gate file to Hunter package manager.
|
||||||
|
# Include this file using `include` command and add package you need, example:
|
||||||
|
#
|
||||||
|
# cmake_minimum_required(VERSION 3.2)
|
||||||
|
#
|
||||||
|
# include("cmake/HunterGate.cmake")
|
||||||
|
# HunterGate(
|
||||||
|
# URL "https://github.com/path/to/hunter/archive.tar.gz"
|
||||||
|
# SHA1 "798501e983f14b28b10cda16afa4de69eee1da1d"
|
||||||
|
# )
|
||||||
|
#
|
||||||
|
# project(MyProject)
|
||||||
|
#
|
||||||
|
# hunter_add_package(Foo)
|
||||||
|
# hunter_add_package(Boo COMPONENTS Bar Baz)
|
||||||
|
#
|
||||||
|
# Projects:
|
||||||
|
# * https://github.com/hunter-packages/gate/
|
||||||
|
# * https://github.com/ruslo/hunter
|
||||||
|
|
||||||
|
option(HUNTER_ENABLED "Enable Hunter package manager support" ON)
|
||||||
|
|
||||||
|
if(HUNTER_ENABLED)
|
||||||
|
if(CMAKE_VERSION VERSION_LESS "3.2")
|
||||||
|
message(
|
||||||
|
FATAL_ERROR
|
||||||
|
"At least CMake version 3.2 required for Hunter dependency management."
|
||||||
|
" Update CMake or set HUNTER_ENABLED to OFF."
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include(CMakeParseArguments) # cmake_parse_arguments
|
||||||
|
|
||||||
|
option(HUNTER_STATUS_PRINT "Print working status" ON)
|
||||||
|
option(HUNTER_STATUS_DEBUG "Print a lot info" OFF)
|
||||||
|
option(HUNTER_TLS_VERIFY "Enable/disable TLS certificate checking on downloads" ON)
|
||||||
|
|
||||||
|
set(HUNTER_ERROR_PAGE "https://docs.hunter.sh/en/latest/reference/errors")
|
||||||
|
|
||||||
|
function(hunter_gate_status_print)
|
||||||
|
if(HUNTER_STATUS_PRINT OR HUNTER_STATUS_DEBUG)
|
||||||
|
foreach(print_message ${ARGV})
|
||||||
|
message(STATUS "[hunter] ${print_message}")
|
||||||
|
endforeach()
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(hunter_gate_status_debug)
|
||||||
|
if(HUNTER_STATUS_DEBUG)
|
||||||
|
foreach(print_message ${ARGV})
|
||||||
|
string(TIMESTAMP timestamp)
|
||||||
|
message(STATUS "[hunter *** DEBUG *** ${timestamp}] ${print_message}")
|
||||||
|
endforeach()
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(hunter_gate_error_page error_page)
|
||||||
|
message("------------------------------ ERROR ------------------------------")
|
||||||
|
message(" ${HUNTER_ERROR_PAGE}/${error_page}.html")
|
||||||
|
message("-------------------------------------------------------------------")
|
||||||
|
message("")
|
||||||
|
message(FATAL_ERROR "")
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(hunter_gate_internal_error)
|
||||||
|
message("")
|
||||||
|
foreach(print_message ${ARGV})
|
||||||
|
message("[hunter ** INTERNAL **] ${print_message}")
|
||||||
|
endforeach()
|
||||||
|
message("[hunter ** INTERNAL **] [Directory:${CMAKE_CURRENT_LIST_DIR}]")
|
||||||
|
message("")
|
||||||
|
hunter_gate_error_page("error.internal")
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(hunter_gate_fatal_error)
|
||||||
|
cmake_parse_arguments(hunter "" "ERROR_PAGE" "" "${ARGV}")
|
||||||
|
if("${hunter_ERROR_PAGE}" STREQUAL "")
|
||||||
|
hunter_gate_internal_error("Expected ERROR_PAGE")
|
||||||
|
endif()
|
||||||
|
message("")
|
||||||
|
foreach(x ${hunter_UNPARSED_ARGUMENTS})
|
||||||
|
message("[hunter ** FATAL ERROR **] ${x}")
|
||||||
|
endforeach()
|
||||||
|
message("[hunter ** FATAL ERROR **] [Directory:${CMAKE_CURRENT_LIST_DIR}]")
|
||||||
|
message("")
|
||||||
|
hunter_gate_error_page("${hunter_ERROR_PAGE}")
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(hunter_gate_user_error)
|
||||||
|
hunter_gate_fatal_error(${ARGV} ERROR_PAGE "error.incorrect.input.data")
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(hunter_gate_self root version sha1 result)
|
||||||
|
string(COMPARE EQUAL "${root}" "" is_bad)
|
||||||
|
if(is_bad)
|
||||||
|
hunter_gate_internal_error("root is empty")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
string(COMPARE EQUAL "${version}" "" is_bad)
|
||||||
|
if(is_bad)
|
||||||
|
hunter_gate_internal_error("version is empty")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
string(COMPARE EQUAL "${sha1}" "" is_bad)
|
||||||
|
if(is_bad)
|
||||||
|
hunter_gate_internal_error("sha1 is empty")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
string(SUBSTRING "${sha1}" 0 7 archive_id)
|
||||||
|
|
||||||
|
set(
|
||||||
|
hunter_self
|
||||||
|
"${root}/_Base/Download/Hunter/${version}/${archive_id}/Unpacked"
|
||||||
|
)
|
||||||
|
|
||||||
|
set("${result}" "${hunter_self}" PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# Set HUNTER_GATE_ROOT cmake variable to suitable value.
|
||||||
|
function(hunter_gate_detect_root)
|
||||||
|
# Check CMake variable
|
||||||
|
string(COMPARE NOTEQUAL "${HUNTER_ROOT}" "" not_empty)
|
||||||
|
if(not_empty)
|
||||||
|
set(HUNTER_GATE_ROOT "${HUNTER_ROOT}" PARENT_SCOPE)
|
||||||
|
hunter_gate_status_debug("HUNTER_ROOT detected by cmake variable")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Check environment variable
|
||||||
|
string(COMPARE NOTEQUAL "$ENV{HUNTER_ROOT}" "" not_empty)
|
||||||
|
if(not_empty)
|
||||||
|
set(HUNTER_GATE_ROOT "$ENV{HUNTER_ROOT}" PARENT_SCOPE)
|
||||||
|
hunter_gate_status_debug("HUNTER_ROOT detected by environment variable")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Check HOME environment variable
|
||||||
|
string(COMPARE NOTEQUAL "$ENV{HOME}" "" result)
|
||||||
|
if(result)
|
||||||
|
set(HUNTER_GATE_ROOT "$ENV{HOME}/.hunter" PARENT_SCOPE)
|
||||||
|
hunter_gate_status_debug("HUNTER_ROOT set using HOME environment variable")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Check SYSTEMDRIVE and USERPROFILE environment variable (windows only)
|
||||||
|
if(WIN32)
|
||||||
|
string(COMPARE NOTEQUAL "$ENV{SYSTEMDRIVE}" "" result)
|
||||||
|
if(result)
|
||||||
|
set(HUNTER_GATE_ROOT "$ENV{SYSTEMDRIVE}/.hunter" PARENT_SCOPE)
|
||||||
|
hunter_gate_status_debug(
|
||||||
|
"HUNTER_ROOT set using SYSTEMDRIVE environment variable"
|
||||||
|
)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
string(COMPARE NOTEQUAL "$ENV{USERPROFILE}" "" result)
|
||||||
|
if(result)
|
||||||
|
set(HUNTER_GATE_ROOT "$ENV{USERPROFILE}/.hunter" PARENT_SCOPE)
|
||||||
|
hunter_gate_status_debug(
|
||||||
|
"HUNTER_ROOT set using USERPROFILE environment variable"
|
||||||
|
)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
hunter_gate_fatal_error(
|
||||||
|
"Can't detect HUNTER_ROOT"
|
||||||
|
ERROR_PAGE "error.detect.hunter.root"
|
||||||
|
)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(hunter_gate_download dir)
|
||||||
|
string(
|
||||||
|
COMPARE
|
||||||
|
NOTEQUAL
|
||||||
|
"$ENV{HUNTER_DISABLE_AUTOINSTALL}"
|
||||||
|
""
|
||||||
|
disable_autoinstall
|
||||||
|
)
|
||||||
|
if(disable_autoinstall AND NOT HUNTER_RUN_INSTALL)
|
||||||
|
hunter_gate_fatal_error(
|
||||||
|
"Hunter not found in '${dir}'"
|
||||||
|
"Set HUNTER_RUN_INSTALL=ON to auto-install it from '${HUNTER_GATE_URL}'"
|
||||||
|
"Settings:"
|
||||||
|
" HUNTER_ROOT: ${HUNTER_GATE_ROOT}"
|
||||||
|
" HUNTER_SHA1: ${HUNTER_GATE_SHA1}"
|
||||||
|
ERROR_PAGE "error.run.install"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
string(COMPARE EQUAL "${dir}" "" is_bad)
|
||||||
|
if(is_bad)
|
||||||
|
hunter_gate_internal_error("Empty 'dir' argument")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
string(COMPARE EQUAL "${HUNTER_GATE_SHA1}" "" is_bad)
|
||||||
|
if(is_bad)
|
||||||
|
hunter_gate_internal_error("HUNTER_GATE_SHA1 empty")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
string(COMPARE EQUAL "${HUNTER_GATE_URL}" "" is_bad)
|
||||||
|
if(is_bad)
|
||||||
|
hunter_gate_internal_error("HUNTER_GATE_URL empty")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(done_location "${dir}/DONE")
|
||||||
|
set(sha1_location "${dir}/SHA1")
|
||||||
|
|
||||||
|
set(build_dir "${dir}/Build")
|
||||||
|
set(cmakelists "${dir}/CMakeLists.txt")
|
||||||
|
|
||||||
|
hunter_gate_status_debug("Locking directory: ${dir}")
|
||||||
|
file(LOCK "${dir}" DIRECTORY GUARD FUNCTION)
|
||||||
|
hunter_gate_status_debug("Lock done")
|
||||||
|
|
||||||
|
if(EXISTS "${done_location}")
|
||||||
|
# while waiting for lock other instance can do all the job
|
||||||
|
hunter_gate_status_debug("File '${done_location}' found, skip install")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
file(REMOVE_RECURSE "${build_dir}")
|
||||||
|
file(REMOVE_RECURSE "${cmakelists}")
|
||||||
|
|
||||||
|
file(MAKE_DIRECTORY "${build_dir}") # check directory permissions
|
||||||
|
|
||||||
|
# Disabling languages speeds up a little bit, reduces noise in the output
|
||||||
|
# and avoids path too long windows error
|
||||||
|
file(
|
||||||
|
WRITE
|
||||||
|
"${cmakelists}"
|
||||||
|
"cmake_minimum_required(VERSION 3.2)\n"
|
||||||
|
"project(HunterDownload LANGUAGES NONE)\n"
|
||||||
|
"include(ExternalProject)\n"
|
||||||
|
"ExternalProject_Add(\n"
|
||||||
|
" Hunter\n"
|
||||||
|
" URL\n"
|
||||||
|
" \"${HUNTER_GATE_URL}\"\n"
|
||||||
|
" URL_HASH\n"
|
||||||
|
" SHA1=${HUNTER_GATE_SHA1}\n"
|
||||||
|
" DOWNLOAD_DIR\n"
|
||||||
|
" \"${dir}\"\n"
|
||||||
|
" TLS_VERIFY\n"
|
||||||
|
" ${HUNTER_TLS_VERIFY}\n"
|
||||||
|
" SOURCE_DIR\n"
|
||||||
|
" \"${dir}/Unpacked\"\n"
|
||||||
|
" CONFIGURE_COMMAND\n"
|
||||||
|
" \"\"\n"
|
||||||
|
" BUILD_COMMAND\n"
|
||||||
|
" \"\"\n"
|
||||||
|
" INSTALL_COMMAND\n"
|
||||||
|
" \"\"\n"
|
||||||
|
")\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
if(HUNTER_STATUS_DEBUG)
|
||||||
|
set(logging_params "")
|
||||||
|
else()
|
||||||
|
set(logging_params OUTPUT_QUIET)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
hunter_gate_status_debug("Run generate")
|
||||||
|
|
||||||
|
# Need to add toolchain file too.
|
||||||
|
# Otherwise on Visual Studio + MDD this will fail with error:
|
||||||
|
# "Could not find an appropriate version of the Windows 10 SDK installed on this machine"
|
||||||
|
if(EXISTS "${CMAKE_TOOLCHAIN_FILE}")
|
||||||
|
get_filename_component(absolute_CMAKE_TOOLCHAIN_FILE "${CMAKE_TOOLCHAIN_FILE}" ABSOLUTE)
|
||||||
|
set(toolchain_arg "-DCMAKE_TOOLCHAIN_FILE=${absolute_CMAKE_TOOLCHAIN_FILE}")
|
||||||
|
else()
|
||||||
|
# 'toolchain_arg' can't be empty
|
||||||
|
set(toolchain_arg "-DCMAKE_TOOLCHAIN_FILE=")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
string(COMPARE EQUAL "${CMAKE_MAKE_PROGRAM}" "" no_make)
|
||||||
|
if(no_make)
|
||||||
|
set(make_arg "")
|
||||||
|
else()
|
||||||
|
# Test case: remove Ninja from PATH but set it via CMAKE_MAKE_PROGRAM
|
||||||
|
set(make_arg "-DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND
|
||||||
|
"${CMAKE_COMMAND}"
|
||||||
|
"-H${dir}"
|
||||||
|
"-B${build_dir}"
|
||||||
|
"-G${CMAKE_GENERATOR}"
|
||||||
|
"${toolchain_arg}"
|
||||||
|
${make_arg}
|
||||||
|
WORKING_DIRECTORY "${dir}"
|
||||||
|
RESULT_VARIABLE download_result
|
||||||
|
${logging_params}
|
||||||
|
)
|
||||||
|
|
||||||
|
if(NOT download_result EQUAL 0)
|
||||||
|
hunter_gate_internal_error(
|
||||||
|
"Configure project failed."
|
||||||
|
"To reproduce the error run: ${CMAKE_COMMAND} -H${dir} -B${build_dir} -G${CMAKE_GENERATOR} ${toolchain_arg} ${make_arg}"
|
||||||
|
"In directory ${dir}"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
hunter_gate_status_print(
|
||||||
|
"Initializing Hunter workspace (${HUNTER_GATE_SHA1})"
|
||||||
|
" ${HUNTER_GATE_URL}"
|
||||||
|
" -> ${dir}"
|
||||||
|
)
|
||||||
|
execute_process(
|
||||||
|
COMMAND "${CMAKE_COMMAND}" --build "${build_dir}"
|
||||||
|
WORKING_DIRECTORY "${dir}"
|
||||||
|
RESULT_VARIABLE download_result
|
||||||
|
${logging_params}
|
||||||
|
)
|
||||||
|
|
||||||
|
if(NOT download_result EQUAL 0)
|
||||||
|
hunter_gate_internal_error("Build project failed")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
file(REMOVE_RECURSE "${build_dir}")
|
||||||
|
file(REMOVE_RECURSE "${cmakelists}")
|
||||||
|
|
||||||
|
file(WRITE "${sha1_location}" "${HUNTER_GATE_SHA1}")
|
||||||
|
file(WRITE "${done_location}" "DONE")
|
||||||
|
|
||||||
|
hunter_gate_status_debug("Finished")
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
# Must be a macro so master file 'cmake/Hunter' can
|
||||||
|
# apply all variables easily just by 'include' command
|
||||||
|
# (otherwise PARENT_SCOPE magic needed)
|
||||||
|
macro(HunterGate)
|
||||||
|
if(HUNTER_GATE_DONE)
|
||||||
|
# variable HUNTER_GATE_DONE set explicitly for external project
|
||||||
|
# (see `hunter_download`)
|
||||||
|
set_property(GLOBAL PROPERTY HUNTER_GATE_DONE YES)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# First HunterGate command will init Hunter, others will be ignored
|
||||||
|
get_property(_hunter_gate_done GLOBAL PROPERTY HUNTER_GATE_DONE SET)
|
||||||
|
|
||||||
|
if(NOT HUNTER_ENABLED)
|
||||||
|
# Empty function to avoid error "unknown function"
|
||||||
|
function(hunter_add_package)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
set(
|
||||||
|
_hunter_gate_disabled_mode_dir
|
||||||
|
"${CMAKE_CURRENT_LIST_DIR}/cmake/Hunter/disabled-mode"
|
||||||
|
)
|
||||||
|
if(EXISTS "${_hunter_gate_disabled_mode_dir}")
|
||||||
|
hunter_gate_status_debug(
|
||||||
|
"Adding \"disabled-mode\" modules: ${_hunter_gate_disabled_mode_dir}"
|
||||||
|
)
|
||||||
|
list(APPEND CMAKE_PREFIX_PATH "${_hunter_gate_disabled_mode_dir}")
|
||||||
|
endif()
|
||||||
|
elseif(_hunter_gate_done)
|
||||||
|
hunter_gate_status_debug("Secondary HunterGate (use old settings)")
|
||||||
|
hunter_gate_self(
|
||||||
|
"${HUNTER_CACHED_ROOT}"
|
||||||
|
"${HUNTER_VERSION}"
|
||||||
|
"${HUNTER_SHA1}"
|
||||||
|
_hunter_self
|
||||||
|
)
|
||||||
|
include("${_hunter_self}/cmake/Hunter")
|
||||||
|
else()
|
||||||
|
set(HUNTER_GATE_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||||
|
|
||||||
|
string(COMPARE NOTEQUAL "${PROJECT_NAME}" "" _have_project_name)
|
||||||
|
if(_have_project_name)
|
||||||
|
hunter_gate_fatal_error(
|
||||||
|
"Please set HunterGate *before* 'project' command. "
|
||||||
|
"Detected project: ${PROJECT_NAME}"
|
||||||
|
ERROR_PAGE "error.huntergate.before.project"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
cmake_parse_arguments(
|
||||||
|
HUNTER_GATE "LOCAL" "URL;SHA1;GLOBAL;FILEPATH" "" ${ARGV}
|
||||||
|
)
|
||||||
|
|
||||||
|
string(COMPARE EQUAL "${HUNTER_GATE_SHA1}" "" _empty_sha1)
|
||||||
|
string(COMPARE EQUAL "${HUNTER_GATE_URL}" "" _empty_url)
|
||||||
|
string(
|
||||||
|
COMPARE
|
||||||
|
NOTEQUAL
|
||||||
|
"${HUNTER_GATE_UNPARSED_ARGUMENTS}"
|
||||||
|
""
|
||||||
|
_have_unparsed
|
||||||
|
)
|
||||||
|
string(COMPARE NOTEQUAL "${HUNTER_GATE_GLOBAL}" "" _have_global)
|
||||||
|
string(COMPARE NOTEQUAL "${HUNTER_GATE_FILEPATH}" "" _have_filepath)
|
||||||
|
|
||||||
|
if(_have_unparsed)
|
||||||
|
hunter_gate_user_error(
|
||||||
|
"HunterGate unparsed arguments: ${HUNTER_GATE_UNPARSED_ARGUMENTS}"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
if(_empty_sha1)
|
||||||
|
hunter_gate_user_error("SHA1 suboption of HunterGate is mandatory")
|
||||||
|
endif()
|
||||||
|
if(_empty_url)
|
||||||
|
hunter_gate_user_error("URL suboption of HunterGate is mandatory")
|
||||||
|
endif()
|
||||||
|
if(_have_global)
|
||||||
|
if(HUNTER_GATE_LOCAL)
|
||||||
|
hunter_gate_user_error("Unexpected LOCAL (already has GLOBAL)")
|
||||||
|
endif()
|
||||||
|
if(_have_filepath)
|
||||||
|
hunter_gate_user_error("Unexpected FILEPATH (already has GLOBAL)")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
if(HUNTER_GATE_LOCAL)
|
||||||
|
if(_have_global)
|
||||||
|
hunter_gate_user_error("Unexpected GLOBAL (already has LOCAL)")
|
||||||
|
endif()
|
||||||
|
if(_have_filepath)
|
||||||
|
hunter_gate_user_error("Unexpected FILEPATH (already has LOCAL)")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
if(_have_filepath)
|
||||||
|
if(_have_global)
|
||||||
|
hunter_gate_user_error("Unexpected GLOBAL (already has FILEPATH)")
|
||||||
|
endif()
|
||||||
|
if(HUNTER_GATE_LOCAL)
|
||||||
|
hunter_gate_user_error("Unexpected LOCAL (already has FILEPATH)")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
hunter_gate_detect_root() # set HUNTER_GATE_ROOT
|
||||||
|
|
||||||
|
# Beautify path, fix probable problems with windows path slashes
|
||||||
|
get_filename_component(
|
||||||
|
HUNTER_GATE_ROOT "${HUNTER_GATE_ROOT}" ABSOLUTE
|
||||||
|
)
|
||||||
|
hunter_gate_status_debug("HUNTER_ROOT: ${HUNTER_GATE_ROOT}")
|
||||||
|
if(NOT HUNTER_ALLOW_SPACES_IN_PATH)
|
||||||
|
string(FIND "${HUNTER_GATE_ROOT}" " " _contain_spaces)
|
||||||
|
if(NOT _contain_spaces EQUAL -1)
|
||||||
|
hunter_gate_fatal_error(
|
||||||
|
"HUNTER_ROOT (${HUNTER_GATE_ROOT}) contains spaces."
|
||||||
|
"Set HUNTER_ALLOW_SPACES_IN_PATH=ON to skip this error"
|
||||||
|
"(Use at your own risk!)"
|
||||||
|
ERROR_PAGE "error.spaces.in.hunter.root"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
string(
|
||||||
|
REGEX
|
||||||
|
MATCH
|
||||||
|
"[0-9]+\\.[0-9]+\\.[0-9]+[-_a-z0-9]*"
|
||||||
|
HUNTER_GATE_VERSION
|
||||||
|
"${HUNTER_GATE_URL}"
|
||||||
|
)
|
||||||
|
string(COMPARE EQUAL "${HUNTER_GATE_VERSION}" "" _is_empty)
|
||||||
|
if(_is_empty)
|
||||||
|
set(HUNTER_GATE_VERSION "unknown")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
hunter_gate_self(
|
||||||
|
"${HUNTER_GATE_ROOT}"
|
||||||
|
"${HUNTER_GATE_VERSION}"
|
||||||
|
"${HUNTER_GATE_SHA1}"
|
||||||
|
_hunter_self
|
||||||
|
)
|
||||||
|
|
||||||
|
set(_master_location "${_hunter_self}/cmake/Hunter")
|
||||||
|
get_filename_component(_archive_id_location "${_hunter_self}/.." ABSOLUTE)
|
||||||
|
set(_done_location "${_archive_id_location}/DONE")
|
||||||
|
set(_sha1_location "${_archive_id_location}/SHA1")
|
||||||
|
|
||||||
|
# Check Hunter already downloaded by HunterGate
|
||||||
|
if(NOT EXISTS "${_done_location}")
|
||||||
|
hunter_gate_download("${_archive_id_location}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT EXISTS "${_done_location}")
|
||||||
|
hunter_gate_internal_error("hunter_gate_download failed")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT EXISTS "${_sha1_location}")
|
||||||
|
hunter_gate_internal_error("${_sha1_location} not found")
|
||||||
|
endif()
|
||||||
|
file(READ "${_sha1_location}" _sha1_value)
|
||||||
|
string(COMPARE EQUAL "${_sha1_value}" "${HUNTER_GATE_SHA1}" _is_equal)
|
||||||
|
if(NOT _is_equal)
|
||||||
|
hunter_gate_internal_error(
|
||||||
|
"Short SHA1 collision:"
|
||||||
|
" ${_sha1_value} (from ${_sha1_location})"
|
||||||
|
" ${HUNTER_GATE_SHA1} (HunterGate)"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
if(NOT EXISTS "${_master_location}")
|
||||||
|
hunter_gate_user_error(
|
||||||
|
"Master file not found:"
|
||||||
|
" ${_master_location}"
|
||||||
|
"try to update Hunter/HunterGate"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
include("${_master_location}")
|
||||||
|
set_property(GLOBAL PROPERTY HUNTER_GATE_DONE YES)
|
||||||
|
endif()
|
||||||
|
endmacro()
|
@ -0,0 +1,112 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.14)
|
||||||
|
|
||||||
|
foreach(var IN ITEMS PROJECT_BINARY_DIR PROJECT_SOURCE_DIR)
|
||||||
|
if(NOT DEFINED "${var}")
|
||||||
|
message(FATAL_ERROR "${var} must be defined")
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
set(bin "${PROJECT_BINARY_DIR}")
|
||||||
|
set(src "${PROJECT_SOURCE_DIR}")
|
||||||
|
|
||||||
|
# ---- Dependencies ----
|
||||||
|
|
||||||
|
set(mcss_SOURCE_DIR "${bin}/docs/.ci")
|
||||||
|
if(NOT IS_DIRECTORY "${mcss_SOURCE_DIR}")
|
||||||
|
file(MAKE_DIRECTORY "${mcss_SOURCE_DIR}")
|
||||||
|
file(
|
||||||
|
DOWNLOAD
|
||||||
|
https://github.com/friendlyanon/m.css/releases/download/release-1/mcss.zip
|
||||||
|
"${mcss_SOURCE_DIR}/mcss.zip"
|
||||||
|
STATUS status
|
||||||
|
EXPECTED_MD5 00cd2757ebafb9bcba7f5d399b3bec7f
|
||||||
|
)
|
||||||
|
if(NOT status MATCHES "^0;")
|
||||||
|
message(FATAL_ERROR "Download failed with ${status}")
|
||||||
|
endif()
|
||||||
|
execute_process(
|
||||||
|
COMMAND "${CMAKE_COMMAND}" -E tar xf mcss.zip
|
||||||
|
WORKING_DIRECTORY "${mcss_SOURCE_DIR}"
|
||||||
|
RESULT_VARIABLE result
|
||||||
|
)
|
||||||
|
if(NOT result EQUAL "0")
|
||||||
|
message(FATAL_ERROR "Extraction failed with ${result}")
|
||||||
|
endif()
|
||||||
|
file(REMOVE "${mcss_SOURCE_DIR}/mcss.zip")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
find_program(Python3_EXECUTABLE NAMES python3 python)
|
||||||
|
if(NOT Python3_EXECUTABLE)
|
||||||
|
message(FATAL_ERROR "Python executable was not found")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# ---- Process project() call in CMakeLists.txt ----
|
||||||
|
|
||||||
|
file(READ "${src}/CMakeLists.txt" content)
|
||||||
|
|
||||||
|
string(FIND "${content}" "project(" index)
|
||||||
|
if(index EQUAL "-1")
|
||||||
|
message(FATAL_ERROR "Could not find \"project(\"")
|
||||||
|
endif()
|
||||||
|
string(SUBSTRING "${content}" "${index}" -1 content)
|
||||||
|
|
||||||
|
string(FIND "${content}" "\n)\n" index)
|
||||||
|
if(index EQUAL "-1")
|
||||||
|
message(FATAL_ERROR "Could not find \"\\n)\\n\"")
|
||||||
|
endif()
|
||||||
|
string(SUBSTRING "${content}" 0 "${index}" content)
|
||||||
|
|
||||||
|
file(WRITE "${bin}/docs-ci.project.cmake" "docs_${content}\n)\n")
|
||||||
|
|
||||||
|
macro(list_pop_front list out)
|
||||||
|
list(GET "${list}" 0 "${out}")
|
||||||
|
list(REMOVE_AT "${list}" 0)
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
function(docs_project name)
|
||||||
|
cmake_parse_arguments(PARSE_ARGV 1 "" "" "VERSION;DESCRIPTION;HOMEPAGE_URL" LANGUAGES)
|
||||||
|
set(PROJECT_NAME "${name}" PARENT_SCOPE)
|
||||||
|
if(DEFINED _VERSION)
|
||||||
|
set(PROJECT_VERSION "${_VERSION}" PARENT_SCOPE)
|
||||||
|
string(REGEX MATCH "^[0-9]+(\\.[0-9]+)*" versions "${_VERSION}")
|
||||||
|
string(REPLACE . ";" versions "${versions}")
|
||||||
|
set(suffixes MAJOR MINOR PATCH TWEAK)
|
||||||
|
while(NOT versions STREQUAL "" AND NOT suffixes STREQUAL "")
|
||||||
|
list_pop_front(versions version)
|
||||||
|
list_pop_front(suffixes suffix)
|
||||||
|
set("PROJECT_VERSION_${suffix}" "${version}" PARENT_SCOPE)
|
||||||
|
endwhile()
|
||||||
|
endif()
|
||||||
|
if(DEFINED _DESCRIPTION)
|
||||||
|
set(PROJECT_DESCRIPTION "${_DESCRIPTION}" PARENT_SCOPE)
|
||||||
|
endif()
|
||||||
|
if(DEFINED _HOMEPAGE_URL)
|
||||||
|
set(PROJECT_HOMEPAGE_URL "${_HOMEPAGE_URL}" PARENT_SCOPE)
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
include("${bin}/docs-ci.project.cmake")
|
||||||
|
|
||||||
|
# ---- Generate docs ----
|
||||||
|
|
||||||
|
if(NOT DEFINED DOXYGEN_OUTPUT_DIRECTORY)
|
||||||
|
set(DOXYGEN_OUTPUT_DIRECTORY "${bin}/docs")
|
||||||
|
endif()
|
||||||
|
set(out "${DOXYGEN_OUTPUT_DIRECTORY}")
|
||||||
|
|
||||||
|
foreach(file IN ITEMS Doxyfile conf.py)
|
||||||
|
configure_file("${src}/docs/${file}.in" "${bin}/docs/${file}" @ONLY)
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
set(mcss_script "${mcss_SOURCE_DIR}/documentation/doxygen.py")
|
||||||
|
set(config "${bin}/docs/conf.py")
|
||||||
|
|
||||||
|
file(REMOVE_RECURSE "${out}/html" "${out}/xml")
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND "${Python3_EXECUTABLE}" "${mcss_script}" "${config}"
|
||||||
|
WORKING_DIRECTORY "${bin}/docs"
|
||||||
|
RESULT_VARIABLE result
|
||||||
|
)
|
||||||
|
if(NOT result EQUAL "0")
|
||||||
|
message(FATAL_ERROR "m.css returned with ${result}")
|
||||||
|
endif()
|
@ -0,0 +1,46 @@
|
|||||||
|
# ---- Dependencies ----
|
||||||
|
|
||||||
|
set(extract_timestamps "")
|
||||||
|
if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.24")
|
||||||
|
set(extract_timestamps DOWNLOAD_EXTRACT_TIMESTAMP YES)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
include(FetchContent)
|
||||||
|
FetchContent_Declare(
|
||||||
|
mcss URL
|
||||||
|
https://github.com/friendlyanon/m.css/releases/download/release-1/mcss.zip
|
||||||
|
URL_MD5 00cd2757ebafb9bcba7f5d399b3bec7f
|
||||||
|
SOURCE_DIR "${PROJECT_BINARY_DIR}/mcss"
|
||||||
|
UPDATE_DISCONNECTED YES
|
||||||
|
${extract_timestamps}
|
||||||
|
)
|
||||||
|
FetchContent_MakeAvailable(mcss)
|
||||||
|
|
||||||
|
find_package(Python3 3.6 REQUIRED)
|
||||||
|
|
||||||
|
# ---- Declare documentation target ----
|
||||||
|
|
||||||
|
set(
|
||||||
|
DOXYGEN_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/docs"
|
||||||
|
CACHE PATH "Path for the generated Doxygen documentation"
|
||||||
|
)
|
||||||
|
|
||||||
|
set(working_dir "${PROJECT_BINARY_DIR}/docs")
|
||||||
|
|
||||||
|
foreach (file IN ITEMS Doxyfile conf.py)
|
||||||
|
configure_file("docs/${file}.in" "${working_dir}/${file}" @ONLY)
|
||||||
|
endforeach ()
|
||||||
|
|
||||||
|
set(mcss_script "${mcss_SOURCE_DIR}/documentation/doxygen.py")
|
||||||
|
set(config "${working_dir}/conf.py")
|
||||||
|
|
||||||
|
add_custom_target(
|
||||||
|
docs
|
||||||
|
COMMAND "${CMAKE_COMMAND}" -E remove_directory
|
||||||
|
"${DOXYGEN_OUTPUT_DIRECTORY}/html"
|
||||||
|
"${DOXYGEN_OUTPUT_DIRECTORY}/xml"
|
||||||
|
COMMAND "${Python3_EXECUTABLE}" "${mcss_script}" "${config}"
|
||||||
|
COMMENT "Building documentation using Doxygen and m.css"
|
||||||
|
WORKING_DIRECTORY "${working_dir}"
|
||||||
|
VERBATIM
|
||||||
|
)
|
@ -0,0 +1,58 @@
|
|||||||
|
from conans import ConanFile
|
||||||
|
from conan.tools.cmake import CMake, CMakeToolchain, CMakeDeps
|
||||||
|
|
||||||
|
|
||||||
|
class LnavConan(ConanFile):
|
||||||
|
name = "lnav"
|
||||||
|
version = "0.12.0"
|
||||||
|
homepage = "https://lnav.org"
|
||||||
|
url = "https://github.com/tstack/lnav.git"
|
||||||
|
license = "BSD-2-Clause"
|
||||||
|
description = (
|
||||||
|
"The Log File Navigator, lnav for short, is an advanced "
|
||||||
|
"log file viewer for the small-scale"
|
||||||
|
)
|
||||||
|
settings = "os", "compiler", "build_type", "arch"
|
||||||
|
exports_sources = "*"
|
||||||
|
no_copy_source = True
|
||||||
|
requires = (
|
||||||
|
"bzip2/1.0.8",
|
||||||
|
"libarchive/3.6.0",
|
||||||
|
"libcurl/7.85.0",
|
||||||
|
"ncurses/6.3",
|
||||||
|
"pcre2/10.40",
|
||||||
|
"readline/8.1.2",
|
||||||
|
"sqlite3/3.38.0",
|
||||||
|
"zlib/1.2.12",
|
||||||
|
)
|
||||||
|
generators = ("virtualrunenv",)
|
||||||
|
default_options = {
|
||||||
|
"libarchive:with_bzip2": True,
|
||||||
|
"libarchive:with_lz4": True,
|
||||||
|
"libarchive:with_lzo": True,
|
||||||
|
"libarchive:with_lzma": True,
|
||||||
|
"libarchive:with_zstd": True,
|
||||||
|
"pcre2:support_jit": True,
|
||||||
|
"pcre2:build_pcre2_8": True,
|
||||||
|
"sqlite3:enable_json1": True,
|
||||||
|
"sqlite3:enable_soundex": True,
|
||||||
|
"readline:with_library": "curses",
|
||||||
|
}
|
||||||
|
|
||||||
|
def generate(self):
|
||||||
|
CMakeToolchain(self).generate()
|
||||||
|
CMakeDeps(self).generate()
|
||||||
|
|
||||||
|
def build(self):
|
||||||
|
cmake = CMake(self)
|
||||||
|
cmake.configure()
|
||||||
|
if self.settings.os == "Macos" and self.settings.arch == "armv8":
|
||||||
|
cmake.definitions["CMAKE_SYSTEM_PROCESSOR"] = "arm64"
|
||||||
|
cmake.build()
|
||||||
|
|
||||||
|
def package(self):
|
||||||
|
cmake = CMake(self)
|
||||||
|
cmake.install()
|
||||||
|
|
||||||
|
def deploy(self):
|
||||||
|
self.copy("*", dst="bin", src="bin")
|
@ -1,19 +0,0 @@
|
|||||||
# syntax=docker/dockerfile:1
|
|
||||||
|
|
||||||
ARG PYTHON_VERSION=3.12.3
|
|
||||||
|
|
||||||
FROM python:${PYTHON_VERSION}-slim
|
|
||||||
|
|
||||||
LABEL fly_launch_runtime="flask"
|
|
||||||
|
|
||||||
WORKDIR /code
|
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends gcc build-essential
|
|
||||||
COPY requirements.txt requirements.txt
|
|
||||||
RUN pip3 install -r requirements.txt
|
|
||||||
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
EXPOSE 8080
|
|
||||||
|
|
||||||
CMD [ "python3", "-m" , "flask", "run", "--host=0.0.0.0", "--port=8080"]
|
|
@ -1 +0,0 @@
|
|||||||
web: gunicorn app:app
|
|
@ -1,148 +0,0 @@
|
|||||||
from werkzeug.middleware.proxy_fix import ProxyFix
|
|
||||||
from flask import Flask, request, send_file, after_this_request
|
|
||||||
import os
|
|
||||||
import glob
|
|
||||||
import uuid
|
|
||||||
from datetime import datetime
|
|
||||||
import zipfile
|
|
||||||
import spookyhash
|
|
||||||
|
|
||||||
app = Flask(__name__)
|
|
||||||
app.wsgi_app = ProxyFix(
|
|
||||||
app.wsgi_app, x_for=2, x_proto=2, x_host=2, x_prefix=2
|
|
||||||
)
|
|
||||||
|
|
||||||
ROOT_PAGE = """
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>lnav crash upload site</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
You can help improve <b>lnav</b> by uploading your crash logs by running:
|
|
||||||
<pre>
|
|
||||||
lnav -m crash upload
|
|
||||||
</pre>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
# Function to check free space on filesystem
|
|
||||||
def check_free_space():
|
|
||||||
statvfs = os.statvfs('/logs')
|
|
||||||
# Calculate free space in MB
|
|
||||||
free_space_mb = (statvfs.f_bsize * statvfs.f_bavail) / (1024 * 1024)
|
|
||||||
return free_space_mb
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/crash', methods=['POST'])
|
|
||||||
def crash_handler():
|
|
||||||
# Check free space on filesystem
|
|
||||||
free_space_mb = check_free_space()
|
|
||||||
if free_space_mb < 100:
|
|
||||||
return 'Insufficient free space on the filesystem!\n', 500
|
|
||||||
|
|
||||||
# Retrieve the secret value from the environment variable
|
|
||||||
lnav_secret_env = os.environ.get('LNAV_SECRET')
|
|
||||||
|
|
||||||
# Check if header 'lnav-secret' exists and has the correct value
|
|
||||||
if request.headers.get('lnav-secret') == lnav_secret_env:
|
|
||||||
# Check if content length is provided
|
|
||||||
if 'Content-Length' not in request.headers:
|
|
||||||
return 'Content length header is missing!', 400
|
|
||||||
|
|
||||||
# Get the content length
|
|
||||||
content_length = int(request.headers['Content-Length'])
|
|
||||||
|
|
||||||
# Check if content length is zero
|
|
||||||
if content_length == 0:
|
|
||||||
return 'Empty request body!', 400
|
|
||||||
|
|
||||||
# Check if content length exceeds 10MB
|
|
||||||
if content_length > 10 * 1024 * 1024: # 10MB limit
|
|
||||||
return 'Content size exceeds the limit of 10MB!', 413
|
|
||||||
|
|
||||||
# Get the content from the request body
|
|
||||||
content = request.data
|
|
||||||
|
|
||||||
nonce = request.headers.get('X-lnav-nonce', '')
|
|
||||||
crash_hash = request.headers.get('X-lnav-hash', '')
|
|
||||||
if not crash_hash.startswith("0000"):
|
|
||||||
return "Invalid proof of work hash", 401
|
|
||||||
|
|
||||||
sh = spookyhash.Hash128()
|
|
||||||
sh.update(nonce.encode('utf-8'))
|
|
||||||
sh.update(content)
|
|
||||||
verify_hash = sh.hexdigest()
|
|
||||||
if verify_hash != crash_hash:
|
|
||||||
return "Proof of work hash does not match", 401
|
|
||||||
|
|
||||||
# Generate a unique ID
|
|
||||||
unique_id = str(uuid.uuid4())
|
|
||||||
|
|
||||||
# Get the current time
|
|
||||||
current_time = datetime.now().strftime('%Y-%m-%d_%H-%M-%S')
|
|
||||||
|
|
||||||
# Construct the file name with current time and unique ID
|
|
||||||
file_name = f'crash_log_{current_time}_{unique_id}.txt'
|
|
||||||
full_path = os.path.join("/logs", file_name)
|
|
||||||
|
|
||||||
# Save the content to the file in the current directory
|
|
||||||
with open(full_path, 'wb') as f:
|
|
||||||
f.write(content)
|
|
||||||
|
|
||||||
return 'Data saved successfully!', 200
|
|
||||||
else:
|
|
||||||
return 'Unauthorized access!', 401
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/download_crashes', methods=['GET'])
|
|
||||||
def download_crashes():
|
|
||||||
# Retrieve the secret value for downloading from the environment variable
|
|
||||||
lnav_download_secret_env = os.environ.get('LNAV_DOWNLOAD_SECRET')
|
|
||||||
|
|
||||||
# Check if header 'lnav-secret' exists and has the correct value for downloading
|
|
||||||
if request.headers.get('lnav-secret') == lnav_download_secret_env:
|
|
||||||
# Get all the files in the current directory
|
|
||||||
crash_files = glob.glob("/logs/crash_log_*")
|
|
||||||
|
|
||||||
# Generate a unique ID for the zip file
|
|
||||||
zip_id = str(uuid.uuid4())
|
|
||||||
|
|
||||||
# Construct the zip file name
|
|
||||||
zip_file_name = f'crash_archive_{zip_id}.zip'
|
|
||||||
|
|
||||||
# Create a new zip file
|
|
||||||
with zipfile.ZipFile(zip_file_name, 'w') as zipf:
|
|
||||||
# Add each crash file to the zip file
|
|
||||||
for crash_file in crash_files:
|
|
||||||
zipf.write(crash_file)
|
|
||||||
|
|
||||||
# Delete the crash files
|
|
||||||
for crash_file in crash_files:
|
|
||||||
os.remove(crash_file)
|
|
||||||
|
|
||||||
@after_this_request
|
|
||||||
def remove_zip(response):
|
|
||||||
try:
|
|
||||||
os.remove(zip_file_name)
|
|
||||||
except Exception as e:
|
|
||||||
app.logger.error(f"Error removing zip file: {e}")
|
|
||||||
return response
|
|
||||||
|
|
||||||
# Send the zip file as a response
|
|
||||||
return send_file(zip_file_name, as_attachment=True, download_name=zip_file_name)
|
|
||||||
|
|
||||||
else:
|
|
||||||
return 'Unauthorized access!\n', 401
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/', methods=['GET'])
|
|
||||||
def root_page():
|
|
||||||
return ROOT_PAGE, 200
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
# Run the Flask app
|
|
||||||
app.run()
|
|
@ -1,26 +0,0 @@
|
|||||||
# fly.toml app configuration file generated for crashd on 2024-05-24T15:13:43-07:00
|
|
||||||
#
|
|
||||||
# See https://fly.io/docs/reference/configuration/ for information about how to use this file.
|
|
||||||
#
|
|
||||||
|
|
||||||
app = 'crashd'
|
|
||||||
primary_region = 'sea'
|
|
||||||
|
|
||||||
[build]
|
|
||||||
|
|
||||||
[mounts]
|
|
||||||
source = "crash_logs"
|
|
||||||
destination = "/logs"
|
|
||||||
|
|
||||||
[http_service]
|
|
||||||
internal_port = 8080
|
|
||||||
force_https = true
|
|
||||||
auto_stop_machines = true
|
|
||||||
auto_start_machines = true
|
|
||||||
min_machines_running = 0
|
|
||||||
processes = ['app']
|
|
||||||
|
|
||||||
[[vm]]
|
|
||||||
memory = '1gb'
|
|
||||||
cpu_kind = 'shared'
|
|
||||||
cpus = 1
|
|
@ -1,10 +0,0 @@
|
|||||||
blinker==1.8.2
|
|
||||||
click==8.1.7
|
|
||||||
Flask==3.0.3
|
|
||||||
gunicorn==22.0.0
|
|
||||||
itsdangerous==2.2.0
|
|
||||||
Jinja2==3.1.4
|
|
||||||
MarkupSafe==2.1.5
|
|
||||||
packaging==24.0
|
|
||||||
spookyhash==2.1.0
|
|
||||||
Werkzeug==3.0.3
|
|
@ -1,51 +0,0 @@
|
|||||||
---
|
|
||||||
layout: post
|
|
||||||
title: Support for the PRQL in the database query prompt
|
|
||||||
excerpt: >-
|
|
||||||
PRQL is a database query language that is pipeline-oriented
|
|
||||||
and easier to use interactively
|
|
||||||
---
|
|
||||||
|
|
||||||
The v0.12.1 release of lnav includes support for
|
|
||||||
[PRQL](https://prql-lang.org). PRQL is a database query language
|
|
||||||
that has a pipeline-oriented syntax. The main advantage of PRQL,
|
|
||||||
in the context of lnav, is that it is easier to work with
|
|
||||||
interactively compared to SQL. For example, lnav can provide
|
|
||||||
previews of different stages of the pipeline and provide more
|
|
||||||
accurate tab-completions for the columns in the result set. I'm
|
|
||||||
hoping that the ease-of-use will make doing log analysis in lnav
|
|
||||||
much easier.
|
|
||||||
|
|
||||||
You can execute a PRQL query using the existing database prompt
|
|
||||||
(press `;`). A query is interpreted as PRQL if it starts with
|
|
||||||
the [`from`](https://prql-lang.org/book/reference/data/from.html)
|
|
||||||
keyword. After `from`, the database table should be provided.
|
|
||||||
The table for the focused log message will be suggested by default.
|
|
||||||
You can accept the suggestion by pressing TAB. To add a new stage
|
|
||||||
to the pipeline, enter a pipe symbol (`|`), followed by a
|
|
||||||
[PRQL transform](https://prql-lang.org/book/reference/stdlib/transforms/index.html)
|
|
||||||
and its arguments. In addition to the standard set of transforms,
|
|
||||||
lnav provides some convenience transforms in the `stats` and `utils`
|
|
||||||
namespaces. For example, `stats.count_by` can be passed one or more
|
|
||||||
column names to group by and count, with the result sorted by most
|
|
||||||
to least.
|
|
||||||
|
|
||||||
As you enter a query, lnav will update various panels on the display
|
|
||||||
to show help, preview data, and errors. The following is a
|
|
||||||
screenshot of lnav viewing a web access log with a query in progress:
|
|
||||||
|
|
||||||
![Screenshot of PRQL in action](/assets/images/lnav-prql-preview.png)
|
|
||||||
|
|
||||||
The top half is the usual log message view. Below that is the online
|
|
||||||
help panel showing the documentation for the `stats.count_by` PRQL
|
|
||||||
function. lnav will show the help for what is currently under the
|
|
||||||
cursor. The next panel shows the preview data for the pipeline stage
|
|
||||||
that precedes the stage where the cursor is. In this case, the
|
|
||||||
results of `from access_log`, which is the contents of the access
|
|
||||||
log table. The second preview window shows the result of the
|
|
||||||
pipeline stage where the cursor is located.
|
|
||||||
|
|
||||||
There is still a lot of work to be done on the integration and PRQL
|
|
||||||
itself, but I'm very hopeful this will work out well in the long
|
|
||||||
term. Many thanks to the PRQL team for starting the project and
|
|
||||||
keeping it going, it's not easy competing with SQL.
|
|
Before Width: | Height: | Size: 774 KiB |
Before Width: | Height: | Size: 1.5 MiB After Width: | Height: | Size: 1.5 MiB |
Before Width: | Height: | Size: 1.3 MiB After Width: | Height: | Size: 1.3 MiB |
Before Width: | Height: | Size: 400 KiB After Width: | Height: | Size: 35 KiB |
@ -1,70 +0,0 @@
|
|||||||
vcpkg_download_distfile(
|
|
||||||
ARCHIVE_PATH
|
|
||||||
URLS
|
|
||||||
"https://invisible-mirror.net/archives/ncurses/ncurses-${VERSION}.tar.gz"
|
|
||||||
"ftp://ftp.invisible-island.net/ncurses/ncurses-${VERSION}.tar.gz"
|
|
||||||
"https://ftp.gnu.org/gnu/ncurses/ncurses-${VERSION}.tar.gz"
|
|
||||||
FILENAME "ncurses-${VERSION}.tgz"
|
|
||||||
SHA512 1c2efff87a82a57e57b0c60023c87bae93f6718114c8f9dc010d4c21119a2f7576d0225dab5f0a227c2cfc6fb6bdbd62728e407f35fce5bf351bb50cf9e0fd34
|
|
||||||
)
|
|
||||||
|
|
||||||
vcpkg_extract_source_archive(
|
|
||||||
SOURCE_PATH
|
|
||||||
ARCHIVE "${ARCHIVE_PATH}"
|
|
||||||
)
|
|
||||||
|
|
||||||
vcpkg_list(SET OPTIONS)
|
|
||||||
|
|
||||||
if (VCPKG_LIBRARY_LINKAGE STREQUAL "dynamic")
|
|
||||||
list(APPEND OPTIONS
|
|
||||||
--with-cxx-shared
|
|
||||||
--with-shared # "lib model"
|
|
||||||
--without-normal # "lib model"
|
|
||||||
)
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
if (NOT VCPKG_TARGET_IS_MINGW)
|
|
||||||
list(APPEND OPTIONS
|
|
||||||
--enable-mixed-case
|
|
||||||
)
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
if (VCPKG_TARGET_IS_MINGW)
|
|
||||||
list(APPEND OPTIONS
|
|
||||||
--disable-home-terminfo
|
|
||||||
--enable-term-driver
|
|
||||||
--disable-termcap
|
|
||||||
)
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
vcpkg_configure_make(
|
|
||||||
SOURCE_PATH "${SOURCE_PATH}"
|
|
||||||
DETERMINE_BUILD_TRIPLET
|
|
||||||
NO_ADDITIONAL_PATHS
|
|
||||||
OPTIONS
|
|
||||||
${OPTIONS}
|
|
||||||
--disable-db-install
|
|
||||||
--enable-pc-files
|
|
||||||
--enable-widec
|
|
||||||
--enable-sigwinch
|
|
||||||
--enable-termcap
|
|
||||||
--enable-ext-colors
|
|
||||||
--without-ada
|
|
||||||
--without-debug # "lib model"
|
|
||||||
--without-manpages
|
|
||||||
--without-progs
|
|
||||||
--without-tack
|
|
||||||
--without-tests
|
|
||||||
--with-pkg-config-libdir=libdir
|
|
||||||
)
|
|
||||||
vcpkg_install_make()
|
|
||||||
|
|
||||||
vcpkg_fixup_pkgconfig()
|
|
||||||
|
|
||||||
file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/bin")
|
|
||||||
file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/bin")
|
|
||||||
file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include")
|
|
||||||
file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/share")
|
|
||||||
|
|
||||||
file(INSTALL "${CMAKE_CURRENT_LIST_DIR}/usage" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}")
|
|
||||||
vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/COPYING")
|
|
@ -1,10 +0,0 @@
|
|||||||
The package ncurses is compatible with built-in CMake variables:
|
|
||||||
|
|
||||||
set(CURSES_NEED_NCURSES TRUE)
|
|
||||||
find_package(Curses REQUIRED)
|
|
||||||
target_include_directories(main PRIVATE ${CURSES_INCLUDE_DIRS})
|
|
||||||
target_compile_options(main PRIVATE ${CURSES_CFLAGS})
|
|
||||||
target_link_libraries(main PRIVATE ${CURSES_LIBRARIES})
|
|
||||||
|
|
||||||
|
|
||||||
Blah
|
|
@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "ncurses",
|
|
||||||
"version": "6.4",
|
|
||||||
"port-version": 2,
|
|
||||||
"description": "Free software emulation of curses in System V Release 4.0, and more",
|
|
||||||
"homepage": "https://invisible-island.net/ncurses/announce.html",
|
|
||||||
"license": "MIT",
|
|
||||||
"supports": "!windows | mingw"
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
set(VCPKG_POLICY_EMPTY_PACKAGE enabled)
|
|
@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "readline-osx",
|
|
||||||
"version-date": "2020-01-04",
|
|
||||||
"description": "empty package, linking to readline-unix",
|
|
||||||
"supports": "osx",
|
|
||||||
"dependencies": [
|
|
||||||
"readline-unix"
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
set(filename readline-${VERSION}.tar.gz)
|
|
||||||
vcpkg_download_distfile(
|
|
||||||
ARCHIVE
|
|
||||||
URLS
|
|
||||||
"https://ftpmirror.gnu.org/gnu/readline/${filename}"
|
|
||||||
"https://ftp.gnu.org/gnu/readline/${filename}"
|
|
||||||
FILENAME "${filename}"
|
|
||||||
SHA512 0a451d459146bfdeecc9cdd94bda6a6416d3e93abd80885a40b334312f16eb890f8618a27ca26868cebbddf1224983e631b1cbc002c1a4d1cd0d65fba9fea49a
|
|
||||||
)
|
|
||||||
|
|
||||||
vcpkg_extract_source_archive(SOURCE_PATH
|
|
||||||
ARCHIVE "${ARCHIVE}"
|
|
||||||
PATCHES
|
|
||||||
8.2p1.diff
|
|
||||||
)
|
|
||||||
|
|
||||||
vcpkg_configure_make(
|
|
||||||
SOURCE_PATH "${SOURCE_PATH}"
|
|
||||||
DETERMINE_BUILD_TRIPLET
|
|
||||||
OPTIONS
|
|
||||||
--with-curses=yes
|
|
||||||
--disable-install-examples
|
|
||||||
)
|
|
||||||
|
|
||||||
vcpkg_install_make()
|
|
||||||
|
|
||||||
file(REMOVE_RECURSE
|
|
||||||
"${CURRENT_PACKAGES_DIR}/debug/share"
|
|
||||||
"${CURRENT_PACKAGES_DIR}/tools"
|
|
||||||
)
|
|
||||||
|
|
||||||
vcpkg_fixup_pkgconfig()
|
|
||||||
|
|
||||||
file(INSTALL "${SOURCE_PATH}/COPYING" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}" RENAME copyright)
|
|
@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "readline-unix",
|
|
||||||
"version": "8.2",
|
|
||||||
"port-version": 1,
|
|
||||||
"description": "The GNU Readline library provides a set of functions for use by applications that allow users to edit command lines as they are typed in.",
|
|
||||||
"homepage": "https://tiswww.case.edu/php/chet/readline/rltop.html",
|
|
||||||
"license": "GPL-3.0-or-later",
|
|
||||||
"supports": "!windows",
|
|
||||||
"dependencies": [
|
|
||||||
"ncurses"
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
if(VCPKG_CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
|
|
||||||
message(FATAL_ERROR "No implementation of readline is currently available for UWP targets")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(VCPKG_POLICY_EMPTY_PACKAGE enabled)
|
|
||||||
FILE(INSTALL "${CMAKE_CURRENT_LIST_DIR}/usage" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}")
|
|
@ -1,10 +0,0 @@
|
|||||||
the package readline can be used under windows via:
|
|
||||||
|
|
||||||
find_package(unofficial-readline-win32 CONFIG REQUIRED)
|
|
||||||
target_link_libraries(main PRIVATE unofficial::readline-win32::readline)
|
|
||||||
|
|
||||||
The package readline can be imported via the CMake FindPkgConfig module:
|
|
||||||
|
|
||||||
find_package(PkgConfig REQUIRED)
|
|
||||||
pkg_check_modules(readline REQUIRED IMPORTED_TARGET readline)
|
|
||||||
target_link_libraries(main PRIVATE PkgConfig::readline)
|
|
@ -1,17 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "readline",
|
|
||||||
"version": "0",
|
|
||||||
"port-version": 5,
|
|
||||||
"description": "GNU readline and history libraries",
|
|
||||||
"supports": "!uwp",
|
|
||||||
"dependencies": [
|
|
||||||
{
|
|
||||||
"name": "readline-unix",
|
|
||||||
"platform": "!windows"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "readline-win32",
|
|
||||||
"platform": "windows"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,88 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2024, Timothy Stack
|
|
||||||
*
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
* * Neither the name of Timothy Stack nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef lnav_itertools_enumerate_hh
|
|
||||||
#define lnav_itertools_enumerate_hh
|
|
||||||
|
|
||||||
#include <tuple>
|
|
||||||
|
|
||||||
namespace lnav::itertools {
|
|
||||||
|
|
||||||
namespace details {
|
|
||||||
|
|
||||||
template<typename Iterator, typename CounterType = size_t>
|
|
||||||
class EnumerateIterator {
|
|
||||||
Iterator iter;
|
|
||||||
CounterType index;
|
|
||||||
|
|
||||||
public:
|
|
||||||
EnumerateIterator(Iterator iter, CounterType index)
|
|
||||||
: iter(std::move(iter)), index(index)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
EnumerateIterator& operator++()
|
|
||||||
{
|
|
||||||
++iter;
|
|
||||||
++index;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto operator*() { return std::forward_as_tuple(index, *iter); }
|
|
||||||
bool operator!=(EnumerateIterator const& rhs) const
|
|
||||||
{
|
|
||||||
return iter != rhs.iter;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace details
|
|
||||||
|
|
||||||
template<typename Iterable, typename CounterType = size_t>
|
|
||||||
class enumerate {
|
|
||||||
public:
|
|
||||||
enumerate(Iterable& iterable, CounterType start = 0)
|
|
||||||
: iterable(iterable), index(start)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
auto begin()
|
|
||||||
{
|
|
||||||
return details::EnumerateIterator{std::begin(iterable), index};
|
|
||||||
}
|
|
||||||
|
|
||||||
auto end() { return details::EnumerateIterator{std::end(iterable), index}; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
Iterable& iterable;
|
|
||||||
CounterType index;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace lnav::itertools
|
|
||||||
|
|
||||||
#endif
|
|