Skip to content

Commit

Permalink
Initial code
Browse files Browse the repository at this point in the history
  • Loading branch information
AttilaGombosER committed Jul 27, 2024
1 parent c8fba15 commit 88908fe
Show file tree
Hide file tree
Showing 23 changed files with 850 additions and 1 deletion.
23 changes: 23 additions & 0 deletions .github/workflows/python-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: Python test

on:
pull_request:
branches: [ "main" ]

jobs:
build:
name: Build and test

runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Verify code quality
shell: bash
run: |
cd python
pip install mypy flake8 pytest
mypy
flake8
pytest
3 changes: 2 additions & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
MIT License

Copyright (c) 2024 EffectiveRange
Copyright (c) 2024 Ferenc Nandor Janky <[email protected]>
Copyright (c) 2024 Attila Gombos <[email protected]>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
26 changes: 26 additions & 0 deletions cmake/pack_cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/bin/bash

# SPDX-FileCopyrightText: 2024 Ferenc Nandor Janky <[email protected]>
# SPDX-FileCopyrightText: 2024 Attila Gombos <[email protected]>
# SPDX-License-Identifier: MIT

set -x -e -o pipefail

if [ ! -d "$1" ]; then
echo "Usage: $0 <workspace dir>"
exit 1
fi

if [ ! -d "$1/build" ]; then
echo "No build directory found in $1"
exit 1
fi

cd "$1/build"

DEB_FILES_LIST="$(cpack . | grep "CPack: - package:" | sed -r 's/CPack: - package: //' | sed -r 's/ generated.*//')"

for f in "$DEB_FILES_LIST"
do
echo "$f"
done
Empty file added python/common/__init__.py
Empty file.
36 changes: 36 additions & 0 deletions python/common/common.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# SPDX-FileCopyrightText: 2024 Ferenc Nandor Janky <[email protected]>
# SPDX-FileCopyrightText: 2024 Attila Gombos <[email protected]>
# SPDX-License-Identifier: MIT

import re
import subprocess
import sys
from os.path import exists
from typing import Generator


def check_workspace(workspace_dir: str) -> None:
if not exists(workspace_dir):
print(f'Workspace directory {workspace_dir} does not exist', file=sys.stderr)
exit(1)

if not exists(f'{workspace_dir}/setup.py'):
print(f'There is no setup.py in the workspace directory {workspace_dir}', file=sys.stderr)
exit(2)


def run_command(workspace_dir: str, command: str | list[str], matcher: str,
first_match_only: bool = True) -> Generator[str, None, None]:
result = subprocess.run(command, cwd=workspace_dir, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

if result.returncode:
exit(result.returncode)

output = result.stdout.split('\n')
pattern = re.compile(matcher)

for line in output:
if match := pattern.match(line):
yield match.group(1)
if first_match_only:
break
92 changes: 92 additions & 0 deletions python/pack_python
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
#!/usr/bin/env python3

# SPDX-FileCopyrightText: 2024 Ferenc Nandor Janky <[email protected]>
# SPDX-FileCopyrightText: 2024 Attila Gombos <[email protected]>
# SPDX-License-Identifier: MIT

import re
import subprocess
from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter, Namespace, BooleanOptionalAction
from configparser import ConfigParser
from os.path import exists, dirname, abspath

from common.common import check_workspace

DEFAULT_PACKAGING = 'wheel'


def main() -> None:
arguments = _get_arguments()

workspace_dir = abspath(arguments.workspace_dir)

check_workspace(workspace_dir)

config_file = f'{workspace_dir}/{arguments.config_file}'

packaging = [DEFAULT_PACKAGING]

configuration = None

if exists(config_file):
parser = ConfigParser()
parser.read(config_file)

if parser.has_section('pack-python'):
configuration = dict(parser['pack-python'])

packaging_options = configuration.get('packaging', '').split()

if arguments.all:
packaging = packaging_options
else:
default = configuration.get('default', DEFAULT_PACKAGING)
if default in packaging_options:
packaging = [default]

scripts_dir = f'{abspath(dirname(__file__))}/scripts'

for script in packaging:
script_file = f'{scripts_dir}/{script}'
if exists(script_file):

command = [script_file, workspace_dir]

if configuration:
arg_string = configuration.get(script)
if arg_string:
command.extend(split_arguments(arg_string))

if arguments.python_bin:
command.extend(['-p', arguments.python_bin])

if arguments.output_dir:
command.extend(['-o', arguments.output_dir])

result = subprocess.run(command, text=True, stdout=subprocess.PIPE)

if not result.returncode:
if result.stdout:
print(result.stdout.rstrip('\n'))


def _get_arguments() -> Namespace:
parser = ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter)
parser.add_argument('-a', '--all', help='run all packaging scripts', action=BooleanOptionalAction, default=False)
parser.add_argument('-c', '--config-file', help='config file path relative to the workspace directory',
default='setup.cfg')
parser.add_argument('-p', '--python-bin', help='python executable to use', default='python3')
parser.add_argument('-o', '--output-dir', help='package output directory')
parser.add_argument('workspace_dir', help='workspace directory where setup.py is located')
return parser.parse_args()


def split_arguments(arg_string: str) -> list[str]:
# Split on spaces, but allow spaces inside double quotes
pattern = r'\"(.*?)\"|(\S+)'
matches = re.findall(pattern, arg_string)
return [match[0] if match[0] else match[1] for match in matches]


if __name__ == '__main__':
main()
111 changes: 111 additions & 0 deletions python/scripts/dh-virtualenv
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
#!/usr/bin/env python3

# SPDX-FileCopyrightText: 2024 Ferenc Nandor Janky <[email protected]>
# SPDX-FileCopyrightText: 2024 Attila Gombos <[email protected]>
# SPDX-License-Identifier: MIT

import glob
import os
import re
import shutil
import sys
from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter, Namespace
from os.path import abspath
from pathlib import Path
from typing import Generator

sys.path.append(str(Path(os.path.dirname(__file__)).resolve().parent))

from common.common import check_workspace, run_command


def main() -> None:
arguments = _get_arguments()

workspace_dir = abspath(arguments.workspace_dir)

check_workspace(workspace_dir)

output_dir = f'{workspace_dir}/dist'

if arguments.output_dir:
output_dir = abspath(arguments.output_dir)

results = create_sources(arguments, workspace_dir, output_dir)

build_dir = f'{output_dir}/{next(results)}'

results = build_package(arguments, workspace_dir, build_dir)

for result in results:
print(f'{output_dir}/{result}')


def create_sources(arguments: Namespace, workspace_dir: str, output_dir: str) -> Generator[str, None, None]:
package_name = extract_package_name(workspace_dir)

command_arguments = ['--package3', package_name, '--dist-dir', output_dir, '--with-dh-virtualenv', '--compat', '10']

if arguments.arguments:
command_arguments.extend(arguments.arguments.split())

if arguments.service_file:
command_arguments.append('--with-dh-systemd')

command = [arguments.python_bin, 'setup.py', '--command-packages=stdeb.command', 'sdist_dsc', *command_arguments]

return run_command(workspace_dir, command, r'copying setup.py -> (.+)')


def extract_package_name(workspace_dir: str) -> str:
with open(f'{workspace_dir}/setup.py', 'r') as file:
setup_code = file.read()

pattern = r'name\s*=\s*[\'"]([^\'"]+)[\'"]'

match = re.search(pattern, setup_code)

if match:
return match.group(1)
else:
return workspace_dir.split('/')[-1]


def build_package(arguments: Namespace, workspace_dir: str, build_dir: str) -> Generator[str, None, None]:
debian_dir = f'{build_dir}/debian'

if arguments.service_file:
if arguments.service_file.startswith('/'):
service_file = arguments.service_file
else:
service_file = f'{workspace_dir}/{arguments.service_file}'

shutil.copy(service_file, debian_dir)

if arguments.extra_files:
if arguments.extra_files.startswith('/'):
extra_files = arguments.extra_files
else:
extra_files = f'{workspace_dir}/{arguments.extra_files}'

for file in glob.glob(extra_files):
shutil.copy(file, debian_dir)

command = ['dpkg-buildpackage', '-us', '-uc', '-ui', '-b']

return run_command(build_dir, command, r".*'\.\./(.+\.deb)'")


def _get_arguments() -> Namespace:
parser = ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter)
parser.add_argument('-a', '--arguments', help='extra arguments passed to stdeb')
parser.add_argument('-p', '--python-bin', help='python executable to use', default='python3')
parser.add_argument('-s', '--service-file', help='service unit file path')
parser.add_argument('-e', '--extra-files', help='add extra files into debian folder before build')
parser.add_argument('-o', '--output-dir', help='package output directory')
parser.add_argument('workspace_dir', help='workspace directory where setup.py is located')
return parser.parse_args()


if __name__ == '__main__':
main()
59 changes: 59 additions & 0 deletions python/scripts/fpm-deb
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#!/usr/bin/env python3

# SPDX-FileCopyrightText: 2024 Ferenc Nandor Janky <[email protected]>
# SPDX-FileCopyrightText: 2024 Attila Gombos <[email protected]>
# SPDX-License-Identifier: MIT

import os
import sys
from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter, Namespace
from os.path import abspath
from pathlib import Path

sys.path.append(str(Path(sys.argv[0]).resolve().parent.parent))

from common.common import check_workspace, run_command


def main() -> None:
arguments = _get_arguments()

workspace_dir = abspath(arguments.workspace_dir)

check_workspace(workspace_dir)

fpm_arguments = ['-s', 'python', '-t', 'deb', '--python-bin', arguments.python_bin,
'--python-package-name-prefix', 'python3', '--log', 'error', '-f']

if arguments.arguments:
fpm_arguments.extend(arguments.arguments.split())

output_dir = f'{workspace_dir}/dist'

if arguments.output_dir:
output_dir = abspath(arguments.output_dir)

os.makedirs(output_dir, exist_ok=True)
fpm_arguments.extend(['--package', output_dir])

command = ['fpm', *fpm_arguments, 'setup.py']

results = run_command(workspace_dir, command, r'.*"(.+\.deb)"')

for result in results:
if not result.startswith('/'):
result = output_dir if arguments.output_dir else f'{workspace_dir}/{result}'
print(result)


def _get_arguments() -> Namespace:
parser = ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter)
parser.add_argument('-a', '--arguments', help='extra arguments passed to fpm')
parser.add_argument('-p', '--python-bin', help='python executable to use', default='python3')
parser.add_argument('-o', '--output-dir', help='package output directory')
parser.add_argument('workspace_dir', help='workspace directory where setup.py is located')
return parser.parse_args()


if __name__ == '__main__':
main()
Loading

0 comments on commit 88908fe

Please sign in to comment.