1. 程式人生 > >python實現綠色軟件的升級,包括單文件升級和多文件升級

python實現綠色軟件的升級,包括單文件升級和多文件升級

odi dev argv odin txt 註意 store isf out

# coding:utf-8
import sys, os, time
import zipfile
import shutil


def print_usage():
    print ‘‘‘usage:
  python software_upgrade.py subZipFullPath, targetZipFullPath, mainVersionZipPath[, relativePath]\n
  for example:
        linux platform:
            python software_upgrade.py /test/software_upgrade/subVersionDir/readme.txt /test/software_upgrade/latestVersionDir/myAPP_latest.zip /test/software_upgrade/mainVersionDir/myAPP_main.zip /readme.txt
            python software_upgrade.py /test/software_upgrade/subVersionDir/myAPP_subVersion_0.1.zip /test/software_upgrade/latestVersionDir/myAPP_latest.zip /test/software_upgrade/mainVersionDir/myAPP_main.zip
        windows platform:
            python software_upgrade.py C:\software_upgrade\subVersionDir\readme.txt C:\software_upgrade\latestVersionDir\myAPP_latest.zip C:\software_upgrade\mainVersionDir\myAPP_main.zip \readme.txt
            python software_upgrade.py C:\software_upgrade\subVersionDir\myAPP_subVersion_0.1.zip C:\software_upgrade\latestVersionDir\myAPP_latest.zip C:\software_upgrade\mainVersionDir\myAPP_main.zip

‘‘‘


def my_copytree(src, dst, symlinks=False):
    """
    若同樣的目標已存在則不動
    Args:
        src:
        dst:
        symlinks:

    Returns:

    """
    names = os.listdir(src)
    if not os.path.isdir(dst):
        os.makedirs(dst)

    errors = []
    for name in names:
        srcname = os.path.join(src, name)
        dstname = os.path.join(dst, name)
        try:
            if symlinks and os.path.islink(srcname):
                linkto = os.readlink(srcname)
                os.symlink(linkto, dstname)
            elif os.path.isdir(srcname):
                my_copytree(srcname, dstname, symlinks)
            else:
                if os.path.isdir(dstname):
                    os.rmdir(dstname)
                elif os.path.isfile(dstname):
                    os.remove(dstname)
                shutil.copy2(srcname, dstname)
                # XXX What about devices, sockets etc.?
        except (IOError, os.error) as why:
            errors.append((srcname, dstname, str(why)))
        # catch the Error from the recursive copytree so that we can
        # continue with other files
        except OSError as err:
            errors.extend(err.args[0])
    try:
        shutil.copystat(src, dst)
    except WindowsError:
        # can‘t copy file access times on Windows
        pass
    except OSError as why:
        errors.extend((src, dst, str(why)))
    if errors:
        pass
        # raise Error(errors)


def unzip(filename, filedir):
    """

    Args:
        filename: ‘foobar.zip‘  #要解壓的文件
        filedir: 解壓後放入的目錄

    Returns:

    """
    r = zipfile.is_zipfile(filename)
    if r:
        starttime = time.time()
        fz = zipfile.ZipFile(filename, ‘r‘)
        for file in fz.namelist():
            # print(file)  # 打印zip歸檔中目錄
            fz.extract(file, filedir)
        endtime = time.time()
        times = endtime - starttime
    else:
        print(‘This file is not zip file‘)
    print(‘[unzip file] time costs:‘ + str(times))


def zip(path, filename):
    """
    默認情況下,zip壓縮會保留根目錄,我們這裏不保留根目錄
    Args:
        path: 要進行壓縮的文檔目錄
        filename: ‘foobar.zip‘  # 壓縮後的文件名

    Returns:

    """
    try:
        import zlib
        compression = zipfile.ZIP_DEFLATED  # 壓縮方法
    except:
        compression = zipfile.ZIP_STORED
    starttime = time.time()
    # start = path.rfind(os.sep) + 1  # os.sep 分隔符  (保留根目錄)
    start = len(path)  # (不保留根目錄)
    z = zipfile.ZipFile(filename, mode="w", compression=compression)
    try:
        for dirpath, dirs, files in os.walk(path):
            for file in files:
                if file == filename or file == "zip.py":
                    continue
                # print(file)
                z_path = os.path.join(dirpath, file)
                z.write(z_path, z_path[start:])
        z.close()
        endtime = time.time()
        times = endtime - starttime
    except:
        if z:
            z.close()
    print(‘[create zip file] time costs:‘ + str(times))


def create_latest_package(subVersionFullPath, latestVersionFullPath, mainVersionFullPath, relativePath):
    """
    Args:
        subVersionFullPath:
        latestVersionFullPath: latest_Zip_path
        mainVersionFullPath:
        relativePath:

    Returns:

    """
    if os.path.exists(subVersionFullPath) and os.path.exists(mainVersionFullPath):  # 判斷子版本和主版本zip包是否存在
        if not os.path.exists(latestVersionFullPath):
            # 如果不存在最新版本的zip包,將子版本的最新文件與主版本的文件進行組裝,然後將組裝後的文件壓縮到最新版本所在的目錄
            oper(subVersionFullPath, mainVersionFullPath, latestVersionFullPath, relativePath)
        else:
            # 如果存在最新版本的zip包,將子版本的最新文件與最新版本的文件進行組裝,然後將組裝後的文件壓縮到最新版本所在的目錄
            oper(subVersionFullPath, latestVersionFullPath, latestVersionFullPath, relativePath)

    else:
        print "not exists {0} or {1}".format(subVersionFullPath, mainVersionFullPath)


def oper(srvZipPath, destZipPath, outZipPath, relativePath):
    """
    註意:多文件替換時,一般多文件存在壓縮包中,所以需要解壓
    基本思路 1.將最新版本的zip文件解壓到同級的tmp目錄中
            2.如果是單文件升級,則將子版本的文件拷貝到1步驟中的tmp目錄裏;如果是多文件升級,則首先需要將多文件解壓,然後再拷貝
            3.將步驟2替換後的tmp文件重新壓縮,並放到新版本的位置
    Args:
        srvZipPath: 子版本zip路徑
        destZipPath: 目標版本zip路徑
        outZipPath: 組裝後,生成新的zip文件的完整路徑
        relativePath: 單文件和多文件標識,若為None則表明多文件替換,否則單文件替換

    Returns:

    """
    # 若最終生成的zip文件所在的路徑不存在,則創建
    outZipPathDir = os.path.dirname(outZipPath)
    os.makedirs(outZipPathDir) if not os.path.exists(outZipPathDir) else ‘‘

    # 確定臨時文件的路徑
    srvZipPathTmp = os.path.dirname(srvZipPath) + os.sep + "tmp"
    destZipPathTmp = os.path.dirname(destZipPath) + os.sep + "tmp"
    print "[unzip target zip] srv:{0}   dest:{1}".format(destZipPath, destZipPathTmp)

    unzip(destZipPath, destZipPathTmp)  # 解壓目標zip文件
    if relativePath:  # 單文件和多文件標識,若為None則表明多文件替換,否則單文件替換
        print "[single file replace] srv:{0}   dest:{1}".format(srvZipPath, destZipPathTmp + relativePath)
        shutil.copy(srvZipPath, destZipPathTmp + relativePath)  # 將要升級的文件拷貝到已經解壓開的目標zip文件destZipPathTmp中
    else:
        print "[unzip source zip] srv:{0}   dest:{1}".format(srvZipPath, srvZipPathTmp)
        unzip(srvZipPath, srvZipPathTmp)
        print "[replace files] srvZipPathTmp:{0}    destZipPathTmp:{1}".format(srvZipPathTmp, destZipPathTmp)
        my_copytree(srvZipPathTmp, destZipPathTmp)  # 將要升級的文件拷貝到已經解壓開的目標zip文件destZipPathTmp中
    print "[create new zip file] srv:{0}   dest:{1}".format(destZipPathTmp, outZipPath)
    zip(destZipPathTmp, outZipPath)

    # 刪除臨時文件
    shutil.rmtree(srvZipPathTmp) if os.path.exists(srvZipPathTmp) else ‘‘
    shutil.rmtree(destZipPathTmp) if os.path.exists(destZipPathTmp) else ‘‘
    print "success"


if __name__ == ‘__main__‘:
    number = 0
    for i in sys.argv:
        print "arg{0}: {1}".format(number, i)
        number += 1
    if len(sys.argv) < 4 or len(sys.argv) > 5:
        print_usage()
    if len(sys.argv) == 4:
        create_latest_package(sys.argv[1], sys.argv[2], sys.argv[3], None)
    elif len(sys.argv) == 5:
        create_latest_package(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4])

  

python實現綠色軟件的升級,包括單文件升級和多文件升級