diff options
| author | 2014-06-13 21:51:04 -0300 | |
|---|---|---|
| committer | 2014-06-13 21:51:04 -0300 | |
| commit | 3dddbd8cc879402c2047919bccd20e6697082657 (patch) | |
| tree | 38d6290f37be1d67d91c46027974e6ee3372e232 /nikola/winutils.py | |
| parent | 7ac2cf148f7a8ea0de126fed3360b49964ce9b45 (diff) | |
| parent | 58c4878526dec5510f23c812274686787d8724ba (diff) | |
Merge tag 'upstream/7.0.1'
Upstream version 7.0.1
Diffstat (limited to 'nikola/winutils.py')
| -rw-r--r-- | nikola/winutils.py | 120 |
1 files changed, 69 insertions, 51 deletions
diff --git a/nikola/winutils.py b/nikola/winutils.py index 517a326..712de39 100644 --- a/nikola/winutils.py +++ b/nikola/winutils.py @@ -26,74 +26,92 @@ """windows utilities to workaround problems with symlinks in a git clone""" +from __future__ import print_function, unicode_literals import os import shutil -import sys -# don't add imports outside stdlib, will be imported in setup.py +# don't add imports to nikola code, will be imported in setup.py -def should_fix_git_symlinked(): - """True if git symlinls markers should be filled with the real content""" - if sys.platform == 'win32': - path = (os.path.dirname(__file__) + - r'\data\samplesite\stories\theming.rst') - try: - if os.path.getsize(path) < 200: - return True - except Exception: - pass - return False +def is_file_into_dir(filename, dirname): + try: + res = not os.path.relpath(filename, dirname).startswith('.') + except ValueError: + res = False + return res -def fix_git_symlinked(src, dst): - """fix git symlinked files in windows that had been copied from src to dst +def fix_all_git_symlinked(topdir): + """inplace conversion of git symlinks to real content Most (all?) of git implementations in windows store a symlink pointing into the repo as a text file, the text being the relative path to the file with the real content. So, in a clone of nikola in windows the symlinked files will have the - wrong content. + wrong content; a .zip download from Github has the same problem. - The linux usage pattern for those files is 'copy to some dir, then use', - so we inspect after the copy and rewrite the wrong contents. + This function will rewrite each symlinked file with the correct contents, but + keep in mind that the working copy will be seen as dirty by git after operation. - The goals are: - support running nikola from a clone without installing and without - making dirty the WC. + Expects to find a list of symlinked files at nikola/data/symlinked.txt - support install from the WC. + The list can be generated by scripts/generate_symlinked_list.sh , which is + basically a redirect of + cd nikola_checkout + git ls-files -s | awk '/120000/{print $4}' - if possible and needed, support running the test suite without making - dirty the WC. + Weakness: if interrupted of fail amidst a directory copy, next run will not + see the missing files. """ - # if running from WC there should be a 'doc' dir sibling to nikola package - if not should_fix_git_symlinked(): - return - # probabbly in a WC, so symlinks should be fixed - for root, dirs, files in os.walk(dst): - for name in files: - filename = os.path.join(root, name) - - # detect if symlinked - try: - if not (2 < os.path.getsize(filename) < 500): - continue - # which encoding uses a git symlink marker ? betting on default - with open(filename, 'r') as f: - text = f.read() - if text[0] != '.': - # de facto hint to skip binary files and exclude.meta - continue - except Exception: - # probably encoding: content binary or encoding not defalt, - # also in py2.6 it can be path encoding + with open(topdir + r'\nikola\data\symlinked.txt', 'rb') as f: + all_bytes = f.read() + text = all_bytes.decode('utf8') + # expect each line a relpath from git or zip root, + # smoke test relpaths are relative to git root + if text.startswith('.'): + raise Exception(r'Bad data in \nikola\data\symlinked.txt') + relnames = text.split('\n') + relnames = [name.strip().replace('/', '\\') for name in relnames] + relnames = [name for name in relnames if name] + + failures = 0 + for name in relnames: + # build dst path and do some basic validation + dst = os.path.join(topdir, name) + # don't access files outside topdir + if not is_file_into_dir(dst, topdir): + continue + if os.path.isdir(dst): + # assume the file was de-symlinked + continue + + # build src path and do some basic validation + with open(os.path.join(topdir, dst), 'r') as f: + text = f.read() + dst_dir = os.path.dirname(dst) + try: + src = os.path.normpath(os.path.join(dst_dir, text)) + if not os.path.exists(src): + # assume the file was de-symlinked before continue - dst_dir_relpath = os.path.dirname(os.path.relpath(filename, dst)) - path = os.path.normpath(os.path.join(src, dst_dir_relpath, text)) - if not os.path.exists(path): + # don't access files outside topdir + if not is_file_into_dir(src, topdir): continue - # most probably it is a git symlinked file + except Exception: + # assume the file was de-symlinked before + continue + + # copy src to dst + try: + if os.path.isdir(src): + os.unlink(dst) + shutil.copytree(src, dst) + else: + shutil.copy2(src, dst) + except Exception: + failures += 1 + print("*** copy failed for") + print("\t src:", src) + print("\t dst:", dst) - # copy original content to filename - shutil.copy(path, filename) + return failures |
