Skip to content

Commit

Permalink
* Inherit sources from previous exported dependencies.
Browse files Browse the repository at this point in the history
When creating a notebook package, sources from other previously-exported
notebooks the current one explicitly depends on are copied inside the
Sources directory.

So, if notebook 1 depends on notebook 0, the sources from 0 will be
copied inside 1. If notebook 2 depends on notebook 1, the sources from 1
(which includes the sources from 0) will be copied.

This makes declarations "visible" by simply importing the previous
package, and not the ones where the symbols were declared. In fact,
declarations from notebook 0 used this way in notebook 2 do not
really come from the implementation in 0, but from the copy in 1.

We probably don't need the dependency lines in the SPM definition any
more.
  • Loading branch information
pcuenca committed Apr 23, 2019
1 parent 8c87af5 commit 73caf6a
Showing 1 changed file with 41 additions and 0 deletions.
41 changes: 41 additions & 0 deletions Sources/NotebookExport/NotebookExport.swift
Expand Up @@ -172,12 +172,53 @@ public extension NotebookExport {
return toScript(inside: Path.from(packagePath), mergingDependencies: mergingDependencies)
}

/// Copy sources from previously exported notebooks this one explicitly depends on.
internal
func copySourcesFromLocalDependencies(withPrefix prefix: String, inside packagePath: Path) {
do {
// Parse dependencies again and copy sources from local (i.e., path:) ones
// with the same prefix in the same parent directory.
let localSpec = NSRegularExpression(#"^\s*.package\(path:\s*"([^"]*)"(.*)\)$"#)
try extractDependencies().forEach { dependency in
guard dependency.name.hasPrefix(prefix) else { return }
let spec = dependency.rawSpec
let range = NSRange(spec.startIndex ..< spec.endIndex, in: spec)
localSpec.enumerateMatches(in: spec, options: [], range: range) { (match, _, _) in
guard let match = match else { return }
guard match.numberOfRanges == 3 else { return }
guard let pathRange = Range(match.range(at: 1), in: spec) else { return }

let path = Path.from(String(spec[pathRange]))
guard path.parent == packagePath.parent else { return }

// Do copy files
do {
let packageName = packagePath.basename()
let destination = packagePath/"Sources"/packageName
for entry in try (path/"Sources"/dependency.name).ls() where entry.kind == .file {
try entry.path.copy(into: destination)
}
} catch {
/* Ignore file */
}
}
}
} catch {
// pass
}
}

/// Export as an independent package, prepending the specified prefix to the name
@discardableResult
func toPackage(prefix: String = defaultPackagePrefix) -> ExportResult {
// Create the isolated package
let packagePath = Path.from(prefix + filepath.basename(dropExtension: true))
let packageResult = toScript(inside: packagePath, mergingDependencies: false)
guard case .success = packageResult else { return packageResult }

// Should we do this optional?
copySourcesFromLocalDependencies(withPrefix: prefix, inside: packagePath)

return packageResult
}

Expand Down

0 comments on commit 73caf6a

Please sign in to comment.