mirror of
https://github.com/veracrypt/VeraCrypt.git
synced 2025-11-11 02:58:02 -06:00
Add python script that automates uploading VeraCrypt release files to Launchpad
This commit is contained in:
158
src/Build/veracrypt-launchpad-uploader.py
Normal file
158
src/Build/veracrypt-launchpad-uploader.py
Normal file
@@ -0,0 +1,158 @@
|
||||
# =============================================================================
|
||||
# VeraCrypt Launchpad Uploader
|
||||
# =============================================================================
|
||||
#
|
||||
# Author: Mounir IDRASSI <mounir.idrassi@amcrypto.jp>
|
||||
# Date: May 31st, 2025
|
||||
#
|
||||
# This script is part of the VeraCrypt project
|
||||
# https://www.veracrypt.jp
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# Description:
|
||||
# This script automates the process of uploading VeraCrypt release packages
|
||||
# to Launchpad. It authenticates with Launchpad, locates the appropriate
|
||||
# project, series, milestone, and release, and then uploads all package files
|
||||
# from a specified directory, skipping any that have already been uploaded.
|
||||
# =============================================================================
|
||||
|
||||
import os
|
||||
import mimetypes
|
||||
from launchpadlib.launchpad import Launchpad
|
||||
|
||||
# === CONFIGURATION ===
|
||||
PROJECT_NAME = 'veracrypt'
|
||||
SERIES_NAME = 'trunk'
|
||||
MILESTONE_NAME = '1.26.24'
|
||||
RELEASE_VERSION = '1.26.24'
|
||||
FILES_DIRECTORY = r"/opt/VeraCrypt_Packages/1.26.24"
|
||||
|
||||
APPLICATION_NAME = 'launchpad-batch-uploader'
|
||||
CACHEDIR = os.path.expanduser(r"~/.launchpadlib/cache")
|
||||
|
||||
# === AUTHENTICATION ===
|
||||
print("Authenticating with Launchpad…")
|
||||
launchpad = Launchpad.login_with(APPLICATION_NAME, 'production', CACHEDIR)
|
||||
|
||||
# === LOOK UP TARGET OBJECTS ===
|
||||
try:
|
||||
# First try direct dictionary-style lookup
|
||||
project = launchpad.projects[PROJECT_NAME]
|
||||
except KeyError:
|
||||
# Fallback: use getByName on projects
|
||||
project = launchpad.projects.getByName(name=PROJECT_NAME)
|
||||
if project is None:
|
||||
raise Exception(f"Project '{PROJECT_NAME}' not found.")
|
||||
|
||||
# Safely fetch the series object
|
||||
try:
|
||||
series = project.series[SERIES_NAME]
|
||||
except (KeyError, TypeError):
|
||||
series = project.getSeries(name=SERIES_NAME)
|
||||
if series is None:
|
||||
raise Exception(f"Series '{SERIES_NAME}' not found in project '{PROJECT_NAME}'.")
|
||||
|
||||
# === REPLACE getMilestone with a loop over all_milestones ===
|
||||
milestone = None
|
||||
print(f"Locating milestone '{MILESTONE_NAME}' in series '{SERIES_NAME}'…")
|
||||
for m in series.all_milestones: # ← series.all_milestones is a PagedCollection of Milestone
|
||||
if m.name == MILESTONE_NAME:
|
||||
milestone = m
|
||||
break
|
||||
|
||||
if milestone is None:
|
||||
raise Exception(f"Milestone '{MILESTONE_NAME}' not found in series '{SERIES_NAME}'.")
|
||||
|
||||
# --- FIND THE RELEASE UNDER THAT MILESTONE ----------------------------
|
||||
print(f"Locating release for milestone '{MILESTONE_NAME}'…")
|
||||
|
||||
try:
|
||||
release = milestone.release # <-- the only release tied to this milestone
|
||||
except AttributeError:
|
||||
# (very old Launchpadlib versions expose only the _link)
|
||||
release = launchpad.load(milestone.release_link)
|
||||
|
||||
# sanity-check
|
||||
if release is None or release.version != RELEASE_VERSION:
|
||||
raise Exception(
|
||||
f"Expected version '{RELEASE_VERSION}', "
|
||||
f"but milestone only links to '{getattr(release, 'version', None)}'."
|
||||
)
|
||||
print("Release found. Beginning upload…")
|
||||
|
||||
# === UPLOAD FILES ===
|
||||
|
||||
# Build a set of filenames already present on the release
|
||||
existing_files = set()
|
||||
for f in release.files:
|
||||
# Each f is a URL; the filename is after the last '/'
|
||||
filename_on_release = os.path.basename(f.self_link)
|
||||
existing_files.add(filename_on_release)
|
||||
|
||||
# Print existing files if existing_files is not empty
|
||||
if not existing_files:
|
||||
print("No files already uploaded to this release.")
|
||||
else:
|
||||
print("Files already uploaded to this release:")
|
||||
for ef in sorted(existing_files):
|
||||
print(" -", ef)
|
||||
|
||||
print()
|
||||
|
||||
for filename in os.listdir(FILES_DIRECTORY):
|
||||
if filename.endswith('.sig'):
|
||||
continue
|
||||
|
||||
if filename in existing_files:
|
||||
print(f">>> Skipping {filename} (already uploaded)")
|
||||
continue
|
||||
|
||||
filepath = os.path.join(FILES_DIRECTORY, filename)
|
||||
sig_path = filepath + '.sig'
|
||||
has_signature = os.path.isfile(sig_path)
|
||||
|
||||
content_type, _ = mimetypes.guess_type(filepath)
|
||||
content_type = content_type or 'application/octet-stream'
|
||||
|
||||
print(f"Uploading: {filename} (type: {content_type})")
|
||||
try:
|
||||
with open(filepath, 'rb') as file_content:
|
||||
file_bytes = file_content.read()
|
||||
if has_signature:
|
||||
with open(sig_path, 'rb') as sig_handle:
|
||||
sig_bytes = sig_handle.read()
|
||||
release.add_file(
|
||||
description=f"Uploaded file: {filename}",
|
||||
content_type=content_type,
|
||||
filename=filename,
|
||||
file_content=file_bytes,
|
||||
signature_filename=os.path.basename(sig_path),
|
||||
signature_content=sig_bytes
|
||||
)
|
||||
print(f" -> Uploaded {filename} with signature.")
|
||||
else:
|
||||
release.add_file(
|
||||
description=f"Uploaded file: {filename}",
|
||||
content_type=content_type,
|
||||
filename=filename,
|
||||
file_content=file_bytes,
|
||||
signature_filename=None,
|
||||
signature_content=None
|
||||
)
|
||||
print(f" -> Uploaded {filename} without signature.")
|
||||
except Exception as e:
|
||||
print(f"!!! Failed to upload '{filename}': {e}")
|
||||
continue
|
||||
|
||||
print("Done! All files uploaded (or attempted) successfully.")
|
||||
Reference in New Issue
Block a user