From 8542528c8408ffe4ee752d1ded32c78c2ea7a405 Mon Sep 17 00:00:00 2001 From: Romain Demeure Date: Wed, 26 Aug 2026 11:23:10 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20fix:=20support=20UTF-16=20encode?= =?UTF-8?q?d=20input=20files=20for=20--filename=20option?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- oks_cli/cluster.py | 6 +++--- oks_cli/project.py | 2 +- oks_cli/utils.py | 10 ++++++++++ 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/oks_cli/cluster.py b/oks_cli/cluster.py index 75b15ff..9e7ef5b 100644 --- a/oks_cli/cluster.py +++ b/oks_cli/cluster.py @@ -381,7 +381,7 @@ def _create_cluster(project_name, cluster_config, output): @click.option('--cp-multi-az', '-m', is_flag=True, help="Enable control plane multi AZ") @click.option('--dry-run', is_flag=True, help="Client dry-run, only print the object that would be sent, without sending it") @click.option('--output', '-o', type=click.Choice(["json", "yaml"]), help="Specify output format, by default is json") -@click.option('--filename', '-f', type=click.File("r"), help="Path to file to use to create the cluster ") +@click.option('--filename', '-f', type=click.File("rb"), help="Path to file to use to create the cluster ") @click.option('--profile', help="Configuration profile to use", shell_complete=profile_completer) @click.option('--set', 'set_fields', multiple=True, help="Set arbitrary nested fields, e.g. auth.oidc.issuer-url=value") @click.pass_context @@ -479,7 +479,7 @@ def cluster_create_command(ctx, project_name, cluster_name, description, admin, @click.option('--control-plane', shell_complete=shell_completions, help="Controlplane plan") @click.option('--dry-run', is_flag=True, help="Client dry-run, only print the object that would be sent, without sending it") @click.option('--output', '-o', type=click.Choice(["json", "yaml"]), help="Specify output format, by default is json") -@click.option('--filename', '-f', type=click.File("r"), help="Path to file to use to update the cluster ") +@click.option('--filename', '-f', type=click.File("rb"), help="Path to file to use to update the cluster ") @click.option('--profile', help="Configuration profile to use", shell_complete=profile_completer) @click.option('--set', 'set_fields', multiple=True, help="Set arbitrary nested fields, e.g. auth.oidc.issuer-url=value") @click.pass_context @@ -822,7 +822,7 @@ def nodepool_list(ctx): @click.option('--zone', '-z', multiple=True, help="Provide zone(s)") @click.option('--output', '-o', type=click.Choice(["json", "yaml"]), help="Specify output format, by default is json") @click.option('--dry-run', is_flag=True, help="Run without any action") -@click.option('--filename', '-f', type=click.File("r"), help="Path to file to use to create the Nodepool") +@click.option('--filename', '-f', type=click.File("rb"), help="Path to file to use to create the Nodepool") @click.pass_context def setup_worker_pool(ctx, nodepool_name, count, vmtype, zone, output, dry_run, filename): """Create a new nodepool in the cluster, optionally from a file or parameters.""" diff --git a/oks_cli/project.py b/oks_cli/project.py index 95f21d1..80e62e6 100644 --- a/oks_cli/project.py +++ b/oks_cli/project.py @@ -193,7 +193,7 @@ def project_list(ctx, project_name, deleted, plain, msword, uuid, watch, output, @click.option('--disable-api-termination', type=click.BOOL, help="Disable delete action by API") @click.option('--dry-run', is_flag=True, help="Client dry-run, only print the object that would be sent, without sending it") @click.option('--output', '-o', type=click.Choice(["json", "yaml", "silent"]), help="Specify output format, by default is json") -@click.option('--filename', '-f', type=click.File("r"), help="Path to file to use to create the project") +@click.option('--filename', '-f', type=click.File("rb"), help="Path to file to use to create the project") @click.option('--profile', help="Configuration profile to use", shell_complete=profile_completer) @click.option('--set', 'set_fields', multiple=True, help="Set arbitrary nested fields, e.g. auth.oidc.issuer-url=value") @click.pass_context diff --git a/oks_cli/utils.py b/oks_cli/utils.py index 432b8db..f237a3b 100644 --- a/oks_cli/utils.py +++ b/oks_cli/utils.py @@ -1,4 +1,5 @@ import click +import codecs import os import subprocess import logging @@ -753,6 +754,15 @@ def remove_jwt_token(token_type): def detect_and_parse_input(input_data): """Parse input as JSON or YAML; raise error if invalid.""" + if isinstance(input_data, bytes): + try: + if input_data.startswith((codecs.BOM_UTF16_LE, codecs.BOM_UTF16_BE)): + input_data = input_data.decode("utf-16") + else: + input_data = input_data.decode("utf-8-sig") + except UnicodeDecodeError: + raise click.BadParameter("Input file is neither valid JSON nor YAML.") + try: return json.loads(input_data) except json.JSONDecodeError: