Skip to content

Instantly share code, notes, and snippets.

@JarekParal
Created December 9, 2019 15:57
Show Gist options
  • Save JarekParal/24e15de33971674a8c0f9955f6ad15e0 to your computer and use it in GitHub Desktop.
Save JarekParal/24e15de33971674a8c0f9955f6ad15e0 to your computer and use it in GitHub Desktop.
Pyinstaller - update version during CI build / automatic update of version file
python CI/updateVersion.py %NEW_VERSION%
pyinstaller testApp.py --version-file "CI/version.py"
import sys
import re
FILE_WITH_VERSION_INFORMATIONS = "CI\\version"
if len(sys.argv) != 2:
print("""Problem with argument.\n
Expected exactly one argument with new version number - e.g. '1.23.0.0'""")
exit(1)
new_version = sys.argv[1]
if re.match(r"[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+", new_version) == None:
print("Wrong format of argument:", new_version,
"\nRequired format: 1.23.0.0")
exit(1)
new_version_commas = new_version.replace('.', ', ')
# Read data from template file
fin = open(FILE_WITH_VERSION_INFORMATIONS + "_template.py", "rt")
data = fin.read()
data = data.replace('filevers=(78, 0, 3904, 108)',
'filevers=(' + new_version_commas + ')')
data = data.replace('prodvers=(78, 0, 3904, 108)',
'prodvers=(' + new_version_commas + ')')
data = data.replace("u'FileVersion', u'78, 0, 3904, 108'",
"u'FileVersion', u'" + new_version + "'")
data = data.replace("u'ProductVersion', u'78, 0, 3904, 108'",
"u'ProductVersion', u'" + new_version + "'")
fin.close()
# Write the data to new output file
fin = open(FILE_WITH_VERSION_INFORMATIONS + ".py", "wt")
fin.write(data)
fin.close()
print(sys.argv[0], "- version updated to:", new_version)
# Version info from Google Chrome
# Get this info with util `pyi-grab_version`
# UTF-8
#
# For more details about fixed file info 'ffi' see:
# http://msdn.microsoft.com/en-us/library/ms646997.aspx
VSVersionInfo(
ffi=FixedFileInfo(
# filevers and prodvers should be always a tuple with four items: (1, 2, 3, 4)
# Set not needed items to zero 0.
filevers=(78, 0, 3904, 108),
prodvers=(78, 0, 3904, 108),
# Contains a bitmask that specifies the valid bits 'flags'r
mask=0x17,
# Contains a bitmask that specifies the Boolean attributes of the file.
flags=0x0,
# The operating system for which this file was designed.
# 0x4 - NT and there is no need to change it.
OS=0x4,
# The general type of file.
# 0x1 - the file is an application.
fileType=0x1,
# The function of the file.
# 0x0 - the function is not defined for this fileType
subtype=0x0,
# Creation date and time stamp.
date=(0, 0)
),
kids=[
StringFileInfo(
[
StringTable(
u'040904b0',
[StringStruct(u'CompanyName', u'Google LLC'),
StringStruct(u'FileDescription', u'Google Chrome'),
StringStruct(u'FileVersion', u'78, 0, 3904, 108'),
StringStruct(u'InternalName', u'chrome_exe'),
StringStruct(u'LegalCopyright', u'Copyright 2019 Google LLC. All rights reserved.'),
StringStruct(u'OriginalFilename', u'chrome.exe'),
StringStruct(u'ProductName', u'Google Chrome'),
StringStruct(u'ProductVersion', u'78.0.3904.108'),
StringStruct(u'CompanyShortName', u'Google'),
StringStruct(u'ProductShortName', u'Chrome'),
StringStruct(u'LastChange', u'4b26898a39ee037623a72fcfb77279fce0e7d648-refs/branch-heads/3904@{#889}'),
StringStruct(u'Official Build', u'1')])
]),
VarFileInfo([VarStruct(u'Translation', [1033, 1200])])
]
)
@Lagdu
Copy link

Lagdu commented Jan 16, 2020

Helped me a lot thank you bro :)

I also added code like this to bring in my versioning the GIT commit :

import subprocess
def get_git_revision_hash():
    return subprocess.check_output(['git', 'rev-parse', 'HEAD'])

def get_git_revision_short_hash():
    return subprocess.check_output(['git', 'rev-parse', '--short', 'HEAD']) 

git_commit_short = get_git_revision_short_hash().decode('ASCII').replace('\n', "")
git_commit_long = get_git_revision_hash().decode('ASCII').replace('\n', "")

@JarekParal
Copy link
Author

JarekParal commented Jan 16, 2020

@Lagdu Thanks for contributing.

Which StringStruct do you use for the git commit hash? I test them and unfortunately, just some of them are shown in program properties:
image

@Lagdu
Copy link

Lagdu commented Jan 21, 2020

Hi Jarek

I guess i'm not using a special structure (don't really know in fact)

Here is what I have tested tonight.

Details

So i guess you should put the git hash in the ProducVersion and it will work with a simple string.

The filevers seems to be a special format and maybe you cannot add the format you want but only "X,X,X,X" format

I personnaly dont care about the windows detail but I use it inside my program as follow (copy screen of mu prog) :

prog

If u want to use thoses informations in your code you can do like this.

import win32api
def getFileProperties(fname):
    """
    Read all properties of the given file return them as a dictionary.
    """
    propNames = ('Comments', 'InternalName', 'ProductName',
             'CompanyName', 'LegalCopyright', 'ProductVersion',
             'FileDescription', 'LegalTrademarks', 'PrivateBuild',
             'FileVersion', 'OriginalFilename', 'SpecialBuild')

    props = {'StringFileInfo': None}

    strInfo = {}
    try:
        for propName in propNames:
            # The "040904B0" must match the information you have in your version file. Dont know how to get it dynamic
            strInfoPath = u'\\StringFileInfo\\040904B0\\'
            strInfo[propName] = win32api.GetFileVersionInfo(fname, strInfoPath+propName)

        props['StringFileInfo'] = strInfo
    except:
        props=False
    return props


........................

        properties_detail = getFileProperties("./Prog.exe")
        if properties_detail:
            product_name_text = properties_detail['StringFileInfo']['ProductName']
            product_version_text = properties_detail['StringFileInfo']['ProductVersion']
            product_desc_text = properties_detail['StringFileInfo']['FileDescription']
            product_file_version_text = properties_detail['StringFileInfo']['FileVersion']
            product_support_text = "[email protected]"

I'm begining in python so i guess there are better way to do it but it works for me.

@Lagdu
Copy link

Lagdu commented Jan 21, 2020

I also made some modification in your process.

I'am calling the updateVersion.py in my spec file so when i want to build my program i write the command line like this.

pyinstaller Prog.spec 1.1.0.2

So i just need one line to build and set my version.

@llamafilm
Copy link

Thanks for this code. I made a simpler version since I am only using it for argparse --version command.

At the top of the spec file:

# update the version with the latest git commit
import subprocess
git_commit = subprocess.check_output(['git', 'rev-parse', '--short', 'HEAD'], text=True)
new_version = '1.0-' + git_commit.strip()
print('Building with new version number', new_version)
with open('_version.py', 'w') as f:
    f.write('version = "' + new_version + '"')

And this at the end to reset so that git doesn't notice changes every time

with open('_version.py', 'w') as f:
    f.write("# placeholder will be overwritten by PyInstaller\nversion = ''")

@QAC-Lab
Copy link

QAC-Lab commented May 17, 2022

@Lagdu, can u share a sample . I am trying to achieve the same

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment