Skip to content
This repository was archived by the owner on Dec 19, 2020. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions lib/wit/dependency.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def __eq__(self, other):
def infer_name(source):
return Path(source).name.replace('.git', '')

# NB: mutates packages[self.name]
# NB: mutates packages!
def load(self, packages, repo_paths, wsroot, download):
if self.name in packages:
self.package = packages[self.name]
Expand Down Expand Up @@ -131,12 +131,18 @@ def get_id(self):
return "dep_"+re.sub(r"([^\w\d])", "_", self.tag())

def crawl_dep_tree(self, wsroot, repo_paths, packages):
fancy_tag = "{}::{}".format(self.name, self.short_revision())
self.load(packages, repo_paths, wsroot, False)
fancy_tag = "{}::{}".format(self.name, self.short_revision())
if self.package.repo is None:
return {'': "{} \033[91m(missing)\033[m".format(fancy_tag)}
if self.package.revision != self.resolved_rev():
fancy_tag += "->{}".format(self.package.short_revision())

different_name = self.package.name != self.name
if self.package.revision != self.resolved_rev() or different_name:
if different_name:
replacement = self.package.tag()
else:
replacement = self.package.short_revision()
fancy_tag += " -> {}".format(replacement)
return {'': fancy_tag}

tree = {'': fancy_tag}
Expand Down
2 changes: 1 addition & 1 deletion lib/wit/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ def add_dep(ws, args) -> None:
if manifest_path.exists():
manifest = Manifest.read_manifest(manifest_path)
else:
manifest = Manifest([])
manifest = Manifest([], [])

# make sure the dependency is not already in the cwd's manifest
if manifest.contains_dependency(req_dep.name):
Expand Down
18 changes: 14 additions & 4 deletions lib/wit/manifest.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/env python3

import json
import collections
from pathlib import Path
from .witlogger import getLogger

Expand All @@ -15,8 +16,9 @@ class Manifest:
Common class for the description of package dependencies and a workspace
"""

def __init__(self, dependencies):
def __init__(self, dependencies, replaces):
self.dependencies = dependencies
self.replaces = replaces

def get_dependency(self, name: str):
for d in self.dependencies:
Expand Down Expand Up @@ -58,16 +60,24 @@ def write(self, path):
@staticmethod
def read_manifest(path, safe=False):
if safe and not Path(path).exists():
return Manifest([])
return Manifest([], [])
content = json.loads(path.read_text())
return Manifest.process_manifest(content)

@staticmethod
def process_manifest(json_content):
replaces = []
if isinstance(json_content, collections.Mapping):
if 'replaces' in json_content:
replaces = json_content['replaces']
dep_specs = json_content['dependencies']
else:
dep_specs = json_content

# import here to prevent circular dependency
from .dependency import manifest_item_to_dep
dependencies = [manifest_item_to_dep(x) for x in json_content]
return Manifest(dependencies)
dependencies = [manifest_item_to_dep(x) for x in dep_specs]
return Manifest(dependencies, replaces)


if __name__ == '__main__':
Expand Down
1 change: 1 addition & 0 deletions lib/wit/package.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ def __init__(self, name, repo_paths):

self.repo = None
self.dependents = []
self.replaces = []

def set_source(self, source):
self.source = self.resolve_source(source)
Expand Down
38 changes: 36 additions & 2 deletions lib/wit/workspace.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def create(cls, name, repo_paths):
shutil.rmtree(str(dotwit))
dotwit.mkdir()

manifest = Manifest([])
manifest = Manifest([], [])
manifest.write(manifest_path)

lockfile = LockFile([])
Expand Down Expand Up @@ -160,6 +160,32 @@ def resolve(self, download=False):
source_map, packages, queue, errors = \
dep.resolve_deps(self.root, self.repo_paths, download,
source_map, packages, queue, errors)

replaces_map = {}
for name in packages:
pkg = packages[name]
if pkg.repo:
replaces_map[name] = pkg.repo.read_manifest_from_commit(pkg.revision).replaces
for parent_name in replaces_map:
parent = packages[parent_name]
child_names = replaces_map[parent_name]
if len(child_names) > 0:
for child_name in child_names:
if child_name not in packages:
log.debug("Did not find replaced child {}".format(child_name))
continue
replaced = packages[child_name]
if not parent.repo.is_ancestor(replaced.revision, parent.revision):
error("I refuse to replace package '{}' with '{}' because \n"
"{} is not a git ancestor of {}".format(child_name, parent_name,
replaced.tag(), parent.tag()))
log.debug("Replacing {} with {}".format(child_name, parent_name))
for dependent in replaced.dependents:
dependent.package = parent
parent.add_dependent(dependent)

packages[child_name] = parent

return packages, errors

@passbyval
Expand All @@ -180,7 +206,15 @@ def resolve_deps(self, wsroot, repo_paths, download, source_map, packages, queue

def checkout(self, packages):
lock_packages = []
for name in packages:

for orig_name in packages:
pkg = packages[orig_name]
if orig_name != pkg.name and (self.root/orig_name).exists():
log.warn("Package '{}' has been replaced by '{}', but the folder of '{}' still "
"exists".format(orig_name, pkg.name, orig_name))
package_names = [packages[orig_name].name for orig_name in packages]
package_names = list(set(package_names))
for name in package_names:
package = packages[name]
package.checkout(self.root)
lock_packages.append(package)
Expand Down
53 changes: 53 additions & 0 deletions t/manifest_replaces.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#!/bin/sh

. $(dirname $0)/regress_util.sh

prereq "on"

# Set up repo foo
make_repo 'foo'
foo_commit=$(git -C foo rev-parse HEAD)

cp -r foo newdir

touch newdir/xyz
cat << EOF | jq . > newdir/wit-manifest.json
{
"name": "foo-newname",
"replaces": ["foo"],
"dependencies": []
}
EOF
git -C newdir add -A
git -C newdir commit -m "rename to foo-newdir"
foo_newname_commit=$(git -C newdir rev-parse HEAD)

# Now set up repo main_repo to depend on foo, foo2, foo3
mkdir main_repo
git -C main_repo init

cat << EOF | jq . > main_repo/wit-manifest.json
[
{ "commit": "$foo_commit", "name": "foo", "source": "$PWD/foo" },
{ "commit": "$foo_newname_commit", "name": "foo-newname", "source": "$PWD/newdir" }
]
EOF

git -C main_repo add -A
git -C main_repo commit -m "commit1"
main_repo_commit=$(git -C main_repo rev-parse HEAD)

prereq "off"

# Now create a workspace from main_repo
wit init myws -a $PWD/main_repo

# Should fail because of conflicting paths for foo
check "wit init with conflicting paths passes" [ $? -eq 0 ]


wit --repo-path="$PWD $PWD/newdir $PWD/newdir2" init myws2 -a $PWD/main_repo
check "wit with path set succeeds" [ $? -eq 0 ]

report
finish