broken but cleaner

This commit is contained in:
Mathieu Comandon 2010-08-12 00:00:57 +02:00
parent 4428127ceb
commit 43cb1af48f
5 changed files with 353 additions and 259 deletions

View file

@ -17,16 +17,17 @@
import sys
import os
import gtk
import gobject
# optional Launchpad integration
# this shouldn't crash if not found as it is simply used for bug reporting
try:
import LaunchpadIntegration
launchpad_available = True
except:
launchpad_available = False
import gobject
LAUNCHPAD_AVAILABLE = True
except ImportError:
LAUNCHPAD_AVAILABLE = False
# Check if we are working in the source tree or from the installed
# package and mangle the python path accordingly
@ -39,6 +40,7 @@ else:
fullPath = os.getcwd()
sys.path.insert(0, os.path.dirname(fullPath))
from lutris.coverflow.coverflow import coverflow
from lutris.gui.dictionary_grid import DictionaryGrid
import lutris.runners
@ -59,6 +61,7 @@ from lutris.gui.google_image_dialog import GoogleImageDialog
from lutris.gui.edit_game_config_dialog import EditGameConfigDialog
class LutrisWindow(gtk.Window):
""" Main Lutris window """
__gtype_name__ = "LutrisWindow"
def __init__(self):
@ -69,8 +72,8 @@ class LutrisWindow(gtk.Window):
self.builder = builder
self.builder.connect_signals(self)
global launchpad_available
if launchpad_available:
global LAUNCHPAD_AVAILABLE
if LAUNCHPAD_AVAILABLE:
# see https://wiki.ubuntu.com/UbuntuDevelopment/Internationalisation/Coding for more information
# about LaunchpadIntegration
helpmenu = self.builder.get_object('menu3')
@ -78,11 +81,11 @@ class LutrisWindow(gtk.Window):
LaunchpadIntegration.set_sourcepackagename('lutris')
LaunchpadIntegration.add_items(helpmenu, 0, False, True)
else:
launchpad_available = False
LAUNCHPAD_AVAILABLE = False
self.game_cover_image = self.builder.get_object("game_cover_image")
self.game_cover_image.set_from_file("data/media/background.png")
self.set_title("Lutris")
#Load Lutris configuration
@ -92,7 +95,7 @@ class LutrisWindow(gtk.Window):
game_rename = "Rename", self.edit_game_name
game_config = "Configure", self.edit_game_configuration
game_get_cover = "Get cover", self.get_cover
menu_actions = [game_rename,game_config,game_get_cover]
menu_actions = [game_rename, game_config, game_get_cover]
self.menu = gtk.Menu()
for item in menu_actions:
if item == None:
@ -101,12 +104,12 @@ class LutrisWindow(gtk.Window):
subitem = gtk.ImageMenuItem(item[0])
subitem.connect("activate", item[1])
self.menu.append(subitem)
self.menu.show_all()
self.menu.show_all()
#Status bar
self.status_label = self.builder.get_object("status_label")
self.status_label.set_text("Game on!")
self.joystick_icons = []
self.joystick_icons.append(self.builder.get_object("js0image"))
self.joystick_icons.append(self.builder.get_object("js1image"))
@ -115,15 +118,16 @@ class LutrisWindow(gtk.Window):
for joystick_icon in self.joystick_icons:
joystick_icon.hide()
#Toolbar
# Toolbar
self.toolbar = self.builder.get_object("lutris_toolbar")
#Game list
# Game list
self.game_list = self.get_game_list()
self.game_list_grid_view = DictionaryGrid(self.game_list,["Game Name","Runner"])
self.game_list_grid_view.connect('row-activated',self.game_launch)
self.game_list_grid_view = DictionaryGrid(self.game_list,
["Game Name", "Runner"])
self.game_list_grid_view.connect('row-activated', self.game_launch)
self.game_list_grid_view.connect("cursor-changed", self.select_game)
self.game_list_grid_view.connect("button-press-event", self.mouse_menu)
self.game_list_grid_view.connect("button-press-event", self.mouse_menu)
self.game_list_grid_view.show()
self.game_column = self.game_list_grid_view.get_column(0)
@ -138,36 +142,35 @@ class LutrisWindow(gtk.Window):
self.timer_id = gobject.timeout_add(1000, self.refresh_status)
def refresh_status(self):
###FIXME !!
# if hasattr(self.running_game.game_process, "pid"):
# self.status_text = "Game is running (pid: %s)" % str(self.running_game.game_process.pid)
# self.status_bar.push(self.status_bar_context_id,self.status_text)
# else:
# self.status_bar.push(self.status_bar_context_id,"Welcome to Lutris")
for index in range(0,3):
# FIXME !!
# if hasattr(self.running_game.game_process, "pid"):
# self.status_text = "Game is running (pid: %s)" % str(self.running_game.game_process.pid)
# self.status_bar.push(self.status_bar_context_id,self.status_text)
# else:
# self.status_bar.push(self.status_bar_context_id,"Welcome to Lutris")
for index in range(0, 3):
if os.path.exists("/dev/input/js%d" % index):
self.joystick_icons[index].show()
else:
self.joystick_icons[index].hide()
return True
def get_game_list(self):
game_list = []
for file in os.listdir(lutris.constants.game_config_path):
if file.endswith(lutris.constants.config_extension):
game_name = file[:len(file)-len(lutris.constants.config_extension)]
game_name = file[:len(file) - len(lutris.constants.config_extension)]
Game = LutrisGame(game_name)
if not Game.load_success:
message = "Error while loading configuration for %s" % game_name
error_dialog = gtk.MessageDialog(parent=self, flags=0,
type=gtk.MESSAGE_ERROR,
buttons=gtk.BUTTONS_OK,
error_dialog = gtk.MessageDialog(parent=self, flags=0,
type=gtk.MESSAGE_ERROR,
buttons=gtk.BUTTONS_OK,
message_format=message)
error_dialog.run()
error_dialog.destroy()
game_list.append({"Game Name":Game.real_name,"Runner":Game.runner_name,"name":game_name})
return game_list
game_list.append({"Game Name":Game.real_name, "Runner":Game.runner_name, "name":game_name})
return game_list
def about(self, widget, data=None):
"""about - display the about box for lutris """
@ -177,14 +180,15 @@ class LutrisWindow(gtk.Window):
def quit(self, widget, data=None):
"""quit - signal handler for closing the LutrisWindow"""
self.destroy()
def on_destroy(self, widget, data=None):
"""on_destroy - called when the LutrisWindow is close. """
#clean up code for saving application state should be added here
gtk.main_quit()
def mouse_menu(self,widget,event):
def mouse_menu(self, widget, event):
if event.button == 3:
(model, self.paths) = widget.get_selection().get_selected_rows()
try:
@ -192,9 +196,9 @@ class LutrisWindow(gtk.Window):
except IndexError:
return
if len(self.paths) > 0:
self.menu.popup(None, None, None, event.button, event.time)
self.menu.popup(None, None, None, event.button, event.time)
def remove_game(self,widget,data=None):
def remove_game(self, widget, data=None):
"""Remove game configuration file
Note: this won't delete the actual game"""
if not self.gameName:
@ -212,7 +216,7 @@ class LutrisWindow(gtk.Window):
model, select_iter = gameSelection.get_selected()
game_name = model.get_value(select_iter, 2)
return game_name["name"]
def select_game(self, treeview):
gameSelection = treeview.get_selection()
model, select_iter = gameSelection.get_selected()
@ -220,47 +224,47 @@ class LutrisWindow(gtk.Window):
self.gameName = model.get_value(select_iter, 2)["name"]
self.set_game_cover()
def on_mount_iso_menuitem_activate(self,widget):
mount_iso_dialog = MountIsoDialog()
def on_fullscreen_clicked(self,widget):
game = lutris.coverflow.coverflow.coverflow()
if game:
if game == "NOCOVERS":
def on_fullscreen_clicked(self, widget):
""" Switch to coverflow mode """
coverflow = lutris.coverflow.coverflow.coverflow()
if coverflow:
if coverflow == "NOCOVERS":
logging.error("Add some covers to these games first !")
return
if game == "NOPYGLET":
if coverflow == "NOPYGLET":
logging.debug("python-pyglet is not installed")
return
filename = os.path.basename(game)
filename = os.path.basename(coverflow)
game_name = filename[:filename.rfind(".")]
running_game = LutrisGame(game_name)
running_game.play()
def reset(self,widget,data=None):
if hasattr(self,"running_game"):
def reset(self, widget, data=None):
if hasattr(self, "running_game"):
self.running_game.quit_game()
else:
LutrisDesktopControl().reset_desktop()
def install_game(self,widget,data=None):
def install_game(self, widget, data=None):
installer_dialog = InstallerDialog(self)
def add_game(self,widget,data=None):
def add_game(self, widget, data=None):
add_game_dialog = AddGameDialog(self)
if hasattr(add_game_dialog,"game_info"):
if hasattr(add_game_dialog, "game_info"):
game_info = add_game_dialog.game_info
self.game_list_grid_view.append_row(game_info)
def import_cedega(self,widget,data=None):
def import_cedega(self, widget, data=None):
cedega = lutris.runners.cedega.cedega()
cedega.import_games()
self.get_game_list()
def import_steam(self,widget,data=None):
def import_steam(self, widget, data=None):
logging.debug("Import from steam not yet implemented")
def import_scummvm(self,widget,data=None):
def import_scummvm(self, widget, data=None):
scummvm = lutris.runners.scummvm.scummvm()
scummvm.import_games()
games = self.get_game_list()
@ -271,55 +275,59 @@ class LutrisWindow(gtk.Window):
if game['name'] not in current_game_names:
self.game_list_grid_view.append_row(game)
def on_getfromftp_clicked(self,widget,data=None):
def on_getfromftp_clicked(self, widget, data=None):
FtpDialog()
def system_preferences(self,widget,data=None):
def system_preferences(self, widget, data=None):
SystemConfigDialog()
def runner_preferences(self,widget,data=None):
def runner_preferences(self, widget, data=None):
RunnersDialog()
def edit_game_name(self,button):
"""Change game name"""
self.game_cell.set_property('editable',True)
self.game_list_grid_view.set_cursor(self.paths[0][0],self.game_column,True)
def on_mount_iso_menuitem_activate(self, widget):
MountIsoDialog()
def game_name_edited_callback(self,widget,index,new_name):
def edit_game_name(self, button):
"""Change game name"""
self.game_cell.set_property('editable', True)
self.game_list_grid_view.set_cursor(self.paths[0][0], self.game_column, True)
def game_name_edited_callback(self, widget, index, new_name):
self.game_list_grid_view.get_model()[index][0] = new_name
new_name_game_config = LutrisConfig(game=self.get_selected_game())
new_name_game_config.config["realname"] =new_name
new_name_game_config.config["realname"] = new_name
new_name_game_config.save(type="game")
self.game_cell.set_property('editable',False)
self.game_cell.set_property('editable', False)
def edit_game_configuration(self,button):
def edit_game_configuration(self, button):
"""Edit game preferences"""
game = self.get_selected_game()
EditGameConfigDialog(self,game)
EditGameConfigDialog(self, game)
def get_cover(self,button):
def get_cover(self, button):
"""Fetch cover from Google Image"""
game = self.get_selected_game()
GoogleImageDialog(game)
def set_game_cover(self):
if self.gameName:
extensions = ["png", "jpg", "jpeg"]
for extension in extensions:
coverFile = os.path.join(lutris.constants.cover_path, self.gameName + "." + extension)
coverFile = os.path.join(lutris.constants.cover_path,
self.gameName + "." + extension)
if os.path.exists(coverFile):
#Resize the image
cover_pixbuf = gtk.gdk.pixbuf_new_from_file(coverFile)
dest_w = 250.0
h = cover_pixbuf.get_height()
w = cover_pixbuf.get_width()
dest_h = h * (dest_w/w)
self.game_cover_image.set_from_pixbuf(cover_pixbuf.scale_simple(int(dest_w),int(dest_h),gtk.gdk.INTERP_BILINEAR))
dest_h = h * (dest_w / w)
self.game_cover_image.set_from_pixbuf(cover_pixbuf.scale_simple(int(dest_w), int(dest_h), gtk.gdk.INTERP_BILINEAR))
return
else:
self.game_cover_image.set_from_file("data/media/background.png")
def NewLutrisWindow():
"""NewLutrisWindow - returns a fully instantiated
def new_lutris_window():
"""new_lutris_window - returns a fully instantiated
LutrisWindow object. Use this function rather than
creating a LutrisWindow directly.
"""
@ -336,36 +344,39 @@ def NewLutrisWindow():
return window
if __name__ == "__main__":
#support for command line options
import logging, optparse
# Support for command line options.
import logging
import optparse
parser = optparse.OptionParser(version="%prog %ver")
parser.add_option("-v", "--verbose", action="store_true", dest="verbose", help="Show debug messages")
parser.add_option("-v", "--verbose", action="store_true",
dest="verbose", help="Show debug messages")
(options, args) = parser.parse_args()
#set the logging level to show debug messages
# Set the logging level to show debug messages.
if options.verbose:
logging.basicConfig(level=logging.DEBUG)
logging.debug('logging enabled')
#run the application
# Run the application.
game = None
for arg in args:
if arg.startswith('lutris://'):
print 'will install : ' + arg[9:]
print 'Installing ' + arg[9:]
game = arg[9:]
break
if game:
#TODO: Fetch the .lutris file
#Todo : install the game
installer = Installer(game)
installer.install()
#window = lutris.gui.InstallerDialog(name=game)
success = installer.pre_install()
if not success:
print "Unable to install game"
else:
print "Ready! Launching installer."
installer.install()
exit()
else:
window = NewLutrisWindow()
window.show()
lutris_window = new_lutris_window()
lutris_window.show()
gtk.gdk.threads_init()
gtk.gdk.threads_enter()
gtk.main()
gtk.gdk.threads_leave()

View file

@ -19,11 +19,10 @@
## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
###############################################################################
import gtk
import lutris.runners
import logging
import lutris.runners
from lutris.config import LutrisConfig
from lutris.game_config_vbox import GameConfigVBox
from lutris.runner_config_vbox import RunnerConfigVBox
@ -119,7 +118,7 @@ class AddGameDialog(gtk.Dialog):
logging.debug(self.lutris_config.game_config)
if self.runner_class and realname:
game_identifier = self.lutris_config.save(type = "game")
game_identifier = self.lutris_config.save(type="game")
self.game_info = {"Game Name": realname, "Runner": self.runner_class , "name": game_identifier}
self.destroy()
@ -155,7 +154,7 @@ class AddGameDialog(gtk.Dialog):
self.system_config_scrolled_window.show_all()
def close(self, widget = None, other = None):
def close(self, widget=None, other=None):
self.destroy()
def no_runner_selected(self):

View file

@ -22,30 +22,32 @@
import yaml
import os
import logging
import copy
import lutris.constants as constants
class LutrisConfig():
def __init__(self, runner=None, game=None):
def __init__(self, runner = None, game = None):
#Check if configuration directories exists and create them if needed.
config_paths = [constants.lutris_config_path, \
constants.runner_config_path, \
constants.game_config_path, \
constants.cover_path, \
constants.tmp_path ]
config_paths = [
constants.lutris_config_path,
constants.runner_config_path,
constants.game_config_path,
constants.cover_path,
constants.tmp_path,
constants.cache_path
]
for config_path in config_paths:
if not os.path.exists(config_path):
os.mkdir(config_path)
#Initialize configuration
self.config = {}
self.game_config = {}
self.runner_config = {}
self.system_config = {}
self.game = None
self.runner = None
#By default config type is system, it can also be runner and game
#this means that when you call lutris_config_instance["key"] is will
#pick up the right configuration depending of config_type
@ -63,14 +65,14 @@ class LutrisConfig():
if self.system_config is None:
self.system_config = {}
else:
file(constants.system_config_full_path,"w+")
file(constants.system_config_full_path, "w+")
if self.game:
game_config_full_path = os.path.join(constants.game_config_path,
self.game + constants.config_extension)
if os.path.exists(game_config_full_path):
try:
self.game_config = yaml.load(file(game_config_full_path,'r').read())
self.game_config = yaml.load(file(game_config_full_path, 'r').read())
self.runner = self.game_config["runner"]
except yaml.scanner.ScannerError:
logging.debug("error parsing config file %s" % game_config_full_path)
@ -81,10 +83,10 @@ class LutrisConfig():
runner_config_full_path = os.path.join(constants.runner_config_path,
self.runner + constants.config_extension)
if os.path.exists(runner_config_full_path):
self.runner_config = yaml.load(file(runner_config_full_path,'r').read())
self.runner_config = yaml.load(file(runner_config_full_path, 'r').read())
self.update_global_config()
def __getitem__(self,key):
def __getitem__(self, key):
"""Allows to access config data directly by keys"""
if self.config_type == "game":
value = self.game_config[key]
@ -94,7 +96,7 @@ class LutrisConfig():
value = self.system_config[key]
return value
def __setitem__(self,key,value):
def __setitem__(self, key, value):
if self.config_type == "game":
self.game_config[key] = value
elif self.config_type == "runner":
@ -109,7 +111,7 @@ class LutrisConfig():
self.config[key].update(self.system_config[key])
else:
self.config[key] = self.system_config[key]
for key in self.runner_config.keys():
if key in self.config:
self.config[key].update(self.runner_config[key])
@ -122,12 +124,12 @@ class LutrisConfig():
self.config[key].update(self.game_config[key])
else:
self.config[key] = self.game_config[key]
def remove(self,game_name):
logging.debug("removing %s" % game_name)
os.remove(os.path.join(constants.game_config_path,game_name+constants.config_extension))
def save(self,type=None):
def remove(self, game_name):
logging.debug("removing %s" % game_name)
os.remove(os.path.join(constants.game_config_path, game_name + constants.config_extension))
def save(self, type = None):
"""Save configuration file
The way to save config files can be set by the type argument
or with self.config_type"""
@ -137,38 +139,39 @@ class LutrisConfig():
logging.debug(self.config)
if type is None:
type = self.config_type
yaml_config = yaml.dump(self.config,default_flow_style=False)
yaml_config = yaml.dump(self.config, default_flow_style = False)
if type == "system":
file(constants.system_config_full_path,"w").write(yaml_config)
file(constants.system_config_full_path, "w").write(yaml_config)
elif type == "runner":
runner_config_path = os.path.join(constants.runner_config_path,self.runner+constants.config_extension)
file(runner_config_path,"w").write(yaml_config)
runner_config_path = os.path.join(constants.runner_config_path, self.runner + constants.config_extension)
file(runner_config_path, "w").write(yaml_config)
elif type == "game":
if not self.game:
self.game = self.config["runner"] + "-" + self.config["realname"].replace(" ","_")
self.game = self.config["runner"] + "-" + self.config["realname"].replace(" ", "_")
self.game_config_path = os.path.join(constants.game_config_path,
self.game.replace('/','_') + constants.config_extension)
config_file = file(self.game_config_path,"w")
self.game.replace('/', '_') + constants.config_extension)
config_file = file(self.game_config_path, "w")
config_file.write(yaml_config)
return self.game
else:
print "Config type is %s or %s" % (self.config_type, type)
print "i don't know how to save this yet"
def get_path(self,runner):
def get_path(self, runner = None, default = None):
"""Gets the path to install games for a given runner"""
if "system" in self.config:
if "game_path" in self.config["system"]:
return self.config["system"]["game_path"]
logging.debug("Fail !")
logging.debug(self.config)
return os.path.expanduser("~")
if __name__ == "__main__":
logging.basicConfig(level=logging.DEBUG)
logging.basicConfig(level = logging.DEBUG)
logging.debug('logging enabled')
lc = LutrisConfig(runner="wine")
lc = LutrisConfig(runner = "wine")
print "system config : "
print lc.system_config
print "runner config : "
@ -180,7 +183,7 @@ if __name__ == "__main__":
print ("* testing games *")
print ("*****************")
lc = LutrisConfig(game="wine-Ghostbusters")
lc = LutrisConfig(game = "wine-Ghostbusters")
print "system config : "
print lc.system_config
print ("-----------------------")
@ -193,4 +196,4 @@ if __name__ == "__main__":
print "global config"
print lc.config

View file

@ -25,7 +25,6 @@ import sys
name = "Lutris"
version = "0.2"
website = "http://lutris.net"
#installer_prefix = "http://localhost:8000/media/installers/"
installer_prefix = "http://lutris.net/media/installers/"
config_extension = ".yml"
license = 'GPL-3'
@ -53,6 +52,7 @@ lutris_icon_path = os.path.join(sys.path[0], lutris_icon_file)
#Config files
lutris_config_path = os.path.join(os.path.expanduser('~'), '.config', 'lutris')
system_config_file = 'system' + config_extension
protocol_version = 1
system_config_full_path = os.path.join(lutris_config_path, system_config_file)
runner_config_path = os.path.join(lutris_config_path, 'runners"')

View file

@ -1,170 +1,251 @@
# -*- coding:Utf-8 -*-
###############################################################################
## Lutris
##
## Copyright (C) 2009 Mathieu Comandon strycore@gmail.com
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 3 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
###############################################################################
""" Here is your docstring ... """
import os
import logging
import yaml
import shutil
import urllib
import urllib2
import logging
import subprocess
import shutil
import time
import yaml
import platform
from lutris.config import LutrisConfig
import lutris.constants
from distutils.command.install_data import install_data
from lutris.config import LutrisConfig
def unzip(filename):
"""Unzips a file"""
subprocess.Popen(["_unzip", 'o', filename])
def unrar(filename):
"""Unrar a file"""
subprocess.Popen(["_unrar", "x", filename])
def untgz(filename):
"""Untgz a file"""
subprocess.Popen(["tar", "xzf", filename])
def run_installer(filename):
"""Run an installer of .sh or .run type"""
subprocess.Popen(["chmod", "+x", filename])
subprocess.Popen([filename])
def reporthook(arg1, received_bytes, total_size):
"""Follows the progress of a download"""
print "What is this ? : %d " % arg1
print "received_bytes : %d " % received_bytes
print "total_size : %d" % total_size
def check_md5(data):
""" Calculates the checksum of a file and validates it. """
print 'checking md5 for file ' + self.gamefiles[data['file']]
print 'expecting ' + data['value']
print "NOT IMPLEMENTED"
return True
class Installer():
""" Lutris installer """
def __init__(self, game):
self.supported_protocol_version = 1
self.lutris_config = LutrisConfig()
self.website_url = lutris.constants.installer_prefix
self.installer_cache = lutris.constants.cache_path
self.gameName = game
self.game_name = game
self.installer_dest_path = os.path.join(lutris.constants.cache_path,
self.game_name + ".yml")
# Stores a list of actions that will be sent back to the user
# in order to complete the installation
self.installer_user_actions = []
# Actions that the installer has to run
# in order to complete the install.
self.installer_actions = []
# List of errors that occurred while installing the game
self.installer_errors = []
# ???
self.install_data = []
# Essential game information to create Lutris launcher
self.game_info = {}
#FIXME : The thing that should not be
self.gamesDir = "/media/seagate300/games/"
self.gameDir = os.path.join(self.gamesDir, self.gameName)
if not os.path.exists(self.gameDir):
os.mkdir(self.gameDir)
self.lutrisConfigDir = lutris.constants.lutris_config_path
self.installer_dest_path = os.path.join(self.installer_cache, self.gameName + ".yml")
#WTF ?
self.totalDownloaded = 0
# Dictionary of the files needed to install the game
self.gamefiles = {}
def set_games_dir(self, path):
""" Set the base path where the game will be installed """
self.games_dir = path
def pre_install(self):
"""Reads the installer and checks everything is OK
before beginning the install process
"""
success = self.save_installer_content()
if not success:
return False
success = self.parseconfig()
self.games_dir = self.lutris_config.get_path(
runner=self.game_info['runner'])
if not self.games_dir:
self.installer_user_actions.append("ask_games_dir")
self.game_dir = os.path.join(self.games_dir, self.game_name)
if not os.path.exists(self.game_dir):
os.mkdir(self.game_dir)
return success
def install(self):
self.save_installer_content()
success = self.parseconfig()
if success:
self.writeConfig()
else:
print "Installer failed"
""" Runs the actions to complete the install. """
def save_installer_content(self):
print 'downloading installer for ' + self.gameName
full_url = self.website_url + self.gameName + '.yml'
request = urllib2.Request(url = full_url)
f = urllib2.urlopen(request)
os.chdir(self.game_dir)
installer_file = open(self.installer_dest_path, "w")
installer_file.write(f.read())
installer_file.close()
#TODO : Check size
def parseconfig(self):
self.install_data = yaml.load(file(self.installer_dest_path, 'r').read())
#Checking protocol
protocol_version = self.install_data['protocol']
if protocol_version != self.supported_protocol_version:
print "Wrong protocol version (Expected %d, got %d)" % (self.supported_protocol_version, protocol_version)
return False
mandatory_fields = ['version', 'runner', 'name']
optional_fields = ['exe']
for field in mandatory_fields:
self.game_info[field] = self.install_data[field]
for field in optional_fields:
if field in self.install_data:
self.game_info[field] = self.install_data[field]
files = self.install_data['files']
self.gamefiles = {}
for gamefile in files:
file_id = gamefile.keys()[0]
dest_path = self.download(gamefile[file_id])
self.gamefiles[file_id] = dest_path
installer_actions = self.install_data['installer']
#FIXME ?
os.chdir(self.gameDir)
for action in installer_actions:
for action in self.installer_actions:
action_name = action.keys()[0]
action_data = action[action_name]
mappings = {
'check_md5': self.check_md5,
'extract' : self.extract,
'move' : self.move,
'delete': self.delete
'check_md5': check_md5,
'extract' : self._extract,
'move' : self._move
}
if action_name not in mappings.keys():
print "Action " + action_name + " not supported !"
return False
mappings[action_name](action_data)
return True
def writeConfig(self):
config_filename = os.path.join(self.lutrisConfigDir,
"games" , self.game_info['runner'] + "-" + self.gameName + ".yml")
config_file = open(config_filename, "w")
config_data = {
'game': {},
'realname': self.game_info['name'],
'runner': self.game_info['runner']
}
if('exe' in self.game_info):
config_data['game']['exe'] = os.path.join(self.gameDir, self.game_info['exe'])
yaml_config = yaml.dump(config_data, default_flow_style=False)
file(config_filename, "w").write(yaml_config)
self.write_config()
def reporthook(self, arg1, bytes, totalSize):
self.totalDownloaded = self.totalDownloaded + bytes
#print self.totalDownloaded / totalSize * 100.0
def save_installer_content(self):
""" Save the downloaded installer to disk. """
def download(self, url):
logging.debug('Downloading ' + url)
destFile = os.path.join(self.gamesDir, self.gameName, url.split("/")[-1])
if os.path.exists(destFile):
return destFile
if url.startswith("file://"):
shutil.copy(url[7:], self.gameDir)
print 'downloading installer for ' + self.game_name
full_url = lutris.constants.installer_prefix + self.game_name + '.yml'
request = urllib2.Request(url=full_url)
try:
response = urllib2.urlopen(request)
except urllib2.URLError:
print "Server is unreachable"
self.installer_errors.append("SERVER_UNREACHABLE")
success = False
else:
urllib.urlretrieve(url, destFile, self.reporthook)
return destFile
installer_file = open(self.installer_dest_path, "w")
installer_file.write(response.read())
installer_file.close()
success = True
finally:
return success
def check_md5(self, data):
print 'checking md5 for file ' + self.gamefiles[data['file']]
print 'expecting ' + data['value']
print "NOT IMPLEMENTED"
return True
def parseconfig(self):
""" Reads the installer file. """
self.install_data = yaml.load(file(self.installer_dest_path,
'r').read())
#Checking protocol
protocol_version = self.install_data['protocol']
if protocol_version != lutris.constants.protocol_version:
print("Wrong protocol version (Expected %d, got %d)" %
(lutris.constants.protocol_version, protocol_version))
return False
#Script version
self.game_info['version'] = self.install_data['version']
#Runner
self.game_info['runner'] = self.install_data['runner']
#Name
self.game_info['name'] = self.install_data['name']
files = self.install_data['files']
for gamefile in files:
file_id = gamefile.keys()[0]
dest_path = self._download(gamefile[file_id])
self.gamefiles[file_id] = dest_path
self.installer_actions = self.install_data['installer']
def write_config(self):
""" Writes the game configration as a Lutris launcher. """
config_filename = os.path.join(lutris.constants.lutris_config_path, "games",
self.game_name + ".conf")
config_file = open(config_filename, "w")
config_file.write("[main]\n")
config_file.write("path = " + self.game_dir + "\n")
if('exe' in self.game_info):
config_file.write("exe = " + self.game_info['exe'] + "\n")
config_file.write("runner = " + self.game_info['runner'])
config_file.close()
def _download(self, url):
""" Downloads a file. """
logging.debug('Downloading ' + url)
dest_dir = os.path.join(lutris.constants.tmp_path, self.game_name)
if not os.path.exists(dest_dir):
os.mkdir(dest_dir)
dest_file = os.path.join(dest_dir, url.split("/")[-1])
if os.path.exists(dest_file):
return dest_file
if url.startswith("file://"):
shutil.copy(url[7:], self.game_dir)
else:
urllib.urlretrieve(url, dest_file, reporthook)
return dest_file
def _extract(self, data):
""" Extracts a file, guessing the compression method """
def extract(self, data):
print 'extracting ' + data['file']
filename = self.gamefiles[data['file']]
print "NOT IMPLEMENTED"
extension = filename[filename.rfind(".") + 1:]
if extension == "zip":
self.unzip(filename)
unzip(filename)
def move(self, data):
src = os.path.join(self.gameDir, data['src'])
if not os.path.exists(src):
time.sleep(1)
if not os.path.exists(src):
return False
def _move(self, data):
""" Moves a file. """
src = data['src']
destination_alias = data['dst']
if destination_alias == 'gamedir':
dst = self.gameDir;
dst = self.game_dir
else:
dst = '/tmp'
print "Moving %s to %s" % (src, dst)
shutil.move(src, dst)
def unzip(self, file):
subprocess.call(["unzip", '-o', '-qq', file])
try:
shutil.move(src, dst)
except ValueError:
print "Could not move the file, destination already exists ?"
def unrar(self, file):
subprocess.Popen(["unrar", "x", file])
def untgz(self, file):
subprocess.Popen(["tar", "xzf", file])
def runInstaller(self, file):
subprocess.Popen(["chmod", "+x", file])
subprocess.Popen([file])
def delete(self, data):
print "let's not delete anything right now, m'kay ?"
if __name__ == "__main__":
quakeInstall = LutrisInstaller("quake")
quakeInstall.install()