Skip to content

Commit a9205f8

Browse files
committedMay 20, 2020
revise internal libraries handling + refinings
1 parent 80f80dc commit a9205f8

File tree

5 files changed

+64
-38
lines changed

5 files changed

+64
-38
lines changed
 

‎README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -85,13 +85,13 @@ The entry point for script execution is "up" file. The actual name can be differ
8585
require('./highlands/')
8686
.lib('//lib/some/library', 'group:artifact:version')
8787
.lib('//lib/other/library:classifier', 'group:artifact:classifier:version')
88-
.lib('//lib/junit', ['junit:junit:4.12', 'org.hamcrest:hamcrest-core:1.3']))
88+
.lib('//lib/junit', ['junit:junit:4.12', 'org.hamcrest:hamcrest-core:1.3'])
8989
.run() // <- finishing move, required to launch the script execution
9090
```
9191
### ".lib" definition
9292

9393
```js
94-
.lib('//lib/some/library', 'group:artifact:version', options)
94+
.lib('//lib/some/library', 'group:artifact:version', options)
9595
```
9696

9797
Library definition contains library's canonical Buck path. By convention, if `:target` part is omitted it is considered the same as last segment of a path, so `//lib/one` is equivalent to `//lib/one:one` and is so called default target. Non-default targets are also supported and can be used for classifier jars or logically "sibling" jars/flavors. The example uses `//lib/` shared suffix for such libraries and it is not mandatory — use the path you want, but it's usually a good idea to have such common prefix (`//lib`, `//extern`, `//third-party/` etc are commonly used).

‎buck.js

+9-2
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,21 @@ class Target {
4141
withGoal(goal) {
4242
return new Target(this.path, goal)
4343
}
44+
45+
resolve(target) {
46+
return (!this.isLocal && target.isLocal)
47+
? this.withGoal(target.goal)
48+
: target
49+
}
4450
}
4551

4652
function trimSlashes(path) {
4753
return path.replace(/^[/]+/, '').replace(/[/]+$/, '')
4854
}
4955

50-
function target(string) {
51-
let [p, g] = string.split(':')
56+
function target(arg) {
57+
if (arg instanceof Target) return arg
58+
let [p, g] = String(arg).split(':')
5259
p = trimSlashes(p)
5360
g = g || paths.basename(p)
5461
if (!p && !g) throw `Wrong target specifier '${string}'`

‎lock.js

+11-9
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,14 @@ function load() {
1515
throw `File '${LOCKFILE}' is not found, please restore it or regenerate by running with --uplock --lib`
1616
}
1717
let lockdata = JSON.parse(ops.read(LOCKFILE))
18-
let libs = lockdata.libs.map(l => [
19-
l.target,
20-
l.jars.map(toCoordsSavingChecksum(mvn.EXT.jar_sum, l.options)),
21-
(l.srcs.map(toCoordsSavingChecksum(mvn.EXT.src_sum, l.options)), l.options),
22-
])
18+
let libs = lockdata.libs.map(l => {
19+
if ((l.options || {}).internal) {
20+
return [l.target, [], l.options]
21+
}
22+
let jars = l.jars.map(toCoordsSavingChecksum(mvn.EXT.jar_sum, l.options))
23+
l.srcs.forEach(toCoordsSavingChecksum(mvn.EXT.src_sum, l.options)) // cache only
24+
return [l.target, jars, l.options]
25+
})
2326
return libs
2427

2528
function toCoordsSavingChecksum(ext, options) {
@@ -36,12 +39,11 @@ function load() {
3639
function store(libs) {
3740
let lockdata = {
3841
note: GEN_BANNER,
39-
libs: libs.filter(l => !l.options.internal)
40-
.map(l => ({
42+
libs: libs.map(l => ({
4143
target: String(l.target),
4244
options: l.options,
43-
jars: l.jars.map(outputJar),
44-
srcs: l.srcs.map(outputSrc),
45+
jars: l.options.internal ? [] : l.jars.map(outputJar),
46+
srcs: l.options.internal ? [] : l.srcs.map(outputSrc),
4547
}))
4648
}
4749
return ops.write(LOCKFILE, JSON.stringify(lockdata, null, 2))

‎mods.js

+41-24
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ const mods = {
7373
let isTest = isTestRule(rule)
7474

7575
addSourceFolders(m.srcs, rule, isTest)
76-
mergeDeps(m.deps, depsOf(rule, isTest))
76+
mergeDeps(m.deps, depsOf(t, rule, isTest))
7777

7878
moduleByTarget[String(t)] = m
7979
}
@@ -134,7 +134,7 @@ const mods = {
134134
}
135135
}
136136

137-
function depsOf(rule, isTestRule) {
137+
function depsOf(target, rule, isTestRule) {
138138
let plainDeps = rule[buck.attr.deps] || []
139139
let providedDeps = rule[buck.attr.providedDeps] || []
140140
let exportedDeps = rule[buck.attr.exportedDeps] || []
@@ -144,10 +144,11 @@ const mods = {
144144
...plainDeps,
145145
...providedDeps,
146146
...exportedDeps,
147-
...exportedProvidedDeps].reduce((ds, d) => (ds[d] = {}, ds), {})
147+
...exportedProvidedDeps]
148+
.map(d => target.resolve(buck.target(d)))
149+
.reduce((ds, d) => (ds[d] = {target:d}, ds), {})
148150

149151
for (let [k, dep] of Object.entries(deps)) {
150-
dep.target = buck.target(k)
151152
dep.test = isTestRule
152153
dep.provided = providedDeps.includes(k) || exportedProvidedDeps.includes(k)
153154
dep.exported = exportedDeps.includes(k) || exportedProvidedDeps.includes(k)
@@ -212,19 +213,28 @@ const mods = {
212213
}
213214
}
214215

215-
function collectTransitiveDependencies(target) {
216-
let result = new Set()
217-
let toProcess = [target]
218-
while (toProcess.length > 0) {
219-
let d = toProcess.shift()
220-
if (result.has(d)) continue
221-
result.add(d)
222-
let deplib = libs.byTarget[d]
223-
if (deplib) {
224-
toProcess.push(...((deplib.options.deps || []).map(buck.target).map(String)))
216+
function collectLibraryTransitiveDependencies(target) {
217+
if (!(target in libs.byTarget)) throw `Not in libs.byTarget: ${target}`
218+
219+
let results = new Set()
220+
let unprocessed = [target]
221+
222+
do {
223+
let l = unprocessed.shift()
224+
results.add(l)
225+
let deplib = libs.byTarget[l]
226+
for (let d of (deplib.options.deps || [])) {
227+
let t = deplib.target.resolve(d).toString()
228+
if ((t in libs.byTarget) && !results.has(l)) {
229+
unprocessed.push(t)
230+
}
231+
// it occurs to me that under current model, we cannot
232+
// properly propagate library's dependency on a [ide] module,
233+
// only to other external or internal libraries, should be fine though
225234
}
226-
}
227-
return [...result]
235+
} while (unprocessed.length > 0)
236+
237+
return [...results]
228238
}
229239

230240
function wireDependencies() {
@@ -234,30 +244,37 @@ const mods = {
234244
// resolve dependency as sibling module in project workspace
235245
if (t in moduleByTarget) {
236246
let mod = moduleByTarget[t]
237-
m.depmods[mod.path] = Object.assign({}, dep, {mod})
247+
if (mod !== m) {
248+
// in case of local dependency, we cannot add dependency on self module
249+
// only dependency on local internal libs (to be jar compiled) are supported
250+
// but we mark dependency resolved anyway
251+
m.depmods[mod.path] = Object.assign({}, dep, {mod})
252+
}
238253
resolved = true
239254
}
240255
// and / or as dependency to a jar library (external/3rdparty or prebuilt internal)
241256
// if both module and library dependency are not desired at the same time
242257
// it's better to manage these dependencies, potentially, by
243258
// making module reexport same dependencies instead of using library directly
259+
244260
if (t in libs.byTarget) {
245-
let deplibs = collectTransitiveDependencies(t)
246-
.filter(dk => !!libs.byTarget[dk])
261+
let deplibs = collectLibraryTransitiveDependencies(t)
247262
.reduce((r, depkey) => {
248263
r[depkey] = Object.assign({}, dep, {lib: libs.byTarget[depkey]})
249264
return r
250265
}, {})
266+
251267
mergeDeps(m.deplibs, deplibs)
252268

253269
resolved = true
254270
}
271+
255272
if (!resolved) {
256-
if (buck.target(t).isLocal) {
257-
// local dependency should be implicit in IDE
258-
} else {
259-
err(`${p}: Unresolvable dependency ${t}`)
260-
}
273+
let t = buck.target(t)
274+
if (t.isLocal || t.path == m.path) {
275+
// local dependency should be implicit in IDE module
276+
// or it should have been an internal library
277+
} else err(`${p}: Unresolvable dependency ${t}`)
261278
}
262279
}
263280
}

‎ops.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const c = {
1717
const use = {
1818
workdir: process.cwd(),
1919
trace: false,
20-
timeout: 3, // seconds
20+
timeout: 5, // seconds
2121
}
2222

2323
function ls(path) {

0 commit comments

Comments
 (0)
Please sign in to comment.