Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error in updating deck by importing from Github URL (Anki 2.1.46) #138

Closed
Raagaception opened this issue Aug 13, 2021 · 6 comments · Fixed by #139
Closed

Error in updating deck by importing from Github URL (Anki 2.1.46) #138

Raagaception opened this issue Aug 13, 2021 · 6 comments · Fixed by #139

Comments

@Raagaception
Copy link

I've been trying to get my deck uploaded with CrowdAnki in my attempt to open community contributions for v1.0.0 of my deck which can be found here. While testing out the "Import git repository" feature, I am encountering a weird error again and again. Apologies if this has been explained earlier, but I've wracked my brain trying to understand the fixes suggested in past similar issues and I still can't resolve this myself.

Steps to reproduce the error

  1. Create a new profile
  2. Import v1.0.0 via Git URL https://github.com/Raagaception/raagaception-12STD-CBSE-deck - this works flawlessly for the first time, every time. Regardless of whether I first import an older version (v0.9.3) of my deck and update that, or I start out in a blank profile, the first import is always perfect.
  3. Try importing v1.0.0 again via Git URL - importing a second time might work, but from the third time it almost always breaks. The error can also be caused by importing the deck, deleting it, and reimporting it again.

The resulting error(s)

Error 
An error occurred. Please start Anki while holding down the shift key, which will temporarily disable the add-ons you have installed. 
If the issue only occurs when add-ons are enabled, please use the Tools>Add-ons menu item to disable some add-ons and restart Anki, repeat until you discover the add-on that is causing the problem. 
When you've discovered the add-on that is causing the problem, please report the issue on the add-ons section of our support site. 
Debug info:
Anki 2.1.46 (94913ec2) Python 3.8.6 Qt 5.14.2 PyQt 5.14.2
Platform: Windows 10
Flags: frz=True ao=True sv=2
Add-ons, last update check: 2021-08-13 11:56:43

Caught exception:
Traceback (most recent call last):
  File "C:\Users\Adi\AppData\Roaming\Anki2\addons21\1788670778\anki\ui\action_vendor.py", line 35, in <lambda>
    lambda: GitImporter.on_git_import_action(self.window.col))
  File "C:\Users\Adi\AppData\Roaming\Anki2\addons21\1788670778\github\github_importer.py", line 28, in on_git_import_action
    GitImporter(collection).import_from_git()
  File "C:\Users\Adi\AppData\Roaming\Anki2\addons21\1788670778\github\github_importer.py", line 33, in import_from_git
    self.clone_repository_and_import(repo_url)
  File "C:\Users\Adi\AppData\Roaming\Anki2\addons21\1788670778\github\github_importer.py", line 39, in clone_repository_and_import
    porcelain.pull(porcelain.open_repo(str(repo_local_path)), repo_url)
  File "C:\Users\Adi\AppData\Roaming\Anki2\addons21\1788670778\dist\dulwich\porcelain.py", line 961, in pull
    fetch_result = client.fetch(
  File "C:\Users\Adi\AppData\Roaming\Anki2\addons21\1788670778\dist\dulwich\client.py", line 430, in fetch
    commit()
  File "C:\Users\Adi\AppData\Roaming\Anki2\addons21\1788670778\dist\dulwich\client.py", line 416, in commit
    target.object_store.add_thin_pack(f.read, None)
  File "C:\Users\Adi\AppData\Roaming\Anki2\addons21\1788670778\dist\dulwich\object_store.py", line 765, in add_thin_pack
    return self._complete_thin_pack(f, path, copier, indexer)
  File "C:\Users\Adi\AppData\Roaming\Anki2\addons21\1788670778\dist\dulwich\object_store.py", line 734, in _complete_thin_pack
    index_file.close()
  File "C:\Users\Adi\AppData\Roaming\Anki2\addons21\1788670778\dist\dulwich\file.py", line 175, in close
    os.replace(self._lockfilename, self._filename)
PermissionError: [WinError 5] Access is denied: 'C:\\Users\\Adi\\AppData\\Roaming\\Anki2\\addons21\\1788670778\\user_files\\Demo 2\\raagaception-12STD-CBSE-deck\\.git\\objects\\pack\\pack-da39a3ee5e6b4b0d3255bfef95601890afd80709.idx.lock' -> 'C:\\Users\\Adi\\AppData\\Roaming\\Anki2\\addons21\\1788670778\\user_files\\Demo 2\\raagaception-12STD-CBSE-deck\\.git\\objects\\pack\\pack-da39a3ee5e6b4b0d3255bfef95601890afd80709.idx'

The error PermissionError: [WinError x] where x can be 5, 32, or something else always shows up. And when WinError 32 occurs (haven't found a reliable way to reproduce it), Anki doesn't allow to delete the demo profile which I created for testing purposes. The .git folder mentioned in the error cannot be deleted, as Windows says it's "in use by another process".
A system restart allows me to delete the demo profile, but the CrowdAnki import issue still remains.

Any ideas as to what I might be doing wrong? Thanks for your help and patience in advance!

@aplaice
Copy link
Collaborator

aplaice commented Aug 13, 2021

Thanks for the bug report and I'm sorry that you're encountering the bug!

This looks like a windows file permission or file locking problem, but I'm not 100% sure. I'll try to reproduce (and hopefully fix), but probably not in the next several days. (I don't usually use Windows, so I'll need to reboot etc.)

(This might be a dulwich issue — perhaps we're not "closing" the repo always when we should? — I'll investigate. )

@Raagaception
Copy link
Author

Raagaception commented Aug 13, 2021

P.S. I reproduced the WinError 32 too; just import via URL once, then do it again, after which it throws the following error:

Error 
An error occurred. Please start Anki while holding down the shift key, which will temporarily disable the add-ons you have installed. 
If the issue only occurs when add-ons are enabled, please use the Tools>Add-ons menu item to disable some add-ons and restart Anki, repeat until you discover the add-on that is causing the problem. 
When you've discovered the add-on that is causing the problem, please report the issue on the add-ons section of our support site. 
Debug info:
Anki 2.1.46 (94913ec2) Python 3.8.6 Qt 5.14.2 PyQt 5.14.2
Platform: Windows 10
Flags: frz=True ao=True sv=2
Add-ons, last update check: 2021-08-13 11:56:43

Caught exception:
Traceback (most recent call last):
  File "C:\Users\Adi\AppData\Roaming\Anki2\addons21\1788670778\anki\ui\action_vendor.py", line 35, in <lambda>
    lambda: GitImporter.on_git_import_action(self.window.col))
  File "C:\Users\Adi\AppData\Roaming\Anki2\addons21\1788670778\github\github_importer.py", line 28, in on_git_import_action
    GitImporter(collection).import_from_git()
  File "C:\Users\Adi\AppData\Roaming\Anki2\addons21\1788670778\github\github_importer.py", line 33, in import_from_git
    self.clone_repository_and_import(repo_url)
  File "C:\Users\Adi\AppData\Roaming\Anki2\addons21\1788670778\github\github_importer.py", line 39, in clone_repository_and_import
    porcelain.pull(porcelain.open_repo(str(repo_local_path)), repo_url)
  File "C:\Users\Adi\AppData\Roaming\Anki2\addons21\1788670778\dist\dulwich\porcelain.py", line 961, in pull
    fetch_result = client.fetch(
  File "C:\Users\Adi\AppData\Roaming\Anki2\addons21\1788670778\dist\dulwich\client.py", line 430, in fetch
    commit()
  File "C:\Users\Adi\AppData\Roaming\Anki2\addons21\1788670778\dist\dulwich\client.py", line 416, in commit
    target.object_store.add_thin_pack(f.read, None)
  File "C:\Users\Adi\AppData\Roaming\Anki2\addons21\1788670778\dist\dulwich\object_store.py", line 765, in add_thin_pack
    return self._complete_thin_pack(f, path, copier, indexer)
  File "C:\Users\Adi\AppData\Roaming\Anki2\addons21\1788670778\dist\dulwich\object_store.py", line 724, in _complete_thin_pack
    os.remove(target_pack)
PermissionError: [WinError 32] The process cannot access the file because it is being used by another process: 'C:\\Users\\Adi\\AppData\\Roaming\\Anki2\\addons21\\1788670778\\user_files\\Demo 1\\raagaception-12STD-CBSE-deck\\.git\\objects\\pack\\pack-da39a3ee5e6b4b0d3255bfef95601890afd80709.pack'

Hopefully it might help you in fixing the error when you have the time! Thanks again for your patience.

EDIT :

(This might be a dulwich issue — perhaps we're not "closing" the repo always when we should? — I'll investigate. )

The issue listed at jelmer/dulwich#584 is the exact same error I'm facing.

aplaice added a commit to aplaice/CrowdAnki that referenced this issue Aug 17, 2021
Otherwise, especially on Windows, we might end up with locked files.

Fix Stvad#138.

dulwich's pull can operate either on paths or on dulwich repo objects.
Since it's using `open_repo_closing` internally, if it (and hence
`open_repo_closing`) are passed a path, the associated repo object
will be automatically closed after use, so we don't have to worry
about anything.  (If they're passed an already existing "repo object",
as we had been doing previously, then, internally, they use
`_noop_context_manager()`, instead of `closing()` and the repo object
isn't closed.)

(The above is true for current dulwich master
(`80bffaca1dfe59a5ba57a045f3ce7122227a7647`) — see
`dulwich/porcelain.py`.)
@aplaice
Copy link
Collaborator

aplaice commented Aug 17, 2021

Thanks again for your patience.

Thank you for your patience! :) (You're the one being affected by the bug!) Thanks also for the very detailed bug report!

I could, indeed, reproduce the error on Windows.

Like we both noted, the issue seems to be caused by the fact that the dulwich repo objects weren't being closed. I've fixed that in the linked PR (#139), and with that fix the error seems to have disappeared, at least for me!

Unfortunately, there are, as you can see, quite a few open PRs, so it might take a while for an updated version of CrowdAnki to be released to AnkiWeb. In the mean-time, if you want to fix the bug on your system (and it'd be great if you tested whether the bug is indeed fixed — I might have missed something), you can manually patch github_importer.py, which, in your case, should be at: C:\Users\Adi\AppData\Roaming\Anki2\addons21\1788670778\github\github_importer.py, as in the diff:

        try:
            repo_local_path = self.get_repo_local_path(repo_url)
-            porcelain.pull(porcelain.open_repo(str(repo_local_path)), repo_url)
+            porcelain.pull(str(repo_local_path), repo_url)
        except ValueError:
    def clone_repository(self, repo_url, repo_path):
        repo_path.mkdir(parents=True, exist_ok=True)
-        porcelain.clone(repo_url, target=str(repo_path), bare=False, checkout=True, errstream=porcelain.NoneStream(),
-                        outstream=porcelain.NoneStream())
+        repo_object = porcelain.clone(repo_url, target=str(repo_path), bare=False, checkout=True, errstream=porcelain.NoneStream(),
+                                      outstream=porcelain.NoneStream())
+        repo_object.close()

(The third change is an unimportant trailing newline one.)

(If something is unclear, or doesn't make sense, please ask.)


(For clarity: I'm not merging most of the open PRs, yet, despite most of them being by me, because:

  1. I'd like to double-check that there aren't any weird interactions between the PRs.
  2. I'd like to make sure that the PRs/fixes work with the latest versions of Anki.
  3. (Ideally) add automated integration-with-Anki tests.

)

@Raagaception
Copy link
Author

I made the changes, but unfortunately it still throws an error. github_importer.py.txt

Error 
An error occurred. Please start Anki while holding down the shift key, which will temporarily disable the add-ons you have installed. 
If the issue only occurs when add-ons are enabled, please use the Tools>Add-ons menu item to disable some add-ons and restart Anki, repeat until you discover the add-on that is causing the problem. 
When you've discovered the add-on that is causing the problem, please report the issue on the add-ons section of our support site. 
Debug info:
Anki 2.1.46 (94913ec2) Python 3.8.6 Qt 5.14.2 PyQt 5.14.2
Platform: Windows 10
Flags: frz=True ao=True sv=2
Add-ons, last update check: 2021-08-17 16:20:51

Caught exception:
Traceback (most recent call last):
  File "C:\Users\Adi\AppData\Roaming\Anki2\addons21\1788670778\anki\ui\action_vendor.py", line 35, in <lambda>
    lambda: GitImporter.on_git_import_action(self.window.col))
  File "C:\Users\Adi\AppData\Roaming\Anki2\addons21\1788670778\github\github_importer.py", line 28, in on_git_import_action
    GitImporter(collection).import_from_git()
  File "C:\Users\Adi\AppData\Roaming\Anki2\addons21\1788670778\github\github_importer.py", line 33, in import_from_git
    self.clone_repository_and_import(repo_url)
  File "C:\Users\Adi\AppData\Roaming\Anki2\addons21\1788670778\github\github_importer.py", line 39, in clone_repository_and_import
    porcelain.pull(str(repo_local_path), repo_url)
  File "C:\Users\Adi\AppData\Roaming\Anki2\addons21\1788670778\dist\dulwich\porcelain.py", line 961, in pull
    fetch_result = client.fetch(
  File "C:\Users\Adi\AppData\Roaming\Anki2\addons21\1788670778\dist\dulwich\client.py", line 430, in fetch
    commit()
  File "C:\Users\Adi\AppData\Roaming\Anki2\addons21\1788670778\dist\dulwich\client.py", line 416, in commit
    target.object_store.add_thin_pack(f.read, None)
  File "C:\Users\Adi\AppData\Roaming\Anki2\addons21\1788670778\dist\dulwich\object_store.py", line 765, in add_thin_pack
    return self._complete_thin_pack(f, path, copier, indexer)
  File "C:\Users\Adi\AppData\Roaming\Anki2\addons21\1788670778\dist\dulwich\object_store.py", line 734, in _complete_thin_pack
    index_file.close()
  File "C:\Users\Adi\AppData\Roaming\Anki2\addons21\1788670778\dist\dulwich\file.py", line 175, in close
    os.replace(self._lockfilename, self._filename)
PermissionError: [WinError 5] Access is denied: 'C:\\Users\\Adi\\AppData\\Roaming\\Anki2\\addons21\\1788670778\\user_files\\Demo 1\\raagaception-12STD-CBSE-deck\\.git\\objects\\pack\\pack-da39a3ee5e6b4b0d3255bfef95601890afd80709.idx.lock' -> 'C:\\Users\\Adi\\AppData\\Roaming\\Anki2\\addons21\\1788670778\\user_files\\Demo 1\\raagaception-12STD-CBSE-deck\\.git\\objects\\pack\\pack-da39a3ee5e6b4b0d3255bfef95601890afd80709.idx'

To recreate : import via GitHub URL, and do it again after the first import is successful.

@aplaice
Copy link
Collaborator

aplaice commented Aug 18, 2021

After a larger number of tests, I can also, again reproduce the error.

I'm slightly confused, as I've now tried quite a few permutations of dulwich repo closing, and none has worked.

(I've also realised that I had neglected to ensure that the repository was closed when archiving/snapshotting, but I can reproduce the issue without snapshotting enabled, so it's not the problem.)

I'll try the following (at some point, in some order (1. will be tried first, but I'm not sure about the rest)):

  1. Try upgrading dulwich (the version we have in AnkiWeb is 0.19.16, from Aprill 2020).
  2. Add a timer/delay before closing...
  3. Try to manually remove the lock file... (except PermissionError ...) (would need a huge amount of care to avoid unforeseen consequences)
  4. Report the issue upstream.
  5. Think about a reverse approach (i.e. instead of closing the "repo objects" asap, make them persistent and only close them once Anki is being closed).

Thanks for your patience! :)


Edit: 1 seems to work: Updating dulwich together with the patch seems to resolve the issue (I now did more tests than the last time I declared victory, but I may still have missed something :)). Unfortunately, manually editing the source of the add-on isn't practicable in this case — you could try building CrowdAnki yourself or I could upload an .ankiaddon file, once I'm sure that I haven't broken anything (and once building works without workarounds...).

@aplaice
Copy link
Collaborator

aplaice commented Aug 19, 2021

I've tested the version with both the mentioned changes on our side and an updated dulwich (in effect what's built from #139) and I think that the bug is fixed. (I've tested repeated git import, git import interspersed with snapshots and git imports from different repositories.)

If you want to check (I might have still missed something and behaviour might be different on different PCs) you could either build it yourself (using package_plugin.sh)/test it "from source" (as described in https://github.com/Stvad/CrowdAnki/blob/master/CONTRIBUTING.md#testing) or test it with this zip file (crowd_anki_20210819.zip). (You can either unzip it and place it in the relevant addons21 directory (AppData\Roaming\Anki2\addons21\) or rename the .zip to .ankiaddon and use Anki's built-in Tools > Add-ons > Install from file... mechanism. (Obviously, please disable the CrowdAnki from AnkiWeb, if it's enabled, and restart Anki.)

aplaice added a commit that referenced this issue Nov 20, 2021
Diagnose #138 which occurred on Windows.  (A lock for the git pack
file is often held by a previous clone/pull and not released, so the
next pull fails (`PermissionError`).)
aplaice added a commit to aplaice/CrowdAnki that referenced this issue Nov 20, 2021
Otherwise, especially on Windows, we might end up with locked files.

Fix Stvad#138.

dulwich's pull can operate either on paths or on dulwich repo objects.
Since it's using `open_repo_closing` internally, if it (and hence
`open_repo_closing`) are passed a path, the associated repo object
will be automatically closed after use, so we don't have to worry
about anything.  (If they're passed an already existing "repo object",
as we had been doing previously, then, internally, they use
`_noop_context_manager()`, instead of `closing()` and the repo object
isn't closed.)

(The above is true for current dulwich master
(`80bffaca1dfe59a5ba57a045f3ce7122227a7647`) — see
`dulwich/porcelain.py`.)
aplaice added a commit to aplaice/CrowdAnki that referenced this issue Nov 20, 2021
Otherwise, especially on Windows, we might end up with locked files.

Fix Stvad#138.

dulwich's pull can operate either on paths or on dulwich repo objects.
Since it's using `open_repo_closing` internally, if it (and hence
`open_repo_closing`) are passed a path, the associated repo object
will be automatically closed after use, so we don't have to worry
about anything.  (If they're passed an already existing "repo object",
as we had been doing previously, then, internally, they use
`_noop_context_manager()`, instead of `closing()` and the repo object
isn't closed.)

(The above is true for current dulwich master
(`80bffaca1dfe59a5ba57a045f3ce7122227a7647`) — see
`dulwich/porcelain.py`.)
aplaice added a commit to aplaice/CrowdAnki that referenced this issue Nov 20, 2021
Diagnose Stvad#138 which occurred on Windows.  (A lock for the git pack
file is often held by a previous clone/pull and not released, so the
next pull fails (`PermissionError`).)
aplaice added a commit to aplaice/CrowdAnki that referenced this issue Nov 20, 2021
Diagnose Stvad#138 which occurred on Windows.  (A lock for the git pack
file is often held by a previous clone/pull and not released, so the
next pull fails (`PermissionError`).)
aplaice added a commit to aplaice/CrowdAnki that referenced this issue Nov 22, 2021
Diagnose Stvad#138 which occurred on Windows.  (A lock for the git pack
file is often held by a previous clone/pull and not released, so the
next pull fails (`PermissionError`).)
aplaice added a commit to aplaice/CrowdAnki that referenced this issue Nov 22, 2021
Diagnose Stvad#138 which occurred on Windows.  (A lock for the git pack
file is often held by a previous clone/pull and not released, so the
next pull fails (`PermissionError`).)

The monkey-patching of `get_repo_local_path` is ugly, but far less
complex than partially mocking ConfigSettings.
aplaice added a commit to aplaice/CrowdAnki that referenced this issue Nov 23, 2021
Diagnose Stvad#138 which occurred on Windows.  (A lock for the git pack
file is often held by a previous clone/pull and not released, so the
next pull fails (`PermissionError`).)

The monkey-patching of `get_repo_local_path` is ugly, but far less
complex than partially mocking ConfigSettings.  Alternatively, we
could have modified `get_repo_local_path` to have an extra, optional
argument (say `full_snapshot_path` that'd override the config call),
but modifying the code to fit the test is also ugly.
aplaice added a commit to aplaice/CrowdAnki that referenced this issue Nov 23, 2021
Otherwise, especially on Windows, we might end up with locked files.

Fix Stvad#138.

dulwich's pull can operate either on paths or on dulwich repo objects.
Since it's using `open_repo_closing` internally, if it (and hence
`open_repo_closing`) are passed a path, the associated repo object
will be automatically closed after use, so we don't have to worry
about anything.  (If they're passed an already existing "repo object",
as we had been doing previously, then, internally, they use
`_noop_context_manager()`, instead of `closing()` and the repo object
isn't closed.)

(The above is true for current dulwich master
(`80bffaca1dfe59a5ba57a045f3ce7122227a7647`) — see
`dulwich/porcelain.py`.)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants