Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

# -*- coding:Utf-8 -*- 

""" Generic runner """ 

import os 

import subprocess 

import platform 

import hashlib 

 

from lutris import settings 

from lutris.config import LutrisConfig 

from lutris.gui.dialogs import ErrorDialog, DownloadDialog 

from lutris.util.extract import extract_archive 

from lutris.util.log import logger 

from lutris.util.system import find_executable 

 

 

def get_arch(): 

    machine = platform.machine() 

    if '64' in machine: 

        return 'x64' 

    elif '86' in machine: 

        return 'i386' 

 

 

class Runner(object): 

    """Generic runner (base class for other runners) """ 

    def __init__(self, settings=None): 

        """ Initialize runner """ 

        self.is_installable = False 

        self.game = None 

        self.depends = None 

        self.arch = get_arch() 

        self.logger = logger 

        self.settings = settings or {} 

 

    @property 

    def description(self): 

        """Return the class' docstring as the description""" 

        return self.__doc__ 

 

    @description.setter 

    def description(self, value): 

        """Leave the ability to override the docstring""" 

        self.__doc__ = value 

 

    @property 

    def name(self): 

        return self.__class__.__name__ 

 

    @property 

    def default_config(self): 

        return LutrisConfig(runner=self.name) 

 

    @property 

    def runner_config(self): 

        config = self.default_config.runner_config[self.name] 

        if self.settings[self.name]: 

            config.update(self.settings[self.name]) 

        return config 

 

    @property 

    def default_path(self): 

        """ Return the default path where games are installed """ 

        config = self.default_config.get('system') 

        if config: 

            return config.get('game_path') 

 

    @property 

    def machine(self): 

        self.logger.error("runner.machine accessed, please use platform") 

        return self.platform 

 

    def load(self, game): 

        """ Load a game """ 

        self.game = game 

 

    def play(self): 

        """dummy method, must be implemented by derived runnners""" 

        raise NotImplementedError("Implement the play method in your runner") 

 

    def check_depends(self): 

        """Check if all the dependencies for a runner are installed.""" 

        if not self.depends: 

            return True 

 

        classname = "lutris.runners.%s" % str(self.depends) 

        parts = classname.split('.') 

        module = ".".join(parts[:-1]) 

        module = __import__(module) 

        for component in parts[1:]: 

            module = getattr(module, component) 

        runner = getattr(module, str(self.depends)) 

        runner_instance = runner() 

        return runner_instance.is_installed() 

 

    def is_installed(self): 

        """Return  True if runner is installed else False""" 

        is_installed = False 

        if not self.executable: 

            return False 

        if hasattr(self, 'get_executable'): 

            if os.path.exists(self.get_executable()): 

                return True 

        result = find_executable(self.executable) 

        if result == '': 

            is_installed = False 

        else: 

            is_installed = True 

        return is_installed 

 

    def get_game_path(self): 

        """ Return the directory where the game is installed. """ 

        if hasattr(self, 'game_path'): 

            return self.game_path 

        else: 

            system_settings = self.settings.get('system') 

            if system_settings: 

                return system_settings.get('game_path') 

 

    def md5sum(self, filename): 

        """checks the md5sum of a file, does not belong here""" 

        logger.warning("please remove md5sum from Runner") 

        md5check = hashlib.md5() 

        file_ = open(filename, "rb") 

        content = file_.readlines() 

        file_.close() 

        for line in content: 

            md5check.update(line) 

        return md5check.hexdigest() 

 

    def install(self): 

        """Install runner using package management systems.""" 

 

        # Return false if runner has no package, must be then another method 

        # and install method should be overridden by the specific runner 

        if not hasattr(self, 'package'): 

            return False 

        if self.is_installable is False: 

            ErrorDialog('This runner is not yet installable') 

            return False 

 

        package_installer_candidates = ( 

            'gpk-install-package-name' 

            'software-center', 

        ) 

        package_installer = None 

        for candidate in package_installer_candidates: 

            if find_executable(candidate): 

                package_installer = candidate 

                break 

 

        if not package_installer: 

            logger.error("The distribution you're running is not supported.") 

            logger.error("Edit runners/runner.py to add support for it") 

            return False 

 

        if not self.package: 

            ErrorDialog('This runner is not yet installable') 

            logger.error("The requested runner %s can't be installed", 

                         self.__class__.__name__) 

            return False 

 

        subprocess.Popen("%s %s" % (package_installer, self.package), 

                         shell=True, stderr=subprocess.PIPE) 

        return True 

 

    def download_and_extract(self, tarball): 

        runner_archive = os.path.join(settings.CACHE_DIR, tarball) 

 

        dialog = DownloadDialog(settings.RUNNERS_URL + tarball, runner_archive) 

        dialog.run() 

 

        extract_archive(runner_archive, settings.RUNNER_DIR, 

                        merge_single=False) 

        os.remove(runner_archive) 

 

    def write_config(self, _id, name, fullpath): 

        """Write game configuration to settings directory.""" 

        system = self.__class__.__name__ 

        index = fullpath.rindex("/") 

        exe = fullpath[index + 1:] 

        path = fullpath[:index] 

        if path.startswith("file://"): 

            path = path[7:] 

        config = LutrisConfig() 

        config.config = { 

            "main": { 

                "path": path, 

                "exe": exe, 

                "realname": name, 

                "runner": system 

            } 

        } 

        config.save(config_type="game")