mirror of
https://github.com/boltgolt/howdy.git
synced 2024-09-12 09:41:18 +02:00
build: add meson build system
Add Meson as a build system for the whole howdy package, which allow better flexibility for the paths configuration. Generate a python module, which contains the paths used by the other modules and the header containing the paths for the PAM module.
This commit is contained in:
parent
53a6ea5eb1
commit
2d2480054d
18 changed files with 189 additions and 40 deletions
3
howdy/src/bin/howdy.in
Normal file
3
howdy/src/bin/howdy.in
Normal file
|
@ -0,0 +1,3 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
/usr/bin/env python3 "@script_path@" "$@"
|
|
@ -28,7 +28,7 @@ except ImportError as err:
|
|||
import cv2
|
||||
|
||||
# Test if at lest 1 of the data files is there and abort if it's not
|
||||
if not os.path.isfile(paths.dlib_data_dir + "shape_predictor_5_face_landmarks.dat"):
|
||||
if not os.path.isfile(paths.dlib_data_dir / "shape_predictor_5_face_landmarks.dat"):
|
||||
print(_("Data files have not been downloaded, please run the following commands:"))
|
||||
print("\n\tcd " + paths.dlib_data_dir)
|
||||
print("\tsudo ./install.sh\n")
|
||||
|
@ -36,20 +36,20 @@ if not os.path.isfile(paths.dlib_data_dir + "shape_predictor_5_face_landmarks.da
|
|||
|
||||
# Read config from disk
|
||||
config = configparser.ConfigParser()
|
||||
config.read(paths.config_dir + "/config.ini")
|
||||
config.read(paths.config_dir / "config.ini")
|
||||
|
||||
use_cnn = config.getboolean("core", "use_cnn", fallback=False)
|
||||
if use_cnn:
|
||||
face_detector = dlib.cnn_face_detection_model_v1(paths.dlib_data_dir + "mmod_human_face_detector.dat")
|
||||
face_detector = dlib.cnn_face_detection_model_v1(paths.dlib_data_dir / "mmod_human_face_detector.dat")
|
||||
else:
|
||||
face_detector = dlib.get_frontal_face_detector()
|
||||
|
||||
pose_predictor = dlib.shape_predictor(paths.dlib_data_dir + "shape_predictor_5_face_landmarks.dat")
|
||||
face_encoder = dlib.face_recognition_model_v1(paths.dlib_data_dir + "dlib_face_recognition_resnet_model_v1.dat")
|
||||
pose_predictor = dlib.shape_predictor(paths.dlib_data_dir / "shape_predictor_5_face_landmarks.dat")
|
||||
face_encoder = dlib.face_recognition_model_v1(paths.dlib_data_dir / "dlib_face_recognition_resnet_model_v1.dat")
|
||||
|
||||
user = builtins.howdy_user
|
||||
# The permanent file to store the encoded model in
|
||||
enc_file = paths.user_models_dir + user + ".dat"
|
||||
enc_file = paths.user_models_dir / f"{user}.dat"
|
||||
# Known encodings
|
||||
encodings = []
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ if not os.path.exists(paths.user_models_dir):
|
|||
sys.exit(1)
|
||||
|
||||
# Check if the user has a models file to delete
|
||||
if not os.path.isfile(paths.user_models_dir + user + ".dat"):
|
||||
if not os.path.isfile(paths.user_models_dir / f"{user}.dat"):
|
||||
print(_("{} has no models or they have been cleared already").format(user))
|
||||
sys.exit(1)
|
||||
|
||||
|
@ -33,5 +33,5 @@ if not builtins.howdy_args.y:
|
|||
sys.exit(1)
|
||||
|
||||
# Delete otherwise
|
||||
os.remove(paths.user_models_dir + user + ".dat")
|
||||
os.remove(paths.user_models_dir / f"{user}.dat")
|
||||
print(_("\nModels cleared"))
|
||||
|
|
|
@ -20,4 +20,4 @@ elif os.path.isfile("/etc/alternatives/editor"):
|
|||
editor = "/etc/alternatives/editor"
|
||||
|
||||
# Open the editor as a subprocess and fork it
|
||||
subprocess.call([editor, paths.config_dir + "config.ini"])
|
||||
subprocess.call([editor, paths.config_dir / "config.ini"])
|
||||
|
|
|
@ -11,7 +11,7 @@ import paths
|
|||
from i18n import _
|
||||
|
||||
# Get the absolute filepath
|
||||
config_path = os.path.dirname(paths.config_dir) + "/config.ini"
|
||||
config_path = paths.config_dir.parent / "config.ini"
|
||||
|
||||
# Read config from disk
|
||||
config = configparser.ConfigParser()
|
||||
|
|
|
@ -19,7 +19,7 @@ if not os.path.exists(paths.user_models_dir):
|
|||
sys.exit(1)
|
||||
|
||||
# Path to the models file
|
||||
enc_file = paths.user_models_dir + user + ".dat"
|
||||
enc_file = paths.user_models_dir / f"{user}.dat"
|
||||
|
||||
# Try to load the models file and abort if the user does not have it yet
|
||||
try:
|
||||
|
|
|
@ -27,7 +27,7 @@ if not os.path.exists(paths.user_models_dir):
|
|||
sys.exit(1)
|
||||
|
||||
# Path to the models file
|
||||
enc_file = paths.user_models_dir + user + ".dat"
|
||||
enc_file = paths.user_models_dir / f"{user}.dat"
|
||||
|
||||
# Try to load the models file and abort if the user does not have it yet
|
||||
try:
|
||||
|
@ -71,7 +71,7 @@ if not found:
|
|||
|
||||
# Remove the entire file if this encoding is the only one
|
||||
if len(encodings) == 1:
|
||||
os.remove(paths.user_models_dir + user + ".dat")
|
||||
os.remove(paths.user_models_dir / f"{user}.dat")
|
||||
print(_("Removed last model, howdy disabled for user"))
|
||||
else:
|
||||
# A place holder to contain the encodings that will remain
|
||||
|
|
|
@ -10,7 +10,7 @@ import paths
|
|||
from i18n import _
|
||||
|
||||
# Get the absolute filepath
|
||||
config_path = os.path.dirname(paths.config_dir) + "/config.ini"
|
||||
config_path = paths.config_dir / "/config.ini"
|
||||
|
||||
# Check if enough arguments have been passed
|
||||
if len(builtins.howdy_args.arguments) < 2:
|
||||
|
|
|
@ -12,7 +12,7 @@ from i18n import _
|
|||
|
||||
# Read the config
|
||||
config = configparser.ConfigParser()
|
||||
config.read(paths.config_dir + "config.ini")
|
||||
config.read(paths.config_dir / "config.ini")
|
||||
|
||||
# Start video capture
|
||||
video_capture = VideoCapture(config)
|
||||
|
|
|
@ -20,7 +20,7 @@ path = "/etc/howdy"
|
|||
|
||||
# Read config from disk
|
||||
config = configparser.ConfigParser()
|
||||
config.read(paths.config_dir + "config.ini")
|
||||
config.read(paths.config_dir / "config.ini")
|
||||
|
||||
if config.get("video", "recording_plugin", fallback="opencv") != "opencv":
|
||||
print(_("Howdy has been configured to use a recorder which doesn't support the test command yet, aborting"))
|
||||
|
@ -60,20 +60,20 @@ use_cnn = config.getboolean('core', 'use_cnn', fallback=False)
|
|||
|
||||
if use_cnn:
|
||||
face_detector = dlib.cnn_face_detection_model_v1(
|
||||
paths.dlib_data_dir + "mmod_human_face_detector.dat"
|
||||
paths.dlib_data_dir / "mmod_human_face_detector.dat"
|
||||
)
|
||||
else:
|
||||
face_detector = dlib.get_frontal_face_detector()
|
||||
|
||||
pose_predictor = dlib.shape_predictor(paths.dlib_data_dir + "shape_predictor_5_face_landmarks.dat")
|
||||
face_encoder = dlib.face_recognition_model_v1(paths.dlib_data_dir + "dlib_face_recognition_resnet_model_v1.dat")
|
||||
pose_predictor = dlib.shape_predictor(paths.dlib_data_dir / "shape_predictor_5_face_landmarks.dat")
|
||||
face_encoder = dlib.face_recognition_model_v1(paths.dlib_data_dir / "dlib_face_recognition_resnet_model_v1.dat")
|
||||
|
||||
encodings = []
|
||||
models = None
|
||||
|
||||
try:
|
||||
user = builtins.howdy_user
|
||||
models = json.load(open(paths.user_models_dir + user + ".dat"))
|
||||
models = json.load(open(paths.user_models_dir / f"{user}.dat"))
|
||||
|
||||
for model in models:
|
||||
encodings += model["data"]
|
||||
|
|
|
@ -49,7 +49,7 @@ def init_detector(lock):
|
|||
global face_detector, pose_predictor, face_encoder
|
||||
|
||||
# Test if at lest 1 of the data files is there and abort if it's not
|
||||
if not os.path.isfile(paths.dlib_data_dir + "shape_predictor_5_face_landmarks.dat"):
|
||||
if not os.path.isfile(paths.dlib_data_dir / "shape_predictor_5_face_landmarks.dat"):
|
||||
print(_("Data files have not been downloaded, please run the following commands:"))
|
||||
print("\n\tcd " + paths.dlib_data_dir)
|
||||
print("\tsudo ./install.sh\n")
|
||||
|
@ -58,13 +58,13 @@ def init_detector(lock):
|
|||
|
||||
# Use the CNN detector if enabled
|
||||
if use_cnn:
|
||||
face_detector = dlib.cnn_face_detection_model_v1(paths.dlib_data_dir + "mmod_human_face_detector.dat")
|
||||
face_detector = dlib.cnn_face_detection_model_v1(paths.dlib_data_dir / "mmod_human_face_detector.dat")
|
||||
else:
|
||||
face_detector = dlib.get_frontal_face_detector()
|
||||
|
||||
# Start the others regardless
|
||||
pose_predictor = dlib.shape_predictor(paths.dlib_data_dir + "shape_predictor_5_face_landmarks.dat")
|
||||
face_encoder = dlib.face_recognition_model_v1(paths.dlib_data_dir + "dlib_face_recognition_resnet_model_v1.dat")
|
||||
pose_predictor = dlib.shape_predictor(paths.dlib_data_dir / "shape_predictor_5_face_landmarks.dat")
|
||||
face_encoder = dlib.face_recognition_model_v1(paths.dlib_data_dir / "dlib_face_recognition_resnet_model_v1.dat")
|
||||
|
||||
# Note the time it took to initialize detectors
|
||||
timings["ll"] = time.time() - timings["ll"]
|
||||
|
@ -127,7 +127,7 @@ face_encoder = None
|
|||
|
||||
# Try to load the face model from the models folder
|
||||
try:
|
||||
models = json.load(open(paths.user_models_dir + user + ".dat"))
|
||||
models = json.load(open(paths.user_models_dir / f"{user}.dat"))
|
||||
|
||||
for model in models:
|
||||
encodings += model["data"]
|
||||
|
@ -140,7 +140,7 @@ if len(models) < 1:
|
|||
|
||||
# Read config from disk
|
||||
config = configparser.ConfigParser()
|
||||
config.read(paths.config_dir + "config.ini")
|
||||
config.read(paths.config_dir / "config.ini")
|
||||
|
||||
# Get all config values needed
|
||||
use_cnn = config.getboolean("core", "use_cnn", fallback=False)
|
||||
|
|
129
howdy/src/meson.build
Normal file
129
howdy/src/meson.build
Normal file
|
@ -0,0 +1,129 @@
|
|||
project('howdy', 'cpp', license: 'MIT', license_files: '../LICENSE', version: 'beta', meson_version: '>= 1.1.0')
|
||||
|
||||
py = import('python').find_installation()
|
||||
py.dependency()
|
||||
|
||||
confdir = join_paths(get_option('sysconfdir'), 'howdy')
|
||||
dlibdatadir = join_paths(confdir, 'dlib-data')
|
||||
usermodelsdir = join_paths(confdir, 'models')
|
||||
logpath = '/var/log/howdy'
|
||||
|
||||
py_conf = configuration_data({
|
||||
'config_dir': confdir,
|
||||
'dlib_data_dir': dlibdatadir,
|
||||
'user_models_dir': usermodelsdir,
|
||||
'log_path': logpath,
|
||||
})
|
||||
|
||||
py_paths = configure_file(
|
||||
input: 'paths.py.in',
|
||||
output: 'paths.py',
|
||||
configuration: py_conf,
|
||||
)
|
||||
|
||||
py_sources = [
|
||||
'cli/__init__.py',
|
||||
'cli/add.py',
|
||||
'cli/clear.py',
|
||||
'cli/config.py',
|
||||
'cli/disable.py',
|
||||
'cli/list.py',
|
||||
'cli/remove.py',
|
||||
'cli/set.py',
|
||||
'cli/snap.py',
|
||||
'cli/test.py',
|
||||
'cli.py',
|
||||
'compare.py',
|
||||
'i18n.py',
|
||||
'recorders/__init__.py',
|
||||
'recorders/ffmpeg_reader.py',
|
||||
'recorders/pyv4l2_reader.py',
|
||||
'recorders/v4l2.py',
|
||||
'recorders/video_capture.py',
|
||||
'rubberstamps/__init__.py',
|
||||
'rubberstamps/hotkey.py',
|
||||
'rubberstamps/nod.py',
|
||||
'snapshot.py',
|
||||
py_paths,
|
||||
]
|
||||
|
||||
# Include PAM module
|
||||
compare_script_path = join_paths(py.get_install_dir(), 'howdy', 'compare.py')
|
||||
subdir('pam')
|
||||
|
||||
py.install_sources(
|
||||
py_sources,
|
||||
subdir: 'howdy',
|
||||
preserve_path: true,
|
||||
)
|
||||
|
||||
install_data('logo.png', install_tag: 'meta')
|
||||
|
||||
install_data('config.ini', install_dir: confdir, install_mode: 'rwxr--r--', install_tag: 'config')
|
||||
|
||||
install_data('dlib-data/install.sh', install_dir: dlibdatadir, install_mode: 'rwxr--r--')
|
||||
|
||||
install_data('dlib-data/Readme.md', install_dir: dlibdatadir, install_mode: 'r--r--r--', install_tag: 'docs')
|
||||
install_man('../howdy.1')
|
||||
|
||||
# if get_option('fetch_dlib_data')
|
||||
# downloader = find_program('wget')
|
||||
# bunzip2 = find_program('bunzip2')
|
||||
|
||||
# links = [
|
||||
# 'https://github.com/davisking/dlib-models/raw/master/dlib_face_recognition_resnet_model_v1.dat.bz2',
|
||||
# 'https://github.com/davisking/dlib-models/raw/master/mmod_human_face_detector.dat.bz2',
|
||||
# 'https://github.com/davisking/dlib-models/raw/master/shape_predictor_5_face_landmarks.dat.bz2'
|
||||
# ]
|
||||
|
||||
# archived_model_files = [
|
||||
# 'dlib_face_recognition_resnet_model_v1.dat.bz2',
|
||||
# 'shape_predictor_5_face_landmarks.dat.bz2',
|
||||
# 'mmod_human_face_detector.dat.bz2'
|
||||
# ]
|
||||
|
||||
# download = run_command(
|
||||
# 'download',
|
||||
# links,
|
||||
# output: archived_model_files,
|
||||
# command: [downloader, '-O', '@OUTPUT@', '@INPUT@']
|
||||
# )
|
||||
|
||||
# model_files = [
|
||||
# 'dlib_face_recognition_resnet_model_v1.dat',
|
||||
# 'shape_predictor_5_face_landmarks.dat',
|
||||
# 'mmod_human_face_detector.dat'
|
||||
# ]
|
||||
|
||||
# models = custom_target(
|
||||
# 'models',
|
||||
# input: archived_model_files,
|
||||
# output: model_files,
|
||||
# command: [bunzip2, '-k', '@INPUT@'],
|
||||
# )
|
||||
|
||||
# install_data(
|
||||
# model_files,
|
||||
# install_dir: join_paths(get_option('prefix'), get_option('libdir'), 'dlib_models'),
|
||||
# )
|
||||
|
||||
# endif
|
||||
|
||||
py_path = py.get_install_dir()
|
||||
cli_path = join_paths(py_path, 'howdy', 'cli.py')
|
||||
|
||||
conf_data = configuration_data({ 'script_path': cli_path })
|
||||
|
||||
bin_name = 'howdy'
|
||||
|
||||
bin = configure_file(
|
||||
input: 'bin/howdy.in',
|
||||
output: bin_name,
|
||||
configuration: conf_data
|
||||
)
|
||||
|
||||
install_data(
|
||||
bin,
|
||||
install_mode: 'rwxr-xr-x',
|
||||
install_dir: get_option('bindir'),
|
||||
)
|
2
howdy/src/meson.options
Normal file
2
howdy/src/meson.options
Normal file
|
@ -0,0 +1,2 @@
|
|||
option('pam_dir', type: 'string', value: '/lib/security', description: 'Set the pam_howdy destination directory')
|
||||
#option('fetch_dlib_data', type: 'boolean', value: false, description: 'Download dlib data files')
|
|
@ -41,12 +41,12 @@
|
|||
#include "enter_device.hh"
|
||||
#include "main.hh"
|
||||
#include "optional_task.hh"
|
||||
#include "paths.hh"
|
||||
|
||||
const auto DEFAULT_TIMEOUT =
|
||||
std::chrono::duration<int, std::chrono::milliseconds::period>(100);
|
||||
const auto MAX_RETRIES = 5;
|
||||
const auto PYTHON_EXECUTABLE = "python3";
|
||||
const auto COMPARE_PROCESS_PATH = "/lib/security/howdy/compare.py";
|
||||
|
||||
#define S(msg) gettext(msg)
|
||||
|
||||
|
@ -80,7 +80,8 @@ auto howdy_error(int status,
|
|||
syslog(LOG_ERR, "Failure, image too dark");
|
||||
break;
|
||||
case CompareError::INVALID_DEVICE:
|
||||
syslog(LOG_ERR, "Failure, not possible to open camera at configured path");
|
||||
syslog(LOG_ERR,
|
||||
"Failure, not possible to open camera at configured path");
|
||||
break;
|
||||
default:
|
||||
conv_function(PAM_ERROR_MSG,
|
||||
|
@ -321,7 +322,8 @@ auto identify(pam_handle_t *pamh, int flags, int argc, const char **argv,
|
|||
// Wait for the end either of the child or the password input
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutx);
|
||||
convar.wait(lock, [&] { return confirmation_type != ConfirmationType::Unset; });
|
||||
convar.wait(lock,
|
||||
[&] { return confirmation_type != ConfirmationType::Unset; });
|
||||
}
|
||||
|
||||
// The password has been entered or an error has occurred
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
project('pam_howdy', 'cpp', version: '0.1.0', default_options: ['cpp_std=c++14'])
|
||||
|
||||
inih_cpp = dependency('INIReader', fallback: ['inih', 'INIReader_dep'])
|
||||
libevdev = dependency('libevdev')
|
||||
libpam = meson.get_compiler('cpp').find_library('pam')
|
||||
|
@ -8,6 +6,16 @@ threads = dependency('threads')
|
|||
# Translations
|
||||
subdir('po')
|
||||
|
||||
# Paths
|
||||
paths = { 'compare_script_path': compare_script_path }
|
||||
|
||||
paths_h = configure_file(
|
||||
input: 'paths.hh.in',
|
||||
output: 'paths.hh',
|
||||
configuration: paths,
|
||||
install_dir: get_option('pam_dir')
|
||||
)
|
||||
|
||||
shared_library(
|
||||
'pam_howdy',
|
||||
'main.cc',
|
||||
|
@ -18,7 +26,10 @@ shared_library(
|
|||
threads,
|
||||
libevdev,
|
||||
],
|
||||
link_depends: [
|
||||
paths_h,
|
||||
],
|
||||
install: true,
|
||||
install_dir: '/lib/security',
|
||||
install_dir: get_option('pam_dir'),
|
||||
name_prefix: ''
|
||||
)
|
||||
|
|
1
howdy/src/pam/paths.hh.in
Normal file
1
howdy/src/pam/paths.hh.in
Normal file
|
@ -0,0 +1 @@
|
|||
const auto COMPARE_PROCESS_PATH = "@compare_script_path@";
|
|
@ -1,12 +1,13 @@
|
|||
from pathlib import PurePath
|
||||
|
||||
# Define the absolute path to the config directory
|
||||
config_dir = "/etc/howdy/"
|
||||
config_dir = PurePath("@config_dir@")
|
||||
|
||||
# Define the absolute path to the DLib models data directory
|
||||
dlib_data_dir = config_dir + "/dlib-data/"
|
||||
dlib_data_dir = PurePath("@dlib_data_dir@")
|
||||
|
||||
# Define the absolute path to the Howdy user models directory
|
||||
user_models_dir = config_dir + "/models/"
|
||||
user_models_dir = PurePath("@user_models_dir@")
|
||||
|
||||
# Define path to any howdy logs
|
||||
log_path = "/var/log/howdy"
|
||||
log_path = PurePath("@log_path@")
|
|
@ -52,13 +52,13 @@ def generate(frames, text_lines):
|
|||
# Made sure a snapshot folder exist
|
||||
if not os.path.exists(paths.log_path):
|
||||
os.makedirs(paths.log_path)
|
||||
if not os.path.exists(paths.log_path + "/snapshots"):
|
||||
os.makedirs(paths.log_path + "/snapshots")
|
||||
if not os.path.exists(paths.log_path / "snapshots"):
|
||||
os.makedirs(paths.log_path / "snapshots")
|
||||
|
||||
# Generate a filename based on the current time
|
||||
filename = datetime.datetime.utcnow().strftime("%Y%m%dT%H%M%S.jpg")
|
||||
# Write the image to that file
|
||||
cv2.imwrite(paths.log_path + "/snapshots/" + filename, snap)
|
||||
cv2.imwrite(paths.log_path / "snapshots" / filename, snap)
|
||||
|
||||
# Return the saved file location
|
||||
return paths.log_path + "/snapshots/" + filename
|
||||
return paths.log_path / "/snapshots/" / filename
|
||||
|
|
Loading…
Reference in a new issue