xref: /openbsd-src/gnu/llvm/clang/tools/scan-view/share/startfile.py (revision e5dd70708596ae51455a0ffa086a00c5b29f8583)
1*e5dd7070Spatrick#!/usr/bin/env python
2*e5dd7070Spatrick# -*- coding: utf-8 -*-
3*e5dd7070Spatrick
4*e5dd7070Spatrick"""Utility for opening a file using the default application in a cross-platform
5*e5dd7070Spatrickmanner. Modified from http://code.activestate.com/recipes/511443/.
6*e5dd7070Spatrick"""
7*e5dd7070Spatrick
8*e5dd7070Spatrick__version__ = '1.1x'
9*e5dd7070Spatrick__all__ = ['open']
10*e5dd7070Spatrick
11*e5dd7070Spatrickimport os
12*e5dd7070Spatrickimport sys
13*e5dd7070Spatrickimport webbrowser
14*e5dd7070Spatrickimport subprocess
15*e5dd7070Spatrick
16*e5dd7070Spatrick_controllers = {}
17*e5dd7070Spatrick_open = None
18*e5dd7070Spatrick
19*e5dd7070Spatrick
20*e5dd7070Spatrickclass BaseController(object):
21*e5dd7070Spatrick    '''Base class for open program controllers.'''
22*e5dd7070Spatrick
23*e5dd7070Spatrick    def __init__(self, name):
24*e5dd7070Spatrick        self.name = name
25*e5dd7070Spatrick
26*e5dd7070Spatrick    def open(self, filename):
27*e5dd7070Spatrick        raise NotImplementedError
28*e5dd7070Spatrick
29*e5dd7070Spatrick
30*e5dd7070Spatrickclass Controller(BaseController):
31*e5dd7070Spatrick    '''Controller for a generic open program.'''
32*e5dd7070Spatrick
33*e5dd7070Spatrick    def __init__(self, *args):
34*e5dd7070Spatrick        super(Controller, self).__init__(os.path.basename(args[0]))
35*e5dd7070Spatrick        self.args = list(args)
36*e5dd7070Spatrick
37*e5dd7070Spatrick    def _invoke(self, cmdline):
38*e5dd7070Spatrick        if sys.platform[:3] == 'win':
39*e5dd7070Spatrick            closefds = False
40*e5dd7070Spatrick            startupinfo = subprocess.STARTUPINFO()
41*e5dd7070Spatrick            startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
42*e5dd7070Spatrick        else:
43*e5dd7070Spatrick            closefds = True
44*e5dd7070Spatrick            startupinfo = None
45*e5dd7070Spatrick
46*e5dd7070Spatrick        if (os.environ.get('DISPLAY') or sys.platform[:3] == 'win' or
47*e5dd7070Spatrick                                                    sys.platform == 'darwin'):
48*e5dd7070Spatrick            inout = file(os.devnull, 'r+')
49*e5dd7070Spatrick        else:
50*e5dd7070Spatrick            # for TTY programs, we need stdin/out
51*e5dd7070Spatrick            inout = None
52*e5dd7070Spatrick
53*e5dd7070Spatrick        # if possible, put the child precess in separate process group,
54*e5dd7070Spatrick        # so keyboard interrupts don't affect child precess as well as
55*e5dd7070Spatrick        # Python
56*e5dd7070Spatrick        setsid = getattr(os, 'setsid', None)
57*e5dd7070Spatrick        if not setsid:
58*e5dd7070Spatrick            setsid = getattr(os, 'setpgrp', None)
59*e5dd7070Spatrick
60*e5dd7070Spatrick        pipe = subprocess.Popen(cmdline, stdin=inout, stdout=inout,
61*e5dd7070Spatrick                                stderr=inout, close_fds=closefds,
62*e5dd7070Spatrick                                preexec_fn=setsid, startupinfo=startupinfo)
63*e5dd7070Spatrick
64*e5dd7070Spatrick        # It is assumed that this kind of tools (gnome-open, kfmclient,
65*e5dd7070Spatrick        # exo-open, xdg-open and open for OSX) immediately exit after launching
66*e5dd7070Spatrick        # the specific application
67*e5dd7070Spatrick        returncode = pipe.wait()
68*e5dd7070Spatrick        if hasattr(self, 'fixreturncode'):
69*e5dd7070Spatrick            returncode = self.fixreturncode(returncode)
70*e5dd7070Spatrick        return not returncode
71*e5dd7070Spatrick
72*e5dd7070Spatrick    def open(self, filename):
73*e5dd7070Spatrick        if isinstance(filename, basestring):
74*e5dd7070Spatrick            cmdline = self.args + [filename]
75*e5dd7070Spatrick        else:
76*e5dd7070Spatrick            # assume it is a sequence
77*e5dd7070Spatrick            cmdline = self.args + filename
78*e5dd7070Spatrick        try:
79*e5dd7070Spatrick            return self._invoke(cmdline)
80*e5dd7070Spatrick        except OSError:
81*e5dd7070Spatrick            return False
82*e5dd7070Spatrick
83*e5dd7070Spatrick
84*e5dd7070Spatrick# Platform support for Windows
85*e5dd7070Spatrickif sys.platform[:3] == 'win':
86*e5dd7070Spatrick
87*e5dd7070Spatrick    class Start(BaseController):
88*e5dd7070Spatrick        '''Controller for the win32 start program through os.startfile.'''
89*e5dd7070Spatrick
90*e5dd7070Spatrick        def open(self, filename):
91*e5dd7070Spatrick            try:
92*e5dd7070Spatrick                os.startfile(filename)
93*e5dd7070Spatrick            except WindowsError:
94*e5dd7070Spatrick                # [Error 22] No application is associated with the specified
95*e5dd7070Spatrick                # file for this operation: '<URL>'
96*e5dd7070Spatrick                return False
97*e5dd7070Spatrick            else:
98*e5dd7070Spatrick                return True
99*e5dd7070Spatrick
100*e5dd7070Spatrick    _controllers['windows-default'] = Start('start')
101*e5dd7070Spatrick    _open = _controllers['windows-default'].open
102*e5dd7070Spatrick
103*e5dd7070Spatrick
104*e5dd7070Spatrick# Platform support for MacOS
105*e5dd7070Spatrickelif sys.platform == 'darwin':
106*e5dd7070Spatrick    _controllers['open']= Controller('open')
107*e5dd7070Spatrick    _open = _controllers['open'].open
108*e5dd7070Spatrick
109*e5dd7070Spatrick
110*e5dd7070Spatrick# Platform support for Unix
111*e5dd7070Spatrickelse:
112*e5dd7070Spatrick
113*e5dd7070Spatrick    try:
114*e5dd7070Spatrick        from commands import getoutput
115*e5dd7070Spatrick    except ImportError:
116*e5dd7070Spatrick        from subprocess import getoutput
117*e5dd7070Spatrick
118*e5dd7070Spatrick    # @WARNING: use the private API of the webbrowser module
119*e5dd7070Spatrick    from webbrowser import _iscommand
120*e5dd7070Spatrick
121*e5dd7070Spatrick    class KfmClient(Controller):
122*e5dd7070Spatrick        '''Controller for the KDE kfmclient program.'''
123*e5dd7070Spatrick
124*e5dd7070Spatrick        def __init__(self, kfmclient='kfmclient'):
125*e5dd7070Spatrick            super(KfmClient, self).__init__(kfmclient, 'exec')
126*e5dd7070Spatrick            self.kde_version = self.detect_kde_version()
127*e5dd7070Spatrick
128*e5dd7070Spatrick        def detect_kde_version(self):
129*e5dd7070Spatrick            kde_version = None
130*e5dd7070Spatrick            try:
131*e5dd7070Spatrick                info = getoutput('kde-config --version')
132*e5dd7070Spatrick
133*e5dd7070Spatrick                for line in info.splitlines():
134*e5dd7070Spatrick                    if line.startswith('KDE'):
135*e5dd7070Spatrick                        kde_version = line.split(':')[-1].strip()
136*e5dd7070Spatrick                        break
137*e5dd7070Spatrick            except (OSError, RuntimeError):
138*e5dd7070Spatrick                pass
139*e5dd7070Spatrick
140*e5dd7070Spatrick            return kde_version
141*e5dd7070Spatrick
142*e5dd7070Spatrick        def fixreturncode(self, returncode):
143*e5dd7070Spatrick            if returncode is not None and self.kde_version > '3.5.4':
144*e5dd7070Spatrick                return returncode
145*e5dd7070Spatrick            else:
146*e5dd7070Spatrick                return os.EX_OK
147*e5dd7070Spatrick
148*e5dd7070Spatrick    def detect_desktop_environment():
149*e5dd7070Spatrick        '''Checks for known desktop environments
150*e5dd7070Spatrick
151*e5dd7070Spatrick        Return the desktop environments name, lowercase (kde, gnome, xfce)
152*e5dd7070Spatrick        or "generic"
153*e5dd7070Spatrick
154*e5dd7070Spatrick        '''
155*e5dd7070Spatrick
156*e5dd7070Spatrick        desktop_environment = 'generic'
157*e5dd7070Spatrick
158*e5dd7070Spatrick        if os.environ.get('KDE_FULL_SESSION') == 'true':
159*e5dd7070Spatrick            desktop_environment = 'kde'
160*e5dd7070Spatrick        elif os.environ.get('GNOME_DESKTOP_SESSION_ID'):
161*e5dd7070Spatrick            desktop_environment = 'gnome'
162*e5dd7070Spatrick        else:
163*e5dd7070Spatrick            try:
164*e5dd7070Spatrick                info = getoutput('xprop -root _DT_SAVE_MODE')
165*e5dd7070Spatrick                if ' = "xfce4"' in info:
166*e5dd7070Spatrick                    desktop_environment = 'xfce'
167*e5dd7070Spatrick            except (OSError, RuntimeError):
168*e5dd7070Spatrick                pass
169*e5dd7070Spatrick
170*e5dd7070Spatrick        return desktop_environment
171*e5dd7070Spatrick
172*e5dd7070Spatrick
173*e5dd7070Spatrick    def register_X_controllers():
174*e5dd7070Spatrick        if _iscommand('kfmclient'):
175*e5dd7070Spatrick            _controllers['kde-open'] = KfmClient()
176*e5dd7070Spatrick
177*e5dd7070Spatrick        for command in ('gnome-open', 'exo-open', 'xdg-open'):
178*e5dd7070Spatrick            if _iscommand(command):
179*e5dd7070Spatrick                _controllers[command] = Controller(command)
180*e5dd7070Spatrick
181*e5dd7070Spatrick    def get():
182*e5dd7070Spatrick        controllers_map = {
183*e5dd7070Spatrick            'gnome': 'gnome-open',
184*e5dd7070Spatrick            'kde': 'kde-open',
185*e5dd7070Spatrick            'xfce': 'exo-open',
186*e5dd7070Spatrick        }
187*e5dd7070Spatrick
188*e5dd7070Spatrick        desktop_environment = detect_desktop_environment()
189*e5dd7070Spatrick
190*e5dd7070Spatrick        try:
191*e5dd7070Spatrick            controller_name = controllers_map[desktop_environment]
192*e5dd7070Spatrick            return _controllers[controller_name].open
193*e5dd7070Spatrick
194*e5dd7070Spatrick        except KeyError:
195*e5dd7070Spatrick            if 'xdg-open' in _controllers:
196*e5dd7070Spatrick                return _controllers['xdg-open'].open
197*e5dd7070Spatrick            else:
198*e5dd7070Spatrick                return webbrowser.open
199*e5dd7070Spatrick
200*e5dd7070Spatrick
201*e5dd7070Spatrick    if os.environ.get("DISPLAY"):
202*e5dd7070Spatrick        register_X_controllers()
203*e5dd7070Spatrick    _open = get()
204*e5dd7070Spatrick
205*e5dd7070Spatrick
206*e5dd7070Spatrickdef open(filename):
207*e5dd7070Spatrick    '''Open a file or a URL in the registered default application.'''
208*e5dd7070Spatrick
209*e5dd7070Spatrick    return _open(filename)
210