nix-channels: Split argument list in script

This commit is contained in:
dramforever 2020-03-03 14:07:05 +08:00 committed by GitHub
parent ce612f6cbb
commit 00a82c5e4e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -258,7 +258,56 @@ def clone_channels():
return channels_to_update return channels_to_update
def make_xargs():
arg_max = int(subprocess.run(
[ 'getconf', 'ARG_MAX' ],
stdout=subprocess.PIPE
).stdout)
env_size = sum(
len(k.encode()) + len(v.encode()) + 2
for k, v in os.environ.items()
)
# Subtract 1024 to be safe safe
usable = arg_max - env_size - 1024
logging.info(f'- mk_xargs: Usable command line bytes: {usable}')
def check_run(args):
global failure
p = subprocess.run(args)
if p.returncode != 0:
logging.info(f' - Subprocess failed with code {p.returncode}')
failure = True
def xargs(common, args):
common = [ a.encode() if isinstance(a, str) else a for a in common ]
args = [ a.encode() if isinstance(a, str) else a for a in args ]
common_size = sum(len(a) + 1 for a in common)
buf, cur_size = [], common_size
for a in args:
size = len(a) + 1
if cur_size + size > usable:
check_run(common + buf)
buf, cur_size = [], common_size
buf.append(a)
cur_size += size
assert cur_size <= usable, f'Argument {a[:50]}... will never fit'
if buf:
check_run(common + buf)
return xargs
def update_channels(channels): def update_channels(channels):
xargs = make_xargs()
logging.info(f'- Updating binary cache') logging.info(f'- Updating binary cache')
has_cache_info = False has_cache_info = False
@ -287,31 +336,17 @@ def update_channels(channels):
logging.info(f' - {len(paths)} paths listed') logging.info(f' - {len(paths)} paths listed')
# xargs can splits up the argument lists and invokes nix copy multiple xargs(
# times to avoid E2BIG (Argument list too long) [
nix_process = subprocess.Popen( 'nix', 'copy',
[ 'xargs', 'nix', 'copy',
'--from', upstream_binary_cache, '--from', upstream_binary_cache,
'--to', nix_store_dest, '--to', nix_store_dest,
'--verbose' '--verbose'
], ],
universal_newlines=True, paths
stdin=subprocess.PIPE
) )
for path in paths: logging.info(f' - Finished')
nix_process.stdin.write(path.decode() + '\n')
retcode = nix_process.wait()
if retcode == 0:
chan_path_update.rename(working_dir / channel)
logging.info(f' - Done')
else:
global failure
failure = True
logging.info(f' - nix copy failed')
if __name__ == '__main__': if __name__ == '__main__':
channels = clone_channels() channels = clone_channels()