Skip to content

Better Windows support #103

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

Closed

Conversation

wildmichael
Copy link

This branch provides a few fixes / changes to enable better support for Windows (using wrapper executables). Further, pip installation works better because git_describe_version() creates PEP 440 compliant version numbers.

@wildmichael wildmichael changed the title Feature/windows support Better Windows support Apr 29, 2021
Makefile Outdated
@@ -35,32 +35,39 @@ install-html:
lint: lint-black lint-isort lint-flake8 lint-t

lint-black:
$(PYTHON) -m black --check --quiet --diff . stg
$(PYTHON) -m black --check --quiet --diff . stgit/main.py
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do not need to add stgit/main.py to the command line of black, isort, or flake8. Those tools already find all the appropriate .py files, including stgit/main.py. The reason the stg script was here explicitly was because it lacked a .py extension. So passing . is sufficient for all three tools.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, will amend.

stgit/utils.py Outdated
@@ -93,7 +95,12 @@ def hook(*parameters):

# On Windows, run the hook using "bash" explicitly
if os.name != 'posix':
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the new behavior is even more Windows-specific, perhaps this test should become stronger. I.e. os.name == 'nt' or platform.system() == 'Windows'.

We may also wan to preserve the old behavior for non-Windows non-posix platforms. I.e. something like:

if os.name == 'nt':
    ...  # new behavior
elif os.name != 'posix':
    ...  # old behavior

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, but I will have to make sure that I don't break Cygwin. There's some weirdness there, if I remember correctly, in that it identifies both as Windows and POSIX.

stgit/utils.py Outdated
Comment on lines 99 to 102
git_exe = shutil.which('git.exe')
if not git_exe:
raise StgException('Failed to locate git.exe')
bash_exe = pathlib.Path(git_exe).parents[1] / 'bin' / 'bash.exe'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something I'm finding troubling here is that we seem to be subverting the user's PATH with this approach. I.e. if the user has their PATH setup such that there is a bash.exe available in a different location than their git.exe, we would override their PATH by forcing git's bash.exe to be used.

Along these lines, it's not entirely clear to me why the solution to this problem isn't to require the user to have a properly constructed PATH?

Also, in what circumstances is git.exe available, but bash.exe is not? StGit doesn't do anything special on Windows to find git.exe; so if bash.exe is in the same directory as git.exe, why do we have to perform this dance to find bash.exe relative to git.exe?

The comment seems to indicate that bash.exe is sometimes incorrectly found in the `Windows/System32' directory. Under what circumstances does this happen? I'm not a regular user of Windows, so I need help connecting these dots.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is that C:\Windows\System32\bash.exe is just a stupid bootstrapper that allows the user to install WSL, and it is present on all recent versions of Windows. Completely and utterly useless. For me the problem was that the bin directory of Git for Windows was appended to the PATH, i.e. after C:\Windows\System32. Hence, git.exe is found, but bash.exe resolves to this shim.

But I agree, subverting the user's PATH is bad. I'll have a look at how Git for Windows deals with this.

Makefile Outdated
Comment on lines 58 to 63
.install: build
pyver=`$(PYTHON) -c 'import sys; print(".".join(map(str, sys.version_info[:2])))'` && \
prefix="$(PWD)/inst/python$$pyver" && \
sitepackages="$$prefix/lib/python$$pyver/site-packages" && \
mkdir -p "$$sitepackages" && \
PYTHONPATH="$$sitepackages" $(PYTHON) setup.py develop --prefix="$$prefix"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not immediately comfortable with this approach. It's both different than StGit's existing non-setuptool strategy as well as being unconventional relative to how setuptools and entry-points are normally used.

In other setuptools projects that I work on, the pattern is to run pip install -e or setup.py develop to reify the entry points into runnable programs. This typically happens in the context of a virtualenv, but could also conceivably be done in the context of the per-user site-packages (PEP 370).

Creating this inst directory instead of either using a virtualenv or the user's site-packages is the part that seems unconventional to me--and perhaps unnecessarily so?

I'm a little fuzzy on whether setuptools is truly needed on Windows or whether it is a convenience versus the status quo? Is it not possible to install StGit correctly on Windows without this change?

Copy link
Author

@wildmichael wildmichael May 2, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem on Windows is that you need the exe-wrapper.

The reason I added the .install target was that the tests need a runnable version of stgit. Maybe the .install target is not necessary at all and make test can be run in a simpler way? I'll investigate a bit more.

t/test-lib.sh Outdated
PYTHON="${PYTHON:-python}"
python_major_minor="$($PYTHON -c '
import sys
print(".".join(map(str, sys.version_info[:2])))')"
stg_bin_dir="$stg_build_dir"/scripts-"$python_major_minor"
stg_inst_dir="$STG_ROOT/inst/python$python_major_minor"
stg_bin_dir="$stg_inst_dir"/bin # TODO on Windows this is .../Scripts
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment sort of implies that the test suite may not actually be runnable on Windows. What's the status of that?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Windows is... difficult :-) Honestly, I forgot about that before making the PR. The whole thing's been sitting on my computer for far too long.

@jpgrayson
Copy link
Collaborator

Thank you for this PR @wildmichael. It's good to know that there is someone out there using StGit on Windows.

There is a lot going on in these patches and I have several comments and questions that I've added as review comments.

@wildmichael wildmichael force-pushed the feature/windows-support branch from d268509 to b70819c Compare May 2, 2021 18:59
@wildmichael
Copy link
Author

wildmichael commented May 2, 2021

@jpgrayson I rebased to your current master and added two fixup commits (for later squashing) where I try to address your comments with the following actions:

  • stgit/main.py is removed from the black, flake8, etc. calls.
  • Instead of locally installing stgit to run the unit tests, I added a stgit/__main__.py that imports main.main() and runs it. This allows stgit to be run as a module like python -m stgit <command>. I leverage this in the script t/stgit. For the unit tests the PYTHONPATH and PATH are modified such that the module from the build directory is picked up and that running stg uses said wrapper script. That means the tests should now also run on Windows, provided they are started from a Bash shell (like Git Bash) and you get quilt to run (which I didn't try to, but the basic tests ran through).
  • In stgit/utils.py I modified the logic as suggested that a) the original behavior is preserved and b) on Windows the user's PATH is honoured as far as possible. I.e. C:/Windows/System32 is removed from PATH when trying to first locate bash.exe, and if that fails, git.exe. The latter helps because Git for Windows installs a bash.exe, but it is in a different directory than git.exe, and hence often not on the PATH.

@jpgrayson
Copy link
Collaborator

@jpgrayson I rebased to your current master and added two fixup commits (for later squashing) where I try to address your comments with the following actions:

* `stgit/main.py` is removed from the `black`, `flake8`, etc. calls.

Looks like one more instance of this remains in the format target.

* Instead of locally installing stgit to run the unit tests, I added a `stgit/__main__.py` that imports `main.main()` and runs it. This allows stgit to be run as a module like `python -m stgit <command>`. I leverage this in the script `t/stgit`. For the unit tests the `PYTHONPATH` and `PATH` are modified such that the module from the build directory is picked up and that running `stg` uses said wrapper script. That means the tests should now also run on Windows, provided they are started from a Bash shell (like Git Bash) and you get quilt to run (which I didn't try to, but the basic tests ran through).

My feeling is that you're on the right track with this approach. But given that the CI failed, it seems this may need some more attention.

* In `stgit/utils.py` I modified the logic as suggested that a) the original behavior is preserved and b) on Windows the user's `PATH` is honoured as far as possible. I.e. `C:/Windows/System32` is removed from `PATH` when trying to first locate `bash.exe`, and if that fails, `git.exe`. The latter helps because Git for Windows installs a `bash.exe`, but it is in a different directory than `git.exe`, and hence often not on the `PATH`.

I appreciate the explanation you provided about the Windows-provided bash.exe found in the System32 directory. This updated approach seems okay. And if it's not perfectly okay, it is at least well-contained to Windows platforms.

Thanks for the additional forward progress on this PR. Obviously need to resolve the failing CI as a key next step. I'm also wondering if we might want to split this into a couple of pieces. For example, the PEP-440 version strings is largely orthogonal and non-controversial, so we could get that piece merged sooner than later if it was in its own PR.

@wildmichael wildmichael force-pushed the feature/windows-support branch from b70819c to 3aa91d5 Compare May 4, 2021 07:44
@wildmichael
Copy link
Author

Finally the CI runs through cleanly on my fork (embarrassing, sorry). I also found a way of getting around the stgit/__main__.py file.

While tinkering I found that some tests that grep the output of stg are a bit fragile. Because I had __main__.py as argv[0] the line got longer and the output wrapped, causing the grep to fail.

@wildmichael wildmichael force-pushed the feature/windows-support branch from 43acf68 to 9eaaaa2 Compare May 17, 2021 10:20
Comment on lines +1 to +4
#!/bin/sh

# This script is only used by the tests so they can work without stgit being
# installed. It assumes PYTHONPATH to be set up correctly.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we want to avoid making changes like this to the test infra. The test infra is heavily borrowed from git -- every change we make makes it more difficult to update our infra to match git's. If think is something we think is important the best place to add it might be the git repo itself.

Is this something that's needed for Windows?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for being MIA for so long... Yes, I agree, it is bad. Maybe move it out of t/? As to your question: no, it is more related to setuptool packaging.

done

.PHONY: format test test-patches
.PHONY: format test test-patches .install
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the rule has been removed?

@@ -71,10 +71,11 @@ coverage-test:
$(MAKE) .coverage

.coverage:
rm -rf build
rm -rf install
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is adding this install file? am i missing something?

-mkdir .cov-files
COVERAGE_FILE=$(CURDIR)/.cov-files/.coverage \
$(PYTHON) -m coverage run --context=setup setup.py build
$(PYTHON) -m coverage run --context=setup setup.py install
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same

@@ -96,6 +97,7 @@ clean:
$(MAKE) -C $$dir clean; \
done
rm -rf build
rm -rf inst
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

install?

jpgrayson added a commit that referenced this pull request Aug 29, 2021
When running hooks on Windows, bash.exe must be supplied on the command
line to run the hook script. This change tries to find a viable bash.exe
from the user's PATH, while avoiding the bash.exe stub in the OS's System32
directory.

This change is adapted from Michael Wild's PR #103.

Signed-off-by: Peter Grayson <[email protected]>
@jpgrayson
Copy link
Collaborator

I've posted a discussion topic #152 that is directly related to this PR. @wildmichael @topher200

Michael Wild added 10 commits August 30, 2021 15:49
This allows stgit to work seamlessly on Windows where setuptools automatically
creates a wrapper executable. On other platforms, a wrapper script is
generated.

Requires setuptools instead of distutils. The little functionality that was
present in stg has been migrated to stg.main:main().

Signed-off-by: Michael Wild <[email protected]>
Don't output current working directory to stdout in t/stg
Simplify by removing stgit/__main__.py and directly calling stgit.main as module from t/stg
Remove more instances of stgit/main.py being passed to linting tools.
@wildmichael wildmichael force-pushed the feature/windows-support branch from 9eaaaa2 to 37b43b4 Compare August 30, 2021 14:06
@jpgrayson
Copy link
Collaborator

I've pushed several changes that overlap with the changes and goals of this PR:

  • Use setuptools instead of distutils
  • Install stg executable as a console_script entry point.
  • Enable running StGit with python -m stgit ....
  • Make test suite work with all of the above

So at this point, I think all of the goals of this PR are accomplished. Would love feedback from @wildmichael or any other Windows users out. Would like to close this PR if everything is covered.

@wildmichael
Copy link
Author

wildmichael commented Sep 9, 2021

So far your master branch works nicely on Windows. However, one strange thing: I had to install it from a local copy. Installing directly from the GitHub repo via URL fails to create / find completion/stg.fish:

PS1> pip install git+https://github.com/stacked-git/stgit.git
Collecting git+https://github.com/stacked-git/stgit.git
  Cloning https://github.com/stacked-git/stgit.git to c:\users\me\appdata\local\temp\pip-req-build-53fyh2xq
  Running command git clone -q https://github.com/stacked-git/stgit.git 'C:\Users\me\AppData\Local\Temp\pip-req-build-53fyh2xq'
  Resolved https://github.com/stacked-git/stgit.git to commit 1aa00150ee9aa41d0d1f6e13ed08692446c8378d
  Installing build dependencies ... done
  Getting requirements to build wheel ... done
    Preparing wheel metadata ... done
Building wheels for collected packages: stgit
  Building wheel for stgit (PEP 517) ... error
  ERROR: Command errored out with exit status 1:
   command: 'c:\tools\miniconda3\python.exe' 'c:\tools\miniconda3\lib\site-packages\pip\_vendor\pep517\in_process\_in_process.py' build_wheel 'C:\Users\me\AppData\Local\Temp\tmpwkmf4w9y'
       cwd: C:\Users\me\AppData\Local\Temp\pip-req-build-53fyh2xq
  Complete output (209 lines):
  Skipping stgit code generation
  running bdist_wheel
  running build
  running build_py
  creating build
  creating build\lib
  creating build\lib\stgit
  copying stgit\argparse.py -> build\lib\stgit
  copying stgit\compat.py -> build\lib\stgit
  copying stgit\config.py -> build\lib\stgit
  copying stgit\exception.py -> build\lib\stgit
  copying stgit\main.py -> build\lib\stgit
  copying stgit\out.py -> build\lib\stgit
  copying stgit\pager.py -> build\lib\stgit
  copying stgit\run.py -> build\lib\stgit
  copying stgit\templates.py -> build\lib\stgit
  copying stgit\utils.py -> build\lib\stgit
  copying stgit\_version.py -> build\lib\stgit
  copying stgit\__init__.py -> build\lib\stgit
  copying stgit\__main__.py -> build\lib\stgit
  creating build\lib\stgit\commands
  copying stgit\commands\branch.py -> build\lib\stgit\commands
  copying stgit\commands\clean.py -> build\lib\stgit\commands
  copying stgit\commands\clone.py -> build\lib\stgit\commands
  copying stgit\commands\commit.py -> build\lib\stgit\commands
  copying stgit\commands\common.py -> build\lib\stgit\commands
  copying stgit\commands\delete.py -> build\lib\stgit\commands
  copying stgit\commands\diff.py -> build\lib\stgit\commands
  copying stgit\commands\edit.py -> build\lib\stgit\commands
  copying stgit\commands\export.py -> build\lib\stgit\commands
  copying stgit\commands\files.py -> build\lib\stgit\commands
  copying stgit\commands\float.py -> build\lib\stgit\commands
  copying stgit\commands\fold.py -> build\lib\stgit\commands
  copying stgit\commands\goto.py -> build\lib\stgit\commands
  copying stgit\commands\hide.py -> build\lib\stgit\commands
  copying stgit\commands\id.py -> build\lib\stgit\commands
  copying stgit\commands\imprt.py -> build\lib\stgit\commands
  copying stgit\commands\init.py -> build\lib\stgit\commands
  copying stgit\commands\log.py -> build\lib\stgit\commands
  copying stgit\commands\mail.py -> build\lib\stgit\commands
  copying stgit\commands\new.py -> build\lib\stgit\commands
  copying stgit\commands\next.py -> build\lib\stgit\commands
  copying stgit\commands\patches.py -> build\lib\stgit\commands
  copying stgit\commands\pick.py -> build\lib\stgit\commands
  copying stgit\commands\pop.py -> build\lib\stgit\commands
  copying stgit\commands\prev.py -> build\lib\stgit\commands
  copying stgit\commands\pull.py -> build\lib\stgit\commands
  copying stgit\commands\push.py -> build\lib\stgit\commands
  copying stgit\commands\rebase.py -> build\lib\stgit\commands
  copying stgit\commands\redo.py -> build\lib\stgit\commands
  copying stgit\commands\refresh.py -> build\lib\stgit\commands
  copying stgit\commands\rename.py -> build\lib\stgit\commands
  copying stgit\commands\repair.py -> build\lib\stgit\commands
  copying stgit\commands\reset.py -> build\lib\stgit\commands
  copying stgit\commands\series.py -> build\lib\stgit\commands
  copying stgit\commands\show.py -> build\lib\stgit\commands
  copying stgit\commands\sink.py -> build\lib\stgit\commands
  copying stgit\commands\squash.py -> build\lib\stgit\commands
  copying stgit\commands\sync.py -> build\lib\stgit\commands
  copying stgit\commands\top.py -> build\lib\stgit\commands
  copying stgit\commands\uncommit.py -> build\lib\stgit\commands
  copying stgit\commands\undo.py -> build\lib\stgit\commands
  copying stgit\commands\unhide.py -> build\lib\stgit\commands
  copying stgit\commands\__init__.py -> build\lib\stgit\commands
  creating build\lib\stgit\completion
  copying stgit\completion\bash.py -> build\lib\stgit\completion
  copying stgit\completion\fish.py -> build\lib\stgit\completion
  copying stgit\completion\__init__.py -> build\lib\stgit\completion
  creating build\lib\stgit\lib
  copying stgit\lib\edit.py -> build\lib\stgit\lib
  copying stgit\lib\log.py -> build\lib\stgit\lib
  copying stgit\lib\objcache.py -> build\lib\stgit\lib
  copying stgit\lib\stack.py -> build\lib\stgit\lib
  copying stgit\lib\stackupgrade.py -> build\lib\stgit\lib
  copying stgit\lib\transaction.py -> build\lib\stgit\lib
  copying stgit\lib\__init__.py -> build\lib\stgit\lib
  creating build\lib\stgit\lib\git
  copying stgit\lib\git\base.py -> build\lib\stgit\lib\git
  copying stgit\lib\git\branch.py -> build\lib\stgit\lib\git
  copying stgit\lib\git\date.py -> build\lib\stgit\lib\git
  copying stgit\lib\git\iw.py -> build\lib\stgit\lib\git
  copying stgit\lib\git\objects.py -> build\lib\stgit\lib\git
  copying stgit\lib\git\person.py -> build\lib\stgit\lib\git
  copying stgit\lib\git\repository.py -> build\lib\stgit\lib\git
  copying stgit\lib\git\__init__.py -> build\lib\stgit\lib\git
  running egg_info
  writing stgit.egg-info\PKG-INFO
  writing dependency_links to stgit.egg-info\dependency_links.txt
  writing entry points to stgit.egg-info\entry_points.txt
  writing top-level names to stgit.egg-info\top_level.txt
  reading manifest file 'stgit.egg-info\SOURCES.txt'
  reading manifest template 'MANIFEST.in'
  adding license file 'COPYING'
  adding license file 'AUTHORS.md'
  writing manifest file 'stgit.egg-info\SOURCES.txt'
  creating build\lib\stgit\templates
  copying stgit\templates\covermail.tmpl -> build\lib\stgit\templates
  copying stgit\templates\mailattch.tmpl -> build\lib\stgit\templates
  copying stgit\templates\patchandattch.tmpl -> build\lib\stgit\templates
  copying stgit\templates\patchexport.tmpl -> build\lib\stgit\templates
  copying stgit\templates\patchmail.tmpl -> build\lib\stgit\templates
  installing to build\bdist.win-amd64\wheel
  running install
  running install_lib
  creating build\bdist.win-amd64
  creating build\bdist.win-amd64\wheel
  creating build\bdist.win-amd64\wheel\stgit
  copying build\lib\stgit\argparse.py -> build\bdist.win-amd64\wheel\.\stgit
  creating build\bdist.win-amd64\wheel\stgit\commands
  copying build\lib\stgit\commands\branch.py -> build\bdist.win-amd64\wheel\.\stgit\commands
  copying build\lib\stgit\commands\clean.py -> build\bdist.win-amd64\wheel\.\stgit\commands
  copying build\lib\stgit\commands\clone.py -> build\bdist.win-amd64\wheel\.\stgit\commands
  copying build\lib\stgit\commands\commit.py -> build\bdist.win-amd64\wheel\.\stgit\commands
  copying build\lib\stgit\commands\common.py -> build\bdist.win-amd64\wheel\.\stgit\commands
  copying build\lib\stgit\commands\delete.py -> build\bdist.win-amd64\wheel\.\stgit\commands
  copying build\lib\stgit\commands\diff.py -> build\bdist.win-amd64\wheel\.\stgit\commands
  copying build\lib\stgit\commands\edit.py -> build\bdist.win-amd64\wheel\.\stgit\commands
  copying build\lib\stgit\commands\export.py -> build\bdist.win-amd64\wheel\.\stgit\commands
  copying build\lib\stgit\commands\files.py -> build\bdist.win-amd64\wheel\.\stgit\commands
  copying build\lib\stgit\commands\float.py -> build\bdist.win-amd64\wheel\.\stgit\commands
  copying build\lib\stgit\commands\fold.py -> build\bdist.win-amd64\wheel\.\stgit\commands
  copying build\lib\stgit\commands\goto.py -> build\bdist.win-amd64\wheel\.\stgit\commands
  copying build\lib\stgit\commands\hide.py -> build\bdist.win-amd64\wheel\.\stgit\commands
  copying build\lib\stgit\commands\id.py -> build\bdist.win-amd64\wheel\.\stgit\commands
  copying build\lib\stgit\commands\imprt.py -> build\bdist.win-amd64\wheel\.\stgit\commands
  copying build\lib\stgit\commands\init.py -> build\bdist.win-amd64\wheel\.\stgit\commands
  copying build\lib\stgit\commands\log.py -> build\bdist.win-amd64\wheel\.\stgit\commands
  copying build\lib\stgit\commands\mail.py -> build\bdist.win-amd64\wheel\.\stgit\commands
  copying build\lib\stgit\commands\new.py -> build\bdist.win-amd64\wheel\.\stgit\commands
  copying build\lib\stgit\commands\next.py -> build\bdist.win-amd64\wheel\.\stgit\commands
  copying build\lib\stgit\commands\patches.py -> build\bdist.win-amd64\wheel\.\stgit\commands
  copying build\lib\stgit\commands\pick.py -> build\bdist.win-amd64\wheel\.\stgit\commands
  copying build\lib\stgit\commands\pop.py -> build\bdist.win-amd64\wheel\.\stgit\commands
  copying build\lib\stgit\commands\prev.py -> build\bdist.win-amd64\wheel\.\stgit\commands
  copying build\lib\stgit\commands\pull.py -> build\bdist.win-amd64\wheel\.\stgit\commands
  copying build\lib\stgit\commands\push.py -> build\bdist.win-amd64\wheel\.\stgit\commands
  copying build\lib\stgit\commands\rebase.py -> build\bdist.win-amd64\wheel\.\stgit\commands
  copying build\lib\stgit\commands\redo.py -> build\bdist.win-amd64\wheel\.\stgit\commands
  copying build\lib\stgit\commands\refresh.py -> build\bdist.win-amd64\wheel\.\stgit\commands
  copying build\lib\stgit\commands\rename.py -> build\bdist.win-amd64\wheel\.\stgit\commands
  copying build\lib\stgit\commands\repair.py -> build\bdist.win-amd64\wheel\.\stgit\commands
  copying build\lib\stgit\commands\reset.py -> build\bdist.win-amd64\wheel\.\stgit\commands
  copying build\lib\stgit\commands\series.py -> build\bdist.win-amd64\wheel\.\stgit\commands
  copying build\lib\stgit\commands\show.py -> build\bdist.win-amd64\wheel\.\stgit\commands
  copying build\lib\stgit\commands\sink.py -> build\bdist.win-amd64\wheel\.\stgit\commands
  copying build\lib\stgit\commands\squash.py -> build\bdist.win-amd64\wheel\.\stgit\commands
  copying build\lib\stgit\commands\sync.py -> build\bdist.win-amd64\wheel\.\stgit\commands
  copying build\lib\stgit\commands\top.py -> build\bdist.win-amd64\wheel\.\stgit\commands
  copying build\lib\stgit\commands\uncommit.py -> build\bdist.win-amd64\wheel\.\stgit\commands
  copying build\lib\stgit\commands\undo.py -> build\bdist.win-amd64\wheel\.\stgit\commands
  copying build\lib\stgit\commands\unhide.py -> build\bdist.win-amd64\wheel\.\stgit\commands
  copying build\lib\stgit\commands\__init__.py -> build\bdist.win-amd64\wheel\.\stgit\commands
  copying build\lib\stgit\compat.py -> build\bdist.win-amd64\wheel\.\stgit
  creating build\bdist.win-amd64\wheel\stgit\completion
  copying build\lib\stgit\completion\bash.py -> build\bdist.win-amd64\wheel\.\stgit\completion
  copying build\lib\stgit\completion\fish.py -> build\bdist.win-amd64\wheel\.\stgit\completion
  copying build\lib\stgit\completion\__init__.py -> build\bdist.win-amd64\wheel\.\stgit\completion
  copying build\lib\stgit\config.py -> build\bdist.win-amd64\wheel\.\stgit
  copying build\lib\stgit\exception.py -> build\bdist.win-amd64\wheel\.\stgit
  creating build\bdist.win-amd64\wheel\stgit\lib
  copying build\lib\stgit\lib\edit.py -> build\bdist.win-amd64\wheel\.\stgit\lib
  creating build\bdist.win-amd64\wheel\stgit\lib\git
  copying build\lib\stgit\lib\git\base.py -> build\bdist.win-amd64\wheel\.\stgit\lib\git
  copying build\lib\stgit\lib\git\branch.py -> build\bdist.win-amd64\wheel\.\stgit\lib\git
  copying build\lib\stgit\lib\git\date.py -> build\bdist.win-amd64\wheel\.\stgit\lib\git
  copying build\lib\stgit\lib\git\iw.py -> build\bdist.win-amd64\wheel\.\stgit\lib\git
  copying build\lib\stgit\lib\git\objects.py -> build\bdist.win-amd64\wheel\.\stgit\lib\git
  copying build\lib\stgit\lib\git\person.py -> build\bdist.win-amd64\wheel\.\stgit\lib\git
  copying build\lib\stgit\lib\git\repository.py -> build\bdist.win-amd64\wheel\.\stgit\lib\git
  copying build\lib\stgit\lib\git\__init__.py -> build\bdist.win-amd64\wheel\.\stgit\lib\git
  copying build\lib\stgit\lib\log.py -> build\bdist.win-amd64\wheel\.\stgit\lib
  copying build\lib\stgit\lib\objcache.py -> build\bdist.win-amd64\wheel\.\stgit\lib
  copying build\lib\stgit\lib\stack.py -> build\bdist.win-amd64\wheel\.\stgit\lib
  copying build\lib\stgit\lib\stackupgrade.py -> build\bdist.win-amd64\wheel\.\stgit\lib
  copying build\lib\stgit\lib\transaction.py -> build\bdist.win-amd64\wheel\.\stgit\lib
  copying build\lib\stgit\lib\__init__.py -> build\bdist.win-amd64\wheel\.\stgit\lib
  copying build\lib\stgit\main.py -> build\bdist.win-amd64\wheel\.\stgit
  copying build\lib\stgit\out.py -> build\bdist.win-amd64\wheel\.\stgit
  copying build\lib\stgit\pager.py -> build\bdist.win-amd64\wheel\.\stgit
  copying build\lib\stgit\run.py -> build\bdist.win-amd64\wheel\.\stgit
  creating build\bdist.win-amd64\wheel\stgit\templates
  copying build\lib\stgit\templates\covermail.tmpl -> build\bdist.win-amd64\wheel\.\stgit\templates
  copying build\lib\stgit\templates\mailattch.tmpl -> build\bdist.win-amd64\wheel\.\stgit\templates
  copying build\lib\stgit\templates\patchandattch.tmpl -> build\bdist.win-amd64\wheel\.\stgit\templates
  copying build\lib\stgit\templates\patchexport.tmpl -> build\bdist.win-amd64\wheel\.\stgit\templates
  copying build\lib\stgit\templates\patchmail.tmpl -> build\bdist.win-amd64\wheel\.\stgit\templates
  copying build\lib\stgit\templates.py -> build\bdist.win-amd64\wheel\.\stgit
  copying build\lib\stgit\utils.py -> build\bdist.win-amd64\wheel\.\stgit
  copying build\lib\stgit\_version.py -> build\bdist.win-amd64\wheel\.\stgit
  copying build\lib\stgit\__init__.py -> build\bdist.win-amd64\wheel\.\stgit
  copying build\lib\stgit\__main__.py -> build\bdist.win-amd64\wheel\.\stgit
  running install_data
  creating build\bdist.win-amd64\wheel\stgit-1.1.dev75+g1aa0015.data
  creating build\bdist.win-amd64\wheel\stgit-1.1.dev75+g1aa0015.data\data
  creating build\bdist.win-amd64\wheel\stgit-1.1.dev75+g1aa0015.data\data\share
  creating build\bdist.win-amd64\wheel\stgit-1.1.dev75+g1aa0015.data\data\share\stgit
  creating build\bdist.win-amd64\wheel\stgit-1.1.dev75+g1aa0015.data\data\share\stgit\templates
  copying stgit\templates\covermail.tmpl -> build\bdist.win-amd64\wheel\stgit-1.1.dev75+g1aa0015.data\data\share\stgit\templates
  copying stgit\templates\mailattch.tmpl -> build\bdist.win-amd64\wheel\stgit-1.1.dev75+g1aa0015.data\data\share\stgit\templates
  copying stgit\templates\patchandattch.tmpl -> build\bdist.win-amd64\wheel\stgit-1.1.dev75+g1aa0015.data\data\share\stgit\templates
  copying stgit\templates\patchexport.tmpl -> build\bdist.win-amd64\wheel\stgit-1.1.dev75+g1aa0015.data\data\share\stgit\templates
  copying stgit\templates\patchmail.tmpl -> build\bdist.win-amd64\wheel\stgit-1.1.dev75+g1aa0015.data\data\share\stgit\templates
  creating build\bdist.win-amd64\wheel\stgit-1.1.dev75+g1aa0015.data\data\share\stgit\examples
  copying examples\patchdescr.tmpl -> build\bdist.win-amd64\wheel\stgit-1.1.dev75+g1aa0015.data\data\share\stgit\examples
  copying examples\gitconfig -> build\bdist.win-amd64\wheel\stgit-1.1.dev75+g1aa0015.data\data\share\stgit\examples
  creating build\bdist.win-amd64\wheel\stgit-1.1.dev75+g1aa0015.data\data\share\stgit\contrib
  copying contrib\stgbashprompt.sh -> build\bdist.win-amd64\wheel\stgit-1.1.dev75+g1aa0015.data\data\share\stgit\contrib
  creating build\bdist.win-amd64\wheel\stgit-1.1.dev75+g1aa0015.data\data\share\stgit\completion
  error: can't copy 'completion\stg.fish': doesn't exist or not a regular file
  ----------------------------------------
  ERROR: Failed building wheel for stgit
Failed to build stgit
ERROR: Could not build wheels for stgit which use PEP 517 and cannot be installed directly

I think the message about PEP 517 is a fluke, the real error is error: can't copy 'completion\stg.fish': doesn't exist or not a regular file. I haven't yet figured out what's causing this.

@jpgrayson
Copy link
Collaborator

Thanks @wildmichael for taking the time to try this out on Windows--I really appreciate it.

Installing directly from the GitHub repo via URL

That was not a use case I had considered.

PS1> pip install git+https://github.com/stacked-git/stgit.git
...
  creating build\bdist.win-amd64\wheel\stgit-1.1.dev75+g1aa0015.data\data\share\stgit\completion
  error: can't copy 'completion\stg.fish': doesn't exist or not a regular file
  ----------------------------------------
  ERROR: Failed building wheel for stgit
Failed to build stgit
ERROR: Could not build wheels for stgit which use PEP 517 and cannot be installed directly

I think the message about PEP 517 is a fluke, the real error is error: can't copy 'completion\stg.fish': doesn't exist or not a regular file. I haven't yet figured out what's causing this.

I think I know the problem. And you're right that it is all about the generated files, which includes stg.fish and a few others.

When building from a local git worktree, setup.py generates three files: stg.fish, stgit.bash, and cmdlist.py. The code that performs the code generation needs to import stgit to do the code generation. This creates a bit of a chicken and egg problem such that stgit needs to be imported before it is built/installed. In the context of a local worktree, the chicken/egg is resolvable because stgit is importable from the worktree. In the context of the pip installation process, however, stgit is not (trivially) importable and as such, setup.py skips the code generation phase. Note this line from the output:

Skipping stgit code generation

The import-ability of stgit at pip install time may be solvable by altering sys.path or with some fancy use of importlib. However, taking such measures might violate the build sandbox that pip/pep-517 are trying to establish, which could mean that something that works today may not work in the future if the sandbox changes.

I'll note that in the context of either an sdist tarball, a git archive tarball, or a wheel (.whl), the generated files are included in those distributions such that the setup.py-time code generation is unnecessary. So if one were to attempt to install StGit from any of those, e.g. with pip install https://.../stgit-xxx.tar.gz, it would work. These are paths that are tested with the new contrib/release/pkgtest.py script.

Anyway, I do think it would be good for the use case of installing from a git URL to work, so I'll try to figure that out.

@wildmichael
Copy link
Author

Once released on pypi or as a conda package, this indeed shouldn't be an issue for most users anymore. For packages where I want to try out a specific branch though, I often pip install from a git URL, and I don't think I'm the only one. If it proves too hard or hacky to work around this problem, maybe there is a way of giving a better error message? Having to clone to /temp and then pip install really isn't that much of a problem once you realize what the issue is.

@jpgrayson
Copy link
Collaborator

I was able to update setup.py to allow installation from a git URL to work (f40b254).

I'm closing this PR. Let's open new issues for any further problems we find with Windows, packaging, or installation.

@jpgrayson jpgrayson closed this Sep 10, 2021
@wildmichael
Copy link
Author

I just gave it a shot, and can confirm it works like a charm! Thank you so much. No I can start proselytizing stgit to my work mates 😀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants