Proton files embedded
This commit is contained in:
parent
fa625f7bd6
commit
bd65a5efa1
221
data_from_portwine/LICENSE
Normal file
221
data_from_portwine/LICENSE
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
Copyright (c) 2018-2020, Valve Corporation
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation and/or
|
||||||
|
other materials provided with the distribution.
|
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
may be used to endorse or promote products derived from this software without
|
||||||
|
specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
|
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
Browse the source code for more information
|
||||||
|
|
||||||
|
https://github.com/ValveSoftware/Proton
|
||||||
|
|
||||||
|
---- ---- ---- ----
|
||||||
|
|
||||||
|
This software contains a modified version of Wine licensed under the LGPL 2.1. Wine is
|
||||||
|
|
||||||
|
Copyright (c) 1993-2020 the Wine project authors
|
||||||
|
|
||||||
|
Visit Wine at
|
||||||
|
|
||||||
|
https://winehq.org
|
||||||
|
|
||||||
|
View our modifications at
|
||||||
|
|
||||||
|
https://github.com/ValveSoftware/wine
|
||||||
|
|
||||||
|
---- ---- ---- ----
|
||||||
|
|
||||||
|
This software contains a modified version of DXVK licensed under the zlib/libpng license. DXVK is
|
||||||
|
|
||||||
|
Copyright (c) 2017-2020 Philip Rebohle
|
||||||
|
Copyright (c) 2019-2020 Joshua Ashton
|
||||||
|
|
||||||
|
Visit DXVK at
|
||||||
|
|
||||||
|
https://github.com/doitsujin/dxvk
|
||||||
|
|
||||||
|
View our modifications at
|
||||||
|
|
||||||
|
https://github.com/ValveSoftware/dxvk
|
||||||
|
|
||||||
|
---- ---- ---- ----
|
||||||
|
|
||||||
|
This software contains FAudio licensed under the zlib license. FAudio is
|
||||||
|
|
||||||
|
Copyright (c) 2011-2020 Ethan Lee, Luigi Auriemma, and the MonoGame Team
|
||||||
|
|
||||||
|
Visit FAudio at
|
||||||
|
|
||||||
|
https://github.com/FNA-XNA/FAudio
|
||||||
|
|
||||||
|
---- ---- ---- ----
|
||||||
|
|
||||||
|
This software contains some Liberation Fonts licensed under the SIL Open Font License, available at LICENSE.OFL. These fonts are
|
||||||
|
|
||||||
|
Copyright (c) 2010 Google Corporation
|
||||||
|
Copyright (c) 2012 Red Hat, Inc.
|
||||||
|
|
||||||
|
Visit Liberation Fonts at
|
||||||
|
|
||||||
|
https://github.com/liberationfonts/liberation-fonts
|
||||||
|
|
||||||
|
---- ---- ---- ----
|
||||||
|
|
||||||
|
This software contains Source Han Sans licensed under the SIL Open Font License, available at LICENSE.OFL. This font is
|
||||||
|
|
||||||
|
Copyright 2014-2019 Adobe (http://www.adobe.com/)
|
||||||
|
|
||||||
|
Visit Source Han Sans at
|
||||||
|
|
||||||
|
https://github.com/adobe-fonts/source-han-sans
|
||||||
|
|
||||||
|
---- ---- ---- ----
|
||||||
|
|
||||||
|
This software contains wine-mono, parts of which are included under a variety of licenses.
|
||||||
|
|
||||||
|
Parts of Mono (mono/) are variously licensed under the GPL, LGPL, and MIT X11 licenses. All parts are available as LGPL or MIT X11 except for the following:
|
||||||
|
* The ICSharpCode.SharpZipLib library is available as GPL with an exception (see mono/mcs/class/ICSharpCode.SharpZipLib/README).
|
||||||
|
* mcs/jay is BSD-licensed.
|
||||||
|
|
||||||
|
The Visual Basic class libraries (mono-basic/) are MIT X11. The compiler is LGPL v2.
|
||||||
|
|
||||||
|
FNA is a mix of MSPL and MIT. It has the following library dependencies:
|
||||||
|
* FAudio, MojoShader, Theorafile, SDL2, SDL_image_compact, and SDL2-CS are zlib-licensed. SDL2-CS is built into FNA.dll.
|
||||||
|
* FNA.NetStub is MSPL.
|
||||||
|
|
||||||
|
The winforms and wpf libraries are MIT.
|
||||||
|
|
||||||
|
wine-mono itself is included under the MIT license. wine-mono is
|
||||||
|
|
||||||
|
Copyright (c) 2012 Vincent Povirk for CodeWeavers
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
|
||||||
|
Visit wine-mono at
|
||||||
|
|
||||||
|
https://github.com/madewokherd/wine-mono
|
||||||
|
|
||||||
|
View wine-mono's complete license at
|
||||||
|
|
||||||
|
https://github.com/madewokherd/wine-mono/blob/master/COPYING
|
||||||
|
|
||||||
|
---- ---- ---- ----
|
||||||
|
|
||||||
|
This software contains wine-gecko, parts of which are included under a variety of licenses.
|
||||||
|
|
||||||
|
wine-gecko itself is included under the Mozilla Public License 2.0.
|
||||||
|
|
||||||
|
wine-gecko is available in Source Code form at
|
||||||
|
|
||||||
|
https://sourceforge.net/p/wine/wine-gecko
|
||||||
|
|
||||||
|
---- ---- ---- ----
|
||||||
|
|
||||||
|
This software contains a modified version of Vkd3d licensed under the LGPL 2.1. Vkd3d is
|
||||||
|
|
||||||
|
Copyright 2016-2019 the Vkd3d project authors
|
||||||
|
|
||||||
|
Visit Vkd3d at
|
||||||
|
|
||||||
|
https://source.winehq.org/git/vkd3d.git
|
||||||
|
|
||||||
|
View our modifications at
|
||||||
|
|
||||||
|
https://github.com/ValveSoftware/vkd3d
|
||||||
|
|
||||||
|
---- ---- ---- ----
|
||||||
|
|
||||||
|
Parts of this software are based on the OpenVR SDK, which is
|
||||||
|
|
||||||
|
Copyright (c) 2015, Valve Corporation
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation and/or
|
||||||
|
other materials provided with the distribution.
|
||||||
|
|
||||||
|
3. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
may be used to endorse or promote products derived from this software without
|
||||||
|
specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
|
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
Visit OpenVR at
|
||||||
|
|
||||||
|
https://github.com/ValveSoftware/openvr
|
||||||
|
|
||||||
|
---- ---- ---- ----
|
||||||
|
|
||||||
|
Parts of this software are based on the AMD AGS library, which is
|
||||||
|
|
||||||
|
Copyright (c) 2017 Advanced Micro Devices, Inc. All rights reserved.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
451
data_from_portwine/filelock.py
Normal file
451
data_from_portwine/filelock.py
Normal file
@ -0,0 +1,451 @@
|
|||||||
|
# This is free and unencumbered software released into the public domain.
|
||||||
|
#
|
||||||
|
# Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||||
|
# distribute this software, either in source code form or as a compiled
|
||||||
|
# binary, for any purpose, commercial or non-commercial, and by any
|
||||||
|
# means.
|
||||||
|
#
|
||||||
|
# In jurisdictions that recognize copyright laws, the author or authors
|
||||||
|
# of this software dedicate any and all copyright interest in the
|
||||||
|
# software to the public domain. We make this dedication for the benefit
|
||||||
|
# of the public at large and to the detriment of our heirs and
|
||||||
|
# successors. We intend this dedication to be an overt act of
|
||||||
|
# relinquishment in perpetuity of all present and future rights to this
|
||||||
|
# software under copyright law.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||||
|
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||||
|
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
# OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
#
|
||||||
|
# For more information, please refer to <http://unlicense.org>
|
||||||
|
|
||||||
|
"""
|
||||||
|
A platform independent file lock that supports the with-statement.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
# Modules
|
||||||
|
# ------------------------------------------------
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
try:
|
||||||
|
import warnings
|
||||||
|
except ImportError:
|
||||||
|
warnings = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
import msvcrt
|
||||||
|
except ImportError:
|
||||||
|
msvcrt = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
import fcntl
|
||||||
|
except ImportError:
|
||||||
|
fcntl = None
|
||||||
|
|
||||||
|
|
||||||
|
# Backward compatibility
|
||||||
|
# ------------------------------------------------
|
||||||
|
try:
|
||||||
|
TimeoutError
|
||||||
|
except NameError:
|
||||||
|
TimeoutError = OSError
|
||||||
|
|
||||||
|
|
||||||
|
# Data
|
||||||
|
# ------------------------------------------------
|
||||||
|
__all__ = [
|
||||||
|
"Timeout",
|
||||||
|
"BaseFileLock",
|
||||||
|
"WindowsFileLock",
|
||||||
|
"UnixFileLock",
|
||||||
|
"SoftFileLock",
|
||||||
|
"FileLock"
|
||||||
|
]
|
||||||
|
|
||||||
|
__version__ = "3.0.12"
|
||||||
|
|
||||||
|
|
||||||
|
_logger = None
|
||||||
|
def logger():
|
||||||
|
"""Returns the logger instance used in this module."""
|
||||||
|
global _logger
|
||||||
|
_logger = _logger or logging.getLogger(__name__)
|
||||||
|
return _logger
|
||||||
|
|
||||||
|
|
||||||
|
# Exceptions
|
||||||
|
# ------------------------------------------------
|
||||||
|
class Timeout(TimeoutError):
|
||||||
|
"""
|
||||||
|
Raised when the lock could not be acquired in *timeout*
|
||||||
|
seconds.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, lock_file):
|
||||||
|
"""
|
||||||
|
"""
|
||||||
|
#: The path of the file lock.
|
||||||
|
self.lock_file = lock_file
|
||||||
|
return None
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
temp = "The file lock '{}' could not be acquired."\
|
||||||
|
.format(self.lock_file)
|
||||||
|
return temp
|
||||||
|
|
||||||
|
|
||||||
|
# Classes
|
||||||
|
# ------------------------------------------------
|
||||||
|
|
||||||
|
# This is a helper class which is returned by :meth:`BaseFileLock.acquire`
|
||||||
|
# and wraps the lock to make sure __enter__ is not called twice when entering
|
||||||
|
# the with statement.
|
||||||
|
# If we would simply return *self*, the lock would be acquired again
|
||||||
|
# in the *__enter__* method of the BaseFileLock, but not released again
|
||||||
|
# automatically.
|
||||||
|
#
|
||||||
|
# :seealso: issue #37 (memory leak)
|
||||||
|
class _Acquire_ReturnProxy(object):
|
||||||
|
|
||||||
|
def __init__(self, lock):
|
||||||
|
self.lock = lock
|
||||||
|
return None
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
return self.lock
|
||||||
|
|
||||||
|
def __exit__(self, exc_type, exc_value, traceback):
|
||||||
|
self.lock.release()
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class BaseFileLock(object):
|
||||||
|
"""
|
||||||
|
Implements the base class of a file lock.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, lock_file, timeout = -1):
|
||||||
|
"""
|
||||||
|
"""
|
||||||
|
# The path to the lock file.
|
||||||
|
self._lock_file = lock_file
|
||||||
|
|
||||||
|
# The file descriptor for the *_lock_file* as it is returned by the
|
||||||
|
# os.open() function.
|
||||||
|
# This file lock is only NOT None, if the object currently holds the
|
||||||
|
# lock.
|
||||||
|
self._lock_file_fd = None
|
||||||
|
|
||||||
|
# The default timeout value.
|
||||||
|
self.timeout = timeout
|
||||||
|
|
||||||
|
# We use this lock primarily for the lock counter.
|
||||||
|
self._thread_lock = threading.Lock()
|
||||||
|
|
||||||
|
# The lock counter is used for implementing the nested locking
|
||||||
|
# mechanism. Whenever the lock is acquired, the counter is increased and
|
||||||
|
# the lock is only released, when this value is 0 again.
|
||||||
|
self._lock_counter = 0
|
||||||
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def lock_file(self):
|
||||||
|
"""
|
||||||
|
The path to the lock file.
|
||||||
|
"""
|
||||||
|
return self._lock_file
|
||||||
|
|
||||||
|
@property
|
||||||
|
def timeout(self):
|
||||||
|
"""
|
||||||
|
You can set a default timeout for the filelock. It will be used as
|
||||||
|
fallback value in the acquire method, if no timeout value (*None*) is
|
||||||
|
given.
|
||||||
|
|
||||||
|
If you want to disable the timeout, set it to a negative value.
|
||||||
|
|
||||||
|
A timeout of 0 means, that there is exactly one attempt to acquire the
|
||||||
|
file lock.
|
||||||
|
|
||||||
|
.. versionadded:: 2.0.0
|
||||||
|
"""
|
||||||
|
return self._timeout
|
||||||
|
|
||||||
|
@timeout.setter
|
||||||
|
def timeout(self, value):
|
||||||
|
"""
|
||||||
|
"""
|
||||||
|
self._timeout = float(value)
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Platform dependent locking
|
||||||
|
# --------------------------------------------
|
||||||
|
|
||||||
|
def _acquire(self):
|
||||||
|
"""
|
||||||
|
Platform dependent. If the file lock could be
|
||||||
|
acquired, self._lock_file_fd holds the file descriptor
|
||||||
|
of the lock file.
|
||||||
|
"""
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def _release(self):
|
||||||
|
"""
|
||||||
|
Releases the lock and sets self._lock_file_fd to None.
|
||||||
|
"""
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
# Platform independent methods
|
||||||
|
# --------------------------------------------
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_locked(self):
|
||||||
|
"""
|
||||||
|
True, if the object holds the file lock.
|
||||||
|
|
||||||
|
.. versionchanged:: 2.0.0
|
||||||
|
|
||||||
|
This was previously a method and is now a property.
|
||||||
|
"""
|
||||||
|
return self._lock_file_fd is not None
|
||||||
|
|
||||||
|
def acquire(self, timeout=None, poll_intervall=0.05):
|
||||||
|
"""
|
||||||
|
Acquires the file lock or fails with a :exc:`Timeout` error.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
# You can use this method in the context manager (recommended)
|
||||||
|
with lock.acquire():
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Or use an equivalent try-finally construct:
|
||||||
|
lock.acquire()
|
||||||
|
try:
|
||||||
|
pass
|
||||||
|
finally:
|
||||||
|
lock.release()
|
||||||
|
|
||||||
|
:arg float timeout:
|
||||||
|
The maximum time waited for the file lock.
|
||||||
|
If ``timeout < 0``, there is no timeout and this method will
|
||||||
|
block until the lock could be acquired.
|
||||||
|
If ``timeout`` is None, the default :attr:`~timeout` is used.
|
||||||
|
|
||||||
|
:arg float poll_intervall:
|
||||||
|
We check once in *poll_intervall* seconds if we can acquire the
|
||||||
|
file lock.
|
||||||
|
|
||||||
|
:raises Timeout:
|
||||||
|
if the lock could not be acquired in *timeout* seconds.
|
||||||
|
|
||||||
|
.. versionchanged:: 2.0.0
|
||||||
|
|
||||||
|
This method returns now a *proxy* object instead of *self*,
|
||||||
|
so that it can be used in a with statement without side effects.
|
||||||
|
"""
|
||||||
|
# Use the default timeout, if no timeout is provided.
|
||||||
|
if timeout is None:
|
||||||
|
timeout = self.timeout
|
||||||
|
|
||||||
|
# Increment the number right at the beginning.
|
||||||
|
# We can still undo it, if something fails.
|
||||||
|
with self._thread_lock:
|
||||||
|
self._lock_counter += 1
|
||||||
|
|
||||||
|
lock_id = id(self)
|
||||||
|
lock_filename = self._lock_file
|
||||||
|
start_time = time.time()
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
with self._thread_lock:
|
||||||
|
if not self.is_locked:
|
||||||
|
logger().debug('Attempting to acquire lock %s on %s', lock_id, lock_filename)
|
||||||
|
self._acquire()
|
||||||
|
|
||||||
|
if self.is_locked:
|
||||||
|
logger().info('Lock %s acquired on %s', lock_id, lock_filename)
|
||||||
|
break
|
||||||
|
elif timeout >= 0 and time.time() - start_time > timeout:
|
||||||
|
logger().debug('Timeout on acquiring lock %s on %s', lock_id, lock_filename)
|
||||||
|
raise Timeout(self._lock_file)
|
||||||
|
else:
|
||||||
|
logger().debug(
|
||||||
|
'Lock %s not acquired on %s, waiting %s seconds ...',
|
||||||
|
lock_id, lock_filename, poll_intervall
|
||||||
|
)
|
||||||
|
time.sleep(poll_intervall)
|
||||||
|
except:
|
||||||
|
# Something did go wrong, so decrement the counter.
|
||||||
|
with self._thread_lock:
|
||||||
|
self._lock_counter = max(0, self._lock_counter - 1)
|
||||||
|
|
||||||
|
raise
|
||||||
|
return _Acquire_ReturnProxy(lock = self)
|
||||||
|
|
||||||
|
def release(self, force = False):
|
||||||
|
"""
|
||||||
|
Releases the file lock.
|
||||||
|
|
||||||
|
Please note, that the lock is only completly released, if the lock
|
||||||
|
counter is 0.
|
||||||
|
|
||||||
|
Also note, that the lock file itself is not automatically deleted.
|
||||||
|
|
||||||
|
:arg bool force:
|
||||||
|
If true, the lock counter is ignored and the lock is released in
|
||||||
|
every case.
|
||||||
|
"""
|
||||||
|
with self._thread_lock:
|
||||||
|
|
||||||
|
if self.is_locked:
|
||||||
|
self._lock_counter -= 1
|
||||||
|
|
||||||
|
if self._lock_counter == 0 or force:
|
||||||
|
lock_id = id(self)
|
||||||
|
lock_filename = self._lock_file
|
||||||
|
|
||||||
|
logger().debug('Attempting to release lock %s on %s', lock_id, lock_filename)
|
||||||
|
self._release()
|
||||||
|
self._lock_counter = 0
|
||||||
|
logger().info('Lock %s released on %s', lock_id, lock_filename)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
self.acquire()
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __exit__(self, exc_type, exc_value, traceback):
|
||||||
|
self.release()
|
||||||
|
return None
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
self.release(force = True)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
# Windows locking mechanism
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
class WindowsFileLock(BaseFileLock):
|
||||||
|
"""
|
||||||
|
Uses the :func:`msvcrt.locking` function to hard lock the lock file on
|
||||||
|
windows systems.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def _acquire(self):
|
||||||
|
open_mode = os.O_RDWR | os.O_CREAT | os.O_TRUNC
|
||||||
|
|
||||||
|
try:
|
||||||
|
fd = os.open(self._lock_file, open_mode)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
msvcrt.locking(fd, msvcrt.LK_NBLCK, 1)
|
||||||
|
except (IOError, OSError):
|
||||||
|
os.close(fd)
|
||||||
|
else:
|
||||||
|
self._lock_file_fd = fd
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _release(self):
|
||||||
|
fd = self._lock_file_fd
|
||||||
|
self._lock_file_fd = None
|
||||||
|
msvcrt.locking(fd, msvcrt.LK_UNLCK, 1)
|
||||||
|
os.close(fd)
|
||||||
|
|
||||||
|
try:
|
||||||
|
os.remove(self._lock_file)
|
||||||
|
# Probably another instance of the application
|
||||||
|
# that acquired the file lock.
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Unix locking mechanism
|
||||||
|
# ~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
class UnixFileLock(BaseFileLock):
|
||||||
|
"""
|
||||||
|
Uses the :func:`fcntl.flock` to hard lock the lock file on unix systems.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def _acquire(self):
|
||||||
|
open_mode = os.O_RDWR | os.O_CREAT | os.O_TRUNC
|
||||||
|
fd = os.open(self._lock_file, open_mode)
|
||||||
|
|
||||||
|
try:
|
||||||
|
fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
||||||
|
except (IOError, OSError):
|
||||||
|
os.close(fd)
|
||||||
|
else:
|
||||||
|
self._lock_file_fd = fd
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _release(self):
|
||||||
|
# Do not remove the lockfile:
|
||||||
|
#
|
||||||
|
# https://github.com/benediktschmitt/py-filelock/issues/31
|
||||||
|
# https://stackoverflow.com/questions/17708885/flock-removing-locked-file-without-race-condition
|
||||||
|
fd = self._lock_file_fd
|
||||||
|
self._lock_file_fd = None
|
||||||
|
fcntl.flock(fd, fcntl.LOCK_UN)
|
||||||
|
os.close(fd)
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Soft lock
|
||||||
|
# ~~~~~~~~~
|
||||||
|
|
||||||
|
class SoftFileLock(BaseFileLock):
|
||||||
|
"""
|
||||||
|
Simply watches the existence of the lock file.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def _acquire(self):
|
||||||
|
open_mode = os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_TRUNC
|
||||||
|
try:
|
||||||
|
fd = os.open(self._lock_file, open_mode)
|
||||||
|
except (IOError, OSError):
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
self._lock_file_fd = fd
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _release(self):
|
||||||
|
os.close(self._lock_file_fd)
|
||||||
|
self._lock_file_fd = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
os.remove(self._lock_file)
|
||||||
|
# The file is already deleted and that's what we want.
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
# Platform filelock
|
||||||
|
# ~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
#: Alias for the lock, which should be used for the current platform. On
|
||||||
|
#: Windows, this is an alias for :class:`WindowsFileLock`, on Unix for
|
||||||
|
#: :class:`UnixFileLock` and otherwise for :class:`SoftFileLock`.
|
||||||
|
FileLock = None
|
||||||
|
|
||||||
|
if msvcrt:
|
||||||
|
FileLock = WindowsFileLock
|
||||||
|
elif fcntl:
|
||||||
|
FileLock = UnixFileLock
|
||||||
|
else:
|
||||||
|
FileLock = SoftFileLock
|
||||||
|
|
||||||
|
if warnings is not None:
|
||||||
|
warnings.warn("only soft file lock is available")
|
708
data_from_portwine/proton
Executable file
708
data_from_portwine/proton
Executable file
@ -0,0 +1,708 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
#script to launch Wine with the correct environment
|
||||||
|
|
||||||
|
import fcntl
|
||||||
|
import array
|
||||||
|
import filecmp
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import errno
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import tarfile
|
||||||
|
|
||||||
|
from filelock import FileLock
|
||||||
|
|
||||||
|
#To enable debug logging, copy "user_settings.sample.py" to "user_settings.py"
|
||||||
|
#and edit it if needed.
|
||||||
|
|
||||||
|
CURRENT_PREFIX_VERSION="5.6-GE-2"
|
||||||
|
|
||||||
|
PFX="Proton: "
|
||||||
|
ld_path_var = "LD_LIBRARY_PATH"
|
||||||
|
|
||||||
|
def nonzero(s):
|
||||||
|
return len(s) > 0 and s != "0"
|
||||||
|
|
||||||
|
def log(msg):
|
||||||
|
sys.stderr.write(PFX + msg + os.linesep)
|
||||||
|
sys.stderr.flush()
|
||||||
|
|
||||||
|
def file_is_wine_fake_dll(path):
|
||||||
|
if not os.path.exists(path):
|
||||||
|
return False
|
||||||
|
try:
|
||||||
|
sfile = open(path, "rb")
|
||||||
|
sfile.seek(0x40)
|
||||||
|
tag = sfile.read(20)
|
||||||
|
return tag == b"Wine placeholder DLL"
|
||||||
|
except IOError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def makedirs(path):
|
||||||
|
try:
|
||||||
|
os.makedirs(path)
|
||||||
|
except OSError:
|
||||||
|
#already exists
|
||||||
|
pass
|
||||||
|
|
||||||
|
def try_copy(src, dst):
|
||||||
|
try:
|
||||||
|
if os.path.isdir(dst):
|
||||||
|
dstfile = dst + "/" + os.path.basename(src)
|
||||||
|
if os.path.lexists(dstfile):
|
||||||
|
os.remove(dstfile)
|
||||||
|
elif os.path.lexists(dst):
|
||||||
|
os.remove(dst)
|
||||||
|
shutil.copy(src, dst)
|
||||||
|
except PermissionError as e:
|
||||||
|
if e.errno == errno.EPERM:
|
||||||
|
#be forgiving about permissions errors; if it's a real problem, things will explode later anyway
|
||||||
|
log('Error while copying to \"' + dst + '\": ' + e.strerror)
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
|
||||||
|
def real_copy(src, dst):
|
||||||
|
if os.path.islink(src):
|
||||||
|
os.symlink(os.readlink(src), dst)
|
||||||
|
else:
|
||||||
|
try_copy(src, dst)
|
||||||
|
|
||||||
|
EXT2_IOC_GETFLAGS = 0x80086601
|
||||||
|
EXT2_IOC_SETFLAGS = 0x40086602
|
||||||
|
|
||||||
|
EXT4_CASEFOLD_FL = 0x40000000
|
||||||
|
|
||||||
|
def set_dir_casefold_bit(dir_path):
|
||||||
|
dr = os.open(dir_path, 0o644)
|
||||||
|
if dr < 0:
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
dat = array.array('I', [0])
|
||||||
|
if fcntl.ioctl(dr, EXT2_IOC_GETFLAGS, dat, True) >= 0:
|
||||||
|
dat[0] = dat[0] | EXT4_CASEFOLD_FL
|
||||||
|
fcntl.ioctl(dr, EXT2_IOC_SETFLAGS, dat, False)
|
||||||
|
except OSError:
|
||||||
|
#no problem
|
||||||
|
pass
|
||||||
|
os.close(dr)
|
||||||
|
|
||||||
|
class Proton:
|
||||||
|
def __init__(self, base_dir):
|
||||||
|
self.base_dir = os.environ["STEAM_COMPAT_DATA_PATH"]
|
||||||
|
self.dist_dir = self.path("dist/")
|
||||||
|
self.bin_dir = self.path("dist/bin/")
|
||||||
|
self.lib_dir = self.path("dist/lib/")
|
||||||
|
self.lib64_dir = self.path("dist/lib64/")
|
||||||
|
self.fonts_dir = self.path("dist/share/fonts/")
|
||||||
|
self.version_file = self.path("version")
|
||||||
|
self.default_pfx_dir = self.path("dist/share/default_pfx/")
|
||||||
|
self.user_settings_file = self.path("user_settings.py")
|
||||||
|
self.wine_bin = self.bin_dir + "wine"
|
||||||
|
self.wineserver_bin = self.bin_dir + "wineserver"
|
||||||
|
self.dist_lock = FileLock(self.path("dist.lock"), timeout=-1)
|
||||||
|
|
||||||
|
def path(self, d):
|
||||||
|
return self.base_dir + d
|
||||||
|
|
||||||
|
def extract_tarball(self):
|
||||||
|
with self.dist_lock:
|
||||||
|
if not os.path.exists(self.dist_dir) or \
|
||||||
|
not os.path.exists(self.path("dist/version")) or \
|
||||||
|
not filecmp.cmp(self.version_file, self.path("dist/version")):
|
||||||
|
if os.path.exists(self.dist_dir):
|
||||||
|
shutil.rmtree(self.dist_dir)
|
||||||
|
tar = None
|
||||||
|
for sf in ["", ".xz", ".bz2", ".gz"]:
|
||||||
|
if os.path.exists(self.path("proton_dist.tar" + sf)):
|
||||||
|
tar = tarfile.open(self.path("proton_dist.tar" + sf), mode="r:*")
|
||||||
|
break
|
||||||
|
if not tar:
|
||||||
|
log("No proton_dist tarball??")
|
||||||
|
sys.exit(1)
|
||||||
|
tar.extractall(path=self.dist_dir)
|
||||||
|
tar.close()
|
||||||
|
try_copy(self.version_file, self.dist_dir)
|
||||||
|
|
||||||
|
def make_default_prefix(self):
|
||||||
|
with self.dist_lock:
|
||||||
|
local_env = dict(g_session.env)
|
||||||
|
if not os.path.isdir(self.default_pfx_dir):
|
||||||
|
#make default prefix
|
||||||
|
local_env["WINEPREFIX"] = self.default_pfx_dir
|
||||||
|
local_env["WINEDEBUG"] = "-all"
|
||||||
|
g_session.run_proc([self.wine_bin, "wineboot"], local_env)
|
||||||
|
g_session.run_proc([self.wineserver_bin, "-w"], local_env)
|
||||||
|
|
||||||
|
class CompatData:
|
||||||
|
def __init__(self, compatdata):
|
||||||
|
self.base_dir = os.environ["STEAM_COMPAT_DATA_PATH"]
|
||||||
|
self.prefix_dir = self.path("pfx/")
|
||||||
|
self.version_file = self.path("version")
|
||||||
|
self.tracked_files_file = self.path("tracked_files")
|
||||||
|
self.prefix_lock = FileLock(self.path("pfx.lock"), timeout=-1)
|
||||||
|
|
||||||
|
def path(self, d):
|
||||||
|
return self.base_dir + d
|
||||||
|
|
||||||
|
def remove_tracked_files(self):
|
||||||
|
if not os.path.exists(self.tracked_files_file):
|
||||||
|
log("Prefix has no tracked_files??")
|
||||||
|
return
|
||||||
|
|
||||||
|
with open(self.tracked_files_file, "r") as tracked_files:
|
||||||
|
dirs = []
|
||||||
|
for f in tracked_files:
|
||||||
|
path = self.prefix_dir + f.strip()
|
||||||
|
if os.path.exists(path):
|
||||||
|
if os.path.isfile(path) or os.path.islink(path):
|
||||||
|
os.remove(path)
|
||||||
|
else:
|
||||||
|
dirs.append(path)
|
||||||
|
for d in dirs:
|
||||||
|
try:
|
||||||
|
os.rmdir(d)
|
||||||
|
except OSError:
|
||||||
|
#not empty
|
||||||
|
pass
|
||||||
|
|
||||||
|
os.remove(self.tracked_files_file)
|
||||||
|
os.remove(self.version_file)
|
||||||
|
|
||||||
|
def upgrade_pfx(self, old_ver):
|
||||||
|
if old_ver == CURRENT_PREFIX_VERSION:
|
||||||
|
return
|
||||||
|
|
||||||
|
log("Upgrading prefix from " + str(old_ver) + " to " + CURRENT_PREFIX_VERSION + " (" + self.base_dir + ")")
|
||||||
|
|
||||||
|
if old_ver is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
if not '-' in old_ver:
|
||||||
|
#How can this happen??
|
||||||
|
log("Prefix has an invalid version?! You may want to back up user files and delete this prefix.")
|
||||||
|
#If it does, just let the Wine upgrade happen and hope it works...
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
old_proton_ver, old_prefix_ver = old_ver.split('-')
|
||||||
|
old_proton_maj, old_proton_min = old_proton_ver.split('.')
|
||||||
|
new_proton_ver, new_prefix_ver = CURRENT_PREFIX_VERSION.split('-')
|
||||||
|
new_proton_maj, new_proton_min = new_proton_ver.split('.')
|
||||||
|
|
||||||
|
if int(new_proton_maj) < int(old_proton_maj) or \
|
||||||
|
(int(new_proton_maj) == int(old_proton_maj) and \
|
||||||
|
int(new_proton_min) < int(old_proton_min)):
|
||||||
|
log("Removing newer prefix")
|
||||||
|
if old_proton_ver == "3.7" and not os.path.exists(self.tracked_files_file):
|
||||||
|
#proton 3.7 did not generate tracked_files, so copy it into place first
|
||||||
|
try_copy(g_proton.path("proton_3.7_tracked_files"), self.tracked_files_file)
|
||||||
|
self.remove_tracked_files()
|
||||||
|
return
|
||||||
|
|
||||||
|
if old_proton_ver == "3.7" and old_prefix_ver == "1":
|
||||||
|
if not os.path.exists(self.prefix_dir + "/drive_c/windows/syswow64/kernel32.dll"):
|
||||||
|
#shipped a busted 64-bit-only installation on 20180822. detect and wipe clean
|
||||||
|
log("Detected broken 64-bit-only installation, re-creating prefix.")
|
||||||
|
shutil.rmtree(self.prefix_dir)
|
||||||
|
return
|
||||||
|
|
||||||
|
#replace broken .NET installations with wine-mono support
|
||||||
|
if os.path.exists(self.prefix_dir + "/drive_c/windows/Microsoft.NET/NETFXRepair.exe") and \
|
||||||
|
file_is_wine_fake_dll(self.prefix_dir + "/drive_c/windows/system32/mscoree.dll"):
|
||||||
|
log("Broken .NET installation detected, switching to wine-mono.")
|
||||||
|
#deleting this directory allows wine-mono to work
|
||||||
|
shutil.rmtree(self.prefix_dir + "/drive_c/windows/Microsoft.NET")
|
||||||
|
|
||||||
|
#prior to prefix version 4.11-2, all controllers were xbox controllers. wipe out the old registry entries.
|
||||||
|
if (int(old_proton_maj) < 4 or (int(old_proton_maj) == 4 and int(old_proton_min) == 11)) and \
|
||||||
|
int(old_prefix_ver) < 2:
|
||||||
|
log("Removing old xinput registry entries.")
|
||||||
|
with open(self.prefix_dir + "system.reg", "r") as reg_in:
|
||||||
|
with open(self.prefix_dir + "system.reg.new", "w") as reg_out:
|
||||||
|
for line in reg_in:
|
||||||
|
if line[0] == '[' and "CurrentControlSet" in line and "IG_" in line:
|
||||||
|
if "DeviceClasses" in line:
|
||||||
|
reg_out.write(line.replace("DeviceClasses", "DeviceClasses_old"))
|
||||||
|
elif "Enum" in line:
|
||||||
|
reg_out.write(line.replace("Enum", "Enum_old"))
|
||||||
|
else:
|
||||||
|
reg_out.write(line)
|
||||||
|
try:
|
||||||
|
os.rename(self.prefix_dir + "system.reg", self.prefix_dir + "system.reg.old")
|
||||||
|
except OSError:
|
||||||
|
os.remove(self.prefix_dir + "system.reg")
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
os.rename(self.prefix_dir + "system.reg.new", self.prefix_dir + "system.reg")
|
||||||
|
except OSError:
|
||||||
|
log("Unable to write new registry file to " + self.prefix_dir + "system.reg")
|
||||||
|
pass
|
||||||
|
|
||||||
|
except ValueError:
|
||||||
|
log("Prefix has an invalid version?! You may want to back up user files and delete this prefix.")
|
||||||
|
#Just let the Wine upgrade happen and hope it works...
|
||||||
|
return
|
||||||
|
|
||||||
|
def copy_pfx(self):
|
||||||
|
with open(self.tracked_files_file, "w") as tracked_files:
|
||||||
|
for src_dir, dirs, files in os.walk(g_proton.default_pfx_dir):
|
||||||
|
rel_dir = src_dir.replace(g_proton.default_pfx_dir, "", 1).lstrip('/')
|
||||||
|
if len(rel_dir) > 0:
|
||||||
|
rel_dir = rel_dir + "/"
|
||||||
|
dst_dir = src_dir.replace(g_proton.default_pfx_dir, self.prefix_dir, 1)
|
||||||
|
if not os.path.exists(dst_dir):
|
||||||
|
os.makedirs(dst_dir)
|
||||||
|
tracked_files.write(rel_dir + "\n")
|
||||||
|
for dir_ in dirs:
|
||||||
|
src_file = os.path.join(src_dir, dir_)
|
||||||
|
dst_file = os.path.join(dst_dir, dir_)
|
||||||
|
if os.path.islink(src_file) and not os.path.exists(dst_file):
|
||||||
|
real_copy(src_file, dst_file)
|
||||||
|
for file_ in files:
|
||||||
|
src_file = os.path.join(src_dir, file_)
|
||||||
|
dst_file = os.path.join(dst_dir, file_)
|
||||||
|
if not os.path.exists(dst_file):
|
||||||
|
real_copy(src_file, dst_file)
|
||||||
|
tracked_files.write(rel_dir + file_ + "\n")
|
||||||
|
|
||||||
|
def create_fonts_symlinks(self):
|
||||||
|
fontsmap = [
|
||||||
|
( "LiberationSans-Regular.ttf", "arial.ttf" ),
|
||||||
|
( "LiberationSans-Bold.ttf", "arialbd.ttf" ),
|
||||||
|
( "LiberationSerif-Regular.ttf", "times.ttf" ),
|
||||||
|
( "LiberationMono-Regular.ttf", "cour.ttf" ),
|
||||||
|
( "SourceHanSansSCRegular.otf", "msyh.ttf" ),
|
||||||
|
]
|
||||||
|
|
||||||
|
windowsfonts = self.prefix_dir + "/drive_c/windows/Fonts"
|
||||||
|
makedirs(windowsfonts)
|
||||||
|
for p in fontsmap:
|
||||||
|
lname = os.path.join(windowsfonts, p[1])
|
||||||
|
fname = os.path.join(g_proton.fonts_dir, p[0])
|
||||||
|
if os.path.lexists(lname):
|
||||||
|
if os.path.islink(lname):
|
||||||
|
os.remove(lname)
|
||||||
|
os.symlink(fname, lname)
|
||||||
|
else:
|
||||||
|
os.symlink(fname, lname)
|
||||||
|
|
||||||
|
def setup_prefix(self):
|
||||||
|
with self.prefix_lock:
|
||||||
|
if os.path.exists(self.version_file):
|
||||||
|
with open(self.version_file, "r") as f:
|
||||||
|
self.upgrade_pfx(f.readline().strip())
|
||||||
|
else:
|
||||||
|
self.upgrade_pfx(None)
|
||||||
|
|
||||||
|
if not os.path.exists(self.prefix_dir):
|
||||||
|
makedirs(self.prefix_dir + "/drive_c")
|
||||||
|
set_dir_casefold_bit(self.prefix_dir + "/drive_c")
|
||||||
|
|
||||||
|
if not os.path.exists(self.prefix_dir + "/user.reg"):
|
||||||
|
self.copy_pfx()
|
||||||
|
|
||||||
|
with open(self.version_file, "w") as f:
|
||||||
|
f.write(CURRENT_PREFIX_VERSION + "\n")
|
||||||
|
|
||||||
|
#create font files symlinks
|
||||||
|
self.create_fonts_symlinks()
|
||||||
|
|
||||||
|
#copy steam files into place
|
||||||
|
if "STEAM_COMPAT_CLIENT_INSTALL_PATH" in os.environ:
|
||||||
|
#modern steam client sets this
|
||||||
|
steamdir = os.environ["STEAM_COMPAT_CLIENT_INSTALL_PATH"]
|
||||||
|
else:
|
||||||
|
#linux-only fallback, really shouldn't get here
|
||||||
|
steamdir = os.environ["HOME"] + ".steam/root/"
|
||||||
|
dst = self.prefix_dir + "/drive_c/Program Files (x86)/"
|
||||||
|
makedirs(dst + "Steam")
|
||||||
|
filestocopy = ["steamclient.dll",
|
||||||
|
"steamclient64.dll",
|
||||||
|
"Steam.dll"]
|
||||||
|
for f in filestocopy:
|
||||||
|
if os.path.isfile(steamdir + "/legacycompat/" + f):
|
||||||
|
dstfile = dst + "Steam/" + f
|
||||||
|
if os.path.isfile(dstfile):
|
||||||
|
os.remove(dstfile)
|
||||||
|
try_copy(steamdir + "/legacycompat/" + f, dstfile)
|
||||||
|
|
||||||
|
#copy openvr files into place
|
||||||
|
dst = self.prefix_dir + "/drive_c/vrclient/bin/"
|
||||||
|
makedirs(dst)
|
||||||
|
try_copy(g_proton.lib_dir + "wine/fakedlls/vrclient.dll", dst)
|
||||||
|
try_copy(g_proton.lib64_dir + "wine/fakedlls/vrclient_x64.dll", dst)
|
||||||
|
|
||||||
|
try_copy(g_proton.lib_dir + "wine/dxvk/openvr_api_dxvk.dll", self.prefix_dir + "/drive_c/windows/syswow64/")
|
||||||
|
try_copy(g_proton.lib64_dir + "wine/dxvk/openvr_api_dxvk.dll", self.prefix_dir + "/drive_c/windows/system32/")
|
||||||
|
|
||||||
|
if "wined3d" in g_session.compat_config:
|
||||||
|
dxvkfiles = ["dxvk_config"]
|
||||||
|
wined3dfiles = ["d3d11", "d3d10", "d3d10core", "d3d10_1", "d3d9"]
|
||||||
|
else:
|
||||||
|
dxvkfiles = ["dxvk_config", "d3d11", "d3d10", "d3d10core", "d3d10_1", "d3d9"]
|
||||||
|
wined3dfiles = []
|
||||||
|
|
||||||
|
#if the user asked for dxvk's dxgi (dxgi=n), then copy it into place
|
||||||
|
if "WINEDLLOVERRIDES" in os.environ and "dxgi=n" in os.environ["WINEDLLOVERRIDES"]:
|
||||||
|
dxvkfiles.append("dxgi")
|
||||||
|
else:
|
||||||
|
wined3dfiles.append("dxgi")
|
||||||
|
|
||||||
|
for f in wined3dfiles:
|
||||||
|
try_copy(g_proton.default_pfx_dir + "drive_c/windows/system32/" + f + ".dll",
|
||||||
|
self.prefix_dir + "drive_c/windows/system32/" + f + ".dll")
|
||||||
|
try_copy(g_proton.default_pfx_dir + "drive_c/windows/syswow64/" + f + ".dll",
|
||||||
|
self.prefix_dir + "drive_c/windows/syswow64/" + f + ".dll")
|
||||||
|
|
||||||
|
for f in dxvkfiles:
|
||||||
|
try_copy(g_proton.lib64_dir + "wine/dxvk/" + f + ".dll",
|
||||||
|
self.prefix_dir + "drive_c/windows/system32/" + f + ".dll")
|
||||||
|
try_copy(g_proton.lib_dir + "wine/dxvk/" + f + ".dll",
|
||||||
|
self.prefix_dir + "drive_c/windows/syswow64/" + f + ".dll")
|
||||||
|
g_session.dlloverrides[f] = "n"
|
||||||
|
|
||||||
|
def comma_escaped(s):
|
||||||
|
escaped = False
|
||||||
|
idx = -1
|
||||||
|
while s[idx] == '\\':
|
||||||
|
escaped = not escaped
|
||||||
|
idx = idx - 1
|
||||||
|
return escaped
|
||||||
|
|
||||||
|
class Session:
|
||||||
|
def __init__(self):
|
||||||
|
self.log_file = None
|
||||||
|
self.env = dict(os.environ)
|
||||||
|
self.dlloverrides = {
|
||||||
|
"steam.exe": "b" #always use our special built-in steam.exe
|
||||||
|
}
|
||||||
|
|
||||||
|
self.compat_config = set()
|
||||||
|
self.cmdlineappend = []
|
||||||
|
|
||||||
|
if "STEAM_COMPAT_CONFIG" in os.environ:
|
||||||
|
config = os.environ["STEAM_COMPAT_CONFIG"]
|
||||||
|
|
||||||
|
while config:
|
||||||
|
(cur, sep, config) = config.partition(',')
|
||||||
|
if cur.startswith("cmdlineappend:"):
|
||||||
|
while comma_escaped(cur):
|
||||||
|
(a, b, c) = config.partition(',')
|
||||||
|
cur = cur[:-1] + ',' + a
|
||||||
|
config = c
|
||||||
|
self.cmdlineappend.append(cur[14:].replace('\\\\','\\'))
|
||||||
|
else:
|
||||||
|
self.compat_config.add(cur)
|
||||||
|
|
||||||
|
#turn forcelgadd on by default unless it is disabled in compat config
|
||||||
|
if not "noforcelgadd" in self.compat_config:
|
||||||
|
self.compat_config.add("forcelgadd")
|
||||||
|
|
||||||
|
def init_wine(self):
|
||||||
|
if "HOST_LC_ALL" in self.env and len(self.env["HOST_LC_ALL"]) > 0:
|
||||||
|
#steam sets LC_ALL=C to help some games, but Wine requires the real value
|
||||||
|
#in order to do path conversion between win32 and host. steam sets
|
||||||
|
#HOST_LC_ALL to allow us to use the real value.
|
||||||
|
self.env["LC_ALL"] = self.env["HOST_LC_ALL"]
|
||||||
|
else:
|
||||||
|
self.env.pop("LC_ALL", "")
|
||||||
|
|
||||||
|
self.env.pop("WINEARCH", "")
|
||||||
|
|
||||||
|
if 'ORIG_'+ld_path_var not in os.environ:
|
||||||
|
# Allow wine to restore this when calling an external app.
|
||||||
|
self.env['ORIG_'+ld_path_var] = os.environ.get(ld_path_var, '')
|
||||||
|
|
||||||
|
if ld_path_var in os.environ:
|
||||||
|
self.env[ld_path_var] = g_proton.lib64_dir + ":" + g_proton.lib_dir + ":" + os.environ[ld_path_var]
|
||||||
|
else:
|
||||||
|
self.env[ld_path_var] = g_proton.lib64_dir + ":" + g_proton.lib_dir
|
||||||
|
|
||||||
|
self.env["WINEDLLPATH"] = g_proton.lib64_dir + "/wine:" + g_proton.lib_dir + "/wine"
|
||||||
|
|
||||||
|
self.env["GST_PLUGIN_SYSTEM_PATH_1_0"] = g_proton.lib64_dir + "gstreamer-1.0" + ":" + g_proton.lib_dir + "gstreamer-1.0"
|
||||||
|
self.env["WINE_GST_REGISTRY_DIR"] = g_compatdata.path("gstreamer-1.0/")
|
||||||
|
|
||||||
|
if "PATH" in os.environ:
|
||||||
|
self.env["PATH"] = g_proton.bin_dir + ":" + os.environ["PATH"]
|
||||||
|
else:
|
||||||
|
self.env["PATH"] = g_proton.bin_dir
|
||||||
|
|
||||||
|
def check_environment(self, env_name, config_name):
|
||||||
|
if not env_name in self.env:
|
||||||
|
return False
|
||||||
|
if nonzero(self.env[env_name]):
|
||||||
|
self.compat_config.add(config_name)
|
||||||
|
else:
|
||||||
|
self.compat_config.discard(config_name)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def init_session(self):
|
||||||
|
self.env["WINEPREFIX"] = g_compatdata.prefix_dir
|
||||||
|
|
||||||
|
#load environment overrides
|
||||||
|
if os.path.exists(g_proton.user_settings_file):
|
||||||
|
try:
|
||||||
|
import user_settings
|
||||||
|
for key, value in user_settings.user_settings.items():
|
||||||
|
self.env.setdefault(key, value)
|
||||||
|
except:
|
||||||
|
log("************************************************")
|
||||||
|
log("THERE IS AN ERROR IN YOUR user_settings.py FILE:")
|
||||||
|
log("%s" % sys.exc_info()[1])
|
||||||
|
log("************************************************")
|
||||||
|
|
||||||
|
if "PROTON_LOG" in self.env and nonzero(self.env["PROTON_LOG"]):
|
||||||
|
self.env.setdefault("WINEDEBUG", "+timestamp,+pid,+tid,+seh,+debugstr,+loaddll,+mscoree")
|
||||||
|
self.env.setdefault("DXVK_LOG_LEVEL", "info")
|
||||||
|
self.env.setdefault("VKD3D_DEBUG", "warn")
|
||||||
|
self.env.setdefault("WINE_MONO_TRACE", "E:System.NotImplementedException")
|
||||||
|
|
||||||
|
#for performance, logging is disabled by default; override with user_settings.py
|
||||||
|
self.env.setdefault("WINEDEBUG", "-all")
|
||||||
|
self.env.setdefault("DXVK_LOG_LEVEL", "none")
|
||||||
|
self.env.setdefault("VKD3D_DEBUG", "none")
|
||||||
|
|
||||||
|
#default wine-mono override for FNA games
|
||||||
|
self.env.setdefault("WINE_MONO_OVERRIDES", "Microsoft.Xna.Framework.*,Gac=n")
|
||||||
|
|
||||||
|
if "wined3d11" in self.compat_config:
|
||||||
|
self.compat_config.add("wined3d")
|
||||||
|
|
||||||
|
if not self.check_environment("PROTON_USE_WINED3D", "wined3d"):
|
||||||
|
self.check_environment("PROTON_USE_WINED3D11", "wined3d")
|
||||||
|
self.check_environment("PROTON_NO_D3D11", "nod3d11")
|
||||||
|
self.check_environment("PROTON_NO_D3D10", "nod3d10")
|
||||||
|
self.check_environment("PROTON_NO_D9VK", "nod3d9")
|
||||||
|
self.check_environment("PROTON_NO_ESYNC", "noesync")
|
||||||
|
self.check_environment("PROTON_NO_FSYNC", "nofsync")
|
||||||
|
self.check_environment("PROTON_FORCE_LARGE_ADDRESS_AWARE", "forcelgadd")
|
||||||
|
self.check_environment("PROTON_OLD_GL_STRING", "oldglstr")
|
||||||
|
self.check_environment("PROTON_USE_SECCOMP", "seccomp")
|
||||||
|
|
||||||
|
if not "noesync" in self.compat_config:
|
||||||
|
self.env["WINEESYNC"] = "1" if "SteamGameId" in self.env else "0"
|
||||||
|
|
||||||
|
if not "nofsync" in self.compat_config:
|
||||||
|
self.env["WINEFSYNC"] = "1" if "SteamGameId" in self.env else "0"
|
||||||
|
|
||||||
|
if "seccomp" in self.compat_config:
|
||||||
|
self.env["WINESECCOMP"] = "1"
|
||||||
|
|
||||||
|
if "oldglstr" in self.compat_config:
|
||||||
|
#mesa override
|
||||||
|
self.env["MESA_EXTENSION_MAX_YEAR"] = "2003"
|
||||||
|
#nvidia override
|
||||||
|
self.env["__GL_ExtensionStringVersion"] = "17700"
|
||||||
|
|
||||||
|
if "forcelgadd" in self.compat_config:
|
||||||
|
self.env["WINE_LARGE_ADDRESS_AWARE"] = "1"
|
||||||
|
|
||||||
|
if "SteamGameId" in self.env:
|
||||||
|
if self.env["WINEDEBUG"] != "-all":
|
||||||
|
lfile_path = os.environ["HOME"] + "/steam-" + os.environ["SteamGameId"] + ".log"
|
||||||
|
if os.path.exists(lfile_path):
|
||||||
|
os.remove(lfile_path)
|
||||||
|
self.log_file = open(lfile_path, "w+")
|
||||||
|
self.log_file.write("======================\n")
|
||||||
|
with open(g_proton.version_file, "r") as f:
|
||||||
|
self.log_file.write("Proton: " + f.readline().strip() + "\n")
|
||||||
|
self.log_file.write("SteamGameId: " + self.env["SteamGameId"] + "\n")
|
||||||
|
self.log_file.write("Command: " + str(sys.argv[2:] + self.cmdlineappend) + "\n")
|
||||||
|
self.log_file.write("Options: " + str(self.compat_config) + "\n")
|
||||||
|
self.log_file.write("======================\n")
|
||||||
|
self.log_file.flush()
|
||||||
|
else:
|
||||||
|
self.env["WINEDEBUG"] = "-all"
|
||||||
|
|
||||||
|
g_compatdata.setup_prefix()
|
||||||
|
|
||||||
|
if "nod3d11" in self.compat_config:
|
||||||
|
self.dlloverrides["d3d11"] = ""
|
||||||
|
if "dxgi" in self.dlloverrides:
|
||||||
|
del self.dlloverrides["dxgi"]
|
||||||
|
|
||||||
|
if "nod3d10" in self.compat_config:
|
||||||
|
self.dlloverrides["d3d10_1"] = ""
|
||||||
|
self.dlloverrides["d3d10"] = ""
|
||||||
|
self.dlloverrides["dxgi"] = ""
|
||||||
|
|
||||||
|
if "nod3d9" in self.compat_config:
|
||||||
|
self.dlloverrides["d3d9"] = ""
|
||||||
|
|
||||||
|
s = ""
|
||||||
|
for dll in self.dlloverrides:
|
||||||
|
setting = self.dlloverrides[dll]
|
||||||
|
if len(s) > 0:
|
||||||
|
s = s + ";" + dll + "=" + setting
|
||||||
|
else:
|
||||||
|
s = dll + "=" + setting
|
||||||
|
if "WINEDLLOVERRIDES" in os.environ:
|
||||||
|
self.env["WINEDLLOVERRIDES"] = os.environ["WINEDLLOVERRIDES"] + ";" + s
|
||||||
|
else:
|
||||||
|
self.env["WINEDLLOVERRIDES"] = s
|
||||||
|
|
||||||
|
def dump_dbg_env(self, f):
|
||||||
|
f.write("PATH=\"" + self.env["PATH"] + "\" \\\n")
|
||||||
|
f.write("\tTERM=\"xterm\" \\\n") #XXX
|
||||||
|
f.write("\tWINEDEBUG=\"-all\" \\\n")
|
||||||
|
f.write("\tWINEDLLPATH=\"" + self.env["WINEDLLPATH"] + "\" \\\n")
|
||||||
|
f.write("\t" + ld_path_var + "=\"" + self.env[ld_path_var] + "\" \\\n")
|
||||||
|
f.write("\tWINEPREFIX=\"" + self.env["WINEPREFIX"] + "\" \\\n")
|
||||||
|
if "WINEESYNC" in self.env:
|
||||||
|
f.write("\tWINEESYNC=\"" + self.env["WINEESYNC"] + "\" \\\n")
|
||||||
|
if "WINEFSYNC" in self.env:
|
||||||
|
f.write("\tWINEFSYNC=\"" + self.env["WINEFSYNC"] + "\" \\\n")
|
||||||
|
if "SteamGameId" in self.env:
|
||||||
|
f.write("\tSteamGameId=\"" + self.env["SteamGameId"] + "\" \\\n")
|
||||||
|
if "SteamAppId" in self.env:
|
||||||
|
f.write("\tSteamAppId=\"" + self.env["SteamAppId"] + "\" \\\n")
|
||||||
|
if "WINEDLLOVERRIDES" in self.env:
|
||||||
|
f.write("\tWINEDLLOVERRIDES=\"" + self.env["WINEDLLOVERRIDES"] + "\" \\\n")
|
||||||
|
if "STEAM_COMPAT_CLIENT_INSTALL_PATH" in self.env:
|
||||||
|
f.write("\tSTEAM_COMPAT_CLIENT_INSTALL_PATH=\"" + self.env["STEAM_COMPAT_CLIENT_INSTALL_PATH"] + "\" \\\n")
|
||||||
|
if "WINE_LARGE_ADDRESS_AWARE" in self.env:
|
||||||
|
f.write("\tWINE_LARGE_ADDRESS_AWARE=\"" + self.env["WINE_LARGE_ADDRESS_AWARE"] + "\" \\\n")
|
||||||
|
|
||||||
|
def dump_dbg_scripts(self):
|
||||||
|
exe_name = os.path.basename(sys.argv[2])
|
||||||
|
|
||||||
|
tmpdir = self.env.get("PROTON_DEBUG_DIR", "/tmp") + "/proton_" + os.environ["USER"] + "/"
|
||||||
|
makedirs(tmpdir)
|
||||||
|
|
||||||
|
with open(tmpdir + "winedbg", "w") as f:
|
||||||
|
f.write("#!/bin/bash\n")
|
||||||
|
f.write("#Run winedbg with args\n\n")
|
||||||
|
f.write("cd \"" + os.getcwd() + "\"\n")
|
||||||
|
self.dump_dbg_env(f)
|
||||||
|
f.write("\t\"" + g_proton.wine_bin + "\" winedbg \"$@\"\n")
|
||||||
|
os.chmod(tmpdir + "winedbg", 0o755)
|
||||||
|
|
||||||
|
with open(tmpdir + "winedbg_run", "w") as f:
|
||||||
|
f.write("#!/bin/bash\n")
|
||||||
|
f.write("#Run winedbg and prepare to run game or given program\n\n")
|
||||||
|
f.write("cd \"" + os.getcwd() + "\"\n")
|
||||||
|
f.write("DEF_CMD=(")
|
||||||
|
first = True
|
||||||
|
for arg in sys.argv[2:]:
|
||||||
|
if first:
|
||||||
|
f.write("\"" + arg + "\"")
|
||||||
|
first = False
|
||||||
|
else:
|
||||||
|
f.write(" \"" + arg + "\"")
|
||||||
|
f.write(")\n")
|
||||||
|
self.dump_dbg_env(f)
|
||||||
|
f.write("\t\"" + g_proton.wine_bin + "\" winedbg \"${@:-${DEF_CMD[@]}}\"\n")
|
||||||
|
os.chmod(tmpdir + "winedbg_run", 0o755)
|
||||||
|
|
||||||
|
with open(tmpdir + "gdb_attach", "w") as f:
|
||||||
|
f.write("#!/bin/bash\n")
|
||||||
|
f.write("#Run winedbg in gdb mode and auto-attach to already-running program\n\n")
|
||||||
|
f.write("cd \"" + os.getcwd() + "\"\n")
|
||||||
|
f.write("EXE_NAME=${1:-\"" + exe_name + "\"}\n")
|
||||||
|
f.write("WPID_HEX=$(\"" + tmpdir + "winedbg\" --command 'info process' | grep -i \"$EXE_NAME\" | cut -f2 -d' ' | tr -d '0')\n")
|
||||||
|
f.write("if [ -z \"$WPID_HEX\" ]; then \n")
|
||||||
|
f.write(" echo \"Program does not appear to be running: \\\"$EXE_NAME\\\"\"\n")
|
||||||
|
f.write(" exit 1\n")
|
||||||
|
f.write("fi\n")
|
||||||
|
f.write("WPID_DEC=$(printf %d 0x$WPID_HEX)\n")
|
||||||
|
self.dump_dbg_env(f)
|
||||||
|
f.write("\t\"" + g_proton.wine_bin + "\" winedbg --gdb $WPID_DEC\n")
|
||||||
|
os.chmod(tmpdir + "gdb_attach", 0o755)
|
||||||
|
|
||||||
|
with open(tmpdir + "gdb_run", "w") as f:
|
||||||
|
f.write("#!/bin/bash\n")
|
||||||
|
f.write("#Run winedbg in gdb mode and prepare to run game or given program\n\n")
|
||||||
|
f.write("cd \"" + os.getcwd() + "\"\n")
|
||||||
|
f.write("DEF_CMD=(")
|
||||||
|
first = True
|
||||||
|
for arg in sys.argv[2:]:
|
||||||
|
if first:
|
||||||
|
f.write("\"" + arg + "\"")
|
||||||
|
first = False
|
||||||
|
else:
|
||||||
|
f.write(" \"" + arg + "\"")
|
||||||
|
f.write(")\n")
|
||||||
|
self.dump_dbg_env(f)
|
||||||
|
f.write("\t\"" + g_proton.wine_bin + "\" winedbg --gdb \"${@:-${DEF_CMD[@]}}\"\n")
|
||||||
|
os.chmod(tmpdir + "gdb_run", 0o755)
|
||||||
|
|
||||||
|
with open(tmpdir + "run", "w") as f:
|
||||||
|
f.write("#!/bin/bash\n")
|
||||||
|
f.write("#Run game or given command in environment\n\n")
|
||||||
|
f.write("cd \"" + os.getcwd() + "\"\n")
|
||||||
|
f.write("DEF_CMD=(")
|
||||||
|
first = True
|
||||||
|
for arg in sys.argv[2:]:
|
||||||
|
if first:
|
||||||
|
f.write("\"" + arg + "\"")
|
||||||
|
first = False
|
||||||
|
else:
|
||||||
|
f.write(" \"" + arg + "\"")
|
||||||
|
f.write(")\n")
|
||||||
|
self.dump_dbg_env(f)
|
||||||
|
f.write("\t\"" + g_proton.wine_bin + "\" steam.exe \"${@:-${DEF_CMD[@]}}\"\n")
|
||||||
|
os.chmod(tmpdir + "run", 0o755)
|
||||||
|
|
||||||
|
def run_proc(self, args, local_env=None):
|
||||||
|
if local_env is None:
|
||||||
|
local_env = self.env
|
||||||
|
subprocess.call(args, env=local_env, stderr=self.log_file, stdout=self.log_file)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
if "PROTON_DUMP_DEBUG_COMMANDS" in self.env and nonzero(self.env["PROTON_DUMP_DEBUG_COMMANDS"]):
|
||||||
|
try:
|
||||||
|
self.dump_dbg_scripts()
|
||||||
|
except OSError:
|
||||||
|
log("Unable to write debug scripts! " + str(sys.exc_info()[1]))
|
||||||
|
self.run_proc([g_proton.wine_bin, "steam"] + sys.argv[2:] + self.cmdlineappend)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
if not "STEAM_COMPAT_DATA_PATH" in os.environ:
|
||||||
|
log("No compat data path?")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
g_proton = Proton(os.path.dirname(sys.argv[0]))
|
||||||
|
|
||||||
|
# g_proton.extract_tarball()
|
||||||
|
|
||||||
|
g_compatdata = CompatData(os.environ["STEAM_COMPAT_DATA_PATH"])
|
||||||
|
|
||||||
|
g_session = Session()
|
||||||
|
|
||||||
|
g_session.init_wine()
|
||||||
|
|
||||||
|
g_proton.make_default_prefix()
|
||||||
|
|
||||||
|
g_session.init_session()
|
||||||
|
|
||||||
|
#determine mode
|
||||||
|
if sys.argv[1] == "run":
|
||||||
|
#start target app
|
||||||
|
g_session.run()
|
||||||
|
elif sys.argv[1] == "waitforexitandrun":
|
||||||
|
#wait for wineserver to shut down
|
||||||
|
g_session.run_proc([g_proton.wineserver_bin, "-w"])
|
||||||
|
#then run
|
||||||
|
g_session.run()
|
||||||
|
elif sys.argv[1] == "getcompatpath":
|
||||||
|
#linux -> windows path
|
||||||
|
path = subprocess.check_output([g_proton.wine_bin, "winepath", "-w", sys.argv[2]], env=g_session.env, stderr=g_session.log_file)
|
||||||
|
sys.stdout.buffer.write(path)
|
||||||
|
elif sys.argv[1] == "getnativepath":
|
||||||
|
#windows -> linux path
|
||||||
|
path = subprocess.check_output([g_proton.wine_bin, "winepath", sys.argv[2]], env=g_session.env, stderr=g_session.log_file)
|
||||||
|
sys.stdout.buffer.write(path)
|
||||||
|
else:
|
||||||
|
log("Need a verb.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
#pylint --disable=C0301,C0326,C0330,C0111,C0103,R0902,C1801,R0914,R0912,R0915
|
||||||
|
# vim: set syntax=python:
|
Loading…
Reference in New Issue
Block a user