langfield / ki

version control for Anki collections
https://langfield.github.io/ki/
GNU Affero General Public License v3.0
74 stars 3 forks source link

fix submodule.py script to handle empty directories #130

Closed SimonSelg closed 1 year ago

SimonSelg commented 1 year ago

When converting a desk into a submodule, the original folder gets rm'ed from the git repo. However, git rm does not always remove the folder: if there are untracked objects inside the folder (such as an empty _media) folder, it does not remove it.

This commit adds a check for that, and if it was not removed manually removes the folder.

This was disscussed in https://github.com/langfield/ki/issues/128

langfield commented 1 year ago

Hey @SimonSelg, this is very high-quality work! I'm impressed you went through the trouble of understanding this silly DSL I've written (the F namespace). I need to figure out how to run the tests on this, and I will rebase to change desk to deck in places. Other than that it looks great! I wrote a version of this that appears much worse than yours, so I'll compare and make sure there's no functionality missing.

SimonSelg commented 1 year ago

Oops, i missed that s/desk/deck in the comment. Sounds good :+1:

Question out of curiosity, while you mention the F namespace: what is the intention of having all those "as good as python allows"-typed "helper functions" all inside one big file? I think I get the difference between maybes.py and functional.py (the functions from maybes all can raise an exception), but yeah, would be interested in that.

langfield commented 1 year ago

Question out of curiosity, while you mention the F namespace: what is the intention of having all those "as good as python allows"-typed "helper functions" all inside one big file? I think I get the difference between maybes.py and functional.py (the functions from maybes all can raise an exception), but yeah, would be interested in that.

Ah yeah, long story short it's to get certain correctness guarantees from beartype. Basically it's another way of preventing a large class of bugs.

The typed paths allow you to distinguish between "this path doesn't exist because I forgot to create it" and "this path doesn't exist because I created it and somebody else deleted it from my filesystem". The former is a simple bug, the latter could be some weird-ass race condition or something.

To be more concrete with this example, a Dir is a directory that exists because we checked it's existence earlier in the program (or because we created it). It is thus a much more serious bug if we get a Directory not found-kind of error on a Dir than an ordinary Path.

The maybes.py functions are things that would actually return parametrized Maybe a type in a functional language like Haskell or Lean. You can think of it as a way of doing error-handling that composes really, really nicely. I recommend this video for an accessible introduction to the idea.

langfield commented 1 year ago

Okay so I merged it into a feature branch so I could mess around with it, but basically, this does not do exactly what we want.

(anki) mal@computer:~$ python3 ki/submodule.py --kirepo collection/ --deck Programming --remote git@github.com:langfield/submodule-pull-test.git
Operating on '/tmp/tmppnjda8oe/submodule-88928199c2338e23e72db19770e4502067a1c996'
Parsed 2 commits
New history written in 0.02 seconds; now repacking/cleaning...
Repacking your repo and cleaning out old unneeded objects
HEAD is now at c591193 Remove 'Programming'
Enumerating objects: 9, done.
Counting objects: 100% (9/9), done.
Delta compression using up to 8 threads
Compressing objects: 100% (8/8), done.
Writing objects: 100% (9/9), done.
Total 9 (delta 1), reused 0 (delta 0), pack-reused 0
Completely finished after 0.07 seconds.
branch 'main' set up to track 'origin/main'.
Traceback (most recent call last):
  File "/home/mal/ki/submodule.py", line 115, in <module>
    main()
  File "<@beartype(__main__.main) at 0x7fedec3930d0>", line 10, in main
  File "/home/mal/ki/submodule.py", line 94, in main
    repo.git.rm(args.deck, r=True)
  File "/home/mal/conda/envs/anki/lib/python3.9/site-packages/git/cmd.py", line 696, in <lambda>
    return lambda *args, **kwargs: self._call_process(name, *args, **kwargs)
  File "/home/mal/conda/envs/anki/lib/python3.9/site-packages/git/cmd.py", line 1270, in _call_process
    return self.execute(call, **exec_kwargs)
  File "/home/mal/conda/envs/anki/lib/python3.9/site-packages/git/cmd.py", line 1064, in execute
    raise GitCommandError(redacted_command, status, stderr_value, stdout_value)
git.exc.GitCommandError: Cmd('git') failed due to: exit code(128)
  cmdline: git rm -r Programming
  stderr: 'fatal: pathspec 'Programming' did not match any files'

Still raises an error if the deck is empty. I will merge a fix for it from this branch!