Compare commits
16 Commits
update-3rd
...
filePath
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f7add727a6 | ||
|
|
cd947c2554 | ||
|
|
9422a30ebf | ||
|
|
ed273a6e92 | ||
|
|
0136c25e1d | ||
|
|
cf03bdc17b | ||
|
|
093b882141 | ||
|
|
46507f10b6 | ||
|
|
54fbf666fd | ||
|
|
faecaf1ee4 | ||
|
|
a062b36ee5 | ||
|
|
00b6d60309 | ||
|
|
1e0121b4d6 | ||
|
|
d7a3708a13 | ||
|
|
73ac17942f | ||
|
|
54e599a18b |
2
.github/CODEOWNERS
vendored
2
.github/CODEOWNERS
vendored
@@ -1,2 +1,2 @@
|
|||||||
# All PRs to V1 must be approved by Frooodle
|
# All PRs to V1 must be approved by Frooodle
|
||||||
* @Frooodle @reecebrowne @Ludy87 @DarioGii @ConnorYoh
|
* @Frooodle @reecebrowne @Ludy87 @DarioGii
|
||||||
|
|||||||
2
.github/labeler-config.yml
vendored
2
.github/labeler-config.yml
vendored
@@ -9,7 +9,6 @@ Front End:
|
|||||||
- any-glob-to-any-file: 'src/main/resources/templates/**/*'
|
- any-glob-to-any-file: 'src/main/resources/templates/**/*'
|
||||||
- any-glob-to-any-file: 'src/main/resources/static/**/*'
|
- any-glob-to-any-file: 'src/main/resources/static/**/*'
|
||||||
- any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/controller/web/**'
|
- any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/controller/web/**'
|
||||||
- any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/UI/**/*'
|
|
||||||
|
|
||||||
Java:
|
Java:
|
||||||
- changed-files:
|
- changed-files:
|
||||||
@@ -30,7 +29,6 @@ Security:
|
|||||||
- any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/config/security/**/*'
|
- any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/config/security/**/*'
|
||||||
- any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/model/provider/**/*'
|
- any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/model/provider/**/*'
|
||||||
- any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/model/AuthenticationType.java'
|
- any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/model/AuthenticationType.java'
|
||||||
- any-glob-to-any-file: 'src/main/java/stirling/software/SPDF/model/BackupNotFoundException.java'
|
|
||||||
- any-glob-to-any-file: 'scripts/download-security-jar.sh'
|
- any-glob-to-any-file: 'scripts/download-security-jar.sh'
|
||||||
- any-glob-to-any-file: '.github/workflows/dependency-review.yml'
|
- any-glob-to-any-file: '.github/workflows/dependency-review.yml'
|
||||||
- any-glob-to-any-file: '.github/workflows/scorecards.yml'
|
- any-glob-to-any-file: '.github/workflows/scorecards.yml'
|
||||||
|
|||||||
29
.github/pull_request_template.md
vendored
29
.github/pull_request_template.md
vendored
@@ -1,34 +1,15 @@
|
|||||||
# Description of Changes
|
# Description
|
||||||
|
|
||||||
Please provide a summary of the changes, including:
|
Please provide a summary of the changes, including relevant motivation and context.
|
||||||
|
|
||||||
- What was changed
|
|
||||||
- Why the change was made
|
|
||||||
- Any challenges encountered
|
|
||||||
|
|
||||||
Closes #(issue_number)
|
Closes #(issue_number)
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Checklist
|
## Checklist
|
||||||
|
|
||||||
### General
|
|
||||||
|
|
||||||
- [ ] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
|
- [ ] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
|
||||||
- [ ] I have read the [Stirling-PDF Developer Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md) (if applicable)
|
|
||||||
- [ ] I have read the [How to add new languages to Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md) (if applicable)
|
|
||||||
- [ ] I have performed a self-review of my own code
|
- [ ] I have performed a self-review of my own code
|
||||||
|
- [ ] I have attached images of the change if it is UI based
|
||||||
|
- [ ] I have commented my code, particularly in hard-to-understand areas
|
||||||
|
- [ ] If my code has heavily changed functionality I have updated relevant docs on [Stirling-PDFs doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
|
||||||
- [ ] My changes generate no new warnings
|
- [ ] My changes generate no new warnings
|
||||||
|
|
||||||
### Documentation
|
|
||||||
|
|
||||||
- [ ] I have updated relevant docs on [Stirling-PDF's doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/) (if functionality has heavily changed)
|
|
||||||
- [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only)
|
- [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only)
|
||||||
|
|
||||||
### UI Changes (if applicable)
|
|
||||||
|
|
||||||
- [ ] Screenshots or videos demonstrating the UI changes are attached (e.g., as comments or direct attachments in the PR)
|
|
||||||
|
|
||||||
### Testing (if applicable)
|
|
||||||
|
|
||||||
- [ ] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#6-testing) for more details.
|
|
||||||
|
|||||||
6
.github/release.yml
vendored
6
.github/release.yml
vendored
@@ -1,4 +1,10 @@
|
|||||||
changelog:
|
changelog:
|
||||||
|
exclude:
|
||||||
|
labels:
|
||||||
|
- Documentation
|
||||||
|
- Test
|
||||||
|
- Github
|
||||||
|
|
||||||
categories:
|
categories:
|
||||||
- title: Bug Fixes
|
- title: Bug Fixes
|
||||||
labels:
|
labels:
|
||||||
|
|||||||
51
.github/scripts/check_duplicates.py
vendored
Normal file
51
.github/scripts/check_duplicates.py
vendored
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def find_duplicate_keys(file_path):
|
||||||
|
"""
|
||||||
|
Finds duplicate keys in a properties file and returns their occurrences.
|
||||||
|
|
||||||
|
This function reads a properties file, identifies any keys that occur more than
|
||||||
|
once, and returns a dictionary with these keys and the line numbers of their occurrences.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
file_path (str): The path to the properties file to be checked.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: A dictionary where each key is a duplicated key in the file, and the value is a list
|
||||||
|
of line numbers where the key occurs.
|
||||||
|
"""
|
||||||
|
with open(file_path, "r", encoding="utf-8") as file:
|
||||||
|
lines = file.readlines()
|
||||||
|
|
||||||
|
keys = {}
|
||||||
|
duplicates = {}
|
||||||
|
|
||||||
|
for line_number, line in enumerate(lines, start=1):
|
||||||
|
line = line.strip()
|
||||||
|
if line and not line.startswith("#") and "=" in line:
|
||||||
|
key = line.split("=", 1)[0].strip()
|
||||||
|
if key in keys:
|
||||||
|
# If the key already exists, add the current line number
|
||||||
|
duplicates.setdefault(key, []).append(line_number)
|
||||||
|
# Also add the first instance of the key if not already done
|
||||||
|
if keys[key] not in duplicates[key]:
|
||||||
|
duplicates[key].insert(0, keys[key])
|
||||||
|
else:
|
||||||
|
# Store the line number of the first instance of the key
|
||||||
|
keys[key] = line_number
|
||||||
|
|
||||||
|
return duplicates
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
failed = False
|
||||||
|
for ar in sys.argv[1:]:
|
||||||
|
duplicates = find_duplicate_keys(ar)
|
||||||
|
if duplicates:
|
||||||
|
for key, lines in duplicates.items():
|
||||||
|
lines_str = ", ".join(map(str, lines))
|
||||||
|
print(f"{key} duplicated in {ar} on lines {lines_str}")
|
||||||
|
failed = True
|
||||||
|
if failed:
|
||||||
|
sys.exit(1)
|
||||||
122
.github/scripts/check_language_properties.py
vendored
122
.github/scripts/check_language_properties.py
vendored
@@ -11,8 +11,6 @@ adjusting the format.
|
|||||||
Usage:
|
Usage:
|
||||||
python check_language_properties.py --reference-file <path_to_reference_file> --branch <branch_name> [--actor <actor_name>] [--files <list_of_changed_files>]
|
python check_language_properties.py --reference-file <path_to_reference_file> --branch <branch_name> [--actor <actor_name>] [--files <list_of_changed_files>]
|
||||||
"""
|
"""
|
||||||
# Sample for Windows:
|
|
||||||
# python .github/scripts/check_language_properties.py --reference-file src\main\resources\messages_en_GB.properties --branch "" --files src\main\resources\messages_de_DE.properties src\main\resources\messages_uk_UA.properties
|
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
import glob
|
import glob
|
||||||
@@ -21,60 +19,25 @@ import argparse
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
|
|
||||||
def find_duplicate_keys(file_path):
|
|
||||||
"""
|
|
||||||
Identifies duplicate keys in a .properties file.
|
|
||||||
:param file_path: Path to the .properties file.
|
|
||||||
:return: List of tuples (key, first_occurrence_line, duplicate_line).
|
|
||||||
"""
|
|
||||||
keys = {}
|
|
||||||
duplicates = []
|
|
||||||
|
|
||||||
with open(file_path, "r", encoding="utf-8") as file:
|
|
||||||
for line_number, line in enumerate(file, start=1):
|
|
||||||
stripped_line = line.strip()
|
|
||||||
|
|
||||||
# Skip empty lines and comments
|
|
||||||
if not stripped_line or stripped_line.startswith("#"):
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Split the line into key and value
|
|
||||||
if "=" in stripped_line:
|
|
||||||
key, _ = stripped_line.split("=", 1)
|
|
||||||
key = key.strip()
|
|
||||||
|
|
||||||
# Check if the key already exists
|
|
||||||
if key in keys:
|
|
||||||
duplicates.append((key, keys[key], line_number))
|
|
||||||
else:
|
|
||||||
keys[key] = line_number
|
|
||||||
|
|
||||||
return duplicates
|
|
||||||
|
|
||||||
|
|
||||||
# Maximum size for properties files (e.g., 200 KB)
|
# Maximum size for properties files (e.g., 200 KB)
|
||||||
MAX_FILE_SIZE = 200 * 1024
|
MAX_FILE_SIZE = 200 * 1024
|
||||||
|
|
||||||
|
|
||||||
def parse_properties_file(file_path):
|
def parse_properties_file(file_path):
|
||||||
"""
|
"""Parses a .properties file and returns a list of objects (including comments, empty lines, and line numbers)."""
|
||||||
Parses a .properties file and returns a structured list of its contents.
|
|
||||||
:param file_path: Path to the .properties file.
|
|
||||||
:return: List of dictionaries representing each line in the file.
|
|
||||||
"""
|
|
||||||
properties_list = []
|
properties_list = []
|
||||||
with open(file_path, "r", encoding="utf-8") as file:
|
with open(file_path, "r", encoding="utf-8") as file:
|
||||||
for line_number, line in enumerate(file, start=1):
|
for line_number, line in enumerate(file, start=1):
|
||||||
stripped_line = line.strip()
|
stripped_line = line.strip()
|
||||||
|
|
||||||
# Handle empty lines
|
# Empty lines
|
||||||
if not stripped_line:
|
if not stripped_line:
|
||||||
properties_list.append(
|
properties_list.append(
|
||||||
{"line_number": line_number, "type": "empty", "content": ""}
|
{"line_number": line_number, "type": "empty", "content": ""}
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Handle comments
|
# Comments
|
||||||
if stripped_line.startswith("#"):
|
if stripped_line.startswith("#"):
|
||||||
properties_list.append(
|
properties_list.append(
|
||||||
{
|
{
|
||||||
@@ -85,7 +48,7 @@ def parse_properties_file(file_path):
|
|||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Handle key-value pairs
|
# Key-value pairs
|
||||||
match = re.match(r"^([^=]+)=(.*)$", line)
|
match = re.match(r"^([^=]+)=(.*)$", line)
|
||||||
if match:
|
if match:
|
||||||
key, value = match.groups()
|
key, value = match.groups()
|
||||||
@@ -102,14 +65,9 @@ def parse_properties_file(file_path):
|
|||||||
|
|
||||||
|
|
||||||
def write_json_file(file_path, updated_properties):
|
def write_json_file(file_path, updated_properties):
|
||||||
"""
|
|
||||||
Writes updated properties back to the file in their original format.
|
|
||||||
:param file_path: Path to the .properties file.
|
|
||||||
:param updated_properties: List of updated properties to write.
|
|
||||||
"""
|
|
||||||
updated_lines = {entry["line_number"]: entry for entry in updated_properties}
|
updated_lines = {entry["line_number"]: entry for entry in updated_properties}
|
||||||
|
|
||||||
# Sort lines by their numbers and retain comments and empty lines
|
# Sort by line numbers and retain comments and empty lines
|
||||||
all_lines = sorted(set(updated_lines.keys()))
|
all_lines = sorted(set(updated_lines.keys()))
|
||||||
|
|
||||||
original_format = []
|
original_format = []
|
||||||
@@ -128,8 +86,8 @@ def write_json_file(file_path, updated_properties):
|
|||||||
# Replace entries with those from the current JSON
|
# Replace entries with those from the current JSON
|
||||||
original_format.append(entry)
|
original_format.append(entry)
|
||||||
|
|
||||||
# Write the updated content back to the file
|
# Write back in the original format
|
||||||
with open(file_path, "w", encoding="utf-8", newline="\n") as file:
|
with open(file_path, "w", encoding="utf-8") as file:
|
||||||
for entry in original_format:
|
for entry in original_format:
|
||||||
if entry["type"] == "comment":
|
if entry["type"] == "comment":
|
||||||
file.write(f"{entry['content']}\n")
|
file.write(f"{entry['content']}\n")
|
||||||
@@ -140,12 +98,6 @@ def write_json_file(file_path, updated_properties):
|
|||||||
|
|
||||||
|
|
||||||
def update_missing_keys(reference_file, file_list, branch=""):
|
def update_missing_keys(reference_file, file_list, branch=""):
|
||||||
"""
|
|
||||||
Updates missing keys in the translation files based on the reference file.
|
|
||||||
:param reference_file: Path to the reference .properties file.
|
|
||||||
:param file_list: List of translation files to update.
|
|
||||||
:param branch: Branch where the files are located.
|
|
||||||
"""
|
|
||||||
reference_properties = parse_properties_file(reference_file)
|
reference_properties = parse_properties_file(reference_file)
|
||||||
for file_path in file_list:
|
for file_path in file_list:
|
||||||
basename_current_file = os.path.basename(os.path.join(branch, file_path))
|
basename_current_file = os.path.basename(os.path.join(branch, file_path))
|
||||||
@@ -164,7 +116,7 @@ def update_missing_keys(reference_file, file_list, branch=""):
|
|||||||
if current_entry["type"] == "entry":
|
if current_entry["type"] == "entry":
|
||||||
if ref_entry_copy["type"] != "entry":
|
if ref_entry_copy["type"] != "entry":
|
||||||
continue
|
continue
|
||||||
if ref_entry_copy["key"].lower() == current_entry["key"].lower():
|
if ref_entry_copy["key"] == current_entry["key"]:
|
||||||
ref_entry_copy["value"] = current_entry["value"]
|
ref_entry_copy["value"] = current_entry["value"]
|
||||||
updated_properties.append(ref_entry_copy)
|
updated_properties.append(ref_entry_copy)
|
||||||
write_json_file(os.path.join(branch, file_path), updated_properties)
|
write_json_file(os.path.join(branch, file_path), updated_properties)
|
||||||
@@ -199,30 +151,23 @@ def check_for_differences(reference_file, file_list, branch, actor):
|
|||||||
base_dir = os.path.abspath(os.path.join(os.getcwd(), "src", "main", "resources"))
|
base_dir = os.path.abspath(os.path.join(os.getcwd(), "src", "main", "resources"))
|
||||||
|
|
||||||
for file_path in file_arr:
|
for file_path in file_arr:
|
||||||
file_normpath = os.path.normpath(file_path)
|
absolute_path = os.path.abspath(file_path)
|
||||||
absolute_path = os.path.abspath(file_normpath)
|
|
||||||
# Verify that file is within the expected directory
|
# Verify that file is within the expected directory
|
||||||
if not absolute_path.startswith(base_dir):
|
if not absolute_path.startswith(base_dir):
|
||||||
raise ValueError(f"Unsafe file found: {file_normpath}")
|
raise ValueError(f"Unsafe file found: {file_path}")
|
||||||
# Verify file size before processing
|
# Verify file size before processing
|
||||||
if os.path.getsize(os.path.join(branch, file_normpath)) > MAX_FILE_SIZE:
|
if os.path.getsize(os.path.join(branch, file_path)) > MAX_FILE_SIZE:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
f"The file {file_normpath} is too large and could pose a security risk."
|
f"The file {file_path} is too large and could pose a security risk."
|
||||||
)
|
)
|
||||||
|
|
||||||
basename_current_file = os.path.basename(os.path.join(branch, file_normpath))
|
basename_current_file = os.path.basename(os.path.join(branch, file_path))
|
||||||
if (
|
if (
|
||||||
basename_current_file == basename_reference_file
|
basename_current_file == basename_reference_file
|
||||||
or (
|
or not file_path.startswith(
|
||||||
# only local windows command
|
os.path.join("src", "main", "resources", "messages_")
|
||||||
not file_normpath.startswith(
|
|
||||||
os.path.join("", "src", "main", "resources", "messages_")
|
|
||||||
)
|
|
||||||
and not file_normpath.startswith(
|
|
||||||
os.path.join(os.getcwd(), "src", "main", "resources", "messages_")
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
or not file_normpath.endswith(".properties")
|
or not file_path.endswith(".properties")
|
||||||
or not basename_current_file.startswith("messages_")
|
or not basename_current_file.startswith("messages_")
|
||||||
):
|
):
|
||||||
continue
|
continue
|
||||||
@@ -292,24 +237,6 @@ def check_for_differences(reference_file, file_list, branch, actor):
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
report.append("2. **Test Status:** ✅ **_Passed_**")
|
report.append("2. **Test Status:** ✅ **_Passed_**")
|
||||||
|
|
||||||
if find_duplicate_keys(os.path.join(branch, file_normpath)):
|
|
||||||
has_differences = True
|
|
||||||
output = "\n".join(
|
|
||||||
[
|
|
||||||
f" - `{key}`: first at line {first}, duplicate at `line {duplicate}`"
|
|
||||||
for key, first, duplicate in find_duplicate_keys(
|
|
||||||
os.path.join(branch, file_normpath)
|
|
||||||
)
|
|
||||||
]
|
|
||||||
)
|
|
||||||
report.append("3. **Test Status:** ❌ **_Failed_**")
|
|
||||||
report.append(" - **Issue:**")
|
|
||||||
report.append(" - duplicate entries were found:")
|
|
||||||
report.append(output)
|
|
||||||
else:
|
|
||||||
report.append("3. **Test Status:** ✅ **_Passed_**")
|
|
||||||
|
|
||||||
report.append("")
|
report.append("")
|
||||||
report.append("---")
|
report.append("---")
|
||||||
report.append("")
|
report.append("")
|
||||||
@@ -348,12 +275,6 @@ if __name__ == "__main__":
|
|||||||
required=True,
|
required=True,
|
||||||
help="Branch name.",
|
help="Branch name.",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
|
||||||
"--check-file",
|
|
||||||
type=str,
|
|
||||||
required=False,
|
|
||||||
help="List of changed files, separated by spaces.",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--files",
|
"--files",
|
||||||
nargs="+",
|
nargs="+",
|
||||||
@@ -372,14 +293,11 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
file_list = args.files
|
file_list = args.files
|
||||||
if file_list is None:
|
if file_list is None:
|
||||||
if args.check_file:
|
file_list = glob.glob(
|
||||||
file_list = [args.check_file]
|
os.path.join(
|
||||||
else:
|
os.getcwd(), "src", "main", "resources", "messages_*.properties"
|
||||||
file_list = glob.glob(
|
|
||||||
os.path.join(
|
|
||||||
os.getcwd(), "src", "main", "resources", "messages_*.properties"
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
)
|
||||||
update_missing_keys(args.reference_file, file_list)
|
update_missing_keys(args.reference_file, file_list)
|
||||||
else:
|
else:
|
||||||
check_for_differences(args.reference_file, file_list, args.branch, args.actor)
|
check_for_differences(args.reference_file, file_list, args.branch, args.actor)
|
||||||
|
|||||||
85
.github/scripts/check_tabulator.py
vendored
Normal file
85
.github/scripts/check_tabulator.py
vendored
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
"""check_tabulator.py"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def check_tabs(file_path):
|
||||||
|
"""
|
||||||
|
Checks for tabs in the specified file.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
file_path (str): The path to the file to be checked.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if tabs are found, False otherwise.
|
||||||
|
"""
|
||||||
|
with open(file_path, "r", encoding="utf-8") as file:
|
||||||
|
content = file.read()
|
||||||
|
|
||||||
|
if "\t" in content:
|
||||||
|
print(f"Tab found in {file_path}")
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def replace_tabs_with_spaces(file_path, replace_with=" "):
|
||||||
|
"""
|
||||||
|
Replaces tabs with a specified number of spaces in the file.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
file_path (str): The path to the file where tabs will be replaced.
|
||||||
|
replace_with (str): The character(s) to replace tabs with. Defaults to two spaces.
|
||||||
|
"""
|
||||||
|
with open(file_path, "r", encoding="utf-8") as file:
|
||||||
|
content = file.read()
|
||||||
|
|
||||||
|
updated_content = content.replace("\t", replace_with)
|
||||||
|
|
||||||
|
with open(file_path, "w", encoding="utf-8") as file:
|
||||||
|
file.write(updated_content)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""
|
||||||
|
Main function to replace tabs with spaces in the provided files.
|
||||||
|
The replacement character and files to check are taken from command line arguments.
|
||||||
|
"""
|
||||||
|
# Create ArgumentParser instance
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="Replace tabs in files with specified characters."
|
||||||
|
)
|
||||||
|
|
||||||
|
# Define optional argument `--replace_with`
|
||||||
|
parser.add_argument(
|
||||||
|
"--replace_with",
|
||||||
|
default=" ",
|
||||||
|
help="Character(s) to replace tabs with. Default is two spaces.",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Define argument for file paths
|
||||||
|
parser.add_argument("files", metavar="FILE", nargs="+", help="Files to process.")
|
||||||
|
|
||||||
|
# Parse arguments
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
# Extract replacement characters and files from the parsed arguments
|
||||||
|
replace_with = args.replace_with
|
||||||
|
files_checked = args.files
|
||||||
|
|
||||||
|
error = False
|
||||||
|
|
||||||
|
for file_path in files_checked:
|
||||||
|
if check_tabs(file_path):
|
||||||
|
replace_tabs_with_spaces(file_path, replace_with)
|
||||||
|
error = True
|
||||||
|
|
||||||
|
if error:
|
||||||
|
print("Error: Originally found tabs in HTML files, now replaced.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
1
.github/scripts/requirements_pre_commit.in
vendored
1
.github/scripts/requirements_pre_commit.in
vendored
@@ -1 +0,0 @@
|
|||||||
pre-commit
|
|
||||||
93
.github/scripts/requirements_pre_commit.txt
vendored
93
.github/scripts/requirements_pre_commit.txt
vendored
@@ -1,93 +0,0 @@
|
|||||||
#
|
|
||||||
# This file is autogenerated by pip-compile with Python 3.10
|
|
||||||
# by the following command:
|
|
||||||
#
|
|
||||||
# pip-compile --generate-hashes --output-file='.github\scripts\requirements_pre_commit.txt' '.github\scripts\requirements_pre_commit.in'
|
|
||||||
#
|
|
||||||
cfgv==3.4.0 \
|
|
||||||
--hash=sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9 \
|
|
||||||
--hash=sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560
|
|
||||||
# via pre-commit
|
|
||||||
distlib==0.3.9 \
|
|
||||||
--hash=sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87 \
|
|
||||||
--hash=sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403
|
|
||||||
# via virtualenv
|
|
||||||
filelock==3.16.1 \
|
|
||||||
--hash=sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0 \
|
|
||||||
--hash=sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435
|
|
||||||
# via virtualenv
|
|
||||||
identify==2.6.5 \
|
|
||||||
--hash=sha256:14181a47091eb75b337af4c23078c9d09225cd4c48929f521f3bf16b09d02566 \
|
|
||||||
--hash=sha256:c10b33f250e5bba374fae86fb57f3adcebf1161bce7cdf92031915fd480c13bc
|
|
||||||
# via pre-commit
|
|
||||||
nodeenv==1.9.1 \
|
|
||||||
--hash=sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f \
|
|
||||||
--hash=sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9
|
|
||||||
# via pre-commit
|
|
||||||
platformdirs==4.3.6 \
|
|
||||||
--hash=sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907 \
|
|
||||||
--hash=sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb
|
|
||||||
# via virtualenv
|
|
||||||
pre-commit==4.0.1 \
|
|
||||||
--hash=sha256:80905ac375958c0444c65e9cebebd948b3cdb518f335a091a670a89d652139d2 \
|
|
||||||
--hash=sha256:efde913840816312445dc98787724647c65473daefe420785f885e8ed9a06878
|
|
||||||
# via -r .github\scripts\requirements_pre_commit.in
|
|
||||||
pyyaml==6.0.2 \
|
|
||||||
--hash=sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff \
|
|
||||||
--hash=sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48 \
|
|
||||||
--hash=sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086 \
|
|
||||||
--hash=sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e \
|
|
||||||
--hash=sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133 \
|
|
||||||
--hash=sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5 \
|
|
||||||
--hash=sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484 \
|
|
||||||
--hash=sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee \
|
|
||||||
--hash=sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5 \
|
|
||||||
--hash=sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68 \
|
|
||||||
--hash=sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a \
|
|
||||||
--hash=sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf \
|
|
||||||
--hash=sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99 \
|
|
||||||
--hash=sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8 \
|
|
||||||
--hash=sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85 \
|
|
||||||
--hash=sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19 \
|
|
||||||
--hash=sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc \
|
|
||||||
--hash=sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a \
|
|
||||||
--hash=sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1 \
|
|
||||||
--hash=sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317 \
|
|
||||||
--hash=sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c \
|
|
||||||
--hash=sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631 \
|
|
||||||
--hash=sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d \
|
|
||||||
--hash=sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652 \
|
|
||||||
--hash=sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5 \
|
|
||||||
--hash=sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e \
|
|
||||||
--hash=sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b \
|
|
||||||
--hash=sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8 \
|
|
||||||
--hash=sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476 \
|
|
||||||
--hash=sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706 \
|
|
||||||
--hash=sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563 \
|
|
||||||
--hash=sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237 \
|
|
||||||
--hash=sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b \
|
|
||||||
--hash=sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083 \
|
|
||||||
--hash=sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180 \
|
|
||||||
--hash=sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425 \
|
|
||||||
--hash=sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e \
|
|
||||||
--hash=sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f \
|
|
||||||
--hash=sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725 \
|
|
||||||
--hash=sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183 \
|
|
||||||
--hash=sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab \
|
|
||||||
--hash=sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774 \
|
|
||||||
--hash=sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725 \
|
|
||||||
--hash=sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e \
|
|
||||||
--hash=sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5 \
|
|
||||||
--hash=sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d \
|
|
||||||
--hash=sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290 \
|
|
||||||
--hash=sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44 \
|
|
||||||
--hash=sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed \
|
|
||||||
--hash=sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4 \
|
|
||||||
--hash=sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba \
|
|
||||||
--hash=sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12 \
|
|
||||||
--hash=sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4
|
|
||||||
# via pre-commit
|
|
||||||
virtualenv==20.28.1 \
|
|
||||||
--hash=sha256:412773c85d4dab0409b83ec36f7a6499e72eaf08c80e81e9576bca61831c71cb \
|
|
||||||
--hash=sha256:5d34ab240fdb5d21549b76f9e8ff3af28252f5499fb6d6f031adac4e5a8c5329
|
|
||||||
# via pre-commit
|
|
||||||
1
.github/scripts/requirements_sync_readme.in
vendored
1
.github/scripts/requirements_sync_readme.in
vendored
@@ -1 +0,0 @@
|
|||||||
tomlkit
|
|
||||||
10
.github/scripts/requirements_sync_readme.txt
vendored
10
.github/scripts/requirements_sync_readme.txt
vendored
@@ -1,10 +0,0 @@
|
|||||||
#
|
|
||||||
# This file is autogenerated by pip-compile with Python 3.10
|
|
||||||
# by the following command:
|
|
||||||
#
|
|
||||||
# pip-compile --generate-hashes --output-file='.github\scripts\requirements_sync_readme.txt' '.github\scripts\requirements_sync_readme.in'
|
|
||||||
#
|
|
||||||
tomlkit==0.13.2 \
|
|
||||||
--hash=sha256:7a974427f6e119197f670fbbbeae7bef749a6c14e793db934baefc1b5f03efde \
|
|
||||||
--hash=sha256:fff5fe59a87295b278abd31bec92c15d9bc4a06885ab12bcea52c71119392e79
|
|
||||||
# via -r .github\scripts\requirements_sync_readme.in
|
|
||||||
19
.github/workflows/PR-Demo-Comment.yml
vendored
19
.github/workflows/PR-Demo-Comment.yml
vendored
@@ -26,9 +26,7 @@ jobs:
|
|||||||
github.event.comment.user.login == 'Ludy87' ||
|
github.event.comment.user.login == 'Ludy87' ||
|
||||||
github.event.comment.user.login == 'LaserKaspar' ||
|
github.event.comment.user.login == 'LaserKaspar' ||
|
||||||
github.event.comment.user.login == 'sbplat' ||
|
github.event.comment.user.login == 'sbplat' ||
|
||||||
github.event.comment.user.login == 'reecebrowne' ||
|
github.event.comment.user.login == 'reecebrowne'
|
||||||
github.event.comment.user.login == 'DarioGii' ||
|
|
||||||
github.event.comment.user.login == 'ConnorYoh'
|
|
||||||
)
|
)
|
||||||
outputs:
|
outputs:
|
||||||
pr_number: ${{ steps.get-pr.outputs.pr_number }}
|
pr_number: ${{ steps.get-pr.outputs.pr_number }}
|
||||||
@@ -37,7 +35,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Harden Runner
|
- name: Harden Runner
|
||||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
|
||||||
with:
|
with:
|
||||||
egress-policy: audit
|
egress-policy: audit
|
||||||
|
|
||||||
@@ -82,7 +80,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Harden Runner
|
- name: Harden Runner
|
||||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
|
||||||
with:
|
with:
|
||||||
egress-policy: audit
|
egress-policy: audit
|
||||||
|
|
||||||
@@ -94,19 +92,18 @@ jobs:
|
|||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Set up JDK
|
- name: Set up JDK
|
||||||
uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0
|
uses: actions/setup-java@7a6d8a8234af8eb26422e24e3006232cccaa061b # v4.6.0
|
||||||
with:
|
with:
|
||||||
java-version: "17"
|
java-version: '17'
|
||||||
distribution: "temurin"
|
distribution: 'temurin'
|
||||||
|
|
||||||
- name: Run Gradle Command
|
- name: Run Gradle Command
|
||||||
run: ./gradlew clean build
|
run: ./gradlew clean build
|
||||||
env:
|
env:
|
||||||
DOCKER_ENABLE_SECURITY: false
|
DOCKER_ENABLE_SECURITY: false
|
||||||
STIRLING_PDF_DESKTOP_UI: false
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@f7ce87c1d6bead3e36075b2ce75da1f6cc28aaca # v3.9.0
|
uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3.8.0
|
||||||
|
|
||||||
- name: Get version number
|
- name: Get version number
|
||||||
id: versionNumber
|
id: versionNumber
|
||||||
@@ -121,7 +118,7 @@ jobs:
|
|||||||
password: ${{ secrets.DOCKER_HUB_API }}
|
password: ${{ secrets.DOCKER_HUB_API }}
|
||||||
|
|
||||||
- name: Build and push PR-specific image
|
- name: Build and push PR-specific image
|
||||||
uses: docker/build-push-action@0adf9959216b96bec444f325f1e493d4aa344497 # v6.14.0
|
uses: docker/build-push-action@48aba3b46d1b1fec4febb7c5d0c644b249a11355 # v6.10.0
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: ./Dockerfile
|
file: ./Dockerfile
|
||||||
|
|||||||
34
.github/workflows/PR-Demo-cleanup.yml
vendored
34
.github/workflows/PR-Demo-cleanup.yml
vendored
@@ -8,8 +8,8 @@ permissions:
|
|||||||
contents: read
|
contents: read
|
||||||
|
|
||||||
env:
|
env:
|
||||||
SERVER_IP: ${{ secrets.VPS_IP }} # Add this to your GitHub secrets
|
SERVER_IP: ${{ secrets.VPS_IP }} # Add this to your GitHub secrets
|
||||||
CLEANUP_PERFORMED: "false" # Add flag to track if cleanup occurred
|
CLEANUP_PERFORMED: 'false' # Add flag to track if cleanup occurred
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
cleanup:
|
cleanup:
|
||||||
@@ -21,7 +21,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Harden Runner
|
- name: Harden Runner
|
||||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
|
||||||
with:
|
with:
|
||||||
egress-policy: audit
|
egress-policy: audit
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ jobs:
|
|||||||
- name: Cleanup PR deployment
|
- name: Cleanup PR deployment
|
||||||
id: cleanup
|
id: cleanup
|
||||||
run: |
|
run: |
|
||||||
ssh -i ../private.key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -T ${{ secrets.VPS_USERNAME }}@${{ secrets.VPS_HOST }} << 'ENDSSH'
|
CLEANUP_STATUS=$(ssh -i ../private.key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -T ${{ secrets.VPS_USERNAME }}@${{ secrets.VPS_HOST }} << 'ENDSSH'
|
||||||
if [ -d "/stirling/PR-${{ github.event.pull_request.number }}" ]; then
|
if [ -d "/stirling/PR-${{ github.event.pull_request.number }}" ]; then
|
||||||
echo "Found PR directory, proceeding with cleanup..."
|
echo "Found PR directory, proceeding with cleanup..."
|
||||||
|
|
||||||
@@ -57,3 +57,29 @@ jobs:
|
|||||||
echo "NO_CLEANUP_NEEDED"
|
echo "NO_CLEANUP_NEEDED"
|
||||||
fi
|
fi
|
||||||
ENDSSH
|
ENDSSH
|
||||||
|
)
|
||||||
|
|
||||||
|
if [[ $CLEANUP_STATUS == *"PERFORMED_CLEANUP"* ]]; then
|
||||||
|
echo "cleanup_performed=true" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "cleanup_performed=false" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Post cleanup notice to PR
|
||||||
|
if: steps.cleanup.outputs.cleanup_performed == 'true'
|
||||||
|
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const { GITHUB_REPOSITORY } = process.env;
|
||||||
|
const [repoOwner, repoName] = GITHUB_REPOSITORY.split('/');
|
||||||
|
const prNumber = context.issue.number;
|
||||||
|
|
||||||
|
const commentBody = `## 🧹 Deployment Cleanup\n\n` +
|
||||||
|
`The test deployment for this PR has been cleaned up.`;
|
||||||
|
|
||||||
|
await github.rest.issues.createComment({
|
||||||
|
owner: repoOwner,
|
||||||
|
repo: repoName,
|
||||||
|
issue_number: prNumber,
|
||||||
|
body: commentBody
|
||||||
|
});
|
||||||
|
|||||||
2
.github/workflows/auto-labeler.yml
vendored
2
.github/workflows/auto-labeler.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
|||||||
pull-requests: write
|
pull-requests: write
|
||||||
steps:
|
steps:
|
||||||
- name: Harden Runner
|
- name: Harden Runner
|
||||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
|
||||||
with:
|
with:
|
||||||
egress-policy: audit
|
egress-policy: audit
|
||||||
|
|
||||||
|
|||||||
55
.github/workflows/build.yml
vendored
55
.github/workflows/build.yml
vendored
@@ -24,7 +24,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Harden Runner
|
- name: Harden Runner
|
||||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
|
||||||
with:
|
with:
|
||||||
egress-policy: audit
|
egress-policy: audit
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ jobs:
|
|||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
- name: Set up JDK ${{ matrix.jdk-version }}
|
- name: Set up JDK ${{ matrix.jdk-version }}
|
||||||
uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0
|
uses: actions/setup-java@7a6d8a8234af8eb26422e24e3006232cccaa061b # v4.6.0
|
||||||
with:
|
with:
|
||||||
java-version: ${{ matrix.jdk-version }}
|
java-version: ${{ matrix.jdk-version }}
|
||||||
distribution: "temurin"
|
distribution: "temurin"
|
||||||
@@ -49,7 +49,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Upload Test Reports
|
- name: Upload Test Reports
|
||||||
if: always()
|
if: always()
|
||||||
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: test-reports-jdk-${{ matrix.jdk-version }}
|
name: test-reports-jdk-${{ matrix.jdk-version }}
|
||||||
path: |
|
path: |
|
||||||
@@ -57,36 +57,7 @@ jobs:
|
|||||||
build/test-results/
|
build/test-results/
|
||||||
build/reports/problems/
|
build/reports/problems/
|
||||||
retention-days: 3
|
retention-days: 3
|
||||||
|
|
||||||
check-licence:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Harden Runner
|
|
||||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
|
||||||
with:
|
|
||||||
egress-policy: audit
|
|
||||||
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
||||||
|
|
||||||
- name: Set up JDK 17
|
|
||||||
uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0
|
|
||||||
with:
|
|
||||||
java-version: "17"
|
|
||||||
distribution: "adopt"
|
|
||||||
|
|
||||||
- name: check the licenses for compatibility
|
|
||||||
run: ./gradlew clean checkLicense
|
|
||||||
|
|
||||||
- name: FAILED - check the licenses for compatibility
|
|
||||||
if: failure()
|
|
||||||
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1
|
|
||||||
with:
|
|
||||||
name: dependencies-without-allowed-license.json
|
|
||||||
path: |
|
|
||||||
build/reports/dependency-license/dependencies-without-allowed-license.json
|
|
||||||
retention-days: 3
|
|
||||||
|
|
||||||
docker-compose-tests:
|
docker-compose-tests:
|
||||||
# if: github.event_name == 'push' && github.ref == 'refs/heads/main' ||
|
# if: github.event_name == 'push' && github.ref == 'refs/heads/main' ||
|
||||||
# (github.event_name == 'pull_request' &&
|
# (github.event_name == 'pull_request' &&
|
||||||
@@ -106,7 +77,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Harden Runner
|
- name: Harden Runner
|
||||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
|
||||||
with:
|
with:
|
||||||
egress-policy: audit
|
egress-policy: audit
|
||||||
|
|
||||||
@@ -114,31 +85,29 @@ jobs:
|
|||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
- name: Set up Java 17
|
- name: Set up Java 17
|
||||||
uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0
|
uses: actions/setup-java@7a6d8a8234af8eb26422e24e3006232cccaa061b # v4.6.0
|
||||||
with:
|
with:
|
||||||
java-version: "17"
|
java-version: "17"
|
||||||
distribution: "adopt"
|
distribution: "adopt"
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@f7ce87c1d6bead3e36075b2ce75da1f6cc28aaca # v3.9.0
|
uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3.8.0
|
||||||
|
|
||||||
- name: Install Docker Compose
|
- name: Install Docker Compose
|
||||||
run: |
|
run: |
|
||||||
sudo curl -SL "https://github.com/docker/compose/releases/download/v2.32.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
|
sudo curl -SL "https://github.com/docker/compose/releases/download/v2.32.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
|
||||||
sudo chmod +x /usr/local/bin/docker-compose
|
sudo chmod +x /usr/local/bin/docker-compose
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
|
uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
|
||||||
with:
|
with:
|
||||||
python-version: "3.12"
|
python-version: "3.12"
|
||||||
cache: 'pip' # caching pip dependencies
|
|
||||||
|
|
||||||
- name: Pip requirements
|
- name: Pip requirements
|
||||||
run: |
|
run: |
|
||||||
pip install --require-hashes -r ./testing/cucumber/requirements.txt
|
pip install -r ./cucumber/requirements.txt
|
||||||
|
|
||||||
- name: Run Docker Compose Tests
|
- name: Run Docker Compose Tests
|
||||||
run: |
|
run: |
|
||||||
chmod +x ./testing/test_webpages.sh
|
chmod +x ./test.sh
|
||||||
chmod +x ./testing/test.sh
|
./test.sh
|
||||||
./testing/test.sh
|
|
||||||
|
|||||||
10
.github/workflows/check_properties.yml
vendored
10
.github/workflows/check_properties.yml
vendored
@@ -18,7 +18,7 @@ jobs:
|
|||||||
pull-requests: write
|
pull-requests: write
|
||||||
steps:
|
steps:
|
||||||
- name: Harden Runner
|
- name: Harden Runner
|
||||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
|
||||||
with:
|
with:
|
||||||
egress-policy: audit
|
egress-policy: audit
|
||||||
|
|
||||||
@@ -26,9 +26,9 @@ jobs:
|
|||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
|
uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
|
||||||
with:
|
with:
|
||||||
python-version: "3.12"
|
python-version: "3.x"
|
||||||
|
|
||||||
- name: Get PR data
|
- name: Get PR data
|
||||||
id: get-pr-data
|
id: get-pr-data
|
||||||
@@ -58,7 +58,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
echo "Fetching PR changed files..."
|
echo "Fetching PR changed files..."
|
||||||
echo "Getting list of changed files from PR..."
|
echo "Getting list of changed files from PR..."
|
||||||
gh pr view ${{ steps.get-pr-data.outputs.pr_number }} --json files -q ".files[].path" | grep -E '^src/main/resources/messages_[a-zA-Z_]{2}_[a-zA-Z_]{2,7}\.properties$' > changed_files.txt # Filter only matching property files
|
gh pr view ${{ steps.get-pr-data.outputs.pr_number }} --json files -q ".files[].path" | grep -E '^src/main/resources/messages_[a-zA-Z_]+\.properties$' > changed_files.txt # Filter only matching property files
|
||||||
|
|
||||||
- name: Determine reference file test
|
- name: Determine reference file test
|
||||||
id: determine-file
|
id: determine-file
|
||||||
@@ -99,7 +99,7 @@ jobs:
|
|||||||
// Filter for relevant files based on the PR changes
|
// Filter for relevant files based on the PR changes
|
||||||
const changedFiles = files
|
const changedFiles = files
|
||||||
.map(file => file.filename)
|
.map(file => file.filename)
|
||||||
.filter(file => /^src\/main\/resources\/messages_[a-zA-Z_]{2}_[a-zA-Z_]{2,7}\.properties$/.test(file));
|
.filter(file => /^src\/main\/resources\/messages_[a-zA-Z_]+\.properties$/.test(file));
|
||||||
|
|
||||||
console.log("Changed files:", changedFiles);
|
console.log("Changed files:", changedFiles);
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/codeql.yml-disabled
vendored
2
.github/workflows/codeql.yml-disabled
vendored
@@ -42,7 +42,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Harden Runner
|
- name: Harden Runner
|
||||||
uses: step-security/harden-runner@c95a14d0e5bab51a9f56296a4eb0e416910cd350 # v2.10.3
|
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
|
||||||
with:
|
with:
|
||||||
egress-policy: audit
|
egress-policy: audit
|
||||||
|
|
||||||
|
|||||||
8
.github/workflows/dependency-review.yml
vendored
8
.github/workflows/dependency-review.yml
vendored
@@ -6,7 +6,7 @@
|
|||||||
# PRs introducing known-vulnerable packages will be blocked from merging.
|
# PRs introducing known-vulnerable packages will be blocked from merging.
|
||||||
#
|
#
|
||||||
# Source repository: https://github.com/actions/dependency-review-action
|
# Source repository: https://github.com/actions/dependency-review-action
|
||||||
name: "Dependency Review"
|
name: 'Dependency Review'
|
||||||
on: [pull_request]
|
on: [pull_request]
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
@@ -17,11 +17,11 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Harden Runner
|
- name: Harden Runner
|
||||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
|
||||||
with:
|
with:
|
||||||
egress-policy: audit
|
egress-policy: audit
|
||||||
|
|
||||||
- name: "Checkout Repository"
|
- name: 'Checkout Repository'
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
- name: "Dependency Review"
|
- name: 'Dependency Review'
|
||||||
uses: actions/dependency-review-action@3b139cfc5fae8b618d3eae3675e383bb1769c019 # v4.5.0
|
uses: actions/dependency-review-action@3b139cfc5fae8b618d3eae3675e383bb1769c019 # v4.5.0
|
||||||
|
|||||||
56
.github/workflows/licenses-update.yml
vendored
56
.github/workflows/licenses-update.yml
vendored
@@ -18,39 +18,23 @@ jobs:
|
|||||||
pull-requests: write
|
pull-requests: write
|
||||||
steps:
|
steps:
|
||||||
- name: Harden Runner
|
- name: Harden Runner
|
||||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
|
||||||
with:
|
with:
|
||||||
egress-policy: audit
|
egress-policy: audit
|
||||||
|
|
||||||
- name: Generate GitHub App Token
|
|
||||||
id: generate-token
|
|
||||||
uses: actions/create-github-app-token@0d564482f06ca65fa9e77e2510873638c82206f2 # v1.11.5
|
|
||||||
with:
|
|
||||||
app-id: ${{ secrets.GH_APP_ID }}
|
|
||||||
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
|
|
||||||
|
|
||||||
- name: Check out code
|
- name: Check out code
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
- name: Set up JDK 17
|
- name: Set up JDK 17
|
||||||
uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0
|
uses: actions/setup-java@7a6d8a8234af8eb26422e24e3006232cccaa061b # v4.6.0
|
||||||
with:
|
with:
|
||||||
java-version: "17"
|
java-version: "17"
|
||||||
distribution: "adopt"
|
distribution: "adopt"
|
||||||
|
|
||||||
- uses: gradle/actions/setup-gradle@94baf225fe0a508e581a564467443d0e2379123b # v4.3.0
|
- uses: gradle/actions/setup-gradle@0bdd871935719febd78681f197cd39af5b6e16a6 # v4.2.2
|
||||||
|
|
||||||
- name: check the licenses for compatibility
|
- name: Run Gradle Command
|
||||||
run: ./gradlew clean checkLicense
|
run: ./gradlew clean generateLicenseReport
|
||||||
|
|
||||||
- name: FAILED - check the licenses for compatibility
|
|
||||||
if: failure()
|
|
||||||
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1
|
|
||||||
with:
|
|
||||||
name: dependencies-without-allowed-license.json
|
|
||||||
path: |
|
|
||||||
build/reports/dependency-license/dependencies-without-allowed-license.json
|
|
||||||
retention-days: 3
|
|
||||||
|
|
||||||
- name: Move and Rename License File
|
- name: Move and Rename License File
|
||||||
run: |
|
run: |
|
||||||
@@ -58,8 +42,8 @@ jobs:
|
|||||||
|
|
||||||
- name: Set up git config
|
- name: Set up git config
|
||||||
run: |
|
run: |
|
||||||
git config --global user.name "stirlingbot[bot]"
|
git config --global user.name "github-actions[bot]"
|
||||||
git config --global user.email "1113334+stirlingbot[bot]@users.noreply.github.com"
|
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
||||||
|
|
||||||
- name: Run git add
|
- name: Run git add
|
||||||
run: |
|
run: |
|
||||||
@@ -69,24 +53,34 @@ jobs:
|
|||||||
- name: Create Pull Request
|
- name: Create Pull Request
|
||||||
id: cpr
|
id: cpr
|
||||||
if: env.CHANGES_DETECTED == 'true'
|
if: env.CHANGES_DETECTED == 'true'
|
||||||
uses: peter-evans/create-pull-request@dd2324fc52d5d43c699a5636bcf19fceaa70c284 # v7.0.7
|
uses: peter-evans/create-pull-request@67ccf781d68cd99b580ae25a5c18a1cc84ffff1f # v7.0.6
|
||||||
with:
|
with:
|
||||||
token: ${{ steps.generate-token.outputs.token }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
commit-message: "Update 3rd Party Licenses"
|
commit-message: "Update 3rd Party Licenses"
|
||||||
committer: "stirlingbot[bot] <1113334+stirlingbot[bot]@users.noreply.github.com>"
|
committer: GitHub Action <action@github.com>
|
||||||
author: "stirlingbot[bot] <1113334+stirlingbot[bot]@users.noreply.github.com>"
|
author: GitHub Action <action@github.com>
|
||||||
signoff: true
|
signoff: true
|
||||||
branch: update-3rd-party-licenses
|
branch: update-3rd-party-licenses
|
||||||
title: "Update 3rd Party Licenses"
|
title: "Update 3rd Party Licenses"
|
||||||
body: |
|
body: |
|
||||||
Auto-generated by StirlingBot
|
Auto-generated by [create-pull-request][1]
|
||||||
|
|
||||||
|
[1]: https://github.com/peter-evans/create-pull-request
|
||||||
labels: licenses,github-actions
|
labels: licenses,github-actions
|
||||||
draft: false
|
draft: false
|
||||||
delete-branch: true
|
delete-branch: true
|
||||||
sign-commits: true
|
sign-commits: true
|
||||||
|
|
||||||
- name: Enable Pull Request Automerge
|
- name: Auto approve
|
||||||
if: steps.cpr.outputs.pull-request-operation == 'created'
|
if: steps.cpr.outputs.pull-request-operation == 'created'
|
||||||
run: gh pr merge --squash --auto "${{ steps.cpr.outputs.pull-request-number }}"
|
run: gh pr review --approve "${{ steps.cpr.outputs.pull-request-number }}"
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Enable auto-merge
|
||||||
|
if: steps.cpr.outputs.pull-request-operation == 'created'
|
||||||
|
uses: peter-evans/enable-pull-request-automerge@a660677d5469627102a1c1e11409dd063606628d # v3.0.0
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
pull-request-number: ${{ steps.cpr.outputs.pull-request-number }}
|
||||||
|
merge-method: squash # Choose the merge method: merge, squash, or rebase
|
||||||
|
|||||||
4
.github/workflows/manage-label.yml
vendored
4
.github/workflows/manage-label.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
|||||||
issues: write
|
issues: write
|
||||||
steps:
|
steps:
|
||||||
- name: Harden Runner
|
- name: Harden Runner
|
||||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
|
||||||
with:
|
with:
|
||||||
egress-policy: audit
|
egress-policy: audit
|
||||||
|
|
||||||
@@ -23,7 +23,7 @@ jobs:
|
|||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
- name: Run Labeler
|
- name: Run Labeler
|
||||||
uses: crazy-max/ghaction-github-labeler@31674a3852a9074f2086abcf1c53839d466a47e7 # v5.2.0
|
uses: crazy-max/ghaction-github-labeler@b54af0c25861143e7c8813d7cbbf46d2c341680c # v5.1.0
|
||||||
with:
|
with:
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
yaml-file: .github/labels.yml
|
yaml-file: .github/labels.yml
|
||||||
|
|||||||
265
.github/workflows/multiOSReleases.yml
vendored
265
.github/workflows/multiOSReleases.yml
vendored
@@ -9,149 +9,39 @@ permissions:
|
|||||||
contents: read
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
read_versions:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
outputs:
|
|
||||||
version: ${{ steps.versionNumber.outputs.versionNumber }}
|
|
||||||
versionMac: ${{ steps.versionNumberMac.outputs.versionNumberMac }}
|
|
||||||
steps:
|
|
||||||
- name: Harden Runner
|
|
||||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
|
||||||
with:
|
|
||||||
egress-policy: audit
|
|
||||||
|
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
||||||
|
|
||||||
# Get version number
|
|
||||||
- name: Get version number
|
|
||||||
id: versionNumber
|
|
||||||
run: |
|
|
||||||
VERSION=$(grep "^version =" build.gradle | awk -F'"' '{print $2}')
|
|
||||||
echo "versionNumber=$VERSION" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Get version number mac
|
|
||||||
id: versionNumberMac
|
|
||||||
run: |
|
|
||||||
VERSION=$(grep "^version =" build.gradle | awk -F'"' '{print $2}')
|
|
||||||
CURRENT_YEAR=$(date +'%Y')
|
|
||||||
IFS='.' read -r -a VERSION_PARTS <<< "$VERSION"
|
|
||||||
MAC_VERSION="$CURRENT_YEAR.${VERSION_PARTS[1]:-0}.${VERSION_PARTS[2]:-0}"
|
|
||||||
echo "versionNumberMac=$MAC_VERSION" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
build-portable:
|
|
||||||
needs: read_versions
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
enable_security: [true, false]
|
|
||||||
include:
|
|
||||||
- enable_security: true
|
|
||||||
file_suffix: "-with-login"
|
|
||||||
- enable_security: false
|
|
||||||
file_suffix: ""
|
|
||||||
steps:
|
|
||||||
- name: Harden Runner
|
|
||||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
|
||||||
with:
|
|
||||||
egress-policy: audit
|
|
||||||
|
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
||||||
|
|
||||||
- name: Set up JDK 21
|
|
||||||
uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0
|
|
||||||
with:
|
|
||||||
java-version: "21"
|
|
||||||
distribution: "temurin"
|
|
||||||
|
|
||||||
- uses: gradle/actions/setup-gradle@94baf225fe0a508e581a564467443d0e2379123b # v4.3.0
|
|
||||||
with:
|
|
||||||
gradle-version: 8.12
|
|
||||||
|
|
||||||
- name: Generate jar (With Security=${{ matrix.enable_security }})
|
|
||||||
run: ./gradlew clean createExe
|
|
||||||
env:
|
|
||||||
DOCKER_ENABLE_SECURITY: ${{ matrix.enable_security }}
|
|
||||||
STIRLING_PDF_DESKTOP_UI: false
|
|
||||||
|
|
||||||
- name: Rename binaries
|
|
||||||
run: |
|
|
||||||
mkdir ./binaries
|
|
||||||
mv ./build/launch4j/Stirling-PDF.exe ./binaries/win-Stirling-PDF-portable-Server${{ matrix.file_suffix }}.exe
|
|
||||||
mv ./build/libs/Stirling-PDF-${{ needs.read_versions.outputs.version }}.jar ./binaries/Stirling-PDF${{ matrix.file_suffix }}.jar
|
|
||||||
|
|
||||||
- name: Upload build artifacts
|
|
||||||
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1
|
|
||||||
with:
|
|
||||||
retention-days: 1
|
|
||||||
if-no-files-found: error
|
|
||||||
name: stirling${{ matrix.file_suffix }}-binaries
|
|
||||||
path: |
|
|
||||||
./binaries/*
|
|
||||||
|
|
||||||
sign_verify-portable:
|
|
||||||
needs: [build-portable, read_versions]
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
enable_security: [true, false]
|
|
||||||
include:
|
|
||||||
- enable_security: true
|
|
||||||
file_suffix: "with-login-"
|
|
||||||
- enable_security: false
|
|
||||||
file_suffix: ""
|
|
||||||
steps:
|
|
||||||
- name: Harden Runner
|
|
||||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
|
||||||
with:
|
|
||||||
egress-policy: audit
|
|
||||||
|
|
||||||
- name: Download build artifacts
|
|
||||||
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
|
|
||||||
with:
|
|
||||||
name: stirling-${{ matrix.file_suffix }}binaries
|
|
||||||
|
|
||||||
- name: Display structure of downloaded files
|
|
||||||
run: ls -R
|
|
||||||
|
|
||||||
- name: Upload signed artifacts
|
|
||||||
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1
|
|
||||||
with:
|
|
||||||
retention-days: 1
|
|
||||||
if-no-files-found: error
|
|
||||||
name: stirling-${{ matrix.file_suffix }}signed
|
|
||||||
path: |
|
|
||||||
./*
|
|
||||||
!cosign.*
|
|
||||||
|
|
||||||
build-installers:
|
build-installers:
|
||||||
needs: read_versions
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- os: windows-latest
|
- os: windows-latest
|
||||||
platform: win-
|
platform: win
|
||||||
- os: macos-latest
|
ext: exe
|
||||||
platform: mac-
|
#- os: macos-latest
|
||||||
# - os: ubuntu-latest
|
# platform: mac
|
||||||
# platform: linux-
|
# ext: dmg
|
||||||
|
#- os: ubuntu-latest
|
||||||
|
# platform: linux
|
||||||
|
# ext: deb
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
|
packages: write
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Harden Runner
|
- name: Harden Runner
|
||||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
|
||||||
with:
|
with:
|
||||||
egress-policy: audit
|
egress-policy: audit
|
||||||
|
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
- name: Set up JDK 21
|
- name: Set up JDK 21
|
||||||
uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0
|
uses: actions/setup-java@7a6d8a8234af8eb26422e24e3006232cccaa061b # v4.6.0
|
||||||
with:
|
with:
|
||||||
java-version: "21"
|
java-version: "21"
|
||||||
distribution: "temurin"
|
distribution: "temurin"
|
||||||
|
|
||||||
- uses: gradle/actions/setup-gradle@94baf225fe0a508e581a564467443d0e2379123b # v4.3.0
|
- uses: gradle/actions/setup-gradle@0bdd871935719febd78681f197cd39af5b6e16a6 # v4.2.2
|
||||||
with:
|
with:
|
||||||
gradle-version: 8.12
|
gradle-version: 8.12
|
||||||
|
|
||||||
@@ -162,127 +52,54 @@ jobs:
|
|||||||
curl -L -o wix.exe https://github.com/wixtoolset/wix3/releases/download/wix3141rtm/wix314.exe
|
curl -L -o wix.exe https://github.com/wixtoolset/wix3/releases/download/wix3141rtm/wix314.exe
|
||||||
.\wix.exe /install /quiet
|
.\wix.exe /install /quiet
|
||||||
|
|
||||||
|
# Install Linux dependencies
|
||||||
|
- name: Install Linux Dependencies
|
||||||
|
if: matrix.os == 'ubuntu-latest'
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y fakeroot rpm
|
||||||
|
|
||||||
|
# Get version number
|
||||||
|
- name: Get version number
|
||||||
|
id: versionNumber
|
||||||
|
run: echo "versionNumber=$(./gradlew printVersion --quiet | tail -1)" >> $GITHUB_OUTPUT
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Get version number mac
|
||||||
|
id: versionNumberMac
|
||||||
|
run: echo "versionNumberMac=$(./gradlew printMacVersion --quiet | tail -1)" >> $GITHUB_OUTPUT
|
||||||
|
shell: bash
|
||||||
|
|
||||||
# Build installer
|
# Build installer
|
||||||
- name: Build Installer
|
- name: Build Installer
|
||||||
run: ./gradlew build jpackage -x test --info
|
run: ./gradlew build jpackage -x test --info
|
||||||
env:
|
env:
|
||||||
DOCKER_ENABLE_SECURITY: false
|
DOCKER_ENABLE_SECURITY: false
|
||||||
STIRLING_PDF_DESKTOP_UI: true
|
STIRLING_PDF_DESKTOP_UI: true
|
||||||
BROWSER_OPEN: true
|
|
||||||
|
|
||||||
# Rename and collect artifacts based on OS
|
# Rename and collect artifacts based on OS
|
||||||
- name: Prepare artifacts
|
- name: Prepare artifacts
|
||||||
id: prepare
|
id: prepare
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
mkdir ./binaries
|
|
||||||
if [ "${{ matrix.os }}" = "windows-latest" ]; then
|
if [ "${{ matrix.os }}" = "windows-latest" ]; then
|
||||||
mv "./build/jpackage/Stirling-PDF-${{ needs.read_versions.outputs.version }}.exe" "./binaries/Stirling-PDF-win-installer.exe"
|
mv "build/jpackage/Stirling-PDF-${{ steps.versionNumber.outputs.versionNumber }}.exe" "Stirling-PDF-${{ matrix.platform }}-installer.${{ matrix.ext }}"
|
||||||
elif [ "${{ matrix.os }}" = "macos-latest" ]; then
|
elif [ "${{ matrix.os }}" = "macos-latest" ]; then
|
||||||
mv "./build/jpackage/Stirling-PDF-${{ needs.read_versions.outputs.versionMac }}.dmg" "./binaries/Stirling-PDF-mac-installer.dmg"
|
mv "build/jpackage/Stirling-PDF-${{ steps.versionNumberMac.outputs.versionNumberMac }}.dmg" "Stirling-PDF-${{ steps.versionNumber.outputs.versionNumber }}-${{ matrix.platform }}.${{ matrix.ext }}"
|
||||||
else
|
else
|
||||||
mv "./build/jpackage/stirling-pdf_${{ needs.read_versions.outputs.version }}-1_amd64.deb" "./binaries/Stirling-PDF-linux-installer.deb"
|
mv "build/jpackage/stirling-pdf_${{ steps.versionNumber.outputs.versionNumber }}-1_amd64.deb" "Stirling-PDF-${{ steps.versionNumber.outputs.versionNumber }}-${{ matrix.platform }}.${{ matrix.ext }}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Display structure of downloaded files
|
# Upload installer as artifact for testing
|
||||||
run: ls -R ./binaries
|
- name: Upload Installer Artifact
|
||||||
|
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
|
||||||
- name: Upload build artifacts
|
|
||||||
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1
|
|
||||||
with:
|
with:
|
||||||
|
name: Stirling-PDF-${{ matrix.platform }}-installer.${{ matrix.ext }}
|
||||||
|
path: Stirling-PDF-${{ matrix.platform }}-installer.${{ matrix.ext }}
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
name: ${{ matrix.platform }}binaries
|
|
||||||
path: |
|
|
||||||
./binaries/*
|
|
||||||
|
|
||||||
sign_verify:
|
- name: Upload binaries to release
|
||||||
needs: [read_versions, build-installers]
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- os: windows-latest
|
|
||||||
platform: win-
|
|
||||||
- os: macos-latest
|
|
||||||
platform: mac-
|
|
||||||
# - os: ubuntu-latest
|
|
||||||
# platform: linux-
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Harden Runner
|
|
||||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
|
||||||
with:
|
|
||||||
egress-policy: audit
|
|
||||||
|
|
||||||
- name: Download build artifacts
|
|
||||||
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
|
|
||||||
with:
|
|
||||||
name: ${{ matrix.platform }}binaries
|
|
||||||
|
|
||||||
- name: Display structure of downloaded files
|
|
||||||
run: ls -R
|
|
||||||
|
|
||||||
- name: Install Cosign
|
|
||||||
if: matrix.os == 'windows-latest'
|
|
||||||
uses: sigstore/cosign-installer@d7d6bc7722e3daa8354c50bcb52f4837da5e9b6a # v3.8.1
|
|
||||||
|
|
||||||
- name: Generate key pair
|
|
||||||
if: matrix.os == 'windows-latest'
|
|
||||||
run: cosign generate-key-pair
|
|
||||||
|
|
||||||
- name: Sign and generate attestations
|
|
||||||
if: matrix.os == 'windows-latest'
|
|
||||||
run: |
|
|
||||||
cosign sign-blob \
|
|
||||||
--key ./cosign.key \
|
|
||||||
--yes \
|
|
||||||
--output-signature ./Stirling-PDF-win-installer.exe.sig \
|
|
||||||
./Stirling-PDF-win-installer.exe
|
|
||||||
|
|
||||||
cosign attest-blob \
|
|
||||||
--predicate - \
|
|
||||||
--key ./cosign.key \
|
|
||||||
--yes \
|
|
||||||
--output-attestation ./Stirling-PDF-win-installer.exe.intoto.jsonl \
|
|
||||||
./Stirling-PDF-win-installer.exe
|
|
||||||
|
|
||||||
cosign verify-blob \
|
|
||||||
--key ./cosign.pub \
|
|
||||||
--signature ./Stirling-PDF-win-installer.exe.sig \
|
|
||||||
./Stirling-PDF-win-installer.exe
|
|
||||||
|
|
||||||
- name: Display structure of downloaded files
|
|
||||||
run: ls -R
|
|
||||||
|
|
||||||
- name: Upload signed artifacts
|
|
||||||
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1
|
|
||||||
with:
|
|
||||||
retention-days: 1
|
|
||||||
if-no-files-found: error
|
|
||||||
name: ${{ matrix.platform }}signed
|
|
||||||
path: |
|
|
||||||
./Stirling-PDF-${{ matrix.platform }}installer.*
|
|
||||||
!cosign.*
|
|
||||||
|
|
||||||
create-release:
|
|
||||||
needs: [read_versions, sign_verify, sign_verify-portable]
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
steps:
|
|
||||||
- name: Harden Runner
|
|
||||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
|
||||||
with:
|
|
||||||
egress-policy: audit
|
|
||||||
|
|
||||||
- name: Download signed artifacts
|
|
||||||
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
|
|
||||||
- name: Display structure of downloaded files
|
|
||||||
run: ls -R
|
|
||||||
- name: Upload binaries, attestations and signatures to Release and create GitHub Release
|
|
||||||
uses: softprops/action-gh-release@01570a1f39cb168c169c802c3bceb9e93fb10974 # v2.1.0
|
uses: softprops/action-gh-release@01570a1f39cb168c169c802c3bceb9e93fb10974 # v2.1.0
|
||||||
with:
|
with:
|
||||||
tag_name: v${{ needs.read_versions.outputs.version }}
|
files: ./Stirling-PDF-${{ matrix.platform }}-installer.${{ matrix.ext }}
|
||||||
generate_release_notes: true
|
|
||||||
files: |
|
|
||||||
./*signed/*
|
|
||||||
|
|||||||
59
.github/workflows/pre_commit.yml
vendored
59
.github/workflows/pre_commit.yml
vendored
@@ -1,77 +1,52 @@
|
|||||||
name: Pre-commit
|
name: Pre-commit
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
push:
|
||||||
schedule:
|
branches: [main]
|
||||||
- cron: "0 0 * * 1"
|
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
pre-commit:
|
update:
|
||||||
|
if: ${{ github.event.pull_request.user.login != 'dependabot[bot]' }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
steps:
|
steps:
|
||||||
- name: Harden Runner
|
|
||||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
|
||||||
with:
|
|
||||||
egress-policy: audit
|
|
||||||
|
|
||||||
- name: Generate GitHub App Token
|
|
||||||
id: generate-token
|
|
||||||
uses: actions/create-github-app-token@0d564482f06ca65fa9e77e2510873638c82206f2 # v1.11.5
|
|
||||||
with:
|
|
||||||
app-id: ${{ secrets.GH_APP_ID }}
|
|
||||||
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
|
|
||||||
|
|
||||||
- name: Get GitHub App User ID
|
|
||||||
id: get-user-id
|
|
||||||
run: echo "user-id=$(gh api "/users/${{ steps.generate-token.outputs.app-slug }}[bot]" --jq .id)" >> $GITHUB_OUTPUT
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
|
|
||||||
|
|
||||||
- id: committer
|
|
||||||
run: |
|
|
||||||
echo "string=${{ steps.generate-token.outputs.app-slug }}[bot] <${{ steps.get-user-id.outputs.user-id }}+${{ steps.generate-token.outputs.app-slug }}[bot]@users.noreply.github.com>" >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
|
uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
|
||||||
with:
|
with:
|
||||||
python-version: 3.12
|
python-version: 3.12
|
||||||
cache: 'pip' # caching pip dependencies
|
|
||||||
- name: Run Pre-Commit Hooks
|
- name: Run Pre-Commit Hooks
|
||||||
run: |
|
uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1
|
||||||
pip install --require-hashes -r ./.github/scripts/requirements_pre_commit.txt
|
|
||||||
- run: pre-commit run --all-files -c .pre-commit-config.yaml
|
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
- name: Set up git config
|
- name: Set up git config
|
||||||
run: |
|
run: |
|
||||||
git config --global user.name ${{ steps.generate-token.outputs.app-slug }}[bot]
|
git config --global user.name "github-actions[bot]"
|
||||||
git config --global user.email "${{ steps.get-user-id.outputs.user-id }}+${{ steps.generate-token.outputs.app-slug }}[bot]@users.noreply.github.com"
|
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
||||||
- name: git add
|
- name: git add
|
||||||
run: |
|
run: |
|
||||||
git add .
|
git add .
|
||||||
git diff --staged --quiet || echo "CHANGES_DETECTED=true" >> $GITHUB_ENV
|
git diff --staged --quiet || git commit -m ":file_folder: pre-commit
|
||||||
|
> Made via .github/workflows/pre_commit.yml" || echo "pre-commit: no changes"
|
||||||
- name: Create Pull Request
|
- name: Create Pull Request
|
||||||
if: env.CHANGES_DETECTED == 'true'
|
uses: peter-evans/create-pull-request@67ccf781d68cd99b580ae25a5c18a1cc84ffff1f # v7.0.6
|
||||||
uses: peter-evans/create-pull-request@dd2324fc52d5d43c699a5636bcf19fceaa70c284 # v7.0.7
|
|
||||||
with:
|
with:
|
||||||
token: ${{ steps.generate-token.outputs.token }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
commit-message: ":file_folder: pre-commit"
|
commit-message: "ci: 🤖 format everything with pre-commit"
|
||||||
committer: ${{ steps.committer.outputs.string }}
|
committer: GitHub Action <action@github.com>
|
||||||
author: ${{ steps.committer.outputs.string }}
|
author: GitHub Action <action@github.com>
|
||||||
signoff: true
|
signoff: true
|
||||||
branch: pre-commit
|
branch: pre-commit
|
||||||
title: "🤖 format everything with pre-commit by <${{ steps.generate-token.outputs.app-slug }}>"
|
title: "🤖 format everything with pre-commit by <github-actions[bot]>"
|
||||||
body: |
|
body: |
|
||||||
Auto-generated by [create-pull-request][1] with **${{ steps.generate-token.outputs.app-slug }}**
|
Auto-generated by [create-pull-request][1]
|
||||||
|
|
||||||
[1]: https://github.com/peter-evans/create-pull-request
|
[1]: https://github.com/peter-evans/create-pull-request
|
||||||
draft: false
|
draft: false
|
||||||
|
|||||||
21
.github/workflows/push-docker.yml
vendored
21
.github/workflows/push-docker.yml
vendored
@@ -18,19 +18,19 @@ jobs:
|
|||||||
id-token: write
|
id-token: write
|
||||||
steps:
|
steps:
|
||||||
- name: Harden Runner
|
- name: Harden Runner
|
||||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
|
||||||
with:
|
with:
|
||||||
egress-policy: audit
|
egress-policy: audit
|
||||||
|
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
- name: Set up JDK 17
|
- name: Set up JDK 17
|
||||||
uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0
|
uses: actions/setup-java@7a6d8a8234af8eb26422e24e3006232cccaa061b # v4.6.0
|
||||||
with:
|
with:
|
||||||
java-version: "17"
|
java-version: "17"
|
||||||
distribution: "temurin"
|
distribution: "temurin"
|
||||||
|
|
||||||
- uses: gradle/actions/setup-gradle@94baf225fe0a508e581a564467443d0e2379123b # v4.3.0
|
- uses: gradle/actions/setup-gradle@0bdd871935719febd78681f197cd39af5b6e16a6 # v4.2.2
|
||||||
with:
|
with:
|
||||||
gradle-version: 8.12
|
gradle-version: 8.12
|
||||||
|
|
||||||
@@ -38,17 +38,16 @@ jobs:
|
|||||||
run: ./gradlew clean build
|
run: ./gradlew clean build
|
||||||
env:
|
env:
|
||||||
DOCKER_ENABLE_SECURITY: false
|
DOCKER_ENABLE_SECURITY: false
|
||||||
STIRLING_PDF_DESKTOP_UI: false
|
|
||||||
|
|
||||||
- name: Install cosign
|
- name: Install cosign
|
||||||
if: github.ref == 'refs/heads/master'
|
if: github.ref == 'refs/heads/master'
|
||||||
uses: sigstore/cosign-installer@d7d6bc7722e3daa8354c50bcb52f4837da5e9b6a # v3.8.1
|
uses: sigstore/cosign-installer@dc72c7d5c4d10cd6bcb8cf6e3fd625a9e5e537da # v3.7.0
|
||||||
with:
|
with:
|
||||||
cosign-release: "v2.4.1"
|
cosign-release: 'v2.4.1'
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
id: buildx
|
id: buildx
|
||||||
uses: docker/setup-buildx-action@f7ce87c1d6bead3e36075b2ce75da1f6cc28aaca # v3.9.0
|
uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3.8.0
|
||||||
|
|
||||||
- name: Get version number
|
- name: Get version number
|
||||||
id: versionNumber
|
id: versionNumber
|
||||||
@@ -68,7 +67,7 @@ jobs:
|
|||||||
password: ${{ github.token }}
|
password: ${{ github.token }}
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@4574d27a4764455b42196d70a065bc6853246a25 # v3.4.0
|
uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # v3.2.0
|
||||||
|
|
||||||
- name: Convert repository owner to lowercase
|
- name: Convert repository owner to lowercase
|
||||||
id: repoowner
|
id: repoowner
|
||||||
@@ -90,7 +89,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Build and push main Dockerfile
|
- name: Build and push main Dockerfile
|
||||||
id: build-push-regular
|
id: build-push-regular
|
||||||
uses: docker/build-push-action@0adf9959216b96bec444f325f1e493d4aa344497 # v6.14.0
|
uses: docker/build-push-action@48aba3b46d1b1fec4febb7c5d0c644b249a11355 # v6.10.0
|
||||||
with:
|
with:
|
||||||
builder: ${{ steps.buildx.outputs.name }}
|
builder: ${{ steps.buildx.outputs.name }}
|
||||||
context: .
|
context: .
|
||||||
@@ -135,7 +134,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Build and push Dockerfile-ultra-lite
|
- name: Build and push Dockerfile-ultra-lite
|
||||||
id: build-push-lite
|
id: build-push-lite
|
||||||
uses: docker/build-push-action@0adf9959216b96bec444f325f1e493d4aa344497 # v6.14.0
|
uses: docker/build-push-action@48aba3b46d1b1fec4febb7c5d0c644b249a11355 # v6.10.0
|
||||||
if: github.ref != 'refs/heads/main'
|
if: github.ref != 'refs/heads/main'
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
@@ -166,7 +165,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Build and push main Dockerfile fat
|
- name: Build and push main Dockerfile fat
|
||||||
id: build-push-fat
|
id: build-push-fat
|
||||||
uses: docker/build-push-action@0adf9959216b96bec444f325f1e493d4aa344497 # v6.14.0
|
uses: docker/build-push-action@48aba3b46d1b1fec4febb7c5d0c644b249a11355 # v6.10.0
|
||||||
if: github.ref != 'refs/heads/main'
|
if: github.ref != 'refs/heads/main'
|
||||||
with:
|
with:
|
||||||
builder: ${{ steps.buildx.outputs.name }}
|
builder: ${{ steps.buildx.outputs.name }}
|
||||||
|
|||||||
167
.github/workflows/releaseArtifacts.yml
vendored
167
.github/workflows/releaseArtifacts.yml
vendored
@@ -9,8 +9,11 @@ permissions:
|
|||||||
contents: read
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
push:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
packages: write
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
enable_security: [true, false]
|
enable_security: [true, false]
|
||||||
@@ -19,23 +22,21 @@ jobs:
|
|||||||
file_suffix: "-with-login"
|
file_suffix: "-with-login"
|
||||||
- enable_security: false
|
- enable_security: false
|
||||||
file_suffix: ""
|
file_suffix: ""
|
||||||
outputs:
|
|
||||||
version: ${{ steps.versionNumber.outputs.versionNumber }}
|
|
||||||
steps:
|
steps:
|
||||||
- name: Harden Runner
|
- name: Harden Runner
|
||||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
|
||||||
with:
|
with:
|
||||||
egress-policy: audit
|
egress-policy: audit
|
||||||
|
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
- name: Set up JDK 17
|
- name: Set up JDK 17
|
||||||
uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0
|
uses: actions/setup-java@7a6d8a8234af8eb26422e24e3006232cccaa061b # v4.6.0
|
||||||
with:
|
with:
|
||||||
java-version: "17"
|
java-version: "17"
|
||||||
distribution: "temurin"
|
distribution: "temurin"
|
||||||
|
|
||||||
- uses: gradle/actions/setup-gradle@94baf225fe0a508e581a564467443d0e2379123b # v4.3.0
|
- uses: gradle/actions/setup-gradle@0bdd871935719febd78681f197cd39af5b6e16a6 # v4.2.2
|
||||||
with:
|
with:
|
||||||
gradle-version: 8.12
|
gradle-version: 8.12
|
||||||
|
|
||||||
@@ -47,134 +48,38 @@ jobs:
|
|||||||
|
|
||||||
- name: Get version number
|
- name: Get version number
|
||||||
id: versionNumber
|
id: versionNumber
|
||||||
run: |
|
run: echo "versionNumber=$(./gradlew printVersion --quiet | tail -1)" >> $GITHUB_OUTPUT
|
||||||
VERSION=$(grep "^version =" build.gradle | awk -F'"' '{print $2}')
|
|
||||||
echo "versionNumber=$VERSION" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Rename binaries
|
- name: Rename binarie
|
||||||
run: |
|
run: cp ./build/launch4j/Stirling-PDF.exe ./build/launch4j/Stirling-PDF-Server${{ matrix.file_suffix }}.exe
|
||||||
mv ./build/launch4j/Stirling-PDF.exe ./build/launch4j/Stirling-PDF-Server${{ matrix.file_suffix }}.exe
|
|
||||||
mv ./build/libs/Stirling-PDF-${{ steps.versionNumber.outputs.versionNumber }}.jar ./build/libs/Stirling-PDF${{ matrix.file_suffix }}.jar
|
|
||||||
|
|
||||||
- name: Debug build artifacts
|
- name: Upload Assets binarie
|
||||||
run: |
|
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
|
||||||
echo "Current Directory: $(pwd)"
|
|
||||||
ls -R ./build/libs
|
|
||||||
ls -R ./build/launch4j
|
|
||||||
|
|
||||||
- name: Upload build artifacts
|
|
||||||
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1
|
|
||||||
with:
|
with:
|
||||||
name: binaries${{ matrix.file_suffix }}
|
path: ./build/launch4j/Stirling-PDF-Server${{ matrix.file_suffix }}.exe
|
||||||
path: |
|
name: Stirling-PDF-Server${{ matrix.file_suffix }}.exe
|
||||||
./build/launch4j/Stirling-PDF-Server${{ matrix.file_suffix }}.*
|
overwrite: true
|
||||||
./build/libs/Stirling-PDF${{ matrix.file_suffix }}.*
|
retention-days: 1
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
sign_verify:
|
- name: Upload binaries to release
|
||||||
needs: build
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
enable_security: [true, false]
|
|
||||||
include:
|
|
||||||
- enable_security: true
|
|
||||||
file_suffix: "-with-login"
|
|
||||||
- enable_security: false
|
|
||||||
file_suffix: ""
|
|
||||||
steps:
|
|
||||||
- name: Harden Runner
|
|
||||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
|
||||||
with:
|
|
||||||
egress-policy: audit
|
|
||||||
|
|
||||||
- name: Download build artifacts
|
|
||||||
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
|
|
||||||
with:
|
|
||||||
name: binaries${{ matrix.file_suffix }}
|
|
||||||
- name: Display structure of downloaded files
|
|
||||||
run: ls -R
|
|
||||||
|
|
||||||
- name: Install Cosign
|
|
||||||
uses: sigstore/cosign-installer@d7d6bc7722e3daa8354c50bcb52f4837da5e9b6a # v3.8.1
|
|
||||||
|
|
||||||
- name: Generate key pair
|
|
||||||
run: cosign generate-key-pair
|
|
||||||
|
|
||||||
- name: Sign and generate attestations
|
|
||||||
run: |
|
|
||||||
cosign sign-blob \
|
|
||||||
--key ./cosign.key \
|
|
||||||
--yes \
|
|
||||||
--output-signature ./libs/Stirling-PDF${{ matrix.file_suffix }}.jar.sig \
|
|
||||||
./libs/Stirling-PDF${{ matrix.file_suffix }}.jar
|
|
||||||
|
|
||||||
cosign attest-blob \
|
|
||||||
--predicate - \
|
|
||||||
--key ./cosign.key \
|
|
||||||
--yes \
|
|
||||||
--output-attestation ./libs/Stirling-PDF${{ matrix.file_suffix }}.jar.intoto.jsonl \
|
|
||||||
./libs/Stirling-PDF${{ matrix.file_suffix }}.jar
|
|
||||||
|
|
||||||
cosign verify-blob \
|
|
||||||
--key ./cosign.pub \
|
|
||||||
--signature ./libs/Stirling-PDF${{ matrix.file_suffix }}.jar.sig \
|
|
||||||
./libs/Stirling-PDF${{ matrix.file_suffix }}.jar
|
|
||||||
|
|
||||||
cosign sign-blob \
|
|
||||||
--key ./cosign.key \
|
|
||||||
--yes \
|
|
||||||
--output-signature ./launch4j/Stirling-PDF-Server${{ matrix.file_suffix }}.exe.sig \
|
|
||||||
./launch4j/Stirling-PDF-Server${{ matrix.file_suffix }}.exe
|
|
||||||
|
|
||||||
cosign attest-blob \
|
|
||||||
--predicate - \
|
|
||||||
--key ./cosign.key \
|
|
||||||
--yes \
|
|
||||||
--output-attestation ./launch4j/Stirling-PDF-Server${{ matrix.file_suffix }}.exe.intoto.jsonl \
|
|
||||||
./launch4j/Stirling-PDF-Server${{ matrix.file_suffix }}.exe
|
|
||||||
|
|
||||||
cosign verify-blob \
|
|
||||||
--key ./cosign.pub \
|
|
||||||
--signature ./launch4j/Stirling-PDF-Server${{ matrix.file_suffix }}.exe.sig \
|
|
||||||
./launch4j/Stirling-PDF-Server${{ matrix.file_suffix }}.exe
|
|
||||||
|
|
||||||
- name: Upload signed artifacts
|
|
||||||
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1
|
|
||||||
with:
|
|
||||||
name: signed${{ matrix.file_suffix }}
|
|
||||||
path: |
|
|
||||||
./libs/Stirling-PDF${{ matrix.file_suffix }}.*
|
|
||||||
./launch4j/Stirling-PDF-Server${{ matrix.file_suffix }}.*
|
|
||||||
|
|
||||||
release:
|
|
||||||
needs: [build, sign_verify]
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
enable_security: [true, false]
|
|
||||||
include:
|
|
||||||
- enable_security: true
|
|
||||||
file_suffix: "-with-login"
|
|
||||||
- enable_security: false
|
|
||||||
file_suffix: ""
|
|
||||||
steps:
|
|
||||||
- name: Harden Runner
|
|
||||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
|
||||||
with:
|
|
||||||
egress-policy: audit
|
|
||||||
|
|
||||||
- name: Download signed artifacts
|
|
||||||
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
|
|
||||||
with:
|
|
||||||
name: signed${{ matrix.file_suffix }}
|
|
||||||
|
|
||||||
- name: Upload binaries, attestations and signatures to Release and create GitHub Release
|
|
||||||
uses: softprops/action-gh-release@01570a1f39cb168c169c802c3bceb9e93fb10974 # v2.1.0
|
uses: softprops/action-gh-release@01570a1f39cb168c169c802c3bceb9e93fb10974 # v2.1.0
|
||||||
with:
|
with:
|
||||||
tag_name: v${{ needs.build.outputs.version }}
|
files: ./build/launch4j/Stirling-PDF-Server${{ matrix.file_suffix }}.exe
|
||||||
generate_release_notes: true
|
|
||||||
files: |
|
- name: Rename jar binaries
|
||||||
./libs/Stirling-PDF*
|
run: cp ./build/libs/Stirling-PDF-${{ steps.versionNumber.outputs.versionNumber }}.jar ./build/libs/Stirling-PDF${{ matrix.file_suffix }}.jar
|
||||||
./launch4j/Stirling-PDF-Server*
|
|
||||||
|
- name: Upload Assets jar binaries
|
||||||
|
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
|
||||||
|
with:
|
||||||
|
path: ./build/libs/Stirling-PDF${{ matrix.file_suffix }}.jar
|
||||||
|
name: Stirling-PDF${{ matrix.file_suffix }}.jar
|
||||||
|
overwrite: true
|
||||||
|
retention-days: 1
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
|
- name: Upload jar binaries to release
|
||||||
|
uses: softprops/action-gh-release@01570a1f39cb168c169c802c3bceb9e93fb10974 # v2.1.0
|
||||||
|
with:
|
||||||
|
files: ./build/libs/Stirling-PDF${{ matrix.file_suffix }}.jar
|
||||||
|
|||||||
10
.github/workflows/scorecards.yml
vendored
10
.github/workflows/scorecards.yml
vendored
@@ -10,7 +10,7 @@ on:
|
|||||||
# To guarantee Maintained check is occasionally updated. See
|
# To guarantee Maintained check is occasionally updated. See
|
||||||
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
|
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
|
||||||
schedule:
|
schedule:
|
||||||
- cron: "20 7 * * 2"
|
- cron: '20 7 * * 2'
|
||||||
push:
|
push:
|
||||||
branches: ["main"]
|
branches: ["main"]
|
||||||
permissions: read-all
|
permissions: read-all
|
||||||
@@ -34,7 +34,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Harden Runner
|
- name: Harden Runner
|
||||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
|
||||||
with:
|
with:
|
||||||
egress-policy: audit
|
egress-policy: audit
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: "Run analysis"
|
- name: "Run analysis"
|
||||||
uses: ossf/scorecard-action@f49aabe0b5af0936a0987cfb85d86b75731b0186 # v2.4.1
|
uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0
|
||||||
with:
|
with:
|
||||||
results_file: results.sarif
|
results_file: results.sarif
|
||||||
results_format: sarif
|
results_format: sarif
|
||||||
@@ -66,7 +66,7 @@ jobs:
|
|||||||
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
|
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
|
||||||
# format to the repository Actions tab.
|
# format to the repository Actions tab.
|
||||||
- name: "Upload artifact"
|
- name: "Upload artifact"
|
||||||
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1
|
uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0
|
||||||
with:
|
with:
|
||||||
name: SARIF file
|
name: SARIF file
|
||||||
path: results.sarif
|
path: results.sarif
|
||||||
@@ -74,6 +74,6 @@ jobs:
|
|||||||
|
|
||||||
# Upload the results to GitHub's code scanning dashboard.
|
# Upload the results to GitHub's code scanning dashboard.
|
||||||
- name: "Upload to code-scanning"
|
- name: "Upload to code-scanning"
|
||||||
uses: github/codeql-action/upload-sarif@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3.28.10
|
uses: github/codeql-action/upload-sarif@48ab28a6f5dbc2a99bf1e0131198dd8f1df78169 # v3.28.0
|
||||||
with:
|
with:
|
||||||
sarif_file: results.sarif
|
sarif_file: results.sarif
|
||||||
|
|||||||
63
.github/workflows/sonarqube.yml
vendored
63
.github/workflows/sonarqube.yml
vendored
@@ -1,63 +0,0 @@
|
|||||||
name: Run Sonarqube
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
pull_request_target:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
pull-requests: read
|
|
||||||
actions: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
sonarqube:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Harden Runner
|
|
||||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
|
||||||
with:
|
|
||||||
egress-policy: audit
|
|
||||||
|
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Setup Gradle
|
|
||||||
uses: gradle/actions/setup-gradle@94baf225fe0a508e581a564467443d0e2379123b # v4.3.0
|
|
||||||
|
|
||||||
- name: Build and analyze with Gradle
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
|
||||||
DOCKER_ENABLE_SECURITY: true
|
|
||||||
STIRLING_PDF_DESKTOP_UI: true
|
|
||||||
run: |
|
|
||||||
./gradlew clean build sonar \
|
|
||||||
-Dsonar.projectKey=Stirling-Tools_Stirling-PDF \
|
|
||||||
-Dsonar.organization=stirling-tools \
|
|
||||||
-Dsonar.host.url=https://sonarcloud.io \
|
|
||||||
-Dsonar.login=${SONAR_TOKEN} \
|
|
||||||
-Dsonar.log.level=DEBUG \
|
|
||||||
--info
|
|
||||||
|
|
||||||
- name: Upload Problems Report on Failure
|
|
||||||
if: failure()
|
|
||||||
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1
|
|
||||||
with:
|
|
||||||
name: gradle-problems-report
|
|
||||||
path: build/reports/problems/problems-report.html
|
|
||||||
retention-days: 7
|
|
||||||
|
|
||||||
- name: Upload Sonar Logs on Failure
|
|
||||||
if: failure()
|
|
||||||
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1
|
|
||||||
with:
|
|
||||||
name: sonar-logs
|
|
||||||
path: |
|
|
||||||
.scannerwork/report-task.txt
|
|
||||||
build/sonar/
|
|
||||||
retention-days: 7
|
|
||||||
6
.github/workflows/stale.yml
vendored
6
.github/workflows/stale.yml
vendored
@@ -16,12 +16,12 @@ jobs:
|
|||||||
pull-requests: write
|
pull-requests: write
|
||||||
steps:
|
steps:
|
||||||
- name: Harden Runner
|
- name: Harden Runner
|
||||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
|
||||||
with:
|
with:
|
||||||
egress-policy: audit
|
egress-policy: audit
|
||||||
|
|
||||||
- name: 30 days stale issues
|
- name: 30 days stale issues
|
||||||
uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 # v9.1.0
|
uses: actions/stale@28ca1036281a5e5922ead5184a1bbf96e5fc984e # v9.0.0
|
||||||
with:
|
with:
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
days-before-stale: 30
|
days-before-stale: 30
|
||||||
@@ -37,4 +37,4 @@ jobs:
|
|||||||
only-issue-labels: "more-info-needed"
|
only-issue-labels: "more-info-needed"
|
||||||
days-before-pr-stale: -1 # Prevents PRs from being marked as stale
|
days-before-pr-stale: -1 # Prevents PRs from being marked as stale
|
||||||
days-before-pr-close: -1 # Prevents PRs from being closed
|
days-before-pr-close: -1 # Prevents PRs from being closed
|
||||||
start-date: "2024-07-06T00:00:00Z" # ISO 8601 Format
|
start-date: '2024-07-06T00:00:00Z' # ISO 8601 Format
|
||||||
|
|||||||
6
.github/workflows/swagger.yml
vendored
6
.github/workflows/swagger.yml
vendored
@@ -14,19 +14,19 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Harden Runner
|
- name: Harden Runner
|
||||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
|
||||||
with:
|
with:
|
||||||
egress-policy: audit
|
egress-policy: audit
|
||||||
|
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
- name: Set up JDK 17
|
- name: Set up JDK 17
|
||||||
uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0
|
uses: actions/setup-java@7a6d8a8234af8eb26422e24e3006232cccaa061b # v4.6.0
|
||||||
with:
|
with:
|
||||||
java-version: "17"
|
java-version: "17"
|
||||||
distribution: "temurin"
|
distribution: "temurin"
|
||||||
|
|
||||||
- uses: gradle/actions/setup-gradle@94baf225fe0a508e581a564467443d0e2379123b # v4.3.0
|
- uses: gradle/actions/setup-gradle@0bdd871935719febd78681f197cd39af5b6e16a6 # v4.2.2
|
||||||
|
|
||||||
- name: Generate Swagger documentation
|
- name: Generate Swagger documentation
|
||||||
run: ./gradlew generateOpenApiDocs
|
run: ./gradlew generateOpenApiDocs
|
||||||
|
|||||||
129
.github/workflows/sync_files.yml
vendored
129
.github/workflows/sync_files.yml
vendored
@@ -1,145 +1,62 @@
|
|||||||
name: Sync Files
|
name: Sync Files
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
paths:
|
paths:
|
||||||
- "build.gradle"
|
- "build.gradle"
|
||||||
- "README.md"
|
|
||||||
- "src/main/resources/messages_*.properties"
|
- "src/main/resources/messages_*.properties"
|
||||||
- "src/main/resources/static/3rdPartyLicenses.json"
|
|
||||||
- "scripts/ignore_translation.toml"
|
- "scripts/ignore_translation.toml"
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
read_bot_entries:
|
sync-readme:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
outputs:
|
permissions:
|
||||||
userName: ${{ steps.get-user-id.outputs.user_name }}
|
contents: write
|
||||||
userEmail: ${{ steps.get-user-id.outputs.user_email }}
|
pull-requests: write
|
||||||
committer: ${{ steps.committer.outputs.committer }}
|
|
||||||
steps:
|
steps:
|
||||||
- name: Harden Runner
|
- name: Harden Runner
|
||||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
|
||||||
with:
|
with:
|
||||||
egress-policy: audit
|
egress-policy: audit
|
||||||
|
|
||||||
- name: Generate GitHub App Token
|
|
||||||
id: generate-token
|
|
||||||
uses: actions/create-github-app-token@0d564482f06ca65fa9e77e2510873638c82206f2 # v1.11.5
|
|
||||||
with:
|
|
||||||
app-id: ${{ secrets.GH_APP_ID }}
|
|
||||||
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
|
|
||||||
|
|
||||||
- name: Get GitHub App User ID
|
|
||||||
id: get-user-id
|
|
||||||
run: |
|
|
||||||
USER_NAME="${{ steps.generate-token.outputs.app-slug }}[bot]"
|
|
||||||
USER_ID=$(gh api "/users/$USER_NAME" --jq .id)
|
|
||||||
USER_EMAIL="$USER_ID+$USER_NAME@users.noreply.github.com"
|
|
||||||
echo "user_name=$USER_NAME" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "user_email=$USER_EMAIL" >> "$GITHUB_OUTPUT"
|
|
||||||
echo "user-id=$USER_ID" >> "$GITHUB_OUTPUT"
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
|
|
||||||
|
|
||||||
- id: committer
|
|
||||||
run: |
|
|
||||||
COMMITTER="${{ steps.get-user-id.outputs.user_name }} <${{ steps.get-user-id.outputs.user_email }}>"
|
|
||||||
echo "committer=$COMMITTER" >> "$GITHUB_OUTPUT"
|
|
||||||
|
|
||||||
sync-files:
|
|
||||||
needs: ["read_bot_entries"]
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Harden Runner
|
|
||||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
|
||||||
with:
|
|
||||||
egress-policy: audit
|
|
||||||
|
|
||||||
- name: Generate GitHub App Token
|
|
||||||
id: generate-token
|
|
||||||
uses: actions/create-github-app-token@0d564482f06ca65fa9e77e2510873638c82206f2 # v1.11.5
|
|
||||||
with:
|
|
||||||
app-id: ${{ vars.GH_APP_ID }}
|
|
||||||
private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
|
|
||||||
|
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
|
uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
|
||||||
with:
|
with:
|
||||||
python-version: "3.12"
|
python-version: "3.x"
|
||||||
cache: 'pip' # caching pip dependencies
|
- name: Install dependencies
|
||||||
|
run: pip install tomlkit
|
||||||
- name: Sync translation property files
|
- name: Sync README
|
||||||
run: |
|
run: python scripts/counter_translation.py
|
||||||
python .github/scripts/check_language_properties.py --reference-file "src/main/resources/messages_en_GB.properties" --branch main
|
|
||||||
|
|
||||||
- name: Set up git config
|
- name: Set up git config
|
||||||
run: |
|
run: |
|
||||||
git config --global user.name ${{ needs.read_bot_entries.outputs.userName }}
|
git config --global user.name "github-actions[bot]"
|
||||||
git config --global user.email ${{ needs.read_bot_entries.outputs.userEmail }}
|
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
||||||
|
|
||||||
- name: Run git add
|
- name: Run git add
|
||||||
run: |
|
run: |
|
||||||
git add src/main/resources/messages_*.properties
|
git add .
|
||||||
git diff --staged --quiet || git commit -m ":memo: Sync translation files" || echo "no changes"
|
git diff --staged --quiet || git commit -m ":memo: Sync README
|
||||||
|
> Made via sync_files.yml" || echo "no changes"
|
||||||
- name: Install dependencies
|
|
||||||
run: pip install --require-hashes -r ./.github/scripts/requirements_sync_readme.txt
|
|
||||||
|
|
||||||
- name: Sync README.md
|
|
||||||
run: |
|
|
||||||
python scripts/counter_translation.py
|
|
||||||
|
|
||||||
- name: Run git add
|
|
||||||
run: |
|
|
||||||
git add README.md
|
|
||||||
git diff --staged --quiet || git commit -m ":memo: Sync README.md" || echo "no changes"
|
|
||||||
|
|
||||||
- name: Create Pull Request
|
- name: Create Pull Request
|
||||||
uses: peter-evans/create-pull-request@dd2324fc52d5d43c699a5636bcf19fceaa70c284 # v7.0.7
|
uses: peter-evans/create-pull-request@67ccf781d68cd99b580ae25a5c18a1cc84ffff1f # v7.0.6
|
||||||
with:
|
with:
|
||||||
token: ${{ steps.generate-token.outputs.token }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
commit-message: Update files
|
commit-message: Update files
|
||||||
committer: ${{ needs.read_bot_entries.outputs.committer }}
|
committer: GitHub Action <action@github.com>
|
||||||
author: ${{ needs.read_bot_entries.outputs.committer }}
|
author: GitHub Action <action@github.com>
|
||||||
signoff: true
|
signoff: true
|
||||||
branch: sync_readme
|
branch: sync_readme
|
||||||
title: ":globe_with_meridians: Sync Translations + Update README Progress Table"
|
title: ":memo: Update README: Translation Progress Table"
|
||||||
body: |
|
body: |
|
||||||
### Description of Changes
|
Auto-generated by [create-pull-request][1]
|
||||||
|
|
||||||
This Pull Request was automatically generated to synchronize updates to translation files and documentation. Below are the details of the changes made:
|
|
||||||
|
|
||||||
#### **1. Synchronization of Translation Files**
|
|
||||||
- Updated translation files (`messages_*.properties`) to reflect changes in the reference file `messages_en_GB.properties`.
|
|
||||||
- Ensured consistency and synchronization across all supported language files.
|
|
||||||
- Highlighted any missing or incomplete translations.
|
|
||||||
|
|
||||||
#### **2. Update README.md**
|
|
||||||
- Generated the translation progress table in `README.md`.
|
|
||||||
- Added a summary of the current translation status for all supported languages.
|
|
||||||
- Included up-to-date statistics on translation coverage.
|
|
||||||
|
|
||||||
#### **Why these changes are necessary**
|
|
||||||
- Keeps translation files aligned with the latest reference updates.
|
|
||||||
- Ensures the documentation reflects the current translation progress.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Auto-generated by [create-pull-request][1].
|
|
||||||
|
|
||||||
[1]: https://github.com/peter-evans/create-pull-request
|
[1]: https://github.com/peter-evans/create-pull-request
|
||||||
draft: false
|
draft: false
|
||||||
delete-branch: true
|
delete-branch: true
|
||||||
labels: github-actions
|
labels: Documentation,Translation,github-actions
|
||||||
sign-commits: true
|
sign-commits: true
|
||||||
add-paths: |
|
|
||||||
README.md
|
|
||||||
src/main/resources/messages_*.properties
|
|
||||||
|
|||||||
154
.github/workflows/testdriver.yml
vendored
154
.github/workflows/testdriver.yml
vendored
@@ -1,154 +0,0 @@
|
|||||||
name: UI test with TestDriverAI
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: ["master", "UITest", "testdriver"]
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
deploy:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Harden Runner
|
|
||||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
|
||||||
with:
|
|
||||||
egress-policy: audit
|
|
||||||
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
||||||
|
|
||||||
- name: Set up JDK
|
|
||||||
uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0
|
|
||||||
with:
|
|
||||||
java-version: '17'
|
|
||||||
distribution: 'temurin'
|
|
||||||
|
|
||||||
- name: Build with Gradle
|
|
||||||
run: ./gradlew clean build
|
|
||||||
env:
|
|
||||||
DOCKER_ENABLE_SECURITY: false
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@f7ce87c1d6bead3e36075b2ce75da1f6cc28aaca # v3.9.0
|
|
||||||
|
|
||||||
- name: Get version number
|
|
||||||
id: versionNumber
|
|
||||||
run: |
|
|
||||||
VERSION=$(grep "^version =" build.gradle | awk -F'"' '{print $2}')
|
|
||||||
echo "versionNumber=$VERSION" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Login to Docker Hub
|
|
||||||
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKER_HUB_API }}
|
|
||||||
|
|
||||||
- name: Build and push test image
|
|
||||||
uses: docker/build-push-action@0adf9959216b96bec444f325f1e493d4aa344497 # v6.14.0
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
file: ./Dockerfile
|
|
||||||
push: true
|
|
||||||
tags: ${{ secrets.DOCKER_HUB_USERNAME }}/test:test-${{ github.sha }}
|
|
||||||
build-args: VERSION_TAG=${{ steps.versionNumber.outputs.versionNumber }}
|
|
||||||
platforms: linux/amd64
|
|
||||||
|
|
||||||
- name: Set up SSH
|
|
||||||
run: |
|
|
||||||
mkdir -p ~/.ssh/
|
|
||||||
echo "${{ secrets.VPS_SSH_KEY }}" > ../private.key
|
|
||||||
sudo chmod 600 ../private.key
|
|
||||||
|
|
||||||
- name: Deploy to VPS
|
|
||||||
run: |
|
|
||||||
cat > docker-compose.yml << EOF
|
|
||||||
version: '3.3'
|
|
||||||
services:
|
|
||||||
stirling-pdf:
|
|
||||||
container_name: stirling-pdf-test-${{ github.sha }}
|
|
||||||
image: ${{ secrets.DOCKER_HUB_USERNAME }}/test:test-${{ github.sha }}
|
|
||||||
ports:
|
|
||||||
- "1337:8080"
|
|
||||||
volumes:
|
|
||||||
- /stirling/test-${{ github.sha }}/data:/usr/share/tessdata:rw
|
|
||||||
- /stirling/test-${{ github.sha }}/config:/configs:rw
|
|
||||||
- /stirling/test-${{ github.sha }}/logs:/logs:rw
|
|
||||||
environment:
|
|
||||||
DOCKER_ENABLE_SECURITY: "false"
|
|
||||||
SECURITY_ENABLELOGIN: "false"
|
|
||||||
SYSTEM_DEFAULTLOCALE: en-GB
|
|
||||||
UI_APPNAME: "Stirling-PDF Test"
|
|
||||||
UI_HOMEDESCRIPTION: "Test Deployment"
|
|
||||||
UI_APPNAMENAVBAR: "Test"
|
|
||||||
SYSTEM_MAXFILESIZE: "100"
|
|
||||||
METRICS_ENABLED: "true"
|
|
||||||
SYSTEM_GOOGLEVISIBILITY: "false"
|
|
||||||
SYSTEM_ENABLEANALYTICS: "false"
|
|
||||||
restart: on-failure:5
|
|
||||||
EOF
|
|
||||||
|
|
||||||
scp -i ../private.key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null docker-compose.yml ${{ secrets.VPS_USERNAME }}@${{ secrets.VPS_HOST }}:/tmp/docker-compose.yml
|
|
||||||
|
|
||||||
ssh -i ../private.key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ${{ secrets.VPS_USERNAME }}@${{ secrets.VPS_HOST }} << EOF
|
|
||||||
mkdir -p /stirling/test-${{ github.sha }}/{data,config,logs}
|
|
||||||
mv /tmp/docker-compose.yml /stirling/test-${{ github.sha }}/docker-compose.yml
|
|
||||||
cd /stirling/test-${{ github.sha }}
|
|
||||||
docker-compose pull
|
|
||||||
docker-compose up -d
|
|
||||||
EOF
|
|
||||||
|
|
||||||
test:
|
|
||||||
needs: deploy
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Harden Runner
|
|
||||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
|
||||||
with:
|
|
||||||
egress-policy: audit
|
|
||||||
|
|
||||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
||||||
|
|
||||||
- name: Run TestDriver.ai
|
|
||||||
uses: testdriverai/action@f0d0f45fdd684db628baa843fe9313f3ca3a8aa8 #1.1.3
|
|
||||||
with:
|
|
||||||
key: ${{secrets.TESTDRIVER_API_KEY}}
|
|
||||||
prerun: |
|
|
||||||
npm install
|
|
||||||
npm run build
|
|
||||||
npm install dashcam-chrome --save
|
|
||||||
Start-Process "C:/Program Files/Google/Chrome/Application/chrome.exe" -ArgumentList "--start-maximized", "--load-extension=$(pwd)/node_modules/dashcam-chrome/build", "http://${{ secrets.VPS_HOST }}:1337"
|
|
||||||
Start-Sleep -Seconds 20
|
|
||||||
prompt: |
|
|
||||||
1. /run testing/testdriver/test.yml
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
FORCE_COLOR: "3"
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
needs: [deploy, test]
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: always()
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Harden Runner
|
|
||||||
uses: step-security/harden-runner@4d991eb9b905ef189e4c376166672c3f2f230481 # v2.11.0
|
|
||||||
with:
|
|
||||||
egress-policy: audit
|
|
||||||
|
|
||||||
- name: Set up SSH
|
|
||||||
run: |
|
|
||||||
mkdir -p ~/.ssh/
|
|
||||||
echo "${{ secrets.VPS_SSH_KEY }}" > ../private.key
|
|
||||||
sudo chmod 600 ../private.key
|
|
||||||
|
|
||||||
- name: Cleanup deployment
|
|
||||||
run: |
|
|
||||||
ssh -i ../private.key -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ${{ secrets.VPS_USERNAME }}@${{ secrets.VPS_HOST }} << EOF
|
|
||||||
cd /stirling/test-${{ github.sha }}
|
|
||||||
docker-compose down
|
|
||||||
cd /stirling
|
|
||||||
rm -rf test-${{ github.sha }}
|
|
||||||
EOF
|
|
||||||
72
.github/workflows/update-translations.yml
vendored
Normal file
72
.github/workflows/update-translations.yml
vendored
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
name: Update Translations
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: ["main"]
|
||||||
|
paths:
|
||||||
|
- "src/main/resources/messages_en_GB.properties"
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
update-translations-main:
|
||||||
|
if: github.event_name == 'push'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
pull-requests: write
|
||||||
|
steps:
|
||||||
|
- name: Harden Runner
|
||||||
|
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
|
||||||
|
with:
|
||||||
|
egress-policy: audit
|
||||||
|
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
|
||||||
|
with:
|
||||||
|
python-version: "3.x"
|
||||||
|
|
||||||
|
- name: Run Python script to check files
|
||||||
|
id: run-check
|
||||||
|
run: |
|
||||||
|
echo "Running Python script to check files..."
|
||||||
|
python .github/scripts/check_language_properties.py \
|
||||||
|
--reference-file src/main/resources/messages_en_GB.properties \
|
||||||
|
--branch main
|
||||||
|
|
||||||
|
- name: Set up git config
|
||||||
|
run: |
|
||||||
|
git config --global user.name "github-actions[bot]"
|
||||||
|
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
||||||
|
|
||||||
|
- name: Add translation keys
|
||||||
|
run: |
|
||||||
|
git add src/main/resources/messages_*.properties
|
||||||
|
git diff --staged --quiet || echo "CHANGES_DETECTED=true" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Create Pull Request
|
||||||
|
id: cpr
|
||||||
|
if: env.CHANGES_DETECTED == 'true'
|
||||||
|
uses: peter-evans/create-pull-request@67ccf781d68cd99b580ae25a5c18a1cc84ffff1f # v7.0.6
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
commit-message: "Update translation files"
|
||||||
|
committer: GitHub Action <action@github.com>
|
||||||
|
author: GitHub Action <action@github.com>
|
||||||
|
signoff: true
|
||||||
|
branch: update_translation_files
|
||||||
|
title: "Update translation files"
|
||||||
|
add-paths: |
|
||||||
|
src/main/resources/messages_*.properties
|
||||||
|
body: |
|
||||||
|
Auto-generated by [create-pull-request][1]
|
||||||
|
|
||||||
|
[1]: https://github.com/peter-evans/create-pull-request
|
||||||
|
draft: false
|
||||||
|
delete-branch: true
|
||||||
|
labels: Translation,github-actions
|
||||||
|
sign-commits: true
|
||||||
10
.gitignore
vendored
10
.gitignore
vendored
@@ -14,18 +14,12 @@ local.properties
|
|||||||
.classpath
|
.classpath
|
||||||
.project
|
.project
|
||||||
version.properties
|
version.properties
|
||||||
|
|
||||||
#### Stirling-PDF Files ###
|
|
||||||
pipeline/watchedFolders/
|
pipeline/watchedFolders/
|
||||||
pipeline/finishedFolders/
|
pipeline/finishedFolders/
|
||||||
|
#### Stirling-PDF Files ###
|
||||||
customFiles/
|
customFiles/
|
||||||
configs/
|
configs/
|
||||||
watchedFolders/
|
watchedFolders/
|
||||||
clientWebUI/
|
|
||||||
!cucumber/
|
|
||||||
!cucumber/exampleFiles/
|
|
||||||
!cucumber/exampleFiles/example_html.zip
|
|
||||||
exampleYmlFiles/stirling/
|
|
||||||
|
|
||||||
# Gradle
|
# Gradle
|
||||||
.gradle
|
.gradle
|
||||||
@@ -117,7 +111,6 @@ exampleYmlFiles/stirling/
|
|||||||
*.war
|
*.war
|
||||||
*.nar
|
*.nar
|
||||||
*.ear
|
*.ear
|
||||||
*.zip
|
|
||||||
*.tar.gz
|
*.tar.gz
|
||||||
*.rar
|
*.rar
|
||||||
*.db
|
*.db
|
||||||
@@ -140,7 +133,6 @@ venv.bak/
|
|||||||
# VS Code
|
# VS Code
|
||||||
/.vscode/**/*
|
/.vscode/**/*
|
||||||
!/.vscode/settings.json
|
!/.vscode/settings.json
|
||||||
!/.vscode/extensions.json
|
|
||||||
|
|
||||||
# IntelliJ IDEA
|
# IntelliJ IDEA
|
||||||
.idea/
|
.idea/
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ repos:
|
|||||||
args:
|
args:
|
||||||
- --fix
|
- --fix
|
||||||
- --line-length=127
|
- --line-length=127
|
||||||
files: ^((\.github/scripts|scripts)/.+)?[^/]+\.py$
|
files: ^((.github/scripts|scripts)/.+)?[^/]+\.py$
|
||||||
exclude: (split_photos.py)
|
exclude: (split_photos.py)
|
||||||
- id: ruff-format
|
- id: ruff-format
|
||||||
files: ^((\.github/scripts|scripts)/.+)?[^/]+\.py$
|
files: ^((.github/scripts|scripts)/.+)?[^/]+\.py$
|
||||||
exclude: (split_photos.py)
|
exclude: (split_photos.py)
|
||||||
- repo: https://github.com/codespell-project/codespell
|
- repo: https://github.com/codespell-project/codespell
|
||||||
rev: v2.3.0
|
rev: v2.3.0
|
||||||
@@ -19,18 +19,39 @@ repos:
|
|||||||
- --ignore-words-list=
|
- --ignore-words-list=
|
||||||
- --skip="./.*,*.csv,*.json,*.ambr"
|
- --skip="./.*,*.csv,*.json,*.ambr"
|
||||||
- --quiet-level=2
|
- --quiet-level=2
|
||||||
files: \.(html|css|js|py|md)$
|
files: \.(properties|html|css|js|py|md)$
|
||||||
exclude: (.vscode|.devcontainer|src/main/resources|Dockerfile|.*/pdfjs.*|.*/thirdParty.*|bootstrap.*|.*\.min\..*|.*diff\.js)
|
exclude: (.vscode|.devcontainer|src/main/resources|Dockerfile)
|
||||||
- repo: https://github.com/gitleaks/gitleaks
|
- repo: https://github.com/gitleaks/gitleaks
|
||||||
rev: v8.22.0
|
rev: v8.22.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: gitleaks
|
- id: gitleaks
|
||||||
|
- repo: https://github.com/jumanjihouse/pre-commit-hooks
|
||||||
|
rev: 3.0.0
|
||||||
|
hooks:
|
||||||
|
- id: shellcheck
|
||||||
|
files: ^.*(\.bash|\.sh|\.ksh|\.zsh)$
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
rev: v5.0.0
|
rev: v5.0.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: end-of-file-fixer
|
- id: end-of-file-fixer
|
||||||
files: ^.*(\.js|\.java|\.py|\.yml)$
|
files: ^.*(\.js|\.java|\.py|\.yml)$
|
||||||
exclude: ^(.*/pdfjs.*|.*/thirdParty.*|bootstrap.*|.*\.min\..*|.*diff\.js|\.github/workflows/.*$)
|
exclude: ^(.*/pdfjs.*|.*/thirdParty.*|bootstrap.*|.*\.min\..*|.*diff\.js$)
|
||||||
- id: trailing-whitespace
|
- id: trailing-whitespace
|
||||||
files: ^.*(\.js|\.java|\.py|\.yml)$
|
files: ^.*(\.js|\.java|\.py|\.yml)$
|
||||||
exclude: ^(.*/pdfjs.*|.*/thirdParty.*|bootstrap.*|.*\.min\..*|.*diff\.js|\.github/workflows/.*$)
|
exclude: ^(.*/pdfjs.*|.*/thirdParty.*|bootstrap.*|.*\.min\..*|.*diff\.js$)
|
||||||
|
|
||||||
|
- repo: local
|
||||||
|
hooks:
|
||||||
|
- id: check-duplicate-properties-keys
|
||||||
|
name: Check Duplicate Properties Keys
|
||||||
|
entry: python .github/scripts/check_duplicates.py
|
||||||
|
language: python
|
||||||
|
files: ^(src)/.+\.properties$
|
||||||
|
- id: check-html-tabs
|
||||||
|
name: Check HTML for tabs
|
||||||
|
description: Ensures HTML/CSS/JS files do not contain tab characters
|
||||||
|
# args: ["--replace_with= "]
|
||||||
|
entry: python .github/scripts/check_tabulator.py
|
||||||
|
language: python
|
||||||
|
exclude: ^(.*/pdfjs.*|.*/thirdParty.*|bootstrap.*|.*\.min\..*|.*diff\.js$)
|
||||||
|
files: ^.*(\.html|\.css|\.js)$
|
||||||
23
.vscode/extensions.json
vendored
23
.vscode/extensions.json
vendored
@@ -1,23 +0,0 @@
|
|||||||
{
|
|
||||||
"recommendations": [
|
|
||||||
"elagil.pre-commit-helper", // Support for pre-commit hooks to enforce code quality
|
|
||||||
"josevseb.google-java-format-for-vs-code", // Google Java code formatter to follow the Google Java Style Guide
|
|
||||||
"ms-python.black-formatter", // Python code formatter using Black
|
|
||||||
"ms-python.flake8", // Flake8 linter for Python to enforce code quality
|
|
||||||
"ms-python.python", // Official Microsoft Python extension with IntelliSense, debugging, and Jupyter support
|
|
||||||
// "ms-vscode-remote.remote-containers", // Support for remote development with containers (Docker, Dev Containers)
|
|
||||||
// "ms-vscode-remote.vscode-remote-extensionpack", // Remote Development Pack for SSH, WSL, and Containers
|
|
||||||
"Oracle.oracle-java", // Oracle Java extension with additional features for Java development
|
|
||||||
"redhat.java", // Java support by Red Hat with IntelliSense, debugging, and code navigation
|
|
||||||
"streetsidesoftware.code-spell-checker", // Spell checker for code to avoid typos
|
|
||||||
"vmware.vscode-boot-dev-pack", // Developer tools for Spring Boot by VMware
|
|
||||||
"vmware.vscode-spring-boot", // Spring Boot tools by VMware for enhanced Spring development
|
|
||||||
"vscjava.vscode-gradle", // Gradle extension for build and automation support
|
|
||||||
"vscjava.vscode-java-debug", // Debugging support for Java projects
|
|
||||||
"vscjava.vscode-java-dependency", // Java dependency management within VS Code
|
|
||||||
"vscjava.vscode-java-pack", // Java Extension Pack with essential Java tools for VS Code
|
|
||||||
"vscjava.vscode-java-test", // Java test framework for running and debugging tests in VS Code
|
|
||||||
"vscjava.vscode-spring-boot-dashboard", // Spring Boot dashboard for managing and visualizing Spring Boot applications
|
|
||||||
"vscjava.vscode-spring-initializr" // Support for Spring Initializr to create new Spring projects
|
|
||||||
]
|
|
||||||
}
|
|
||||||
121
.vscode/settings.json
vendored
121
.vscode/settings.json
vendored
@@ -2,147 +2,54 @@
|
|||||||
"java.compile.nullAnalysis.mode": "automatic",
|
"java.compile.nullAnalysis.mode": "automatic",
|
||||||
"files.eol": "auto",
|
"files.eol": "auto",
|
||||||
"java.configuration.updateBuildConfiguration": "interactive",
|
"java.configuration.updateBuildConfiguration": "interactive",
|
||||||
"black-formatter.args": [
|
"black-formatter.args": ["--line-length", "127"],
|
||||||
"--line-length",
|
"flake8.args": ["--max-line-length", "127"],
|
||||||
"127"
|
"pylint.args": ["max-line-length", "127"],
|
||||||
],
|
|
||||||
"flake8.args": [
|
|
||||||
"--max-line-length",
|
|
||||||
"127"
|
|
||||||
],
|
|
||||||
"[java]": {
|
"[java]": {
|
||||||
"editor.tabSize": 4,
|
"editor.tabSize": 4,
|
||||||
"editor.detectIndentation": false,
|
"editor.detectIndentation": false,
|
||||||
"editor.rulers": [
|
"editor.rulers": [127]
|
||||||
127
|
|
||||||
],
|
|
||||||
"editor.defaultFormatter": "josevseb.google-java-format-for-vs-code"
|
|
||||||
},
|
},
|
||||||
"[python]": {
|
"[python]": {
|
||||||
"editor.tabSize": 2,
|
"editor.tabSize": 2,
|
||||||
"editor.detectIndentation": false,
|
"editor.detectIndentation": false,
|
||||||
"editor.rulers": [
|
"editor.rulers": [127]
|
||||||
127
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"[gradle-build]": {
|
"[gradle-build]": {
|
||||||
"editor.tabSize": 4,
|
"editor.tabSize": 4,
|
||||||
"editor.detectIndentation": false,
|
"editor.detectIndentation": false,
|
||||||
"editor.rulers": [
|
"editor.rulers": [127]
|
||||||
127
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"[gradle]": {
|
"[gradle]": {
|
||||||
"editor.tabSize": 4,
|
"editor.tabSize": 4,
|
||||||
"editor.detectIndentation": false,
|
"editor.detectIndentation": false,
|
||||||
"editor.rulers": [
|
"editor.rulers": [127]
|
||||||
127
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"[html]": {
|
"[html]": {
|
||||||
"editor.tabSize": 2,
|
"editor.tabSize": 2,
|
||||||
"editor.rulers": [
|
"editor.rulers": [127],
|
||||||
127
|
|
||||||
],
|
|
||||||
"files.trimFinalNewlines": false,
|
"files.trimFinalNewlines": false,
|
||||||
"files.insertFinalNewline": false
|
"files.insertFinalNewline": false
|
||||||
},
|
},
|
||||||
"[javascript]": {
|
"[javascript]": {
|
||||||
"editor.tabSize": 2,
|
"editor.tabSize": 2,
|
||||||
"editor.rulers": [
|
"editor.rulers": [127]
|
||||||
127
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"[yaml]": {
|
"[yaml]": {
|
||||||
"files.trimFinalNewlines": false,
|
"files.trimFinalNewlines": false,
|
||||||
"files.insertFinalNewline": false
|
"files.insertFinalNewline": false
|
||||||
},
|
},
|
||||||
|
"diffEditor.maxComputationTime": 0,
|
||||||
|
"editor.wordSegmenterLocales": null,
|
||||||
|
"editor.guides.bracketPairs": "active",
|
||||||
|
"editor.guides.bracketPairsHorizontal": "active",
|
||||||
"files.insertFinalNewline": true,
|
"files.insertFinalNewline": true,
|
||||||
"files.trimFinalNewlines": true,
|
"files.trimFinalNewlines": true,
|
||||||
"files.trimTrailingWhitespace": true,
|
"files.trimTrailingWhitespace": true,
|
||||||
"files.autoSave": "onFocusChange",
|
|
||||||
"files.autoSaveWhenNoErrors": true,
|
|
||||||
"diffEditor.maxComputationTime": 0,
|
|
||||||
"editor.wordSegmenterLocales": "",
|
|
||||||
"editor.guides.bracketPairs": "active",
|
|
||||||
"editor.guides.bracketPairsHorizontal": "active",
|
|
||||||
"editor.indentSize": "tabSize",
|
"editor.indentSize": "tabSize",
|
||||||
"editor.stickyScroll.enabled": false,
|
"editor.stickyScroll.enabled": false,
|
||||||
"editor.minimap.enabled": false,
|
"editor.minimap.enabled": false,
|
||||||
"editor.formatOnSave": true,
|
"editor.formatOnSave": true,
|
||||||
"editor.insertSpaces": true,
|
|
||||||
"java.format.enabled": true,
|
|
||||||
"java.format.settings.profile": "GoogleStyle",
|
|
||||||
"java.format.settings.google.version": "1.25.2",
|
|
||||||
"java.format.settings.google.mode": "jar-file",
|
"java.format.settings.google.mode": "jar-file",
|
||||||
"java.format.settings.google.extra": "--aosp --skip-sorting-imports --skip-javadoc-formatting",
|
"java.format.settings.google.extra": "--aosp --skip-sorting-imports"
|
||||||
// (DE) Aktiviert Kommentare im Java-Format.
|
|
||||||
// (EN) Enables comments in Java formatting.
|
|
||||||
// "java.format.comments.enabled": true,
|
|
||||||
// (DE) Generiert automatisch Kommentare im Code.
|
|
||||||
// (EN) Automatically generates comments in code.
|
|
||||||
// "java.codeGeneration.generateComments": true,
|
|
||||||
// https://github.com/redhat-developer/vscode-java/blob/master/document/_java.learnMoreAboutCleanUps.md#java-clean-ups
|
|
||||||
"java.saveActions.cleanup": true,
|
|
||||||
"java.cleanup.actions": [
|
|
||||||
"invertEquals", // Inverts calls to Object.equals(Object) and String.equalsIgnoreCase(String) to avoid useless null pointer exception.
|
|
||||||
"instanceofPatternMatch" // Replaces instanceof checks with pattern matching.
|
|
||||||
],
|
|
||||||
// (DE) Aktiviert die Code-Vervollständigung für Java.
|
|
||||||
// (EN) Enables code completion for Java.
|
|
||||||
"java.completion.engine": "dom",
|
|
||||||
"java.completion.enabled": true,
|
|
||||||
"java.completion.importOrder": [
|
|
||||||
"java",
|
|
||||||
"javax",
|
|
||||||
"org",
|
|
||||||
"com",
|
|
||||||
"net",
|
|
||||||
"io",
|
|
||||||
"jakarta",
|
|
||||||
"lombok",
|
|
||||||
"me",
|
|
||||||
"stirling",
|
|
||||||
],
|
|
||||||
"java.project.resourceFilters": [
|
|
||||||
".devcontainer/",
|
|
||||||
".git/",
|
|
||||||
".github/",
|
|
||||||
".gradle/",
|
|
||||||
".venv/",
|
|
||||||
".venv*/",
|
|
||||||
".vscode/",
|
|
||||||
"bin/",
|
|
||||||
"build/",
|
|
||||||
"configs/",
|
|
||||||
"customFiles/",
|
|
||||||
"docs/",
|
|
||||||
"exampleYmlFiles",
|
|
||||||
"gradle/",
|
|
||||||
"images/",
|
|
||||||
"logs/",
|
|
||||||
"pipeline/",
|
|
||||||
"scripts/",
|
|
||||||
"testings/",
|
|
||||||
".git-blame-ignore-revs",
|
|
||||||
".gitattributes",
|
|
||||||
".gitignore",
|
|
||||||
".pre-commit-config.yaml",
|
|
||||||
],
|
|
||||||
// Enables signature help in Java.
|
|
||||||
"java.signatureHelp.enabled": true,
|
|
||||||
// Enables detailed signature help descriptions.
|
|
||||||
"java.signatureHelp.description.enabled": true,
|
|
||||||
// Downloads sources for Maven dependencies.
|
|
||||||
"java.maven.downloadSources": true,
|
|
||||||
// Enables Gradle project import.
|
|
||||||
"java.import.gradle.enabled": true,
|
|
||||||
// Downloads sources for Eclipse projects.
|
|
||||||
"java.eclipse.downloadSources": true,
|
|
||||||
// Enables import of the Gradle wrapper.
|
|
||||||
"java.import.gradle.wrapper.enabled": true,
|
|
||||||
"spring.initializr.defaultLanguage": "Java",
|
|
||||||
"spring.initializr.defaultGroupId": "stirling.software.SPDF",
|
|
||||||
"spring.initializr.defaultArtifactId": "SPDF",
|
|
||||||
"cSpell.enabled": false,
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,16 +39,6 @@ Stirling-PDF is built using:
|
|||||||
2. Install Docker and JDK17 if not already installed.
|
2. Install Docker and JDK17 if not already installed.
|
||||||
|
|
||||||
3. Install a recommended Java IDE such as Eclipse, IntelliJ, or VSCode
|
3. Install a recommended Java IDE such as Eclipse, IntelliJ, or VSCode
|
||||||
1. Only VSCode
|
|
||||||
1. Open VS Code.
|
|
||||||
2. When prompted, install the recommended extensions.
|
|
||||||
3. Alternatively, open the command palette (`Ctrl + Shift + P` or `Cmd + Shift + P` on macOS) and run:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
Extensions: Show Recommended Extensions
|
|
||||||
```
|
|
||||||
|
|
||||||
4. Install the required extensions from the list.
|
|
||||||
|
|
||||||
4. Lombok Setup
|
4. Lombok Setup
|
||||||
Stirling-PDF uses Lombok to reduce boilerplate code. Some IDEs, like Eclipse, don't support Lombok out of the box. To set up Lombok in your development environment:
|
Stirling-PDF uses Lombok to reduce boilerplate code. Some IDEs, like Eclipse, don't support Lombok out of the box. To set up Lombok in your development environment:
|
||||||
|
|||||||
79
Dockerfile
79
Dockerfile
@@ -1,5 +1,5 @@
|
|||||||
# Main stage
|
# Main stage
|
||||||
FROM alpine:3.21.3@sha256:a8560b36e8b8210634f77d9f7f9efd7ffa463e380b75e2e74aff4511df3ef88c
|
FROM alpine:3.20.3
|
||||||
|
|
||||||
# Copy necessary files
|
# Copy necessary files
|
||||||
COPY scripts /scripts
|
COPY scripts /scripts
|
||||||
@@ -25,66 +25,49 @@ LABEL org.opencontainers.image.keywords="PDF, manipulation, merge, split, conver
|
|||||||
# Set Environment Variables
|
# Set Environment Variables
|
||||||
ENV DOCKER_ENABLE_SECURITY=false \
|
ENV DOCKER_ENABLE_SECURITY=false \
|
||||||
VERSION_TAG=$VERSION_TAG \
|
VERSION_TAG=$VERSION_TAG \
|
||||||
JAVA_TOOL_OPTIONS="-XX:+UnlockExperimentalVMOptions \
|
JAVA_TOOL_OPTIONS="$JAVA_TOOL_OPTIONS -XX:MaxRAMPercentage=75" \
|
||||||
-XX:MaxRAMPercentage=75 \
|
|
||||||
-XX:InitiatingHeapOccupancyPercent=20 \
|
|
||||||
-XX:+G1PeriodicGCInvokesConcurrent \
|
|
||||||
-XX:G1PeriodicGCInterval=10000 \
|
|
||||||
-XX:+UseStringDeduplication \
|
|
||||||
-XX:G1PeriodicGCSystemLoadThreshold=70" \
|
|
||||||
HOME=/home/stirlingpdfuser \
|
HOME=/home/stirlingpdfuser \
|
||||||
PUID=1000 \
|
PUID=1000 \
|
||||||
PGID=1000 \
|
PGID=1000 \
|
||||||
UMASK=022 \
|
UMASK=022
|
||||||
PYTHONPATH=/usr/lib/libreoffice/program:/opt/venv/lib/python3.12/site-packages \
|
|
||||||
UNO_PATH=/usr/lib/libreoffice/program \
|
|
||||||
URE_BOOTSTRAP=file:///usr/lib/libreoffice/program/fundamentalrc
|
|
||||||
|
|
||||||
|
|
||||||
# JDK for app
|
# JDK for app
|
||||||
RUN echo "@main https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/apk/repositories && \
|
RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/apk/repositories && \
|
||||||
echo "@community https://dl-cdn.alpinelinux.org/alpine/edge/community" | tee -a /etc/apk/repositories && \
|
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/community" | tee -a /etc/apk/repositories && \
|
||||||
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/testing" | tee -a /etc/apk/repositories && \
|
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/testing" | tee -a /etc/apk/repositories && \
|
||||||
apk upgrade --no-cache -a && \
|
apk upgrade --no-cache -a && \
|
||||||
apk add --no-cache \
|
apk add --no-cache \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
tzdata \
|
tzdata \
|
||||||
tini \
|
tini \
|
||||||
bash \
|
bash \
|
||||||
curl \
|
curl \
|
||||||
qpdf \
|
qpdf \
|
||||||
shadow \
|
shadow \
|
||||||
su-exec \
|
su-exec \
|
||||||
openssl \
|
openssl \
|
||||||
openssl-dev \
|
openssl-dev \
|
||||||
openjdk21-jre \
|
openjdk21-jre \
|
||||||
# Doc conversion
|
# Doc conversion
|
||||||
gcompat \
|
libreoffice \
|
||||||
libc6-compat \
|
# pdftohtml
|
||||||
libreoffice \
|
poppler-utils \
|
||||||
# pdftohtml
|
# OCR MY PDF (unpaper for descew and other advanced features)
|
||||||
poppler-utils \
|
tesseract-ocr-data-eng \
|
||||||
# OCR MY PDF (unpaper for descew and other advanced features)
|
# CV
|
||||||
tesseract-ocr-data-eng \
|
py3-opencv \
|
||||||
# CV
|
# python3/pip
|
||||||
py3-opencv \
|
python3 \
|
||||||
python3 \
|
py3-pip && \
|
||||||
py3-pip \
|
# uno unoconv and HTML
|
||||||
py3-pillow@testing \
|
pip install --break-system-packages --no-cache-dir --upgrade unoconv WeasyPrint pdf2image pillow && \
|
||||||
py3-pdf2image@testing && \
|
|
||||||
python3 -m venv /opt/venv && \
|
|
||||||
export PATH="/opt/venv/bin:$PATH" && \
|
|
||||||
pip install --upgrade pip && \
|
|
||||||
pip install --no-cache-dir --upgrade unoserver weasyprint && \
|
|
||||||
ln -s /usr/lib/libreoffice/program/uno.py /opt/venv/lib/python3.12/site-packages/ && \
|
|
||||||
ln -s /usr/lib/libreoffice/program/unohelper.py /opt/venv/lib/python3.12/site-packages/ && \
|
|
||||||
ln -s /usr/lib/libreoffice/program /opt/venv/lib/python3.12/site-packages/LibreOffice && \
|
|
||||||
mv /usr/share/tessdata /usr/share/tessdata-original && \
|
mv /usr/share/tessdata /usr/share/tessdata-original && \
|
||||||
mkdir -p $HOME /configs /logs /customFiles /pipeline/watchedFolders /pipeline/finishedFolders && \
|
mkdir -p $HOME /configs /logs /customFiles /pipeline/watchedFolders /pipeline/finishedFolders && \
|
||||||
fc-cache -f -v && \
|
fc-cache -f -v && \
|
||||||
chmod +x /scripts/* && \
|
chmod +x /scripts/* && \
|
||||||
chmod +x /scripts/init.sh && \
|
chmod +x /scripts/init.sh && \
|
||||||
# User permissions
|
# User permissions
|
||||||
addgroup -S stirlingpdfgroup && adduser -S stirlingpdfuser -G stirlingpdfgroup && \
|
addgroup -S stirlingpdfgroup && adduser -S stirlingpdfuser -G stirlingpdfgroup && \
|
||||||
chown -R stirlingpdfuser:stirlingpdfgroup $HOME /scripts /usr/share/fonts/opentype/noto /configs /customFiles /pipeline && \
|
chown -R stirlingpdfuser:stirlingpdfgroup $HOME /scripts /usr/share/fonts/opentype/noto /configs /customFiles /pipeline && \
|
||||||
chown stirlingpdfuser:stirlingpdfgroup /app.jar
|
chown stirlingpdfuser:stirlingpdfgroup /app.jar
|
||||||
@@ -93,4 +76,4 @@ EXPOSE 8080/tcp
|
|||||||
|
|
||||||
# Set user and run command
|
# Set user and run command
|
||||||
ENTRYPOINT ["tini", "--", "/scripts/init.sh"]
|
ENTRYPOINT ["tini", "--", "/scripts/init.sh"]
|
||||||
CMD ["sh", "-c", "java -Dfile.encoding=UTF-8 -jar /app.jar & /opt/venv/bin/unoserver --port 2003 --interface 0.0.0.0"]
|
CMD ["java", "-Dfile.encoding=UTF-8", "-jar", "/app.jar"]
|
||||||
|
|||||||
@@ -9,11 +9,10 @@ COPY . .
|
|||||||
|
|
||||||
# Build the application with DOCKER_ENABLE_SECURITY=false
|
# Build the application with DOCKER_ENABLE_SECURITY=false
|
||||||
RUN DOCKER_ENABLE_SECURITY=true \
|
RUN DOCKER_ENABLE_SECURITY=true \
|
||||||
STIRLING_PDF_DESKTOP_UI=false \
|
./gradlew clean build
|
||||||
./gradlew clean build
|
|
||||||
|
|
||||||
# Main stage
|
# Main stage
|
||||||
FROM alpine:3.21.3@sha256:a8560b36e8b8210634f77d9f7f9efd7ffa463e380b75e2e74aff4511df3ef88c
|
FROM alpine:3.20.3
|
||||||
|
|
||||||
# Copy necessary files
|
# Copy necessary files
|
||||||
COPY scripts /scripts
|
COPY scripts /scripts
|
||||||
@@ -26,75 +25,58 @@ ARG VERSION_TAG
|
|||||||
# Set Environment Variables
|
# Set Environment Variables
|
||||||
ENV DOCKER_ENABLE_SECURITY=false \
|
ENV DOCKER_ENABLE_SECURITY=false \
|
||||||
VERSION_TAG=$VERSION_TAG \
|
VERSION_TAG=$VERSION_TAG \
|
||||||
JAVA_TOOL_OPTIONS="-XX:+UnlockExperimentalVMOptions \
|
JAVA_TOOL_OPTIONS="$JAVA_TOOL_OPTIONS -XX:MaxRAMPercentage=75" \
|
||||||
-XX:MaxRAMPercentage=75 \
|
|
||||||
-XX:InitiatingHeapOccupancyPercent=20 \
|
|
||||||
-XX:+G1PeriodicGCInvokesConcurrent \
|
|
||||||
-XX:G1PeriodicGCInterval=10000 \
|
|
||||||
-XX:+UseStringDeduplication \
|
|
||||||
-XX:G1PeriodicGCSystemLoadThreshold=70" \
|
|
||||||
HOME=/home/stirlingpdfuser \
|
HOME=/home/stirlingpdfuser \
|
||||||
PUID=1000 \
|
PUID=1000 \
|
||||||
PGID=1000 \
|
PGID=1000 \
|
||||||
UMASK=022 \
|
UMASK=022 \
|
||||||
FAT_DOCKER=true \
|
FAT_DOCKER=true \
|
||||||
INSTALL_BOOK_AND_ADVANCED_HTML_OPS=false \
|
INSTALL_BOOK_AND_ADVANCED_HTML_OPS=false
|
||||||
PYTHONPATH=/usr/lib/libreoffice/program:/opt/venv/lib/python3.12/site-packages \
|
|
||||||
UNO_PATH=/usr/lib/libreoffice/program \
|
|
||||||
URE_BOOTSTRAP=file:///usr/lib/libreoffice/program/fundamentalrc
|
|
||||||
|
|
||||||
|
|
||||||
# JDK for app
|
# JDK for app
|
||||||
RUN echo "@main https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/apk/repositories && \
|
RUN echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/main" | tee -a /etc/apk/repositories && \
|
||||||
echo "@community https://dl-cdn.alpinelinux.org/alpine/edge/community" | tee -a /etc/apk/repositories && \
|
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/community" | tee -a /etc/apk/repositories && \
|
||||||
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/testing" | tee -a /etc/apk/repositories && \
|
echo "@testing https://dl-cdn.alpinelinux.org/alpine/edge/testing" | tee -a /etc/apk/repositories && \
|
||||||
apk upgrade --no-cache -a && \
|
apk upgrade --no-cache -a && \
|
||||||
apk add --no-cache \
|
apk add --no-cache \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
tzdata \
|
tzdata \
|
||||||
tini \
|
tini \
|
||||||
bash \
|
bash \
|
||||||
curl \
|
curl \
|
||||||
shadow \
|
shadow \
|
||||||
su-exec \
|
su-exec \
|
||||||
openssl \
|
openssl \
|
||||||
openssl-dev \
|
openssl-dev \
|
||||||
openjdk21-jre \
|
openjdk21-jre \
|
||||||
# Doc conversion
|
# Doc conversion
|
||||||
gcompat \
|
libreoffice \
|
||||||
libc6-compat \
|
# pdftohtml
|
||||||
libreoffice \
|
poppler-utils \
|
||||||
# pdftohtml
|
# OCR MY PDF (unpaper for descew and other advanced featues)
|
||||||
poppler-utils \
|
qpdf \
|
||||||
# OCR MY PDF (unpaper for descew and other advanced featues)
|
tesseract-ocr-data-eng \
|
||||||
qpdf \
|
font-terminus font-dejavu font-noto font-noto-cjk font-awesome font-noto-extra \
|
||||||
tesseract-ocr-data-eng \
|
# CV
|
||||||
|
py3-opencv \
|
||||||
font-terminus font-dejavu font-noto font-noto-cjk font-awesome font-noto-extra font-liberation font-linux-libertine \
|
# python3/pip
|
||||||
# CV
|
python3 \
|
||||||
py3-opencv \
|
py3-pip && \
|
||||||
python3 \
|
# uno unoconv and HTML
|
||||||
py3-pip \
|
pip install --break-system-packages --no-cache-dir --upgrade unoconv WeasyPrint pdf2image pillow && \
|
||||||
py3-pillow@testing \
|
|
||||||
py3-pdf2image@testing && \
|
|
||||||
python3 -m venv /opt/venv && \
|
|
||||||
export PATH="/opt/venv/bin:$PATH" && \
|
|
||||||
pip install --upgrade pip && \
|
|
||||||
pip install --no-cache-dir --upgrade unoserver weasyprint && \
|
|
||||||
ln -s /usr/lib/libreoffice/program/uno.py /opt/venv/lib/python3.12/site-packages/ && \
|
|
||||||
ln -s /usr/lib/libreoffice/program/unohelper.py /opt/venv/lib/python3.12/site-packages/ && \
|
|
||||||
ln -s /usr/lib/libreoffice/program /opt/venv/lib/python3.12/site-packages/LibreOffice && \
|
|
||||||
mv /usr/share/tessdata /usr/share/tessdata-original && \
|
mv /usr/share/tessdata /usr/share/tessdata-original && \
|
||||||
mkdir -p $HOME /configs /logs /customFiles /pipeline/watchedFolders /pipeline/finishedFolders && \
|
mkdir -p $HOME /configs /logs /customFiles /pipeline/watchedFolders /pipeline/finishedFolders && \
|
||||||
fc-cache -f -v && \
|
fc-cache -f -v && \
|
||||||
chmod +x /scripts/* && \
|
chmod +x /scripts/* && \
|
||||||
chmod +x /scripts/init.sh && \
|
chmod +x /scripts/init.sh && \
|
||||||
# User permissions
|
# User permissions
|
||||||
addgroup -S stirlingpdfgroup && adduser -S stirlingpdfuser -G stirlingpdfgroup && \
|
addgroup -S stirlingpdfgroup && adduser -S stirlingpdfuser -G stirlingpdfgroup && \
|
||||||
chown -R stirlingpdfuser:stirlingpdfgroup $HOME /scripts /usr/share/fonts/opentype/noto /configs /customFiles /pipeline && \
|
chown -R stirlingpdfuser:stirlingpdfgroup $HOME /scripts /usr/share/fonts/opentype/noto /configs /customFiles /pipeline && \
|
||||||
chown stirlingpdfuser:stirlingpdfgroup /app.jar
|
chown stirlingpdfuser:stirlingpdfgroup /app.jar
|
||||||
|
|
||||||
EXPOSE 8080/tcp
|
EXPOSE 8080/tcp
|
||||||
|
|
||||||
# Set user and run command
|
# Set user and run command
|
||||||
ENTRYPOINT ["tini", "--", "/scripts/init.sh"]
|
ENTRYPOINT ["tini", "--", "/scripts/init.sh"]
|
||||||
CMD ["sh", "-c", "java -Dfile.encoding=UTF-8 -jar /app.jar & /opt/venv/bin/unoserver --port 2003 --interface 0.0.0.0"]
|
CMD ["java", "-Dfile.encoding=UTF-8", "-jar", "/app.jar"]
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# use alpine
|
# use alpine
|
||||||
FROM alpine:3.21.3@sha256:a8560b36e8b8210634f77d9f7f9efd7ffa463e380b75e2e74aff4511df3ef88c
|
FROM alpine:3.21.0@sha256:21dc6063fd678b478f57c0e13f47560d0ea4eeba26dfc947b2a4f81f686b9f45
|
||||||
|
|
||||||
ARG VERSION_TAG
|
ARG VERSION_TAG
|
||||||
|
|
||||||
@@ -7,13 +7,7 @@ ARG VERSION_TAG
|
|||||||
ENV DOCKER_ENABLE_SECURITY=false \
|
ENV DOCKER_ENABLE_SECURITY=false \
|
||||||
HOME=/home/stirlingpdfuser \
|
HOME=/home/stirlingpdfuser \
|
||||||
VERSION_TAG=$VERSION_TAG \
|
VERSION_TAG=$VERSION_TAG \
|
||||||
JAVA_TOOL_OPTIONS="-XX:+UnlockExperimentalVMOptions \
|
JAVA_TOOL_OPTIONS="$JAVA_TOOL_OPTIONS -XX:MaxRAMPercentage=75" \
|
||||||
-XX:MaxRAMPercentage=75 \
|
|
||||||
-XX:InitiatingHeapOccupancyPercent=20 \
|
|
||||||
-XX:+G1PeriodicGCInvokesConcurrent \
|
|
||||||
-XX:G1PeriodicGCInterval=10000 \
|
|
||||||
-XX:+UseStringDeduplication \
|
|
||||||
-XX:G1PeriodicGCSystemLoadThreshold=70" \
|
|
||||||
PUID=1000 \
|
PUID=1000 \
|
||||||
PGID=1000 \
|
PGID=1000 \
|
||||||
UMASK=022
|
UMASK=022
|
||||||
|
|||||||
@@ -11,12 +11,16 @@ Fork Stirling-PDF and create a new branch out of `main`.
|
|||||||
Then add a reference to the language in the navbar by adding a new language entry to the dropdown:
|
Then add a reference to the language in the navbar by adding a new language entry to the dropdown:
|
||||||
|
|
||||||
- Edit the file: [languages.html](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/src/main/resources/templates/fragments/languages.html)
|
- Edit the file: [languages.html](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/src/main/resources/templates/fragments/languages.html)
|
||||||
|
- Add a flag SVG file to: [flags directory](https://github.com/Stirling-Tools/Stirling-PDF/tree/main/src/main/resources/static/images/flags)
|
||||||
|
|
||||||
|
Any SVG flags are fine; most of the current ones were sourced from [here](https://flagicons.lipis.dev/). If your language isn't represented by a flag, choose a similar one, such as Saudi Arabia's flag for Arabic.
|
||||||
|
|
||||||
For example, to add Polish, you would add:
|
For example, to add Polish, you would add:
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<div th:replace="~{fragments/languageEntry :: languageEntry ('pl_PL', 'Polski')}" ></div>
|
<a class="dropdown-item lang_dropdown-item" href="" data-bs-language-code="pl_PL">
|
||||||
|
<img src="images/flags/pl.svg" alt="icon" width="20" height="15"> Polski
|
||||||
|
</a>
|
||||||
```
|
```
|
||||||
|
|
||||||
The `data-bs-language-code` is the code used to reference the file in the next step.
|
The `data-bs-language-code` is the code used to reference the file in the next step.
|
||||||
@@ -56,13 +60,3 @@ ignore = [
|
|||||||
- After adding the new tags to `messages_en_GB.properties`, add and translate them in the respective language file (e.g., `messages_pl_PL.properties`).
|
- After adding the new tags to `messages_en_GB.properties`, add and translate them in the respective language file (e.g., `messages_pl_PL.properties`).
|
||||||
|
|
||||||
Make sure to place the entry under the correct language section. This helps maintain the accuracy of translation progress statistics and ensures that the translation tool or scripts do not misinterpret the completion rate.
|
Make sure to place the entry under the correct language section. This helps maintain the accuracy of translation progress statistics and ensures that the translation tool or scripts do not misinterpret the completion rate.
|
||||||
|
|
||||||
### Use this code to perform a local check
|
|
||||||
|
|
||||||
#### Windows command
|
|
||||||
|
|
||||||
```ps
|
|
||||||
python .github/scripts/check_language_properties.py --reference-file src\main\resources\messages_en_GB.properties --branch "" --files src\main\resources\messages_pl_PL.properties
|
|
||||||
|
|
||||||
python .github/scripts/check_language_properties.py --reference-file src\main\resources\messages_en_GB.properties --branch "" --check-file src\main\resources\messages_pl_PL.properties
|
|
||||||
```
|
|
||||||
|
|||||||
70
README.md
70
README.md
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
[](https://hub.docker.com/r/frooodle/s-pdf)
|
[](https://hub.docker.com/r/frooodle/s-pdf)
|
||||||
[](https://discord.gg/HYmhKj45pU)
|
[](https://discord.gg/HYmhKj45pU)
|
||||||
|
[](https://github.com/Stirling-Tools/Stirling-PDF/)
|
||||||
[](https://scorecard.dev/viewer/?uri=github.com/Stirling-Tools/Stirling-PDF)
|
[](https://scorecard.dev/viewer/?uri=github.com/Stirling-Tools/Stirling-PDF)
|
||||||
[](https://github.com/Stirling-Tools/stirling-pdf)
|
[](https://github.com/Stirling-Tools/stirling-pdf)
|
||||||
|
|
||||||
@@ -13,9 +14,8 @@
|
|||||||
|
|
||||||
All files and PDFs exist either exclusively on the client side, reside in server memory only during task execution, or temporarily reside in a file solely for the execution of the task. Any file downloaded by the user will have been deleted from the server by that point.
|
All files and PDFs exist either exclusively on the client side, reside in server memory only during task execution, or temporarily reside in a file solely for the execution of the task. Any file downloaded by the user will have been deleted from the server by that point.
|
||||||
|
|
||||||
Homepage: [https://stirlingpdf.com](https://stirlingpdf.com)
|
|
||||||
|
|
||||||
All documentation available at [https://docs.stirlingpdf.com/](https://docs.stirlingpdf.com/)
|
All information available at [https://docs.stirlingpdf.com/](https://docs.stirlingpdf.com/)
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@@ -112,50 +112,48 @@ Visit our comprehensive documentation at [docs.stirlingpdf.com](https://docs.sti
|
|||||||
|
|
||||||
## Supported Languages
|
## Supported Languages
|
||||||
|
|
||||||
Stirling-PDF currently supports 39 languages!
|
Stirling-PDF currently supports 38 languages!
|
||||||
|
|
||||||
| Language | Progress |
|
| Language | Progress |
|
||||||
| -------------------------------------------- | -------------------------------------- |
|
| -------------------------------------------- | -------------------------------------- |
|
||||||
| Arabic (العربية) (ar_AR) |  |
|
| Arabic (العربية) (ar_AR) |  |
|
||||||
| Azerbaijani (Azərbaycan Dili) (az_AZ) |  |
|
| Azerbaijani (Azərbaycan Dili) (az_AZ) |  |
|
||||||
| Basque (Euskara) (eu_ES) |  |
|
| Basque (Euskara) (eu_ES) |  |
|
||||||
| Bulgarian (Български) (bg_BG) |  |
|
| Bulgarian (Български) (bg_BG) |  |
|
||||||
| Catalan (Català) (ca_CA) |  |
|
| Catalan (Català) (ca_CA) |  |
|
||||||
| Croatian (Hrvatski) (hr_HR) |  |
|
| Croatian (Hrvatski) (hr_HR) |  |
|
||||||
| Czech (Česky) (cs_CZ) |  |
|
| Czech (Česky) (cs_CZ) |  |
|
||||||
| Danish (Dansk) (da_DK) |  |
|
| Danish (Dansk) (da_DK) |  |
|
||||||
| Dutch (Nederlands) (nl_NL) |  |
|
| Dutch (Nederlands) (nl_NL) |  |
|
||||||
| English (English) (en_GB) |  |
|
| English (English) (en_GB) |  |
|
||||||
| English (US) (en_US) |  |
|
| English (US) (en_US) |  |
|
||||||
| French (Français) (fr_FR) |  |
|
| French (Français) (fr_FR) |  |
|
||||||
| German (Deutsch) (de_DE) |  |
|
| German (Deutsch) (de_DE) |  |
|
||||||
| Greek (Ελληνικά) (el_GR) |  |
|
| Greek (Ελληνικά) (el_GR) |  |
|
||||||
| Hindi (हिंदी) (hi_IN) |  |
|
| Hindi (हिंदी) (hi_IN) |  |
|
||||||
| Hungarian (Magyar) (hu_HU) |  |
|
| Hungarian (Magyar) (hu_HU) |  |
|
||||||
| Indonesian (Bahasa Indonesia) (id_ID) |  |
|
| Indonesian (Bahasa Indonesia) (id_ID) |  |
|
||||||
| Irish (Gaeilge) (ga_IE) |  |
|
| Irish (Gaeilge) (ga_IE) |  |
|
||||||
| Italian (Italiano) (it_IT) |  |
|
| Italian (Italiano) (it_IT) |  |
|
||||||
| Japanese (日本語) (ja_JP) |  |
|
| Japanese (日本語) (ja_JP) |  |
|
||||||
| Korean (한국어) (ko_KR) |  |
|
| Korean (한국어) (ko_KR) |  |
|
||||||
| Norwegian (Norsk) (no_NB) |  |
|
| Norwegian (Norsk) (no_NB) |  |
|
||||||
| Persian (فارسی) (fa_IR) |  |
|
| Persian (فارسی) (fa_IR) |  |
|
||||||
| Polish (Polski) (pl_PL) |  |
|
| Polish (Polski) (pl_PL) |  |
|
||||||
| Portuguese (Português) (pt_PT) |  |
|
| Portuguese (Português) (pt_PT) |  |
|
||||||
| Portuguese Brazilian (Português) (pt_BR) |  |
|
| Portuguese Brazilian (Português) (pt_BR) |  |
|
||||||
| Romanian (Română) (ro_RO) |  |
|
| Romanian (Română) (ro_RO) |  |
|
||||||
| Russian (Русский) (ru_RU) |  |
|
| Russian (Русский) (ru_RU) |  |
|
||||||
| Serbian Latin alphabet (Srpski) (sr_LATN_RS) |  |
|
| Serbian Latin alphabet (Srpski) (sr_LATN_RS) |  |
|
||||||
| Simplified Chinese (简体中文) (zh_CN) |  |
|
| Simplified Chinese (简体中文) (zh_CN) |  |
|
||||||
| Slovakian (Slovensky) (sk_SK) |  |
|
| Slovakian (Slovensky) (sk_SK) |  |
|
||||||
| Slovenian (Slovenščina) (sl_SI) |  |
|
| Spanish (Español) (es_ES) |  |
|
||||||
| Spanish (Español) (es_ES) |  |
|
| Swedish (Svenska) (sv_SE) |  |
|
||||||
| Swedish (Svenska) (sv_SE) |  |
|
| Thai (ไทย) (th_TH) |  |
|
||||||
| Thai (ไทย) (th_TH) |  |
|
|
||||||
| Tibetan (བོད་ཡིག་) (zh_BO) |  |
|
|
||||||
| Traditional Chinese (繁體中文) (zh_TW) |  |
|
| Traditional Chinese (繁體中文) (zh_TW) |  |
|
||||||
| Turkish (Türkçe) (tr_TR) |  |
|
| Turkish (Türkçe) (tr_TR) |  |
|
||||||
| Ukrainian (Українська) (uk_UA) |  |
|
| Ukrainian (Українська) (uk_UA) |  |
|
||||||
| Vietnamese (Tiếng Việt) (vi_VN) |  |
|
| Vietnamese (Tiếng Việt) (vi_VN) |  |
|
||||||
|
|
||||||
|
|
||||||
## Stirling PDF Enterprise
|
## Stirling PDF Enterprise
|
||||||
|
|||||||
45
USERS.md
45
USERS.md
@@ -1,45 +0,0 @@
|
|||||||
# Who is using Stirling-PDF?
|
|
||||||
|
|
||||||
Understanding the diverse applications of Stirling-PDF can be an invaluable resource for collaboration and learning. This page provides a directory of users and use cases. If you are using Stirling-PDF, consider sharing your experiences to help others and foster a community of best practices.
|
|
||||||
|
|
||||||
## Adding Yourself as a User
|
|
||||||
|
|
||||||
If you're using Stirling-PDF or have integrated it into your platform or workflow, please consider contributing to this list by describing your use case. You can do this by opening a pull request to this file and adding your details in the format below:
|
|
||||||
|
|
||||||
- **N**: Name of the organization or individual.
|
|
||||||
- **D**: A brief description of your usage.
|
|
||||||
- **U**: Specific features or capabilities utilized.
|
|
||||||
- **L**: Optional link for further information (e.g., website, blog post).
|
|
||||||
- **Q**: Contact information for sharing insights (optional).
|
|
||||||
|
|
||||||
Example entry:
|
|
||||||
|
|
||||||
```
|
|
||||||
* N: Example Corp
|
|
||||||
D: Using Stirling-PDF for automated document processing in our SaaS platform focusing on compression.
|
|
||||||
U: OCR, merging PDFs, metadata editing, encryption, compression.
|
|
||||||
L: https://example.com/stirling-pdf
|
|
||||||
Q: @example-user on Discord/email
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Requirements for Listing
|
|
||||||
|
|
||||||
- You must represent the entity you're listing and ensure the details are accurate.
|
|
||||||
- Trial deployments are welcome if they represent a realistic evaluation of Stirling-PDF in action.
|
|
||||||
- Community contributions, including home-lab setups or non-commercial uses, are encouraged.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Users (Alphabetically)
|
|
||||||
|
|
||||||
* N:
|
|
||||||
D:
|
|
||||||
U:
|
|
||||||
L:
|
|
||||||
|
|
||||||
* N:
|
|
||||||
D:
|
|
||||||
U:
|
|
||||||
L:
|
|
||||||
@@ -1,164 +0,0 @@
|
|||||||
{
|
|
||||||
"allowedLicenses": [
|
|
||||||
{
|
|
||||||
"moduleName": ".*",
|
|
||||||
"moduleLicense": "BSD License"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": ".*",
|
|
||||||
"moduleLicense": "The BSD License"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": ".*",
|
|
||||||
"moduleLicense": "BSD-2-Clause"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": ".*",
|
|
||||||
"moduleLicense": "BSD 2-Clause License"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": ".*",
|
|
||||||
"moduleLicense": "The 2-Clause BSD License"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": ".*",
|
|
||||||
"moduleLicense": "BSD-3-Clause"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": ".*",
|
|
||||||
"moduleLicense": "The BSD 3-Clause License (BSD3)"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": ".*",
|
|
||||||
"moduleLicense": "BSD-4 License"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": ".*",
|
|
||||||
"moduleLicense": "MIT"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": ".*",
|
|
||||||
"moduleLicense": "MIT License"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": ".*",
|
|
||||||
"moduleLicense": "The MIT License"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": "com.github.jai-imageio:jai-imageio-core",
|
|
||||||
"moduleLicense": "LICENSE.txt"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": "com.github.jai-imageio:jai-imageio-jpeg2000",
|
|
||||||
"moduleLicense": "LICENSE-JJ2000.txt, LICENSE-Sun.txt"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": ".*",
|
|
||||||
"moduleLicense": "Apache 2"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": ".*",
|
|
||||||
"moduleLicense": "Apache 2.0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": ".*",
|
|
||||||
"moduleLicense": "Apache-2.0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": ".*",
|
|
||||||
"moduleLicense": "Apache-2.0 License"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": ".*",
|
|
||||||
"moduleLicense": "Apache License 2.0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": ".*",
|
|
||||||
"moduleLicense": "Apache License Version 2.0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": ".*",
|
|
||||||
"moduleLicense": "Apache License, Version 2.0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": ".*",
|
|
||||||
"moduleLicense": "The Apache License, Version 2.0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": ".*",
|
|
||||||
"moduleLicense": "The Apache Software License, Version 2.0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": "com.nimbusds:oauth2-oidc-sdk",
|
|
||||||
"moduleLicense": "\"Apache License, version 2.0\";link=\"https://www.apache.org/licenses/LICENSE-2.0.html\""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": ".*",
|
|
||||||
"moduleLicense": "MPL 2.0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": ".*",
|
|
||||||
"moduleLicense": "UnboundID SCIM2 SDK Free Use License"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": ".*",
|
|
||||||
"moduleLicense": "GPL2 w/ CPE"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": ".*",
|
|
||||||
"moduleLicense": "GPLv2+CE"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": ".*",
|
|
||||||
"moduleLicense": "GNU GENERAL PUBLIC LICENSE, Version 2 + Classpath Exception"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": "com.martiansoftware:jsap",
|
|
||||||
"moduleLicense": "LGPL"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": "org.hibernate.orm:hibernate-core",
|
|
||||||
"moduleLicense": "GNU Library General Public License v2.1 or later"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": ".*",
|
|
||||||
"moduleLicense": "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": ".*",
|
|
||||||
"moduleLicense": "Eclipse Public License - v 1.0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": ".*",
|
|
||||||
"moduleLicense": "Eclipse Public License v. 2.0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": ".*",
|
|
||||||
"moduleLicense": "Eclipse Public License - v 2.0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": ".*",
|
|
||||||
"moduleLicense": "Eclipse Public License - Version 2.0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": ".*",
|
|
||||||
"moduleLicense": "Eclipse Public License, Version 2.0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": ".*",
|
|
||||||
"moduleLicense": "Ubuntu Font Licence 1.0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": ".*",
|
|
||||||
"moduleLicense": "Bouncy Castle Licence"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": ".*",
|
|
||||||
"moduleLicense": "Public Domain, per Creative Commons CC0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"moduleName": ".*",
|
|
||||||
"moduleLicense": "The W3C License"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
183
build.gradle
183
build.gradle
@@ -1,31 +1,34 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id "java"
|
id "java"
|
||||||
id "org.springframework.boot" version "3.4.3"
|
id "org.springframework.boot" version "3.4.1"
|
||||||
id "io.spring.dependency-management" version "1.1.7"
|
id "io.spring.dependency-management" version "1.1.7"
|
||||||
id "org.springdoc.openapi-gradle-plugin" version "1.8.0"
|
id "org.springdoc.openapi-gradle-plugin" version "1.8.0"
|
||||||
id "io.swagger.swaggerhub" version "1.3.2"
|
id "io.swagger.swaggerhub" version "1.3.2"
|
||||||
id "edu.sc.seis.launch4j" version "3.0.6"
|
id "edu.sc.seis.launch4j" version "3.0.6"
|
||||||
id "com.diffplug.spotless" version "7.0.2"
|
id "com.diffplug.spotless" version "6.25.0"
|
||||||
id "com.github.jk1.dependency-license-report" version "2.9"
|
id "com.github.jk1.dependency-license-report" version "2.9"
|
||||||
//id "nebula.lint" version "19.0.3"
|
//id "nebula.lint" version "19.0.3"
|
||||||
id("org.panteleyev.jpackageplugin") version "1.6.1"
|
id("org.panteleyev.jpackageplugin") version "1.6.0"
|
||||||
id "org.sonarqube" version "6.0.1.5171"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import com.github.jk1.license.render.*
|
import com.github.jk1.license.render.*
|
||||||
|
|
||||||
ext {
|
ext {
|
||||||
springBootVersion = "3.4.3"
|
springBootVersion = "3.4.1"
|
||||||
pdfboxVersion = "3.0.4"
|
pdfboxVersion = "3.0.3"
|
||||||
|
logbackVersion = "1.5.7"
|
||||||
imageioVersion = "3.12.0"
|
imageioVersion = "3.12.0"
|
||||||
lombokVersion = "1.18.36"
|
lombokVersion = "1.18.36"
|
||||||
bouncycastleVersion = "1.80"
|
bouncycastleVersion = "1.79"
|
||||||
springSecuritySamlVersion = "6.4.3"
|
springSecuritySamlVersion = "6.4.2"
|
||||||
openSamlVersion = "4.3.2"
|
openSamlVersion = "4.3.2"
|
||||||
}
|
}
|
||||||
|
|
||||||
group = "stirling.software"
|
group = "stirling.software"
|
||||||
version = "0.43.1"
|
version = "0.36.6"
|
||||||
|
|
||||||
|
|
||||||
java {
|
java {
|
||||||
// 17 is lowest but we support and recommend 21
|
// 17 is lowest but we support and recommend 21
|
||||||
@@ -34,13 +37,14 @@ java {
|
|||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
maven { url = "https://build.shibboleth.net/maven/releases" }
|
maven { url "https://jitpack.io" }
|
||||||
maven { url = "https://maven.pkg.github.com/jcefmaven/jcefmaven" }
|
maven { url "https://build.shibboleth.net/maven/releases" }
|
||||||
|
maven { url "https://maven.pkg.github.com/jcefmaven/jcefmaven" }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
licenseReport {
|
licenseReport {
|
||||||
renderers = [new JsonReportRenderer()]
|
renderers = [new JsonReportRenderer()]
|
||||||
allowedLicensesFile = new File("$projectDir/allowed-licenses.json")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
@@ -48,15 +52,13 @@ sourceSets {
|
|||||||
java {
|
java {
|
||||||
if (System.getenv("DOCKER_ENABLE_SECURITY") == "false") {
|
if (System.getenv("DOCKER_ENABLE_SECURITY") == "false") {
|
||||||
exclude "stirling/software/SPDF/config/security/**"
|
exclude "stirling/software/SPDF/config/security/**"
|
||||||
exclude "stirling/software/SPDF/controller/api/DatabaseController.java"
|
|
||||||
exclude "stirling/software/SPDF/controller/api/UserController.java"
|
exclude "stirling/software/SPDF/controller/api/UserController.java"
|
||||||
exclude "stirling/software/SPDF/controller/api/H2SQLCondition.java"
|
exclude "stirling/software/SPDF/controller/api/DatabaseController.java"
|
||||||
exclude "stirling/software/SPDF/controller/web/AccountWebController.java"
|
exclude "stirling/software/SPDF/controller/web/AccountWebController.java"
|
||||||
exclude "stirling/software/SPDF/controller/web/DatabaseWebController.java"
|
exclude "stirling/software/SPDF/controller/web/DatabaseWebController.java"
|
||||||
exclude "stirling/software/SPDF/model/ApiKeyAuthenticationToken.java"
|
exclude "stirling/software/SPDF/model/ApiKeyAuthenticationToken.java"
|
||||||
exclude "stirling/software/SPDF/model/AttemptCounter.java"
|
exclude "stirling/software/SPDF/model/AttemptCounter.java"
|
||||||
exclude "stirling/software/SPDF/model/Authority.java"
|
exclude "stirling/software/SPDF/model/Authority.java"
|
||||||
exclude "stirling/software/SPDF/model/BackupNotFoundException.java"
|
|
||||||
exclude "stirling/software/SPDF/model/PersistentLogin.java"
|
exclude "stirling/software/SPDF/model/PersistentLogin.java"
|
||||||
exclude "stirling/software/SPDF/model/SessionEntity.java"
|
exclude "stirling/software/SPDF/model/SessionEntity.java"
|
||||||
exclude "stirling/software/SPDF/model/User.java"
|
exclude "stirling/software/SPDF/model/User.java"
|
||||||
@@ -64,32 +66,10 @@ sourceSets {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (System.getenv("STIRLING_PDF_DESKTOP_UI") == "false") {
|
if (System.getenv("STIRLING_PDF_DESKTOP_UI") == "false") {
|
||||||
exclude "stirling/software/SPDF/UI/impl/**"
|
exclude "stirling/software/SPDF/UI/impl/**"
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
test {
|
|
||||||
java {
|
|
||||||
if (System.getenv("DOCKER_ENABLE_SECURITY") == "false") {
|
|
||||||
exclude "stirling/software/SPDF/config/security/**"
|
|
||||||
exclude "stirling/software/SPDF/controller/api/UserControllerTest.java"
|
|
||||||
exclude "stirling/software/SPDF/controller/api/DatabaseControllerTest.java"
|
|
||||||
exclude "stirling/software/SPDF/controller/web/AccountWebControllerTest.java"
|
|
||||||
exclude "stirling/software/SPDF/controller/web/DatabaseWebControllerTest.java"
|
|
||||||
exclude "stirling/software/SPDF/model/ApiKeyAuthenticationTokenTest.java"
|
|
||||||
exclude "stirling/software/SPDF/model/AttemptCounterTest.java"
|
|
||||||
exclude "stirling/software/SPDF/model/AuthorityTest.java"
|
|
||||||
exclude "stirling/software/SPDF/model/PersistentLoginTest.java"
|
|
||||||
exclude "stirling/software/SPDF/model/SessionEntityTest.java"
|
|
||||||
exclude "stirling/software/SPDF/model/UserTest.java"
|
|
||||||
exclude "stirling/software/SPDF/repository/**"
|
|
||||||
}
|
|
||||||
|
|
||||||
if (System.getenv("STIRLING_PDF_DESKTOP_UI") == "false") {
|
|
||||||
exclude "stirling/software/SPDF/UI/impl/**"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -109,15 +89,18 @@ def getMacVersion(String version) {
|
|||||||
|
|
||||||
jpackage {
|
jpackage {
|
||||||
input = "build/libs"
|
input = "build/libs"
|
||||||
destination = "${projectDir}/build/jpackage"
|
|
||||||
mainJar = "Stirling-PDF-${project.version}.jar"
|
|
||||||
appName = "Stirling-PDF"
|
appName = "Stirling-PDF"
|
||||||
appVersion = project.version
|
appVersion = project.version
|
||||||
vendor = "Stirling-Software"
|
vendor = "Stirling-Software"
|
||||||
appDescription = "Stirling PDF - Your Local PDF Editor"
|
appDescription = "Stirling PDF - Your Local PDF Editor"
|
||||||
|
|
||||||
|
mainJar = "Stirling-PDF-${project.version}.jar"
|
||||||
|
mainClass = "org.springframework.boot.loader.launch.JarLauncher"
|
||||||
|
|
||||||
icon = "src/main/resources/static/favicon.ico"
|
icon = "src/main/resources/static/favicon.ico"
|
||||||
verbose = true
|
|
||||||
// mainClass = "org.springframework.boot.loader.launch.JarLauncher"
|
|
||||||
|
|
||||||
// JVM Options
|
// JVM Options
|
||||||
javaOptions = [
|
javaOptions = [
|
||||||
@@ -125,21 +108,23 @@ jpackage {
|
|||||||
"-DSTIRLING_PDF_DESKTOP_UI=true",
|
"-DSTIRLING_PDF_DESKTOP_UI=true",
|
||||||
"-Djava.awt.headless=false",
|
"-Djava.awt.headless=false",
|
||||||
"-Dapple.awt.UIElement=true",
|
"-Dapple.awt.UIElement=true",
|
||||||
"--add-opens=java.base/java.lang=ALL-UNNAMED",
|
"--add-opens", "java.base/java.lang=ALL-UNNAMED",
|
||||||
"--add-opens=java.desktop/java.awt.event=ALL-UNNAMED",
|
"--add-opens", "java.desktop/java.awt.event=ALL-UNNAMED",
|
||||||
"--add-opens=java.desktop/sun.awt=ALL-UNNAMED",
|
"--add-opens", "java.desktop/sun.awt=ALL-UNNAMED"
|
||||||
"--add-opens=java.desktop/sun.awt.X11=ALL-UNNAMED",
|
|
||||||
"--add-opens=java.desktop/sun.awt.windows=ALL-UNNAMED",
|
|
||||||
"--add-opens=java.desktop/sun.lwawt=ALL-UNNAMED",
|
|
||||||
"--add-opens=java.desktop/sun.lwawt.macosx=ALL-UNNAMED",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
verbose = true
|
||||||
|
|
||||||
|
destination = "${projectDir}/build/jpackage"
|
||||||
|
|
||||||
// Windows-specific configuration
|
// Windows-specific configuration
|
||||||
windows {
|
windows {
|
||||||
launcherAsService = false
|
launcherAsService = false
|
||||||
appVersion = project.version
|
appVersion = project.version
|
||||||
|
|
||||||
winConsole = false
|
winConsole = false
|
||||||
winMenu = true // Creates start menu entry
|
winMenu = true // Creates start menu entry
|
||||||
winShortcut = true // Creates desktop shortcut
|
winShortcut = true // Creates desktop shortcut
|
||||||
winShortcutPrompt = true // Lets user choose whether to create shortcuts
|
winShortcutPrompt = true // Lets user choose whether to create shortcuts
|
||||||
@@ -155,7 +140,7 @@ jpackage {
|
|||||||
|
|
||||||
// macOS-specific configuration
|
// macOS-specific configuration
|
||||||
mac {
|
mac {
|
||||||
appVersion = getMacVersion(project.version.toString())
|
appVersion = getMacVersion(project.version.toString())
|
||||||
icon = "src/main/resources/static/favicon.icns"
|
icon = "src/main/resources/static/favicon.icns"
|
||||||
type = "dmg"
|
type = "dmg"
|
||||||
macPackageIdentifier = "com.stirling.software.pdf"
|
macPackageIdentifier = "com.stirling.software.pdf"
|
||||||
@@ -179,7 +164,7 @@ jpackage {
|
|||||||
|
|
||||||
// Linux-specific configuration
|
// Linux-specific configuration
|
||||||
linux {
|
linux {
|
||||||
appVersion = project.version
|
appVersion = project.version
|
||||||
icon = "src/main/resources/static/favicon.png"
|
icon = "src/main/resources/static/favicon.png"
|
||||||
type = "deb" // Can also use "rpm" for Red Hat-based systems
|
type = "deb" // Can also use "rpm" for Red Hat-based systems
|
||||||
|
|
||||||
@@ -227,9 +212,9 @@ launch4j {
|
|||||||
outfile="Stirling-PDF.exe"
|
outfile="Stirling-PDF.exe"
|
||||||
|
|
||||||
if(System.getenv("STIRLING_PDF_DESKTOP_UI") == 'true') {
|
if(System.getenv("STIRLING_PDF_DESKTOP_UI") == 'true') {
|
||||||
headerType = "gui"
|
headerType = "gui"
|
||||||
} else {
|
} else {
|
||||||
headerType = "console"
|
headerType = "console"
|
||||||
}
|
}
|
||||||
jarTask = tasks.bootJar
|
jarTask = tasks.bootJar
|
||||||
|
|
||||||
@@ -237,11 +222,13 @@ launch4j {
|
|||||||
downloadUrl="https://download.oracle.com/java/21/latest/jdk-21_windows-x64_bin.exe"
|
downloadUrl="https://download.oracle.com/java/21/latest/jdk-21_windows-x64_bin.exe"
|
||||||
|
|
||||||
if(System.getenv("STIRLING_PDF_DESKTOP_UI") == 'true') {
|
if(System.getenv("STIRLING_PDF_DESKTOP_UI") == 'true') {
|
||||||
variables=["BROWSER_OPEN=true", "STIRLING_PDF_DESKTOP_UI=true"]
|
variables=["BROWSER_OPEN=true", "STIRLING_PDF_DESKTOP_UI=true"]
|
||||||
} else {
|
} else {
|
||||||
variables=["BROWSER_OPEN=true"]
|
variables=["BROWSER_OPEN=true"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
jreMinVersion="17"
|
jreMinVersion="17"
|
||||||
|
|
||||||
mutexName="Stirling-PDF"
|
mutexName="Stirling-PDF"
|
||||||
@@ -260,25 +247,14 @@ spotless {
|
|||||||
|
|
||||||
googleJavaFormat("1.25.2").aosp().reorderImports(false)
|
googleJavaFormat("1.25.2").aosp().reorderImports(false)
|
||||||
|
|
||||||
importOrder("java", "javax", "org", "com", "net", "io", "jakarta", "lombok", "me", "stirling")
|
importOrder("java", "javax", "org", "com", "net", "io")
|
||||||
toggleOffOn()
|
toggleOffOn()
|
||||||
trimTrailingWhitespace()
|
trimTrailingWhitespace()
|
||||||
leadingTabsToSpaces()
|
indentWithSpaces()
|
||||||
endWithNewline()
|
endWithNewline()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sonar {
|
|
||||||
properties {
|
|
||||||
property "sonar.projectKey", "Stirling-Tools_Stirling-PDF"
|
|
||||||
property "sonar.organization", "stirling-tools"
|
|
||||||
|
|
||||||
property "sonar.exclusions", "**/build-wrapper-dump.json, src/main/java/org/apache/**, src/main/resources/static/pdfjs/**, src/main/resources/static/pdfjs-legacy/**, src/main/resources/static/js/thirdParty/**"
|
|
||||||
property "sonar.coverage.exclusions", "src/main/java/org/apache/**, src/main/resources/static/pdfjs/**, src/main/resources/static/pdfjs-legacy/**, src/main/resources/static/js/thirdParty/**"
|
|
||||||
property "sonar.cpd.exclusions", "src/main/java/org/apache/**, src/main/resources/static/pdfjs/**, src/main/resources/static/pdfjs-legacy/**, src/main/resources/static/js/thirdParty/**"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//gradleLint {
|
//gradleLint {
|
||||||
// rules=['unused-dependency']
|
// rules=['unused-dependency']
|
||||||
// }
|
// }
|
||||||
@@ -293,35 +269,26 @@ configurations.all {
|
|||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
|
|
||||||
//tmp for security bumps
|
if (System.getenv("STIRLING_PDF_DESKTOP_UI") != "false") {
|
||||||
implementation 'ch.qos.logback:logback-core:1.5.17'
|
implementation "me.friwi:jcefmaven:127.3.1"
|
||||||
implementation 'ch.qos.logback:logback-classic:1.5.17'
|
implementation "org.openjfx:javafx-controls:21"
|
||||||
|
implementation "org.openjfx:javafx-swing:21"
|
||||||
|
|
||||||
// Exclude vulnerable BouncyCastle version used in tableau
|
|
||||||
configurations.all {
|
|
||||||
exclude group: 'org.bouncycastle', module: 'bcpkix-jdk15on'
|
|
||||||
exclude group: 'org.bouncycastle', module: 'bcutil-jdk15on'
|
|
||||||
exclude group: 'org.bouncycastle', module: 'bcmail-jdk15on'
|
|
||||||
}
|
|
||||||
|
|
||||||
if (System.getenv("STIRLING_PDF_DESKTOP_UI") != "false") {
|
|
||||||
implementation "me.friwi:jcefmaven:132.3.1"
|
|
||||||
implementation "org.openjfx:javafx-controls:21"
|
|
||||||
implementation "org.openjfx:javafx-swing:21"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//security updates
|
//security updates
|
||||||
implementation "org.springframework:spring-webmvc:6.2.3"
|
implementation "org.springframework:spring-webmvc:6.2.1"
|
||||||
|
|
||||||
implementation("io.github.pixee:java-security-toolkit:1.2.1")
|
implementation("io.github.pixee:java-security-toolkit:1.2.1")
|
||||||
|
|
||||||
|
// implementation "org.yaml:snakeyaml:2.2"
|
||||||
|
implementation 'com.github.Carleslc.Simple-YAML:Simple-Yaml:1.8.4'
|
||||||
|
|
||||||
// Exclude Tomcat and include Jetty
|
// Exclude Tomcat and include Jetty
|
||||||
implementation("org.springframework.boot:spring-boot-starter-web:$springBootVersion")
|
implementation("org.springframework.boot:spring-boot-starter-web:$springBootVersion")
|
||||||
implementation "org.springframework.boot:spring-boot-starter-jetty:$springBootVersion"
|
implementation "org.springframework.boot:spring-boot-starter-jetty:$springBootVersion"
|
||||||
|
|
||||||
implementation "org.springframework.boot:spring-boot-starter-thymeleaf:$springBootVersion"
|
implementation "org.springframework.boot:spring-boot-starter-thymeleaf:$springBootVersion"
|
||||||
implementation 'com.posthog.java:posthog:1.2.0'
|
implementation 'com.posthog.java:posthog:1.1.1'
|
||||||
implementation 'com.googlecode.owasp-java-html-sanitizer:owasp-java-html-sanitizer:20240325.1'
|
implementation 'com.googlecode.owasp-java-html-sanitizer:owasp-java-html-sanitizer:20240325.1'
|
||||||
|
|
||||||
|
|
||||||
@@ -331,24 +298,22 @@ dependencies {
|
|||||||
implementation "org.springframework.boot:spring-boot-starter-data-jpa:$springBootVersion"
|
implementation "org.springframework.boot:spring-boot-starter-data-jpa:$springBootVersion"
|
||||||
implementation "org.springframework.boot:spring-boot-starter-oauth2-client:$springBootVersion"
|
implementation "org.springframework.boot:spring-boot-starter-oauth2-client:$springBootVersion"
|
||||||
|
|
||||||
implementation "org.springframework.session:spring-session-core:3.4.2"
|
implementation "org.springframework.session:spring-session-core:$springBootVersion"
|
||||||
implementation "org.springframework:spring-jdbc:6.2.3"
|
|
||||||
|
|
||||||
implementation 'com.unboundid.product.scim2:scim2-sdk-client:2.3.5'
|
implementation 'com.unboundid.product.scim2:scim2-sdk-client:2.3.5'
|
||||||
// Don't upgrade h2database
|
// Don't upgrade h2database
|
||||||
runtimeOnly "com.h2database:h2:2.3.232"
|
runtimeOnly "com.h2database:h2:2.3.232"
|
||||||
runtimeOnly "org.postgresql:postgresql:42.7.5"
|
|
||||||
constraints {
|
constraints {
|
||||||
implementation "org.opensaml:opensaml-core:$openSamlVersion"
|
implementation "org.opensaml:opensaml-core:$openSamlVersion"
|
||||||
implementation "org.opensaml:opensaml-saml-api:$openSamlVersion"
|
implementation "org.opensaml:opensaml-saml-api:$openSamlVersion"
|
||||||
implementation "org.opensaml:opensaml-saml-impl:$openSamlVersion"
|
implementation "org.opensaml:opensaml-saml-impl:$openSamlVersion"
|
||||||
}
|
}
|
||||||
implementation "org.springframework.security:spring-security-saml2-service-provider:$springSecuritySamlVersion"
|
implementation "org.springframework.security:spring-security-saml2-service-provider:$springSecuritySamlVersion"
|
||||||
// implementation 'org.springframework.security:spring-security-core:$springSecuritySamlVersion'
|
// implementation 'org.springframework.security:spring-security-core:$springSecuritySamlVersion'
|
||||||
implementation 'com.coveo:saml-client:5.0.0'
|
implementation 'com.coveo:saml-client:5.0.0'
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
implementation 'org.snakeyaml:snakeyaml-engine:2.9'
|
|
||||||
|
|
||||||
testImplementation "org.springframework.boot:spring-boot-starter-test:$springBootVersion"
|
testImplementation "org.springframework.boot:spring-boot-starter-test:$springBootVersion"
|
||||||
|
|
||||||
@@ -381,15 +346,13 @@ dependencies {
|
|||||||
//general PDF
|
//general PDF
|
||||||
|
|
||||||
// https://mvnrepository.com/artifact/com.opencsv/opencsv
|
// https://mvnrepository.com/artifact/com.opencsv/opencsv
|
||||||
implementation ("com.opencsv:opencsv:5.10") {
|
implementation ("com.opencsv:opencsv:5.9") {
|
||||||
exclude group: "commons-logging", module: "commons-logging"
|
exclude group: "commons-logging", module: "commons-logging"
|
||||||
}
|
}
|
||||||
|
|
||||||
implementation ("org.apache.pdfbox:pdfbox:$pdfboxVersion") {
|
implementation ("org.apache.pdfbox:pdfbox:$pdfboxVersion") {
|
||||||
exclude group: "commons-logging", module: "commons-logging"
|
exclude group: "commons-logging", module: "commons-logging"
|
||||||
}
|
}
|
||||||
implementation "org.apache.pdfbox:preflight:$pdfboxVersion"
|
|
||||||
|
|
||||||
|
|
||||||
implementation ("org.apache.pdfbox:xmpbox:$pdfboxVersion") {
|
implementation ("org.apache.pdfbox:xmpbox:$pdfboxVersion") {
|
||||||
exclude group: "commons-logging", module: "commons-logging"
|
exclude group: "commons-logging", module: "commons-logging"
|
||||||
@@ -407,7 +370,7 @@ dependencies {
|
|||||||
implementation "org.bouncycastle:bcprov-jdk18on:$bouncycastleVersion"
|
implementation "org.bouncycastle:bcprov-jdk18on:$bouncycastleVersion"
|
||||||
implementation "org.bouncycastle:bcpkix-jdk18on:$bouncycastleVersion"
|
implementation "org.bouncycastle:bcpkix-jdk18on:$bouncycastleVersion"
|
||||||
implementation "org.springframework.boot:spring-boot-starter-actuator:$springBootVersion"
|
implementation "org.springframework.boot:spring-boot-starter-actuator:$springBootVersion"
|
||||||
implementation "io.micrometer:micrometer-core:1.14.4"
|
implementation "io.micrometer:micrometer-core:1.14.2"
|
||||||
implementation group: "com.google.zxing", name: "core", version: "3.5.3"
|
implementation group: "com.google.zxing", name: "core", version: "3.5.3"
|
||||||
// https://mvnrepository.com/artifact/org.commonmark/commonmark
|
// https://mvnrepository.com/artifact/org.commonmark/commonmark
|
||||||
implementation "org.commonmark:commonmark:0.24.0"
|
implementation "org.commonmark:commonmark:0.24.0"
|
||||||
@@ -416,8 +379,6 @@ dependencies {
|
|||||||
implementation "com.bucket4j:bucket4j_jdk17-core:8.14.0"
|
implementation "com.bucket4j:bucket4j_jdk17-core:8.14.0"
|
||||||
implementation "com.fathzer:javaluator:3.0.5"
|
implementation "com.fathzer:javaluator:3.0.5"
|
||||||
|
|
||||||
implementation 'com.vladsch.flexmark:flexmark-html2md-converter:0.64.8'
|
|
||||||
|
|
||||||
developmentOnly("org.springframework.boot:spring-boot-devtools:$springBootVersion")
|
developmentOnly("org.springframework.boot:spring-boot-devtools:$springBootVersion")
|
||||||
compileOnly "org.projectlombok:lombok:$lombokVersion"
|
compileOnly "org.projectlombok:lombok:$lombokVersion"
|
||||||
annotationProcessor "org.projectlombok:lombok:$lombokVersion"
|
annotationProcessor "org.projectlombok:lombok:$lombokVersion"
|
||||||
@@ -441,13 +402,13 @@ task writeVersion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
swaggerhubUpload {
|
swaggerhubUpload {
|
||||||
// dependsOn = generateOpenApiDocs // Depends on your task generating Swagger docs
|
//dependsOn generateOpenApiDocs // Depends on your task generating Swagger docs
|
||||||
api = "Stirling-PDF" // The name of your API on SwaggerHub
|
api "Stirling-PDF" // The name of your API on SwaggerHub
|
||||||
owner = "Frooodle" // Your SwaggerHub username (or organization name)
|
owner "Frooodle" // Your SwaggerHub username (or organization name)
|
||||||
version = project.version // The version of your API
|
version project.version // The version of your API
|
||||||
inputFile = "./SwaggerDoc.json" // The path to your Swagger docs
|
inputFile "./SwaggerDoc.json" // The path to your Swagger docs
|
||||||
token = "${System.getenv("SWAGGERHUB_API_KEY")}" // Your SwaggerHub API key, passed as an environment variable
|
token "${System.getenv("SWAGGERHUB_API_KEY")}" // Your SwaggerHub API key, passed as an environment variable
|
||||||
oas = "3.0.0" // The version of the OpenAPI Specification you"re using
|
oas "3.0.0" // The version of the OpenAPI Specification you"re using
|
||||||
}
|
}
|
||||||
|
|
||||||
jar {
|
jar {
|
||||||
|
|||||||
@@ -8,3 +8,4 @@
|
|||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
@@ -18,4 +18,4 @@ def after_scenario(context, scenario):
|
|||||||
# Remove any temporary files
|
# Remove any temporary files
|
||||||
for temp_file in os.listdir('.'):
|
for temp_file in os.listdir('.'):
|
||||||
if temp_file.startswith('genericNonCustomisableName') or temp_file.startswith('temp_image_'):
|
if temp_file.startswith('genericNonCustomisableName') or temp_file.startswith('temp_image_'):
|
||||||
os.remove(temp_file)
|
os.remove(temp_file)
|
||||||
@@ -204,27 +204,4 @@ Feature: API Validation
|
|||||||
Then the response status code should be 200
|
Then the response status code should be 200
|
||||||
And the response file should have size greater than 100
|
And the response file should have size greater than 100
|
||||||
And the response file should have extension ".pdf"
|
And the response file should have extension ".pdf"
|
||||||
|
|
||||||
@markdown @positive
|
|
||||||
Scenario: Convert PDF to Markdown format
|
|
||||||
Given I generate a PDF file as "fileInput"
|
|
||||||
And the pdf contains 3 pages with random text
|
|
||||||
When I send the API request to the endpoint "/api/v1/convert/pdf/markdown"
|
|
||||||
Then the response status code should be 200
|
|
||||||
And the response file should have size greater than 100
|
|
||||||
And the response file should have extension ".md"
|
|
||||||
|
|
||||||
|
|
||||||
@positive @pdftocsv
|
|
||||||
Scenario: Convert PDF with tables to CSV format
|
|
||||||
Given I use an example file at "exampleFiles/tables.pdf" as parameter "fileInput"
|
|
||||||
And the request data includes
|
|
||||||
| parameter | value |
|
|
||||||
| outputFormat | csv |
|
|
||||||
| pageNumbers | all |
|
|
||||||
When I send the API request to the endpoint "/api/v1/convert/pdf/csv"
|
|
||||||
Then the response status code should be 200
|
|
||||||
And the response file should have size greater than 200
|
|
||||||
And the response file should have extension ".zip"
|
|
||||||
And the response ZIP should contain 3 files
|
|
||||||
|
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
import os
|
import os
|
||||||
import requests
|
import requests
|
||||||
from behave import given, when, then
|
from behave import given, when, then
|
||||||
from pypdf import PdfWriter, PdfReader
|
from PyPDF2 import PdfWriter, PdfReader
|
||||||
from pypdf.errors import PdfReadError
|
|
||||||
import io
|
import io
|
||||||
import random
|
import random
|
||||||
import string
|
import string
|
||||||
@@ -43,7 +42,7 @@ def step_use_example_file(context, filePath, fileInput):
|
|||||||
context.file_name = filePath.split('/')[-1]
|
context.file_name = filePath.split('/')[-1]
|
||||||
if not hasattr(context, 'files'):
|
if not hasattr(context, 'files'):
|
||||||
context.files = {}
|
context.files = {}
|
||||||
|
|
||||||
# Ensure the file exists before opening
|
# Ensure the file exists before opening
|
||||||
try:
|
try:
|
||||||
example_file = open(filePath, 'rb')
|
example_file = open(filePath, 'rb')
|
||||||
@@ -166,17 +165,17 @@ def step_pdf_contains_pages_with_random_text(context, page_count):
|
|||||||
buffer = io.BytesIO()
|
buffer = io.BytesIO()
|
||||||
c = canvas.Canvas(buffer, pagesize=letter)
|
c = canvas.Canvas(buffer, pagesize=letter)
|
||||||
width, height = letter
|
width, height = letter
|
||||||
|
|
||||||
for _ in range(page_count):
|
for _ in range(page_count):
|
||||||
text = ''.join(random.choices(string.ascii_letters + string.digits, k=100))
|
text = ''.join(random.choices(string.ascii_letters + string.digits, k=100))
|
||||||
c.drawString(100, height - 100, text)
|
c.drawString(100, height - 100, text)
|
||||||
c.showPage()
|
c.showPage()
|
||||||
|
|
||||||
c.save()
|
c.save()
|
||||||
|
|
||||||
with open(context.file_name, 'wb') as f:
|
with open(context.file_name, 'wb') as f:
|
||||||
f.write(buffer.getvalue())
|
f.write(buffer.getvalue())
|
||||||
|
|
||||||
context.files[context.param_name].close()
|
context.files[context.param_name].close()
|
||||||
context.files[context.param_name] = open(context.file_name, 'rb')
|
context.files[context.param_name] = open(context.file_name, 'rb')
|
||||||
|
|
||||||
@@ -185,16 +184,16 @@ def step_pdf_pages_contain_text(context, text):
|
|||||||
buffer = io.BytesIO()
|
buffer = io.BytesIO()
|
||||||
c = canvas.Canvas(buffer, pagesize=letter)
|
c = canvas.Canvas(buffer, pagesize=letter)
|
||||||
width, height = letter
|
width, height = letter
|
||||||
|
|
||||||
for _ in range(len(PdfReader(context.file_name).pages)):
|
for _ in range(len(PdfReader(context.file_name).pages)):
|
||||||
c.drawString(100, height - 100, text)
|
c.drawString(100, height - 100, text)
|
||||||
c.showPage()
|
c.showPage()
|
||||||
|
|
||||||
c.save()
|
c.save()
|
||||||
|
|
||||||
with open(context.file_name, 'wb') as f:
|
with open(context.file_name, 'wb') as f:
|
||||||
f.write(buffer.getvalue())
|
f.write(buffer.getvalue())
|
||||||
|
|
||||||
context.files[context.param_name].close()
|
context.files[context.param_name].close()
|
||||||
context.files[context.param_name] = open(context.file_name, 'rb')
|
context.files[context.param_name] = open(context.file_name, 'rb')
|
||||||
|
|
||||||
@@ -346,7 +345,7 @@ def step_check_response_pdf_page_count(context, page_count):
|
|||||||
def step_check_response_zip_file_count(context, file_count):
|
def step_check_response_zip_file_count(context, file_count):
|
||||||
response_file = io.BytesIO(context.response.content)
|
response_file = io.BytesIO(context.response.content)
|
||||||
with zipfile.ZipFile(io.BytesIO(response_file.getvalue())) as zip_file:
|
with zipfile.ZipFile(io.BytesIO(response_file.getvalue())) as zip_file:
|
||||||
actual_file_count = len(zip_file.namelist())
|
actual_file_count = len(zip_file.namelist())
|
||||||
assert actual_file_count == file_count, f"Expected {file_count} files but got {actual_file_count} files"
|
assert actual_file_count == file_count, f"Expected {file_count} files but got {actual_file_count} files"
|
||||||
|
|
||||||
@then('the response ZIP file should contain {doc_count:d} documents each having {pages_per_doc:d} pages')
|
@then('the response ZIP file should contain {doc_count:d} documents each having {pages_per_doc:d} pages')
|
||||||
@@ -355,7 +354,7 @@ def step_check_response_zip_doc_page_count(context, doc_count, pages_per_doc):
|
|||||||
with zipfile.ZipFile(io.BytesIO(response_file.getvalue())) as zip_file:
|
with zipfile.ZipFile(io.BytesIO(response_file.getvalue())) as zip_file:
|
||||||
actual_doc_count = len(zip_file.namelist())
|
actual_doc_count = len(zip_file.namelist())
|
||||||
assert actual_doc_count == doc_count, f"Expected {doc_count} documents but got {actual_doc_count} documents"
|
assert actual_doc_count == doc_count, f"Expected {doc_count} documents but got {actual_doc_count} documents"
|
||||||
|
|
||||||
for file_name in zip_file.namelist():
|
for file_name in zip_file.namelist():
|
||||||
with zip_file.open(file_name) as pdf_file:
|
with zip_file.open(file_name) as pdf_file:
|
||||||
reader = PdfReader(pdf_file)
|
reader = PdfReader(pdf_file)
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
behave
|
behave
|
||||||
requests
|
requests
|
||||||
pypdf
|
PyPDF2
|
||||||
reportlab
|
reportlab
|
||||||
PyCryptodome
|
PyCryptodome
|
||||||
BIN
docs/stirling-pdf.png
Normal file
BIN
docs/stirling-pdf.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 50 KiB |
1
docs/stirling-transparent.svg
Normal file
1
docs/stirling-transparent.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 9.4 KiB |
@@ -1,63 +0,0 @@
|
|||||||
services:
|
|
||||||
stirling-pdf:
|
|
||||||
container_name: Stirling-PDF-Security-Fat-Postgres
|
|
||||||
image: stirlingtools/stirling-pdf:latest-fat-postgres
|
|
||||||
deploy:
|
|
||||||
resources:
|
|
||||||
limits:
|
|
||||||
memory: 4G
|
|
||||||
depends_on:
|
|
||||||
- db
|
|
||||||
healthcheck:
|
|
||||||
test: [ "CMD-SHELL", "curl -f http://localhost:8080/api/v1/info/status | grep -q 'UP'" ]
|
|
||||||
interval: 5s
|
|
||||||
timeout: 10s
|
|
||||||
retries: 16
|
|
||||||
ports:
|
|
||||||
- 8080:8080
|
|
||||||
volumes:
|
|
||||||
- ./stirling/latest/data:/usr/share/tessdata:rw
|
|
||||||
- ./stirling/latest/config:/configs:rw
|
|
||||||
- ./stirling/latest/logs:/logs:rw
|
|
||||||
environment:
|
|
||||||
DOCKER_ENABLE_SECURITY: "true"
|
|
||||||
SECURITY_ENABLELOGIN: "false"
|
|
||||||
PUID: 1002
|
|
||||||
PGID: 1002
|
|
||||||
UMASK: "022"
|
|
||||||
SYSTEM_DEFAULTLOCALE: en-US
|
|
||||||
UI_APPNAME: Stirling-PDF
|
|
||||||
UI_HOMEDESCRIPTION: Demo site for Stirling-PDF Latest-fat with Security and PostgreSQL
|
|
||||||
UI_APPNAMENAVBAR: Stirling-PDF Latest-fat-PostgreSQL
|
|
||||||
SYSTEM_MAXFILESIZE: "100"
|
|
||||||
METRICS_ENABLED: "true"
|
|
||||||
SYSTEM_GOOGLEVISIBILITY: "true"
|
|
||||||
SYSTEM_DATASOURCE_ENABLECUSTOMDATABASE: "true"
|
|
||||||
SYSTEM_DATASOURCE_CUSTOMDATABASEURL: "jdbc:postgresql://db:5432/stirling_pdf"
|
|
||||||
SYSTEM_DATASOURCE_USERNAME: "admin"
|
|
||||||
SYSTEM_DATASOURCE_PASSWORD: "stirling"
|
|
||||||
restart: on-failure:5
|
|
||||||
|
|
||||||
db:
|
|
||||||
image: 'postgres:17.2-alpine'
|
|
||||||
restart: on-failure:5
|
|
||||||
container_name: db
|
|
||||||
ports:
|
|
||||||
- "5432:5432"
|
|
||||||
environment:
|
|
||||||
POSTGRES_DB: "stirling_pdf"
|
|
||||||
POSTGRES_USER: "admin"
|
|
||||||
POSTGRES_PASSWORD: "stirling"
|
|
||||||
shm_size: "512mb"
|
|
||||||
deploy:
|
|
||||||
resources:
|
|
||||||
limits:
|
|
||||||
memory: 512m
|
|
||||||
cpus: "0.5"
|
|
||||||
healthcheck:
|
|
||||||
test: [ "CMD-SHELL", "pg_isready -U admin stirling_pdf" ]
|
|
||||||
interval: 1s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 10
|
|
||||||
volumes:
|
|
||||||
- ./stirling/latest/data:/pgdata
|
|
||||||
@@ -14,9 +14,9 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- 8080:8080
|
- 8080:8080
|
||||||
volumes:
|
volumes:
|
||||||
- ./stirling/latest/data:/usr/share/tessdata:rw
|
- /stirling/latest/data:/usr/share/tessdata:rw
|
||||||
- ./stirling/latest/config:/configs:rw
|
- /stirling/latest/config:/configs:rw
|
||||||
- ./stirling/latest/logs:/logs:rw
|
- /stirling/latest/logs:/logs:rw
|
||||||
environment:
|
environment:
|
||||||
DOCKER_ENABLE_SECURITY: "true"
|
DOCKER_ENABLE_SECURITY: "true"
|
||||||
SECURITY_ENABLELOGIN: "false"
|
SECURITY_ENABLELOGIN: "false"
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "8080:8080"
|
- "8080:8080"
|
||||||
volumes:
|
volumes:
|
||||||
- ./stirling/latest/data:/usr/share/tessdata:rw
|
- /stirling/latest/data:/usr/share/tessdata:rw
|
||||||
- ./stirling/latest/config:/configs:rw
|
- /stirling/latest/config:/configs:rw
|
||||||
- ./stirling/latest/logs:/logs:rw
|
- /stirling/latest/logs:/logs:rw
|
||||||
environment:
|
environment:
|
||||||
DOCKER_ENABLE_SECURITY: "true"
|
DOCKER_ENABLE_SECURITY: "true"
|
||||||
SECURITY_ENABLELOGIN: "true"
|
SECURITY_ENABLELOGIN: "true"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
stirling-pdf:
|
stirling-pdf:
|
||||||
container_name: Stirling-PDF-Security-Fat-with-login
|
container_name: Stirling-PDF-Security-Fat
|
||||||
image: stirlingtools/stirling-pdf:latest-fat
|
image: stirlingtools/stirling-pdf:latest-fat
|
||||||
deploy:
|
deploy:
|
||||||
resources:
|
resources:
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
# Enables parallel execution of tasks, allowing multiple tasks to run simultaneously
|
|
||||||
org.gradle.parallel=true
|
|
||||||
|
|
||||||
# Enables build caching to reuse outputs from previous builds for faster execution
|
|
||||||
# org.gradle.caching=true
|
|
||||||
|
|
||||||
org.gradle.build-scan=true
|
|
||||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,7 +1,5 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip
|
||||||
networkTimeout=10000
|
|
||||||
validateDistributionUrl=true
|
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|||||||
37
gradlew
vendored
37
gradlew
vendored
@@ -15,8 +15,6 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
#
|
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
#
|
#
|
||||||
@@ -57,7 +55,7 @@
|
|||||||
# Darwin, MinGW, and NonStop.
|
# Darwin, MinGW, and NonStop.
|
||||||
#
|
#
|
||||||
# (3) This script is generated from the Groovy template
|
# (3) This script is generated from the Groovy template
|
||||||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
# within the Gradle project.
|
# within the Gradle project.
|
||||||
#
|
#
|
||||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
@@ -82,11 +80,13 @@ do
|
|||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
# This is normally unused
|
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||||
# shellcheck disable=SC2034
|
|
||||||
|
APP_NAME="Gradle"
|
||||||
APP_BASE_NAME=${0##*/}
|
APP_BASE_NAME=${0##*/}
|
||||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
|
||||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
MAX_FD=maximum
|
MAX_FD=maximum
|
||||||
@@ -133,29 +133,22 @@ location of your Java installation."
|
|||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
JAVACMD=java
|
JAVACMD=java
|
||||||
if ! command -v java >/dev/null 2>&1
|
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
then
|
|
||||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
|
||||||
|
|
||||||
Please set the JAVA_HOME variable in your environment to match the
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
location of your Java installation."
|
location of your Java installation."
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Increase the maximum file descriptors if we can.
|
# Increase the maximum file descriptors if we can.
|
||||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||||
case $MAX_FD in #(
|
case $MAX_FD in #(
|
||||||
max*)
|
max*)
|
||||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
|
||||||
# shellcheck disable=SC2039,SC3045
|
|
||||||
MAX_FD=$( ulimit -H -n ) ||
|
MAX_FD=$( ulimit -H -n ) ||
|
||||||
warn "Could not query maximum file descriptor limit"
|
warn "Could not query maximum file descriptor limit"
|
||||||
esac
|
esac
|
||||||
case $MAX_FD in #(
|
case $MAX_FD in #(
|
||||||
'' | soft) :;; #(
|
'' | soft) :;; #(
|
||||||
*)
|
*)
|
||||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
|
||||||
# shellcheck disable=SC2039,SC3045
|
|
||||||
ulimit -n "$MAX_FD" ||
|
ulimit -n "$MAX_FD" ||
|
||||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||||
esac
|
esac
|
||||||
@@ -200,15 +193,11 @@ if "$cygwin" || "$msys" ; then
|
|||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Collect all arguments for the java command;
|
||||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
# shell script including quotes and variable substitutions, so put them in
|
||||||
|
# double quotes to make sure that they get re-expanded; and
|
||||||
# Collect all arguments for the java command:
|
# * put everything else in single quotes, so that it's not re-expanded.
|
||||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
|
||||||
# and any embedded shellness will be escaped.
|
|
||||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
|
||||||
# treated as '${Hostname}' itself on the command line.
|
|
||||||
|
|
||||||
set -- \
|
set -- \
|
||||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
|
|||||||
23
gradlew.bat
vendored
23
gradlew.bat
vendored
@@ -13,8 +13,6 @@
|
|||||||
@rem See the License for the specific language governing permissions and
|
@rem See the License for the specific language governing permissions and
|
||||||
@rem limitations under the License.
|
@rem limitations under the License.
|
||||||
@rem
|
@rem
|
||||||
@rem SPDX-License-Identifier: Apache-2.0
|
|
||||||
@rem
|
|
||||||
|
|
||||||
@if "%DEBUG%"=="" @echo off
|
@if "%DEBUG%"=="" @echo off
|
||||||
@rem ##########################################################################
|
@rem ##########################################################################
|
||||||
@@ -28,7 +26,6 @@ if "%OS%"=="Windows_NT" setlocal
|
|||||||
|
|
||||||
set DIRNAME=%~dp0
|
set DIRNAME=%~dp0
|
||||||
if "%DIRNAME%"=="" set DIRNAME=.
|
if "%DIRNAME%"=="" set DIRNAME=.
|
||||||
@rem This is normally unused
|
|
||||||
set APP_BASE_NAME=%~n0
|
set APP_BASE_NAME=%~n0
|
||||||
set APP_HOME=%DIRNAME%
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
@@ -45,11 +42,11 @@ set JAVA_EXE=java.exe
|
|||||||
%JAVA_EXE% -version >NUL 2>&1
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
if %ERRORLEVEL% equ 0 goto execute
|
if %ERRORLEVEL% equ 0 goto execute
|
||||||
|
|
||||||
echo. 1>&2
|
echo.
|
||||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
echo. 1>&2
|
echo.
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
echo location of your Java installation. 1>&2
|
echo location of your Java installation.
|
||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
@@ -59,11 +56,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
|||||||
|
|
||||||
if exist "%JAVA_EXE%" goto execute
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
echo. 1>&2
|
echo.
|
||||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||||
echo. 1>&2
|
echo.
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
echo location of your Java installation. 1>&2
|
echo location of your Java installation.
|
||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 169 KiB After Width: | Height: | Size: 242 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 145 KiB |
@@ -75,7 +75,7 @@ def write_readme(progress_list: list[tuple[str, int]]) -> None:
|
|||||||
f"",
|
f"",
|
||||||
)
|
)
|
||||||
|
|
||||||
with open("README.md", "w", encoding="utf-8", newline="\n") as file:
|
with open("README.md", "w", encoding="utf-8") as file:
|
||||||
file.writelines(content)
|
file.writelines(content)
|
||||||
|
|
||||||
|
|
||||||
@@ -135,10 +135,9 @@ def compare_files(
|
|||||||
# elif "language.direction" in sort_ignore_translation[language]["missing"]:
|
# elif "language.direction" in sort_ignore_translation[language]["missing"]:
|
||||||
# sort_ignore_translation[language]["missing"].remove("language.direction")
|
# sort_ignore_translation[language]["missing"].remove("language.direction")
|
||||||
|
|
||||||
with (
|
with open(default_file_path, encoding="utf-8") as default_file, open(
|
||||||
open(default_file_path, encoding="utf-8") as default_file,
|
file_path, encoding="utf-8"
|
||||||
open(file_path, encoding="utf-8") as file,
|
) as file:
|
||||||
):
|
|
||||||
for _ in range(5):
|
for _ in range(5):
|
||||||
next(default_file)
|
next(default_file)
|
||||||
try:
|
try:
|
||||||
@@ -196,7 +195,7 @@ def compare_files(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
ignore_translation = convert_to_multiline(sort_ignore_translation)
|
ignore_translation = convert_to_multiline(sort_ignore_translation)
|
||||||
with open(ignore_translation_file, "w", encoding="utf-8", newline="\n") as file:
|
with open(ignore_translation_file, "w", encoding="utf-8") as file:
|
||||||
file.write(tomlkit.dumps(ignore_translation))
|
file.write(tomlkit.dumps(ignore_translation))
|
||||||
|
|
||||||
unique_data = list(set(result_list))
|
unique_data = list(set(result_list))
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ ignore = [
|
|||||||
[cs_CZ]
|
[cs_CZ]
|
||||||
ignore = [
|
ignore = [
|
||||||
'language.direction',
|
'language.direction',
|
||||||
|
'pipeline.header',
|
||||||
'text',
|
'text',
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -49,7 +50,6 @@ ignore = [
|
|||||||
'pipeline.title',
|
'pipeline.title',
|
||||||
'pipelineOptions.pipelineHeader',
|
'pipelineOptions.pipelineHeader',
|
||||||
'pro',
|
'pro',
|
||||||
'redact.zoom',
|
|
||||||
'sponsor',
|
'sponsor',
|
||||||
'text',
|
'text',
|
||||||
'validateSignature.cert.bits',
|
'validateSignature.cert.bits',
|
||||||
@@ -210,11 +210,6 @@ ignore = [
|
|||||||
'watermark.type.1',
|
'watermark.type.1',
|
||||||
]
|
]
|
||||||
|
|
||||||
[sl_SI]
|
|
||||||
ignore = [
|
|
||||||
'language.direction',
|
|
||||||
]
|
|
||||||
|
|
||||||
[sr_LATN_RS]
|
[sr_LATN_RS]
|
||||||
ignore = [
|
ignore = [
|
||||||
'language.direction',
|
'language.direction',
|
||||||
@@ -252,11 +247,6 @@ ignore = [
|
|||||||
'showJS.tags',
|
'showJS.tags',
|
||||||
]
|
]
|
||||||
|
|
||||||
[zh_BO]
|
|
||||||
ignore = [
|
|
||||||
'language.direction',
|
|
||||||
]
|
|
||||||
|
|
||||||
[zh_CN]
|
[zh_CN]
|
||||||
ignore = [
|
ignore = [
|
||||||
'language.direction',
|
'language.direction',
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import org.springframework.core.Ordered;
|
|||||||
import org.springframework.core.annotation.Order;
|
import org.springframework.core.annotation.Order;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@@ -28,9 +27,4 @@ public class EEAppConfig {
|
|||||||
public boolean runningEnterpriseEdition() {
|
public boolean runningEnterpriseEdition() {
|
||||||
return licenseKeyChecker.getEnterpriseEnabledResult();
|
return licenseKeyChecker.getEnterpriseEnabledResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean(name = "SSOAutoLogin")
|
|
||||||
public boolean ssoAutoLogin() {
|
|
||||||
return applicationProperties.getEnterpriseEdition().isSsoAutoLogin();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,14 +13,12 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
|||||||
import com.posthog.java.shaded.org.json.JSONObject;
|
import com.posthog.java.shaded.org.json.JSONObject;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
import stirling.software.SPDF.utils.GeneralUtils;
|
import stirling.software.SPDF.utils.GeneralUtils;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class KeygenLicenseVerifier {
|
public class KeygenLicenseVerifier {
|
||||||
// todo: place in config files?
|
|
||||||
private static final String ACCOUNT_ID = "e5430f69-e834-4ae4-befd-b602aae5f372";
|
private static final String ACCOUNT_ID = "e5430f69-e834-4ae4-befd-b602aae5f372";
|
||||||
private static final String BASE_URL = "https://api.keygen.sh/v1/accounts";
|
private static final String BASE_URL = "https://api.keygen.sh/v1/accounts";
|
||||||
private static final ObjectMapper objectMapper = new ObjectMapper();
|
private static final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
@@ -69,7 +67,7 @@ public class KeygenLicenseVerifier {
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("Error verifying license: {}", e.getMessage());
|
log.error("Error verifying license: " + e.getMessage());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -96,9 +94,10 @@ public class KeygenLicenseVerifier {
|
|||||||
.build();
|
.build();
|
||||||
|
|
||||||
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
|
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
|
||||||
log.debug("ValidateLicenseResponse body: {}", response.body());
|
log.info(" validateLicenseResponse body: " + response.body());
|
||||||
JsonNode jsonResponse = objectMapper.readTree(response.body());
|
JsonNode jsonResponse = objectMapper.readTree(response.body());
|
||||||
if (response.statusCode() == 200) {
|
if (response.statusCode() == 200) {
|
||||||
|
|
||||||
JsonNode metaNode = jsonResponse.path("meta");
|
JsonNode metaNode = jsonResponse.path("meta");
|
||||||
boolean isValid = metaNode.path("valid").asBoolean();
|
boolean isValid = metaNode.path("valid").asBoolean();
|
||||||
|
|
||||||
@@ -120,7 +119,7 @@ public class KeygenLicenseVerifier {
|
|||||||
log.info(applicationProperties.toString());
|
log.info(applicationProperties.toString());
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
log.error("Error validating license. Status code: {}", response.statusCode());
|
log.error("Error validating license. Status code: " + response.statusCode());
|
||||||
}
|
}
|
||||||
return jsonResponse;
|
return jsonResponse;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import org.springframework.scheduling.annotation.Scheduled;
|
|||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
import stirling.software.SPDF.utils.GeneralUtils;
|
import stirling.software.SPDF.utils.GeneralUtils;
|
||||||
|
|
||||||
@@ -19,7 +18,7 @@ public class LicenseKeyChecker {
|
|||||||
|
|
||||||
private final ApplicationProperties applicationProperties;
|
private final ApplicationProperties applicationProperties;
|
||||||
|
|
||||||
private boolean enterpriseEnabledResult = false;
|
private boolean enterpriseEnbaledResult = false;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public LicenseKeyChecker(
|
public LicenseKeyChecker(
|
||||||
@@ -36,12 +35,12 @@ public class LicenseKeyChecker {
|
|||||||
|
|
||||||
private void checkLicense() {
|
private void checkLicense() {
|
||||||
if (!applicationProperties.getEnterpriseEdition().isEnabled()) {
|
if (!applicationProperties.getEnterpriseEdition().isEnabled()) {
|
||||||
enterpriseEnabledResult = false;
|
enterpriseEnbaledResult = false;
|
||||||
} else {
|
} else {
|
||||||
enterpriseEnabledResult =
|
enterpriseEnbaledResult =
|
||||||
licenseService.verifyLicense(
|
licenseService.verifyLicense(
|
||||||
applicationProperties.getEnterpriseEdition().getKey());
|
applicationProperties.getEnterpriseEdition().getKey());
|
||||||
if (enterpriseEnabledResult) {
|
if (enterpriseEnbaledResult) {
|
||||||
log.info("License key is valid.");
|
log.info("License key is valid.");
|
||||||
} else {
|
} else {
|
||||||
log.info("License key is invalid.");
|
log.info("License key is invalid.");
|
||||||
@@ -51,11 +50,11 @@ public class LicenseKeyChecker {
|
|||||||
|
|
||||||
public void updateLicenseKey(String newKey) throws IOException {
|
public void updateLicenseKey(String newKey) throws IOException {
|
||||||
applicationProperties.getEnterpriseEdition().setKey(newKey);
|
applicationProperties.getEnterpriseEdition().setKey(newKey);
|
||||||
GeneralUtils.saveKeyToSettings("EnterpriseEdition.key", newKey);
|
GeneralUtils.saveKeyToConfig("EnterpriseEdition.key", newKey, false);
|
||||||
checkLicense();
|
checkLicense();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean getEnterpriseEnabledResult() {
|
public boolean getEnterpriseEnabledResult() {
|
||||||
return enterpriseEnabledResult;
|
return enterpriseEnbaledResult;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package stirling.software.SPDF;
|
package stirling.software.SPDF;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.ServerSocket;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
@@ -21,23 +22,19 @@ import io.github.pixee.security.SystemCommand;
|
|||||||
|
|
||||||
import jakarta.annotation.PostConstruct;
|
import jakarta.annotation.PostConstruct;
|
||||||
import jakarta.annotation.PreDestroy;
|
import jakarta.annotation.PreDestroy;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.SPDF.UI.WebBrowser;
|
import stirling.software.SPDF.UI.WebBrowser;
|
||||||
import stirling.software.SPDF.config.ConfigInitializer;
|
import stirling.software.SPDF.config.ConfigInitializer;
|
||||||
import stirling.software.SPDF.config.InstallationPathConfig;
|
import stirling.software.SPDF.config.InstallationPathConfig;
|
||||||
import stirling.software.SPDF.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
import stirling.software.SPDF.utils.UrlUtils;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@EnableScheduling
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
public class SPDFApplication {
|
@EnableScheduling
|
||||||
|
@Slf4j
|
||||||
|
public class SPdfApplication {
|
||||||
|
|
||||||
private static String serverPortStatic;
|
|
||||||
private static String baseUrlStatic;
|
private static String baseUrlStatic;
|
||||||
|
private static String serverPortStatic;
|
||||||
private final Environment env;
|
private final Environment env;
|
||||||
private final ApplicationProperties applicationProperties;
|
private final ApplicationProperties applicationProperties;
|
||||||
private final WebBrowser webBrowser;
|
private final WebBrowser webBrowser;
|
||||||
@@ -45,7 +42,7 @@ public class SPDFApplication {
|
|||||||
@Value("${baseUrl:http://localhost}")
|
@Value("${baseUrl:http://localhost}")
|
||||||
private String baseUrl;
|
private String baseUrl;
|
||||||
|
|
||||||
public SPDFApplication(
|
public SPdfApplication(
|
||||||
Environment env,
|
Environment env,
|
||||||
ApplicationProperties applicationProperties,
|
ApplicationProperties applicationProperties,
|
||||||
@Autowired(required = false) WebBrowser webBrowser) {
|
@Autowired(required = false) WebBrowser webBrowser) {
|
||||||
@@ -54,25 +51,33 @@ public class SPDFApplication {
|
|||||||
this.webBrowser = webBrowser;
|
this.webBrowser = webBrowser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Optionally keep this method if you want to provide a manual port-incrementation fallback.
|
||||||
|
private static String findAvailablePort(int startPort) {
|
||||||
|
int port = startPort;
|
||||||
|
while (!isPortAvailable(port)) {
|
||||||
|
port++;
|
||||||
|
}
|
||||||
|
return String.valueOf(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isPortAvailable(int port) {
|
||||||
|
try (ServerSocket socket = new ServerSocket(port)) {
|
||||||
|
return true;
|
||||||
|
} catch (IOException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void main(String[] args) throws IOException, InterruptedException {
|
public static void main(String[] args) throws IOException, InterruptedException {
|
||||||
SpringApplication app = new SpringApplication(SPDFApplication.class);
|
SpringApplication app = new SpringApplication(SPdfApplication.class);
|
||||||
|
|
||||||
Properties props = new Properties();
|
Properties props = new Properties();
|
||||||
|
|
||||||
if (Boolean.parseBoolean(System.getProperty("STIRLING_PDF_DESKTOP_UI", "false"))) {
|
if (Boolean.parseBoolean(System.getProperty("STIRLING_PDF_DESKTOP_UI", "false"))) {
|
||||||
System.setProperty("java.awt.headless", "false");
|
System.setProperty("java.awt.headless", "false");
|
||||||
app.setHeadless(false);
|
app.setHeadless(false);
|
||||||
props.put("java.awt.headless", "false");
|
props.put("java.awt.headless", "false");
|
||||||
props.put("spring.main.web-application-type", "servlet");
|
props.put("spring.main.web-application-type", "servlet");
|
||||||
|
|
||||||
int desiredPort = 8080;
|
|
||||||
String port = UrlUtils.findAvailablePort(desiredPort);
|
|
||||||
props.put("server.port", port);
|
|
||||||
System.setProperty("server.port", port);
|
|
||||||
log.info("Desktop UI mode: Using port {}", port);
|
|
||||||
}
|
}
|
||||||
|
app.setAdditionalProfiles("default");
|
||||||
app.setAdditionalProfiles(getActiveProfile(args));
|
|
||||||
|
|
||||||
ConfigInitializer initializer = new ConfigInitializer();
|
ConfigInitializer initializer = new ConfigInitializer();
|
||||||
try {
|
try {
|
||||||
@@ -80,21 +85,20 @@ public class SPDFApplication {
|
|||||||
} catch (IOException | URISyntaxException e) {
|
} catch (IOException | URISyntaxException e) {
|
||||||
log.error("Error initialising configuration", e);
|
log.error("Error initialising configuration", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, String> propertyFiles = new HashMap<>();
|
Map<String, String> propertyFiles = new HashMap<>();
|
||||||
|
|
||||||
// External config files
|
// External config files
|
||||||
Path settingsPath = Paths.get(InstallationPathConfig.getSettingsPath());
|
log.info("Settings file: {}", InstallationPathConfig.getSettingsPath());
|
||||||
log.info("Settings file: {}", settingsPath.toString());
|
if (Files.exists(Paths.get(InstallationPathConfig.getSettingsPath()))) {
|
||||||
if (Files.exists(settingsPath)) {
|
|
||||||
propertyFiles.put(
|
propertyFiles.put(
|
||||||
"spring.config.additional-location", "file:" + settingsPath.toString());
|
"spring.config.additional-location",
|
||||||
|
"file:" + InstallationPathConfig.getSettingsPath());
|
||||||
} else {
|
} else {
|
||||||
log.warn("External configuration file '{}' does not exist.", settingsPath.toString());
|
log.warn(
|
||||||
|
"External configuration file '{}' does not exist.",
|
||||||
|
InstallationPathConfig.getSettingsPath());
|
||||||
}
|
}
|
||||||
|
if (Files.exists(Paths.get(InstallationPathConfig.getCustomSettingsPath()))) {
|
||||||
Path customSettingsPath = Paths.get(InstallationPathConfig.getCustomSettingsPath());
|
|
||||||
log.info("Custom settings file: {}", customSettingsPath.toString());
|
|
||||||
if (Files.exists(customSettingsPath)) {
|
|
||||||
String existingLocation =
|
String existingLocation =
|
||||||
propertyFiles.getOrDefault("spring.config.additional-location", "");
|
propertyFiles.getOrDefault("spring.config.additional-location", "");
|
||||||
if (!existingLocation.isEmpty()) {
|
if (!existingLocation.isEmpty()) {
|
||||||
@@ -102,39 +106,59 @@ public class SPDFApplication {
|
|||||||
}
|
}
|
||||||
propertyFiles.put(
|
propertyFiles.put(
|
||||||
"spring.config.additional-location",
|
"spring.config.additional-location",
|
||||||
existingLocation + "file:" + customSettingsPath.toString());
|
existingLocation + "file:" + InstallationPathConfig.getCustomSettingsPath());
|
||||||
} else {
|
} else {
|
||||||
log.warn(
|
log.warn(
|
||||||
"Custom configuration file '{}' does not exist.",
|
"Custom configuration file '{}' does not exist.",
|
||||||
customSettingsPath.toString());
|
InstallationPathConfig.getCustomSettingsPath());
|
||||||
}
|
}
|
||||||
Properties finalProps = new Properties();
|
Properties finalProps = new Properties();
|
||||||
|
|
||||||
if (!propertyFiles.isEmpty()) {
|
if (!propertyFiles.isEmpty()) {
|
||||||
finalProps.putAll(
|
finalProps.putAll(
|
||||||
Collections.singletonMap(
|
Collections.singletonMap(
|
||||||
"spring.config.additional-location",
|
"spring.config.additional-location",
|
||||||
propertyFiles.get("spring.config.additional-location")));
|
propertyFiles.get("spring.config.additional-location")));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!props.isEmpty()) {
|
if (!props.isEmpty()) {
|
||||||
finalProps.putAll(props);
|
finalProps.putAll(props);
|
||||||
}
|
}
|
||||||
app.setDefaultProperties(finalProps);
|
app.setDefaultProperties(finalProps);
|
||||||
|
|
||||||
app.run(args);
|
app.run(args);
|
||||||
|
|
||||||
// Ensure directories are created
|
// Ensure directories are created
|
||||||
try {
|
try {
|
||||||
Files.createDirectories(Path.of(InstallationPathConfig.getTemplatesPath()));
|
Files.createDirectories(Path.of(InstallationPathConfig.getTemplatesPath()));
|
||||||
Files.createDirectories(Path.of(InstallationPathConfig.getStaticPath()));
|
Files.createDirectories(Path.of(InstallationPathConfig.getStaticPath()));
|
||||||
} catch (IOException e) {
|
} catch (Exception e) {
|
||||||
log.error("Error creating directories: {}", e.getMessage());
|
log.error("Error creating directories: {}", e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
printStartupLogs();
|
printStartupLogs();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void printStartupLogs() {
|
||||||
|
log.info("Stirling-PDF Started.");
|
||||||
|
String url = baseUrlStatic + ":" + getStaticPort();
|
||||||
|
log.info("Navigate to {}", url);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getStaticBaseUrl() {
|
||||||
|
return baseUrlStatic;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getStaticPort() {
|
||||||
|
return serverPortStatic;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Value("${server.port:8080}")
|
||||||
|
public void setServerPortStatic(String port) {
|
||||||
|
if ("auto".equalsIgnoreCase(port)) {
|
||||||
|
// Use Spring Boot's automatic port assignment (server.port=0)
|
||||||
|
SPdfApplication.serverPortStatic = // This will let Spring Boot assign an available port
|
||||||
|
"0";
|
||||||
|
} else {
|
||||||
|
SPdfApplication.serverPortStatic = port;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@PostConstruct
|
@PostConstruct
|
||||||
public void init() {
|
public void init() {
|
||||||
baseUrlStatic = this.baseUrl;
|
baseUrlStatic = this.baseUrl;
|
||||||
@@ -157,7 +181,7 @@ public class SPDFApplication {
|
|||||||
} else if (os.contains("nix") || os.contains("nux")) {
|
} else if (os.contains("nix") || os.contains("nux")) {
|
||||||
SystemCommand.runCommand(rt, "xdg-open " + url);
|
SystemCommand.runCommand(rt, "xdg-open " + url);
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (Exception e) {
|
||||||
log.error("Error opening browser: {}", e.getMessage());
|
log.error("Error opening browser: {}", e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -165,27 +189,6 @@ public class SPDFApplication {
|
|||||||
log.info("Running configs {}", applicationProperties.toString());
|
log.info("Running configs {}", applicationProperties.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Value("${server.port:8080}")
|
|
||||||
public void setServerPort(String port) {
|
|
||||||
if ("auto".equalsIgnoreCase(port)) {
|
|
||||||
// Use Spring Boot's automatic port assignment (server.port=0)
|
|
||||||
SPDFApplication.serverPortStatic =
|
|
||||||
"0"; // This will let Spring Boot assign an available port
|
|
||||||
} else {
|
|
||||||
SPDFApplication.serverPortStatic = port;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setServerPortStatic(String port) {
|
|
||||||
if ("auto".equalsIgnoreCase(port)) {
|
|
||||||
// Use Spring Boot's automatic port assignment (server.port=0)
|
|
||||||
SPDFApplication.serverPortStatic =
|
|
||||||
"0"; // This will let Spring Boot assign an available port
|
|
||||||
} else {
|
|
||||||
SPDFApplication.serverPortStatic = port;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@PreDestroy
|
@PreDestroy
|
||||||
public void cleanup() {
|
public void cleanup() {
|
||||||
if (webBrowser != null) {
|
if (webBrowser != null) {
|
||||||
@@ -193,31 +196,11 @@ public class SPDFApplication {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void printStartupLogs() {
|
public String getNonStaticBaseUrl() {
|
||||||
log.info("Stirling-PDF Started.");
|
|
||||||
String url = baseUrlStatic + ":" + getStaticPort();
|
|
||||||
log.info("Navigate to {}", url);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String[] getActiveProfile(String[] args) {
|
|
||||||
if (args == null) {
|
|
||||||
return new String[] {"default"};
|
|
||||||
}
|
|
||||||
|
|
||||||
for (String arg : args) {
|
|
||||||
if (arg.contains("spring.profiles.active")) {
|
|
||||||
return arg.substring(args[0].indexOf('=') + 1).split(", ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new String[] {"default"};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getStaticBaseUrl() {
|
|
||||||
return baseUrlStatic;
|
return baseUrlStatic;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getStaticPort() {
|
public String getNonStaticPort() {
|
||||||
return serverPortStatic;
|
return serverPortStatic;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -34,17 +34,13 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
|||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import jakarta.annotation.PreDestroy;
|
import jakarta.annotation.PreDestroy;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import me.friwi.jcefmaven.CefAppBuilder;
|
import me.friwi.jcefmaven.CefAppBuilder;
|
||||||
import me.friwi.jcefmaven.EnumProgress;
|
import me.friwi.jcefmaven.EnumProgress;
|
||||||
import me.friwi.jcefmaven.MavenCefAppHandlerAdapter;
|
import me.friwi.jcefmaven.MavenCefAppHandlerAdapter;
|
||||||
import me.friwi.jcefmaven.impl.progress.ConsoleProgressHandler;
|
import me.friwi.jcefmaven.impl.progress.ConsoleProgressHandler;
|
||||||
|
|
||||||
import stirling.software.SPDF.UI.WebBrowser;
|
import stirling.software.SPDF.UI.WebBrowser;
|
||||||
import stirling.software.SPDF.config.InstallationPathConfig;
|
import stirling.software.SPDF.config.InstallationPathConfig;
|
||||||
import stirling.software.SPDF.utils.UIScaling;
|
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@@ -219,7 +215,7 @@ public class DesktopBrowser implements WebBrowser {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
frame.setSize(UIScaling.scaleWidth(1280), UIScaling.scaleHeight(800));
|
frame.setSize(1280, 768);
|
||||||
frame.setLocationRelativeTo(null);
|
frame.setLocationRelativeTo(null);
|
||||||
|
|
||||||
loadIcon();
|
loadIcon();
|
||||||
@@ -268,9 +264,7 @@ public class DesktopBrowser implements WebBrowser {
|
|||||||
frame.setOpacity(1.0f);
|
frame.setOpacity(1.0f);
|
||||||
frame.setUndecorated(false);
|
frame.setUndecorated(false);
|
||||||
frame.pack();
|
frame.pack();
|
||||||
frame.setSize(
|
frame.setSize(1280, 800);
|
||||||
UIScaling.scaleWidth(1280),
|
|
||||||
UIScaling.scaleHeight(800));
|
|
||||||
frame.setLocationRelativeTo(null);
|
frame.setLocationRelativeTo(null);
|
||||||
log.debug("Frame reconfigured");
|
log.debug("Frame reconfigured");
|
||||||
|
|
||||||
|
|||||||
@@ -1,22 +1,13 @@
|
|||||||
package stirling.software.SPDF.UI.impl;
|
package stirling.software.SPDF.UI.impl;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
|
||||||
import io.github.pixee.security.BoundedLineReader;
|
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.SPDF.utils.UIScaling;
|
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class LoadingWindow extends JDialog {
|
public class LoadingWindow extends JDialog {
|
||||||
private final JProgressBar progressBar;
|
private final JProgressBar progressBar;
|
||||||
@@ -25,13 +16,6 @@ public class LoadingWindow extends JDialog {
|
|||||||
private final JLabel brandLabel;
|
private final JLabel brandLabel;
|
||||||
private long startTime;
|
private long startTime;
|
||||||
|
|
||||||
private Timer stuckTimer;
|
|
||||||
private long stuckThreshold = 4000;
|
|
||||||
private long timeAt90Percent = -1;
|
|
||||||
private volatile Process explorerProcess;
|
|
||||||
private static final boolean IS_WINDOWS =
|
|
||||||
System.getProperty("os.name").toLowerCase().contains("win");
|
|
||||||
|
|
||||||
public LoadingWindow(Frame parent, String initialUrl) {
|
public LoadingWindow(Frame parent, String initialUrl) {
|
||||||
super(parent, "Initializing Stirling-PDF", true);
|
super(parent, "Initializing Stirling-PDF", true);
|
||||||
startTime = System.currentTimeMillis();
|
startTime = System.currentTimeMillis();
|
||||||
@@ -57,12 +41,12 @@ public class LoadingWindow extends JDialog {
|
|||||||
if (is != null) {
|
if (is != null) {
|
||||||
Image img = ImageIO.read(is);
|
Image img = ImageIO.read(is);
|
||||||
if (img != null) {
|
if (img != null) {
|
||||||
Image scaledImg = UIScaling.scaleIcon(img, 48, 48);
|
Image scaledImg = img.getScaledInstance(48, 48, Image.SCALE_SMOOTH);
|
||||||
JLabel iconLabel = new JLabel(new ImageIcon(scaledImg));
|
JLabel iconLabel = new JLabel(new ImageIcon(scaledImg));
|
||||||
iconLabel.setHorizontalAlignment(SwingConstants.CENTER);
|
iconLabel.setHorizontalAlignment(SwingConstants.CENTER);
|
||||||
gbc.gridy = 0;
|
gbc.gridy = 0;
|
||||||
mainPanel.add(iconLabel, gbc);
|
mainPanel.add(iconLabel, gbc);
|
||||||
log.info("Icon loaded and scaled successfully");
|
log.debug("Icon loaded and scaled successfully");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -99,8 +83,7 @@ public class LoadingWindow extends JDialog {
|
|||||||
setUndecorated(false);
|
setUndecorated(false);
|
||||||
|
|
||||||
// Set size and position
|
// Set size and position
|
||||||
setSize(UIScaling.scaleWidth(400), UIScaling.scaleHeight(200));
|
setSize(400, 200);
|
||||||
|
|
||||||
setLocationRelativeTo(parent);
|
setLocationRelativeTo(parent);
|
||||||
setAlwaysOnTop(true);
|
setAlwaysOnTop(true);
|
||||||
setProgress(0);
|
setProgress(0);
|
||||||
@@ -111,163 +94,6 @@ public class LoadingWindow extends JDialog {
|
|||||||
System.currentTimeMillis() - startTime);
|
System.currentTimeMillis() - startTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkAndRefreshExplorer() {
|
|
||||||
if (!IS_WINDOWS) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (timeAt90Percent == -1) {
|
|
||||||
timeAt90Percent = System.currentTimeMillis();
|
|
||||||
stuckTimer =
|
|
||||||
new Timer(
|
|
||||||
1000,
|
|
||||||
e -> {
|
|
||||||
long currentTime = System.currentTimeMillis();
|
|
||||||
if (currentTime - timeAt90Percent > stuckThreshold) {
|
|
||||||
try {
|
|
||||||
log.debug(
|
|
||||||
"Attempting Windows explorer refresh due to 90% stuck state");
|
|
||||||
String currentDir = System.getProperty("user.dir");
|
|
||||||
|
|
||||||
// Store current explorer PIDs before we start new one
|
|
||||||
Set<String> existingPids = new HashSet<>();
|
|
||||||
ProcessBuilder listExplorer =
|
|
||||||
new ProcessBuilder(
|
|
||||||
"cmd",
|
|
||||||
"/c",
|
|
||||||
"wmic",
|
|
||||||
"process",
|
|
||||||
"where",
|
|
||||||
"name='explorer.exe'",
|
|
||||||
"get",
|
|
||||||
"ProcessId",
|
|
||||||
"/format:csv");
|
|
||||||
Process process = listExplorer.start();
|
|
||||||
BufferedReader reader =
|
|
||||||
new BufferedReader(
|
|
||||||
new InputStreamReader(
|
|
||||||
process.getInputStream()));
|
|
||||||
String line;
|
|
||||||
while ((line =
|
|
||||||
BoundedLineReader.readLine(
|
|
||||||
reader, 5_000_000))
|
|
||||||
!= null) {
|
|
||||||
if (line.matches(".*\\d+.*")) { // Contains numbers
|
|
||||||
String[] parts = line.trim().split(",");
|
|
||||||
if (parts.length >= 2) {
|
|
||||||
existingPids.add(
|
|
||||||
parts[parts.length - 1].trim());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
process.waitFor(2, TimeUnit.SECONDS);
|
|
||||||
|
|
||||||
// Start new explorer
|
|
||||||
ProcessBuilder pb =
|
|
||||||
new ProcessBuilder(
|
|
||||||
"cmd",
|
|
||||||
"/c",
|
|
||||||
"start",
|
|
||||||
"/min",
|
|
||||||
"/b",
|
|
||||||
"explorer.exe",
|
|
||||||
currentDir);
|
|
||||||
pb.redirectErrorStream(true);
|
|
||||||
explorerProcess = pb.start();
|
|
||||||
|
|
||||||
// Schedule cleanup
|
|
||||||
Timer cleanupTimer =
|
|
||||||
new Timer(
|
|
||||||
2000,
|
|
||||||
cleanup -> {
|
|
||||||
try {
|
|
||||||
// Find new explorer processes
|
|
||||||
ProcessBuilder findNewExplorer =
|
|
||||||
new ProcessBuilder(
|
|
||||||
"cmd",
|
|
||||||
"/c",
|
|
||||||
"wmic",
|
|
||||||
"process",
|
|
||||||
"where",
|
|
||||||
"name='explorer.exe'",
|
|
||||||
"get",
|
|
||||||
"ProcessId",
|
|
||||||
"/format:csv");
|
|
||||||
Process newProcess =
|
|
||||||
findNewExplorer.start();
|
|
||||||
BufferedReader newReader =
|
|
||||||
new BufferedReader(
|
|
||||||
new InputStreamReader(
|
|
||||||
newProcess
|
|
||||||
.getInputStream()));
|
|
||||||
String newLine;
|
|
||||||
while ((newLine =
|
|
||||||
BoundedLineReader
|
|
||||||
.readLine(
|
|
||||||
newReader,
|
|
||||||
5_000_000))
|
|
||||||
!= null) {
|
|
||||||
if (newLine.matches(
|
|
||||||
".*\\d+.*")) {
|
|
||||||
String[] parts =
|
|
||||||
newLine.trim()
|
|
||||||
.split(",");
|
|
||||||
if (parts.length >= 2) {
|
|
||||||
String pid =
|
|
||||||
parts[
|
|
||||||
parts.length
|
|
||||||
- 1]
|
|
||||||
.trim();
|
|
||||||
if (!existingPids
|
|
||||||
.contains(
|
|
||||||
pid)) {
|
|
||||||
log.debug(
|
|
||||||
"Found new explorer.exe with PID: "
|
|
||||||
+ pid);
|
|
||||||
ProcessBuilder
|
|
||||||
killProcess =
|
|
||||||
new ProcessBuilder(
|
|
||||||
"taskkill",
|
|
||||||
"/PID",
|
|
||||||
pid,
|
|
||||||
"/F");
|
|
||||||
killProcess
|
|
||||||
.redirectErrorStream(
|
|
||||||
true);
|
|
||||||
Process killResult =
|
|
||||||
killProcess
|
|
||||||
.start();
|
|
||||||
killResult.waitFor(
|
|
||||||
2,
|
|
||||||
TimeUnit
|
|
||||||
.SECONDS);
|
|
||||||
log.debug(
|
|
||||||
"Explorer process terminated: "
|
|
||||||
+ pid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
newProcess.waitFor(
|
|
||||||
2, TimeUnit.SECONDS);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
log.error(
|
|
||||||
"Error cleaning up Windows explorer process",
|
|
||||||
ex);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
cleanupTimer.setRepeats(false);
|
|
||||||
cleanupTimer.start();
|
|
||||||
stuckTimer.stop();
|
|
||||||
} catch (Exception ex) {
|
|
||||||
log.error("Error refreshing Windows explorer", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
stuckTimer.setRepeats(true);
|
|
||||||
stuckTimer.start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setProgress(final int progress) {
|
public void setProgress(final int progress) {
|
||||||
SwingUtilities.invokeLater(
|
SwingUtilities.invokeLater(
|
||||||
() -> {
|
() -> {
|
||||||
@@ -289,23 +115,11 @@ public class LoadingWindow extends JDialog {
|
|||||||
|
|
||||||
// Add thread state logging
|
// Add thread state logging
|
||||||
Thread currentThread = Thread.currentThread();
|
Thread currentThread = Thread.currentThread();
|
||||||
log.info(
|
log.debug(
|
||||||
"Current thread state - Name: {}, State: {}, Priority: {}",
|
"Current thread state - Name: {}, State: {}, Priority: {}",
|
||||||
currentThread.getName(),
|
currentThread.getName(),
|
||||||
currentThread.getState(),
|
currentThread.getState(),
|
||||||
currentThread.getPriority());
|
currentThread.getPriority());
|
||||||
|
|
||||||
if (validProgress >= 90 && validProgress < 95) {
|
|
||||||
checkAndRefreshExplorer();
|
|
||||||
} else {
|
|
||||||
// Reset the timer if we move past 95%
|
|
||||||
if (validProgress >= 95) {
|
|
||||||
if (stuckTimer != null) {
|
|
||||||
stuckTimer.stop();
|
|
||||||
}
|
|
||||||
timeAt90Percent = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
progressBar.setValue(validProgress);
|
progressBar.setValue(validProgress);
|
||||||
@@ -331,7 +145,7 @@ public class LoadingWindow extends JDialog {
|
|||||||
statusLabel.setText(validStatus);
|
statusLabel.setText(validStatus);
|
||||||
|
|
||||||
// Log UI state when status changes
|
// Log UI state when status changes
|
||||||
log.info(
|
log.debug(
|
||||||
"UI State - Window visible: {}, Progress: {}%, Status: {}",
|
"UI State - Window visible: {}, Progress: {}%, Status: {}",
|
||||||
isVisible(), progressBar.getValue(), validStatus);
|
isVisible(), progressBar.getValue(), validStatus);
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import java.io.IOException;
|
|||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
@@ -20,7 +19,6 @@ import org.springframework.core.io.ResourceLoader;
|
|||||||
import org.thymeleaf.spring6.SpringTemplateEngine;
|
import org.thymeleaf.spring6.SpringTemplateEngine;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@@ -35,7 +33,10 @@ public class AppConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnProperty(name = "system.customHTMLFiles", havingValue = "true")
|
@ConditionalOnProperty(
|
||||||
|
name = "system.customHTMLFiles",
|
||||||
|
havingValue = "true",
|
||||||
|
matchIfMissing = false)
|
||||||
public SpringTemplateEngine templateEngine(ResourceLoader resourceLoader) {
|
public SpringTemplateEngine templateEngine(ResourceLoader resourceLoader) {
|
||||||
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
|
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
|
||||||
templateEngine.addTemplateResolver(new FileFallbackTemplateResolver(resourceLoader));
|
templateEngine.addTemplateResolver(new FileFallbackTemplateResolver(resourceLoader));
|
||||||
@@ -73,11 +74,6 @@ public class AppConfig {
|
|||||||
: "null";
|
: "null";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean(name = "languages")
|
|
||||||
public List<String> languages() {
|
|
||||||
return applicationProperties.getUi().getLanguages();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean(name = "navBarText")
|
@Bean(name = "navBarText")
|
||||||
public String navBarText() {
|
public String navBarText() {
|
||||||
String defaultNavBar =
|
String defaultNavBar =
|
||||||
@@ -96,9 +92,9 @@ public class AppConfig {
|
|||||||
|
|
||||||
@Bean(name = "rateLimit")
|
@Bean(name = "rateLimit")
|
||||||
public boolean rateLimit() {
|
public boolean rateLimit() {
|
||||||
String rateLimit = System.getProperty("rateLimit");
|
String appName = System.getProperty("rateLimit");
|
||||||
if (rateLimit == null) rateLimit = System.getenv("rateLimit");
|
if (appName == null) appName = System.getenv("rateLimit");
|
||||||
return (rateLimit != null) ? Boolean.valueOf(rateLimit) : false;
|
return (appName != null) ? Boolean.valueOf(appName) : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean(name = "RunningInDocker")
|
@Bean(name = "RunningInDocker")
|
||||||
@@ -125,9 +121,18 @@ public class AppConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean(name = "bookAndHtmlFormatsInstalled")
|
||||||
|
public boolean bookAndHtmlFormatsInstalled() {
|
||||||
|
String installOps = System.getProperty("INSTALL_BOOK_AND_ADVANCED_HTML_OPS");
|
||||||
|
if (installOps == null) {
|
||||||
|
installOps = System.getenv("INSTALL_BOOK_AND_ADVANCED_HTML_OPS");
|
||||||
|
}
|
||||||
|
return "true".equalsIgnoreCase(installOps);
|
||||||
|
}
|
||||||
|
|
||||||
@ConditionalOnMissingClass("stirling.software.SPDF.config.security.SecurityConfiguration")
|
@ConditionalOnMissingClass("stirling.software.SPDF.config.security.SecurityConfiguration")
|
||||||
@Bean(name = "activeSecurity")
|
@Bean(name = "activSecurity")
|
||||||
public boolean missingActiveSecurity() {
|
public boolean missingActivSecurity() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,14 +175,16 @@ public class AppConfig {
|
|||||||
@Bean(name = "analyticsPrompt")
|
@Bean(name = "analyticsPrompt")
|
||||||
@Scope("request")
|
@Scope("request")
|
||||||
public boolean analyticsPrompt() {
|
public boolean analyticsPrompt() {
|
||||||
return applicationProperties.getSystem().getEnableAnalytics() == null;
|
return applicationProperties.getSystem().getEnableAnalytics() == null
|
||||||
|
|| "undefined".equals(applicationProperties.getSystem().getEnableAnalytics());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean(name = "analyticsEnabled")
|
@Bean(name = "analyticsEnabled")
|
||||||
@Scope("request")
|
@Scope("request")
|
||||||
public boolean analyticsEnabled() {
|
public boolean analyticsEnabled() {
|
||||||
if (applicationProperties.getEnterpriseEdition().isEnabled()) return true;
|
if (applicationProperties.getEnterpriseEdition().isEnabled()) return true;
|
||||||
return applicationProperties.getSystem().isAnalyticsEnabled();
|
return applicationProperties.getSystem().getEnableAnalytics() != null
|
||||||
|
&& Boolean.parseBoolean(applicationProperties.getSystem().getEnableAnalytics());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean(name = "StirlingPDFLabel")
|
@Bean(name = "StirlingPDFLabel")
|
||||||
|
|||||||
@@ -2,13 +2,13 @@ package stirling.software.SPDF.config;
|
|||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.context.annotation.Scope;
|
import org.springframework.context.annotation.Scope;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import stirling.software.SPDF.config.interfaces.ShowAdminInterface;
|
import stirling.software.SPDF.config.interfaces.ShowAdminInterface;
|
||||||
import stirling.software.SPDF.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
|
|
||||||
@Configuration
|
@Service
|
||||||
class AppUpdateService {
|
class AppUpdateService {
|
||||||
|
|
||||||
private final ApplicationProperties applicationProperties;
|
private final ApplicationProperties applicationProperties;
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ public class CleanUrlInterceptor implements HandlerInterceptor {
|
|||||||
"endpoints",
|
"endpoints",
|
||||||
"logout",
|
"logout",
|
||||||
"error",
|
"error",
|
||||||
"errorOAuth",
|
"erroroauth",
|
||||||
"file",
|
"file",
|
||||||
"messageType",
|
"messageType",
|
||||||
"infoMessage");
|
"infoMessage");
|
||||||
|
|||||||
@@ -9,71 +9,135 @@ import java.nio.file.Files;
|
|||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.nio.file.StandardCopyOption;
|
import java.nio.file.StandardCopyOption;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.simpleyaml.configuration.comments.CommentType;
|
||||||
|
import org.simpleyaml.configuration.file.YamlFile;
|
||||||
|
import org.simpleyaml.configuration.implementation.SimpleYamlImplementation;
|
||||||
|
import org.simpleyaml.configuration.implementation.snakeyaml.lib.DumperOptions;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
/**
|
|
||||||
* A naive, line-based approach to merging "settings.yml" with "settings.yml.template" while
|
|
||||||
* preserving exact whitespace, blank lines, and inline comments -- but we only rewrite the file if
|
|
||||||
* the merged content actually differs.
|
|
||||||
*/
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class ConfigInitializer {
|
public class ConfigInitializer {
|
||||||
|
|
||||||
public void ensureConfigExists() throws IOException, URISyntaxException {
|
public void ensureConfigExists() throws IOException, URISyntaxException {
|
||||||
// 1) If settings file doesn't exist, create from template
|
// Define the path to the external config directory
|
||||||
Path destPath = Paths.get(InstallationPathConfig.getSettingsPath());
|
Path destPath = Paths.get(InstallationPathConfig.getSettingsPath());
|
||||||
|
|
||||||
|
// Check if the file already exists
|
||||||
if (Files.notExists(destPath)) {
|
if (Files.notExists(destPath)) {
|
||||||
|
// Ensure the destination directory exists
|
||||||
Files.createDirectories(destPath.getParent());
|
Files.createDirectories(destPath.getParent());
|
||||||
|
|
||||||
|
// Copy the resource from classpath to the external directory
|
||||||
try (InputStream in =
|
try (InputStream in =
|
||||||
getClass().getClassLoader().getResourceAsStream("settings.yml.template")) {
|
getClass().getClassLoader().getResourceAsStream("settings.yml.template")) {
|
||||||
if (in == null) {
|
if (in != null) {
|
||||||
|
Files.copy(in, destPath);
|
||||||
|
} else {
|
||||||
throw new FileNotFoundException(
|
throw new FileNotFoundException(
|
||||||
"Resource file not found: settings.yml.template");
|
"Resource file not found: settings.yml.template");
|
||||||
}
|
}
|
||||||
Files.copy(in, destPath);
|
|
||||||
}
|
}
|
||||||
log.info("Created settings file from template");
|
log.info("Created settings file from template");
|
||||||
} else {
|
} else {
|
||||||
// 2) Merge existing file with the template
|
|
||||||
URL templateResource = getClass().getClassLoader().getResource("settings.yml.template");
|
// Define the path to the config settings file
|
||||||
if (templateResource == null) {
|
Path settingsPath = Paths.get(InstallationPathConfig.getSettingsPath());
|
||||||
|
// Load the template resource
|
||||||
|
URL settingsTemplateResource =
|
||||||
|
getClass().getClassLoader().getResource("settings.yml.template");
|
||||||
|
if (settingsTemplateResource == null) {
|
||||||
throw new IOException("Resource not found: settings.yml.template");
|
throw new IOException("Resource not found: settings.yml.template");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy template to a temp location so we can read lines
|
// Create a temporary file to copy the resource content
|
||||||
Path tempTemplatePath = Files.createTempFile("settings.yml", ".template");
|
Path tempTemplatePath = Files.createTempFile("settings.yml", ".template");
|
||||||
try (InputStream in = templateResource.openStream()) {
|
|
||||||
|
try (InputStream in = settingsTemplateResource.openStream()) {
|
||||||
Files.copy(in, tempTemplatePath, StandardCopyOption.REPLACE_EXISTING);
|
Files.copy(in, tempTemplatePath, StandardCopyOption.REPLACE_EXISTING);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy setting.yaml to a temp location so we can read lines
|
final YamlFile settingsTemplateFile = new YamlFile(tempTemplatePath.toFile());
|
||||||
Path settingTempPath = Files.createTempFile("settings", ".yaml");
|
DumperOptions yamlOptionsSettingsTemplateFile =
|
||||||
try (InputStream in = Files.newInputStream(destPath)) {
|
((SimpleYamlImplementation) settingsTemplateFile.getImplementation())
|
||||||
Files.copy(in, settingTempPath, StandardCopyOption.REPLACE_EXISTING);
|
.getDumperOptions();
|
||||||
|
yamlOptionsSettingsTemplateFile.setSplitLines(false);
|
||||||
|
settingsTemplateFile.loadWithComments();
|
||||||
|
|
||||||
|
final YamlFile settingsFile = new YamlFile(settingsPath.toFile());
|
||||||
|
DumperOptions yamlOptionsSettingsFile =
|
||||||
|
((SimpleYamlImplementation) settingsFile.getImplementation())
|
||||||
|
.getDumperOptions();
|
||||||
|
yamlOptionsSettingsFile.setSplitLines(false);
|
||||||
|
settingsFile.loadWithComments();
|
||||||
|
|
||||||
|
// Load headers and comments
|
||||||
|
String header = settingsTemplateFile.getHeader();
|
||||||
|
|
||||||
|
// Create a new file for temporary settings
|
||||||
|
final YamlFile tempSettingFile = new YamlFile(settingsPath.toFile());
|
||||||
|
DumperOptions yamlOptionsTempSettingFile =
|
||||||
|
((SimpleYamlImplementation) tempSettingFile.getImplementation())
|
||||||
|
.getDumperOptions();
|
||||||
|
yamlOptionsTempSettingFile.setSplitLines(false);
|
||||||
|
tempSettingFile.createNewFile(true);
|
||||||
|
tempSettingFile.setHeader(header);
|
||||||
|
|
||||||
|
// Get all keys from the template
|
||||||
|
List<String> keys =
|
||||||
|
Arrays.asList(settingsTemplateFile.getKeys(true).toArray(new String[0]));
|
||||||
|
|
||||||
|
for (String key : keys) {
|
||||||
|
if (!key.contains(".")) {
|
||||||
|
// Add blank lines and comments to specific sections
|
||||||
|
tempSettingFile
|
||||||
|
.path(key)
|
||||||
|
.comment(settingsTemplateFile.getComment(key))
|
||||||
|
.blankLine();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Copy settings from the template to the settings.yml file
|
||||||
|
changeConfigItemFromCommentToKeyValue(
|
||||||
|
settingsTemplateFile, settingsFile, tempSettingFile, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
YamlHelper settingsTemplateFile = new YamlHelper(tempTemplatePath);
|
// Save the settings.yml file
|
||||||
YamlHelper settingsFile = new YamlHelper(settingTempPath);
|
tempSettingFile.save();
|
||||||
|
|
||||||
boolean changesMade =
|
|
||||||
settingsTemplateFile.updateValuesFromYaml(settingsFile, settingsTemplateFile);
|
|
||||||
if (changesMade) {
|
|
||||||
settingsTemplateFile.save(destPath);
|
|
||||||
log.info("Settings file updated based on template changes.");
|
|
||||||
} else {
|
|
||||||
log.info("No changes detected; settings file left as-is.");
|
|
||||||
}
|
|
||||||
|
|
||||||
Files.deleteIfExists(tempTemplatePath);
|
|
||||||
Files.deleteIfExists(settingTempPath);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3) Ensure custom settings file exists
|
// Create custom settings file if it doesn't exist
|
||||||
Path customSettingsPath = Paths.get(InstallationPathConfig.getCustomSettingsPath());
|
Path customSettingsPath = Paths.get(InstallationPathConfig.getCustomSettingsPath());
|
||||||
if (Files.notExists(customSettingsPath)) {
|
if (!Files.exists(customSettingsPath)) {
|
||||||
Files.createFile(customSettingsPath);
|
Files.createFile(customSettingsPath);
|
||||||
log.info("Created custom_settings file: {}", customSettingsPath.toString());
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void changeConfigItemFromCommentToKeyValue(
|
||||||
|
final YamlFile settingsTemplateFile,
|
||||||
|
final YamlFile settingsFile,
|
||||||
|
final YamlFile tempSettingFile,
|
||||||
|
String path) {
|
||||||
|
if (settingsFile.get(path) == null && settingsTemplateFile.get(path) != null) {
|
||||||
|
// If the key is only in the template, add it to the temporary settings with comments
|
||||||
|
tempSettingFile
|
||||||
|
.path(path)
|
||||||
|
.set(settingsTemplateFile.get(path))
|
||||||
|
.comment(settingsTemplateFile.getComment(path, CommentType.BLOCK))
|
||||||
|
.commentSide(settingsTemplateFile.getComment(path, CommentType.SIDE));
|
||||||
|
} else if (settingsFile.get(path) != null && settingsTemplateFile.get(path) != null) {
|
||||||
|
// If the key is in both, update the temporary settings with the main settings' value
|
||||||
|
// and comments
|
||||||
|
tempSettingFile
|
||||||
|
.path(path)
|
||||||
|
.set(settingsFile.get(path))
|
||||||
|
.comment(settingsTemplateFile.getComment(path, CommentType.BLOCK))
|
||||||
|
.commentSide(settingsTemplateFile.getComment(path, CommentType.SIDE));
|
||||||
|
} else {
|
||||||
|
// Log if the key is not found in both YAML files
|
||||||
|
log.info("Key not found in both YAML files: " + path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package stirling.software.SPDF.config;
|
package stirling.software.SPDF.config;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -8,24 +9,30 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.context.annotation.DependsOn;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@DependsOn({"bookAndHtmlFormatsInstalled"})
|
||||||
public class EndpointConfiguration {
|
public class EndpointConfiguration {
|
||||||
|
|
||||||
private static final String REMOVE_BLANKS = "remove-blanks";
|
private static final String REMOVE_BLANKS = "remove-blanks";
|
||||||
private final ApplicationProperties applicationProperties;
|
private final ApplicationProperties applicationProperties;
|
||||||
private Map<String, Boolean> endpointStatuses = new ConcurrentHashMap<>();
|
private Map<String, Boolean> endpointStatuses = new ConcurrentHashMap<>();
|
||||||
private Map<String, Set<String>> endpointGroups = new ConcurrentHashMap<>();
|
private Map<String, Set<String>> endpointGroups = new ConcurrentHashMap<>();
|
||||||
|
private boolean bookAndHtmlFormatsInstalled;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public EndpointConfiguration(ApplicationProperties applicationProperties) {
|
public EndpointConfiguration(
|
||||||
|
ApplicationProperties applicationProperties,
|
||||||
|
@Qualifier("bookAndHtmlFormatsInstalled") boolean bookAndHtmlFormatsInstalled) {
|
||||||
this.applicationProperties = applicationProperties;
|
this.applicationProperties = applicationProperties;
|
||||||
|
this.bookAndHtmlFormatsInstalled = bookAndHtmlFormatsInstalled;
|
||||||
init();
|
init();
|
||||||
processEnvironmentConfigs();
|
processEnvironmentConfigs();
|
||||||
}
|
}
|
||||||
@@ -119,7 +126,6 @@ public class EndpointConfiguration {
|
|||||||
addEndpointToGroup("Convert", "url-to-pdf");
|
addEndpointToGroup("Convert", "url-to-pdf");
|
||||||
addEndpointToGroup("Convert", "markdown-to-pdf");
|
addEndpointToGroup("Convert", "markdown-to-pdf");
|
||||||
addEndpointToGroup("Convert", "pdf-to-csv");
|
addEndpointToGroup("Convert", "pdf-to-csv");
|
||||||
addEndpointToGroup("Convert", "pdf-to-markdown");
|
|
||||||
|
|
||||||
// Adding endpoints to "Security" group
|
// Adding endpoints to "Security" group
|
||||||
addEndpointToGroup("Security", "add-password");
|
addEndpointToGroup("Security", "add-password");
|
||||||
@@ -130,7 +136,6 @@ public class EndpointConfiguration {
|
|||||||
addEndpointToGroup("Security", "remove-cert-sign");
|
addEndpointToGroup("Security", "remove-cert-sign");
|
||||||
addEndpointToGroup("Security", "sanitize-pdf");
|
addEndpointToGroup("Security", "sanitize-pdf");
|
||||||
addEndpointToGroup("Security", "auto-redact");
|
addEndpointToGroup("Security", "auto-redact");
|
||||||
addEndpointToGroup("Security", "redact");
|
|
||||||
|
|
||||||
// Adding endpoints to "Other" group
|
// Adding endpoints to "Other" group
|
||||||
addEndpointToGroup("Other", "ocr-pdf");
|
addEndpointToGroup("Other", "ocr-pdf");
|
||||||
@@ -176,6 +181,7 @@ public class EndpointConfiguration {
|
|||||||
addEndpointToGroup("Python", "extract-image-scans");
|
addEndpointToGroup("Python", "extract-image-scans");
|
||||||
addEndpointToGroup("Python", "html-to-pdf");
|
addEndpointToGroup("Python", "html-to-pdf");
|
||||||
addEndpointToGroup("Python", "url-to-pdf");
|
addEndpointToGroup("Python", "url-to-pdf");
|
||||||
|
addEndpointToGroup("Python", "pdf-to-img");
|
||||||
addEndpointToGroup("Python", "file-to-pdf");
|
addEndpointToGroup("Python", "file-to-pdf");
|
||||||
|
|
||||||
// openCV
|
// openCV
|
||||||
@@ -190,8 +196,8 @@ public class EndpointConfiguration {
|
|||||||
addEndpointToGroup("LibreOffice", "pdf-to-html");
|
addEndpointToGroup("LibreOffice", "pdf-to-html");
|
||||||
addEndpointToGroup("LibreOffice", "pdf-to-xml");
|
addEndpointToGroup("LibreOffice", "pdf-to-xml");
|
||||||
|
|
||||||
// Unoconvert
|
// Unoconv
|
||||||
addEndpointToGroup("Unoconvert", "file-to-pdf");
|
addEndpointToGroup("Unoconv", "file-to-pdf");
|
||||||
|
|
||||||
// qpdf
|
// qpdf
|
||||||
addEndpointToGroup("qpdf", "compress-pdf");
|
addEndpointToGroup("qpdf", "compress-pdf");
|
||||||
@@ -229,7 +235,6 @@ public class EndpointConfiguration {
|
|||||||
addEndpointToGroup("Java", "markdown-to-pdf");
|
addEndpointToGroup("Java", "markdown-to-pdf");
|
||||||
addEndpointToGroup("Java", "show-javascript");
|
addEndpointToGroup("Java", "show-javascript");
|
||||||
addEndpointToGroup("Java", "auto-redact");
|
addEndpointToGroup("Java", "auto-redact");
|
||||||
addEndpointToGroup("Java", "redact");
|
|
||||||
addEndpointToGroup("Java", "pdf-to-csv");
|
addEndpointToGroup("Java", "pdf-to-csv");
|
||||||
addEndpointToGroup("Java", "split-by-size-or-count");
|
addEndpointToGroup("Java", "split-by-size-or-count");
|
||||||
addEndpointToGroup("Java", "overlay-pdf");
|
addEndpointToGroup("Java", "overlay-pdf");
|
||||||
@@ -237,7 +242,6 @@ public class EndpointConfiguration {
|
|||||||
addEndpointToGroup("Java", REMOVE_BLANKS);
|
addEndpointToGroup("Java", REMOVE_BLANKS);
|
||||||
addEndpointToGroup("Java", "pdf-to-text");
|
addEndpointToGroup("Java", "pdf-to-text");
|
||||||
addEndpointToGroup("Java", "remove-image-pdf");
|
addEndpointToGroup("Java", "remove-image-pdf");
|
||||||
addEndpointToGroup("Java", "pdf-to-markdown");
|
|
||||||
|
|
||||||
// Javascript
|
// Javascript
|
||||||
addEndpointToGroup("Javascript", "pdf-organizer");
|
addEndpointToGroup("Javascript", "pdf-organizer");
|
||||||
@@ -253,11 +257,12 @@ public class EndpointConfiguration {
|
|||||||
// Weasyprint dependent endpoints
|
// Weasyprint dependent endpoints
|
||||||
addEndpointToGroup("Weasyprint", "html-to-pdf");
|
addEndpointToGroup("Weasyprint", "html-to-pdf");
|
||||||
addEndpointToGroup("Weasyprint", "url-to-pdf");
|
addEndpointToGroup("Weasyprint", "url-to-pdf");
|
||||||
addEndpointToGroup("Weasyprint", "markdown-to-pdf");
|
|
||||||
|
|
||||||
// Pdftohtml dependent endpoints
|
// Pdftohtml dependent endpoints
|
||||||
addEndpointToGroup("Pdftohtml", "pdf-to-html");
|
addEndpointToGroup("Pdftohtml", "pdf-to-html");
|
||||||
addEndpointToGroup("Pdftohtml", "pdf-to-markdown");
|
|
||||||
|
// disabled for now while we resolve issues
|
||||||
|
disableEndpoint("pdf-to-pdfa");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processEnvironmentConfigs() {
|
private void processEnvironmentConfigs() {
|
||||||
@@ -265,6 +270,12 @@ public class EndpointConfiguration {
|
|||||||
List<String> endpointsToRemove = applicationProperties.getEndpoints().getToRemove();
|
List<String> endpointsToRemove = applicationProperties.getEndpoints().getToRemove();
|
||||||
List<String> groupsToRemove = applicationProperties.getEndpoints().getGroupsToRemove();
|
List<String> groupsToRemove = applicationProperties.getEndpoints().getGroupsToRemove();
|
||||||
|
|
||||||
|
if (!bookAndHtmlFormatsInstalled) {
|
||||||
|
if (groupsToRemove == null) {
|
||||||
|
groupsToRemove = new ArrayList<>();
|
||||||
|
}
|
||||||
|
groupsToRemove.add("Calibre");
|
||||||
|
}
|
||||||
if (endpointsToRemove != null) {
|
if (endpointsToRemove != null) {
|
||||||
for (String endpoint : endpointsToRemove) {
|
for (String endpoint : endpointsToRemove) {
|
||||||
disableEndpoint(endpoint.trim());
|
disableEndpoint(endpoint.trim());
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import java.util.stream.Collectors;
|
|||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
import jakarta.annotation.PostConstruct;
|
import jakarta.annotation.PostConstruct;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@@ -17,29 +16,21 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
public class ExternalAppDepConfig {
|
public class ExternalAppDepConfig {
|
||||||
|
|
||||||
private final EndpointConfiguration endpointConfiguration;
|
private final EndpointConfiguration endpointConfiguration;
|
||||||
|
private final Map<String, List<String>> commandToGroupMapping =
|
||||||
|
new HashMap<>() {
|
||||||
|
|
||||||
private final String weasyprintPath;
|
{
|
||||||
private final String unoconvPath;
|
put("soffice", List.of("LibreOffice"));
|
||||||
private final Map<String, List<String>> commandToGroupMapping;
|
put("weasyprint", List.of("Weasyprint"));
|
||||||
|
put("pdftohtml", List.of("Pdftohtml"));
|
||||||
|
put("unoconv", List.of("Unoconv"));
|
||||||
|
put("qpdf", List.of("qpdf"));
|
||||||
|
put("tesseract", List.of("tesseract"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
public ExternalAppDepConfig(
|
public ExternalAppDepConfig(EndpointConfiguration endpointConfiguration) {
|
||||||
EndpointConfiguration endpointConfiguration, RuntimePathConfig runtimePathConfig) {
|
|
||||||
this.endpointConfiguration = endpointConfiguration;
|
this.endpointConfiguration = endpointConfiguration;
|
||||||
weasyprintPath = runtimePathConfig.getWeasyPrintPath();
|
|
||||||
unoconvPath = runtimePathConfig.getUnoConvertPath();
|
|
||||||
|
|
||||||
commandToGroupMapping =
|
|
||||||
new HashMap<>() {
|
|
||||||
|
|
||||||
{
|
|
||||||
put("soffice", List.of("LibreOffice"));
|
|
||||||
put(weasyprintPath, List.of("Weasyprint"));
|
|
||||||
put("pdftohtml", List.of("Pdftohtml"));
|
|
||||||
put(unoconvPath, List.of("Unoconvert"));
|
|
||||||
put("qpdf", List.of("qpdf"));
|
|
||||||
put("tesseract", List.of("tesseract"));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isCommandAvailable(String command) {
|
private boolean isCommandAvailable(String command) {
|
||||||
@@ -110,9 +101,9 @@ public class ExternalAppDepConfig {
|
|||||||
checkDependencyAndDisableGroup("tesseract");
|
checkDependencyAndDisableGroup("tesseract");
|
||||||
checkDependencyAndDisableGroup("soffice");
|
checkDependencyAndDisableGroup("soffice");
|
||||||
checkDependencyAndDisableGroup("qpdf");
|
checkDependencyAndDisableGroup("qpdf");
|
||||||
checkDependencyAndDisableGroup(weasyprintPath);
|
checkDependencyAndDisableGroup("weasyprint");
|
||||||
checkDependencyAndDisableGroup("pdftohtml");
|
checkDependencyAndDisableGroup("pdftohtml");
|
||||||
checkDependencyAndDisableGroup(unoconvPath);
|
checkDependencyAndDisableGroup("unoconv");
|
||||||
// Special handling for Python/OpenCV dependencies
|
// Special handling for Python/OpenCV dependencies
|
||||||
boolean pythonAvailable = isCommandAvailable("python3") || isCommandAvailable("python");
|
boolean pythonAvailable = isCommandAvailable("python3") || isCommandAvailable("python");
|
||||||
if (!pythonAvailable) {
|
if (!pythonAvailable) {
|
||||||
|
|||||||
@@ -13,9 +13,7 @@ import org.springframework.stereotype.Component;
|
|||||||
import io.micrometer.common.util.StringUtils;
|
import io.micrometer.common.util.StringUtils;
|
||||||
|
|
||||||
import jakarta.annotation.PostConstruct;
|
import jakarta.annotation.PostConstruct;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import stirling.software.SPDF.model.ApplicationProperties;
|
import stirling.software.SPDF.model.ApplicationProperties;
|
||||||
import stirling.software.SPDF.utils.GeneralUtils;
|
import stirling.software.SPDF.utils.GeneralUtils;
|
||||||
|
|
||||||
@@ -44,7 +42,7 @@ public class InitialSetup {
|
|||||||
if (!GeneralUtils.isValidUUID(uuid)) {
|
if (!GeneralUtils.isValidUUID(uuid)) {
|
||||||
// Generating a random UUID as the secret key
|
// Generating a random UUID as the secret key
|
||||||
uuid = UUID.randomUUID().toString();
|
uuid = UUID.randomUUID().toString();
|
||||||
GeneralUtils.saveKeyToSettings("AutomaticallyGenerated.UUID", uuid);
|
GeneralUtils.saveKeyToConfig("AutomaticallyGenerated.UUID", uuid);
|
||||||
applicationProperties.getAutomaticallyGenerated().setUUID(uuid);
|
applicationProperties.getAutomaticallyGenerated().setUUID(uuid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -54,7 +52,7 @@ public class InitialSetup {
|
|||||||
if (!GeneralUtils.isValidUUID(secretKey)) {
|
if (!GeneralUtils.isValidUUID(secretKey)) {
|
||||||
// Generating a random UUID as the secret key
|
// Generating a random UUID as the secret key
|
||||||
secretKey = UUID.randomUUID().toString();
|
secretKey = UUID.randomUUID().toString();
|
||||||
GeneralUtils.saveKeyToSettings("AutomaticallyGenerated.key", secretKey);
|
GeneralUtils.saveKeyToConfig("AutomaticallyGenerated.key", secretKey);
|
||||||
applicationProperties.getAutomaticallyGenerated().setKey(secretKey);
|
applicationProperties.getAutomaticallyGenerated().setKey(secretKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -64,8 +62,8 @@ public class InitialSetup {
|
|||||||
"0.36.0", applicationProperties.getAutomaticallyGenerated().getAppVersion())) {
|
"0.36.0", applicationProperties.getAutomaticallyGenerated().getAppVersion())) {
|
||||||
Boolean csrf = applicationProperties.getSecurity().getCsrfDisabled();
|
Boolean csrf = applicationProperties.getSecurity().getCsrfDisabled();
|
||||||
if (!csrf) {
|
if (!csrf) {
|
||||||
GeneralUtils.saveKeyToSettings("security.csrfDisabled", false);
|
GeneralUtils.saveKeyToConfig("security.csrfDisabled", false, false);
|
||||||
GeneralUtils.saveKeyToSettings("system.enableAnalytics", true);
|
GeneralUtils.saveKeyToConfig("system.enableAnalytics", "true", false);
|
||||||
applicationProperties.getSecurity().setCsrfDisabled(false);
|
applicationProperties.getSecurity().setCsrfDisabled(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -76,14 +74,14 @@ public class InitialSetup {
|
|||||||
String termsUrl = applicationProperties.getLegal().getTermsAndConditions();
|
String termsUrl = applicationProperties.getLegal().getTermsAndConditions();
|
||||||
if (StringUtils.isEmpty(termsUrl)) {
|
if (StringUtils.isEmpty(termsUrl)) {
|
||||||
String defaultTermsUrl = "https://www.stirlingpdf.com/terms-and-conditions";
|
String defaultTermsUrl = "https://www.stirlingpdf.com/terms-and-conditions";
|
||||||
GeneralUtils.saveKeyToSettings("legal.termsAndConditions", defaultTermsUrl);
|
GeneralUtils.saveKeyToConfig("legal.termsAndConditions", defaultTermsUrl, false);
|
||||||
applicationProperties.getLegal().setTermsAndConditions(defaultTermsUrl);
|
applicationProperties.getLegal().setTermsAndConditions(defaultTermsUrl);
|
||||||
}
|
}
|
||||||
// Initialize Privacy Policy
|
// Initialize Privacy Policy
|
||||||
String privacyUrl = applicationProperties.getLegal().getPrivacyPolicy();
|
String privacyUrl = applicationProperties.getLegal().getPrivacyPolicy();
|
||||||
if (StringUtils.isEmpty(privacyUrl)) {
|
if (StringUtils.isEmpty(privacyUrl)) {
|
||||||
String defaultPrivacyUrl = "https://www.stirlingpdf.com/privacy-policy";
|
String defaultPrivacyUrl = "https://www.stirlingpdf.com/privacy-policy";
|
||||||
GeneralUtils.saveKeyToSettings("legal.privacyPolicy", defaultPrivacyUrl);
|
GeneralUtils.saveKeyToConfig("legal.privacyPolicy", defaultPrivacyUrl, false);
|
||||||
applicationProperties.getLegal().setPrivacyPolicy(defaultPrivacyUrl);
|
applicationProperties.getLegal().setPrivacyPolicy(defaultPrivacyUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -97,7 +95,7 @@ public class InitialSetup {
|
|||||||
appVersion = props.getProperty("version");
|
appVersion = props.getProperty("version");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
}
|
}
|
||||||
GeneralUtils.saveKeyToSettings("AutomaticallyGenerated.appVersion", appVersion);
|
|
||||||
applicationProperties.getAutomaticallyGenerated().setAppVersion(appVersion);
|
applicationProperties.getAutomaticallyGenerated().setAppVersion(appVersion);
|
||||||
|
GeneralUtils.saveKeyToConfig("AutomaticallyGenerated.appVersion", appVersion, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package stirling.software.SPDF.config;
|
package stirling.software.SPDF.config;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.nio.file.Paths;
|
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
@@ -12,6 +11,7 @@ public class InstallationPathConfig {
|
|||||||
// Root paths
|
// Root paths
|
||||||
private static final String LOG_PATH;
|
private static final String LOG_PATH;
|
||||||
private static final String CONFIG_PATH;
|
private static final String CONFIG_PATH;
|
||||||
|
private static final String PIPELINE_PATH;
|
||||||
private static final String CUSTOM_FILES_PATH;
|
private static final String CUSTOM_FILES_PATH;
|
||||||
private static final String CLIENT_WEBUI_PATH;
|
private static final String CLIENT_WEBUI_PATH;
|
||||||
|
|
||||||
@@ -19,6 +19,10 @@ public class InstallationPathConfig {
|
|||||||
private static final String SETTINGS_PATH;
|
private static final String SETTINGS_PATH;
|
||||||
private static final String CUSTOM_SETTINGS_PATH;
|
private static final String CUSTOM_SETTINGS_PATH;
|
||||||
|
|
||||||
|
// Pipeline paths
|
||||||
|
private static final String PIPELINE_WATCHED_FOLDERS_PATH;
|
||||||
|
private static final String PIPELINE_FINISHED_FOLDERS_PATH;
|
||||||
|
|
||||||
// Custom file paths
|
// Custom file paths
|
||||||
private static final String STATIC_PATH;
|
private static final String STATIC_PATH;
|
||||||
private static final String TEMPLATES_PATH;
|
private static final String TEMPLATES_PATH;
|
||||||
@@ -30,6 +34,7 @@ public class InstallationPathConfig {
|
|||||||
// Initialize root paths
|
// Initialize root paths
|
||||||
LOG_PATH = BASE_PATH + "logs" + File.separator;
|
LOG_PATH = BASE_PATH + "logs" + File.separator;
|
||||||
CONFIG_PATH = BASE_PATH + "configs" + File.separator;
|
CONFIG_PATH = BASE_PATH + "configs" + File.separator;
|
||||||
|
PIPELINE_PATH = BASE_PATH + "pipeline" + File.separator;
|
||||||
CUSTOM_FILES_PATH = BASE_PATH + "customFiles" + File.separator;
|
CUSTOM_FILES_PATH = BASE_PATH + "customFiles" + File.separator;
|
||||||
CLIENT_WEBUI_PATH = BASE_PATH + "clientWebUI" + File.separator;
|
CLIENT_WEBUI_PATH = BASE_PATH + "clientWebUI" + File.separator;
|
||||||
|
|
||||||
@@ -37,6 +42,10 @@ public class InstallationPathConfig {
|
|||||||
SETTINGS_PATH = CONFIG_PATH + "settings.yml";
|
SETTINGS_PATH = CONFIG_PATH + "settings.yml";
|
||||||
CUSTOM_SETTINGS_PATH = CONFIG_PATH + "custom_settings.yml";
|
CUSTOM_SETTINGS_PATH = CONFIG_PATH + "custom_settings.yml";
|
||||||
|
|
||||||
|
// Initialize pipeline paths
|
||||||
|
PIPELINE_WATCHED_FOLDERS_PATH = PIPELINE_PATH + "watchedFolders" + File.separator;
|
||||||
|
PIPELINE_FINISHED_FOLDERS_PATH = PIPELINE_PATH + "finishedFolders" + File.separator;
|
||||||
|
|
||||||
// Initialize custom file paths
|
// Initialize custom file paths
|
||||||
STATIC_PATH = CUSTOM_FILES_PATH + "static" + File.separator;
|
STATIC_PATH = CUSTOM_FILES_PATH + "static" + File.separator;
|
||||||
TEMPLATES_PATH = CUSTOM_FILES_PATH + "templates" + File.separator;
|
TEMPLATES_PATH = CUSTOM_FILES_PATH + "templates" + File.separator;
|
||||||
@@ -47,29 +56,26 @@ public class InstallationPathConfig {
|
|||||||
if (Boolean.parseBoolean(System.getProperty("STIRLING_PDF_DESKTOP_UI", "false"))) {
|
if (Boolean.parseBoolean(System.getProperty("STIRLING_PDF_DESKTOP_UI", "false"))) {
|
||||||
String os = System.getProperty("os.name").toLowerCase();
|
String os = System.getProperty("os.name").toLowerCase();
|
||||||
if (os.contains("win")) {
|
if (os.contains("win")) {
|
||||||
return Paths.get(
|
return System.getenv("APPDATA") + File.separator + "Stirling-PDF" + File.separator;
|
||||||
System.getenv("APPDATA"), // parent path
|
|
||||||
"Stirling-PDF")
|
|
||||||
.toString()
|
|
||||||
+ File.separator;
|
|
||||||
} else if (os.contains("mac")) {
|
} else if (os.contains("mac")) {
|
||||||
return Paths.get(
|
return System.getProperty("user.home")
|
||||||
System.getProperty("user.home"),
|
+ File.separator
|
||||||
"Library",
|
+ "Library"
|
||||||
"Application Support",
|
+ File.separator
|
||||||
"Stirling-PDF")
|
+ "Application Support"
|
||||||
.toString()
|
+ File.separator
|
||||||
|
+ "Stirling-PDF"
|
||||||
+ File.separator;
|
+ File.separator;
|
||||||
} else {
|
} else {
|
||||||
return Paths.get(
|
return System.getProperty("user.home")
|
||||||
System.getProperty("user.home"), // parent path
|
+ File.separator
|
||||||
".config",
|
+ ".config"
|
||||||
"Stirling-PDF")
|
+ File.separator
|
||||||
.toString()
|
+ "Stirling-PDF"
|
||||||
+ File.separator;
|
+ File.separator;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "." + File.separator;
|
return "./";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getPath() {
|
public static String getPath() {
|
||||||
@@ -84,6 +90,10 @@ public class InstallationPathConfig {
|
|||||||
return CONFIG_PATH;
|
return CONFIG_PATH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getPipelinePath() {
|
||||||
|
return PIPELINE_PATH;
|
||||||
|
}
|
||||||
|
|
||||||
public static String getCustomFilesPath() {
|
public static String getCustomFilesPath() {
|
||||||
return CUSTOM_FILES_PATH;
|
return CUSTOM_FILES_PATH;
|
||||||
}
|
}
|
||||||
@@ -100,6 +110,14 @@ public class InstallationPathConfig {
|
|||||||
return CUSTOM_SETTINGS_PATH;
|
return CUSTOM_SETTINGS_PATH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getPipelineWatchedFoldersDir() {
|
||||||
|
return PIPELINE_WATCHED_FOLDERS_PATH;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getPipelineFinishedFoldersDir() {
|
||||||
|
return PIPELINE_FINISHED_FOLDERS_PATH;
|
||||||
|
}
|
||||||
|
|
||||||
public static String getStaticPath() {
|
public static String getStaticPath() {
|
||||||
return STATIC_PATH;
|
return STATIC_PATH;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import jakarta.servlet.ServletException;
|
|||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import jakarta.servlet.http.HttpSession;
|
import jakarta.servlet.http.HttpSession;
|
||||||
|
|
||||||
import stirling.software.SPDF.utils.RequestUriUtils;
|
import stirling.software.SPDF.utils.RequestUriUtils;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
|
|||||||
@@ -8,10 +8,7 @@ import com.posthog.java.PostHog;
|
|||||||
|
|
||||||
import jakarta.annotation.PreDestroy;
|
import jakarta.annotation.PreDestroy;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@Slf4j
|
|
||||||
public class PostHogConfig {
|
public class PostHogConfig {
|
||||||
|
|
||||||
@Value("${posthog.api.key}")
|
@Value("${posthog.api.key}")
|
||||||
@@ -24,11 +21,7 @@ public class PostHogConfig {
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public PostHog postHogClient() {
|
public PostHog postHogClient() {
|
||||||
postHogClient =
|
postHogClient = new PostHog.Builder(posthogApiKey).host(posthogHost).build();
|
||||||
new PostHog.Builder(posthogApiKey)
|
|
||||||
.host(posthogHost)
|
|
||||||
.logger(new PostHogLoggerImpl())
|
|
||||||
.build();
|
|
||||||
return postHogClient;
|
return postHogClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,42 +0,0 @@
|
|||||||
package stirling.software.SPDF.config;
|
|
||||||
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import com.posthog.java.PostHogLogger;
|
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@Component
|
|
||||||
public class PostHogLoggerImpl implements PostHogLogger {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void debug(String message) {
|
|
||||||
log.debug(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void info(String message) {
|
|
||||||
log.info(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void warn(String message) {
|
|
||||||
log.warn(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void error(String message) {
|
|
||||||
log.error(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void error(String message, Throwable throwable) {
|
|
||||||
if (message.contains("Error sending events to PostHog")) {
|
|
||||||
log.warn(
|
|
||||||
"Error sending metrics, Likely caused by no internet connection. Non Blocking");
|
|
||||||
} else {
|
|
||||||
log.error(message, throwable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
package stirling.software.SPDF.config;
|
|
||||||
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
|
|
||||||
import stirling.software.SPDF.model.ApplicationProperties;
|
|
||||||
import stirling.software.SPDF.model.ApplicationProperties.CustomPaths.Operations;
|
|
||||||
import stirling.software.SPDF.model.ApplicationProperties.CustomPaths.Pipeline;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@Configuration
|
|
||||||
@Getter
|
|
||||||
public class RuntimePathConfig {
|
|
||||||
private final ApplicationProperties properties;
|
|
||||||
private final String basePath;
|
|
||||||
private final String weasyPrintPath;
|
|
||||||
private final String unoConvertPath;
|
|
||||||
|
|
||||||
// Pipeline paths
|
|
||||||
private final String pipelineWatchedFoldersPath;
|
|
||||||
private final String pipelineFinishedFoldersPath;
|
|
||||||
private final String pipelineDefaultWebUiConfigs;
|
|
||||||
private final String pipelinePath;
|
|
||||||
|
|
||||||
public RuntimePathConfig(ApplicationProperties properties) {
|
|
||||||
this.properties = properties;
|
|
||||||
this.basePath = InstallationPathConfig.getPath();
|
|
||||||
|
|
||||||
this.pipelinePath = Path.of(basePath, "pipeline").toString();
|
|
||||||
String defaultWatchedFolders = Path.of(this.pipelinePath, "watchedFolders").toString();
|
|
||||||
String defaultFinishedFolders = Path.of(this.pipelinePath, "finishedFolders").toString();
|
|
||||||
String defaultWebUIConfigs = Path.of(this.pipelinePath, "defaultWebUIConfigs").toString();
|
|
||||||
|
|
||||||
Pipeline pipeline = properties.getSystem().getCustomPaths().getPipeline();
|
|
||||||
|
|
||||||
this.pipelineWatchedFoldersPath =
|
|
||||||
resolvePath(
|
|
||||||
defaultWatchedFolders,
|
|
||||||
pipeline != null ? pipeline.getWatchedFoldersDir() : null);
|
|
||||||
this.pipelineFinishedFoldersPath =
|
|
||||||
resolvePath(
|
|
||||||
defaultFinishedFolders,
|
|
||||||
pipeline != null ? pipeline.getFinishedFoldersDir() : null);
|
|
||||||
this.pipelineDefaultWebUiConfigs =
|
|
||||||
resolvePath(
|
|
||||||
defaultWebUIConfigs,
|
|
||||||
pipeline != null ? pipeline.getWebUIConfigsDir() : null);
|
|
||||||
|
|
||||||
boolean isDocker = isRunningInDocker();
|
|
||||||
|
|
||||||
// Initialize Operation paths
|
|
||||||
String defaultWeasyPrintPath = isDocker ? "/opt/venv/bin/weasyprint" : "weasyprint";
|
|
||||||
String defaultUnoConvertPath = isDocker ? "/opt/venv/bin/unoconvert" : "unoconvert";
|
|
||||||
|
|
||||||
Operations operations = properties.getSystem().getCustomPaths().getOperations();
|
|
||||||
this.weasyPrintPath =
|
|
||||||
resolvePath(
|
|
||||||
defaultWeasyPrintPath,
|
|
||||||
operations != null ? operations.getWeasyprint() : null);
|
|
||||||
this.unoConvertPath =
|
|
||||||
resolvePath(
|
|
||||||
defaultUnoConvertPath,
|
|
||||||
operations != null ? operations.getUnoconvert() : null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String resolvePath(String defaultPath, String customPath) {
|
|
||||||
return StringUtils.isNotBlank(customPath) ? customPath : defaultPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isRunningInDocker() {
|
|
||||||
return Files.exists(Path.of("/.dockerenv"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,479 +0,0 @@
|
|||||||
package stirling.software.SPDF.config;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.StringWriter;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.ArrayDeque;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Deque;
|
|
||||||
import java.util.LinkedHashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
import org.snakeyaml.engine.v2.api.Dump;
|
|
||||||
import org.snakeyaml.engine.v2.api.DumpSettings;
|
|
||||||
import org.snakeyaml.engine.v2.api.LoadSettings;
|
|
||||||
import org.snakeyaml.engine.v2.api.StreamDataWriter;
|
|
||||||
import org.snakeyaml.engine.v2.common.FlowStyle;
|
|
||||||
import org.snakeyaml.engine.v2.common.ScalarStyle;
|
|
||||||
import org.snakeyaml.engine.v2.composer.Composer;
|
|
||||||
import org.snakeyaml.engine.v2.nodes.MappingNode;
|
|
||||||
import org.snakeyaml.engine.v2.nodes.Node;
|
|
||||||
import org.snakeyaml.engine.v2.nodes.NodeTuple;
|
|
||||||
import org.snakeyaml.engine.v2.nodes.ScalarNode;
|
|
||||||
import org.snakeyaml.engine.v2.nodes.SequenceNode;
|
|
||||||
import org.snakeyaml.engine.v2.nodes.Tag;
|
|
||||||
import org.snakeyaml.engine.v2.parser.ParserImpl;
|
|
||||||
import org.snakeyaml.engine.v2.scanner.StreamReader;
|
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
public class YamlHelper {
|
|
||||||
|
|
||||||
// YAML dump settings with comment support and block flow style
|
|
||||||
private static final DumpSettings DUMP_SETTINGS =
|
|
||||||
DumpSettings.builder()
|
|
||||||
.setDumpComments(true)
|
|
||||||
.setWidth(Integer.MAX_VALUE)
|
|
||||||
.setDefaultFlowStyle(FlowStyle.BLOCK)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
private final String yamlContent; // Stores the entire YAML content as a string
|
|
||||||
|
|
||||||
private LoadSettings loadSettings =
|
|
||||||
LoadSettings.builder()
|
|
||||||
.setUseMarks(true)
|
|
||||||
.setMaxAliasesForCollections(Integer.MAX_VALUE)
|
|
||||||
.setAllowRecursiveKeys(true)
|
|
||||||
.setParseComments(true)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
private Path originalFilePath;
|
|
||||||
private Node updatedRootNode;
|
|
||||||
|
|
||||||
// Constructor with custom LoadSettings and YAML string
|
|
||||||
public YamlHelper(LoadSettings loadSettings, String yamlContent) {
|
|
||||||
this.loadSettings = loadSettings;
|
|
||||||
this.yamlContent = yamlContent;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Constructor that reads YAML from a file path
|
|
||||||
public YamlHelper(Path originalFilePath) throws IOException {
|
|
||||||
this.yamlContent = Files.readString(originalFilePath);
|
|
||||||
this.originalFilePath = originalFilePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates values in the target YAML based on values from the source YAML. It ensures that only
|
|
||||||
* existing keys in the target YAML are updated.
|
|
||||||
*
|
|
||||||
* @return true if at least one key was updated, false otherwise.
|
|
||||||
*/
|
|
||||||
public boolean updateValuesFromYaml(YamlHelper sourceYaml, YamlHelper targetYaml) {
|
|
||||||
boolean updated = false;
|
|
||||||
Set<String> sourceKeys = sourceYaml.getAllKeys();
|
|
||||||
Set<String> targetKeys = targetYaml.getAllKeys();
|
|
||||||
|
|
||||||
for (String key : sourceKeys) {
|
|
||||||
String[] keyArray = key.split("\\.");
|
|
||||||
|
|
||||||
Object newValue = sourceYaml.getValueByExactKeyPath(keyArray);
|
|
||||||
Object currentValue = targetYaml.getValueByExactKeyPath(keyArray);
|
|
||||||
if (newValue != null
|
|
||||||
&& (!newValue.equals(currentValue) || !sourceKeys.equals(targetKeys))) {
|
|
||||||
boolean updatedKey = targetYaml.updateValue(Arrays.asList(keyArray), newValue);
|
|
||||||
if (updatedKey) updated = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return updated;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates a value in the YAML structure.
|
|
||||||
*
|
|
||||||
* @param keys The hierarchical keys leading to the value.
|
|
||||||
* @param newValue The new value to set.
|
|
||||||
* @return true if the value was updated, false otherwise.
|
|
||||||
*/
|
|
||||||
public boolean updateValue(List<String> keys, Object newValue) {
|
|
||||||
return updateValue(getRootNode(), keys, newValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean updateValue(Node node, List<String> keys, Object newValue) {
|
|
||||||
if (!(node instanceof MappingNode mappingNode)) return false;
|
|
||||||
|
|
||||||
List<NodeTuple> updatedTuples = new ArrayList<>();
|
|
||||||
boolean updated = false;
|
|
||||||
|
|
||||||
for (NodeTuple tuple : mappingNode.getValue()) {
|
|
||||||
ScalarNode keyNode = (tuple.getKeyNode() instanceof ScalarNode sk) ? sk : null;
|
|
||||||
if (keyNode == null || !keyNode.getValue().equals(keys.get(0))) {
|
|
||||||
updatedTuples.add(tuple);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Node valueNode = tuple.getValueNode();
|
|
||||||
|
|
||||||
if (keys.size() == 1) {
|
|
||||||
Tag tag = valueNode.getTag();
|
|
||||||
Node newValueNode = null;
|
|
||||||
|
|
||||||
if (isAnyInteger(newValue)) {
|
|
||||||
newValueNode =
|
|
||||||
new ScalarNode(Tag.INT, String.valueOf(newValue), ScalarStyle.PLAIN);
|
|
||||||
} else if (isFloat(newValue)) {
|
|
||||||
Object floatValue = Float.valueOf(String.valueOf(newValue));
|
|
||||||
newValueNode =
|
|
||||||
new ScalarNode(
|
|
||||||
Tag.FLOAT, String.valueOf(floatValue), ScalarStyle.PLAIN);
|
|
||||||
} else if ("true".equals(newValue) || "false".equals(newValue)) {
|
|
||||||
newValueNode =
|
|
||||||
new ScalarNode(Tag.BOOL, String.valueOf(newValue), ScalarStyle.PLAIN);
|
|
||||||
} else if (newValue instanceof List<?> list) {
|
|
||||||
List<Node> sequenceNodes = new ArrayList<>();
|
|
||||||
for (Object item : list) {
|
|
||||||
Object obj = String.valueOf(item);
|
|
||||||
if (isAnyInteger(item)) {
|
|
||||||
tag = Tag.INT;
|
|
||||||
} else if (isFloat(item)) {
|
|
||||||
obj = Float.valueOf(String.valueOf(item));
|
|
||||||
tag = Tag.FLOAT;
|
|
||||||
} else if ("true".equals(item) || "false".equals(item)) {
|
|
||||||
tag = Tag.BOOL;
|
|
||||||
} else if (item == null || "null".equals(item)) {
|
|
||||||
tag = Tag.NULL;
|
|
||||||
} else {
|
|
||||||
tag = Tag.STR;
|
|
||||||
}
|
|
||||||
sequenceNodes.add(
|
|
||||||
new ScalarNode(tag, String.valueOf(obj), ScalarStyle.PLAIN));
|
|
||||||
}
|
|
||||||
newValueNode = new SequenceNode(Tag.SEQ, sequenceNodes, FlowStyle.FLOW);
|
|
||||||
} else if (tag == Tag.NULL) {
|
|
||||||
if ("true".equals(newValue)
|
|
||||||
|| "false".equals(newValue)
|
|
||||||
|| newValue instanceof Boolean) {
|
|
||||||
tag = Tag.BOOL;
|
|
||||||
}
|
|
||||||
newValueNode = new ScalarNode(tag, String.valueOf(newValue), ScalarStyle.PLAIN);
|
|
||||||
} else {
|
|
||||||
newValueNode = new ScalarNode(tag, String.valueOf(newValue), ScalarStyle.PLAIN);
|
|
||||||
}
|
|
||||||
copyComments(valueNode, newValueNode);
|
|
||||||
|
|
||||||
updatedTuples.add(new NodeTuple(keyNode, newValueNode));
|
|
||||||
updated = true;
|
|
||||||
} else if (valueNode instanceof MappingNode) {
|
|
||||||
updated = updateValue(valueNode, keys.subList(1, keys.size()), newValue);
|
|
||||||
updatedTuples.add(tuple);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (updated) {
|
|
||||||
mappingNode.getValue().clear();
|
|
||||||
mappingNode.getValue().addAll(updatedTuples);
|
|
||||||
}
|
|
||||||
setNewNode(node);
|
|
||||||
|
|
||||||
return updated;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetches a value based on an exact key path.
|
|
||||||
*
|
|
||||||
* @param keys The key hierarchy leading to the value.
|
|
||||||
* @return The value if found, otherwise null.
|
|
||||||
*/
|
|
||||||
public Object getValueByExactKeyPath(String... keys) {
|
|
||||||
return getValueByExactKeyPath(getRootNode(), new ArrayDeque<>(List.of(keys)));
|
|
||||||
}
|
|
||||||
|
|
||||||
private Object getValueByExactKeyPath(Node node, Deque<String> keyQueue) {
|
|
||||||
if (!(node instanceof MappingNode mappingNode)) return null;
|
|
||||||
|
|
||||||
String currentKey = keyQueue.poll();
|
|
||||||
if (currentKey == null) return null;
|
|
||||||
|
|
||||||
for (NodeTuple tuple : mappingNode.getValue()) {
|
|
||||||
if (tuple.getKeyNode() instanceof ScalarNode keyNode
|
|
||||||
&& keyNode.getValue().equals(currentKey)) {
|
|
||||||
if (keyQueue.isEmpty()) {
|
|
||||||
Node valueNode = tuple.getValueNode();
|
|
||||||
|
|
||||||
if (valueNode instanceof ScalarNode scalarValueNode) {
|
|
||||||
return scalarValueNode.getValue();
|
|
||||||
} else if (valueNode instanceof MappingNode subMapping) {
|
|
||||||
return getValueByExactKeyPath(subMapping, keyQueue);
|
|
||||||
} else if (valueNode instanceof SequenceNode sequenceNode) {
|
|
||||||
List<Object> valuesList = new ArrayList<>();
|
|
||||||
for (Node o : sequenceNode.getValue()) {
|
|
||||||
if (o instanceof ScalarNode scalarValue) {
|
|
||||||
valuesList.add(scalarValue.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return valuesList;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return getValueByExactKeyPath(tuple.getValueNode(), keyQueue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Set<String> cachedKeys;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the set of all keys present in the YAML structure. Keys are returned as
|
|
||||||
* dot-separated paths for nested keys.
|
|
||||||
*
|
|
||||||
* @return A set containing all keys in dot notation.
|
|
||||||
*/
|
|
||||||
public Set<String> getAllKeys() {
|
|
||||||
if (cachedKeys == null) {
|
|
||||||
cachedKeys = getAllKeys(getRootNode());
|
|
||||||
}
|
|
||||||
return cachedKeys;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Collects all keys from the YAML node recursively.
|
|
||||||
*
|
|
||||||
* @param node The current YAML node.
|
|
||||||
* @param currentPath The accumulated path of keys.
|
|
||||||
* @param allKeys The set storing all collected keys.
|
|
||||||
*/
|
|
||||||
private Set<String> getAllKeys(Node node) {
|
|
||||||
Set<String> allKeys = new LinkedHashSet<>();
|
|
||||||
collectKeys(node, "", allKeys);
|
|
||||||
return allKeys;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Recursively traverses the YAML structure to collect all keys.
|
|
||||||
*
|
|
||||||
* @param node The current node in the YAML structure.
|
|
||||||
* @param currentPath The accumulated key path.
|
|
||||||
* @param allKeys The set storing collected keys.
|
|
||||||
*/
|
|
||||||
private void collectKeys(Node node, String currentPath, Set<String> allKeys) {
|
|
||||||
if (node instanceof MappingNode mappingNode) {
|
|
||||||
for (NodeTuple tuple : mappingNode.getValue()) {
|
|
||||||
if (tuple.getKeyNode() instanceof ScalarNode keyNode) {
|
|
||||||
String newPath =
|
|
||||||
currentPath.isEmpty()
|
|
||||||
? keyNode.getValue()
|
|
||||||
: currentPath + "." + keyNode.getValue();
|
|
||||||
allKeys.add(newPath);
|
|
||||||
collectKeys(tuple.getValueNode(), newPath, allKeys);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the root node of the YAML document. If a new node was previously set, it is
|
|
||||||
* returned instead.
|
|
||||||
*
|
|
||||||
* @return The root node of the YAML structure.
|
|
||||||
*/
|
|
||||||
private Node getRootNode() {
|
|
||||||
if (this.updatedRootNode != null) {
|
|
||||||
return this.updatedRootNode;
|
|
||||||
}
|
|
||||||
Composer composer = new Composer(loadSettings, getParserImpl());
|
|
||||||
Optional<Node> rootNodeOpt = composer.getSingleNode();
|
|
||||||
if (rootNodeOpt.isPresent()) {
|
|
||||||
return rootNodeOpt.get();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets a new root node, allowing modifications to be tracked.
|
|
||||||
*
|
|
||||||
* @param newRootNode The modified root node.
|
|
||||||
*/
|
|
||||||
public void setNewNode(Node newRootNode) {
|
|
||||||
this.updatedRootNode = newRootNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the current root node (either the original or the updated one).
|
|
||||||
*
|
|
||||||
* @return The root node.
|
|
||||||
*/
|
|
||||||
public Node getUpdatedRootNode() {
|
|
||||||
if (this.updatedRootNode == null) {
|
|
||||||
this.updatedRootNode = getRootNode();
|
|
||||||
}
|
|
||||||
return this.updatedRootNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes the YAML parser.
|
|
||||||
*
|
|
||||||
* @return The configured parser.
|
|
||||||
*/
|
|
||||||
private ParserImpl getParserImpl() {
|
|
||||||
return new ParserImpl(loadSettings, getStreamReader());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a stream reader for the YAML content.
|
|
||||||
*
|
|
||||||
* @return The configured stream reader.
|
|
||||||
*/
|
|
||||||
private StreamReader getStreamReader() {
|
|
||||||
return new StreamReader(loadSettings, yamlContent);
|
|
||||||
}
|
|
||||||
|
|
||||||
public MappingNode save(Path saveFilePath) throws IOException {
|
|
||||||
if (!saveFilePath.equals(originalFilePath)) {
|
|
||||||
Files.writeString(saveFilePath, convertNodeToYaml(getUpdatedRootNode()));
|
|
||||||
}
|
|
||||||
return (MappingNode) getUpdatedRootNode();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void saveOverride(Path saveFilePath) throws IOException {
|
|
||||||
Files.writeString(saveFilePath, convertNodeToYaml(getUpdatedRootNode()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a YAML node back to a YAML-formatted string.
|
|
||||||
*
|
|
||||||
* @param rootNode The root node to be converted.
|
|
||||||
* @return A YAML-formatted string.
|
|
||||||
*/
|
|
||||||
public String convertNodeToYaml(Node rootNode) {
|
|
||||||
StringWriter writer = new StringWriter();
|
|
||||||
StreamDataWriter streamDataWriter =
|
|
||||||
new StreamDataWriter() {
|
|
||||||
@Override
|
|
||||||
public void write(String str) {
|
|
||||||
writer.write(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void write(String str, int off, int len) {
|
|
||||||
writer.write(str, off, len);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
new Dump(DUMP_SETTINGS).dumpNode(rootNode, streamDataWriter);
|
|
||||||
return writer.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isParsable(String value, Function<String, ?> parser) {
|
|
||||||
try {
|
|
||||||
parser.apply(value);
|
|
||||||
return true;
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if a given object is an integer.
|
|
||||||
*
|
|
||||||
* @param object The object to check.
|
|
||||||
* @return True if the object represents an integer, false otherwise.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("UnnecessaryTemporaryOnConversionFromString")
|
|
||||||
public static boolean isInteger(Object object) {
|
|
||||||
if (object instanceof Integer
|
|
||||||
|| object instanceof Short
|
|
||||||
|| object instanceof Byte
|
|
||||||
|| object instanceof Long) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (object instanceof String str) {
|
|
||||||
return isParsable(str, Integer::parseInt);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if a given object is a floating-point number.
|
|
||||||
*
|
|
||||||
* @param object The object to check.
|
|
||||||
* @return True if the object represents a float, false otherwise.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("UnnecessaryTemporaryOnConversionFromString")
|
|
||||||
public static boolean isFloat(Object object) {
|
|
||||||
return (object instanceof Float || object instanceof Double)
|
|
||||||
|| (object instanceof String str && isParsable(str, Float::parseFloat));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if a given object is a short integer.
|
|
||||||
*
|
|
||||||
* @param object The object to check.
|
|
||||||
* @return True if the object represents a short integer, false otherwise.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("UnnecessaryTemporaryOnConversionFromString")
|
|
||||||
public static boolean isShort(Object object) {
|
|
||||||
return (object instanceof Long)
|
|
||||||
|| (object instanceof String str && isParsable(str, Short::parseShort));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if a given object is a byte.
|
|
||||||
*
|
|
||||||
* @param object The object to check.
|
|
||||||
* @return True if the object represents a byte, false otherwise.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("UnnecessaryTemporaryOnConversionFromString")
|
|
||||||
public static boolean isByte(Object object) {
|
|
||||||
return (object instanceof Long)
|
|
||||||
|| (object instanceof String str && isParsable(str, Byte::parseByte));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if a given object is a long integer.
|
|
||||||
*
|
|
||||||
* @param object The object to check.
|
|
||||||
* @return True if the object represents a long integer, false otherwise.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("UnnecessaryTemporaryOnConversionFromString")
|
|
||||||
public static boolean isLong(Object object) {
|
|
||||||
return (object instanceof Long)
|
|
||||||
|| (object instanceof String str && isParsable(str, Long::parseLong));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines if an object is any type of integer (short, byte, long, or int).
|
|
||||||
*
|
|
||||||
* @param object The object to check.
|
|
||||||
* @return True if the object represents an integer type, false otherwise.
|
|
||||||
*/
|
|
||||||
public static boolean isAnyInteger(Object object) {
|
|
||||||
return isInteger(object) || isShort(object) || isByte(object) || isLong(object);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copies comments from an old node to a new one.
|
|
||||||
*
|
|
||||||
* @param oldNode The original node with comments.
|
|
||||||
* @param newValueNode The new node to which comments should be copied.
|
|
||||||
*/
|
|
||||||
private void copyComments(Node oldNode, Node newValueNode) {
|
|
||||||
if (oldNode == null || newValueNode == null) return;
|
|
||||||
if (oldNode.getBlockComments() != null) {
|
|
||||||
newValueNode.setBlockComments(oldNode.getBlockComments());
|
|
||||||
}
|
|
||||||
if (oldNode.getInLineComments() != null) {
|
|
||||||
newValueNode.setInLineComments(oldNode.getInLineComments());
|
|
||||||
}
|
|
||||||
if (oldNode.getEndComments() != null) {
|
|
||||||
newValueNode.setEndComments(oldNode.getEndComments());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package stirling.software.SPDF.config.interfaces;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import stirling.software.SPDF.utils.FileInfo;
|
||||||
|
|
||||||
|
public interface DatabaseBackupInterface {
|
||||||
|
|
||||||
|
void exportDatabase() throws IOException;
|
||||||
|
|
||||||
|
boolean importDatabase();
|
||||||
|
|
||||||
|
boolean hasBackup();
|
||||||
|
|
||||||
|
List<FileInfo> getBackupList();
|
||||||
|
}
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
package stirling.software.SPDF.config.interfaces;
|
|
||||||
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import stirling.software.SPDF.model.exception.UnsupportedProviderException;
|
|
||||||
import stirling.software.SPDF.utils.FileInfo;
|
|
||||||
|
|
||||||
public interface DatabaseInterface {
|
|
||||||
void exportDatabase() throws SQLException, UnsupportedProviderException;
|
|
||||||
|
|
||||||
void importDatabase();
|
|
||||||
|
|
||||||
boolean hasBackup();
|
|
||||||
|
|
||||||
List<FileInfo> getBackupList();
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user