This splits the code for opening the lockfile away from that for
actually obtaining the lock. It enables a test for trying to lock again
with the same file handle.
* On win32 this uses pywin32 package modules, so that's now in
requirements-dev.txt.
* I *think* that code is as clean as it's going to be. Windows is a
pain with having you *append* a Deny ACL (rather than remove an Allow
one), and then you have to find it in all the ACLs for the object in
order to remove it by index.
* Linux version of this using `os.chmod()` currently untested.
Only tested under win32 so far, but I'd hope os.chmod() is the way to go
on Linux and macOS.
The win32 implementation currently relies on the pywin32 package being
installed in order to use its ntsecuritycon and win32security modules.
It might be possible to do this with ctypes instead, but this sure looks
cleaner than most ctypes code I've seen.
* mock get_str() is now via a fixture so it can be re-used in more than
one test, avoiding DRY issue.
* Some actual tests, in the form of asserts, added to
test_journal_lock_init().
In general I think this will keep things neater:
1. Create a directory inside tests/ named after the file the tests are
for.
2. Put all files for that test inside this new directory.
* Extend EDCD copyright into 2021 here as well.
* Recommend *against* any attempt at making plugins also work with
Python 2.7.
* setup.py no longer writes appcast files. Mention
edmarketconnector.xml enclosure instead for the url= bit.
* DRY about location of log files, just point to appropriate wiki link.
Nothing other than /shipyard actually returns the modules and ships
data, so checking for it anywhere other than that automatically is just
asking for extra log noise and nothing else.
* If it's None then set journal_dir_path to None as well. Setting '' or
nothing results in '.' (CWD), which could cause other issues.
* As we do this in three places, it's in a helper function.
* New JournalLockResult.JOURNALDIR_IS_NONE to signal this.
* Fix checking of return from obtain_lock() to specifically reference
JournalLockResult.ALREADY_LOCKED.
On darwin this comes back with the type `__NSCFArray`, which I can't
find the definition of (in order to test against it). So instead let's
check that `res` is not-None, and not one of `str` or `int`, because
then it should be (meant to be) `list`.
Yes, this is weird given the pre-rewrite code is:
```python
def get(self, key: str) -> Union[None, list, str]:
"""Look up a string configuration value."""
val = self.settings.get(key)
if val is None:
return None
elif isinstance(val, str):
return str(val)
elif isinstance(val, list):
return list(val) # make writeable
else:
return None
```
But maybe something changed since 3.43 was tested and built.
This way we can tell the difference between:
1. This process obtained the lock.
2. Another process has the lock.
3. We couldn't get the lock due to not being able to open the lock file
read-write.
Case 3 is currently also returned if the configured journal directory
doesn't exist. This will be the case on any MacOS system that never had
the game running. Likely given the OS hasn't been supported for the
game in years now.
# Conflicts:
# EDMarketConnector.py