IF YOU WOULD LIKE TO GET AN ACCOUNT, please write an email to s dot adaszewski at gmail dot com. User accounts are meant only to report issues and/or generate pull requests. This is a purpose-specific Git hosting for ADARED projects. Thank you for your understanding!
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

81 lines
2.6KB

  1. #
  2. # Copyright (C) Stanislaw Adaszewski, 2020
  3. # License: GNU General Public License v3.0
  4. # URL: https://github.com/sadaszewski/focker
  5. # URL: https://adared.ch/focker
  6. #
  7. import hashlib
  8. import json
  9. from .jail import jail_run
  10. import shutil
  11. import os
  12. import shlex
  13. from .misc import filehash
  14. class RunStep(object):
  15. def __init__(self, spec):
  16. if not isinstance(spec, list) and \
  17. not isinstance(spec, str):
  18. raise ValueError('Run spec must be a list or a string')
  19. self.spec = spec
  20. def hash(self, base, **kwargs):
  21. res = hashlib.sha256(
  22. json.dumps(( base, self.spec ))
  23. .encode('utf-8')).hexdigest()
  24. return res
  25. def execute(self, path, **kwargs):
  26. spec = self.spec
  27. if isinstance(spec, list):
  28. spec = ' && ' .join(self.spec)
  29. jail_run(path, spec)
  30. class CopyStep(object):
  31. def __init__(self, spec):
  32. if not isinstance(spec, list):
  33. raise ValueError('CopyStep spec should be a list')
  34. self.spec = spec
  35. def hash(self, base, args, **kwargs):
  36. if len(self.spec) == 0:
  37. fh = []
  38. elif isinstance(self.spec[0], list):
  39. fh = list(map(lambda a: filehash(os.path.join(args.focker_dir, a[0])), self.spec))
  40. else:
  41. fh = [ filehash(os.path.join(args.focker_dir, self.spec[0])) ]
  42. res = hashlib.sha256(
  43. json.dumps(( base, fh, self.spec ))
  44. .encode('utf-8')).hexdigest()
  45. return res
  46. def execute(self, path, **kwargs):
  47. lst = [ self.spec ] \
  48. if not isinstance(self.spec[0], list) \
  49. else self.spec
  50. for entry in lst:
  51. (source, target) = entry[:2]
  52. options = entry[2] if len(entry) > 2 else {}
  53. target = target.strip('/')
  54. os.makedirs(os.path.split(os.path.join(path, target))[0], exist_ok=True)
  55. shutil.copyfile(os.path.join(kwargs['args'].focker_dir, source),
  56. os.path.join(path, target))
  57. if 'chmod' in options:
  58. os.chmod(os.path.join(path, target), options['chmod'])
  59. if 'chown' in options:
  60. uid, gid = options['chown'].split(':').map(int)
  61. os.chown(os.path.join(path, target), uid, gid)
  62. def create_step(spec):
  63. if not isinstance(spec, dict):
  64. raise ValueError('Step specification must be a dictionary')
  65. if 'copy' in spec:
  66. return CopyStep(spec['copy'])
  67. elif 'run' in spec:
  68. return RunStep(spec['run'])
  69. raise ValueError('Unrecognized step spec: ' + json.dumps(spec))