diff --git a/nim.cfg b/nim.cfg index c08c788..96dcf05 100644 --- a/nim.cfg +++ b/nim.cfg @@ -1,4 +1,4 @@ ---define:debugPath +#--define:debugPath #hint[Conf]=off hint[Processing]=off @@ -19,9 +19,6 @@ hint[Processing]=off # we're going to specify new dependency directories... --clearNimblePath -# first, our local deps ---nimblePath="$config/deps/pkgs" - # output the nimph binary in the project directory instead of # causing a filename clash and naming it src/nimph.out (duh) --outdir="." @@ -34,12 +31,17 @@ hint[Processing]=off # we can just `nimble develop` and create a link, instead of # having to `nimble install compiler` and maintain a separate # copy of the compiler library... ---nimblePath="$home/.nimble/pkgs/compiler-#head" +--path="$home/git/Nim/" + +# lastly, our local deps will show up first +--nimblePath="$config/deps/pkgs" # nimph itself will, over time, move stuff to the bottom ---path="$config/deps/pkgs/parsetoml-#v0.5.0/src" ---path="$config/deps/pkgs/regex-#v0.13.0/src" ---path="$config/deps/pkgs/unicodedb-#head/src" ---path="$config/deps/pkgs/unicodeplus-#v0.5.1/src" ---path="$config/deps/pkgs/npeg-#head/src" +--path="$config/deps/pkgs/parsetoml-#v0.5.0/src/" +--path="$config/deps/pkgs/npeg-#head/src/" +--path="$config/deps/pkgs/github-1.0.2/src/" +--path="$config/deps/pkgs/regex-#v0.13.0/src/" --path="$config/deps/pkgs/github-1.0.2/src/" +--path="$config/deps/pkgs/unicodedb-#head/src/" +--path="$config/deps/pkgs/unicodeplus-#v0.5.1/src/" +--path="$config/deps/pkgs/nim-regex-#head/src/" diff --git a/nimph.nimble b/nimph.nimble index f5ae9c6..afa87f2 100644 --- a/nimph.nimble +++ b/nimph.nimble @@ -1,4 +1,4 @@ -version = "0.0.20" +version = "0.0.21" author = "disruptek" description = "nim package handler from the future" license = "MIT" diff --git a/src/nimph.nim b/src/nimph.nim index aa47046..358dfbb 100644 --- a/src/nimph.nim +++ b/src/nimph.nim @@ -51,7 +51,7 @@ template prepareForTheWorst(body: untyped) = body template setupLocalProject(project: var Project) = - if not findProject(project): + if not findProject(project, getCurrentDir()): crash &"unable to find a project; try `nimble init`?" try: project.cfg = loadAllCfgs(project.repo) diff --git a/src/nimph/config.nim b/src/nimph/config.nim index df6504d..ec500ac 100644 --- a/src/nimph/config.nim +++ b/src/nimph/config.nim @@ -45,16 +45,34 @@ proc loadProjectCfg*(path: string): Option[ConfigRef] = result = config.some proc overlayConfig*(config: var ConfigRef; directory: string): bool = + ## true if new config data was added to the env withinDirectory(directory): - # stuff the current directory as the project path - config.projectPath = AbsoluteDir getCurrentDir() - let filename = config.projectPath.string / NimCfg - if filename.fileExists: - var cache = newIdentCache() - result = readConfigFile(filename.AbsoluteFile, cache, config) - if not result: - let emsg = &"unable to read config in {config.projectPath}" # noqa - warn emsg + var + priorProjectPath = config.projectPath + let + nextProjectPath = AbsoluteDir getCurrentDir() + filename = nextProjectPath.string / NimCfg + + # if there's no config file, we're done + result = filename.fileExists + if not result: + return + + # remember to reset the config's project path + defer: + config.projectPath = priorProjectPath + # set the new project path for substitution purposes + config.projectPath = nextProjectPath + + var cache = newIdentCache() + result = readConfigFile(filename.AbsoluteFile, cache, config) + + if result: + # this config is now authoritative, so force the project path + priorProjectPath = nextProjectPath + else: + let emsg = &"unable to read config in {nextProjectPath}" # noqa + warn emsg proc loadAllCfgs*(directory: string): ConfigRef = ## use the compiler to parse all the usual nim.cfgs; @@ -298,6 +316,8 @@ iterator packagePaths*(config: ConfigRef; exists = true): string = addOne(path) for path in config.lazyPaths: addOne(path) + when defined(debugPath): + debug &"package directory count: {paths.len}" for path in paths: if exists and not path.dirExists: continue diff --git a/src/nimph/dependency.nim b/src/nimph/dependency.nim index d015154..277c1e6 100644 --- a/src/nimph/dependency.nim +++ b/src/nimph/dependency.nim @@ -108,13 +108,19 @@ proc adopt*(parent: Project; child: var Project) = ## associate a child project with the parent project of which the ## child is a requirement, member of local dependencies, or otherwise ## available to the compiler's search paths + if child.parent != nil and child.parent != parent: + let emsg = &"{parent} cannot adopt {child}" + raise newException(Defect, emsg) child.parent = parent -proc childProjects*(project: Project): ProjectGroup = +proc childProjects*(project: var Project): ProjectGroup = ## compose a group of possible dependencies of the project result = project.availableProjects for child in result.mvalues: + if child == project: + continue project.adopt(child) + discard child.fetchConfig proc determineDeps*(project: Project): Option[Requires] = ## try to parse requirements of a project @@ -355,7 +361,7 @@ proc resolveDependencies*(project: var Project; ## store result in dependencies # assert a usable config - discard project.fetchConfig + assert project.cfg != nil info &"{project.cuteRelease:>8} {project.name:>12} {project.releaseSummary}" diff --git a/src/nimph/project.nim b/src/nimph/project.nim index dea305c..1b21741 100644 --- a/src/nimph/project.nim +++ b/src/nimph/project.nim @@ -129,14 +129,20 @@ proc fetchConfig*(project: var Project; force = false): bool = ## ensure we've got a valid configuration to work with if project.cfg == nil or force: if project.parent == nil: + debug &"config fetch for parent {project}" project.cfg = loadAllCfgs(project.repo) result = true else: project.cfg = project.parent.cfg + debug &"config fetch for child {project}" result = overlayConfig(project.cfg, project.repo) - discard project.parent.fetchConfig(force = true) - if not result: - project.cfg = project.parent.cfg + if result: + discard project.parent.fetchConfig(force = true) + result = true + else: + discard + when defined(debug): + notice &"unnecessary config fetch for {project}" proc runNimble*(project: Project; args: seq[string]; opts = {poParentStreams}): RunNimbleOutput = @@ -441,10 +447,11 @@ proc linkedFindTarget(dir: string; target = ""; nimToo = false; result.search.message = e.msg result.search.found = none(Target) -proc findProject*(project: var Project; dir = "."): bool = +proc findProject*(project: var Project; dir: string; + parent: Project = nil): bool = ## locate a project starting from `dir` let - target = linkedFindTarget(dir) + target = linkedFindTarget(dir, ascend = true) if target.search.found.isNone: if target.search.message != "": error target.search.message @@ -456,7 +463,14 @@ proc findProject*(project: var Project; dir = "."): bool = debug &"--> via {target.via.search.found.get}" target = target.via + # there's really no scenario in which we need to instantiate a + # new parent project when looking for children... + if parent != nil: + if parent.nimble == target.search.found.get: + return + project = newProject(target.search.found.get) + project.parent = parent project.develop = target.via project.meta = fetchNimbleMeta(project.repo) project.dist = project.guessDist @@ -486,7 +500,11 @@ proc len*(group: ProjectGroup): int = result = group.table.len proc add*(group: ProjectGroup; name: string; project: Project) = - group.table.add name, project + when defined(debug): + if name in group.table: + raise newException(Defect, "attempt to add duplicate {name}") + if name notin group.table: + group.table.add name, project proc newProjectGroup*(): ProjectGroup = result = ProjectGroup() @@ -546,13 +564,14 @@ proc mgetProjectIn*(group: var ProjectGroup; directory: string): var Project = proc availableProjects*(project: Project): ProjectGroup = ## find packages locally available to a project; note that - ## this can include the project itself -- perfectly fine + ## this will include the project itself result = newProjectGroup() + result.add project.repo, project for directory in project.packageDirectories: - var package: Project - if findProject(package, directory): - if package.repo notin result: - result.add package.repo, package + var proj: Project + if findProject(proj, directory, parent = project): + if proj.repo notin result: + result.add proj.repo, proj else: debug &"no package found in {directory}" @@ -567,7 +586,7 @@ proc `==`*(a, b: Project): bool = if apath == bpath: result = true else: - debug "had to use samefile to compare {apath} to {bpath}" + debug &"had to use samefile to compare {apath} to {bpath}" result = sameFile(apath, bpath) proc findRepositoryUrl*(path: string): Option[Uri] = @@ -621,6 +640,7 @@ proc determineSearchPath(project: Project): string = result = srcDir.absolutePath break result = project.repo + result = result / "" iterator missingSearchPaths*(project: Project; target: Project): string = ## one (or more?) paths to the target package which are @@ -695,7 +715,8 @@ proc clone*(project: var Project; url: Uri; name: string): bool = var proj: Project - if findProject(proj, directory) and proj.repo == directory: + if findProject(proj, directory, parent = project) and + proj.repo == directory: if not writeNimbleMeta(directory, bare, oid): warn &"unable to write {nimbleMeta} in {directory}" proj.relocateDependency(oid) @@ -736,18 +757,25 @@ iterator asFoundVia*(group: ProjectGroup; config: ConfigRef; var dedupe = newTable[string, Project](nextPowerOfTwo(group.len)) + # procede in path order to try to find projects using the paths for path in config.packagePaths(exists = true): let target = linkedFindTarget(path, ascend = false) found = target.search.found - if found.isNone or target.importName in dedupe: + if found.isNone: continue for project in group.mvalues: if found.get == project.nimble: - dedupe.add target.importName, project - yield project + if project.importName notin dedupe: + dedupe.add project.importName, project + yield project break + # now report on anything we weren't able to discover + for project in group.values: + if project.importName notin dedupe: + notice &"no path to {project.repo}" + proc countNimblePaths*(project: Project): tuple[local: int; global: int; paths: seq[string]] = ## try to count the effective number of --nimblePaths