Skip to content

Instantly share code, notes, and snippets.

@Mause

Mause/.gitignore Secret

Last active June 17, 2024 14:52
Show Gist options
  • Save Mause/888ad36325f462641a8e169f6183834a to your computer and use it in GitHub Desktop.
Save Mause/888ad36325f462641a8e169f6183834a to your computer and use it in GitHub Desktop.
import struct
import os
from os.path import expanduser
from argparse import ArgumentParser
import json
import base64
parser = ArgumentParser()
parser.add_argument("filename", type=str)
parser.add_argument("--extension-version", type=str)
parser.add_argument("--duckdb-version", type=str)
parser.add_argument("--platform", type=str)
parser.add_argument("--metadata-version", type=str, default="4")
args = parser.parse_args()
format_string = struct.Struct(("32x" * 4) + ("32s" * 4) + "256s")
def read_metadata(filename):
def try_decode(field):
try:
return field.decode().strip("\x00")
except UnicodeDecodeError:
return field
with open(filename, "rb") as f:
f.seek(-format_string.size, os.SEEK_END)
extension_version, duckdb_version, platform, metadata_version, signature = (
try_decode(field)
for field in format_string.unpack(f.read(format_string.size))
)
return {
"extension_version": extension_version,
"duckdb_version": duckdb_version,
"platform": platform,
"metadata_version": metadata_version,
"signature": signature,
}
def write_metadata(filename):
fields = (
args.extension_version,
args.duckdb_version,
args.platform,
args.metadata_version,
"\x00" * 256, # signature
)
if not all(fields):
parser.error("All fields must be provided")
print(fields)
encoded = format_string.pack(*(field.encode() for field in fields))
with open(filename, "ab") as f:
f.write(encoded)
def main():
filename = expanduser(args.filename)
if not os.path.exists(filename):
parser.error(f"File {filename} does not exist")
if args.extension_version:
print(f"Extension version: {args.extension_version}")
print(f"DuckDB version: {args.duckdb_version}")
print(f"Platform: {args.platform}")
print(f"Metadata version: {args.metadata_version}")
if (
input("Do you want to write this metadata to the file? (y/n) ").lower()
== "y"
):
write_metadata(filename)
else:
breakpoint()
print(
json.dumps(
read_metadata(filename),
default=lambda item: base64.b64encode(item).decode(),
indent=2,
)
)
if __name__ == "__main__":
main()
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "anstream"
version = "0.6.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is_terminal_polyfill",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b"
[[package]]
name = "anstyle-parse"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391"
dependencies = [
"windows-sys",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19"
dependencies = [
"anstyle",
"windows-sys",
]
[[package]]
name = "append_metadata"
version = "0.1.0"
dependencies = [
"clap",
]
[[package]]
name = "clap"
version = "4.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f"
dependencies = [
"clap_builder",
"clap_derive",
]
[[package]]
name = "clap_builder"
version = "4.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7e204572485eb3fbf28f871612191521df159bc3e15a9f5064c66dba3a8c05f"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_derive"
version = "4.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "clap_lex"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70"
[[package]]
name = "colorchoice"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
[[package]]
name = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "is_terminal_polyfill"
version = "1.70.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800"
[[package]]
name = "proc-macro2"
version = "1.0.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
dependencies = [
"proc-macro2",
]
[[package]]
name = "strsim"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "syn"
version = "2.0.66"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "utf8parse"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
[[package]]
name = "windows_i686_gnu"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
[[package]]
name = "windows_i686_msvc"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
[package]
name = "append_metadata"
version = "0.1.0"
edition = "2021"
[dependencies]
clap = { version = "4.5.7", features = ["derive"] }
[[bin]]
name = "append_metadata"
path = "rust.rs"
use clap::Parser;
use std::io::{Read, Seek, SeekFrom, Write};
use std::{ffi::CStr, fs::OpenOptions};
#[repr(C)]
#[derive(Debug)]
struct Metadata {
extension_version: [u8; 32],
duckdb_version: [u8; 32],
platform: [u8; 32],
metadata_version: [u8; 32],
signature: [u8; 256],
}
impl Metadata {
fn read_metadata(filename: &str) -> Result<Metadata, std::io::Error> {
let mut file = OpenOptions::new().read(true).open(filename)?;
file.seek(SeekFrom::End(-(std::mem::size_of::<Metadata>() as i64)))?;
let mut metadata = Metadata {
extension_version: [0; 32],
duckdb_version: [0; 32],
platform: [0; 32],
metadata_version: [0; 32],
signature: [0; 256],
};
file.read_exact(unsafe {
std::slice::from_raw_parts_mut(
metadata.extension_version.as_mut_ptr() as *mut u8,
std::mem::size_of_val(&metadata),
)
})?;
Ok(metadata)
}
fn write_metadata(filename: &str, metadata: Metadata) -> Result<(), std::io::Error> {
let mut file = OpenOptions::new().append(true).open(filename)?;
let bytes = unsafe {
std::slice::from_raw_parts(
(&metadata as *const Metadata) as *const u8,
std::mem::size_of_val(&metadata),
)
};
file.write_all(bytes)?;
Ok(())
}
}
#[derive(Debug, clap::Parser)]
struct Args {
#[clap(subcommand)]
subcommand: Subcommand,
}
#[derive(clap::Parser, Debug)]
enum Subcommand {
Read(ReadCommand),
Write(WriteCommand),
}
#[derive(clap::Parser, Debug)]
struct ReadCommand {
filename: String,
}
#[derive(clap::Parser, Debug)]
struct WriteCommand {
filename: String,
#[clap(short, long)]
extension_version: String,
#[clap(short, long)]
duckdb_version: String,
#[clap(short, long)]
platform: String,
#[clap(short, long, default_value = "4")]
metadata_version: String,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let args = Args::parse();
match args.subcommand {
Subcommand::Read(read) => read_metadata(&read.filename),
Subcommand::Write(write) => write_metadata(&write.filename, &write),
}
}
fn load(data: [u8; 32]) -> Result<String, Box<dyn std::error::Error>> {
let cstr = CStr::from_bytes_until_nul(&data)?;
Ok(cstr.to_str()?.to_string())
}
fn read_metadata(filename: &str) -> Result<(), Box<dyn std::error::Error>> {
let metadata = Metadata::read_metadata(filename)?;
println!("extension_version: {:?}", load(metadata.extension_version)?);
println!("duckdb_version: {:?}", load(metadata.duckdb_version)?);
println!("platform: {:?}", load(metadata.platform)?);
println!("metadata_version: {:?}", load(metadata.metadata_version)?);
Ok(())
}
fn write_metadata(filename: &str, args: &WriteCommand) -> Result<(), Box<dyn std::error::Error>> {
let metadata = Metadata {
extension_version: args.extension_version.as_bytes().try_into()?,
duckdb_version: args.duckdb_version.as_bytes().try_into()?,
platform: args.platform.as_bytes().try_into()?,
metadata_version: args.metadata_version.as_bytes().try_into()?,
signature: [0; 256],
};
Metadata::write_metadata(filename, metadata).expect("Failed to write metadata");
Ok(())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment