aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2022-03-10 17:44:54 -0500
committerJack Lloyd <[email protected]>2022-03-10 17:44:54 -0500
commit546e8064d5a428d90a02c859ea164c28366579ff (patch)
tree1d2bcd610213cfe778a567e3ca564e1d4bcbed8f
parent8de350e896c9f3a998c8eff0053630ff8fa7d560 (diff)
parent5ec991a9b0400e11d7483a4a288d6f9600e3da5c (diff)
Merge GH #2932 Add .editorconfig and Sublime Text helper scripts
-rw-r--r--.gitignore6
-rwxr-xr-xconfigure.py3
-rw-r--r--src/editors/README.md4
-rw-r--r--src/editors/editorconfig/.editorconfig17
-rw-r--r--src/editors/sublime/README.md19
-rwxr-xr-xsrc/editors/sublime/build.py148
-rw-r--r--src/editors/sublime/sublime-project57
-rwxr-xr-xsrc/scripts/ci_build.py3
8 files changed, 255 insertions, 2 deletions
diff --git a/.gitignore b/.gitignore
index 8c7a071b7..7973cba7c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,6 +24,11 @@ vgcore.*
\#*\#
.\#*
+# Editor configuration files (top level)
+/*.sublime-project
+/*.sublime-workspace
+/.editorconfig
+
# Archive files
*.tgz
*.tar
@@ -41,6 +46,7 @@ vgcore.*
*.pyc
.DS_Store
*.swp
+/*.cache
# ctags/etags files
/TAGS
diff --git a/configure.py b/configure.py
index 66a64149f..beed9bbc6 100755
--- a/configure.py
+++ b/configure.py
@@ -1948,7 +1948,8 @@ def create_template_vars(source_paths, build_paths, options, modules, cc, arch,
# Cut absolute path from main executable (e.g. configure.py or python interpreter)
# to get the same result when configuring the same thing on different machines
main_executable = os.path.basename(sys.argv[0])
- return ' '.join([main_executable] + sys.argv[1:])
+ quoted_args = [arg if ' ' not in arg else '\'' + arg + '\'' for arg in sys.argv[1:]]
+ return ' '.join([main_executable] + quoted_args)
def cmake_escape(s):
return s.replace('(', '\\(').replace(')', '\\)')
diff --git a/src/editors/README.md b/src/editors/README.md
new file mode 100644
index 000000000..30f4e3d14
--- /dev/null
+++ b/src/editors/README.md
@@ -0,0 +1,4 @@
+# Editor Configurations
+
+Those editor configurations and/or project files can be used to set up your favourite editor for developing Botan.
+To enable any of those, just symlink the respective files into the repository root.
diff --git a/src/editors/editorconfig/.editorconfig b/src/editors/editorconfig/.editorconfig
new file mode 100644
index 000000000..0dab9d754
--- /dev/null
+++ b/src/editors/editorconfig/.editorconfig
@@ -0,0 +1,17 @@
+# see https://EditorConfig.org
+root = true
+
+[*]
+end_of_line = lf
+insert_final_newline = true
+charset = utf-8
+indent_style = space
+trim_trailing_whitespace = true
+
+[*.{cpp,h}]
+indent_size = 3
+tab_width = 3
+
+[*.py]
+indent_size = 4
+tab_width = 47
diff --git a/src/editors/sublime/README.md b/src/editors/sublime/README.md
new file mode 100644
index 000000000..84edfbd55
--- /dev/null
+++ b/src/editors/sublime/README.md
@@ -0,0 +1,19 @@
+# Sublime Text Project
+
+This provides a few convenience integrations for building, testing and debugging the library.
+
+## Configuring and building
+
+The build integrations simply run an already pre-configured `Makefile`. Hence, before build integrations work, a manual `./configure.py` must be executed. After that, the sublime integration will opportunistically re-configure using the same `./configure.py` arguments.
+
+## Running a specific test
+
+There is a special build command that runs the unit test currently in Sublime's active focus. Note that this command opportunistically re-configures and builds the test binary first. Usage of a compiler cache is hence strongly recommended.
+
+## Running all tests
+
+Builds and executes all unit tests.
+
+## Applying Source Formatting
+
+Use Botan's astyle formatting rules on the C++ or header file that is currently in active focus.
diff --git a/src/editors/sublime/build.py b/src/editors/sublime/build.py
new file mode 100755
index 000000000..3081fdc50
--- /dev/null
+++ b/src/editors/sublime/build.py
@@ -0,0 +1,148 @@
+#!/usr/bin/env python3
+
+"""
+Build helper script for Botan's Sublime Text integration
+
+(C) 2022 Jack Lloyd
+(C) 2022 René Meusel (neXenio GmbH)
+
+Botan is released under the Simplified BSD License (see license.txt)
+"""
+
+import argparse
+import multiprocessing
+import subprocess
+import sys
+import os
+import re
+
+
+class BuildError(Exception):
+ pass
+
+
+def run_cmd(cmd):
+ if isinstance(cmd, str):
+ print('> running: ' + cmd)
+ shell = True
+ else:
+ print('> running: ' + ' '.join(cmd))
+ shell = False
+ sys.stdout.flush()
+
+ try:
+ subprocess.run(cmd, shell=shell, check=True)
+ except subprocess.CalledProcessError:
+ raise BuildError('Command failed, aborting...')
+
+
+def _find_regex_in_makefile(regex):
+ if not os.path.exists('Makefile'):
+ raise BuildError(
+ 'No Makefile found. Initial ./configure.py invocation must be performed manually.')
+
+ with open('Makefile', 'r') as f:
+ return re.search(regex, f.read())
+
+
+def _retrieve_test_binary_name():
+ match = _find_regex_in_makefile(r'TEST\s*=\s*([^\n]+)\n')
+ if not match:
+ raise BuildError('Test binary name not found in Makefile')
+ test_file = os.path.split(match.group(1))[1]
+ if not test_file:
+ raise BuildError(
+ 'Cannot make sense of test binary name: ' + match.group(0))
+
+ return test_file
+
+
+def _retrieve_configure_command():
+ match = _find_regex_in_makefile(r'\'(configure\.py.+)\'\n')
+ if not match:
+ raise BuildError('configure.py command not found in Makefile')
+ return match.group(1)
+
+
+def reconfigure():
+ run_cmd("./" + _retrieve_configure_command())
+
+
+def build(target=''):
+ reconfigure()
+ cmd = ['make', '-j', str(multiprocessing.cpu_count())]
+ if target:
+ cmd.append(target)
+ run_cmd(cmd)
+
+
+def _parse_test_file(test_file):
+ if not re.search(r'.+/tests/.+\.cpp', test_file):
+ raise BuildError(
+ 'Given file path is not a Botan unit test: ' + test_file)
+
+ with open(test_file, 'r') as f:
+ find_test_registration = \
+ re.compile(
+ r'BOTAN_REGISTER_TEST(_FN)?\s*\(\s*\"(.+)\",\s*\"(.+)\",[^)]+\)')
+
+ matches = find_test_registration.findall(f.read())
+ tests = [match[-1] for match in matches]
+
+ if not tests:
+ raise BuildError(
+ 'Failed to find a BOTAN_REGISTER_TEST in the given test file: ' + test_file)
+
+ return tests
+
+
+def unittests(test_file):
+ tests = _parse_test_file(test_file) if test_file else []
+
+ build('tests')
+ run_cmd(['./' + _retrieve_test_binary_name()] + tests)
+
+
+def apply_astyle_format(format_file):
+ ext = os.path.splitext(format_file)[1]
+ if ext not in ['.cpp', '.h']:
+ raise BuildError(
+ "Refuse to format source files that appear to be non-C++")
+
+ try:
+ run_cmd(['astyle',
+ '--suffix=none', # do not create a backup copy of the unformatted file
+ '--project=src/configs/astyle.rc',
+ format_file])
+ except FileNotFoundError:
+ raise BuildError(
+ "astyle utility not installed, cannot apply formatting")
+
+
+def main():
+ parser = argparse.ArgumentParser(description='Sublime build helper')
+ parser.add_argument('job', type=str)
+ parser.add_argument('--project-root', type=str, required=True)
+ parser.add_argument('--test-file', type=str, default='')
+ parser.add_argument('--format-file', type=str, default='')
+
+ opts = parser.parse_args()
+
+ os.chdir(opts.project_root)
+
+ if opts.job == 'all':
+ build()
+ elif opts.job == 'test':
+ unittests(opts.test_file)
+ elif opts.job == 'format':
+ apply_astyle_format(opts.format_file)
+ else:
+ raise RuntimeError('Unknown build job: ' + opts.job)
+
+
+if __name__ == '__main__':
+ try:
+ main()
+ except BuildError as msg:
+ print(msg, file=sys.stderr)
+ sys.exit(1)
diff --git a/src/editors/sublime/sublime-project b/src/editors/sublime/sublime-project
new file mode 100644
index 000000000..3708a9cd2
--- /dev/null
+++ b/src/editors/sublime/sublime-project
@@ -0,0 +1,57 @@
+{
+ "folders":
+ [
+ {
+ "path": ".",
+ "folder_exclude_patterns": [ ".cache", "build"]
+ }
+ ],
+ "settings":
+ {
+ "default_encoding": "UTF-8",
+ "detect_indentation": false,
+ "rulers": [80],
+ "translate_tabs_to_spaces": true,
+ "trim_automatic_white_space": true,
+ "trim_trailing_white_space_on_save": "all"
+ },
+ "build_systems": [
+ {
+ "name": "Build all Targets",
+ "cmd": [
+ "$project_path/src/editors/sublime/build.py",
+ "--project-root", "$project_path",
+ "all"],
+ "cancel": { "kill": true }
+ },
+ {
+ "name": "Apply Formatting to Current File",
+ "cmd": [
+ "$project_path/src/editors/sublime/build.py",
+ "--project-root", "$project_path",
+ "--format-file", "$file",
+ "format"],
+ "file_patterns": [ "*.cpp", "*.h" ]
+ },
+ {
+ "name": "Run Tests",
+ "cmd": [
+ "$project_path/src/editors/sublime/build.py",
+ "--project-root", "$project_path",
+ "test"
+ ],
+ "cancel": { "kill": true }
+ },
+ {
+ "name": "Run Current Test File",
+ "cmd":[
+ "$project_path/src/editors/sublime/build.py",
+ "--project-root", "$project_path",
+ "--test-file", "$file",
+ "test"
+ ],
+ "file_patterns": [ "test_*.cpp", "unit_*.cpp" ],
+ "cancel": { "kill": true }
+ }
+ ]
+}
diff --git a/src/scripts/ci_build.py b/src/scripts/ci_build.py
index 700203471..9d7ee7863 100755
--- a/src/scripts/ci_build.py
+++ b/src/scripts/ci_build.py
@@ -522,7 +522,8 @@ def main(args=None):
'src/scripts/test_fuzzers.py',
'src/scripts/test_cli.py',
'src/scripts/python_unittests.py',
- 'src/scripts/python_unittests_unix.py']
+ 'src/scripts/python_unittests_unix.py',
+ 'src/editors/sublime/build.py']
full_paths = [os.path.join(root_dir, s) for s in py_scripts]