summaryrefslogtreecommitdiff
path: root/bin/just-lock.py
diff options
context:
space:
mode:
Diffstat (limited to 'bin/just-lock.py')
-rwxr-xr-xbin/just-lock.py106
1 files changed, 101 insertions, 5 deletions
diff --git a/bin/just-lock.py b/bin/just-lock.py
index 3cc6659d..997f058f 100755
--- a/bin/just-lock.py
+++ b/bin/just-lock.py
@@ -70,6 +70,12 @@ GIT_NOBODY_ENV: Dict[str, str] = {
"GIT_CONFIG_SYSTEM": "/dev/null",
}
+SPECIAL_PRAGMA_TO_CAS_RESOLVE_MAP: Dict[str, str] = {
+ "ignore": "ignore",
+ "resolve-partially": "tree-upwards",
+ "resolve-completely": "tree-all"
+}
+
class ObjectType(Enum):
FILE = 1
@@ -2074,6 +2080,96 @@ def clone_repo(repos: Json, known_repo: str, deps_chain: List[str],
("\n".join(["\t%s" % (x, ) for x in sources]), ))
return commit
+ def process_archive(repository: Json, repo_type: str, *, clone_to: str,
+ fail_context: str) -> str:
+ """Process an archive-like repository and return its content id."""
+ # Parse entries not covered in fetch method to check for early fail
+ subdir: Optional[str] = repository.get("subdir", None)
+ if subdir is not None:
+ if not isinstance(subdir, str):
+ fail(
+ fail_context +
+ "Expected field \"subdir\" to be a string, but found:\n%r" %
+ (json.dumps(subdir, indent=2), ))
+ subdir = os.path.normpath(subdir)
+ if os.path.isabs(subdir) or subdir.startswith(".."):
+ fail(
+ fail_context +
+ "Expected field \"subdir\" to be a relative non-upward path, but found:\n%r"
+ % (json.dumps(subdir, indent=2), ))
+ if subdir == ".":
+ subdir = None # treat as if missing
+ # Fetch the archive
+ content = archive_fetch_with_parse(repository,
+ fail_context=fail_context)
+ # Stage the content; first resolve special entries, if needed, then keep
+ # the relevant subdir, if given
+ special_pragma: Optional[str] = repository.get("pragma",
+ {}).get("special", None)
+
+ if (special_pragma not in SPECIAL_PRAGMA_TO_CAS_RESOLVE_MAP.keys()
+ and subdir is None):
+ # Unpack directly to clone location
+ unpack_archive(content,
+ archive_type=repo_type,
+ unpack_to=clone_to,
+ fail_context=fail_context)
+ else:
+ # Unpack to a temporary dir
+ workdir: str = create_tmp_dir(type="archive-unpack")
+ srcdir: str = os.path.join(workdir, "src")
+ unpack_archive(content,
+ archive_type=repo_type,
+ unpack_to=srcdir,
+ fail_context=fail_context)
+
+ move_from_dir: str = srcdir
+ if (special_pragma is not None and special_pragma
+ in SPECIAL_PRAGMA_TO_CAS_RESOLVE_MAP.keys()):
+ # Resolve the tree according to the pragma
+ resolve_special_arg = SPECIAL_PRAGMA_TO_CAS_RESOLVE_MAP[
+ special_pragma]
+ resolved_tree = run_cmd(
+ g_LAUNCHER + [
+ g_JUST, "add-to-cas", "--local-build-root", g_ROOT,
+ "--resolve-special=%s" % resolve_special_arg, srcdir
+ ],
+ cwd=workdir,
+ stdout=subprocess.PIPE,
+ fail_context=fail_context)[0].decode('utf-8').strip()
+ # Stage the resolved tree
+ resolved_dir: str = os.path.join(workdir, "resolved")
+ subdir_args: List[str] = []
+ if subdir is not None:
+ subdir_args = ["-P", subdir]
+ run_cmd(g_LAUNCHER + [
+ g_JUST, "install-cas", "--local-build-root", g_ROOT,
+ "%s::t" % resolved_tree, "-o", resolved_dir
+ ] + subdir_args,
+ cwd=workdir,
+ fail_context=fail_context)
+ move_from_dir = resolved_dir
+ else:
+ # Subdir is not None, so keep only that subdirectory
+ move_from_dir = os.path.join(move_from_dir, cast(str, subdir))
+
+ # Do the move into clone directory
+ os.makedirs(clone_to, exist_ok=True)
+ for entry in os.listdir(move_from_dir):
+ # shutil.move uses os.rename if on same filesystem or
+ # shutil.copy2 otherwise, which preserves file metadata
+ # and uses hardlinks if supported by the OS
+ try:
+ shutil.move(os.path.join(move_from_dir, entry), clone_to)
+ except Exception as ex:
+ fail(fail_context + "Moving file path %s failed with:\n%r" %
+ (os.path.join(move_from_dir, entry), ex))
+
+ # Clean up tmp dir
+ try_rmtree(workdir)
+
+ return content
+
def follow_binding(repos: Json, *, repo_name: str, dep_name: str,
fail_context: str) -> str:
"""Follow a named binding."""
@@ -2136,11 +2232,11 @@ def clone_repo(repos: Json, known_repo: str, deps_chain: List[str],
report("\tCloned Git commit %s to %s" % (commit, clone_to))
elif repo_type in ["archive", "zip"]:
- #TODO(psarbu): Implement archives cloning
- warn(fail_context +
- "Cloning from \"%s\" repositories not yet implemented!" %
- (repo_type, ))
- result = None
+ content = process_archive(repository,
+ repo_type,
+ clone_to=clone_to,
+ fail_context=fail_context)
+ report("\tCloned archive-like content %s to %s" % (content, clone_to))
elif repo_type == "foreign file":
#TODO(psarbu): Implement foreign file cloning