首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >更新libgdx游戏框架库文件

更新libgdx游戏框架库文件
EN

Code Review用户
提问于 2013-06-24 04:14:25
回答 1查看 255关注 0票数 3

我编写了剧本,通过从服务器获取最新的夜间构建.zip文件并将内容提取到适当的位置来更新游戏框架libgdx的一些库文件。

代码语言:javascript
运行
复制
#!/usr/bin/python
__appname__ = 'libgdx_library_updater'
__version__ = "0.1"
__author__ = "Jon Renner <rennerjc@gmail.com>"
__url__ = "http://github.com/jrenner/libgdx-updater"
__licence__ = "MIT"

import os, time, sys, urllib2, re, datetime, tempfile, zipfile, argparse

# error handling functions and utils

def fatal_error(msg):
    print "ERROR: %s" % msg
    sys.exit(1)

def warning_error(msg):
    print "WARNING: %s" % msg
    if not FORCE:
        answer = confirm("abort? (Y/n): ")
        if answer in YES:
            fatal_error("USER QUIT")            

def confirm(msg):
    answer = raw_input(msg)
    return answer.lower()

def human_time(t):
    minutes = t / 60
    seconds = t % 60
    return "%.0fm %.1fs" % (minutes, seconds)    

# constants

YES = ['y', 'ye', 'yes', '']
# for finding the time of the latest nightly build from the web page html
DATE_RE = r"[0-9]{1,2}-[A-Za-z]{3,4}-[0-9]{4}\s[0-9]+:[0-9]+"
REMOTE_DATE_FORMAT = "%d-%b-%Y %H:%M"

SUPPORTED_PLATFORMS = ['android', 'desktop', 'gwt']

CORE_LIBS = ["gdx.jar",
             "gdx-sources.jar"]

DESKTOP_LIBS = ["gdx-backend-lwjgl.jar",
                "gdx-backend-lwjgl-natives.jar",
                "gdx-natives.jar"] 

ANDROID_LIBS = ["gdx-backend-android.jar",
                "armeabi/libgdx.so",
                "armeabi/libandroidgl20.so",
                "armeabi-v7a/libgdx.so",
                "armeabi-v7a/libandroidgl20.so"]

GWT_LIBS = ["gdx-backend-gwt.jar"]                

# parse arguments
EPILOGUE_TEXT = "%s\n%s" % (__author__, __url__) + "\nUSE AT YOUR OWN RISK!"
parser = argparse.ArgumentParser(description='LibGDX Library Updater %s' % __version__, epilog=EPILOGUE_TEXT)
parser.add_argument('-d', '--directory', help='set the libgdx project/workspace directory', default=os.getcwd())
parser.add_argument('-i', '--interactive', action='store_true', help='ask for confirmation for every file', default=False)
parser.add_argument('-f', '--force-update', action='store_true', help='no confirmations, just update without checking nightly\'s datetime', default=False)
parser.add_argument('-a', '--archive', help='specify libgdx zip file to use for update', default=None)
args = parser.parse_args()
PROJECT_DIR = args.directory
INTERACTIVE = args.interactive
FORCE = args.force_update
ARCHIVE = args.archive

# mutually exclusive
if FORCE:
    INTERACTIVE = False

# check the time of the latest archive on the nightlies server
def get_remote_archive_mtime():
    index_page = urllib2.urlopen("http://libgdx.badlogicgames.com/nightlies/")
    contents = index_page.read()
    print "-- OK --"
    # regex for filename
    regex = r"libgdx-nightly-latest\.zip"
    # add regex for anything followed by the nighlty html time format
    regex += r".*%s" % DATE_RE
    try:
        result = re.findall(regex, contents)[0]
    except IndexError as e:
        print "REGEX ERROR: failed to find '%s' in:\n%s" % (regex, contents)
        fatal_error("regex failure to match")
    try:
        mtime = re.findall(DATE_RE, result)[0]
    except IndexError as e:
        print "REGEX ERROR: failed to find datetime in: %s" % result
        fatal_error("regex failure to match")
    dtime = datetime.datetime.strptime(mtime, REMOTE_DATE_FORMAT)
    return dtime

# downloads and returns a temporary file contained the latest nightly archive
def download_libgdx_zip():
    libgdx = tempfile.TemporaryFile()
    url = "http://libgdx.badlogicgames.com/nightlies/libgdx-nightly-latest.zip"
    # testing url - don't hammer badlogic server, host the file on localhost instead
    # url = "http://localhost/libgdx-nightly-latest.zip"
    resp = urllib2.urlopen(url)
    print "downloading file: %s" % url
    total_size = resp.info().getheader('Content-Length').strip()
    total_size = int(total_size)    
    # base 10 SI units - following Ubuntu policy because it makes sense - https://wiki.ubuntu.com/UnitsPolicy
    total_size_megabytes = total_size / 1000000.0
    bytes_read = 0
    chunk_size = 10000 # 10kB per chunk
    while True:        
        chunk = resp.read(chunk_size)
        libgdx.write(chunk)
        bytes_read += len(chunk)        
        bytes_read_megabytes = bytes_read / 1000000.0
        percent = (bytes_read / float(total_size)) * 100
        sys.stdout.write("\rprogress: {:>8}{:.2f} / {:.2f} mB ({:.0f}% complete)".format(
            "", bytes_read_megabytes, total_size_megabytes, percent))
        sys.stdout.flush()
        if bytes_read >= total_size:
            print "finished download"
            break
    return libgdx

def update_files(libs, locations, archive):    
    for lib in libs:        
        if lib in archive.namelist():            
            if INTERACTIVE:
                answer = confirm("overwrite %s? (Y/n): " % lib)
                if answer not in YES:                    
                    print "skipped: %s" % lib        
                    continue
            with archive.open(lib, "r") as fin:
                filename = os.path.basename(lib)
                final_path = os.path.join(locations[lib], filename)
                with open(final_path, "w") as fout:
                    fout.write(fin.read())                    
                print "extracted to %s" % final_path

def run_core(locations, archive):
    title("CORE")
    update_files(CORE_LIBS, locations, archive)

def run_android(locations, archive):
    title("ANDROID")
    update_files(ANDROID_LIBS, locations, archive)    

def run_desktop(locations, archive):
    title("DESKTOP")
    update_files(DESKTOP_LIBS, locations, archive)    

def run_gwt(locations, archive):
    title("GWT")
    update_files(GWT_LIBS, locations, archive)

def search_for_lib_locations(directory):    
    platforms = []
    search_list = CORE_LIBS + DESKTOP_LIBS + ANDROID_LIBS
    locations = {}    
    for element in search_list:
        locations[element] = None
    for (this_dir, dirs, files) in os.walk(directory):        
        for element in search_list:
            split_path = os.path.split(element)
            path = os.path.split(split_path[0])[-1]
            filename = split_path[1]
            for f in files:
                match = False
                if filename == f:
                    f_dir = os.path.split(this_dir)[-1]                    
                    if path == "":
                        match = True
                    else:
                        if path == f_dir:
                            match = True
                if match:
                    if locations[element] != None:
                        print "WARNING: found %s in more than one place!" % element
                        if not FORCE:
                            answer = confirm("continue? (Y/n): ")
                            if answer not in YES:
                                fatal_error("USER ABORT")
                    locations[element] = this_dir                   
    for lib, loc in locations.items():
        if loc == None:
            print "WARNING: did not find library %s in directory tree of: %s" % (lib, directory)
    found_libraries = [lib for lib, loc in locations.items() if locations[lib] != None]
    if found_all_in_set(CORE_LIBS, found_libraries):
        platforms.append("core")
    if found_all_in_set(ANDROID_LIBS, found_libraries):
        platforms.append("android")
    if found_all_in_set(DESKTOP_LIBS, found_libraries):
        platforms.append("desktop")
    if found_all_in_set(GWT_LIBS, found_libraries):
        platforms.append("gwt")
    return platforms, locations


def found_all_in_set(lib_set, found_list):
    for lib in lib_set:
        if lib not in found_list:
            return False
    return True

def main():    
    start_time = time.time()
    print "finding local libraries in %s" % PROJECT_DIR
    platforms, locations = search_for_lib_locations(PROJECT_DIR)
    if "core" not in platforms:
        fatal_error("did not find CORE libraries %s in project directory tree" % str(CORE_LIBS))
    else:
        print "found CORE libraries"
    for supported in SUPPORTED_PLATFORMS:
        if supported in platforms:
            print "found libraries for platform: %s" % supported.upper()
        else:
            print "WARNING: did not find libraries for platform: %s - WILL NOT UPDATE" % supported.upper()

    if ARCHIVE == None:
        print "checking latest nightly..."
        mtime = get_remote_archive_mtime()
        print "lastest nightly from server: %s" % mtime
        if not FORCE:
            answer = confirm("replace local libraries with files from latest nightly?(Y/n): ")    
            if answer not in YES:
                fatal_error("USER QUIT")
        libgdx = download_libgdx_zip()        
    else:
        if not os.path.exists(ARCHIVE):
            fatal_error("archive file not found: %s" % ARCHIVE)
        if not FORCE:
            answer = confirm("replace local libraries with files from '%s'?(Y/n): " % os.path.basename(ARCHIVE))    
            if answer not in YES:
                fatal_error("USER QUIT")
        libgdx = open(ARCHIVE, "r")

    with zipfile.ZipFile(libgdx) as archive:
        if "core" in platforms:        
            run_core(locations, archive)
        if "desktop" in platforms:
            run_desktop(locations, archive)
        if "android" in platforms:
            run_android(locations, archive)
        if "gwt" in platforms:
            run_gwt(locations, archive)

    duration = time.time() - start_time    
    print "finished updates in %s" % human_time(duration)
    libgdx.close()

def title(text):
    dashes = "-" * 10
    print dashes + " %s " % text + dashes

if __name__ == "__main__":
    main()
EN

回答 1

Code Review用户

回答已采纳

发布于 2013-06-24 08:38:23

你的代码看起来不错。一些注意事项:

  • 根据PEP8的说法,导入应该用单独的行来写。
  • fatal_error:我可能会把签名写成这样:fatal_error(msg, code=1)
  • INTERACTIVE -> interactive.根据PEP8的说法,全局变量应该是小写的.
  • 这是一种观点:我更喜欢用JSON风格编写多行列表/字典。您节省了缩进空间,元素的重新排序很简单(只需两行的少量成本):DESKTOP_LIBS = “gdx-后端-lwjgl.jar”,“gdx-后端-lwjgl-natives.jar”,“gdx-natives.jar”,
  • 函数download_libgdx_zipsearch_for_lib_locations是以一种非常必要的方式编写的(不必要的IMO)。我可能会用一种功能方法来重构它。至少不要重用相同的变量名来保存不同的值(即total_size),因为这就剥夺了=神圣的数学意义。
  • 这些函数run_xyz(locations, archive)看起来非常相似,为什么不是唯一的run(platform, locations, archive)
  • 函数found_all_in_set可以编写: def found_all_in_set(lib_set,found_list):返回all(lib in found_list in lib In lib_set)或: def found_all_in_set(lib_set,found_list):返回集(Lib_list).issubset(set(Found_list))
  • if ARCHIVE == None: -> if ARCHIVE is None:虽然我更喜欢(几乎)等价的、更具声明性的if not ARCHIVE:
  • 有许多命令式片段可以在功能上编写,例如,这个简单的列表理解替换了您代码中的十几行代码: platforms = zip(平台,lib)平台(平台,lib_)里面_套装(利布斯,找到)_图书馆)
票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/27715

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档