fix: @@homebrew@@ placeholder replacement
This commit is contained in:
11
README.md
11
README.md
@@ -12,13 +12,22 @@ see [usage](#usage) below.
|
||||
Copy `brew.py` to anywhere, where it can be found by your shell.
|
||||
Or add a new path to your `$PATH`.
|
||||
|
||||
In your shell config (e.g., `.zprofile`) add
|
||||
In your shell config (e.g., `.zprofile` or `.bash_profile`) add
|
||||
|
||||
```sh
|
||||
export BREW_PY_CELLAR=$HOME/any/path/you/like
|
||||
```
|
||||
|
||||
|
||||
Some packages use hard-coded path prefixes (e.g. Python).
|
||||
For these, you need to create a symlink:
|
||||
|
||||
```sh
|
||||
sudo mkdir -p /opt/homebrew
|
||||
sudo ln -s $BREW_PY_CELLAR/cellar /opt/homebrew/Cellar
|
||||
```
|
||||
|
||||
|
||||
## FAQ
|
||||
|
||||
### Why this project?
|
||||
|
||||
91
brew.py
91
brew.py
@@ -1883,6 +1883,9 @@ class Fixer:
|
||||
|
||||
if File.isMachO(fname):
|
||||
Dylib(fname).fix()
|
||||
else:
|
||||
# replace all @@homebrew@@ placeholders
|
||||
Fixer.inreplace(fname)
|
||||
|
||||
@staticmethod
|
||||
def symlink(fname: str) -> None:
|
||||
@@ -1893,6 +1896,94 @@ class Fixer:
|
||||
mtime = os.path.getmtime(fname)
|
||||
os.utime(fname, (atime, mtime), follow_symlinks=False)
|
||||
|
||||
@staticmethod
|
||||
def inreplace(fname: str) -> None:
|
||||
# check if file contains any homebrew prefix placeholders
|
||||
matches = Fixer._read_placeholders_location(fname)
|
||||
if not matches:
|
||||
return
|
||||
|
||||
Log.debug(' replace placeholders in', fname)
|
||||
# check that we dont miss any placeholder
|
||||
for pos, match in matches:
|
||||
if match not in Fixer.INREPLACE_DICT:
|
||||
Log.error('missed placeholder', match, 'in', fname,
|
||||
summary=True)
|
||||
|
||||
# if yes, replace all placeholders
|
||||
tmp_tgt = fname + '.brew-repl'
|
||||
Fixer._write_placeholders_replace(matches, fname, tmp_tgt)
|
||||
|
||||
# replace original file and restore file flags
|
||||
shutil.copystat(fname, tmp_tgt)
|
||||
st = os.stat(fname)
|
||||
os.chown(tmp_tgt, st.st_uid, st.st_gid)
|
||||
os.rename(tmp_tgt, fname)
|
||||
|
||||
PlaceholderMatches = list[tuple[int, bytes]]
|
||||
|
||||
@staticmethod
|
||||
def _read_placeholders_location(fname: str) -> PlaceholderMatches:
|
||||
''' Returns list of `(pos, b'@@PLACEHOLDER@@')` '''
|
||||
CHUNK_SIZE = 4096
|
||||
# file_size = 0
|
||||
needle = b'@@HOMEBREW_'
|
||||
rv = []
|
||||
with open(fname, 'rb') as fp:
|
||||
fp.seek(0)
|
||||
while True:
|
||||
chunk = fp.read(CHUNK_SIZE)
|
||||
if len(chunk) == 0:
|
||||
# file_size = fp.tell()
|
||||
break
|
||||
|
||||
if needle not in chunk:
|
||||
continue
|
||||
|
||||
idx = chunk.index(needle)
|
||||
if idx > CHUNK_SIZE - 30:
|
||||
fp.seek(-30, 1) # relative to current pos
|
||||
continue
|
||||
|
||||
suffix = chunk[idx + 2:idx + 30]
|
||||
if b'@@' in suffix:
|
||||
end = idx + 2 + suffix.index(b'@@') + 2
|
||||
fp_idx = fp.tell() - len(chunk) + idx
|
||||
rv.append((fp_idx, chunk[idx:end]))
|
||||
fp.seek(- len(chunk) + end, 1) # relative to current pos
|
||||
continue
|
||||
|
||||
fp.seek(- len(chunk) + idx + len(needle), 1)
|
||||
return rv
|
||||
|
||||
@staticmethod
|
||||
def _write_placeholders_replace(
|
||||
matches: PlaceholderMatches, src: str, dst: str
|
||||
) -> None:
|
||||
''' Apply changes to new file by replacing placeholders with value '''
|
||||
CHUNK_SIZE = 4096
|
||||
# this is easier than adding a special case to read until EOF
|
||||
matches.append((99 ** 9, b''))
|
||||
prev = 0
|
||||
with open(src, 'rb') as fpr:
|
||||
with open(dst, 'wb') as fpw:
|
||||
for pos, match in matches:
|
||||
while prev + CHUNK_SIZE < pos:
|
||||
change = fpw.write(fpr.read(CHUNK_SIZE))
|
||||
if change == 0:
|
||||
return
|
||||
prev += change
|
||||
fpw.write(fpr.read(pos - prev))
|
||||
fpr.seek(pos + len(match))
|
||||
prev = fpr.tell()
|
||||
fpw.write(Fixer.INREPLACE_DICT[match])
|
||||
|
||||
INREPLACE_DICT = {
|
||||
b'@@HOMEBREW_PREFIX@@': Cellar.ROOT.encode('utf8'),
|
||||
b'@@HOMEBREW_CELLAR@@': Cellar.CELLAR.encode('utf8'),
|
||||
b'@@HOMEBREW_LIBRARY@@': Cellar.ROOT.encode('utf8') + b'/Library',
|
||||
}
|
||||
|
||||
|
||||
# -----------------------------------
|
||||
# Dylib
|
||||
|
||||
Reference in New Issue
Block a user