Example #1
0
def parse_binding(ctx, line_num, line):
  words = line.split()
  if not words: return
  cmd = words[0]
  if cmd not in ctx.all_cmds:
    errFL('warning: {}: unknown command: {}', line_num, cmd)
  try:
    when_index = words.index('when')
  except ValueError:
    keys = words[1:]
    whens = []
  else:
    keys = words[1:when_index]
    whens= words[when_index+1:]
  ctx.bound_cmds.add(cmd)
  if not keys: return
  validate_keys(line_num, keys)
  binding = {
    'command': cmd,
    'key': ' '.join(keys)
  }
  if whens:
    validate_whens(ctx, line_num, whens)
    binding['when'] = ' '.join(whens)
  ctx.bindings.append(binding)
Example #2
0
File: __init__.py Project: gwk/muck
def load(target_path, ext=None, **kwargs):
  '''
  Select an appropriate loader based on the file extension, or `ext` if specified.

  If a loader is found, then `open_dep` is called with the default `open_dep_kwargs` registered by `add_loader`,
  except updated by any values with matching keys in `kwargs`.
  The remaining `kwargs` are passed to the loader function registered by `add_loader`.
  Thus, keyword arguments passed to `load` get divvied up between `open_dep` and the custom load function.

  If no loader is found, raise an error.

  Muck's static analysis looks specifically for this function to infer dependencies;
  `target_path` must be a string literal.
  '''
  if ext is None:
    ext = path_ext(target_path)
  elif not isinstance(ext, str): raise TypeError(ext)
  try: load_fn, std_open_args = _loaders[ext]
  except KeyError:
    errFL('ERROR: No loader found for target: {!r}', target_path)
    errFL('NOTE: extension: {!r}', ext)
    raise
  open_args = std_open_args.copy()
  # transfer all matching kwargs to open_args.
  for k in _open_deps_parameters:
    try: v = kwargs[k]
    except KeyError: continue
    open_args[k] = v
    del kwargs[k] # only pass this arg to open_deps; del is safe because kwargs has local lifetime.
  file = open_dep(target_path, **open_args)
  return load_fn(file, **kwargs)
Example #3
0
File: __main__.py Project: gwk/muck
def muck_patch(ctx, args):

  if not len(args) in (1, 2):
    failF('''\
muck patch error: patch command takes one or two arguments. usage:

  muck patch [original_target] [target]
    creates a new target by copying either the source or product of the original to _build/[target],
    and then creates an empty [target].pat.

  muck patch [target.pat]
    update the patch file with the diff of the previously specified original and target.
''')

  if len(args) == 2: # create new patch.
    orig_target_path, target_path = args
    if orig_target_path.endswith('.pat'):
      errFL('muck patch error: original should not be a patch file: {}', orig_target_path)
    if target_path.endswith('.pat'):
      errFL('muck patch error: {} {}: target should not be a patch file: {}', target_path)
    patch_path = target_path + '.pat'
    if path_exists(patch_path):
      failF('muck patch error: {}: patch already exists.', patch_path)
    update_dependency(ctx, orig_target_path, dependent=None)
    orig_path = actual_path_for_target(orig_target_path)
    prod_path = product_path_for_target(target_path)
    if path_exists(prod_path):
      errFL('muck patch note: product already exists: {}', prod_path)
    else:
      errFL('muck patch note: copying original to product: {} -> {}', orig_path, prod_path)
      copy_file(orig_path, prod_path)

  else: # update existing patch.
    patch_path = args[0]
    if path_ext(patch_path) != '.pat':
      failF('muck patch error: argument does not specify a .pat file: {!r}', patch_path)
    deps = pat_dependencies(patch_path, open(patch_path), {})
    orig_target_path = deps[0]
    update_dependency(ctx, orig_target_path, dependent=None)
    orig_path = actual_path_for_target(orig_target_path)
    target_path = path_stem(patch_path)
    prod_path = product_path_for_target(target_path)

  # update patch (both cases).
  patch_path_tmp = patch_path + tmp_ext
  cmd = ['pat', 'diff', orig_path, prod_path]
  errFL('muck patch note: diffing: `{}`', ' '.join(shlex.quote(w) for w in cmd))
  with open(patch_path_tmp, 'wb') as f:
    code = runC(cmd, out=f)
  move_file(patch_path_tmp, patch_path, overwrite=True)

  if len(args) == 1: # updated existing patch.
    # need to remove or update the target record to avoid the 'did you mean to patch?' safeguard.
    # for now, just delete it to be safe; this makes the target look stale.
    try:
      ctx.db.delete_record(target_path=target_path)
    except KeyError: pass
Example #4
0
File: __main__.py Project: gwk/muck
def muck_clean(ctx, args):
  '''
  `muck clean` command.
  '''
  if not args:
    failF('muck clean error: clean command takes specific target arguments; use clean-all to remove all products.')
  for target in args:
    if not ctx.db.contains_record(target_path=target):
      errFL('muck clean note: {}: skipping unknown target.', target)
      continue
    prod_path = product_path_for_target(target)
    remove_file_if_exists(prod_path)
    ctx.db.delete_record(target_path=target)
Example #5
0
File: __init__.py Project: gwk/muck
def open_dep(target_path, binary=False, buffering=-1, encoding=None, errors=None, newline=None):
  '''
  Open a dependency for reading.

  Muck's static analysis looks specifically for this function to infer dependencies;
  `target_path` must be a string literal.
  '''
  path = actual_path_for_target(target_path)
  try:
    return open(path, mode=('rb' if binary else 'r'), buffering=buffering, encoding=encoding, errors=errors, newline=newline)
  except FileNotFoundError:
    errFL('muck.open_dep cannot open path: {}', path)
    if path != target_path:
      errFL('note: nor does a file exist at source path: {}', target_path)
    raise
Example #6
0
File: __init__.py Project: gwk/muck
def fetch(url, expected_status_code=200, headers={}, timeout=4, delay=0, delay_range=0):
  "Fetch the data at `url` and save it to a path in the '_fetch' directory derived from the URL."
  path = path_join('_fetch', path_for_url(url))
  if not path_exists(path):
    errFL('fetch: {}', url)
    r = _fetch(url, timeout, headers, expected_status_code)
    make_dirs(path_dir(path))
    with open(path, 'wb') as f:
      f.write(r.content)
    sleep_min = delay - delay_range * 0.5
    sleep_max = delay + delay_range * 0.5
    sleep_time = random.uniform(sleep_min, sleep_max)
    if sleep_time > 0:
      time.sleep(sleep_time)
  return path
Example #7
0
#!/usr/bin/env python3
# Dedicated to the public domain under CC0: https://creativecommons.org/publicdomain/zero/1.0/.

from sys import argv, stdin, stdout
from json import JSONDecoder, dump

from pithy.io import errFL


if len(argv) > 2:
  exit('requires 1 or no arguments (defaults to std-in)')

if len(argv) == 2:
  f = open(argv[1])
else:
  f = stdin

s = f.read()
o, end_index = JSONDecoder(strict=False).raw_decode(s)

dump(o, stdout, sort_keys=True, indent=2)
stdout.write('\n')

if end_index < len(s):
  tail = '…' if end_index + 64 < len(s) else ''
  errFL('extraneous input beginning at offset {}:\n{}{}\n',
    end_index, s[end_index:end_index + 64].encode('utf8'), tail)
Example #8
0
File: __main__.py Project: gwk/muck
def failF(path, fmt, *items):
  errF('muck error: {}: ', path)
  errFL(fmt, *items)
  exit(1)
Example #9
0
File: __main__.py Project: gwk/muck
def warnF(path, fmt, *items):
  errF('muck WARNING: {}: ', path)
  errFL(fmt, *items)
Example #10
0
File: __main__.py Project: gwk/muck
def noteF(path, fmt, *items):
  errF('muck note: {}: ', path)
  errFL(fmt, *items)
Example #11
0
File: __main__.py Project: gwk/muck
 def dbgF(path, fmt, *items):
   errFL('muck dbg: {}: ' + fmt, path, *items)