From ca15130a4d4a38655350cd4634207da3789f6cbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Maier?= Date: Tue, 19 Mar 2024 18:11:18 +0000 Subject: [PATCH] linux deployment automatization initial --- .devcontainer/Dockerfile | 13 ++++- linux_deploy/control | 7 +++ linux_deploy/data-plotter.desktop | 8 ++++ linux_deploy/deploy.py | 77 ++++++++++++++++++++++++++++++ linux_deploy/icon.png | Bin 0 -> 11658 bytes linux_deploy/qt.conf | 5 ++ 6 files changed, 108 insertions(+), 2 deletions(-) create mode 100755 linux_deploy/control create mode 100644 linux_deploy/data-plotter.desktop create mode 100644 linux_deploy/deploy.py create mode 100644 linux_deploy/icon.png create mode 100644 linux_deploy/qt.conf diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index acfa329..deefec8 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -14,5 +14,14 @@ RUN if [ "${REINSTALL_CMAKE_VERSION_FROM_SOURCE}" != "none" ]; then \ # RUN su vscode -c "${VCPKG_ROOT}/vcpkg install " # [Optional] Uncomment this section to install additional packages. -# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ -# && apt-get -y install --no-install-recommends +RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ + && apt-get -y install --no-install-recommends \ + qt5-default \ + qtdeclarative5-dev \ + libqt5quick5 \ + libqt5quickcontrols2-5 \ + libqt5serialport5-dev \ + mesa-common-dev \ + libglu1-mesa-dev \ + qtquickcontrols2-5-dev \ + libqt5opengl5-dev diff --git a/linux_deploy/control b/linux_deploy/control new file mode 100755 index 0000000..eee8bd6 --- /dev/null +++ b/linux_deploy/control @@ -0,0 +1,7 @@ +Package: data-plotter +Version: {version} +Architecture: amd64 +Essential: no +Priority: optional +Maintainer: Jiri Maier +Description: Universal GUI for software-defined measuring instruments diff --git a/linux_deploy/data-plotter.desktop b/linux_deploy/data-plotter.desktop new file mode 100644 index 0000000..ca421da --- /dev/null +++ b/linux_deploy/data-plotter.desktop @@ -0,0 +1,8 @@ +[Desktop Entry] +Version=1.0 +Type=Application +Name=Data Plotter +Comment=Universal GUI for software-defined measuring instruments +Exec=/usr/bin/data-plotter +Icon=/usr/share/icons/hicolor/256x256/apps/data-plotter.png +Categories=Office \ No newline at end of file diff --git a/linux_deploy/deploy.py b/linux_deploy/deploy.py new file mode 100644 index 0000000..b2d543e --- /dev/null +++ b/linux_deploy/deploy.py @@ -0,0 +1,77 @@ +import os +import shutil +import subprocess + +# Function to get the version from the .pro file +def get_version(file_path): + with open(file_path, 'r') as file: + for line in file: + if line.startswith('VERSION'): + return line.split('=')[1].strip() + return None + + +# Get the version from the .pro file +version = get_version('DataPlotter.pro') +# Trim the version to three numbers +version = ".".join(version.split(".")[:3]) + +# Define the base directory +base_dir = os.path.join("linux_deploy",f"data-plotter_{version}_amd64") + +if os.path.exists(base_dir): + shutil.rmtree(base_dir) + +# Define the directories to be created +dirs = [ + os.path.join(base_dir, "DEBIAN"), + os.path.join(base_dir, "usr", "bin"), + os.path.join(base_dir, "usr", "share", "doc", "data-plotter"), + os.path.join(base_dir, "usr", "lib"), + os.path.join(base_dir,"usr","share","icons","hicolor","256x256","apps"), + os.path.join(base_dir,"usr","share","applications"), +] + +# Create the directories +for dir in dirs: + os.makedirs(dir, exist_ok=True) + +# Define the files to be copied +files = { + os.path.join("linux_deploy","control"): os.path.join(base_dir, "DEBIAN", "control"), + os.path.join("linux_deploy","qt.conf"): os.path.join(base_dir, "usr", "bin", "qt.conf"), + os.path.join("build","DataPlotter"): os.path.join(base_dir, "usr", "bin", "data-plotter"), + os.path.join("documentation","license.txt"): os.path.join(base_dir, "usr", "share", "doc", "data-plotter", "copyright"), + os.path.join("linux_deploy","icon.png"):os.path.join(base_dir,"usr","share","icons","hicolor","256x256","apps","data-plotter.png"), + os.path.join("linux_deploy","data-plotter.desktop"):os.path.join(base_dir,"usr","share","applications","data-plotter.desktop") +} + +# Copy the files +for src, dst in files.items(): + shutil.copy(src, dst) + +with open(os.path.join(base_dir, "DEBIAN", "control"), "r") as file: + content = file.read() +content = content.replace("{version}", f"{version}") +with open(os.path.join(base_dir, "DEBIAN", "control"), "w") as file: + file.write(content) + +# Run ldd on the executable +result = subprocess.run(["ldd", os.path.join("build","DataPlotter")], capture_output=True, text=True) + +# Extract the paths of the shared libraries +libs = [line.split(" ")[2] for line in result.stdout.splitlines() if "=>" in line and not "linux-vdso" in line] + +for lib in libs: + shutil.copy(lib, os.path.join(base_dir, "usr", "lib")) + +shutil.copytree(os.path.join("linux_deploy","plugins"),os.path.join(base_dir,"usr","lib","qt5","plugins")) +shutil.copytree(os.path.join("linux_deploy","qml"),os.path.join(base_dir,"usr","lib","qt5","qml")) + +# Print a success message +print(f"The Debian package folder structure for {base_dir} has been created and the files have been copied.") + +os.remove(base_dir + ".deb") + +#result = subprocess.run(["dpkg-deb", "--build", base_dir], capture_output=True, text=True) +#print(result) \ No newline at end of file diff --git a/linux_deploy/icon.png b/linux_deploy/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..0c4760748570dd27fa449474d2018265369293e6 GIT binary patch literal 11658 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 CZk