npm_workspace.py 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. import os
  2. import json
  3. class NpmWorkspace(object):
  4. @classmethod
  5. def load(cls, path):
  6. ws = cls(path)
  7. ws.read()
  8. return ws
  9. def __init__(self, path):
  10. if not os.path.isabs(path):
  11. raise TypeError("Absolute path required, given: {}".format(path))
  12. self.path = path
  13. # NOTE: pnpm requires relative workspace paths.
  14. self.packages = set()
  15. def read(self):
  16. with open(self.path) as f:
  17. parsed = json.load(f) or {}
  18. self.packages = set(parsed.get("workspaces", []))
  19. def write(self, path=None):
  20. if not path:
  21. path = self.path
  22. with open(path, "w") as f:
  23. data = {
  24. "workspaces": list(self.packages),
  25. }
  26. json.dump(data, f, indent=2)
  27. def get_paths(self, base_path=None, ignore_self=False):
  28. """
  29. Returns absolute paths of the workspace packages.
  30. :param base_path: base path to resolve relative dep paths
  31. :type base_path: str
  32. :param ignore_self: whether path of the current module will be excluded (if present)
  33. :type ignore_self: bool
  34. :rtype: list of str
  35. """
  36. if base_path is None:
  37. base_path = os.path.dirname(self.path)
  38. return [
  39. os.path.normpath(os.path.join(base_path, pkg_path))
  40. for pkg_path in self.packages
  41. if not ignore_self or pkg_path != "."
  42. ]
  43. def set_from_package_json(self, package_json):
  44. """
  45. Sets packages to "workspace" deps from given package.json.
  46. :param package_json: package.json of workspace
  47. :type package_json: PackageJson
  48. """
  49. if os.path.dirname(package_json.path) != os.path.dirname(self.path):
  50. raise TypeError(
  51. "package.json should be in workspace directory {}, given: {}".format(
  52. os.path.dirname(self.path), package_json.path
  53. )
  54. )
  55. self.packages = set(path for _, path in package_json.get_workspace_dep_spec_paths())
  56. def merge(self, ws):
  57. # type: (NpmWorkspace) -> None
  58. """
  59. Adds `ws`'s packages to the workspace.
  60. :param ws: workspace to merge
  61. """
  62. dir_path = os.path.dirname(self.path)
  63. ws_dir_path = os.path.dirname(ws.path)
  64. for p_rel_path in ws.packages:
  65. p_path = os.path.normpath(os.path.join(ws_dir_path, p_rel_path))
  66. self.packages.add(os.path.relpath(p_path, dir_path))