Compiling Go with python I've made a small script to compile Go code with Python.

The result is not something I'm happy with, because:


It seems overly complicated
I'm worried the nested if-else with f string are unreadable
Am I using the subprocess module the correct way?


Any review is welcome.

#!/usr/bin/env python3

import argparse
import subprocess
import os

ARCHS = {
    "32": "386",
    "64": "amd64"
}

BUILDTYPES = ["exe", "dll"]

def parse_arguments():
    parser = argparse.ArgumentParser(usage='%(prog)s [options] &lt;buildtype&gt; &lt;architecture&gt;',
                                     description='Go builder',
                                     formatter_class=argparse.RawDescriptionHelpFormatter,
                                     epilog='''
Python program to build go payloads

Examples:
    ./builder exe 32 --stripped
    ./builder dll 64 --upx --stripped
    ./builder dll 32
''')
    parser.add_argument("buildtype", help="The type to build the paylopad with", type=str)
    parser.add_argument("architecture", help="The architecture to build the paylopad with", type=str, default="32")
    parser.add_argument("--stripped", "-s", help="Strip the payload of symbols", action="store_true", default=False)
    parser.add_argument("--upx", "-u", help="Pack the payload with upx", action="store_true", default=False)
    arguments = parser.parse_args()

    if not arguments.buildtype.lower() in BUILDTYPES:
        parser.error(f"{arguments.buildtype} is not a valid buildtype can only be {', '.join(BUILDTYPES)}")

    if not arguments.architecture.lower() in ARCHS:
        parser.error(f"{arguments.architecture} is not a valid architecture can only be {', '.join(ARCHS.keys())}")
    arguments.architecture = ARCHS[arguments.architecture]

    return arguments

def build_go(**kwargs):
    enviroment = {
        **os.environ,
        "GOOS": "windows",
        "GOARCH": f"{kwargs['architecture']}"
    }
    if kwargs['buildtype'].lower() == "dll":
        enviroment["CGO_ENABLED"] = "1"
        enviroment["CC"] = f"{'i686' if kwargs['architecture'] == '386' else 'x86_64'}-w64-mingw32-gcc"

    build_type = f"go build -buildmode=c-shared" if kwargs["buildtype"].lower() == "dll" else "go build -tags exe"
    stripped = "-s -w" if kwargs['stripped'] else ""
    builder = f'''{build_type} -o GOLoader.{kwargs['buildtype']} -ldflags "-H=windowsgui {stripped}"'''
    subprocess.check_output(builder, shell=True, env=enviroment)

    if kwargs["stripped"]:
        stripped = f"strip GOLoader.{kwargs['buildtype']}"
        subprocess.check_output(stripped, shell=True)

    if kwargs["upx"]:
        upx = f"upx -f GOLoader.{kwargs['buildtype']} -9 --ultra-brute -o GOLoader.upx.{kwargs['buildtype']}"
        subprocess.check_output(upx, shell=True)

if __name__ == '__main__':
    args = parse_arguments()
    build_go(**vars(args))
Some minor notes.

I love the ternary operator and f strings, but...

Here are three ways to express the same thing.  There is the original way, a DRY version of the original way, and a more traditional if/else.  Which is easier to read and understand what is going on?

# variant 1
build_type = f"go build -buildmode=c-shared" if kwargs["buildtype"].lower() == "dll" else "go build -tags exe"

# variant 2
build_type = f"go build {'-buildmode=c-shared' if kwargs['buildtype'].lower() == 'dll' else '-tags exe'}"

# variant 3
if kwargs["buildtype"].lower() == "dll":
    build_type = "go build -buildmode=c-shared"
else:
    build_type = "go build -tags exe"


In this case I would argue that the third variant is MUCH easier to understand what the distinction is between the two build types.  EG: What question is being asked (buildtype) and what is the difference in the result based on the answer.

Environment has a "n" after the "o"

This:

enviroment["CGO_ENABLED"] = "1"


should likely be:

environment["CGO_ENABLED"] = "1"    


Click is the thing.

Not sure this is immediately relevant as a code review, but...

I much prefer click to argparse.  In this simple case there is not likely a huge advantage for Click, but there is little downside.  And if you get comfortable with click and the size of your project increases, I think Click can be quite advantageous.