From 7c9ecd3f4de81e24fbb8e8e4177b37d6822297a5 Mon Sep 17 00:00:00 2001 From: Andy Davidoff Date: Sun, 15 Dec 2019 23:05:54 -0500 Subject: [PATCH] closes #69, fixes #70; auto-rolls and path repairs --- src/nimph.nim | 52 ++++++++++++++++++------ src/nimph/project.nim | 93 ++++++++++++++++++++++++------------------- 2 files changed, 93 insertions(+), 52 deletions(-) diff --git a/src/nimph.nim b/src/nimph.nim index 36ce30c..4bccd77 100644 --- a/src/nimph.nim +++ b/src/nimph.nim @@ -353,7 +353,9 @@ proc cloner*(args: seq[string]; log_level = logLevel; dry_run = false): int = if args.len == 0: crash &"provide a single url, or a github search query" - elif args.len == 1: + + # if only one argument was supplied, see if we can parse it as a url + if args.len == 1: try: let uri = parseUri(args[0]) @@ -366,33 +368,59 @@ proc cloner*(args: seq[string]; log_level = logLevel; dry_run = false): int = var project: Project setupLocalProject(project) + # if the input wasn't parsed to a url, if not url.isValid: + # search github using the input as a query let query {.used.} = args.join(" ") - group = waitfor searchHub(args) - if group.isNone: + hubs = waitfor searchHub(args) + if hubs.isNone: crash &"unable to retrieve search results from github" - var - repository: HubResult + # and pluck the first result, presumed to be the best block found: - for repos in group.get.values: - repository = repos - url = repository.git - name = repository.name + for repo in hubs.get.values: + url = repo.git + name = repo.name break found crash &"unable to find a package matching `{query}`" + # if we STILL don't have a url, we're done if not url.isValid: crash &"unable to determine a valid url to clone" + # perform the clone var cloned: Project if not project.clone(url, name, cloned): - crash &"unable to clone {url}" + crash &"problem cloning {url}" + + # reset our paths to, hopefully, grab the new project + project.cfg = loadAllCfgs(project.repo) - # rename the directory to match head release - project.relocateDependency(cloned) + # setup our dependency group + var group = project.newDependencyGroup(flags = {Flag.Quiet}) + if not project.resolve(group): + notice &"unable to resolve all dependencies for {project}" + + # see if we can find this project in the dependencies + let needed = group.projectForPath(cloned.repo) + + # if it's in there, let's get its requirement and roll to meet it + block relocated: + if needed.isSome: + let requirement = group.reqForProject(cloned) + if requirement.isNone: + warn &"unable to retrieve requirement for {cloned.name}" + else: + # rollTowards will relocate us, too + if cloned.rollTowards(requirement.get): + notice &"rolled {cloned.name} to {cloned.version}" + # so skip the tail of this block (and a 2nd relocate) + break relocated + notice &"unable to meet {requirement} with {cloned}" + # rename the directory to match head release + project.relocateDependency(cloned) # try to point it at github if it looks like it's our repo if not cloned.promote: diff --git a/src/nimph/project.nim b/src/nimph/project.nim index bccfed4..bcb51d1 100644 --- a/src/nimph/project.nim +++ b/src/nimph/project.nim @@ -199,28 +199,28 @@ proc fetchDump*(project: var Project; refresh = false): bool {.discardable.} = proc knowVersion*(project: var Project): Version = ## pull out all the stops to determine the version of a project - if project.dump != nil: - if "version" in project.dump: - let - text {.used.} = project.dump["version"] - parsed = parseVersionLoosely(text) - if parsed.isSome: - when defined(debug): - debug "parsed a version from `nimble dump`" + block: + # this is really the most likely to work, so start with a dump + if project.dump != nil: + if "version" in project.dump: + let + text = project.dump["version"] + parsed = parseVersionLoosely(text) + if parsed.isNone: + let emsg = &"unparsable version `{text}` in {project.name}" # noqa + raise newException(IOError, emsg) result = parsed.get.version - else: - let emsg = &"unparsable version `{text}` in {project.name}" # noqa - raise newException(IOError, emsg) - return - result = project.guessVersion - if result.isValid: - when defined(debug): - debug &"parsed a version from {project.nimble}" - return - if project.fetchDump(): - result = project.knowVersion - return - raise newException(IOError, "unable to determine {project.package} version") + break + + # we don't have a dump to work with, or the dump has no version in it + result = project.guessVersion + if not result.isValid: + # that was a bad guess; if we have no dump, recurse on the dump + if project.dump == nil and project.fetchDump: + result = project.knowVersion + + if not result.isValid: + raise newException(IOError, "unable to determine {project.package} version") proc newProject*(nimble: Target): Project = ## instantiate a new project from the given .nimble @@ -735,16 +735,27 @@ proc relocateDependency*(parent: var Project; project: var Project) = name = project.nameMyRepo splat = repository.splitFile future = splat.dir / name - nimble = future / project.nimble.package.addFileExt(project.nimble.ext) - if current != name: - if dirExists(future): - warn &"cannot rename `{current}` to `{name}` -- already exists" - else: - moveDir(repository, future) - project.nimble = newTarget(nimble) - # the path changed, so point the parent to it - parent.addMissingSearchPathsTo(project) + if current == name: + return + + if dirExists(future): + warn &"cannot rename `{current}` to `{name}` -- already exists" + else: + # we'll need the dump in order to determine the search path + project.fetchDump + let + previous = project.determineSearchPath + nimble = future / project.nimble.package.addFileExt(project.nimble.ext) + + # now we can actually move the repo... + moveDir(repository, future) + # reset the package configuration target + project.nimble = newTarget(nimble) + # the path changed, so remove the old path (if you can) + discard parent.removeSearchPath(previous) + # and point the parent to the new one + parent.addMissingSearchPathsTo(project) proc clone*(project: var Project; url: Uri; name: string; cloned: var Project): bool = @@ -793,28 +804,30 @@ proc clone*(project: var Project; url: Uri; name: string; gitTrap got, clone(got, bare, directory): return - head = getHeadOid(got.repo) - if head.isNone: - oid = "" - else: - oid = $head.get - + # make sure the project we find is in the directory we cloned to; + # this could differ if the repo does not feature a dotNimble file if findProject(cloned, directory, parent = project) and cloned.repo == directory: + {.warning: "gratuitous nimblemeta write?".} + head = getHeadOid(got.repo) + if head.isNone: + oid = "" + else: + oid = $head.get if not writeNimbleMeta(directory, bare, oid): warn &"unable to write {nimbleMeta} in {directory}" + result = true else: error "couldn't make sense of the project i just cloned" - result = true + # if we're gonna fail, ensure that failure is felt + if not result: + cloned = nil proc allImportTargets*(config: ConfigRef; repo: string): OrderedTableRef[Target, LinkedSearchResult] = ## yield projects from the group in the same order that they may be ## resolved by the compiler, if at all, given a particular configuration - ## - ## FIXME: is it safe to assume that searchPaths are searched in the same - ## order that they appear in the parsed configuration? need test for this result = newOrderedTable[Target, LinkedSearchResult]() for path in config.extantSearchPaths: